Skip to main content

Tutorial 14: WebApp Layer Vector Geographic Information Service Integration

Introduction

We will integrate a service that dynamically generates and distributes vector data into SVGMap.js. Here, we will integrate the global earthquake occurrence data (GeoJSON version) distributed by the USGS Hazards Program.

Although it connects to dynamic services, there is no fundamental difference from Tutorial 6.

Source Code

Compared to Tutorial 6, the following differences apply:

Tutorial

We will integrate a service that dynamically generates and distributes vector data into SVGMap.js. Here, we will integrate real-time global earthquake occurrence data (GeoJSON Real-time Feeds) (GeoJSON version) distributed by the USGS Hazards Program. There are basically no differences from Tutorial 6.

geojson1.html

  • There is no particular difference from Tutorial 6.

Container.svg

  • There is no particular difference from Tutorial 6.

geoJsonExample2.svg

  • The data-controller attribute of the document root element (svg element) specifies the webApp that controls this layer.
    • data-controller="geoJsonExample2.html#exec=appearOnLayerLoad
    • exec=appearOnLayerLoad This setting causes the webApp window to appear when the layer is displayed. ( For more information, click here )
  • The defs element defines the marker (POI icon).
    • The marker color is left undefined here because it will change depending on the magnitude.
<?xml version="1.0" encoding="UTF-8"?> 
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="12375.0 -4500.0 2250.0 2250.0" go:dataArea="12375.0 -4500.0 2250.0 2250.0" data-controller="geoJsonExample2.html#exec=appearOnLayerLoad" property="name,address,phone,url">

<defs>
<g id="p0">
<circle cx="0" cy="0" r="10" stroke="none"/>
</g>
</defs>

<globalCoordinateSystem srsName="http://purl.org/crs/84" transform="matrix(100.0,0.0,0.0,-100.0,0.0,0.0)" />
<g id="mapContents"></g>
</svg>

geoJsonExample2.html, geoJsonExample2.js

About the USGS Earthquake GeoJSON Real-time Feeds Service

This service delivers real-time updates of earthquake occurrences around the world at one-minute intervals. The output format is GeoJson, and output data can be selected from several options based on time interval and earthquake scale. There is no query part in the request, and updated data is always delivered via the same URL.

Code

  • A webApp that is linked to geoJsonExample2.svg and can control its DOM
  • The following are the differences from Tutorial 6#geoJsonExample1.html
  • addEventListener("load", function(){..})
    • changeData() A function to request and visualize earthquake data based on UI settings.
      • getUSGSURL() Generate a GET request to retrieve earthquake data from the USGS.
      • loadAndDrawGeoJson() A function that asynchronously retrieves and renders JSON data
        • loadJSON() To prevent browser caching, we add a query part that is constantly changing ( there are getTime() better ways to do this , but this is a classic bad tip).
        • buildSchema()
        • setMagColors()
          • Use the svgMapGIStool.drawGeoJson function's ability to set styles using the properties of each feature to color point features based on their magnitude values.
        • svgMapGIStool.drawGeoJson()
    • setInterval(function(){..}..) A function that updates periodically at specified intervals (since earthquake data is updated in real time)

geoJsonExample2.html

<!doctype html> 
<html>
<head>
<meta charset="utf-8"/>
<title>Sample of drawing geoJson in an SVGMap webApp layer</title>
</head>
<script src="https://cdn.jsdelivr.net/gh/svgmap/svgmapjs@latest/svgMapLayerLib.js"></script>
<script src="geoJsonExample2.js"></script>
<body>
<h3>area layer</h3>
<pVisualization of the <a href="https://earthquake.usgs.gov/earthquakes/feed/">USGS Earthquake Hazards Program Feed</a></p>
Period<select id="dataSelect1" onchange="changeData()"></select><br>
Scale<select id="dataSelect2" onchange="changeData()"></select>
<div id="messageDiv"></div>
</body>
</html>

geoJsonExample2.js

