diff --git a/www/events.js.en b/www/events.js.en new file mode 100644 index 0000000..b059173 --- /dev/null +++ b/www/events.js.en @@ -0,0 +1,434 @@ +/********************************************************************** + * events.js * + * script for event specific functions and setup * + **********************************************************************/ + +/* License + Copyright 2014 Kasper D. Fischer + + This program is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the Free + Software Foundation, either version 3 of the License, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License along + with this program. If not, see http://www.gnu.org/licenses/. + + $Id$ +*/ + +/* adding row(s) to a table and format date strings afterwards */ +function addTableRow(row, table) { + var added = $('#'+table+' tbody').append(row); + added.find('.tablesorter-childRow td').hide(); + $('#'+table).find('td.utctime-date').each(function() { + $.localtime.formatObject($(this), "dd.MM.yyyy"); + $(this).removeClass('utctime-date'); + $(this).addClass('localtime-date'); + }); + $('#'+table).find('td.utctime-time').each(function() { + $.localtime.formatObject($(this), "HH:mm"); + $(this).removeClass('utctime-time'); + $(this).addClass('localtime-time'); + }); +}; + +/* do reverse geolocation lookup */ +function getGeolocation(id, lat, lng) { + if ( !geolocationTable[id] ) { + $.getJSON( config['ajax']['nominatimURL'], { lat: lat, lon: lng, zoom: 10, format: "json" } ) + .done(function( json ) { + var city = json.address["city"]; + var country = json.address["country"]; + var countryCode = json.address["country_code"].toUpperCase(); + geolocationTable[id] = city; + ( country != "Deutschland" ) ? geolocationTable[id] = geolocationTable[id] + " ("+countryCode+")" : null; + if ( city ) { + $("#eventstable a.toggle[eventid="+id+"]").text(geolocationTable[id]); + var sort = [[0,1],[1,1],[2,1]]; + $("#eventstable").trigger("update", [true]); + $("#eventstable").trigger("updateCache"); + $("#eventstable").trigger("sorton", [sort]); + } else { + console.log("Nominatim did not provide a city tag for "+lat+" / "+lng); + }; + }) + .fail(function( jqxhr, textStatus, error ) { + var err = textStatus + ", " + error; + console.log( "Request Failed: " + err ); + }); + }; +}; + +/* Load events using ajax */ +function ajaxLoadEvents(stime, etime, eventid, url, target) { + var mapBounds = map.getBounds(); + var request_data = {}; + var rtime; + var ajax_url = config['ajax']['eventURL']; + if ( stime == '' || !stime ) { + stime = new Date(); + stime.setDate(stime.getDate()-config['map']['timespan']); + rtime = new Date(); + rtime.setDate(rtime.getDate()-Math.min(config['ajax']['timespan'], config['map']['timespan'])); + } else { + rtime = stime; + }; + if ( url ) { + var ajax_url = url; + request_data = {}; + } else { + if ( eventid ) { + request_data = { eventid: eventid }; + } else { + request_data = { + starttime: sprintf("%d-%02d-%02d", rtime.getFullYear(), rtime.getMonth()+1, rtime.getDate()), + orderby: 'time', + minlat: sprintf('%.2f', mapBounds.getSouth()-config['map']['latlngDelta']), + maxlat: sprintf('%.2f', mapBounds.getNorth()+config['map']['latlngDelta']), + minlon: sprintf('%.2f', mapBounds.getWest()-config['map']['latlngDelta']), + maxlon: sprintf('%.2f', mapBounds.getEast()+config['map']['latlngDelta']), + minmag: sprintf('%.1f', config['event']['minMag']-config['event']['minMagDelta']), + }; + if ( etime ) { + request_data['endtime'] = sprintf("%d-%02d-%02d", etime.getFullYear(), etime.getMonth()+1, etime.getDate()); + }; + }; + }; + if ( etime == '' || !etime ) { etime = new Date(); }; + $.ajax({ + type: "GET", + url: ajax_url, + data: request_data, + dataType: "xml", + success: function (xml) { + $(xml).find('event').each(function () { + var id = $(this).attr('publicID').split('/')[2]; + var mag = $(this).find('magnitude > mag > value').text(); + var otime = $(this).find('origin > time > value').text(); + var lng = $(this).find('origin > longitude > value').text(); + var lat = $(this).find('origin > latitude > value').text(); + var depth = $(this).find('origin > depth > value').text(); + var evaluationMode = $(this).find('origin > evaluationMode').text(); + var evaluationStatus = $(this).find('origin > evaluationStatus').text(); + var type = $(this).find('type').last().text(); + var location + // get location, try this in order: + // regional map name, given value, cached value, or nominatim lookup + geolocationTable[id] ? null : getGeolocation(id, lat, lng); // do AJAX lookup if not cached, location will be updated later + location = ( geolocationTable[id] || getLocation(lat, lng)[0] || $(this).find('description > text').text() ); + // create table row: Date, Time, Mag, Location + if ( !eventTable[id] && $.inArray(type, config['event']['typeWhitelist'] )+1 && $.inArray(evaluationStatus, config['event']['evaluationBlacklist'])<0 && Number(mag)+0.05 >= config['event']['minMag'] ) { + // general event info (1st line) + var row = '' + + ''+otime.split('.')[0]+'Z' + + ''+otime.split('.')[0]+'Z' + + sprintf('%.1f', Number(mag)) + + ''+location+' map' + + ''; + // setting up event details (2nd line) + row += '' + + 'Daten werden geladen ...'; + // setting up download links (3nd line) + var xmlurl = sprintf('%s?formatted=true&includearrivals=true&eventid=%s', config['ajax']['eventURL'], id); + var oTime = new Date(otime); + var sTime = new Date(oTime.getTime()-10*1000.-oTime.getMilliseconds()); + var eTime = new Date(oTime.getTime()+50*1000.-oTime.getMilliseconds()); + var mseedurl = sprintf('%s?net=GE,GR,RN&cha=EH?,HH?&start=%04d-%02d-%02dT%02d:%02d:%02d&end=%04d-%02d-%02dT%02d:%02d:%02d', config['ajax']['mseedURL'], Number(sTime.getUTCFullYear()), Number(sTime.getUTCMonth())+1, Number(sTime.getUTCDate()), Number(sTime.getUTCHours()), Number(sTime.getUTCMinutes()), Number(sTime.getUTCSeconds()), Number(eTime.getUTCFullYear()), Number(eTime.getUTCMonth())+1, Number(eTime.getUTCDate()), Number(eTime.getUTCHours()), Number(eTime.getUTCMinutes()), Number(eTime.getUTCSeconds())); + row += '' + + '' + + sprintf('Download QuakeML or miniSEED', id, xmlurl, id, mseedurl) + + ''; + // add row to table + if ( stime <= oTime && etime >= oTime ) { + addTableRow(row, 'eventstable'); + }; + if ( target ) { + addTableRow(row, target); + } + // create marker + if ((stime <= oTime && etime >= oTime ) || ( id == eventid )) { + var marker = addEventMarker(id, Number(lat), Number(lng), Number(mag), type); + var text = sprintf('

%s

', id, location) + + sprintf('

Ereignis: %s
', id) + + sprintf('Type: %s
', type) + + sprintf('Magnitude: %3.1f
', Number(mag)) + + sprintf('Ort: %.4f °N, %.4f °O
', Number(lat), Number(lng)) + + sprintf('Tiefe: %.1f km
', Number(depth)/1000.) + + sprintf('Zeit: %sZ

', otime.split('.')[0], otime.split('.')[0]); + marker.bindPopup(text); + }; + }; + }); + }, + complete: function () { + var sort = [[0,1],[1,1],[2,1]]; + $("#eventstable").trigger("update", [true]); + $("#eventstable").trigger("updateCache"); + $("#eventstable").trigger("sorton", [sort]); + initMapLink(); + eventLayer.bringToBack(); + highlightFirstEvent(); + }, + error: function( jqxhr, textStatus, error ) { + var err = textStatus + ", " + error; + console.log( "Request Failed: " + err ); + } + }); + // create events csv download link + request_data['format'] = 'text'; + if ( eventid == '' || !eventid ) { $('#events-csv-link').attr('href', config['ajax']['eventURL']+'?'+$.param(request_data)) }; +}; + +/* ajaxLoadEventInfo */ +function ajaxLoadEventInfo(id) { + var request_data = { + eventid: id, + includeArrivals: true, + }; + $.ajax({ + type: "GET", + url: config['ajax']['eventURL'], + data: request_data, + dataType: "xml", + success: function (xml) { + eventDetails[id] = true; + $(xml).find('event').each(function () { + var event = $(this); + var mag = $(this).find('magnitude > mag > value').text(); + var otime = $(this).find('origin > time > value').text(); + var lng = $(this).find('origin > longitude > value').text(); + var lng_err = $(this).find('origin > longitude > uncertainty').text(); + var lat = $(this).find('origin > latitude > value').text(); + var lat_err = $(this).find('origin > latitude > uncertainty').text(); + var depth = $(this).find('origin > depth > value').text(); + var depth_err = $(this).find('origin > depth > uncertainty').text(); + var rms = $(this).find('origin > quality > standardError').text(); + var gap = $(this).find('origin > quality > azimuthalGap').text(); + var phases_count = $(this).find('origin > quality > usedPhaseCount').text(); + var type = $(this).find('type').last().text(); + // setting up general event info + var row = "
"
+					+ sprintf("ID %49s\n", id)
+					+ sprintf("Type %47s\n\n", type)
+					+ "Origin\n"
+					+ sprintf("Date %18s\n", otime.split('T')[0])
+					+ sprintf("Time %18s UTC\n", otime.split('T')[1].substring(0, 11))
+					+ sprintf("Latitude %14.4f °N +- %4.1f km\n",Number(lat), Number(lat_err))
+					+ sprintf("Longitude %13.4f °E +- %4.1f km\n", Number(lng), Number(lng_err))
+					+ sprintf("Depth %14.1f    km +- %4.1f km\n", Number(depth)/1000., Number(depth_err)/1000.)
+					+ sprintf("Magnitude %10.1f\n", Number(mag))
+					+ sprintf("Residual RMS %7.1f    sec\n", Number(rms))
+					+ sprintf("Azimuthal gap %6.1f    °\n\n", Number(gap))
+					+ sprintf("%d Phase arrivals:\n", Number(phases_count))
+					+ "sta  net  dist azi     phase time         res   wt\n";
+				// adding phase info (TODO sort by distance)
+				$(this).find('origin > arrival').each(function() {
+					var pickid = $(this).find('pickID').text();
+					var azi = $(this).find('azimuth').text();
+					var dist = $(this).find('distance').text();
+					var tres = $(this).find('timeResidual').text();
+					var phase = $(this).find('phase').text();
+					var tweight = $(this).find('timeWeight').text();
+					if ( Number(tweight) > 0.0 ) {
+						var waveformid = event.find('pick[publicID="'+pickid+'"] > waveformID');
+						var networkcode = waveformid.attr('networkCode');
+						var stationcode = waveformid.attr('stationCode');
+						var channel = waveformid.attr('channelCode').substring(2,2);
+						var phasemode = event.find('pick[publicID="'+pickid+'"] > evaluationMode').text().substring(0,1).toUpperCase();
+						var picktime = event.find('pick[publicID="'+pickid+'"] > time > value').text().split('T')[1].substring(0,11);
+						row = row
+							+ sprintf('%-4s %2s  %5.1f %5.1f %3s %1s %13s %5.1f %5.2f\n', stationcode, networkcode, Number(dist), Number(azi), phase, phasemode, picktime, Number(tres), Number(tweight));
+					};
+				});
+				row = row + '
'; + $('#eventstable > tbody > tr.event-details > td[eventid='+id+']').html(row); + }); + }, + complete: function () { + null; + }, + error: function( jqxhr, textStatus, error ) { + var err = textStatus + ", " + error; + console.log( "Request Failed: " + err ); + } + }); +}; + +/* toggles visibility of filtered markers + * only events in the event list are shown */ +function toggleFilteredMarkers() { + // show all shown events in map + $("#eventstable > tbody > tr:not(.filtered) > td > a.map-link").each( function() { + if ( $(this).attr("eventid") ) { + map.addLayer(eventTable[$(this).attr("eventid")]); + }; + }); + // hide filtered events in map + $("#eventstable > tbody > tr.filtered > td > a.map-link").each( function() { + if ( $(this).attr("eventid") ) { + map.removeLayer(eventTable[$(this).attr("eventid")]); + }; + }); + highlightFirstEvent(); +}; + +/* Highlight the first event of the event list on the map if no + * other event is selected */ +function highlightFirstEvent() { + var highlightStyle = { + color: config['event']['markerColorH'], + fillColor: config['event']['markerColorH'], + fillOpacity: 1, + }; + var normalStyle = { + fillColor: config['event']['markerColor'], + color: config['event']['markerColor'], + fillOpacity: config['event']['markerOpacity'], + }; + $("#eventstable a.map-link").each( function() { + if ( $(this).attr("eventid") ) { + eventTable[$(this).attr("eventid")].setStyle(normalStyle); + $(this).removeClass('first'); + $(this).text('map'); + }; + }); + $("#eventstable > tbody > tr:not(.filtered):visible").first().find("a.map-link").each(function() { + if ( $(this).attr("eventid") ) { + eventTable[$(this).attr("eventid")].setStyle(highlightStyle); + eventTable[$(this).attr("eventid")].bringToFront(); + $(this).addClass('first'); + $(this).text('map (red)'); + }; + }); +}; + +function highlightEvent( id ) { + var highlightStyle = { + color: config['event']['markerColorH'], + fillColor: config['event']['markerColorH'], + fillOpacity: 1, + }; + var normalStyle = { + fillColor: config['event']['markerColor'], + color: config['event']['markerColor'], + fillOpacity: config['event']['markerOpacity'], + }; + $("#eventstable > tbody > tr:not(.filtered)").find("a.map-link").each( function() { + if ( $(this).attr("eventid") ) { + if ( $(this).attr("eventid") == id ) { + eventTable[$(this).attr("eventid")].setStyle(highlightStyle); + eventTable[$(this).attr("eventid")].bringToFront(); + $(this).addClass('first'); + $(this).text('map (red)'); + } else { + eventTable[$(this).attr("eventid")].setStyle(normalStyle); + $(this).removeClass('first'); + $(this).text('map'); + } + }; + }); +}; + +/********************************************************************** + * document ready * + **********************************************************************/ +$(document).ready(function() { + // tablesorter for event list + $("#eventstable").tablesorter( + { + theme : 'blue', + dateFormat : "ddmmyyyy", + headers: { + 0: { sorter: "shortDate" } + }, + cssChildRow: "tablesorter-childRow", // this is the default setting + widgets: ["uitheme", "zebra", "filter", "pager"], // initialize zebra and filter widgets, "scroller" + widgetOptions: { + // possible variables: {page}, {totalPages}, {filteredPages}, {startRow}, {endRow}, {filteredRows} and {totalRows} + pager_output: '# {startRow} - {endRow} ({totalRows}) | page {page} ({totalPages})', + pager_removeRows: false, + pager_size: 35, + filter_childRows : true, + filter_cssFilter : 'tablesorter-filter', + filter_startsWith : false, + filter_ignoreCase : true, + scroller_height: $('div.map').height() - 250, + scroller_barWidth: 10, + scroller_jumpToHeader: false, + sortList: "[[0,1], [1,1], [2,1]]", + resort: true, + showProcessing: true, + } + }); + // hide child rows + $('#eventstable > tbody > tr.tablesorter-childRow td').hide(); + // update map after filtering + $('#eventstable').bind('filterEnd', function(){ + toggleFilteredMarkers(); + }); + // highlight first event + $('#eventstable').bind('sortEnd', function(){ + highlightFirstEvent(); + }); + $('#eventstable').bind('pagerComplete', function(){ + highlightFirstEvent(); + }); + // show / hide event info + $('#eventstable').delegate('.toggle', 'click' , function(){ + // load event details + var eventid = $(this).attr('eventid'); + ( eventDetails[eventid] ) ? null : ajaxLoadEventInfo(eventid); + + // toggle visibility of selected row + $(this).closest('tr').nextUntil('tr.tablesorter-hasChildRow').find('td').toggle('slow'); + // mark currently selected row and remove class selected from all other rows + // hide other rows + $(this).closest('tr').nextUntil('tr.tablesorter-hasChildRow').find('td').addClass('selected-now'); + $(this).closest('tbody').find('td.selected').each(function(){ + if ( ! $(this).hasClass('selected-now') ) { + $(this).hide(); + $(this).removeClass('selected'); + }; + }); + $(this).closest('tr').nextUntil('tr.tablesorter-hasChildRow').find('td').each(function(){ + $(this).removeClass('selected-now'); + var selected = $(this).hasClass('selected'); + if ( selected ) { + $(this).removeClass('selected'); + highlightFirstEvent(); + } else { + $(this).addClass('selected'); + highlightEvent($(this).attr('eventid')); + }; + }); + return false; + }); + // update selection / type info + $("#events-timespan").text(config['map']['timespan']); + $("#events-minmag").text(sprintf('%.1f', config['event']['minMag'])); + config['event']['typeWhitelist'].map(function(type) { + var typetext; + ( $("#events-type").text() == "Symbols:" ) ? typetext = ' ' : typetext = ', '; + switch ( type ) { + case 'earthquake': + typetext += 'tectonic earthquake (star)'; + break; + case 'explosion': + typetext += 'explosion (hexagon)'; + break; + case 'induced or triggered event': + typetext += '(mining-)induced event (circle)'; + break; + case 'quarry blast': + typetext += 'quarry blast (wheel)'; + break; + }; + $("#events-type").append(typetext); + }); +}); diff --git a/www/index.html.en b/www/index.html.en new file mode 100755 index 0000000..6e6fca5 --- /dev/null +++ b/www/index.html.en @@ -0,0 +1,184 @@ + + + + + + RUB SeisObs - Event and Station Map + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+
+ First + Prev + + Next + Last + + +
+ + + + + + + + + + + + + + + + + + +
DateTimeMag.Place
+

+ Events of the last 180 days with magnitude 1.2 or larger in the area of the map and special events in adjacents regions. Download as CSV file. +

+

+ Symbols: +

+

+ Nominatim Search Courtesy of MapQuest Mapquest Logo +

+
+ +
+
+ First + Prev + + Next + Last + + +
+ + + + + + + + + + + + + + + + + +
NetworkStationLatitude [°]Longitude [°]
+

Download as CSV file.

+
+ +
+ +
+
+

Navigation / Links

+ +

Copyright / License

+ +

Imprint

+ +
+
+
+ +
+
+ + + +
+ + + diff --git a/www/map.js.en b/www/map.js.en new file mode 100644 index 0000000..3f9663c --- /dev/null +++ b/www/map.js.en @@ -0,0 +1,221 @@ +/********************************************************************** + * map.js * + * script for map specific functions and setup * + **********************************************************************/ + +/* License + Copyright 2014 Kasper D. Fischer + + This program is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the Free + Software Foundation, either version 3 of the License, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License along + with this program. If not, see http://www.gnu.org/licenses/. + + $Id$ +*/ + +/* add station marker */ +function addStationMarker(id, lat, lng, station) { + var marker = L.triangleMarker(L.latLng(lat, lng), + { + gradient: true, + fillColor: config['station']['markerColor'], + fillOpacity: config['station']['markerOpacity'], + color: config['station']['markerColor'], + weight: 1, + opacity: 1, + radius: config['station']['markerSize'][id] || config['station']['markerSize']['default'], + className: id+' stationMarker', + }); + marker.bindLabel('Station '+station); + stationLayer.addLayer(marker); + stationTable[id] = marker; +}; + +/* add event marker */ +function addEventMarker(id, lat, lng, mag, type) { + if ( eventTable[id] ) { + return eventTable[id]; + } else { + var markerOptions = { + gradient: true, + dropShadow: false, + fillColor: config['event']['markerColor'], + fillOpacity: config['event']['markerOpacity'], + color: config['event']['markerColor'], + weight: 0, + opacity: 1, + className: id+' eventMarker', + radius: mag2radius(mag) + }; + var marker; + switch ( type ) { + case 'earthquake': + marker = L.starMarker(L.latLng(lat, lng), markerOptions); + break; + case 'explosion': + markerOptions['numberOfSides'] = 6; + markerOptions['radius'] = 2.0*markerOptions['radius']; + markerOptions['innerRadius'] = 0.3*markerOptions['radius']; + marker = L.regularPolygonMarker(L.latLng(lat, lng), markerOptions); + break; + case 'quarry blast': + markerOptions['numberOfPoints'] = 7; + markerOptions['innerRadius'] = 0.3*markerOptions['radius']; + marker = L.starMarker(L.latLng(lat, lng), markerOptions); + break; + default: + marker = L.circleMarker(L.latLng(lat, lng), markerOptions); + }; + eventLayer.addLayer(marker); + eventTable[id] = marker; + return marker; + }; +}; + +/* handle to show events on map */ +function initMapLink() { + $("#eventstable > tbody > tr > td > a.map-link").off('click'); + $("#eventstable > tbody > tr > td > a.map-link").on('click' , function(){ + var highlightStyle = { + color: config['event']['markerColorH'], + fillColor: config['event']['markerColorH'], + fillOpacity: 1, + className: $(this).attr('eventid') + } + var normalStyle = { + fillColor: config['event']['markerColor'], + fillOpacity: config['event']['markerOpacity'], + color: config['event']['markerColor'] + }; + // mark currently selected link and remove class selected from all other links + // set everything to normal state + $(this).addClass('selected-now'); + $("#eventstable > tbody > tr:not(.filtered) > td > a.map-link:not(.selected-now)").each(function(){ + $(this).removeClass('selected'); + $(this).text('Karte'); + eventTable[$(this).attr('eventid')].setStyle(normalStyle); + }); + // switch event of first row to normalStyle if it is not the selected one + ( $(this).hasClass('first') ) ? null : eventTable[$("#eventstable > tbody > tr:not(.filtered)").first().find("a.map-link").attr("eventid")].setStyle(normalStyle); + $(this).each(function(){ + $(this).removeClass('selected-now'); + // selected -> unselected + if ( $(this).hasClass('selected') ) { + $(this).removeClass('selected'); + $(this).text('Karte'); + map.setView(config['map']['centerDefault'], config['map']['zoomDefault']); + eventTable[$(this).attr('eventid')].setStyle(normalStyle); + highlightFirstEvent(); + // unselected -> selected + } else { + $(this).addClass('selected'); + $(this).text('at focus (red)'); + map.setView(eventTable[$(this).attr('eventid')].getLatLng(), config['map']['zoomFocus']); + eventTable[$(this).attr('eventid')].setStyle(highlightStyle) + }; + }); + return false; + }); +}; + +/********************************************************************** + * document ready * + **********************************************************************/ +$(document).ready(function() { + + // create a map in the "map" div, set the view to a given place and zoom + map = L.map('map', { zoomControl: false, worldCopyJump: true }).setView(config['map']['centerDefault'], config['map']['zoomDefault']); + new L.Control.Zoom({ position: 'topright' }).addTo(map); + new L.control.scale({position: 'bottomright', imperial: false}).addTo(map); + + // create baselayer + switch ( config['map']['baselayer'] ) { + case 'osmde': // add OpenStreetMap.DE tile layer + L.tileLayer('http://{s}.tile.openstreetmap.de/tiles/osmde/{z}/{x}/{y}.png', + { + attribution: '© OpenStreetMap contributors, CC-BY-SA', + }).addTo(map); + break; + case 'esrigray': // add ESRI Grayscale World Map (neither city nor road names) + L.tileLayer('//server.arcgisonline.com/ArcGIS/rest/services/Canvas/World_Light_Gray_Base/MapServer/tile/{z}/{y}/{x}', + { + attribution: 'Tiles © Esri — Esri, DeLorme, NAVTEQ', + maxZoom: 16 + }).addTo(map); + break; + case 'aerial': // add ESRI WordImagery tile layer + L.tileLayer('http://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}', + { + attribution: 'Tiles © Esri — Source: Esri, i-cubed, USDA, USGS, AEX, GeoEye, Getmapping, Aerogrid, IGN, IGP, UPR-EGP, and the GIS User Community' + }).addTo(map); + break; + case 'mapquestgray': // add MapQuestOSM tile layer + L.tileLayer.grayscale('http://otile{s}.mqcdn.com/tiles/1.0.0/map/{z}/{x}/{y}.jpg', + { + subdomains: '1234', + detectRetina: true, + attribution: 'Map data © OpenStreetMap contributors, CC-BY-SA | Tiles Courtesy of MapQuest ', + }).addTo(map); + break; + case 'mapquest': // add MapQuestOSM tile layer + null; + default: + L.tileLayer('http://otile{s}.mqcdn.com/tiles/1.0.0/map/{z}/{x}/{y}.jpg', + { + subdomains: '1234', + detectRetina: true, + attribution: 'Map data © OpenStreetMap contributors, CC-BY-SA | Tiles Courtesy of MapQuest ', + }).addTo(map); + }; + + // create station and event layer + // stationLayer = L.geoJson().addTo(map); + stationLayer = new L.MarkerGroup().addTo(map); + eventLayer = new L.MarkerGroup().addTo(map); + + // load events + ajaxLoadEvents('', '', '', 'events.xml'); + ajaxLoadEvents(); + specialEvents.map(function(id) { + ajaxLoadEvents('', '', id) + }); + toggleFilteredMarkers(); + + // bind popupopen event + map.on('popupopen', function() { + // convert date/time to localtime + $("div.leaflet-popup span.utctime").each(function(){$(this).addClass("localtime").removeClass("utctime");$.localtime.formatObject($(this), "dd.MM.yyyy - HH:mm")}); + openMarkerID = $("div.leaflet-popup h3").attr("eventid"); + if ( openMarkerID ) { + // update city in popup + $("div.leaflet-popup h3").text(geolocationTable[openMarkerID]); + // highlight event in table and show details + // highlightEvent(eventid); + $('#eventstable > tbody > tr > td > a.toggle').each(function() { + if ( $(this).attr('eventid') == openMarkerID ) { + $(this)[0].click(); + }; + }); + }; + }); + map.on('popupclose', function() { + $('#eventstable > tbody > tr > td > a.toggle').each(function() { + if ( $(this).attr('eventid') == openMarkerID ) { + $(this)[0].click(); + }; + }); + }); + + // print icon + // L.easyPrint().addTo(map); + +}); diff --git a/www/stations.js.en b/www/stations.js.en new file mode 100644 index 0000000..5d6c1ba --- /dev/null +++ b/www/stations.js.en @@ -0,0 +1,234 @@ +/********************************************************************** + * stations.js * + * script for station specific functions and setup * + **********************************************************************/ + +/* License + Copyright 2014 Kasper D. Fischer + + This program is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the Free + Software Foundation, either version 3 of the License, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License along + with this program. If not, see http://www.gnu.org/licenses/. + + $Id$ +*/ + +/* Load the stations using ajax */ +function loadStations(stime, etime) { + var mapBounds = map.getBounds(); + var N = mapBounds.getNorth(); + var E = mapBounds.getEast(); + var S = mapBounds.getSouth(); + var W = mapBounds.getWest(); + if ( !stime ) { + var stime = new Date(); + stime.setDate(stime.getDate()-config['map']['timespan']); + }; + if ( !etime ) { + var etime = new Date(); + etime.setDate(etime.getDate()+1); + }; + var request_data = { + endafter: sprintf("%d-%02d-%02d", stime.getFullYear(), stime.getMonth()+1, stime.getDate()), + startbefore: sprintf("%d-%02d-%02d", etime.getFullYear(), etime.getMonth()+1, etime.getDate()), + level: 'channel', + minlat: S-config['map']['latlngDelta'], + maxlat: N+config['map']['latlngDelta'], + minlon: W-config['map']['latlngDelta'], + maxlon: E+config['map']['latlngDelta'], + }; + $.ajax({ + type: "GET", + url: config['ajax']['stationURL'], + dataType: "xml", + data: request_data, + success: function (xml) { + $(xml).find('Network').each(function () { + var network = $(this).attr('code'); + if ( $.inArray(network, config['station']['networkBlacklist'])<0 ) { + $(this).find('Station').each(function () { + var station = $(this).attr('code'), + lat = $(this).find('Latitude:first').text(), + lng = $(this).find('Longitude:first').text(), + stationID = network+'_'+station, + stationText = network+'.'+station; + if ( !stationTable[stationID] ) { + // general station info (1st line) + var row = sprintf('%s%s%7.4f%7.4f' , network, station, Number(lat), Number(lng)); + // setting up network details (2nd line) + row += sprintf('%s', networkText[network] || ''); + row += ( $.inArray(station, bochumStation)+1 ) ? '
Operator: Ruhr-University Bochum' : '' ; + if ( network == 'RN' || network == 'X5' || $.inArray(station, bochumStation)+1 ) { + // setting up station details (3rd line) + row += ''; + row += stationDetails(station, network, lat, lng, stationID, stationText, $(this)); + row += ''; + // setting up download links (4th line) + var URL, fdsnxmlURL, fdsnxmlRespURL, sc3mlURL, sc3mlRespURL, dlsvURL; + URL = sprintf('%s?network=%s&station=%s', config['ajax']['stationURL'], network, station); + fdsnxmlURL = URL + '&level=station&format=xml'; + fdsnxmlRespURL = URL + '&level=response&format=xml'; + sc3mlURL = URL + '&level=station&format=sc3ml'; + sc3mlRespURL = URL + '&level=response&format=sc3ml'; + dlsvFile = sprintf('%s_%s.dlsv', network.toUpperCase(), station.toUpperCase()); + row += '' + + sprintf('Download details: FDSNxml or SC3ml
', stationID, fdsnxmlURL, stationID, sc3mlURL) + + sprintf('Response files: FDSNxml, SC3ml ', stationID, fdsnxmlRespURL, stationID, sc3mlRespURL) + + sprintf('or datalessSEED', config['ajax']['dlsvURL'] + '/' + dlsvFile, dlsvFile.toLowerCase()) + + ''; + } + else { + row += 'Kontaktieren Sie den '; + row += ( networkURL[network.toUpperCase()] ) ? 'Netzwerkkoordinator' : 'Netzwerkkoordinator'; + row += ' für weitere Details.'; + }; + $('#stationstable tbody').append(row); + addStationMarker(stationID, Number(lat), Number(lng), stationText.toUpperCase()); + }; + }); + }; + }); + }, + complete: function () { + initStationTable(); + var sort = [[0,0],[1,0]]; + $("#stationstable").trigger("update", [true]); + $("#stationstable").trigger("updateCache"); + $("#stationstable").trigger("sorton", [sort]); + $("#stationstable > tbody > tr:even").addClass("odd"); + $("#stationstable > tbody > tr:odd").addClass("even"); + stationLayer.bringToFront(); + }, + error: function( jqxhr, textStatus, error ) { + var err = textStatus + ", " + error; + console.log( "Request Failed: " + err ); + } + }); + // create stations csv download link + request_data['format'] = 'text'; + $('#stations-csv-link').attr('href', config['ajax']['stationURL']+'?'+$.param(request_data)); +}; + +/* format station Details */ +function stationDetails(station, network, lat, lng, stationId, stationText, stationObject) { + var output; + var elevation = stationObject.find('Elevation:first').text(); + var name = stationObject.find('Site > Name').text(); + output = '
'
+		+ name + '
' + + 'Position: ' + lat + '°N ' + lng + '°E, height: ' + elevation + ' m a.s.l.
'; + stationObject.find('Channel').each(function() { + var code = $(this).attr('code'); + var sensor = $(this).find('Sensor > Type').text().split(',')[0]; + var sampleRate = $(this).find('SampleRate').text(); + output += '
Chanel ' + code + ', Samplingrate ' + sampleRate + ' Hz, Sensor ' + sensor; + }); + output += '
'; + return output; +}; + +/* initStationTable */ +function initStationTable() { + // tablesorter for station list + $("#stationstable").tablesorter( + { + theme : 'blue', + cssChildRow: "tablesorter-childRow", // this is the default setting + widgets: ["uitheme", "zebra", "filter", "pager"], // initialize zebra and filter widgets, "scroller" + widgetOptions: { + // output default: '{page}/{totalPages}' + // possible variables: {page}, {totalPages}, {filteredPages}, {startRow}, {endRow}, {filteredRows} and {totalRows} + pager_output: '# {startRow} - {endRow} ({totalRows}) | page {page} ({totalPages})', + // apply disabled classname to the pager arrows when the rows at either extreme is visible + pager_updateArrows: true, + // starting page of the pager (zero based index) + pager_startPage: 0, + // Number of visible rows + pager_size: 35, + // Save pager page & size if the storage script is loaded (requires $.tablesorter.storage in jquery.tablesorter.widgets.js) + pager_savePages: true, + // if true, the table will remain the same height no matter how many records are displayed. The space is made up by an empty + // table row set to a height to compensate; default is false + pager_fixedHeight: false, + // remove rows from the table to speed up the sort of large tables. + // setting this to false, only hides the non-visible rows; needed if you plan to add/remove rows with the pager enabled. + pager_removeRows: false, + // css class names of pager arrows + pager_css: { + container : 'stations-tablesorter-pager', + errorRow : 'stations-tablesorter-errorRow', // error information row (don't include period at beginning) + disabled : 'disabled' // class added to arrows @ extremes (i.e. prev/first arrows "disabled" on first page) + }, + // jQuery pager selectors + pager_selectors: { + container : '.stationspager', // target the pager markup (wrapper) + first : '.stationsfirst', // go to first page arrow + prev : '.stationsprev', // previous page arrow + next : '.stationsnext', // next page arrow + last : '.stationslast', // go to last page arrow + goto : '.stationsgotoPage', // go to page selector - select dropdown that sets the current page + pageDisplay : '.stationspagedisplay', // location of where the "output" is displayed + pageSize : '.stationspagesize' // page size selector - select dropdown that sets the "size" option + }, + + filter_childRows : true, + filter_cssFilter : 'stations-tablesorter-filter', + filter_startsWith : false, + filter_ignoreCase : true, + scroller_height: $('div.map').height() - 250, + scroller_barWidth: 10, + scroller_jumpToHeader: false, + sortList: "[[0,0], [1,0]]", + resort: true, + showProcessing: true, + } + }); + // hide child rows + $('#stationstable > tbody > tr.tablesorter-childRow > td').hide(); + // update map after filtering + // $('#stationsstable').bind('filterEnd', function(){ + // toggleFilteredMarkers(); + // }); +}; + +/********************************************************************** + * document ready * + **********************************************************************/ +$(document).ready(function() { + loadStations(); + // show / hide station info + $('#stationstable').delegate('.toggle', 'click' , function(){ + // toggle visibility of selected row + $(this).closest('tr').nextUntil('tr.tablesorter-hasChildRow').find('td').toggle('slow'); + // mark currently selected row and remove class selected from all other rows + // hide other rows + $(this).closest('tr').nextUntil('tr.tablesorter-hasChildRow').find('td').addClass('selected-now'); + $(this).closest('tbody').find('td.selected').each(function(){ + if ( ! $(this).hasClass('selected-now') ) { + $(this).hide(); + $(this).removeClass('selected'); + }; + }); + $(this).closest('tr').nextUntil('tr.tablesorter-hasChildRow').find('td').each(function(){ + $(this).removeClass('selected-now'); + var selected = $(this).hasClass('selected'); + if ( selected ) { + $(this).removeClass('selected'); + //highlightFirstEvent(); + } else { + $(this).addClass('selected'); + //toggleHighlightStation($(this).attr('stationid')); + }; + }); + return false; + }); +});