Created
June 5, 2021 22:12
-
-
Save ThomasG77/220c74f4b10f7cac94fceecf9c09a313 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!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: '© <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> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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