var usgsEarthquakeService="https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/"; 
var timeSpanKeys=["hour","day","week","month"]; // Selection for setting the period of distributed data
var timeSpanDefault=2; // Display data for the past week by default
var levelKeys=["significant","4.5","2.5","1.0","all"]; // Selection for distributed data by magnitude
var levelDefault=2; // Display earthquakes of M2.5 or higher by default
var intervalMinutes=10; // Update every 10 minutes
var metaSchema; // Store the normalized schema for the metadata display UI when selecting geometry, which is provided as standard in SVGMap.js

addEventListener("load", function(){
buildDataSelect();
changeData();
setInterval(function(){
changeData();
messageDiv.innerText=new Date().toLocaleString() + " update";
} ,intervalMinutes * 60 * 1000);
});

function changeData(){
var param1 = dataSelect1.selectedIndex;
var param2 = dataSelect2.selectedIndex;
var path = getUSGSURL(param1,param2);
loadAndDrawGeoJson(path);
}

async function loadAndDrawGeoJson(dataPath){
var gjs = await loadJSON(dataPath);
buildSchema(gjs.features);
setMagColors(gjs.features);
console.log("geoJson:",gjs);
var parentElm = svgImage.getElementById("mapContents");
removeChildren(parentElm);
svgMapGIStool.drawGeoJson(gjs, layerID, "orange", 2, "orange", "p0", "poi", "", parentElm, metaSchema);
svgMap.refreshScreen();
}

function buildDataSelect(){
var first=true;
for ( var i = 0 ; i < timeSpanKeys.length; i++){
var timeSpanKey = timeSpanKeys[i];
var selectedOpt="";
if ( timeSpanDefault == i){
selectedOpt="selected";
}
dataSelect1.insertAdjacentHTML('beforeend', `<option value="${timeSpanKey}" ${selectedOpt}>${timeSpanKey}</option>`);
}
for ( var i = 0 ; i < levelKeys.length ; i++){
var levelKey = levelKeys[i];
var selectedOpt="";
if ( levelDefault == i){
selectedOpt="selected";
}
dataSelect2.insertAdjacentHTML('beforeend', `<option value="${levelKey}" ${selectedOpt}>${levelKey}</option>`);
}
}

async function loadJSON(url){
var response = await fetch(url+"?time="+new Date().getTime()); // To always get the latest data, add a dummy query part. Bad Tips...
// https://stackoverflow.com/questions/37204296/cache-invalidation-using-the-query-string-bad-practice
// https://stackoverflow.com/questions/9692665/cache-busting-via-params
var json = await response.json();
return ( json );
}

function removeChildren(element){
while (element.firstChild) element.removeChild(element.firstChild);
}

function getUSGSURL(timeSpan, level){
if (!timeSpanKeys[timeSpan]){return};
if (!levelKeys[level]){return};
var ans = `${usgsEarthquakeService}${levelKeys[level]}_${timeSpanKeys[timeSpan]}.geojson`;
console.log("getUSGSURL:",ans);
return (ans);
}

function buildSchema(features){ // Generate a normalized schema from the property name of the geojson feature
metaSchema={};
for ( var feature of features){ // Trace all data just in
case for ( var propName in feature.properties){
if (!metaSchema[propName]){
metaSchema[propName]=true;
}
}
}
metaSchema=Object.keys(metaSchema);
svgImage.documentElement.setAttribute("property",metaSchema.join());
}

function setMagColors(features){ // Use the styling specifications from [[Guide#drawGeoJson]] to assign colors according to magnitude
features.sort(function(a,b){ // Sort by ascending magnitude
return(a.properties.mag - b.properties.mag);
});

for ( var feature of features){
var cmag = feature.properties.mag;
// Clip at magnitude 3...7
cmag = Math.max(3,cmag);
cmag = Math.min(7,cmag);
// Convert to hue and generate an RGB color from it
var hue = (7-cmag)/(4)*240;
var rgb = svgMapGIStool.hsv2rgb(hue,100,100);
console.log(rgb);
if ( } }
console.log(
features
)
;
}

Appendix: Cross-origin access

Cross-origin access ( now a separate page )