Skip to content

Instantly share code, notes, and snippets.

@ThomasG77
Created June 5, 2021 22:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ThomasG77/220c74f4b10f7cac94fceecf9c09a313 to your computer and use it in GitHub Desktop.
Save ThomasG77/220c74f4b10f7cac94fceecf9c09a313 to your computer and use it in GitHub Desktop.
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<script src="https://unpkg.com/leaflet@1.7.1/dist/leaflet.js"
integrity="sha512-XQoYMqMTK8LvdxXYG3nZ448hOEQiglfqkJs1NOQV44cWnUrBc8PkAOcXy20w0vlaXaVUearIOBhiXZ5V3ynxwA=="
crossorigin=""></script>
<!-- Code mainly borrowed from https://github.com/usgs/quakeml-parser-js but done bad workarounds to avoid using "require"
and made some code change to avoid some errors while parsing (was parsing only one event...) -->
<script src="quakeml.js"></script>
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.7.1/dist/leaflet.css"
integrity="sha512-xodZBNTC5n17Xt2atTPuE1HxjVMSvLVW9ocqUKLsCC5CXdbqCmblAshOMAS6/keqq/sMZMZ19scR4PsZChSR7A=="
crossorigin=""/>
<style>
html, body {
height: 100%;
padding: 0;
margin: 0;
}
#map {
/* configure the size of the map */
width: 100%;
height: 100%;
}
</style>
</head>
<body>
<div id="map"></div>
<script>
// initialize Leaflet
var map = L.map('map').setView({lon: 0, lat: 0}, 2);
// add the OpenStreetMap tiles
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 19,
attribution: '&copy; <a href="https://openstreetmap.org/copyright">OpenStreetMap contributors</a>'
}).addTo(map);
// show the scale bar on the lower left corner
L.control.scale().addTo(map);
var FEED1 = 'https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/all_day.geojson';
var FEED2 = 'https://webservices.ingv.it/fdsnws/event/1/query?starttime=2021-05-29&minlatitude=42.12&maxlatitude=44.14&minlongitude=9.90&maxlongitude=14.47';
var NOW = new Date();
var earthquakes = L.geoJson([], {
onEachFeature: function (feature, layer) {
var props = feature.properties;
layer.bindPopup('Dat: ' + props.time + '</br>' + 'Vr: ' + props.magtype + '</br>' + 'Ma: ' + props.mag + '</br>' + 'Du: ' + props.depth + ' km' + '</br>' + 'Iz: ' + props.source_catalog);
},
pointToLayer: function (feature, latlng) {
var color,
mag,
radius,
weight;
mag = feature.properties.mag;
if (mag === null) {
color = '#FF0000';
radius = 2;
weight = 0.7;
} else {
color = '#FF0000';
radius = 2 * Math.max(mag, 1);
weight = 0.7;
}
if (feature.properties.type === 'quarry blast') {
color = '#FF00FF';
}
return L.circleMarker(latlng, {
color: color,
radius: radius,
weight: weight
});
}
}).addTo(map);
fetch(FEED1, {
method:'GET'
})
.then(r => r.json())
.then(json => {
console.log(json);
earthquakes.addData(json);
});
fetch(FEED2, {
method:'GET'
})
.then(r => r.text())
.then(text => {
xml = (new window.DOMParser()).parseFromString(text, "text/xml");
console.log("FEED2");
//console.log(text);
quakeObject = Quakeml({xml: xml});
mags = quakeObject.getMagnitudes()
geojson = {
"type": "FeatureCollection",
"features": quakeObject.getOrigins().map((el, i) => {
return {
"type": "Feature",
"properties": {
// Need to reconciliate properties of both source (not same properties exactly, some already retrieved)
time: el[0].time.value,
depth: el[0].depth.value,
mag: Number(mags[i][0].mag.value),
magtype: mags[i][0].type
},
"geometry": {
"type": "Point",
"coordinates": [
Number(el[0].longitude.value),
Number(el[0].latitude.value)
]
}
}
})
};
console.log(geojson);
earthquakes.addData(geojson);
})
</script>
</body>
</html>
var Quakeml = (function () {
'use strict';
var XmlUtil = {
/**
* Convert simple xml to a json object.
* Does not work well for mixed content (text/elements).
*/
xmlToJson: function (xml) {
// based on http://davidwalsh.name/convert-xml-json
var obj = {},
children = [],
attrs,
attr,
nodes,
node,
nodeName,
nodeValue,
i,
len;
if (typeof xml === 'string') {
xml = new DOMParser().parseFromString(xml, 'text/xml');
}
if (xml.nodeType === 3) {
return xml.nodeValue;
}
if (xml.nodeType === 1) {
attrs = xml.attributes;
for (i = 0, len = attrs.length; i < len; i++) {
attr = attrs.item(i);
obj[attr.nodeName] = attr.nodeValue;
}
}
if (xml.hasChildNodes()) {
nodes = xml.childNodes;
for(i = 0, len = nodes.length; i < len; i++) {
node = nodes.item(i);
nodeName = node.nodeName;
nodeValue = XmlUtil.xmlToJson(node);
children.push(nodeValue);
if (typeof(obj[nodeName]) === 'undefined') {
obj[nodeName] = nodeValue;
} else {
if (typeof(obj[nodeName].push) === 'undefined') {
obj[nodeName] = [obj[nodeName]];
}
obj[nodeName].push(nodeValue);
}
}
}
// clean up '#text' nodes
if (children.length === 1 &&
obj['#text'] &&
Object.keys(obj).length === 1) {
return obj['#text'];
}
return obj;
}
};
/**
* Convert an object to an array if needed.
*
* @param obj {Any}
* @return {Array}
* if obj is an Object, either
* obj, if obj is already an array,
* otherwise, [obj]
* otherwise, [].
*/
var _array = function (obj) {
if (Array.isArray(obj)) {
return obj;
} else if (typeof obj === 'object' && obj !== null) {
return [obj];
} else {
return [];
}
};
/**
* Copy properties from source objects onto dest.
*
* @param dest {Object}
* destination for copied properties.
* @param varargs {Object, ...}
* source objects, processed in argument order from left to right.
* all properties are copied from the source object to dest.
* @return {Object} dest, after copying source object properties.
*/
var _extend = function (dest /*, varargs */) {
var src,
i,
key;
for (i = 1; i < arguments.length; i++) {
src = arguments[i];
if (typeof src === 'object' && src !== null) {
for (key in src) {
dest[key] = src[key];
}
}
}
return dest;
};
/**
* Build a lookup index for objects, based on (unique) property value.
*
* For Example:
* _index([{id: 'a'}, {id: 'b'}], 'id')
* would return
* {
* 'a': {id: 'a'},
* 'b': {id: 'b'}
* }
*
* @param objs {Array<Object>}
* objects to index
* @param key {String}
* property to index.
* @param index {Object}
* optional, existing index to extend.
* @return {Object} indexed data.
*/
var _index = function (objs, key, index) {
var i,
len,
obj;
index = index || {};
if (objs) {
if (!Array.isArray(objs)) {
objs = [objs];
}
for (i = 0, len = objs.length; i < len; i++) {
obj = objs[i];
index[obj[key]] = obj;
}
}
return index;
};
/**
* Construct a new Quakeml Event.
*
* @param ev {Element}
* Quakeml event(like) element
*/
var QuakemlEvent = function (ev) {
var _this,
_initialize,
_amplitudeIndex,
_catalog,
_ev,
_magnitudes,
_origins,
_pickIndex,
_preferredMagnitudeID,
_preferredOriginID,
_stationMagnitudeIndex,
_parseArrivals,
_parseOrigins,
_parseMagnitudeContributions,
_parseMagnitudes;
_this = Object.create({});
/**
* Initialize this event, by parsing origins and magnitudes.
*/
_initialize = function (ev) {
_ev = ev;
_catalog = _ev['catalog:eventSource'];
_preferredOriginID = _ev.preferredOriginID || null;
_preferredMagnitudeID = _ev.preferredMagnitudeID || null;
_pickIndex = _index(_ev.pick, 'publicID');
_amplitudeIndex = _index(_ev.amplitude, 'publicID');
_stationMagnitudeIndex = _index(_ev.stationMagnitude, 'publicID');
_origins = _parseOrigins(_array(_ev.origin));
_magnitudes = _parseMagnitudes(_array(_ev.magnitude));
ev = null;
};
/**
* Parse an array of arrival elements.
*
* @param arrivals {Array<Element>}
* array of quakeml arrival elements.
* @return {Array<Object>} parsed arrival objects.
*/
_parseArrivals = function (arrivals) {
var a,
arrival,
parsed = [],
pickIndex = _pickIndex;
for (a = 0; a < arrivals.length; a++) {
arrival = _extend({}, arrivals[a]);
if (typeof arrival.pickID === 'string') {
arrival.pick = pickIndex[arrival.pickID] || null;
} else {
arrival.pick = null;
}
parsed.push(arrival);
}
return parsed;
};
/**
* Parse an array of stationMagnitudeContribution elements.
*
* @param contributions {Array<Element>}
* array of quakeml stationMagnitudeContribution elements.
* @return {Array<Object>} parsed stationMagnitudeContribution objects.
*/
_parseMagnitudeContributions = function (contributions) {
var amplitudeIndex = _amplitudeIndex,
c,
contribution,
parsed = [],
stationMagnitude,
stationMagnitudeIndex = _stationMagnitudeIndex;
for (c = 0; c < contributions.length; c++) {
contribution = _extend({}, contributions[c]);
stationMagnitude = _extend({},
stationMagnitudeIndex[contribution.stationMagnitudeID]);
contribution.stationMagnitude = stationMagnitude;
if (typeof stationMagnitude.amplitudeID === 'string') {
stationMagnitude.amplitude = _extend({},
amplitudeIndex[stationMagnitude.amplitudeID]);
}
parsed.push(contribution);
}
return parsed;
};
/**
* Parse and array of magnitude elements.
*
* @param magnitudes {Array<Element>}
* array of quakeml magnitude elements.
* @return {Array<Object>} parsed magnitude objects.
*/
_parseMagnitudes = function (magnitudes) {
var m,
magnitude,
parsed = [],
preferredMagnitudeID = _preferredMagnitudeID;
for (m = 0; m < magnitudes.length; m++) {
magnitude = _extend({}, magnitudes[m]);
magnitude.isPreferred = (preferredMagnitudeID === magnitude.publicID);
magnitude.contributions = _parseMagnitudeContributions(
_array(magnitude.stationMagnitudeContribution));
delete magnitude.stationMagnitudeContribution;
if (magnitude.isPreferred) {
parsed.unshift(magnitude);
} else {
parsed.push(magnitude);
}
}
return parsed;
};
/**
* Parse an array of origin elements.
*
* @param origins {Array<Element>}
* array of quakeml origin elements.
* @return {Array<Object>} parsed origin objects.
*/
_parseOrigins = function (origins) {
var o,
origin,
parsed = [],
preferredOriginID = _preferredOriginID;
for (o = 0; o < origins.length; o++) {
origin = _extend({}, origins[o]);
origin.isPreferred = (preferredOriginID === origin.publicID);
origin.arrivals = _parseArrivals(_array(origin.arrival));
delete origin.arrival;
if (origin.isPreferred) {
parsed.unshift(origin);
} else {
parsed.push(origin);
}
}
return parsed;
};
/**
* @return {Object} quakeml event element as json object.
*/
_this.getEvent = function () {
return _ev;
};
/**
* @return {Array<Object>} magnitudes parsed from event.
*/
_this.getMagnitudes = function () {
return _magnitudes;
};
/**
* @return {Array<Object>} origins parsed from event.
*/
_this.getOrigins = function () {
return _origins;
};
_initialize(ev);
ev = null;
return _this;
};
/**
* Create a new Quakeml object.
*
* @param options {Object}
* @param options.xml {String|XMLDocument}
* quakeml xml to parse.
* If a string, options.xml is parsed using DOMParser.
* @param options.eventElement {String}
* Default 'event'.
* The event element inside eventParameters to find.
* The first matching element is parsed during _initialize.
*/
var Quakeml = function (options) {
var _this,
_initialize,
_events,
_updated,
_quakeml;
_this = Object.create({});
/**
* Initialize the quakeml object.
*/
_initialize = function (options) {
var ev,
eventElement = options.eventElement || 'event',
eventParameters,
json,
quakeml;
json = XmlUtil.xmlToJson(options.xml);
quakeml = json['q:quakeml'];
eventParameters = quakeml.eventParameters;
ev = eventParameters[eventElement];
//debugger;
if (typeof ev === 'undefined') {
throw new Error('Event element ' + eventElement + ' not found');
}
_quakeml = quakeml;
//_updated = eventParameters.creationInfo.creationTime;
_events = ev.map( el => QuakemlEvent(el));
};
/**
* @return {Array<Object>} magnitudes parsed from event element.
*/
_this.getMagnitudes = function () {
return _events.map(el => el.getMagnitudes(el));
};
/**
* @return {Array<Object>} origins parsed from event element.
*/
_this.getOrigins = function () {
return _events.map(el => el.getOrigins(el));
};
/**
* @return {String} iso8601 timestamp when quakeml message was updated.
*/
_this.getUpdated = function () {
return _updated;
};
_this.getEvents = function () {
return _events;
};
_initialize(options);
options=null;
return _this;
};
return Quakeml;
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment