Compare commits
No commits in common. "release/r20140505" and "main" have entirely different histories.
release/r2
...
main
46
.gitattributes
vendored
@ -1,17 +1,33 @@
|
||||
* text=auto !eol
|
||||
www/TileLayer.Grayscale.js -text
|
||||
www/first.png -text
|
||||
www/jquery.localtime-0.9.1.min.js -text
|
||||
www/jquery.tablesorter.min.js -text
|
||||
www/jquery.tablesorter.pager.css -text
|
||||
www/jquery.tablesorter.pager.min.js -text
|
||||
www/jquery.tablesorter.widgets.min.js -text
|
||||
www/last.png -text
|
||||
www/leaflet.css -text
|
||||
www/leaflet.js -text
|
||||
scripts/mkEvents.csh -text
|
||||
wsgi/showEnv.py -text
|
||||
www/.htaccess -text
|
||||
www/copyright.inc.de -text
|
||||
www/external/TileLayer.Grayscale.js -text
|
||||
www/external/css/dvf.css -text
|
||||
www/external/css/leaflet.label.css -text
|
||||
www/external/easyPrint.css -text
|
||||
www/external/first.png -text
|
||||
www/external/jQuery.print.js -text
|
||||
www/external/jquery.localtime-0.9.1.min.js -text
|
||||
www/external/jquery.tablesorter.min.js -text
|
||||
www/external/jquery.tablesorter.pager.css -text
|
||||
www/external/jquery.tablesorter.pager.min.js -text
|
||||
www/external/jquery.tablesorter.widgets.min.js -text
|
||||
www/external/last.png -text
|
||||
www/external/leaflet-dvf.markers.min.js -text
|
||||
www/external/leaflet.css -text
|
||||
www/external/leaflet.easyPrint.js -text
|
||||
www/external/leaflet.js -text
|
||||
www/external/leaflet.label.js -text
|
||||
www/external/next.png -text
|
||||
www/external/prev.png -text
|
||||
www/external/print.png -text
|
||||
www/external/sprintf.min.js -text
|
||||
www/external/theme.blue.css -text
|
||||
www/external/widget-pager.js -text
|
||||
www/impressum.inc.de -text
|
||||
www/info.inc.de -text
|
||||
www/logo_RUB_155x30.png -text
|
||||
www/next.png -text
|
||||
www/prev.png -text
|
||||
www/sprintf.min.js -text
|
||||
www/theme.blue.css -text
|
||||
www/widget-pager.js -text
|
||||
www/more.inc.de -text
|
||||
www/spinner.gif -text
|
||||
|
56
.gitignore
vendored
@ -1,2 +1,56 @@
|
||||
www/event.xml
|
||||
## Visual Studio Code
|
||||
# Visual Studio Code files
|
||||
.vscode/*
|
||||
!.vscode/settings.json
|
||||
!.vscode/tasks.json
|
||||
!.vscode/launch.json
|
||||
!.vscode/extensions.json
|
||||
*.code-workspace
|
||||
|
||||
# Local History for Visual Studio Code
|
||||
.history/
|
||||
|
||||
# General
|
||||
.DS_Store
|
||||
.AppleDouble
|
||||
.LSOverride
|
||||
|
||||
# Icon must end with two \r
|
||||
Icon
|
||||
|
||||
## MacOS / OSX
|
||||
# Thumbnails
|
||||
._*
|
||||
|
||||
# Files that might appear in the root of a volume
|
||||
.DocumentRevisions-V100
|
||||
.fseventsd
|
||||
.Spotlight-V100
|
||||
.TemporaryItems
|
||||
.Trashes
|
||||
.VolumeIcon.icns
|
||||
.com.apple.timemachine.donotpresent
|
||||
|
||||
# Directories potentially created on remote AFP share
|
||||
.AppleDB
|
||||
.AppleDesktop
|
||||
Network Trash Folder
|
||||
Temporary Items
|
||||
.apdisk
|
||||
|
||||
## Vagrant
|
||||
.vagrant/
|
||||
|
||||
# Log files (if you are creating logs in debug mode, uncomment this)
|
||||
# *.log
|
||||
|
||||
## Project Files
|
||||
wsgi/.idea
|
||||
www/dlsv
|
||||
www/stations.xml
|
||||
www/index.html
|
||||
www/data/events.xml
|
||||
www/data/geolocation.js
|
||||
scripts/*.json
|
||||
scripts/*.xml
|
||||
|
||||
|
13
Dockerfile
Normal file
@ -0,0 +1,13 @@
|
||||
# Version: v1.3 (2023-04-17)
|
||||
FROM nginx:alpine
|
||||
|
||||
# set labels
|
||||
LABEL org.opencontainers.image.authors="kasper.fischer@rub.de"
|
||||
|
||||
# copy nginx config files
|
||||
COPY nginx/nginx.conf /etc/nginx/nginx.conf
|
||||
COPY nginx/mime.types /etc/nginx/mime.types
|
||||
COPY nginx/default.conf /etc/nginx/conf.d/default.conf
|
||||
|
||||
# copy webpage content
|
||||
COPY www /usr/share/nginx/html/map
|
16
Vagrantfile
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
Vagrant.configure("2") do |config|
|
||||
config.vm.box = "ubuntu/jammy64"
|
||||
config.vm.synced_folder ".", "/vagrant"
|
||||
config.vm.network(:forwarded_port, guest: 80, host: 8888)
|
||||
|
||||
config.vm.provision :shell, inline: <<-SHELL
|
||||
sudo apt-get -y update
|
||||
sudo apt-get -y install nginx
|
||||
|
||||
echo "Starting nginx..."
|
||||
sudo ln -s /vagrant/www /var/www/html/map
|
||||
sudo cp /vagrant/www/index.html.en /vagrant/www/index.html
|
||||
sudo useradd -s /bin/false nginx
|
||||
sudo service nginx restart
|
||||
SHELL
|
||||
end
|
19
docker-compose.yaml
Normal file
@ -0,0 +1,19 @@
|
||||
version: "3.9"
|
||||
|
||||
networks:
|
||||
seisobs:
|
||||
external: false
|
||||
|
||||
services:
|
||||
map:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
image: seisobs-map:v1.1
|
||||
networks:
|
||||
- seisobs
|
||||
volumes:
|
||||
- ./www/data:/usr/share/nginx/html/map/data:ro
|
||||
ports:
|
||||
- "${SEISOBS_MAPPORT}:80"
|
||||
restart: unless-stopped
|
76
nginx/default.conf
Normal file
@ -0,0 +1,76 @@
|
||||
# Version: v1.3 (2023-04-17)
|
||||
server {
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
server_name localhost;
|
||||
|
||||
#charset koi8-r;
|
||||
#access_log /var/log/nginx/host.access.log main;
|
||||
set $first_language $http_accept_language;
|
||||
if ($http_accept_language ~* '^(.+?),') {
|
||||
set $first_language $1;
|
||||
}
|
||||
|
||||
set $language_suffix 'en';
|
||||
if ($first_language ~* 'de') {
|
||||
set $language_suffix 'de';
|
||||
}
|
||||
|
||||
#rewrite rules to /map/
|
||||
rewrite ^(.*)/index(\.html)*$ /map/index.html.$language_suffix last;
|
||||
rewrite ^/favicon.ico$ /map/favicon.ico last;
|
||||
rewrite ^/map$ /map/ last;
|
||||
rewrite ^/map.js$ /map/map.js last;
|
||||
rewrite ^/karte$ /map/ last;
|
||||
rewrite ^/karte/$ /map/ last;
|
||||
rewrite ^/karte/(.*)$ /map/$1 last;
|
||||
|
||||
if ($uri !~ "^/map") {
|
||||
rewrite ^(.*)/(.*)$ /map$1/$2 last;
|
||||
}
|
||||
|
||||
#location /map {
|
||||
# root /usr/share/nginx/html/;
|
||||
# index index.html.$language_suffix index.html;
|
||||
# #try_files $uri.$language_suffix $uri.html.$language_suffix $uri.html $uri index.html.$language_suffix index.html;
|
||||
#}
|
||||
|
||||
location / {
|
||||
root /usr/share/nginx/html/;
|
||||
index index.html.$language_suffix index.html;
|
||||
|
||||
}
|
||||
|
||||
#error_page 404 /404.html;
|
||||
|
||||
# redirect server error pages to the static page /50x.html
|
||||
#
|
||||
error_page 500 502 503 504 /50x.html;
|
||||
location = /50x.html {
|
||||
root /usr/share/nginx/html;
|
||||
}
|
||||
|
||||
# proxy the PHP scripts to Apache listening on 127.0.0.1:80
|
||||
#
|
||||
#location ~ \.php$ {
|
||||
# proxy_pass http://127.0.0.1;
|
||||
#}
|
||||
|
||||
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
|
||||
#
|
||||
#location ~ \.php$ {
|
||||
# root html;
|
||||
# fastcgi_pass 127.0.0.1:9000;
|
||||
# fastcgi_index index.php;
|
||||
# fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
|
||||
# include fastcgi_params;
|
||||
#}
|
||||
|
||||
# deny access to .htaccess files, if Apache's document root
|
||||
# concurs with nginx's one
|
||||
#
|
||||
#location ~ /\.ht {
|
||||
# deny all;
|
||||
#}
|
||||
}
|
||||
|
98
nginx/mime.types
Normal file
@ -0,0 +1,98 @@
|
||||
|
||||
types {
|
||||
text/html html htm shtml de en;
|
||||
text/css css;
|
||||
text/xml xml;
|
||||
image/gif gif;
|
||||
image/jpeg jpeg jpg;
|
||||
application/javascript js;
|
||||
application/atom+xml atom;
|
||||
application/rss+xml rss;
|
||||
|
||||
text/mathml mml;
|
||||
text/plain txt;
|
||||
text/vnd.sun.j2me.app-descriptor jad;
|
||||
text/vnd.wap.wml wml;
|
||||
text/x-component htc;
|
||||
|
||||
image/png png;
|
||||
image/svg+xml svg svgz;
|
||||
image/tiff tif tiff;
|
||||
image/vnd.wap.wbmp wbmp;
|
||||
image/webp webp;
|
||||
image/x-icon ico;
|
||||
image/x-jng jng;
|
||||
image/x-ms-bmp bmp;
|
||||
|
||||
font/woff woff;
|
||||
font/woff2 woff2;
|
||||
|
||||
application/java-archive jar war ear;
|
||||
application/json json;
|
||||
application/mac-binhex40 hqx;
|
||||
application/msword doc;
|
||||
application/pdf pdf;
|
||||
application/postscript ps eps ai;
|
||||
application/rtf rtf;
|
||||
application/vnd.apple.mpegurl m3u8;
|
||||
application/vnd.google-earth.kml+xml kml;
|
||||
application/vnd.google-earth.kmz kmz;
|
||||
application/vnd.ms-excel xls;
|
||||
application/vnd.ms-fontobject eot;
|
||||
application/vnd.ms-powerpoint ppt;
|
||||
application/vnd.oasis.opendocument.graphics odg;
|
||||
application/vnd.oasis.opendocument.presentation odp;
|
||||
application/vnd.oasis.opendocument.spreadsheet ods;
|
||||
application/vnd.oasis.opendocument.text odt;
|
||||
application/vnd.openxmlformats-officedocument.presentationml.presentation
|
||||
pptx;
|
||||
application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
|
||||
xlsx;
|
||||
application/vnd.openxmlformats-officedocument.wordprocessingml.document
|
||||
docx;
|
||||
application/vnd.wap.wmlc wmlc;
|
||||
application/wasm wasm;
|
||||
application/x-7z-compressed 7z;
|
||||
application/x-cocoa cco;
|
||||
application/x-java-archive-diff jardiff;
|
||||
application/x-java-jnlp-file jnlp;
|
||||
application/x-makeself run;
|
||||
application/x-perl pl pm;
|
||||
application/x-pilot prc pdb;
|
||||
application/x-rar-compressed rar;
|
||||
application/x-redhat-package-manager rpm;
|
||||
application/x-sea sea;
|
||||
application/x-shockwave-flash swf;
|
||||
application/x-stuffit sit;
|
||||
application/x-tcl tcl tk;
|
||||
application/x-x509-ca-cert der pem crt;
|
||||
application/x-xpinstall xpi;
|
||||
application/xhtml+xml xhtml;
|
||||
application/xspf+xml xspf;
|
||||
application/zip zip;
|
||||
|
||||
application/octet-stream bin exe dll;
|
||||
application/octet-stream deb;
|
||||
application/octet-stream dmg;
|
||||
application/octet-stream iso img;
|
||||
application/octet-stream msi msp msm;
|
||||
|
||||
audio/midi mid midi kar;
|
||||
audio/mpeg mp3;
|
||||
audio/ogg ogg;
|
||||
audio/x-m4a m4a;
|
||||
audio/x-realaudio ra;
|
||||
|
||||
video/3gpp 3gpp 3gp;
|
||||
video/mp2t ts;
|
||||
video/mp4 mp4;
|
||||
video/mpeg mpeg mpg;
|
||||
video/quicktime mov;
|
||||
video/webm webm;
|
||||
video/x-flv flv;
|
||||
video/x-m4v m4v;
|
||||
video/x-mng mng;
|
||||
video/x-ms-asf asx asf;
|
||||
video/x-ms-wmv wmv;
|
||||
video/x-msvideo avi;
|
||||
}
|
32
nginx/nginx.conf
Normal file
@ -0,0 +1,32 @@
|
||||
# Version: v1.3 (2023-04-17)
|
||||
user nginx;
|
||||
worker_processes 1;
|
||||
|
||||
error_log /var/log/nginx/error.log warn;
|
||||
pid /var/run/nginx.pid;
|
||||
|
||||
|
||||
events {
|
||||
worker_connections 1024;
|
||||
}
|
||||
|
||||
|
||||
http {
|
||||
include /etc/nginx/mime.types;
|
||||
default_type application/octet-stream;
|
||||
|
||||
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
|
||||
'$status $body_bytes_sent "$http_referer" '
|
||||
'"$http_user_agent" "$http_x_forwarded_for"';
|
||||
|
||||
access_log /var/log/nginx/access.log main;
|
||||
|
||||
sendfile on;
|
||||
#tcp_nopush on;
|
||||
|
||||
keepalive_timeout 65;
|
||||
|
||||
#gzip on;
|
||||
|
||||
include /etc/nginx/conf.d/*.conf;
|
||||
}
|
15
scripts/fetchEvents.sh
Executable file
@ -0,0 +1,15 @@
|
||||
#!/bin/bash
|
||||
# Version: v1.3 (2023-04-17)
|
||||
|
||||
# get starting date
|
||||
# find gdate or date command ( OSX: brew install coreutils)
|
||||
# the date command on OSX is not compatible to the linux date command
|
||||
datecmd=$((which gdate || which date )| grep bin)
|
||||
STIME="${1:-$(${datecmd} -d 6-month-ago +%Y-%m-%d)}"
|
||||
STIME="${STIME:-$(date +%Y-%m-%d)}"
|
||||
|
||||
# get output filename
|
||||
OUTPUT="${2:--}"
|
||||
|
||||
# fetch events
|
||||
curl -s -o ${OUTPUT} "https://fdsnws.geophysik.ruhr-uni-bochum.de/fdsnws/event/1/query?starttime=${STIME}&minlat=50.0&maxlat=53.0&minlon=4.0&maxlon=10.0&minmag=0.7"
|
157
scripts/mkGeolocationTable.py
Executable file
@ -0,0 +1,157 @@
|
||||
#! /usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
'''
|
||||
Script to lookup city names of events with Nominatim service
|
||||
|
||||
The input should be an valid quakeML file passed to stdin.
|
||||
The output will will be a javascript structure to be included in the
|
||||
SeisObs map service.
|
||||
|
||||
The script should be updated regularly keep the total number of all
|
||||
AJAX calls to the Nominatim service small, e. g. :
|
||||
curl -s "https://fdsnws.geophysik.ruhr-uni-bochum.de/fdsnws/event/1/query?minlat=50&maxlat=54&minlon=3&maxlon=10&minmag=1" | mkGeolocationTable.py > geolocationTable.js
|
||||
|
||||
Version: v1.3 (2023-04-17)
|
||||
|
||||
License
|
||||
Copyright 2020-2021 Kasper D. Fischer <kasper.fischer@rub.de>
|
||||
|
||||
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/.
|
||||
'''
|
||||
|
||||
def mkGeolocationTable(file=''):
|
||||
## imports
|
||||
|
||||
# XML ElementTree
|
||||
try:
|
||||
import xml.etree.cElementTree as ET
|
||||
except ImportError:
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
# json
|
||||
import json as JSON
|
||||
|
||||
# sys stdin
|
||||
from sys import stdin
|
||||
|
||||
# geopy
|
||||
from geopy.geocoders import Photon
|
||||
from geopy.extra.rate_limiter import RateLimiter
|
||||
from geopy.exc import GeocoderServiceError
|
||||
|
||||
## constants
|
||||
URL = 'https://photon.komoot.io/reverse?lon={lng:.3f}&lat={lat:.3f}&limit=10'
|
||||
NAMESPACES = {'sc3': 'http://geofon.gfz-potsdam.de/ns/seiscomp3-schema/0.7',
|
||||
'qml': 'http://quakeml.org/xmlns/bed/1.2'}
|
||||
|
||||
# try loading the file
|
||||
geolocationTable = {}
|
||||
if file :
|
||||
try:
|
||||
jsonfile = open(file)
|
||||
jsonfileContent = jsonfile.read().split('=')[1].replace(';', '')
|
||||
geolocationTable = JSON.loads(jsonfileContent)
|
||||
except:
|
||||
geolocationTable = {}
|
||||
logging.warning('Could not parse file %s' %file)
|
||||
|
||||
# parse event.xml
|
||||
DOM = ET.parse(stdin).getroot()
|
||||
geolocator = Photon()
|
||||
reverse_geolocate = RateLimiter(geolocator.reverse, min_delay_seconds=2)
|
||||
|
||||
# iterate over all events
|
||||
count = 0
|
||||
for event in DOM.iterfind('qml:eventParameters/qml:event', NAMESPACES):
|
||||
count += 1
|
||||
publicID = event.attrib['publicID'].split('/')[2]
|
||||
lat = float(event.find('./qml:origin/qml:latitude/qml:value', NAMESPACES).text)
|
||||
lng = float(event.find('./qml:origin/qml:longitude/qml:value', NAMESPACES).text)
|
||||
evaluationMode = event.find('./qml:origin/qml:evaluationMode', NAMESPACES).text
|
||||
|
||||
if publicID in geolocationTable:
|
||||
logging.warning('Skipping cached event {id}'.format(id=publicID))
|
||||
elif evaluationMode == 'automatic':
|
||||
logging.warning('Skipping automatic event {id}'.format(id=publicID))
|
||||
else:
|
||||
logging.info('Processing event {id}'.format(id=publicID))
|
||||
try:
|
||||
locations = reverse_geolocate("{lat:.3f}, {lng:.3f}".format(lat=lat, lng=lng),exactly_one=False,limit=10)
|
||||
except GeocoderServiceError:
|
||||
logging.warning('Reverse Geolocation failed. Skipping event.')
|
||||
continue
|
||||
place = []
|
||||
for location in locations:
|
||||
try:
|
||||
place = location.raw['properties']['city']
|
||||
except KeyError:
|
||||
try:
|
||||
place = location.raw['properties']['town']
|
||||
except KeyError:
|
||||
try:
|
||||
place = location.raw['properties']['village']
|
||||
except KeyError:
|
||||
try:
|
||||
place = location.raw['properties']['county']
|
||||
except KeyError:
|
||||
logging.debug('Could not extract city for event {id} at {lat:.3f} N / {lng:.3f} E (Service: {url}), trying next returned result'
|
||||
.format(id=publicID, lat=lat, lng=lng, url=URL.format(lat=lat,lng=lng)))
|
||||
logging.debug(location.raw)
|
||||
if not place:
|
||||
logging.critical('Could not extract city for event {id} at {lat:.3f} N / {lng:.3f} E (Service: {url})'
|
||||
.format(id=publicID, lat=lat, lng=lng, url=URL.format(lat=lat,lng=lng)))
|
||||
geolocationTable[publicID] = place
|
||||
|
||||
# dump json
|
||||
print('var geolocationTable = {0};'.format(JSON.dumps(geolocationTable, sort_keys=True)))
|
||||
logging.info("processed %d events", count)
|
||||
|
||||
# __main__
|
||||
if __name__ == "__main__":
|
||||
# use module logging
|
||||
import logging
|
||||
|
||||
# parse arguments
|
||||
import argparse
|
||||
versionText = 'v1.3 (2023-04-17)'
|
||||
parser = argparse.ArgumentParser(
|
||||
description='Reverse geocoding lookup of events in xml format (stdin).',
|
||||
epilog=versionText)
|
||||
parser.add_argument('-V', '--version', action='version', version=versionText,
|
||||
help="show version")
|
||||
parser.add_argument('-f', '--file', action='store', dest='file',
|
||||
help='read in JSON file containing old output.')
|
||||
group = parser.add_mutually_exclusive_group()
|
||||
group.add_argument("-v", "--verbose", action="store_true",
|
||||
help="increase output verbosity")
|
||||
group.add_argument("-q", "--quiet", action="store_true",
|
||||
help="disable output")
|
||||
group.add_argument("-d", "--debug", action="store_true",
|
||||
help="show debugging output",
|
||||
)
|
||||
cla = parser.parse_args()
|
||||
|
||||
# set logging level
|
||||
if cla.quiet:
|
||||
logging.basicConfig(format='%(levelname)s: %(message)s', level=logging.ERROR)
|
||||
elif cla.verbose:
|
||||
logging.basicConfig(format='%(levelname)s: %(message)s', level=logging.INFO)
|
||||
elif cla.debug:
|
||||
logging.basicConfig(format='%(levelname)s: %(message)s', level=logging.DEBUG)
|
||||
else:
|
||||
logging.basicConfig(format='%(levelname)s: %(message)s', level=logging.WARN)
|
||||
|
||||
# call mkGeolocationTable(...)
|
||||
mkGeolocationTable(file=cla.file)
|
21
scripts/patchVersion.sh
Executable file
@ -0,0 +1,21 @@
|
||||
#!/bin/bash
|
||||
# version: v1.3 (2023-04-17)
|
||||
function fail {
|
||||
printf '%s\n' "$1" >&2 ## Send message to stderr.
|
||||
exit "${2-1}" ## Return a code specified by $2, or 1 by default.
|
||||
}
|
||||
|
||||
if [ $# -le 1 ] ; then
|
||||
echo usage: ${0} version_string files ...
|
||||
exit 0
|
||||
fi
|
||||
version="$1"
|
||||
shift
|
||||
files="$*"
|
||||
|
||||
echo ${version} ${files}
|
||||
which sponge > /dev/null || fail "sponge util must be installed"
|
||||
|
||||
for file in ${files}; do
|
||||
sed "s/V\{5\}/${version}"/ ${file} | sponge ${file}
|
||||
done
|
405
wsgi/plotFDSN.py
Executable file
@ -0,0 +1,405 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Get waveform data from FDSN web service and create a fancy plot
|
||||
This programme runs as a script or as a WSGI application.
|
||||
|
||||
:version v1.1 (2021-10-31)
|
||||
|
||||
:license
|
||||
Copyright 2020 Kasper Fischer <kasper.fischer@ruhr-uni-bochum.de>
|
||||
|
||||
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 2 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, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
MA 02110-1301, USA.
|
||||
"""
|
||||
|
||||
|
||||
def utc2local(utctime, timezone='Europe/Berlin'):
|
||||
"""
|
||||
utc2local(utctime, timezone='Europe/Berlin')
|
||||
converts the UTCDateTime object utctime into a
|
||||
datetime object of the given timezone
|
||||
"""
|
||||
|
||||
import pytz
|
||||
|
||||
utc = pytz.utc
|
||||
local = pytz.timezone(timezone)
|
||||
utctime = utc.localize(utctime.datetime)
|
||||
return local.normalize(utctime.astimezone(local))
|
||||
|
||||
|
||||
def fancy_plot(st, wsgi=False, img_format='png', color=True):
|
||||
"""
|
||||
creating fancy plot from ObsPy stream st
|
||||
returns cStringIO object if wsgi == True
|
||||
:type st: ObsPy Stream object
|
||||
:type wsgi: bool
|
||||
:type img_format: str
|
||||
:type color: bool
|
||||
"""
|
||||
|
||||
import matplotlib as mpl
|
||||
from matplotlib.dates import date2num, AutoDateLocator, AutoDateFormatter
|
||||
|
||||
if wsgi:
|
||||
try:
|
||||
import cStringIO as StringIO
|
||||
except ImportError:
|
||||
import StringIO as StringIO
|
||||
import matplotlib.pyplot as plt
|
||||
from numpy import arange
|
||||
|
||||
# setup figure parameters
|
||||
if wsgi:
|
||||
mpl.rcParams['figure.figsize'] = [12.0, 6.75] # 16:9 aspect ratio
|
||||
else:
|
||||
mpl.rcParams['figure.figsize'] = [16.0, 9.0] # 16:9 aspect ratio
|
||||
|
||||
# get starttime, endtime, localtime and timezone
|
||||
tr = st[0]
|
||||
stime = tr.stats.starttime
|
||||
etime = tr.stats.endtime
|
||||
localtime = utc2local(stime)
|
||||
if localtime.tzname() == u'CET':
|
||||
tzname = u'MEZ'
|
||||
else:
|
||||
tzname = u'MESZ'
|
||||
tz = localtime.timetz().tzinfo
|
||||
|
||||
# create proper time vector
|
||||
d = arange(date2num(stime), date2num(etime), (date2num(etime) - date2num(stime)) / tr.stats.npts)
|
||||
|
||||
# setup time axis decorator
|
||||
locator = AutoDateLocator(interval_multiples=True, minticks=5, maxticks=8, tz=tz)
|
||||
minor_locator = AutoDateLocator(interval_multiples=True, minticks=9, maxticks=70, tz=tz)
|
||||
formatter = AutoDateFormatter(locator, tz=tz)
|
||||
formatter.scaled[1. / (24. * 60.)] = '%H:%M:%S'
|
||||
formatter.scaled[1. / (24. * 60. * 60. * 10.)] = '%H:%M:%S.%f'
|
||||
|
||||
# draw figure
|
||||
if color:
|
||||
trace_color = {'Z': 'r', 'N': 'b', 'E': 'g'}
|
||||
else:
|
||||
trace_color = {'Z': 'k', 'N': 'k', 'E': 'k'}
|
||||
|
||||
fig = plt.figure()
|
||||
|
||||
ax1 = fig.add_subplot(311)
|
||||
ax1.xaxis.set_major_locator(locator)
|
||||
ax1.xaxis.set_major_formatter(formatter)
|
||||
ax1.plot_date(d, st.select(component='Z')[0].data * 1000., trace_color['Z'], label=u'Z', tz=tz)
|
||||
plt.title(u'Station %s' % st[0].stats.station, fontsize=24)
|
||||
plt.legend(loc='upper right')
|
||||
ax1.grid(b=True)
|
||||
|
||||
ax2 = fig.add_subplot(312, sharex=ax1, sharey=ax1)
|
||||
ax2.plot_date(d, st.select(component='N')[0].data * 1000., trace_color['N'], label=u'N', tz=tz)
|
||||
ax2.grid(b=True)
|
||||
plt.ylabel(u'Geschwindigkeit [mm/s]', fontsize=16)
|
||||
plt.legend(loc='upper right')
|
||||
|
||||
ax3 = fig.add_subplot(313, sharex=ax1, sharey=ax1)
|
||||
ax3.plot_date(d, st.select(component='E')[0].data * 1000., trace_color['E'], label=u'E', tz=tz)
|
||||
ax3.grid(b=True)
|
||||
plt.legend(loc='upper right')
|
||||
|
||||
plt.xlabel(u'%s (%s)' % (localtime.strftime('%d.%m.%Y'), tzname), fontsize=16)
|
||||
ax1.minorticks_on()
|
||||
ax1.xaxis.set_minor_locator(minor_locator)
|
||||
|
||||
if wsgi:
|
||||
buf = StringIO.StringIO()
|
||||
plt.savefig(buf, format=img_format, facecolor="lightgray")
|
||||
return buf
|
||||
else:
|
||||
if cla['filename']:
|
||||
plt.savefig(cla['filename'], dpi=300, transparent=True)
|
||||
else:
|
||||
plt.show()
|
||||
|
||||
|
||||
def trace_dayplot(st, deltat = None,
|
||||
ftype='none', fmin=1.0, fmax=7.0,
|
||||
col=('b', 'r', 'g'), interval=20, outpattern='',
|
||||
wsgi=False):
|
||||
"""
|
||||
|
||||
:type st: object
|
||||
:type ftype: str
|
||||
:type fmin: float
|
||||
:type fmax: float
|
||||
:type col: tuple
|
||||
:type interval: float
|
||||
:type outpattern: str
|
||||
:type wsgi: bool
|
||||
"""
|
||||
|
||||
if wsgi:
|
||||
try:
|
||||
import cStringIO as StringIO
|
||||
except ImportError:
|
||||
import StringIO as StringIO
|
||||
|
||||
# filter
|
||||
if (ftype == 'bandpass') or (ftype == 'bandstop'):
|
||||
st.filter(ftype, freqmin=fmin, freqmax=fmax)
|
||||
elif (ftype == 'lowpass') or (ftype == 'highpass'):
|
||||
st.filter(ftype, freq=fmin)
|
||||
st.merge()
|
||||
|
||||
stime = st[0].stats.starttime
|
||||
if deltat:
|
||||
etime = stime + deltat
|
||||
else:
|
||||
etime = st[0].stats.endtime
|
||||
|
||||
# plot
|
||||
for i in range(0, len(st)):
|
||||
if wsgi:
|
||||
buf = StringIO.StringIO()
|
||||
st[i].plot(outfile=buf, format=outpattern, type='dayplot', color=col, interval=interval,
|
||||
starttime=stime, endtime=etime)
|
||||
return buf
|
||||
else:
|
||||
if outpattern != '':
|
||||
imagefile = outpattern.format(st[i].stats.network,
|
||||
st[i].stats.station,
|
||||
st[i].stats.channel,
|
||||
st[i].stats.starttime.year,
|
||||
st[i].stats.starttime.julday)
|
||||
st[i].plot(type='dayplot', color=col, interval=interval,
|
||||
outfile=imagefile)
|
||||
else:
|
||||
st[i].plot(type='dayplot', color=col, interval=interval)
|
||||
|
||||
|
||||
def get_fdsn(bulk_request, output='VEL', base_url='https://ariadne.geophysik.ruhr-uni-bochum.de'):
|
||||
"""
|
||||
Fetches waveform data from FDSN web service and returns
|
||||
instrument corrected seismogram of type given in parameter output.
|
||||
Acceptable values for output are "VEL", "DISP" and "ACC" (see ObsPy documentation)
|
||||
|
||||
:rtype : object
|
||||
:param bulk_request: list
|
||||
:param output: str
|
||||
:param base_url: str
|
||||
:return: ObsPy Stream() object
|
||||
"""
|
||||
import warnings
|
||||
from obspy.fdsn import Client
|
||||
from obspy.fdsn.header import FDSNException
|
||||
|
||||
try:
|
||||
with warnings.catch_warnings():
|
||||
warnings.simplefilter("ignore")
|
||||
client = Client(base_url=base_url, debug=False)
|
||||
st = client.get_waveforms_bulk(bulk_request, attach_response=True)
|
||||
|
||||
st.merge()
|
||||
stime = st[0].stats.starttime
|
||||
etime = st[0].stats.endtime
|
||||
for trace in st.traces:
|
||||
stime = max(stime, trace.stats.starttime)
|
||||
etime = min(etime, trace.stats.endtime)
|
||||
st.trim(starttime=stime, endtime=etime)
|
||||
|
||||
# choose 1 s taper
|
||||
taper_fraction = 1 / (etime - stime)
|
||||
for trace in st.traces:
|
||||
# filter, remove response
|
||||
trace.filter('bandpass', freqmin=0.01, freqmax=25, corners=3, zerophase=False). \
|
||||
remove_response(output=output, zero_mean=True, taper=True, taper_fraction=taper_fraction)
|
||||
return st
|
||||
except FDSNException:
|
||||
return None
|
||||
|
||||
|
||||
def main(backend=None, args=None, wsgi=False):
|
||||
"""
|
||||
Main function to create a waveform plot.
|
||||
This functions calls get_fdsn and fancy_plot to create the figure.
|
||||
If wsgi == True it returns an ioString object containing the figure.
|
||||
|
||||
:type backend: str
|
||||
:type args: dict
|
||||
:type wsgi: bool
|
||||
:rtype : object
|
||||
:param backend:
|
||||
:param args:
|
||||
:param wsgi:
|
||||
:return: ioString object with created image
|
||||
"""
|
||||
|
||||
import warnings
|
||||
import matplotlib as mpl
|
||||
|
||||
if wsgi:
|
||||
backend = 'Agg'
|
||||
if backend:
|
||||
with warnings.catch_warnings():
|
||||
warnings.simplefilter("ignore")
|
||||
mpl.use(backend)
|
||||
from obspy import UTCDateTime
|
||||
|
||||
if args:
|
||||
deltat = args['length']
|
||||
if args['stime']:
|
||||
otime = UTCDateTime(args['stime'])
|
||||
else:
|
||||
otime = UTCDateTime() - 3600. - deltat
|
||||
network = args['station'].split('.')[0]
|
||||
station = args['station'].split('.')[1]
|
||||
if args['type'] == 'dayplot':
|
||||
if network == 'Z3':
|
||||
channel = 'HHZ'
|
||||
else:
|
||||
channel = 'BHZ'
|
||||
else:
|
||||
if args['length'] < 3600.:
|
||||
channel = 'HH?'
|
||||
else:
|
||||
if network == 'Z3':
|
||||
channel = 'HH?'
|
||||
else:
|
||||
channel = 'BH?'
|
||||
else:
|
||||
otime = UTCDateTime() - 3600.
|
||||
deltat = 30
|
||||
network = 'GR'
|
||||
station = 'BUG'
|
||||
channel = 'HH?'
|
||||
|
||||
st = get_fdsn([(network, station, '*', channel, otime, otime + deltat)], base_url=args['server'])
|
||||
if st is not None:
|
||||
stime = max(st[0].stats.starttime, otime)
|
||||
etime = min(st[0].stats.endtime, otime + deltat)
|
||||
st.trim(starttime=stime, endtime=etime)
|
||||
|
||||
if wsgi:
|
||||
if args['type'] == 'dayplot':
|
||||
with warnings.catch_warnings():
|
||||
warnings.simplefilter("ignore")
|
||||
return trace_dayplot(st, outpattern=args['format'], wsgi=wsgi, deltat=deltat)
|
||||
else:
|
||||
return fancy_plot(st, wsgi=wsgi, img_format=args['format'], color=args['color'])
|
||||
else:
|
||||
if args['type'] == 'dayplot':
|
||||
with warnings.catch_warnings():
|
||||
warnings.simplefilter("ignore")
|
||||
trace_dayplot(st, wsgi=wsgi)
|
||||
else:
|
||||
fancy_plot(st, color=args['color'])
|
||||
elif not wsgi:
|
||||
warnings.warn('No data available!')
|
||||
|
||||
|
||||
def application(environ, start_response):
|
||||
"""
|
||||
Function application - Wrapper to process wsgi request
|
||||
:param environ: contains information on the wsgi environment
|
||||
:type environ: dict
|
||||
:param start_response: function to process response header by the wsgi server
|
||||
:type start_response: function
|
||||
:return: response to be sent to the client by the wsgi server
|
||||
:rtype: list
|
||||
"""
|
||||
|
||||
import os
|
||||
from cgi import FieldStorage
|
||||
|
||||
# set HOME environment variable to a directory the httpd server can write to
|
||||
# otherwise matplotlib won't work
|
||||
os.environ['HOME'] = '/tmp/wsgi-kasper'
|
||||
try:
|
||||
os.mkdir('/tmp/wsgi-kasper')
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
# fake command line arguments
|
||||
# setting needed default values
|
||||
wsgi_args = {'server': 'http://localhost/'}
|
||||
|
||||
# fill wsgi_args with environment variables
|
||||
form = FieldStorage(fp=environ['wsgi.input'], environ=environ)
|
||||
wsgi_args['station'] = form.getfirst('station', 'GR.BUG').upper()
|
||||
wsgi_args['stime'] = form.getfirst('start_time', [])
|
||||
wsgi_args['length'] = form.getfirst('length', '30')
|
||||
wsgi_args['length'] = abs(int(wsgi_args['length']))
|
||||
wsgi_args['format'] = form.getfirst('format', 'png').lower()
|
||||
if wsgi_args['format'] != 'png' and wsgi_args['format'] != 'svg':
|
||||
wsgi_args['format'] = 'png'
|
||||
wsgi_args['color'] = form.getfirst('color', 'TRUE').upper()
|
||||
if wsgi_args['color'] == 'FALSE':
|
||||
wsgi_args['color'] = False
|
||||
else:
|
||||
wsgi_args['color'] = True
|
||||
wsgi_args['type'] = form.getfirst('type', '').lower()
|
||||
if (wsgi_args['type'] != 'dayplot' and wsgi_args['type'] != 'normal') or wsgi_args['type'] == '':
|
||||
if wsgi_args['length'] < 43200:
|
||||
wsgi_args['type'] = 'normal'
|
||||
else:
|
||||
wsgi_args['type'] = 'dayplot'
|
||||
|
||||
# process the request
|
||||
buf = main(args=wsgi_args, backend='Agg', wsgi=True)
|
||||
if buf is not None:
|
||||
data = buf.getvalue()
|
||||
buf.close()
|
||||
data_length = len(data)
|
||||
|
||||
if wsgi_args['format'] == 'svg':
|
||||
wsgi_args['format'] = 'svg+xml'
|
||||
start_response('200 OK', [('Content-Type', 'image/%s' % wsgi_args['format']), ('Content-Length', '%d' % data_length)])
|
||||
return [data]
|
||||
else:
|
||||
start_response('400 Bad Request', [])
|
||||
return []
|
||||
|
||||
# __main__
|
||||
if __name__ == "__main__":
|
||||
import os
|
||||
import argparse
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
description=u'Get event waveform data of all RuhrNet stations.',
|
||||
epilog=u'$Revision$ ($Date$, $Author$)'.replace(
|
||||
"$", ""))
|
||||
parser.add_argument(u'-v', u'-V', u'--version', action='version',
|
||||
version=u'v1.1 (2021-10-31)')
|
||||
parser.add_argument(u'-u', u'--url', action='store', dest='server',
|
||||
default=u'https://ariadne.geophysik.ruhr-uni-bochum.de',
|
||||
help=u'Base URL of the FDSN web service (https://ariadne.geophysik.ruhr-uni-bochum.de).')
|
||||
parser.add_argument(u'-t', u'--type', action='store', dest='type', metavar='TYPE',
|
||||
help=u'Type of plot: normal or dayplot.')
|
||||
parser.add_argument(u'-f', u'--file', action='store', dest='filename', metavar='FILENAME',
|
||||
help=u'Save plot to file FILENAME')
|
||||
parser.add_argument(u'-c', u'--color', action='store_true', help=u'Create color plot.')
|
||||
parser.add_argument(u'-l', u'--length', action='store', type=int, default=30,
|
||||
help=u'Length of waveform window in seconds (30 s).')
|
||||
group = parser.add_mutually_exclusive_group(required=True)
|
||||
group.add_argument(u'-s', u'--start_time', dest='stime', action='store', metavar='START',
|
||||
help=u'Start time of waveform window.')
|
||||
group.add_argument(u'-e', u'--event', action='store', metavar='EVENTID',
|
||||
help=u'Get starttime from event P-phase onset at station.')
|
||||
parser.add_argument(u'station', action='store', metavar='NET.STATION',
|
||||
help=u'Station to plot.')
|
||||
|
||||
cla = vars(parser.parse_args())
|
||||
|
||||
if os.getenv('DISPLAY'):
|
||||
main(args=cla)
|
||||
else:
|
||||
main('Agg', cla)
|
19
wsgi/showEnv.py
Normal file
@ -0,0 +1,19 @@
|
||||
def application(environ, start_response):
|
||||
"""
|
||||
Function application - Wrapper to process wsgi request
|
||||
:param environ: contains information on the wsgi environment
|
||||
:type environ: dict
|
||||
:param start_response: function to process response header by the wsgi server
|
||||
:type start_response: function
|
||||
:return: response to be sent to the client by the wsgi server
|
||||
:rtype: list
|
||||
|
||||
:version: v1.2 (2022-02-23)
|
||||
"""
|
||||
|
||||
from cgi import FieldStorage
|
||||
|
||||
form = FieldStorage(fp=environ['wsgi.input'], environ=environ)
|
||||
|
||||
start_response('200 OK', [('Content-Type', 'text/html')])
|
||||
return [form]
|
116
wsgi/traceDayplot.py
Executable file
@ -0,0 +1,116 @@
|
||||
#! /usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Produce a dayplot from seismogram recordings
|
||||
|
||||
version: v1.2 (2022-02-23)
|
||||
|
||||
license: gpl3
|
||||
Copyright 2012-2020 Seismological Observatory, Ruhr-University Bochum
|
||||
http://www.gmg.ruhr-uni-bochum.de/geophysik/seisobs
|
||||
Contributors:
|
||||
Martina Rische <martina.rische@rub.de>
|
||||
Kasper D. Fischer <kasper.fischer@rub.de>
|
||||
Sebastian Wehling-Benatelli <sebastian.wehling@rub.de>
|
||||
|
||||
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/.
|
||||
"""
|
||||
|
||||
|
||||
def trace_dayplot(st, ftype='bandpass', fmin=1.0, fmax=7.0,
|
||||
col=('b', 'r', 'g'), interval=20.0, outpattern=''):
|
||||
"""
|
||||
|
||||
:type st: object
|
||||
:type ftype: str
|
||||
:type fmin: float
|
||||
:type fmax: float
|
||||
:type col: tuple
|
||||
:type interval: float
|
||||
:type outpattern: str
|
||||
"""
|
||||
|
||||
# filter
|
||||
if (ftype == 'bandpass') or (ftype == 'bandstop'):
|
||||
st.filter(ftype, freqmin=fmin, freqmax=fmax)
|
||||
elif (ftype == 'lowpass') or (ftype == 'highpass'):
|
||||
st.filter(ftype, freq=fmin)
|
||||
st.merge()
|
||||
|
||||
# plot
|
||||
for i in range(0, len(st)):
|
||||
if outpattern != '':
|
||||
imagefile = outpattern.format(st[i].stats.network,
|
||||
st[i].stats.station,
|
||||
st[i].stats.channel,
|
||||
st[i].stats.starttime.year,
|
||||
st[i].stats.starttime.julday)
|
||||
st[i].plot(type='dayplot', color=col, interval=interval,
|
||||
outfile=imagefile)
|
||||
else:
|
||||
st[i].plot(type='dayplot', color=col, interval=interval)
|
||||
|
||||
|
||||
# __main__
|
||||
if __name__ == "__main__":
|
||||
|
||||
# parse arguments
|
||||
import argparse
|
||||
from obspy.core import read
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
description='Produce filtered 24h-plot (dayplot).',
|
||||
epilog='$Rev: 403 $ ($Date: 2012-04-13 12:16:22 +0200 (Fri, 13 Apr 2012) $, $Author: kasper $)')
|
||||
parser.add_argument('-v', '-V', '--version', action='version',
|
||||
version='$Rev: 403 $ ($Date: 2012-04-13 12:16:22 +0200 (Fri, 13 Apr 2012) $, $Author: kasper $)')
|
||||
parser.add_argument('file', action='store', metavar='FILE', nargs='+',
|
||||
help='File(s) to use for the dayplot. One dayplot will be used for every file. \
|
||||
Use wildcards to use multiple file for one plot')
|
||||
parser.add_argument('-f', '--filter', action='store', dest='ftype',
|
||||
default='bandpass',
|
||||
choices=['none', 'bandpass', 'bandstop', 'lowpass', 'highpass'],
|
||||
help='Select filtertype to filter the data (default: bandpass)\
|
||||
Note: For low- and highpass only fmin is used.')
|
||||
parser.add_argument('--fmin', action='store', type=float, dest='fmin',
|
||||
default=1.0,
|
||||
help='Lower frequency of the filter in Hz (default: 1.0)')
|
||||
parser.add_argument('--fmax', action='store', type=float, dest='fmax',
|
||||
default=7.0,
|
||||
help='Upper frequency of the filter in Hz (default: 7.0)')
|
||||
parser.add_argument('-c', '--color', '--colour', action='store', dest='color',
|
||||
default=('b', 'r', 'g'),
|
||||
help='Color selection to use in the dayplot (default: brg)')
|
||||
parser.add_argument('-i', '--interval', action='store', type=int, dest='interval',
|
||||
default=20,
|
||||
help='Interval length to show in each line of the dayplot in minutes (default: 20)')
|
||||
parser.add_argument('-o', '--output', action='store', dest='outpattern',
|
||||
default='',
|
||||
help="Output filename pattern for the plot. (default: unset, show plot on screen only), \
|
||||
Use {0} to substitute network code, \
|
||||
{1} to substitute station code, \
|
||||
{2} to substitute station channel, \
|
||||
{3} to substitute year, \
|
||||
{4} to substitute doy number \
|
||||
.format (supported formats: emf, eps, pdf, png, ps, raw, rgba, svg, svgz)")
|
||||
|
||||
cla = parser.parse_args()
|
||||
if cla.fmin < 0:
|
||||
cla.fmin = -cla.fmin
|
||||
if cla.fmax < 0:
|
||||
cla.fmax = -cla.fmax
|
||||
|
||||
# call trace_dayplot(...) for each file
|
||||
for datafile in cla.file:
|
||||
trace_dayplot(read(datafile), cla.ftype, cla.fmin, cla.fmax, cla.color,
|
||||
cla.interval, cla.outpattern)
|
@ -1,51 +0,0 @@
|
||||
/*
|
||||
* L.TileLayer.Grayscale is a regular tilelayer with grayscale makeover.
|
||||
*/
|
||||
|
||||
L.TileLayer.Grayscale = L.TileLayer.extend({
|
||||
options: {
|
||||
enableCanvas: true
|
||||
},
|
||||
|
||||
initialize: function (url, options) {
|
||||
var canvasEl = document.createElement('canvas');
|
||||
if( !(canvasEl.getContext && canvasEl.getContext('2d')) ) {
|
||||
options.enableCanvas = false;
|
||||
}
|
||||
|
||||
L.TileLayer.prototype.initialize.call(this, url, options);
|
||||
},
|
||||
|
||||
_loadTile: function (tile, tilePoint) {
|
||||
tile.setAttribute('crossorigin', 'anonymous');
|
||||
L.TileLayer.prototype._loadTile.call(this, tile, tilePoint);
|
||||
},
|
||||
|
||||
_tileOnLoad: function () {
|
||||
if (this._layer.options.enableCanvas && !this.canvasContext) {
|
||||
var canvas = document.createElement("canvas");
|
||||
canvas.width = canvas.height = this._layer.options.tileSize;
|
||||
this.canvasContext = canvas.getContext("2d");
|
||||
}
|
||||
var ctx = this.canvasContext;
|
||||
|
||||
if (ctx) {
|
||||
this.onload = null; // to prevent an infinite loop
|
||||
ctx.drawImage(this, 0, 0);
|
||||
var imgd = ctx.getImageData(0, 0, this._layer.options.tileSize, this._layer.options.tileSize);
|
||||
var pix = imgd.data;
|
||||
for (var i = 0, n = pix.length; i < n; i += 4) {
|
||||
pix[i] = pix[i + 1] = pix[i + 2] = (3 * pix[i] + 4 * pix[i + 1] + pix[i + 2]) / 8;
|
||||
}
|
||||
ctx.putImageData(imgd, 0, 0);
|
||||
this.removeAttribute("crossorigin");
|
||||
this.src = ctx.canvas.toDataURL();
|
||||
}
|
||||
|
||||
L.TileLayer.prototype._tileOnLoad.call(this);
|
||||
}
|
||||
});
|
||||
|
||||
L.tileLayer.grayscale = function (url, options) {
|
||||
return new L.TileLayer.Grayscale(url, options);
|
||||
};
|
54
www/copyright.inc.de
Normal file
@ -0,0 +1,54 @@
|
||||
<div class="accordioncontent">
|
||||
<p >Das Urheberrecht der verwendeten Daten, Kartengrundlagen und
|
||||
JavaScript Dateien liegt bei dem jeweiligen Urheber. Die
|
||||
Benutzung unterliegt verschiedenen Lizenzen. Eine normale
|
||||
Nutzung zur Darstellung im Internet ist dabei bei den benutzten
|
||||
Quellen frei mögliche. Eine darüber hinaus gehende Nutzung (z.
|
||||
B. drucken, speichern, Weiterverwendung in anderen Publikationen
|
||||
etc.) ist nur unter <b>Beachtung der verschiedenen Lizenzen</b>
|
||||
möglich. Diese sind im folgenden zusammengefasst.</p>
|
||||
|
||||
<h4>Kartengrundlage und Nominatim Dienst</h4>
|
||||
<p>Die Kartengrundlagen und der Nominatim Dienst (reverse
|
||||
Geocodierung) basieren auf Daten des <a
|
||||
href="//www.openstreetmap.org" target="_blank">OpenStreetMap</a>
|
||||
Projektes und wurden durch <a href="//www.mapquest.com/"
|
||||
target="_blank">MapQuest</a> <img alt="Mapquest Logo"
|
||||
src="//developer.mapquest.com/content/osm/mq_logo.png" /> zur
|
||||
Verfügung gestellt. Hierfür gelten die „<a
|
||||
href="//developer.mapquest.com/web/info/terms-of-use"
|
||||
target="_blank">Terms of use</a>“ des Anbieters. Diese gestatten
|
||||
eine nicht-kommerzielle, öffentlich zugängliche Nutzung.</p>
|
||||
|
||||
<h4>Ereignisdaten und Stationsdaten</h4>
|
||||
<p>Die dargestellten Daten der seismischen Ereignisse und der
|
||||
seismischen Stationen unterliegen der „<a
|
||||
href="http://opendatacommons.org/licenses/odbl/summary"
|
||||
target="_blank">Open Data Commons Open Database Lizenz</a>“
|
||||
(ODbL). Die Daten dürfen frei kopieren, weitergegeben,
|
||||
übermittel sowie angepasst werden, sofern das <a
|
||||
href="http://www.gmg.ruhr-uni-bochum.de"
|
||||
target="_blamk">Seismologische Observatorium der
|
||||
Ruhr-Universität</a> als Quelle genannt wird. Werden diese Daten
|
||||
wiederverwendet, so unterliegen sie weiterhin dieser Lizenz. Der
|
||||
vollständige <a
|
||||
href="http://opendatacommons.org/licenses/odbl/1.0/"
|
||||
target="_blank">Lizenztext</a> erläutert die Rechte und
|
||||
Pflichten dieser Lizenz.</p>
|
||||
|
||||
<h4>JavaScript Dateien</h4>
|
||||
<p>Diese Webseite benutzt verschiedene JavaScript Bibliotheken,
|
||||
die unterschiedlichen Lizenzen unterliegen. Die jeweiligen
|
||||
Lizenzen werden in der Regel im Quellcode der benutzten
|
||||
Bibliotheken aufgeführt.</p>
|
||||
|
||||
<h4>Sonstiger Inhalt</h4>
|
||||
<p>Sonstiger Inhalt dieser Webseite unterliegt der
|
||||
„Creative-Commons''-Lizenz „<a
|
||||
href="https://creativecommons.org/licenses/by-sa/4.0/deed.de"
|
||||
target="_blank">Namensnennung – Weitergabe unter gleichen
|
||||
Bedingungen</a>“ 4.0 (CC BY-SA). Der vollständige <a
|
||||
href="https://creativecommons.org/licenses/by-sa/4.0/legalcode"
|
||||
target="_blank">Lizenztext</a> erläutert die Rechte und
|
||||
Pflichten dieser Lizenz.</p>
|
||||
</div>
|
0
www/data/.gitkeep
Normal file
12
www/data/specialevents.js
Normal file
@ -0,0 +1,12 @@
|
||||
/* last change 2022-20-23 */
|
||||
var specialEvents = [
|
||||
// 'bug2016ajgm', // CTBT violation North Korea
|
||||
// 'bug2016qphy', // Central Italy 6.1
|
||||
// 'bug2016rslt', // CTBT violation North Korea
|
||||
// 'bug2016vico', // Central Italy 6.5
|
||||
// 'bug2017rfxe', // CTBT violation North Korea 6.1
|
||||
// 'bug2019fura', // Sprengung Duisburg-Hochheide (Weißer Riese) 2.0
|
||||
// 'bug2021vtgi', // Geilenkirchen 1.9
|
||||
// 'bug2022ahxi', // Erftstadt 2.9
|
||||
'bug2023hlmh' // Brüggen 3.3
|
||||
];
|
447
www/events.js
@ -1,22 +1,62 @@
|
||||
/**********************************************************************
|
||||
* events.js *
|
||||
* script for event specific functions and setup *
|
||||
**********************************************************************/
|
||||
|
||||
/* License
|
||||
Copyright 2014-2021 Kasper D. Fischer <kasper.fischer@rub.de>
|
||||
|
||||
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/.
|
||||
|
||||
Version v1.3 (2023-04-17)
|
||||
*/
|
||||
|
||||
/* 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( "//nominatim.openstreetmap.org/reverse", { lat: lat, lon: lng, zoom: 10, format: "json" } )
|
||||
$.getJSON( "//open.mapquestapi.com/nominatim/v1/reverse.php", { lat: lat, lon: lng, zoom: 10, format: "json" } )
|
||||
if ( $.inArray(id, geolocationTable) == -1 ) {
|
||||
$.getJSON( config['ajax']['nominatimURL'], { lat: lat, lon: lng } )
|
||||
.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);
|
||||
if ( json.features[0] ) {
|
||||
var city = json.features[0].properties.city;
|
||||
var countryCode = json.features[0].properties.country;
|
||||
geolocationTable[id] = city;
|
||||
( countryCode != "Germany" && countryCode != "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 ) {
|
||||
@ -27,34 +67,44 @@ function getGeolocation(id, lat, lng) {
|
||||
};
|
||||
|
||||
/* Load events using ajax */
|
||||
function ajaxLoadEvents(stime, etime) {
|
||||
function ajaxLoadEvents(stime, etime, eventid, url, target) {
|
||||
var mapBounds = map.getBounds();
|
||||
var N = mapBounds.getNorth();
|
||||
var E = mapBounds.getEast();
|
||||
var S = mapBounds.getSouth();
|
||||
var W = mapBounds.getWest();
|
||||
var d = 0.1;
|
||||
if ( !stime ) {
|
||||
var stime = new Date();
|
||||
stime.setDate(stime.getDate()-180);
|
||||
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 ( !etime ) {
|
||||
var etime = new Date();
|
||||
etime.setDate(etime.getDate()+1);
|
||||
};
|
||||
var url = "https://ariadne.geophysik.ruhr-uni-bochum.de/fdsnws/event/1/query"
|
||||
var request_data = {
|
||||
starttime: sprintf("%d-%02d-%02d", stime.getFullYear(), stime.getMonth()+1, stime.getDate()),
|
||||
endtime: sprintf("%d-%02d-%02d", etime.getFullYear(), etime.getMonth()+1, etime.getDate()),
|
||||
minlat: S-d,
|
||||
maxlat: N+d,
|
||||
minlon: W-d,
|
||||
maxlon: E+d,
|
||||
minmag: minMag-0.1,
|
||||
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-asc',
|
||||
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: url,
|
||||
url: ajax_url,
|
||||
data: request_data,
|
||||
dataType: "xml",
|
||||
success: function (xml) {
|
||||
@ -64,53 +114,146 @@ function ajaxLoadEvents(stime, etime) {
|
||||
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 mag = $(this).find('magnitude > mag > value').text();
|
||||
var evaluationMode = $(this).find('evaluationMode').text();
|
||||
var evaluationStatus = $(this).find('evaluationStatus').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 = getLocation(Number(lat), Number(lng))[0];
|
||||
( location ) ? null : location = $(this).find('description > text').text();
|
||||
var location
|
||||
// create table row: Date, Time, Mag, Location
|
||||
if ( !eventTable[id] && ( type == 'earthquake' || type == 'induced or triggered event' || type == 'outside of network interest') && evaluationMode != 'automatic' && evaluationStatus != 'preliminary' && Number(mag)+0.05 >= minMag ) {
|
||||
if ( !eventTable[id] && $.inArray(type, config['event']['typeWhitelist'] ) >= 0 && $.inArray(evaluationStatus, config['event']['evaluationBlacklist'])<0 && Number(mag)+0.05 >= config['event']['minMag'] ) {
|
||||
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() );
|
||||
// general event info (1st line)
|
||||
var row = '<tr class="tablesorter-hasChildRow">'
|
||||
+ '<td class="utctime-date">'+otime.split('.')[0]+'Z</td>'
|
||||
+ '<td class="utctime-time">'+otime.split('.')[0]+'Z</td>'
|
||||
+ sprintf('<td class="ar">%.1f</td>', Number(mag))
|
||||
+ '<td><a href="#" class="toggle" eventid="'+id+'">'+location+'</a><a class="map-link" href="#" eventid="'+id+'">Karte</a></td>'
|
||||
+ '<td><a href="#" class="toggle" eventid="'+id+'">'+location+'</a> <a class="map-link" href="#" eventid="'+id+'">Karte</a></td>'
|
||||
+ '</tr>';
|
||||
row += '<tr class="tablesorter-childRow">'
|
||||
+ '<td colspan="4" eventid="'+id+'">not implemented</td></tr>';
|
||||
var added = $('#eventstable tbody').append(row);
|
||||
added.find('.tablesorter-childRow td').hide();
|
||||
$('#eventstable').find('td.utctime-date').each(function() {
|
||||
$.localtime.formatObject($(this), "dd.MM.yyyy");
|
||||
$(this).removeClass('utctime-date');
|
||||
$(this).addClass('localtime-date');
|
||||
});
|
||||
$('#eventstable').find('td.utctime-time').each(function() {
|
||||
$.localtime.formatObject($(this), "HH:mm");
|
||||
$(this).removeClass('utctime-time');
|
||||
$(this).addClass('localtime-time');
|
||||
});
|
||||
// setting up event details (2nd line)
|
||||
row += '<tr class="tablesorter-childRow event-details">'
|
||||
+ '<td colspan="4" eventid="'+id+'">Daten werden geladen ...</td></tr>';
|
||||
// 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);
|
||||
if ( ~oTime ) {
|
||||
oTime = new Date(otime.split('.')[0]);
|
||||
};
|
||||
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 += '<tr class="tablesorter-childRow event-download">'
|
||||
+ '<td colspan="4" eventid="'+id+'">'
|
||||
+ sprintf('Download <a class="xml-link" target="_blank" download="%s.xml" href="%s">QuakeML</a> or <a class="mseed-link" target="_blank" download="%s.mseed" href="%s">miniSEED</a>', id, xmlurl, id, mseedurl)
|
||||
+ '</td></tr>';
|
||||
// add row to table
|
||||
if ( stime <= oTime && etime >= oTime ) {
|
||||
addTableRow(row, 'eventstable');
|
||||
};
|
||||
if ( target ) {
|
||||
addTableRow(row, target);
|
||||
}
|
||||
// create marker
|
||||
var marker = addEventMarker(id, Number(lat), Number(lng), Number(mag));
|
||||
var text = sprintf('<h3 eventid="%s">%s</h3>', id, location)
|
||||
+ sprintf('<p>Ereignis: %s</br>', id)
|
||||
+ sprintf('Ort: %.4f °N, %.4f °O </br>', Number(lat), Number(lng))
|
||||
+ sprintf('Zeit: <span class="utctime">%sZ</span></p>', otime.split('.')[0], otime.split('.')[0]);
|
||||
marker.bindPopup(text);
|
||||
// try to get better location with reverse geolocation lookup (nominatim)
|
||||
getGeolocation(id, lat, lng);
|
||||
if ((stime <= oTime && etime >= oTime ) || ( id == eventid )) {
|
||||
var marker = addEventMarker(id, Number(lat), Number(lng), Number(mag), type);
|
||||
var text = sprintf('<h3 eventid="%s">%s</h3>', id, location)
|
||||
+ sprintf('<p>Ereignis: %s<br />', id)
|
||||
+ sprintf('Type: %s<br />', type)
|
||||
+ sprintf('Magnitude: %3.1f<br />', Number(mag))
|
||||
+ sprintf('Ort: %.4f °N, %.4f °O <br />', Number(lat), Number(lng))
|
||||
+ sprintf('Tiefe: %.1f km<br />', Number(depth)/1000.)
|
||||
+ sprintf('Zeit: <span class="utctime">%sZ</span></p>', otime.split('.')[0], otime.split('.')[0]);
|
||||
marker.bindPopup(text);
|
||||
};
|
||||
};
|
||||
});
|
||||
},
|
||||
complete: function () {
|
||||
initStationTable();
|
||||
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 = "<pre>"
|
||||
+ 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 + '</pre>';
|
||||
$('#eventstable > tbody > tr.event-details > td[eventid='+id+']').html(row);
|
||||
});
|
||||
},
|
||||
complete: function () {
|
||||
null;
|
||||
},
|
||||
error: function( jqxhr, textStatus, error ) {
|
||||
var err = textStatus + ", " + error;
|
||||
@ -119,54 +262,84 @@ function ajaxLoadEvents(stime, etime) {
|
||||
});
|
||||
};
|
||||
|
||||
// add row to table
|
||||
function addEventRow(id, props) {
|
||||
$('#eventstable').tablesorter({
|
||||
sortList: "[[0,0], [1,1]], [2,1]",
|
||||
resort: true,
|
||||
showProcessing: true,
|
||||
pager_size: 35
|
||||
/* 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")]);
|
||||
};
|
||||
});
|
||||
var html = '<tr class="tablesorter-hasChildRow">'
|
||||
+ '<td class="utctime-date">'+props.date+'T'+props.time.split('.')[0]+'Z</td>'
|
||||
+ '<td class="utctime-time">'+props.date+'T'+props.time.split('.')[0]+'Z</td>'
|
||||
+ '<td class="ar">'+props.mag+'</td>'
|
||||
+ '<td><a href="#" class="toggle">'+props.location+'</a><a class="map-link" href="#" eventid="'+id+'">Karte</a></td>'
|
||||
+ '</tr>'
|
||||
+ '<tr class="tablesorter-childRow">'
|
||||
+ '<td colspan="4" eventid="'+id+'">'
|
||||
+ "<pre>ID "+id+"\n\n"
|
||||
+ "Origin\n"
|
||||
+ "Date "+props.date+"\n"
|
||||
+ "Time "+props.time+"\n"
|
||||
+ "Latitude "+props.lat+" deg +/- "+props.lat_err+" km\n"
|
||||
+ "Longitude "+props.lon+" deg +/- "+props.lon_err+" km\n"
|
||||
+ "Depth "+props.depth+" km +/- "+props.depth_err+" km\n"
|
||||
+ "Residual RMS "+props.rms+" s\n"
|
||||
+ "Azimuthal gap "+props.gap+" deg\n\n"
|
||||
+ props.no_phases + " Phase arrivals:\n"
|
||||
+ "sta net dist azi phase time res wt sta\n";
|
||||
for ( i = 0 ; i < props.no_phases ; i++ ) {
|
||||
html += props.phases[i];
|
||||
( i < props.no_phases -1 ) ? html += "\n" : null ;
|
||||
};
|
||||
html += "</pre></td></tr>\n";
|
||||
var added = $('#eventstable tbody').append(html);
|
||||
added.find('.tablesorter-childRow td').hide();
|
||||
$('#eventstable').find('td.utctime-date').each(function() {
|
||||
$.localtime.formatObject($(this), "dd. MM. yyyy");
|
||||
$(this).removeClass('utctime-date');
|
||||
$(this).addClass('localtime-date');
|
||||
// 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")]);
|
||||
};
|
||||
});
|
||||
$('#eventstable').find('td.utctime-time').each(function() {
|
||||
$.localtime.formatObject($(this), "HH:mm");
|
||||
$(this).removeClass('utctime-time');
|
||||
$(this).addClass('localtime-time');
|
||||
});
|
||||
// force resorting
|
||||
$("#eventstable").trigger("update", [true]);
|
||||
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('Karte');
|
||||
};
|
||||
});
|
||||
$("#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('Karte (rot)');
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
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('Karte (rot)');
|
||||
} else {
|
||||
eventTable[$(this).attr("eventid")].setStyle(normalStyle);
|
||||
$(this).removeClass('first');
|
||||
$(this).text('Karte');
|
||||
}
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
/**********************************************************************
|
||||
* document ready *
|
||||
**********************************************************************/
|
||||
$(document).ready(function() {
|
||||
// tablesorter for event list
|
||||
$("#eventstable").tablesorter(
|
||||
@ -195,31 +368,33 @@ $(document).ready(function() {
|
||||
showProcessing: true,
|
||||
}
|
||||
});
|
||||
|
||||
// hide child rows
|
||||
$('#eventstable > tbody > tr.tablesorter-childRow td').hide();
|
||||
|
||||
// update map after filtering
|
||||
$('#eventstable').bind('filterEnd', function(){
|
||||
$('#eventstable').on('filterEnd', function(){
|
||||
toggleFilteredMarkers();
|
||||
});
|
||||
|
||||
// highlight first event
|
||||
$('#eventstable').bind('sortEnd', function(){
|
||||
$('#eventstable').on('sortEnd', function(){
|
||||
highlightFirstEvent();
|
||||
});
|
||||
$('#eventstable').on('pagerComplete', function(){
|
||||
highlightFirstEvent();
|
||||
});
|
||||
|
||||
// show / hide event info
|
||||
$('#eventstable').delegate('.toggle', 'click' , function(){
|
||||
$('#eventstable').on('click', '.toggle', 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('slow');
|
||||
$(this).hide();
|
||||
$(this).removeClass('selected');
|
||||
};
|
||||
});
|
||||
@ -228,12 +403,36 @@ $(document).ready(function() {
|
||||
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() == "Symbole:" ) ? typetext = ' ' : typetext = ', ';
|
||||
switch ( type ) {
|
||||
case 'earthquake':
|
||||
typetext += 'tektonisches Erdbeben (Stern)';
|
||||
break;
|
||||
case 'induced or triggered event':
|
||||
typetext += '(bergbau-)induziertes Ereignis (Kreis)';
|
||||
break;
|
||||
case 'quarry blast':
|
||||
case 'controlled explosion':
|
||||
case 'explosion':
|
||||
typetext += 'Sprengung (Rad)';
|
||||
break;
|
||||
case 'nuclear explosion':
|
||||
typetext += 'Atomwaffentest (Viereck)';
|
||||
break;
|
||||
};
|
||||
$("#events-type").append(typetext);
|
||||
});
|
||||
});
|
||||
|
438
www/events.js.en
Normal file
@ -0,0 +1,438 @@
|
||||
/**********************************************************************
|
||||
* events.js.en *
|
||||
* script for event specific functions and setup *
|
||||
**********************************************************************/
|
||||
|
||||
/* License
|
||||
Copyright 2014-2021 Kasper D. Fischer <kasper.fischer@rub.de>
|
||||
|
||||
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/.
|
||||
|
||||
Version v1.3 (2023-04-17)
|
||||
*/
|
||||
|
||||
/* 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 ( $.inArray(id, geolocationTable) == -1 ) {
|
||||
$.getJSON( config['ajax']['nominatimURL'], { lat: lat, lon: lng } )
|
||||
.done(function( json ) {
|
||||
if ( json.features[0] ) {
|
||||
var city = json.features[0].properties.city;
|
||||
var countryCode = json.features[0].properties.country;
|
||||
geolocationTable[id] = city;
|
||||
( countryCode != "Germany" && countryCode != "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-asc',
|
||||
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
|
||||
// create table row: Date, Time, Mag, Location
|
||||
if ( !eventTable[id] && $.inArray(type, config['event']['typeWhitelist'] ) >= 0 && $.inArray(evaluationStatus, config['event']['evaluationBlacklist'])<0 && Number(mag)+0.05 >= config['event']['minMag'] ) {
|
||||
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() );
|
||||
// general event info (1st line)
|
||||
var row = '<tr class="tablesorter-hasChildRow">'
|
||||
+ '<td class="utctime-date">'+otime.split('.')[0]+'Z</td>'
|
||||
+ '<td class="utctime-time">'+otime.split('.')[0]+'Z</td>'
|
||||
+ sprintf('<td class="ar">%.1f</td>', Number(mag))
|
||||
+ '<td><a href="#" class="toggle" eventid="'+id+'">'+location+'</a> <a class="map-link" href="#" eventid="'+id+'">map</a></td>'
|
||||
+ '</tr>';
|
||||
// setting up event details (2nd line)
|
||||
row += '<tr class="tablesorter-childRow event-details">'
|
||||
+ '<td colspan="4" eventid="'+id+'">Daten werden geladen ...</td></tr>';
|
||||
// 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);
|
||||
if ( ~oTime ) {
|
||||
oTime = new Date(otime.split('.')[0]);
|
||||
};
|
||||
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 += '<tr class="tablesorter-childRow event-download">'
|
||||
+ '<td colspan="4" eventid="'+id+'">'
|
||||
+ sprintf('Download <a class="xml-link" target="_blank" download="%s.xml" href="%s">QuakeML</a> or <a class="mseed-link" target="_blank" download="%s.mseed" href="%s">miniSEED</a>', id, xmlurl, id, mseedurl)
|
||||
+ '</td></tr>';
|
||||
// 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('<h3 eventid="%s">%s</h3>', id, location)
|
||||
+ sprintf('<p>Ereignis: %s<br />', id)
|
||||
+ sprintf('Type: %s<br />', type)
|
||||
+ sprintf('Magnitude: %3.1f<br />', Number(mag))
|
||||
+ sprintf('Ort: %.4f °N, %.4f °O <br />', Number(lat), Number(lng))
|
||||
+ sprintf('Tiefe: %.1f km<br />', Number(depth)/1000.)
|
||||
+ sprintf('Zeit: <span class="utctime">%sZ</span></p>', 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 = "<pre>"
|
||||
+ 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 + '</pre>';
|
||||
$('#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').on('filterEnd', function(){
|
||||
toggleFilteredMarkers();
|
||||
});
|
||||
// highlight first event
|
||||
$('#eventstable').on('sortEnd', function(){
|
||||
highlightFirstEvent();
|
||||
});
|
||||
$('#eventstable').on('pagerComplete', function(){
|
||||
highlightFirstEvent();
|
||||
});
|
||||
// show / hide event info
|
||||
$('#eventstable').on('click', '.toggle', 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 'induced or triggered event':
|
||||
typetext += '(mining-)induced event (circle)';
|
||||
break;
|
||||
case 'quarry blast':
|
||||
case 'controlled explosion':
|
||||
case 'explosion':
|
||||
typetext += 'quarry blast (wheel)';
|
||||
break;
|
||||
case 'nuclear explosion':
|
||||
typetext += 'nuclear weapon test (square)';
|
||||
break;
|
||||
};
|
||||
$("#events-type").append(typetext);
|
||||
});
|
||||
});
|
0
www/first.png → www/external/first.png
vendored
Before Width: | Height: | Size: 720 B After Width: | Height: | Size: 720 B |
0
www/last.png → www/external/last.png
vendored
Before Width: | Height: | Size: 737 B After Width: | Height: | Size: 737 B |
0
www/next.png → www/external/next.png
vendored
Before Width: | Height: | Size: 736 B After Width: | Height: | Size: 736 B |
0
www/prev.png → www/external/prev.png
vendored
Before Width: | Height: | Size: 745 B After Width: | Height: | Size: 745 B |
BIN
www/favicon.ico
Normal file
After Width: | Height: | Size: 318 B |
29
www/impressum.inc.de
Normal file
@ -0,0 +1,29 @@
|
||||
<div class="accordioncontent">
|
||||
<h4>Anschrift</h4>
|
||||
Seismologisches Observatorium der<br />
|
||||
Ruhr-Universität Bochum<br />
|
||||
NA 3/174<br />
|
||||
44780 Bochum<br />
|
||||
Tel.: 0234 32-27574<br />
|
||||
Fax: 0234 32-07574<br />
|
||||
|
||||
<p>Die Ruhr-Universität ist eine Körperschaft des Öffentlichen Rechts. Sie wird durch ihren Rektor Herrn Prof. Dr. Elmar W. Weiler gesetzlich vertreten.</p>
|
||||
<p>Zuständige Aufsichtsbehörde ist das Ministerium für Innovation, Wissenschaft und Forschung des Landes Nordrhein-Westfalen, Völklinger Straße 49, 40221 Düsseldorf.</p>
|
||||
<p>Umsatzsteuer-Identifikationsnummer: DE 127 056 261</p>
|
||||
|
||||
<h4>Inhaltliche und technische Verantwortung für die Seiten des Seismologischen Observatoriums der Ruhr-Universität Bochum</h4>
|
||||
Herr Dr. Kasper D. Fischer<br />
|
||||
Ruhr-Universität Bochum<br />
|
||||
44780 Bochum<br />
|
||||
Tel.: 0234 32-27574<br />
|
||||
Fax: 0234 32-07574<br />
|
||||
E-Mail: kasper.fischer@ruhr-uni-bochum.de<br />
|
||||
|
||||
<p>Meldungen über missbräuchliche Nutzungen, die von Stationen aus dem IP-Namensbereich ruhr-uni-bochum.de ausgehen, senden Sie bitte an die Email-Adresse
|
||||
abuse@ruhr-uni-bochum.de. Gleichfalls bittet die Ruhr-Universität um Mitteilung an dieselbe Email-Adresse, wenn rechtswidrige Inhalte durch Links auf Seiten der Ruhr-Universität zu
|
||||
erreichen sind.</p>
|
||||
|
||||
<h4>Rechtliche Hinweise</h4>
|
||||
<p>Die Ruhr-Universität Bochum übernimmt keine Gewähr für die Richtigkeit und Vollständigkeit der auf ihren Internetseiten befindlichen Informationen. Das gleiche gilt für die
|
||||
Inhalte verlinkter Seiten.</p>
|
||||
</div>
|
132
www/index.html.de
Normal file → Executable file
@ -1,5 +1,5 @@
|
||||
<!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Transitional//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'>
|
||||
<!-- $Id$ -->
|
||||
<!DOCTYPE html>
|
||||
<!-- Version v1.3 (2023-04-17) -->
|
||||
<html xmlns='http://www.w3.org/1999/xhtml' xml:lang='de' lang='de'>
|
||||
<head>
|
||||
<meta http-equiv="content-type" content="text/html;charset=UTF-8" />
|
||||
@ -7,44 +7,59 @@
|
||||
|
||||
|
||||
<!-- Style definitions -->
|
||||
<link rel="stylesheet" href="main.css">
|
||||
|
||||
<link rel="stylesheet" href="main.css" />
|
||||
<link rel="stylesheet" href="https://code.jquery.com/ui/1.12.1/themes/cupertino/jquery-ui.css" />
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jquery.tablesorter/2.31.3/css/theme.blue.min.css" integrity="sha512-jJ9r3lTLaH5XXa9ZOsCQU8kLvxdAVzyTWO/pnzdZrshJQfnw1oevJFpoyCDr7K1lqt1hUgqoxA5e2PctVtlSTg==" crossorigin="anonymous" />
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jquery.tablesorter/2.31.3/css/jquery.tablesorter.pager.min.css" integrity="sha512-TWYBryfpFn3IugX13ZCIYHNK3/2sZk3dyXMKp3chZL+0wRuwFr1hDqZR9Qd5SONzn+Lja10hercP2Xjuzz5O3g==" crossorigin="anonymous" />
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.7.1/leaflet.css" integrity="sha512-xodZBNTC5n17Xt2atTPuE1HxjVMSvLVW9ocqUKLsCC5CXdbqCmblAshOMAS6/keqq/sMZMZ19scR4PsZChSR7A==" crossorigin="anonymous" referrerpolicy="no-referrer" />
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet-dvf/0.3.1/css/dvf.min.css" integrity="sha512-Ts/IYE5D8PaMBUDHcf6O57lOiV923cai3sEXo0WjhakpTxlwodQQJx1YA2t1mDUKO6fIXEngkKFLQNMXK/kBZg==" crossorigin="anonymous" />
|
||||
<!-- jQuery & jQueryUI -->
|
||||
<link rel="stylesheet" href="//code.jquery.com/ui/1.10.4/themes/smoothness/jquery-ui.css">
|
||||
<link rel="stylesheet" href="http://code.jquery.com/ui/1.10.4/themes/cupertino/jquery-ui.css">
|
||||
<script src="//code.jquery.com/jquery-1.11.0.min.js"></script>
|
||||
<script src="//code.jquery.com/ui/1.10.4/jquery-ui.js"></script>
|
||||
<script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>
|
||||
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js" integrity="sha256-VazP97ZCwtekAsvgPBSUwPFKdrwD3unUfSGVYrahUqU=" crossorigin="anonymous"></script>
|
||||
|
||||
<!-- Localtime -->
|
||||
<script type="text/javascript" src="jquery.localtime-0.9.1.min.js"></script>
|
||||
<!-- Localtime, sprintf, showdown -->
|
||||
<script type="text/javascript" src="external/jquery.localtime-0.9.1.min.js"></script> <!-- current 2020-07-15 -->
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/sprintf/1.1.2/sprintf.min.js" integrity="sha512-pmG0OkYtZVB2EqETE5HPsEaok7sNZFfStp5rNdpHv0tGQjbt1z8Qjzhtx88/4wsttOtDwq5DZGJyKyzEe7ribg==" crossorigin="anonymous"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/showdown/1.9.1/showdown.min.js" integrity="sha512-L03kznCrNOfVxOUovR6ESfCz9Gfny7gihUX/huVbQB9zjODtYpxaVtIaAkpetoiyV2eqWbvxMH9fiSv5enX7bw==" crossorigin="anonymous"></script>
|
||||
|
||||
<!-- Tablesorter: required -->
|
||||
<link rel="stylesheet" href="theme.blue.css">
|
||||
<script src="jquery.tablesorter.min.js"></script>
|
||||
<!-- script src="widget-scroller.js"></script -->
|
||||
<script src="jquery.tablesorter.widgets.min.js"></script>
|
||||
<script src="jquery.tablesorter.pager.min.js"></script>
|
||||
|
||||
<!-- misc functions -->
|
||||
<script src="misc.js"></script>
|
||||
<script src="sprintf.min.js"></script>
|
||||
|
||||
<!-- Tablesorter: pager -->
|
||||
<link rel="stylesheet" href="jquery.tablesorter.pager.css">
|
||||
<script src="widget-pager.js"></script>
|
||||
<script src="events.js"></script>
|
||||
<!-- Tablesorter -->
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery.tablesorter/2.31.3/js/jquery.tablesorter.min.js" integrity="sha512-qzgd5cYSZcosqpzpn7zF2ZId8f/8CHmFKZ8j7mU4OUXTNRd5g+ZHBPsgKEwoqxCtdQvExE5LprwwPAgoicguNg==" crossorigin="anonymous"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery.tablesorter/2.31.3/js/jquery.tablesorter.widgets.min.js" integrity="sha512-dj/9K5GRIEZu+Igm9tC16XPOTz0RdPk9FGxfZxShWf65JJNU2TjbElGjuOo3EhwAJRPhJxwEJ5b+/Ouo+VqZdQ==" crossorigin="anonymous"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery.tablesorter/2.31.3/js/widgets/widget-pager.min.js" integrity="sha512-+X/dsto9+7foPuqwqjm+mJSPYk6Coovg9jQJvM+aBfscXOyBrAKN69GS5Z2TkMLlVHxeiE5doVqelnMfbsS9XQ==" crossorigin="anonymous"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery.tablesorter/2.31.3/js/extras/jquery.tablesorter.pager.min.js" integrity="sha512-y845ijdup9lDunrcSRQAlFdQICHVhkB5UNguWRX8A3L+guxO7Oow0poojw0PLckhcKij++h85bnyro80fjR9+A==" crossorigin="anonymous"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery.tablesorter/2.31.3/js/widgets/widget-scroller.min.js" integrity="sha512-1D2qKse1/4gCgLbgmBBv+9fJluAeJIlDgzIyZkovd1xmoyh1SW30lMIzCrD2X8Xs/sIzitUNDy86YagJRSUmaA==" crossorigin="anonymous"></script>
|
||||
|
||||
<!-- Leaflet -->
|
||||
<link rel="stylesheet" href="leaflet.css" />
|
||||
<script src="leaflet.js"></script>
|
||||
<!-- script src="TileLayer.Grayscale.js"></script -->
|
||||
<script src="map.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.7.1/leaflet.js" integrity="sha512-XQoYMqMTK8LvdxXYG3nZ448hOEQiglfqkJs1NOQV44cWnUrBc8PkAOcXy20w0vlaXaVUearIOBhiXZ5V3ynxwA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet-dvf/0.3.1/leaflet-dvf.markers.min.js" integrity="sha512-R/iucaxFnDFUTdZRxUvxzc+sypDQhqnxInBmNjgGE0RaiMl/ektVB1wFS/L0xDZmLFPpEGR0Kw3GEBgtQNFHyg==" crossorigin="anonymous"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet-providers/1.13.0/leaflet-providers.min.js" integrity="sha512-5EYsvqNbFZ8HX60keFbe56Wr0Mq5J1RrA0KdVcfGDhnjnzIRsDrT/S3cxdzpVN2NGxAB9omgqnlh4/06TvWCMw==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/leaflet.browser.print@1.0.6/dist/leaflet.browser.print.min.js" integrity="sha256-LrZphoL6+XVEuBR4BfhOIdRAMpRigQvsu3/iCNhQSXw=" crossorigin="anonymous"></script>
|
||||
<script src="https://www.mapquestapi.com/sdk/leaflet/v2.2/mq-map.js?key=RPOPuz3lA2GGBtVpEU0ugxtVoGba53Dt"></script>
|
||||
|
||||
<!-- Stations -->
|
||||
<script src="stations.js"></script>
|
||||
<!-- Map, Events & Stations -->
|
||||
<script type="text/javascript" src="misc.js"></script>
|
||||
<script type="text/javascript" src="map.js"></script>
|
||||
<script type="text/javascript" src="events.js"></script>
|
||||
<script type="text/javascript" src="stations.js"></script>
|
||||
<script type="text/javascript" src="data/geolocation.js"></script>
|
||||
<script type="text/javascript" src="data/specialevents.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<!-- noscript -->
|
||||
<noscript>
|
||||
<div class="noscript">
|
||||
<div class="noscriptcontent">
|
||||
<h2>Kein JavaScript verfügbar!</h2>
|
||||
<p>Diese Seite benötigt JavaScript. Bitte schalten Sie JavaScript ein.</p>
|
||||
<h2>JavaScript disabled!</h2>
|
||||
<p>This page requires JavaScript to work. Please enable JavaScript.</p>
|
||||
<h2>Impressum</h2>
|
||||
<!--#include virtual="impressum.inc.de" -->
|
||||
</div>
|
||||
</div>
|
||||
</noscript>
|
||||
<!-- Tabs -->
|
||||
<div class="info" id="tabs">
|
||||
<ul>
|
||||
<li><a href="#eventstab"><span>Ereignisse</span></a></li>
|
||||
@ -55,11 +70,11 @@
|
||||
<!-- Ereignisse -->
|
||||
<div class="tab" id="eventstab">
|
||||
<div class="pager events" id="eventspager">
|
||||
<img src="first.png" class="first" alt="First" />
|
||||
<img src="prev.png" class="prev" alt="Prev" />
|
||||
<img src="external/first.png" class="first" alt="First" />
|
||||
<img src="external/prev.png" class="prev" alt="Prev" />
|
||||
<span class="pagedisplay"></span>
|
||||
<img src="next.png" class="next" alt="Next" />
|
||||
<img src="last.png" class="last" alt="Last" />
|
||||
<img src="external/next.png" class="next" alt="Next" />
|
||||
<img src="external/last.png" class="last" alt="Last" />
|
||||
<select class="pagesize" title="Select page size">
|
||||
<option value="5">5</option>
|
||||
<option value="10">10</option>
|
||||
@ -71,7 +86,7 @@
|
||||
</select>
|
||||
<select class="gotoPage" title="Select page number"></select>
|
||||
</div>
|
||||
<table class="tablesorter" id="eventstable" data-sortlist="[[0,0],[1,1],[2,1]]">
|
||||
<table class="tablesorter" id="eventstable">
|
||||
<colgroup>
|
||||
<col width="85" />
|
||||
<col width="50" />
|
||||
@ -89,16 +104,24 @@
|
||||
<tbody>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>Nominatim Search Courtesy of <a href="http://www.mapquest.com/" target="_blank">MapQuest</a> <img src="http://developer.mapquest.com/content/osm/mq_logo.png"></p>
|
||||
<p class="table-caption">
|
||||
Ereignisse der letzten <span id="events-timespan">180</span> Tage ab Magnitude <span id="events-minmag">1.2</span> im Bereich der Karte und besondere Ereignisse in angrenzenden Bereichen. Download als <a id="events-csv-link" href="link" download="events.csv">CSV-Datei</a>.
|
||||
</p>
|
||||
<p class="table-caption">
|
||||
<span id="events-type">Symbole:</span>
|
||||
</p>
|
||||
<p class="table-caption">
|
||||
Reverse Geolocation courtesy of <a href="http://photon.komoot.io/" target="_blank">Photon by Komoot</a>
|
||||
</p>
|
||||
</div>
|
||||
<!-- Stations -->
|
||||
<div class="tab" id="stationstab">
|
||||
<div class="pager stationspager" id="stationspager">
|
||||
<img src="first.png" class="stationsfirst" alt="First" />
|
||||
<img src="prev.png" class="stationsprev" alt="Prev" />
|
||||
<img src="external/first.png" class="stationsfirst" alt="First" />
|
||||
<img src="external/prev.png" class="stationsprev" alt="Prev" />
|
||||
<span class="stationspagedisplay"></span>
|
||||
<img src="next.png" class="stationsnext" alt="Next" />
|
||||
<img src="last.png" class="stationslast" alt="Last" />
|
||||
<img src="external/next.png" class="stationsnext" alt="Next" />
|
||||
<img src="external/last.png" class="stationslast" alt="Last" />
|
||||
<select class="stationspagesize" title="Select page size">
|
||||
<option value="5">5</option>
|
||||
<option value="10">10</option>
|
||||
@ -114,8 +137,8 @@
|
||||
<colgroup>
|
||||
<col width="77" />
|
||||
<col/>
|
||||
<col width="77" />
|
||||
<col width="77" />
|
||||
<col width="77" align="char" char="." />
|
||||
<col width="77" align="char" char="." />
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr>
|
||||
@ -128,12 +151,29 @@
|
||||
<tbody>
|
||||
</tbody>
|
||||
</table>
|
||||
<p class="table-caption">Download als <a id="stations-csv-link" href="link" download="stations.csv">CSV-Datei</a>.</p>
|
||||
</div>
|
||||
<!-- More -->
|
||||
<div class="tab" id="moretab"></div>
|
||||
<div class="tab more_de" id="moretab">
|
||||
<p>Text wird geladen ...</p>
|
||||
</div>
|
||||
<!-- Info -->
|
||||
<div class="tab" id="infotab"></div>
|
||||
<div class="tab" id="infotab">
|
||||
<div id="infoaccordion">
|
||||
<h3 class="aheader">Navigation / Links</h3>
|
||||
<div class="info_de"><p>Text wird geladen ...</p></div>
|
||||
<h3 class="aheader">Copyright / Lizenz</h3>
|
||||
<div class="copyright_de"><p>Text wird geladen ...</p></div>
|
||||
<h3 class="aheader">Impressum</h3>
|
||||
<div class="imprint_de"><p>Text wird geladen ...</p></div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="rublogo"><img class="rublogo" src="logo_RUB_155x30.png" alt="Ruhr-Universität Bochum" title="Ruhr-Universität Bochum"/></div>
|
||||
<!-- Logo -->
|
||||
<div class="rublogo"><a href="http://www.gmg.ruhr-uni-bochum.de/seisobs"><img class="rublogo" src="logo_RUB_155x30.png" alt="Ruhr-Universität Bochum" title="Ruhr-Universität Bochum" border="0"/></a></div>
|
||||
<!-- Map -->
|
||||
<div id="map" class="map"></div>
|
||||
<div id="spinner" class="spinner" style="display:none;"><img id="img-spinner" src="spinner.gif" alt="Loading"/><br />Loading ...</div>
|
||||
</body>
|
||||
</html>
|
||||
|
180
www/index.html.en
Executable file
@ -0,0 +1,180 @@
|
||||
<!DOCTYPE html>
|
||||
<!-- Version v1.3 (2023-04-17) -->
|
||||
<html xmlns='http://www.w3.org/1999/xhtml' xml:lang='de' lang='de'>
|
||||
<head>
|
||||
<meta http-equiv="content-type" content="text/html;charset=UTF-8" />
|
||||
<title>RUB SeisObs - Event and Station Map</title>
|
||||
|
||||
|
||||
<!-- Style definitions -->
|
||||
<link rel="stylesheet" href="main.css" />
|
||||
<link rel="stylesheet" href="https://code.jquery.com/ui/1.12.1/themes/cupertino/jquery-ui.css" />
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jquery.tablesorter/2.31.3/css/theme.blue.min.css" integrity="sha512-jJ9r3lTLaH5XXa9ZOsCQU8kLvxdAVzyTWO/pnzdZrshJQfnw1oevJFpoyCDr7K1lqt1hUgqoxA5e2PctVtlSTg==" crossorigin="anonymous" />
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jquery.tablesorter/2.31.3/css/jquery.tablesorter.pager.min.css" integrity="sha512-TWYBryfpFn3IugX13ZCIYHNK3/2sZk3dyXMKp3chZL+0wRuwFr1hDqZR9Qd5SONzn+Lja10hercP2Xjuzz5O3g==" crossorigin="anonymous" />
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.7.1/leaflet.css" integrity="sha512-xodZBNTC5n17Xt2atTPuE1HxjVMSvLVW9ocqUKLsCC5CXdbqCmblAshOMAS6/keqq/sMZMZ19scR4PsZChSR7A==" crossorigin="anonymous" referrerpolicy="no-referrer" />
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet-dvf/0.3.1/css/dvf.min.css" integrity="sha512-Ts/IYE5D8PaMBUDHcf6O57lOiV923cai3sEXo0WjhakpTxlwodQQJx1YA2t1mDUKO6fIXEngkKFLQNMXK/kBZg==" crossorigin="anonymous" />
|
||||
|
||||
<!-- jQuery & jQueryUI -->
|
||||
<script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>
|
||||
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js" integrity="sha256-VazP97ZCwtekAsvgPBSUwPFKdrwD3unUfSGVYrahUqU=" crossorigin="anonymous"></script>
|
||||
|
||||
<!-- Localtime, sprintf, showdown -->
|
||||
<script type="text/javascript" src="external/jquery.localtime-0.9.1.min.js"></script> <!-- current 2020-07-15 -->
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/sprintf/1.1.2/sprintf.min.js" integrity="sha512-pmG0OkYtZVB2EqETE5HPsEaok7sNZFfStp5rNdpHv0tGQjbt1z8Qjzhtx88/4wsttOtDwq5DZGJyKyzEe7ribg==" crossorigin="anonymous"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/showdown/1.9.1/showdown.min.js" integrity="sha512-L03kznCrNOfVxOUovR6ESfCz9Gfny7gihUX/huVbQB9zjODtYpxaVtIaAkpetoiyV2eqWbvxMH9fiSv5enX7bw==" crossorigin="anonymous"></script>
|
||||
|
||||
<!-- Tablesorter -->
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery.tablesorter/2.31.3/js/jquery.tablesorter.min.js" integrity="sha512-qzgd5cYSZcosqpzpn7zF2ZId8f/8CHmFKZ8j7mU4OUXTNRd5g+ZHBPsgKEwoqxCtdQvExE5LprwwPAgoicguNg==" crossorigin="anonymous"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery.tablesorter/2.31.3/js/jquery.tablesorter.widgets.min.js" integrity="sha512-dj/9K5GRIEZu+Igm9tC16XPOTz0RdPk9FGxfZxShWf65JJNU2TjbElGjuOo3EhwAJRPhJxwEJ5b+/Ouo+VqZdQ==" crossorigin="anonymous"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery.tablesorter/2.31.3/js/widgets/widget-pager.min.js" integrity="sha512-+X/dsto9+7foPuqwqjm+mJSPYk6Coovg9jQJvM+aBfscXOyBrAKN69GS5Z2TkMLlVHxeiE5doVqelnMfbsS9XQ==" crossorigin="anonymous"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery.tablesorter/2.31.3/js/extras/jquery.tablesorter.pager.min.js" integrity="sha512-y845ijdup9lDunrcSRQAlFdQICHVhkB5UNguWRX8A3L+guxO7Oow0poojw0PLckhcKij++h85bnyro80fjR9+A==" crossorigin="anonymous"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery.tablesorter/2.31.3/js/widgets/widget-scroller.min.js" integrity="sha512-1D2qKse1/4gCgLbgmBBv+9fJluAeJIlDgzIyZkovd1xmoyh1SW30lMIzCrD2X8Xs/sIzitUNDy86YagJRSUmaA==" crossorigin="anonymous"></script>
|
||||
|
||||
<!-- Leaflet -->
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.7.1/leaflet.js" integrity="sha512-XQoYMqMTK8LvdxXYG3nZ448hOEQiglfqkJs1NOQV44cWnUrBc8PkAOcXy20w0vlaXaVUearIOBhiXZ5V3ynxwA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet-dvf/0.3.1/leaflet-dvf.markers.min.js" integrity="sha512-R/iucaxFnDFUTdZRxUvxzc+sypDQhqnxInBmNjgGE0RaiMl/ektVB1wFS/L0xDZmLFPpEGR0Kw3GEBgtQNFHyg==" crossorigin="anonymous"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet-providers/1.13.0/leaflet-providers.min.js" integrity="sha512-5EYsvqNbFZ8HX60keFbe56Wr0Mq5J1RrA0KdVcfGDhnjnzIRsDrT/S3cxdzpVN2NGxAB9omgqnlh4/06TvWCMw==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/leaflet.browser.print@1.0.6/dist/leaflet.browser.print.min.js" integrity="sha256-LrZphoL6+XVEuBR4BfhOIdRAMpRigQvsu3/iCNhQSXw=" crossorigin="anonymous"></script>
|
||||
<script src="https://www.mapquestapi.com/sdk/leaflet/v2.2/mq-map.js?key=RPOPuz3lA2GGBtVpEU0ugxtVoGba53Dt"></script>
|
||||
|
||||
<!-- Map, Events & Stations -->
|
||||
<script type="text/javascript" src="misc.js"></script>
|
||||
<script type="text/javascript" src="map.js.en"></script>
|
||||
<script type="text/javascript" src="events.js.en"></script>
|
||||
<script type="text/javascript" src="stations.js.en"></script>
|
||||
<script type="text/javascript" src="data/geolocation.js"></script>
|
||||
<script type="text/javascript" src="data/specialevents.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<!-- noscript -->
|
||||
<noscript>
|
||||
<div class="noscript">
|
||||
<div class="noscriptcontent">
|
||||
<h2>JavaScript disabled!</h2>
|
||||
<p>This page requires JavaScript to work. Please enable JavaScript.</p>
|
||||
<h2>Kein JavaScript verfügbar!</h2>
|
||||
<p>Diese Seite benötigt JavaScript. Bitte schalten Sie JavaScript ein.</p>
|
||||
<h2>Impressum</h2>
|
||||
<!--#include virtual="impressum.inc.de" -->
|
||||
</div>
|
||||
</div>
|
||||
</noscript>
|
||||
<!-- Tabs -->
|
||||
<div class="info" id="tabs">
|
||||
<ul>
|
||||
<li><a href="#eventstab"><span>Events</span></a></li>
|
||||
<li><a href="#stationstab"><span>Stations</span></a></li>
|
||||
<li><a href="#moretab"><span>More</span></a></li>
|
||||
<li class="infotab"><a href="#infotab"><span>Info</span></a></li>
|
||||
</ul>
|
||||
<!-- Ereignisse -->
|
||||
<div class="tab" id="eventstab">
|
||||
<div class="pager events" id="eventspager">
|
||||
<img src="external/first.png" class="first" alt="First" />
|
||||
<img src="external/prev.png" class="prev" alt="Prev" />
|
||||
<span class="pagedisplay"></span>
|
||||
<img src="external/next.png" class="next" alt="Next" />
|
||||
<img src="external/last.png" class="last" alt="Last" />
|
||||
<select class="pagesize" title="Select page size">
|
||||
<option value="5">5</option>
|
||||
<option value="10">10</option>
|
||||
<option value="15">15</option>
|
||||
<option value="20">20</option>
|
||||
<option value="25">25</option>
|
||||
<option value="30">30</option>
|
||||
<option value="35">35</option>
|
||||
</select>
|
||||
<select class="gotoPage" title="Select page number"></select>
|
||||
</div>
|
||||
<table class="tablesorter" id="eventstable">
|
||||
<colgroup>
|
||||
<col width="85" />
|
||||
<col width="50" />
|
||||
<col width="50" />
|
||||
<col />
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Date</th>
|
||||
<th>Time</th>
|
||||
<th>Mag.</th>
|
||||
<th>Place</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
</tbody>
|
||||
</table>
|
||||
<p class="table-caption">
|
||||
Events of the last <span id="events-timespan">180</span> days with magnitude <span id="events-minmag">1.2</span> or larger in the area of the map and special events in adjacents regions. Download as <a id="events-csv-link" href="link" download="events.csv">CSV file</a>.
|
||||
</p>
|
||||
<p class="table-caption">
|
||||
<span id="events-type">Symbols:</span>
|
||||
</p>
|
||||
<p class="table-caption">
|
||||
Reverse Geolocation courtesy of <a href="http://photon.komoot.io/" target="_blank">Photon by Komoot</a>
|
||||
</p>
|
||||
</div>
|
||||
<!-- Stations -->
|
||||
<div class="tab" id="stationstab">
|
||||
<div class="pager stationspager" id="stationspager">
|
||||
<img src="external/first.png" class="stationsfirst" alt="First" />
|
||||
<img src="external/prev.png" class="stationsprev" alt="Prev" />
|
||||
<span class="stationspagedisplay"></span>
|
||||
<img src="external/next.png" class="stationsnext" alt="Next" />
|
||||
<img src="external/last.png" class="stationslast" alt="Last" />
|
||||
<select class="stationspagesize" title="Select page size">
|
||||
<option value="5">5</option>
|
||||
<option value="10">10</option>
|
||||
<option value="15">15</option>
|
||||
<option value="20">20</option>
|
||||
<option value="25">25</option>
|
||||
<option value="30">30</option>
|
||||
<option value="35">35</option>
|
||||
</select>
|
||||
<select class="stationsgotoPage" title="Select page number"></select>
|
||||
</div>
|
||||
<table class="tablesorter" id="stationstable">
|
||||
<colgroup>
|
||||
<col width="77" />
|
||||
<col/>
|
||||
<col width="100" align="char" char="." />
|
||||
<col width="100" align="char" char="." />
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Network</th>
|
||||
<th>Station</th>
|
||||
<th>Latitude [°]</th>
|
||||
<th>Longitude [°]</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
</tbody>
|
||||
</table>
|
||||
<p class="table-caption">Download as <a id="stations-csv-link" href="link" download="stations.csv">CSV file</a>.</p>
|
||||
</div>
|
||||
<!-- More -->
|
||||
<div class="tab more_de" id="moretab">
|
||||
<p>Loading text ...</p>
|
||||
</div>
|
||||
<!-- Info -->
|
||||
<div class="tab" id="infotab">
|
||||
<div id="infoaccordion">
|
||||
<h3 class="aheader">Navigation / Links</h3>
|
||||
<div class="info_de"><p>Loading text ...</p></div>
|
||||
<h3 class="aheader">Copyright / Licence</h3>
|
||||
<div class="copyright_de"><p>Loading text ...</p></div>
|
||||
<h3 class="aheader">Imprint</h3>
|
||||
<div class="imprint_de"><p>Loading text ...</p></div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<!-- Logo -->
|
||||
<div class="rublogo"><a href="http://www.gmg.ruhr-uni-bochum.de/en/seisobs"><img class="rublogo" src="logo_RUB_155x30.png" alt="Ruhr-University Bochum" title="Ruhr-University Bochum" border="0"/></a></div>
|
||||
<!-- Map -->
|
||||
<div id="map" class="map"></div>
|
||||
<div id="spinner" class="spinner" style="display:none;"><img id="img-spinner" src="spinner.gif" alt="Loading"/><br />Loading ...</div>
|
||||
</body>
|
||||
</html>
|
22
www/info.inc.de
Normal file
@ -0,0 +1,22 @@
|
||||
<div class="accordioncontent">
|
||||
<h4>Navigation zu den Internetseiten</h4>
|
||||
<ul>
|
||||
<li>des <a class="intern" href="http://www.gmg.ruhr-uni-bochum.de/geophysik/seisobs">Seismologisches Observatorium</a><br /> der Ruhr-Universität Bochum</li>
|
||||
<li>der <a class="intern" href="http://www.gmg.ruhr-uni-bochum.de/geophysik/seismology">Arbeitsgruppe Seismologie</a></li>
|
||||
<li>des <a class="intern" href="http://www.gmg.ruhr-uni-bochum.de">Instituts für Geologie, Mineralogie und Geophysik</a></li>
|
||||
<li>der <a class="intern" href="http://www.rub.de">Ruhr-Universität Bochum</a></li>
|
||||
</ul>
|
||||
<h4>Informationen zu Erdbeben</h4>
|
||||
<ul>
|
||||
<li>in <a class="extern" target="_blank" href="http://www.gd.nrw.de/a_beben.php">NRW</a> (<a class="extern" target="_blank" href="http://www.gd.nrw.de">Geologischer Dienst NRW</a>)</li>
|
||||
<li>in <a class="extern" target="_blank" href="http://www.bgr.bund.de/DE/Themen/Erdbeben-Gefaehrdungsanalysen/Seismologie/Seismologie/Seis-Online/Liste_D_1Jahr/li_d_1jahr_node.html">Deutschland</a> (<a class="extern" target="_blank" href="http://www.bgr.bund.de">BGR Hannover</a>)</li>
|
||||
<li>in <a class="extern" target="_blank" href="http://www.emsc-csem.org">Europa / Mittelmeerraum</a> (<a class="extern" target="_blank" href="http://www.emsc-csem.org">EMSC</a>)</li>
|
||||
<li><a class="extern" target="_blank" href="http://geofon.gfz-potsdam.de/eqinfo/seismon/globmon.php">weltweit</a> (<a class="extern" target="_blank" href="http://geofon.gfz-potsdam.de">GEOFON, GFZ Potsdam</a>)</li>
|
||||
<li><a class="extern" target="_blank" href="http://earthquake.usgs.gov/earthquakes/map/">weltweit</a> (<a class="extern" target="_blank" href="http://earthquake.usgs.gov/">USGS</a>)</li>
|
||||
</ul>
|
||||
<h4>Informationen zum Steinkohlenabbau in NRW</h4>
|
||||
<ul>
|
||||
<li>Homepage der <a class="extern" target="_blank" href="http://www.rag.de">RAG</a></li>
|
||||
<li><a class="extern" target="_blank" href="http://www.bid.rag.de">Bürgerinformationssystem</a> der RAG</li>
|
||||
</ul>
|
||||
</div>
|
5
www/jquery.tablesorter.min.js
vendored
@ -1,42 +0,0 @@
|
||||
/* pager wrapper, div */
|
||||
.tablesorter-pager {
|
||||
padding: 5px;
|
||||
}
|
||||
/* pager wrapper, in thead/tfoot */
|
||||
td.tablesorter-pager {
|
||||
background-color: #e6eeee;
|
||||
margin: 0; /* needed for bootstrap .pager gets a 18px bottom margin */
|
||||
}
|
||||
/* pager navigation arrows */
|
||||
.tablesorter-pager img {
|
||||
vertical-align: middle;
|
||||
margin-right: 2px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/* pager output text */
|
||||
.tablesorter-pager .pagedisplay {
|
||||
padding: 0 5px 0 5px;
|
||||
width: auto;
|
||||
white-space: nowrap;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* pager element reset (needed for bootstrap) */
|
||||
.tablesorter-pager select {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/*** css used when "updateArrows" option is true ***/
|
||||
/* the pager itself gets a disabled class when the number of rows is less than the size */
|
||||
.tablesorter-pager.disabled {
|
||||
display: none;
|
||||
}
|
||||
/* hide or fade out pager arrows when the first or last row is visible */
|
||||
.tablesorter-pager .disabled {
|
||||
/* visibility: hidden */
|
||||
opacity: 0.5;
|
||||
filter: alpha(opacity=50);
|
||||
cursor: default;
|
||||
}
|
2
www/jquery.tablesorter.pager.min.js
vendored
17
www/jquery.tablesorter.widgets.min.js
vendored
478
www/leaflet.css
@ -1,478 +0,0 @@
|
||||
/* required styles */
|
||||
|
||||
.leaflet-map-pane,
|
||||
.leaflet-tile,
|
||||
.leaflet-marker-icon,
|
||||
.leaflet-marker-shadow,
|
||||
.leaflet-tile-pane,
|
||||
.leaflet-tile-container,
|
||||
.leaflet-overlay-pane,
|
||||
.leaflet-shadow-pane,
|
||||
.leaflet-marker-pane,
|
||||
.leaflet-popup-pane,
|
||||
.leaflet-overlay-pane svg,
|
||||
.leaflet-zoom-box,
|
||||
.leaflet-image-layer,
|
||||
.leaflet-layer {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
}
|
||||
.leaflet-container {
|
||||
overflow: hidden;
|
||||
-ms-touch-action: none;
|
||||
}
|
||||
.leaflet-tile,
|
||||
.leaflet-marker-icon,
|
||||
.leaflet-marker-shadow {
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
user-select: none;
|
||||
-webkit-user-drag: none;
|
||||
}
|
||||
.leaflet-marker-icon,
|
||||
.leaflet-marker-shadow {
|
||||
display: block;
|
||||
}
|
||||
/* map is broken in FF if you have max-width: 100% on tiles */
|
||||
.leaflet-container img {
|
||||
max-width: none !important;
|
||||
}
|
||||
/* stupid Android 2 doesn't understand "max-width: none" properly */
|
||||
.leaflet-container img.leaflet-image-layer {
|
||||
max-width: 15000px !important;
|
||||
}
|
||||
.leaflet-tile {
|
||||
filter: inherit;
|
||||
visibility: hidden;
|
||||
}
|
||||
.leaflet-tile-loaded {
|
||||
visibility: inherit;
|
||||
}
|
||||
.leaflet-zoom-box {
|
||||
width: 0;
|
||||
height: 0;
|
||||
}
|
||||
/* workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=888319 */
|
||||
.leaflet-overlay-pane svg {
|
||||
-moz-user-select: none;
|
||||
}
|
||||
|
||||
.leaflet-tile-pane { z-index: 2; }
|
||||
.leaflet-objects-pane { z-index: 3; }
|
||||
.leaflet-overlay-pane { z-index: 4; }
|
||||
.leaflet-shadow-pane { z-index: 5; }
|
||||
.leaflet-marker-pane { z-index: 6; }
|
||||
.leaflet-popup-pane { z-index: 7; }
|
||||
|
||||
.leaflet-vml-shape {
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
}
|
||||
.lvml {
|
||||
behavior: url(#default#VML);
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
|
||||
/* control positioning */
|
||||
|
||||
.leaflet-control {
|
||||
position: relative;
|
||||
z-index: 7;
|
||||
pointer-events: auto;
|
||||
}
|
||||
.leaflet-top,
|
||||
.leaflet-bottom {
|
||||
position: absolute;
|
||||
z-index: 1000;
|
||||
pointer-events: none;
|
||||
}
|
||||
.leaflet-top {
|
||||
top: 0;
|
||||
}
|
||||
.leaflet-right {
|
||||
right: 0;
|
||||
}
|
||||
.leaflet-bottom {
|
||||
bottom: 0;
|
||||
}
|
||||
.leaflet-left {
|
||||
left: 0;
|
||||
}
|
||||
.leaflet-control {
|
||||
float: left;
|
||||
clear: both;
|
||||
}
|
||||
.leaflet-right .leaflet-control {
|
||||
float: right;
|
||||
}
|
||||
.leaflet-top .leaflet-control {
|
||||
margin-top: 10px;
|
||||
}
|
||||
.leaflet-bottom .leaflet-control {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.leaflet-left .leaflet-control {
|
||||
margin-left: 10px;
|
||||
}
|
||||
.leaflet-right .leaflet-control {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
|
||||
/* zoom and fade animations */
|
||||
|
||||
.leaflet-fade-anim .leaflet-tile,
|
||||
.leaflet-fade-anim .leaflet-popup {
|
||||
opacity: 0;
|
||||
-webkit-transition: opacity 0.2s linear;
|
||||
-moz-transition: opacity 0.2s linear;
|
||||
-o-transition: opacity 0.2s linear;
|
||||
transition: opacity 0.2s linear;
|
||||
}
|
||||
.leaflet-fade-anim .leaflet-tile-loaded,
|
||||
.leaflet-fade-anim .leaflet-map-pane .leaflet-popup {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.leaflet-zoom-anim .leaflet-zoom-animated {
|
||||
-webkit-transition: -webkit-transform 0.25s cubic-bezier(0,0,0.25,1);
|
||||
-moz-transition: -moz-transform 0.25s cubic-bezier(0,0,0.25,1);
|
||||
-o-transition: -o-transform 0.25s cubic-bezier(0,0,0.25,1);
|
||||
transition: transform 0.25s cubic-bezier(0,0,0.25,1);
|
||||
}
|
||||
.leaflet-zoom-anim .leaflet-tile,
|
||||
.leaflet-pan-anim .leaflet-tile,
|
||||
.leaflet-touching .leaflet-zoom-animated {
|
||||
-webkit-transition: none;
|
||||
-moz-transition: none;
|
||||
-o-transition: none;
|
||||
transition: none;
|
||||
}
|
||||
|
||||
.leaflet-zoom-anim .leaflet-zoom-hide {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
|
||||
/* cursors */
|
||||
|
||||
.leaflet-clickable {
|
||||
cursor: pointer;
|
||||
}
|
||||
.leaflet-container {
|
||||
cursor: -webkit-grab;
|
||||
cursor: -moz-grab;
|
||||
}
|
||||
.leaflet-popup-pane,
|
||||
.leaflet-control {
|
||||
cursor: auto;
|
||||
}
|
||||
.leaflet-dragging .leaflet-container,
|
||||
.leaflet-dragging .leaflet-clickable {
|
||||
cursor: move;
|
||||
cursor: -webkit-grabbing;
|
||||
cursor: -moz-grabbing;
|
||||
}
|
||||
|
||||
|
||||
/* visual tweaks */
|
||||
|
||||
.leaflet-container {
|
||||
background: #ddd;
|
||||
outline: 0;
|
||||
}
|
||||
.leaflet-container a {
|
||||
color: #0078A8;
|
||||
}
|
||||
.leaflet-container a.leaflet-active {
|
||||
outline: 2px solid orange;
|
||||
}
|
||||
.leaflet-zoom-box {
|
||||
border: 2px dotted #38f;
|
||||
background: rgba(255,255,255,0.5);
|
||||
}
|
||||
|
||||
|
||||
/* general typography */
|
||||
.leaflet-container {
|
||||
font: 12px/1.5 "Helvetica Neue", Arial, Helvetica, sans-serif;
|
||||
}
|
||||
|
||||
|
||||
/* general toolbar styles */
|
||||
|
||||
.leaflet-bar {
|
||||
box-shadow: 0 1px 5px rgba(0,0,0,0.65);
|
||||
border-radius: 4px;
|
||||
}
|
||||
.leaflet-bar a,
|
||||
.leaflet-bar a:hover {
|
||||
background-color: #fff;
|
||||
border-bottom: 1px solid #ccc;
|
||||
width: 26px;
|
||||
height: 26px;
|
||||
line-height: 26px;
|
||||
display: block;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
color: black;
|
||||
}
|
||||
.leaflet-bar a,
|
||||
.leaflet-control-layers-toggle {
|
||||
background-position: 50% 50%;
|
||||
background-repeat: no-repeat;
|
||||
display: block;
|
||||
}
|
||||
.leaflet-bar a:hover {
|
||||
background-color: #f4f4f4;
|
||||
}
|
||||
.leaflet-bar a:first-child {
|
||||
border-top-left-radius: 4px;
|
||||
border-top-right-radius: 4px;
|
||||
}
|
||||
.leaflet-bar a:last-child {
|
||||
border-bottom-left-radius: 4px;
|
||||
border-bottom-right-radius: 4px;
|
||||
border-bottom: none;
|
||||
}
|
||||
.leaflet-bar a.leaflet-disabled {
|
||||
cursor: default;
|
||||
background-color: #f4f4f4;
|
||||
color: #bbb;
|
||||
}
|
||||
|
||||
.leaflet-touch .leaflet-bar a {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
}
|
||||
|
||||
|
||||
/* zoom control */
|
||||
|
||||
.leaflet-control-zoom-in,
|
||||
.leaflet-control-zoom-out {
|
||||
font: bold 18px 'Lucida Console', Monaco, monospace;
|
||||
text-indent: 1px;
|
||||
}
|
||||
.leaflet-control-zoom-out {
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.leaflet-touch .leaflet-control-zoom-in {
|
||||
font-size: 22px;
|
||||
}
|
||||
.leaflet-touch .leaflet-control-zoom-out {
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
|
||||
/* layers control */
|
||||
|
||||
.leaflet-control-layers {
|
||||
box-shadow: 0 1px 5px rgba(0,0,0,0.4);
|
||||
background: #fff;
|
||||
border-radius: 5px;
|
||||
}
|
||||
.leaflet-control-layers-toggle {
|
||||
background-image: url(images/layers.png);
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
}
|
||||
.leaflet-retina .leaflet-control-layers-toggle {
|
||||
background-image: url(images/layers-2x.png);
|
||||
background-size: 26px 26px;
|
||||
}
|
||||
.leaflet-touch .leaflet-control-layers-toggle {
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
}
|
||||
.leaflet-control-layers .leaflet-control-layers-list,
|
||||
.leaflet-control-layers-expanded .leaflet-control-layers-toggle {
|
||||
display: none;
|
||||
}
|
||||
.leaflet-control-layers-expanded .leaflet-control-layers-list {
|
||||
display: block;
|
||||
position: relative;
|
||||
}
|
||||
.leaflet-control-layers-expanded {
|
||||
padding: 6px 10px 6px 6px;
|
||||
color: #333;
|
||||
background: #fff;
|
||||
}
|
||||
.leaflet-control-layers-selector {
|
||||
margin-top: 2px;
|
||||
position: relative;
|
||||
top: 1px;
|
||||
}
|
||||
.leaflet-control-layers label {
|
||||
display: block;
|
||||
}
|
||||
.leaflet-control-layers-separator {
|
||||
height: 0;
|
||||
border-top: 1px solid #ddd;
|
||||
margin: 5px -10px 5px -6px;
|
||||
}
|
||||
|
||||
|
||||
/* attribution and scale controls */
|
||||
|
||||
.leaflet-container .leaflet-control-attribution {
|
||||
background: #fff;
|
||||
background: rgba(255, 255, 255, 0.7);
|
||||
margin: 0;
|
||||
}
|
||||
.leaflet-control-attribution,
|
||||
.leaflet-control-scale-line {
|
||||
padding: 0 5px;
|
||||
color: #333;
|
||||
}
|
||||
.leaflet-control-attribution a {
|
||||
text-decoration: none;
|
||||
}
|
||||
.leaflet-control-attribution a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
.leaflet-container .leaflet-control-attribution,
|
||||
.leaflet-container .leaflet-control-scale {
|
||||
font-size: 11px;
|
||||
}
|
||||
.leaflet-left .leaflet-control-scale {
|
||||
margin-left: 5px;
|
||||
}
|
||||
.leaflet-bottom .leaflet-control-scale {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
.leaflet-control-scale-line {
|
||||
border: 2px solid #777;
|
||||
border-top: none;
|
||||
line-height: 1.1;
|
||||
padding: 2px 5px 1px;
|
||||
font-size: 11px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
-moz-box-sizing: content-box;
|
||||
box-sizing: content-box;
|
||||
|
||||
background: #fff;
|
||||
background: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
.leaflet-control-scale-line:not(:first-child) {
|
||||
border-top: 2px solid #777;
|
||||
border-bottom: none;
|
||||
margin-top: -2px;
|
||||
}
|
||||
.leaflet-control-scale-line:not(:first-child):not(:last-child) {
|
||||
border-bottom: 2px solid #777;
|
||||
}
|
||||
|
||||
.leaflet-touch .leaflet-control-attribution,
|
||||
.leaflet-touch .leaflet-control-layers,
|
||||
.leaflet-touch .leaflet-bar {
|
||||
box-shadow: none;
|
||||
}
|
||||
.leaflet-touch .leaflet-control-layers,
|
||||
.leaflet-touch .leaflet-bar {
|
||||
border: 2px solid rgba(0,0,0,0.2);
|
||||
background-clip: padding-box;
|
||||
}
|
||||
|
||||
|
||||
/* popup */
|
||||
|
||||
.leaflet-popup {
|
||||
position: absolute;
|
||||
text-align: center;
|
||||
}
|
||||
.leaflet-popup-content-wrapper {
|
||||
padding: 1px;
|
||||
text-align: left;
|
||||
border-radius: 12px;
|
||||
}
|
||||
.leaflet-popup-content {
|
||||
margin: 13px 19px;
|
||||
line-height: 1.4;
|
||||
}
|
||||
.leaflet-popup-content p {
|
||||
margin: 18px 0;
|
||||
}
|
||||
.leaflet-popup-tip-container {
|
||||
margin: 0 auto;
|
||||
width: 40px;
|
||||
height: 20px;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
.leaflet-popup-tip {
|
||||
width: 17px;
|
||||
height: 17px;
|
||||
padding: 1px;
|
||||
|
||||
margin: -10px auto 0;
|
||||
|
||||
-webkit-transform: rotate(45deg);
|
||||
-moz-transform: rotate(45deg);
|
||||
-ms-transform: rotate(45deg);
|
||||
-o-transform: rotate(45deg);
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
.leaflet-popup-content-wrapper,
|
||||
.leaflet-popup-tip {
|
||||
background: white;
|
||||
|
||||
box-shadow: 0 3px 14px rgba(0,0,0,0.4);
|
||||
}
|
||||
.leaflet-container a.leaflet-popup-close-button {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
padding: 4px 4px 0 0;
|
||||
text-align: center;
|
||||
width: 18px;
|
||||
height: 14px;
|
||||
font: 16px/14px Tahoma, Verdana, sans-serif;
|
||||
color: #c3c3c3;
|
||||
text-decoration: none;
|
||||
font-weight: bold;
|
||||
background: transparent;
|
||||
}
|
||||
.leaflet-container a.leaflet-popup-close-button:hover {
|
||||
color: #999;
|
||||
}
|
||||
.leaflet-popup-scrolled {
|
||||
overflow: auto;
|
||||
border-bottom: 1px solid #ddd;
|
||||
border-top: 1px solid #ddd;
|
||||
}
|
||||
|
||||
.leaflet-oldie .leaflet-popup-content-wrapper {
|
||||
zoom: 1;
|
||||
}
|
||||
.leaflet-oldie .leaflet-popup-tip {
|
||||
width: 24px;
|
||||
margin: 0 auto;
|
||||
|
||||
-ms-filter: "progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678)";
|
||||
filter: progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678);
|
||||
}
|
||||
.leaflet-oldie .leaflet-popup-tip-container {
|
||||
margin-top: -1px;
|
||||
}
|
||||
|
||||
.leaflet-oldie .leaflet-control-zoom,
|
||||
.leaflet-oldie .leaflet-control-layers,
|
||||
.leaflet-oldie .leaflet-popup-content-wrapper,
|
||||
.leaflet-oldie .leaflet-popup-tip {
|
||||
border: 1px solid #999;
|
||||
}
|
||||
|
||||
|
||||
/* div icon */
|
||||
|
||||
.leaflet-div-icon {
|
||||
background: #fff;
|
||||
border: 1px solid #666;
|
||||
}
|
35
www/main.css
@ -13,6 +13,20 @@
|
||||
height: 100%;
|
||||
font-family: sans-serif;
|
||||
}
|
||||
div.noscript {
|
||||
z-index: 20000;
|
||||
position: absolute;
|
||||
left: 0px;
|
||||
top: 0px;
|
||||
width: 100%;
|
||||
height: 200%;
|
||||
background: rgb(255, 255, 255);
|
||||
}
|
||||
div.noscriptcontent {
|
||||
z-index: 20010;
|
||||
margin: 45px;
|
||||
font-size: small;
|
||||
}
|
||||
div.info {
|
||||
z-index: 10000;
|
||||
position: absolute;
|
||||
@ -38,6 +52,12 @@
|
||||
background: rgb(255, 255, 255);
|
||||
background: rgba(25, 255, 255, 0.95);
|
||||
}
|
||||
div.accordioncontent {
|
||||
z-index: 10010;
|
||||
margin: 0px!important;
|
||||
padding: 5px!important;
|
||||
font: sans-serif;
|
||||
}
|
||||
div.rublogo {
|
||||
z-index: 10000;
|
||||
position: absolute;
|
||||
@ -64,4 +84,19 @@
|
||||
td.ar {
|
||||
text-align: right;
|
||||
}
|
||||
p.table-caption {
|
||||
font-size: smaller;
|
||||
}
|
||||
div.spinner {
|
||||
position: fixed;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
margin-left: -64px; /* half width of the spinner gif */
|
||||
margin-top: -8px; /* half height of the spinner gif */
|
||||
text-align:center;
|
||||
z-index: 19000;
|
||||
overflow: auto;
|
||||
width: 128px; /* width of the spinner gif */
|
||||
height: 40px; /*hight of the spinner gif +2px to fix IE8 issue */
|
||||
}
|
||||
</style>
|
||||
|
277
www/map.js
@ -1,117 +1,107 @@
|
||||
/* 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") ) {
|
||||
eventTable[$(this).attr("eventid")].setStyle({opacity: 1, strokeOpacity: 1, fillOpacity: eventMarkerOpacity});
|
||||
};
|
||||
});
|
||||
/**********************************************************************
|
||||
* map.js *
|
||||
* script for map specific functions and setup *
|
||||
**********************************************************************/
|
||||
|
||||
// hide filtered events in map
|
||||
$("#eventstable > tbody > tr.filtered > td > a.map-link").each( function() {
|
||||
if ( $(this).attr("eventid") ) {
|
||||
eventTable[$(this).attr("eventid")].setStyle({opacity: 0, strokeOpacity: 0, fillOpacity: 0});
|
||||
};
|
||||
});
|
||||
highlightFirstEvent();
|
||||
};
|
||||
/* License
|
||||
Copyright 2014-2021 Kasper D. Fischer <kasper.fischer@rub.de>
|
||||
|
||||
/* Highlight the first event of the event list on the map if no
|
||||
* other event is selected */
|
||||
function highlightFirstEvent() {
|
||||
var highlightStyle = {
|
||||
color: 'red',
|
||||
fillColor: '#f03',
|
||||
};
|
||||
var normalStyle = {
|
||||
fillColor: "#FFF500",
|
||||
color: "#FFF500"
|
||||
};
|
||||
$("#eventstable a.map-link").each( function() {
|
||||
if ( $(this).attr("eventid") ) {
|
||||
eventTable[$(this).attr("eventid")].setStyle(normalStyle);
|
||||
$(this).removeClass('first');
|
||||
$(this).text('Karte');
|
||||
};
|
||||
});
|
||||
$("#eventstable > tbody > tr:not(.filtered)").first().find("a.map-link").each(function() {
|
||||
if ( $(this).attr("eventid") ) {
|
||||
eventTable[$(this).attr("eventid")].setStyle(highlightStyle);
|
||||
$(this).addClass('first');
|
||||
$(this).text('Karte (rot)');
|
||||
};
|
||||
});
|
||||
};
|
||||
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.
|
||||
|
||||
function highlightEvent( id ) {
|
||||
var highlightStyle = {
|
||||
color: 'red',
|
||||
fillColor: '#f03',
|
||||
};
|
||||
var normalStyle = {
|
||||
fillColor: "#FFF500",
|
||||
color: "#FFF500"
|
||||
};
|
||||
$("#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);
|
||||
$(this).addClass('first');
|
||||
$(this).text('Karte (rot)');
|
||||
} else {
|
||||
eventTable[$(this).attr("eventid")].setStyle(normalStyle);
|
||||
$(this).removeClass('first');
|
||||
$(this).text('Karte');
|
||||
}
|
||||
};
|
||||
});
|
||||
};
|
||||
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 https://www.gnu.org/licenses/.
|
||||
|
||||
Version v1.3 (2023-04-17)
|
||||
*/
|
||||
|
||||
/* add station marker */
|
||||
function addStationMarker(id, lat, lng) {
|
||||
var a = 0.0025,
|
||||
b = Math.sqrt(3)*a,
|
||||
a = a * Math.cos(lat*Math.PI/180);
|
||||
var corners = [L.latLng(lat+2*a, lng), L.latLng(lat-a, lng+b), L.latLng(lat-a, lng-b)];
|
||||
var marker = L.polygon(corners,
|
||||
function addStationMarker(id, lat, lng, station) {
|
||||
var marker = L.triangleMarker(L.latLng(lat, lng),
|
||||
{
|
||||
fillColor: "#1C771C",
|
||||
color: "#1C771C",
|
||||
gradient: true,
|
||||
fillColor: config['station']['markerColor'],
|
||||
fillOpacity: config['station']['markerOpacity'],
|
||||
color: config['station']['markerColor'],
|
||||
weight: 1,
|
||||
opacity: 1,
|
||||
fillOpacity: stationMarkerOpacity,
|
||||
radius: config['station']['markerSize'][id] || config['station']['markerSize']['defaultSize'],
|
||||
className: id+' stationMarker',
|
||||
}).addTo(stationLayer);
|
||||
});
|
||||
marker.bindTooltip('Station '+station);
|
||||
stationLayer.addLayer(marker);
|
||||
stationTable[id] = marker;
|
||||
};
|
||||
|
||||
/* add event marker */
|
||||
function addEventMarker(id, lat, lng, mag) {
|
||||
var markerOptions = {
|
||||
fillColor: "#FFF500",
|
||||
color: "#FFF500",
|
||||
weight: 1,
|
||||
opacity: 1,
|
||||
fillOpacity: eventMarkerOpacity,
|
||||
className: id+' eventMarker',
|
||||
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 'nuclear explosion':
|
||||
markerOptions['numberOfSides'] = 4;
|
||||
markerOptions['radius'] = 2.0*markerOptions['radius'];
|
||||
markerOptions['innerRadius'] = 0.3*markerOptions['radius'];
|
||||
marker = L.regularPolygonMarker(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':
|
||||
case 'controlled explosion':
|
||||
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;
|
||||
};
|
||||
var marker = L.circle(L.latLng(lat, lng), mag2radius(mag), markerOptions).addTo(eventLayer);
|
||||
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: 'red',
|
||||
fillColor: '#f03',
|
||||
color: config['event']['markerColorH'],
|
||||
fillColor: config['event']['markerColorH'],
|
||||
fillOpacity: 1,
|
||||
className: $(this).attr('eventid')
|
||||
}
|
||||
var normalStyle = {
|
||||
fillColor: "#FFF500",
|
||||
color: "#FFF500"
|
||||
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
|
||||
@ -129,64 +119,103 @@ function initMapLink() {
|
||||
if ( $(this).hasClass('selected') ) {
|
||||
$(this).removeClass('selected');
|
||||
$(this).text('Karte');
|
||||
map.setView(config['map']['centerDefault'], config['map']['zoomDefault']);
|
||||
eventTable[$(this).attr('eventid')].setStyle(normalStyle);
|
||||
map.setView(mapCentreDefault, zoomDefault);
|
||||
highlightFirstEvent();
|
||||
// unselected -> selected
|
||||
} else {
|
||||
$(this).addClass('selected');
|
||||
$(this).text('im Fokus (rot)');
|
||||
eventTable[$(this).attr('eventid')].setStyle(highlightStyle);
|
||||
map.setView(eventTable[$(this).attr('eventid')].getLatLng(), zoomFocus);
|
||||
map.setView(eventTable[$(this).attr('eventid')].getLatLng(), config['map']['zoomFocus']);
|
||||
eventTable[$(this).attr('eventid')].setStyle(highlightStyle)
|
||||
};
|
||||
});
|
||||
return false;
|
||||
});
|
||||
};
|
||||
|
||||
/******************
|
||||
* document ready *
|
||||
******************/
|
||||
/**********************************************************************
|
||||
* 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 }).setView(mapCentreDefault, zoomDefault);
|
||||
map = L.map('map', {
|
||||
center: config['map']['centerDefault'],
|
||||
zoom: config['map']['zoomDefault'],
|
||||
zoomControl: false,
|
||||
worldCopyJump: true
|
||||
});
|
||||
|
||||
// change baselayer if mapquest is not requested
|
||||
switch ( config['map']['baselayer'] ) {
|
||||
case 'esrigray': // add ESRI Grayscale World Map (neither city nor road names)
|
||||
L.tileLayer.provider('Esri.WorldGrayCanvas').addTo(map);
|
||||
break;
|
||||
case 'aerial': // add ESRI WordImagery tile layer
|
||||
L.tileLayer.provider('Esri.WorldImagery').addTo(map);
|
||||
break;
|
||||
case 'opentopo': // add OpenTopoMap tile layer
|
||||
L.tileLayer.provider('OpenTopoMap').addTo(map);
|
||||
break;
|
||||
case 'mapnik': // add OpenStreetMap.Mapnik tile layer
|
||||
L.tileLayer.provider('OpenStreetMap.Mapnik').addTo(map);
|
||||
break;
|
||||
case 'topplus': // add TopPlus tile layer (https://gdz.bkg.bund.de/index.php/default/webdienste/topplus-produkte/wmts-topplusopen-wmts-topplus-open.html)
|
||||
L.tileLayer('https://sgx.geodatenzentrum.de/wmts_topplus_open/tile/1.0.0/web/default/WEBMERCATOR/{z}/{y}/{x}.png',
|
||||
{attribution: '© Bundesamt für Kartographie und Geodäsie ('+jahr+'), Datenquellen: <a href="http://sg.geodatenzentrum.de/web_public/Datenquellen_TopPlus_Open.pdf">Geodatenzentrum</a>'}).addTo(map);
|
||||
break;
|
||||
case 'mapquest':
|
||||
MQ.mapLayer().addTo(map);
|
||||
break;
|
||||
default: // use OpenStreetMap.DE as default
|
||||
L.tileLayer.provider('OpenStreetMap.DE').addTo(map);
|
||||
};
|
||||
|
||||
// add controls
|
||||
new L.Control.Zoom({ position: 'topright' }).addTo(map);
|
||||
new L.control.scale({position: 'bottomright', imperial: false}).addTo(map);
|
||||
|
||||
// add MapQuestOSM tile layer
|
||||
// L.tileLayer.grayscale('http://otile{s}.mqcdn.com/tiles/1.0.0/map/{z}/{x}/{y}.jpg',
|
||||
L.tileLayer('http://otile{s}.mqcdn.com/tiles/1.0.0/map/{z}/{x}/{y}.jpg',
|
||||
{
|
||||
subdomains: '1234',
|
||||
detectRetina: true,
|
||||
attribution: 'Map data © <a href="https://openstreetmap.org">OpenStreetMap</a> contributors, <a href="https://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a> | Tiles Courtesy of <a href="http://www.mapquest.com/">MapQuest</a> <img src="https://developer.mapquest.com/content/osm/mq_logo.png">',
|
||||
}).addTo(map);
|
||||
// create station and event layer
|
||||
// stationLayer = L.geoJson().addTo(map);
|
||||
stationLayer = new L.MarkerGroup().addTo(map);
|
||||
eventLayer = new L.MarkerGroup().addTo(map);
|
||||
|
||||
// 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); */
|
||||
|
||||
// read in stations
|
||||
stationLayer = L.geoJson().addTo(map);
|
||||
|
||||
// read in events, process filter
|
||||
eventLayer = L.geoJson().addTo(map);
|
||||
// load events
|
||||
ajaxLoadEvents('', '', '', 'data/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")});
|
||||
var eventid = $("div.leaflet-popup h3").attr("eventid");
|
||||
if ( eventid ) {
|
||||
// highlight event in table
|
||||
highlightEvent(eventid);
|
||||
openMarkerID = $("div.leaflet-popup h3").attr("eventid");
|
||||
if ( openMarkerID ) {
|
||||
// update city in popup
|
||||
$("div.leaflet-popup h3").text(geolocationTable[eventid]);
|
||||
$("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.control.browserPrint({
|
||||
title: 'print map',
|
||||
position: 'topright',
|
||||
}).addTo(map);
|
||||
});
|
||||
|
221
www/map.js.en
Normal file
@ -0,0 +1,221 @@
|
||||
/**********************************************************************
|
||||
* map.js.en *
|
||||
* script for map specific functions and setup *
|
||||
**********************************************************************/
|
||||
|
||||
/* License
|
||||
Copyright 2014-2021 Kasper D. Fischer <kasper.fischer@rub.de>
|
||||
|
||||
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 https://www.gnu.org/licenses/.
|
||||
|
||||
Version v1.3 (2023-04-17)
|
||||
*/
|
||||
|
||||
/* 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']['defaultSize'],
|
||||
className: id+' stationMarker',
|
||||
});
|
||||
marker.bindTooltip('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 'nuclear explosion':
|
||||
markerOptions['numberOfSides'] = 4;
|
||||
markerOptions['radius'] = 2.0*markerOptions['radius'];
|
||||
markerOptions['innerRadius'] = 0.3*markerOptions['radius'];
|
||||
marker = L.regularPolygonMarker(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':
|
||||
case 'controlled explosion':
|
||||
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() {
|
||||
|
||||
map = L.map('map', {
|
||||
center: config['map']['centerDefault'],
|
||||
zoom: config['map']['zoomDefault'],
|
||||
zoomControl: false,
|
||||
worldCopyJump: true
|
||||
});
|
||||
|
||||
// change baselayer if mapquest is not requested
|
||||
switch ( config['map']['baselayer'] ) {
|
||||
case 'esrigray': // add ESRI Grayscale World Map (neither city nor road names)
|
||||
L.tileLayer.provider('Esri.WorldGrayCanvas').addTo(map);
|
||||
break;
|
||||
case 'aerial': // add ESRI WordImagery tile layer
|
||||
L.tileLayer.provider('Esri.WorldImagery').addTo(map);
|
||||
break;
|
||||
case 'opentopo': // add OpenTopoMap tile layer
|
||||
L.tileLayer.provider('OpenTopoMap').addTo(map);
|
||||
break;
|
||||
case 'mapnik': // add OpenStreetMap.Mapnik tile layer
|
||||
L.tileLayer.provider('OpenStreetMap.Mapnik').addTo(map);
|
||||
break;
|
||||
case 'topplus': // add TopPlus tile layer (https://gdz.bkg.bund.de/index.php/default/webdienste/topplus-produkte/wmts-topplusopen-wmts-topplus-open.html)
|
||||
L.tileLayer('https://sgx.geodatenzentrum.de/wmts_topplus_open/tile/1.0.0/web/default/WEBMERCATOR/{z}/{y}/{x}.png',
|
||||
{attribution: '© Federal Agency for Cartography and Geodesy ('+jahr+'), Datasource: <a href="http://sg.geodatenzentrum.de/web_public/Datenquellen_TopPlus_Open.pdf">Geodatenzentrum</a>'}).addTo(map);
|
||||
break;
|
||||
case 'mapquest':
|
||||
MQ.mapLayer().addTo(map);
|
||||
break;
|
||||
default: // use OpenStreetMap.DE as default
|
||||
L.tileLayer.provider('OpenStreetMap.DE').addTo(map);
|
||||
};
|
||||
|
||||
// add controls
|
||||
new L.Control.Zoom({ position: 'topright' }).addTo(map);
|
||||
new L.control.scale({position: 'bottomright', imperial: false}).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('', '', '', 'data/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.control.browserPrint({
|
||||
title: 'print map',
|
||||
position: 'topright',
|
||||
}).addTo(map);
|
||||
});
|
237
www/misc.js
@ -1,23 +1,38 @@
|
||||
// calculate marker radius from magnitude, both formulas have equal radii at mag=1.2
|
||||
/**********************************************************************
|
||||
* misc.js *
|
||||
* script for unspecific functions and setup *
|
||||
**********************************************************************/
|
||||
|
||||
/* License
|
||||
Copyright 2014-2023 Kasper D. Fischer <kasper.fischer@rub.de>
|
||||
|
||||
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/.
|
||||
|
||||
Version v1.3 (2023-04-17)
|
||||
*/
|
||||
|
||||
/* calculate marker radius from magnitude
|
||||
* both formulas have equal radii at mag=1.2 */
|
||||
function mag2radius(mag) {
|
||||
return 400*mag; // radius proportional to magagnitude
|
||||
return 3*mag; // radius proportional to magnitude
|
||||
// return 8.104*Math.pow(30,mag) // radius proportional to energy
|
||||
};
|
||||
|
||||
// set height of eventlist div
|
||||
function sleep(milliseconds) {
|
||||
var start = new Date().getTime();
|
||||
for (var i = 0; i < 1e7; i++) {
|
||||
if ((new Date().getTime() - start) > milliseconds){
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* set height of eventlist div */
|
||||
function setInfoHeight() {
|
||||
var height = $('div.map').height() - 36;
|
||||
$('div.info').height(height);
|
||||
//$('.tab').height(height-80);
|
||||
//$('#eventtable').height(height-100);
|
||||
};
|
||||
|
||||
/* get region and regionID of a location */
|
||||
@ -51,36 +66,186 @@ function getLocation(lat, lng) {
|
||||
return [ region, regionID ];
|
||||
};
|
||||
|
||||
// window resize
|
||||
$( window ).resize(function() {
|
||||
setInfoHeight();
|
||||
});
|
||||
/* window resize */
|
||||
$( window ).on('resize', function() { setInfoHeight(); });
|
||||
|
||||
// create global vars
|
||||
var map
|
||||
/* parseQueryString */
|
||||
function parseQueryString() {
|
||||
var query = (window.location.search || '?').substr(1),
|
||||
map = {};
|
||||
query.replace(/([^&=]+)=?([^&]*)(?:&+|$)/g, function(match, key, value) {
|
||||
key.toLowerCase();
|
||||
(map[key] = map[key] || []).push(value);
|
||||
});
|
||||
return map;
|
||||
}
|
||||
|
||||
/* create global vars */
|
||||
var jahr = new Date().getFullYear();
|
||||
var map;
|
||||
var openMarkerID;
|
||||
var eventTable = {};
|
||||
var geolocationTable = {};
|
||||
var eventDetails = {};
|
||||
var stationTable = {};
|
||||
var eventMarkerOpacity = 0.3;
|
||||
var stationMarkerOpacity = 0.5;
|
||||
var zoomFocus = 12;
|
||||
var zoomDefault = 9;
|
||||
var mapCentreDefault = [51.85, 7.0];
|
||||
var minMag = 1.2;
|
||||
var config = {
|
||||
ajax: {
|
||||
timeout: 20000, // 20 seconds
|
||||
eventURL: 'https://fdsnws.geophysik.ruhr-uni-bochum.de/fdsnws/event/1/query',
|
||||
dlsvURL: 'dlsv',
|
||||
mseedURL: 'https://fdsnws.geophysik.ruhr-uni-bochum.de/fdsnws/dataselect/1/query',
|
||||
stationURL: 'https://fdsnws.geophysik.ruhr-uni-bochum.de/fdsnws/station/1/query',
|
||||
nominatimURL: 'https://photon.komoot.io/reverse',
|
||||
timespan: 400,
|
||||
},
|
||||
event: {
|
||||
evaluationBlacklist: ['automatic', 'preliminary', 'rejected'],
|
||||
markerOpacity: 0.4,
|
||||
markerColor: 'blue',
|
||||
markerColorH: 'red',
|
||||
minMag: 0.7,
|
||||
minMagDelta: 0.1,
|
||||
typeWhitelist: ['earthquake', 'induced or triggered event', 'controlled explosion'],
|
||||
// typeWhitelist: ['earthquake', 'induced or triggered event', 'controlled explosion', 'nuclear explosion'],
|
||||
// typeWhitelist: ['earthquake', 'induced or triggered event'],
|
||||
},
|
||||
map: {
|
||||
zoomDefault: 9,
|
||||
zoomFocus: 12,
|
||||
centerDefault: [51.85, 7.0],
|
||||
timespan: 180,
|
||||
latlngDelta: 0.1,
|
||||
baselayer: 'OpenStreetMap.DE',
|
||||
},
|
||||
station: {
|
||||
markerColor: 'darkgreen',
|
||||
markerOpacity: 1,
|
||||
markerSize: {
|
||||
defaultSize: 8,
|
||||
GE_IBBN: 10,
|
||||
GR_BUG: 10,
|
||||
GR_KAST: 10,
|
||||
NL_HGN: 3,
|
||||
NL_OPLO: 3,
|
||||
NL_VKB: 3,
|
||||
NL_WIT: 3,
|
||||
NL_WTSB: 3,
|
||||
},
|
||||
networkBlacklist: ['NL', 'X5', '1A', 'AM'],
|
||||
stationBlacklist: ['RN_WEA2', 'RN_ACN', 'RN_BHE', 'RN_ENT', 'RN_GSH', 'RN_HES', 'RN_JCKS', 'RN_LOH',
|
||||
'RN_OLF', 'RN_PLH', 'RN_RWB', 'RN_SOR', 'RN_TDN', 'RN_WBS',
|
||||
'RN_HAM1', 'RN_HAM2', 'RN_HAM3', 'RN_HAM4', 'RN_HAM5', 'RN_HAM6', 'RN_HAM7', 'RN_HAM8', 'RN_HAM9',
|
||||
'RN_HAM10', 'RN_HAM11', 'RN_HAM12', 'RN_HAM13', 'RN_HAM14', 'RN_HAM15', 'RN_HAM16', 'RN_HAM17'],
|
||||
},
|
||||
tab: {
|
||||
active: 0,
|
||||
disabled: [2],
|
||||
max: 4,
|
||||
},
|
||||
};
|
||||
var networkURL = {
|
||||
GE: 'http://dx.doi.org/10.14470/TR560404',
|
||||
GR: 'http://www.bgr.bund.de/DE/Themen/Erdbeben-Gefaehrdungsanalysen/Seismologie/Seismologie/Seismometer_Stationen/Stationsnetze/d_stationsnetz_node.html',
|
||||
NH: 'http://www.gd.nrw.de/gg_le.htm',
|
||||
NL: 'http://www.knmi.nl/seismologie/seismisch_network_knmi3.html',
|
||||
RN: 'https://doi.org/10.7914/SN/RN',
|
||||
YD: 'https://doi.org/10.7914/SN/YD_2020',
|
||||
};
|
||||
var networkText = {
|
||||
GE: '<a href="'+networkURL['GE']+'" target="_blank">GEOFON Seismic Network</a> - Deutsches GeoForschungsZentrum GFZ',
|
||||
GR: '<a href="'+networkURL['GR']+'" target="_blank">German Regional Seismic Network</a>, BGR Hannover',
|
||||
NH: '<a href="'+networkURL['NH']+'" target="_blank">Geologischer Dienst NRW</a>, Krefeld',
|
||||
NL: '<a href="'+networkURL['NL']+'" target="_blank">Netherlands Seismic Network</a>, The Netherlands',
|
||||
RN: '<a href="'+networkURL['RN']+'" target="_blank">RuhrNet - Ruhr-University Bochum, Germany</a>',
|
||||
YD: '<a href="'+networkURL['YD']+'" target="_blank">FloodRisk Seismic Network</a>',
|
||||
};
|
||||
var bochumStation = ['BUG', 'IBBN', 'KERA', 'KARP'];
|
||||
|
||||
// run when ready
|
||||
// FIX: firefox has no console
|
||||
if (typeof console == "undefined") var console = { log: function() {} };
|
||||
|
||||
/**********************************************************************
|
||||
* document ready *
|
||||
**********************************************************************/
|
||||
$(document).ready(function() {
|
||||
// parse query string
|
||||
var parameters = parseQueryString();
|
||||
if ( parameters['baselayer']) {
|
||||
config['map']['baselayer'] = parameters['baselayer'][0];
|
||||
};
|
||||
if ( parameters['basemap'] ) {
|
||||
config['map']['baselayer'] = parameters['basemap'][0];
|
||||
};
|
||||
if ( Number(parameters['lat']) && Number(parameters['lon']) ) {
|
||||
config['map']['centerDefault'] = [Number(parameters['lat']), Number(parameters['lon'])];
|
||||
};
|
||||
if ( Number(parameters['minmag']) ) {
|
||||
config['event']['minMag'] = Number(parameters['minmag']);
|
||||
};
|
||||
if ( parameters['eventcolor'] ) {
|
||||
config['event']['markerColor'] = parameters['eventcolor'];
|
||||
};
|
||||
if ( parameters['eventcolorh'] ) {
|
||||
config['event']['markerColorH'] = parameters['eventcolorh'];
|
||||
};
|
||||
if ( parameters['stationcolor'] ) {
|
||||
config['station']['markerColor'] = parameters['stationcolor'];
|
||||
};
|
||||
if ( Number(parameters['timespan']) ) {
|
||||
config['map']['timespan'] = Number(parameters['timespan']);
|
||||
};
|
||||
if ( Number(parameters['tab']) ) {
|
||||
if ( Number(parameters['tab']) < config['tab']['max'] ) {
|
||||
config['tab']['active'] = Number(parameters['tab']);
|
||||
};
|
||||
};
|
||||
if ( Number(parameters['zoom']) ) {
|
||||
config['map']['zoomDefault'] = Number(parameters['zoom']);
|
||||
config['map']['zoomFocus'] = Number(parameters['zoom']+3);
|
||||
};
|
||||
|
||||
// AJAX setup
|
||||
$.ajaxSetup({timeout: 15000}); // 15 seconds
|
||||
$.ajaxSetup({timeout: config['ajax']['timeout']});
|
||||
|
||||
// adjust height of infocontainer
|
||||
setInfoHeight();
|
||||
// create tabs
|
||||
var tabOptions = {
|
||||
active: 0,
|
||||
disabled: [2, 3],
|
||||
};
|
||||
$('#tabs').tabs(tabOptions);
|
||||
// $('.ui-tabs-nav').sortable();
|
||||
});
|
||||
|
||||
// create tabs
|
||||
$('#tabs').tabs({
|
||||
active: config['tab']['active'],
|
||||
disabled: config['tab']['disabled'],
|
||||
activate: function( event, ui ) { ui['newPanel'].find('table').trigger("update", [true]); },
|
||||
});
|
||||
// create accordions
|
||||
$( '#infoaccordion' ).accordion({
|
||||
active: 0,
|
||||
header: 'h3.aheader',
|
||||
heightStyle: 'content',
|
||||
animate: 200,
|
||||
});
|
||||
// spinner
|
||||
$(document).on("ajaxSend", function() {
|
||||
$("#spinner").show();
|
||||
}).on("ajaxStop", function() {
|
||||
$("#spinner").hide();
|
||||
});
|
||||
|
||||
// load more tab content
|
||||
$.get("more_de.md", function( data ) {
|
||||
var converter = new showdown.Converter();
|
||||
$('.more_de').html(converter.makeHtml(data));
|
||||
});
|
||||
$.get("more_en.md", function( data ) {
|
||||
var converter = new showdown.Converter();
|
||||
$('.more_en').html(converter.makeHtml(data));
|
||||
});
|
||||
// load info tab content
|
||||
$.get("info.inc.de", function( data ) {
|
||||
$('.info_de, .info_en').html(data);
|
||||
});
|
||||
$.get("copyright.inc.de", function( data ) {
|
||||
$('.copyright_de, .copyright_en').html(data);
|
||||
});
|
||||
$.get("impressum.inc.de", function( data ) {
|
||||
$('.imprint_de, .imprint_en').html(data);
|
||||
});
|
||||
});
|
||||
|
9
www/more_de.md
Normal file
@ -0,0 +1,9 @@
|
||||
# Seismologisches Observatorium
|
||||
## Stationsnetz
|
||||
|
||||
Das seismologische Observatorium der Ruhr-Universität Bochum betreibt mehrere seismologische Stationen im Ruhrgebiet, im Raum Ibbenbüren und im Alpenvorland. Zwei breitbandige Stationen (BUG und IBBN) sind gleichzeitig Bestandteil des Deutschen Seismologischen Regionalnetzes (GRSN). Sie befinden sich in der Nähe der Ruhr-Universität in einem stillgelegten Stollen der Zeche Klosterbusch bzw. bei Ibbenbüren.
|
||||
|
||||
## Seismologische Netzwerke
|
||||
### RuhrNet (RN)
|
||||
### FloodRisk (YD)
|
||||
### AlpArray (Z3)
|
9
www/more_en.md
Normal file
@ -0,0 +1,9 @@
|
||||
# Seismological Observatory
|
||||
## Station Network
|
||||
|
||||
The seismological observatory of the Ruhr-University Bochum (Germany) maintains several seismolocical stations in the Ruhr area, around Ibbenbueren and in the foreland of the Alps. Two broadband stations (BUG and IBBN) are also part of the German Regional Seismological Network (GRSN). These are located near the Ruhr-University in an abandoned coal mine and near the city of Ibbenbueren.
|
||||
|
||||
## Seismological Networks
|
||||
### RuhrNet (RN)
|
||||
### FloodRisk (YD)
|
||||
### AlpArray (Z3)
|
BIN
www/spinner.gif
Normal file
After Width: | Height: | Size: 3.9 KiB |
1
www/sprintf.min.js
vendored
@ -1 +0,0 @@
|
||||
/*! sprintf.js | Copyright (c) 2007-2013 Alexandru Marasteanu <hello at alexei dot ro> | 3 clause BSD license */(function(e){function r(e){return Object.prototype.toString.call(e).slice(8,-1).toLowerCase()}function i(e,t){for(var n=[];t>0;n[--t]=e);return n.join("")}var t=function(){return t.cache.hasOwnProperty(arguments[0])||(t.cache[arguments[0]]=t.parse(arguments[0])),t.format.call(null,t.cache[arguments[0]],arguments)};t.format=function(e,n){var s=1,o=e.length,u="",a,f=[],l,c,h,p,d,v;for(l=0;l<o;l++){u=r(e[l]);if(u==="string")f.push(e[l]);else if(u==="array"){h=e[l];if(h[2]){a=n[s];for(c=0;c<h[2].length;c++){if(!a.hasOwnProperty(h[2][c]))throw t('[sprintf] property "%s" does not exist',h[2][c]);a=a[h[2][c]]}}else h[1]?a=n[h[1]]:a=n[s++];if(/[^s]/.test(h[8])&&r(a)!="number")throw t("[sprintf] expecting number but found %s",r(a));switch(h[8]){case"b":a=a.toString(2);break;case"c":a=String.fromCharCode(a);break;case"d":a=parseInt(a,10);break;case"e":a=h[7]?a.toExponential(h[7]):a.toExponential();break;case"f":a=h[7]?parseFloat(a).toFixed(h[7]):parseFloat(a);break;case"o":a=a.toString(8);break;case"s":a=(a=String(a))&&h[7]?a.substring(0,h[7]):a;break;case"u":a>>>=0;break;case"x":a=a.toString(16);break;case"X":a=a.toString(16).toUpperCase()}a=/[def]/.test(h[8])&&h[3]&&a>=0?"+"+a:a,d=h[4]?h[4]=="0"?"0":h[4].charAt(1):" ",v=h[6]-String(a).length,p=h[6]?i(d,v):"",f.push(h[5]?a+p:p+a)}}return f.join("")},t.cache={},t.parse=function(e){var t=e,n=[],r=[],i=0;while(t){if((n=/^[^\x25]+/.exec(t))!==null)r.push(n[0]);else if((n=/^\x25{2}/.exec(t))!==null)r.push("%");else{if((n=/^\x25(?:([1-9]\d*)\$|\(([^\)]+)\))?(\+)?(0|'[^$])?(-)?(\d+)?(?:\.(\d+))?([b-fosuxX])/.exec(t))===null)throw"[sprintf] huh?";if(n[2]){i|=1;var s=[],o=n[2],u=[];if((u=/^([a-z_][a-z_\d]*)/i.exec(o))===null)throw"[sprintf] huh?";s.push(u[1]);while((o=o.substring(u[0].length))!=="")if((u=/^\.([a-z_][a-z_\d]*)/i.exec(o))!==null)s.push(u[1]);else{if((u=/^\[(\d+)\]/.exec(o))===null)throw"[sprintf] huh?";s.push(u[1])}n[2]=s}else i|=2;if(i===3)throw"[sprintf] mixing positional and named placeholders is not (yet) supported";r.push(n)}t=t.substring(n[0].length)}return r};var n=function(e,n,r){return r=n.slice(0),r.splice(0,0,e),t.apply(null,r)};e.sprintf=t,e.vsprintf=n})(typeof exports!="undefined"?exports:window);
|
202
www/stations.js
@ -1,48 +1,110 @@
|
||||
// Load the stations using ajax
|
||||
function loadStations(stime, etime) {
|
||||
/**********************************************************************
|
||||
* stations.js *
|
||||
* script for station specific functions and setup *
|
||||
**********************************************************************/
|
||||
|
||||
/* License
|
||||
Copyright 2014-2021 Kasper D. Fischer <kasper.fischer@rub.de>
|
||||
|
||||
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/.
|
||||
|
||||
Version v1.3 (2023-04-17)
|
||||
*/
|
||||
|
||||
/* Load the stations using ajax */
|
||||
function loadStations(station, stime, etime) {
|
||||
var mapBounds = map.getBounds();
|
||||
var N = mapBounds.getNorth();
|
||||
var E = mapBounds.getEast();
|
||||
var S = mapBounds.getSouth();
|
||||
var W = mapBounds.getWest();
|
||||
var d = 0.1;
|
||||
var url = "https://ariadne.geophysik.ruhr-uni-bochum.de/fdsnws/station/1/query";
|
||||
if ( !stime ) {
|
||||
var stime = new Date();
|
||||
stime.setDate(stime.getDate()-180);
|
||||
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()),
|
||||
minlat: S-d,
|
||||
maxlat: N+d,
|
||||
minlon: W-d,
|
||||
maxlon: E+d,
|
||||
if ( !station ) {
|
||||
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: 'station',
|
||||
minlat: S-config['map']['latlngDelta'],
|
||||
maxlat: N+config['map']['latlngDelta'],
|
||||
minlon: W-config['map']['latlngDelta'],
|
||||
maxlon: E+config['map']['latlngDelta'],
|
||||
};
|
||||
} else {
|
||||
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',
|
||||
station: station,
|
||||
};
|
||||
};
|
||||
$.ajax({
|
||||
type: "GET",
|
||||
url: url,
|
||||
url: config['ajax']['stationURL'],
|
||||
dataType: "xml",
|
||||
data: request_data,
|
||||
success: function (xml) {
|
||||
$(xml).find('Network').each(function () {
|
||||
var network = $(this).attr('code');
|
||||
$(this).find('Station').each(function () {
|
||||
var station = $(this).attr('code'),
|
||||
lat = $(this).find('Latitude').text(),
|
||||
lng = $(this).find('Longitude').text(),
|
||||
stationID = network+'.'+station;
|
||||
if ( !stationTable[stationID] ) { // && N >= lat && S <= lat && W<= lng && E >= lng
|
||||
var row = sprintf('<tr><td>%s</td><td>%s</td><td class="ar">%7.4f</td><td class="ar">%7.4f</td></tr>' , network, station, Number(lat), Number(lng));
|
||||
var r = $(row);
|
||||
$('#stationstable tbody').append(r);
|
||||
addStationMarker(stationID, Number(lat), Number(lng));
|
||||
};
|
||||
});
|
||||
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] && $.inArray(stationID, config['station']['stationBlacklist']) <0 ) {
|
||||
// general station info (1st line)
|
||||
var row = sprintf('<tr><td><a href="#" class="toggle">%s</a></td><td><a href="#" class="toggle">%s</a></td><td class="ar">%7.4f</td><td class="ar">%7.4f</td></tr>' , network, station, Number(lat), Number(lng));
|
||||
// setting up network details (2nd line)
|
||||
row += sprintf('<tr class="tablesorter-childRow station-details"><td colspan="4">%s', networkText[network] || '');
|
||||
row += ( $.inArray(station, bochumStation)+1 ) ? '<br /><em>Betreiber:</em> Ruhr-Universität Bochum</td></tr>' : '</td></tr>' ;
|
||||
if ( network == 'RN' || network == 'Z3' || network == '1A' || network == 'YD' || $.inArray(station, bochumStation)+1 ) {
|
||||
// setting up station details (3rd line)
|
||||
row += '<tr class="tablesorter-childRow station-details"><td colspan="4">';
|
||||
row += stationDetails(station, network, lat, lng, stationID, stationText, $(this));
|
||||
row += '</td></tr>';
|
||||
// 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 += '<tr class="tablesorter-childRow station-download"><td colspan="4">'
|
||||
+ sprintf('Download details: <a download="%s.xml" href="%s" target="_blank">FDSNxml</a> or <a download="%s.sc3" href="%s" target="_blank">SC3ml</a><br /> ', stationID, fdsnxmlURL, stationID, sc3mlURL)
|
||||
+ sprintf('Response files: <a download="%s_response.xml" href="%s" target="_blank">FDSNxml</a>, <a download="%s_response.sc3" href="%s" target="_blank">SC3ml</a> ', stationID, fdsnxmlRespURL, stationID, sc3mlRespURL)
|
||||
+ sprintf('or <a href="%s" download="%s" type="application/octet-stream">datalessSEED</a>', config['ajax']['dlsvURL'] + '/' + dlsvFile, dlsvFile.toLowerCase())
|
||||
+ '</td></tr>';
|
||||
}
|
||||
else {
|
||||
row += '<tr class="tablesorter-childRow station-details"><td colspan="4">Kontaktieren Sie den ';
|
||||
row += ( networkURL[network.toUpperCase()] ) ? '<a href="'+networkURL[network.toUpperCase()]+'" target="_blank">Netzwerkkoordinator</a>' : 'Netzwerkkoordinator';
|
||||
row += ' für weitere Details.</td></tr>';
|
||||
};
|
||||
$('#stationstable tbody').append(row);
|
||||
addStationMarker(stationID, Number(lat), Number(lng), stationText.toUpperCase());
|
||||
};
|
||||
});
|
||||
};
|
||||
});
|
||||
},
|
||||
complete: function () {
|
||||
@ -53,10 +115,46 @@ function loadStations(stime, etime) {
|
||||
$("#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
|
||||
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: 'station',
|
||||
minlat: S-config['map']['latlngDelta'],
|
||||
maxlat: N+config['map']['latlngDelta'],
|
||||
minlon: W-config['map']['latlngDelta'],
|
||||
maxlon: E+config['map']['latlngDelta'],
|
||||
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 = '<pre>'
|
||||
+ name + '<br />'
|
||||
+ 'Position: ' + lat + '°N ' + lng + '°E, Höhe: ' + elevation + ' m NN<br />';
|
||||
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 += '<br />Kanal ' + code + ', Abtastrate ' + sampleRate + ' Hz, Sensor ' + sensor;
|
||||
});
|
||||
output += '</pre>';
|
||||
return output;
|
||||
};
|
||||
|
||||
/* initStationTable */
|
||||
function initStationTable() {
|
||||
// tablesorter for station list
|
||||
$("#stationstable").tablesorter(
|
||||
@ -85,7 +183,7 @@ function initStationTable() {
|
||||
// css class names of pager arrows
|
||||
pager_css: {
|
||||
container : 'stations-tablesorter-pager',
|
||||
errorRow : 'tablesorter-errorRow', // error information row (don't include period at beginning)
|
||||
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
|
||||
@ -101,7 +199,7 @@ function initStationTable() {
|
||||
},
|
||||
|
||||
filter_childRows : true,
|
||||
filter_cssFilter : 'tablesorter-filter',
|
||||
filter_cssFilter : 'stations-tablesorter-filter',
|
||||
filter_startsWith : false,
|
||||
filter_ignoreCase : true,
|
||||
scroller_height: $('div.map').height() - 250,
|
||||
@ -112,7 +210,57 @@ function initStationTable() {
|
||||
showProcessing: true,
|
||||
}
|
||||
});
|
||||
// hide child rows
|
||||
$('#stationstable > tbody > tr.tablesorter-childRow > td').hide();
|
||||
// update map after filtering
|
||||
// $('#stationsstable').on('filterEnd', function(){
|
||||
// toggleFilteredMarkers();
|
||||
// });
|
||||
};
|
||||
|
||||
/**********************************************************************
|
||||
* document ready *
|
||||
**********************************************************************/
|
||||
$(document).ready(function() {
|
||||
loadStations();
|
||||
loadStations('A100A');
|
||||
loadStations('A101B');
|
||||
loadStations('A102A');
|
||||
loadStations('A103A');
|
||||
loadStations('A103B');
|
||||
loadStations('A104A');
|
||||
loadStations('A104B');
|
||||
loadStations('A105A');
|
||||
loadStations('A106B');
|
||||
loadStations('A107C');
|
||||
loadStations('A108A');
|
||||
loadStations('A109A');
|
||||
// loadStations('KERA');
|
||||
// loadStations('KARP');
|
||||
// show / hide station info
|
||||
$('#stationstable').on('click', '.toggle' , 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;
|
||||
});
|
||||
});
|
||||
|
266
www/stations.js.en
Normal file
@ -0,0 +1,266 @@
|
||||
/**********************************************************************
|
||||
* stations.js.en *
|
||||
* script for station specific functions and setup *
|
||||
**********************************************************************/
|
||||
|
||||
/* License
|
||||
Copyright 2014-2021 Kasper D. Fischer <kasper.fischer@rub.de>
|
||||
|
||||
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/.
|
||||
|
||||
Version v1.3 (2023-04-17)
|
||||
*/
|
||||
|
||||
/* Load the stations using ajax */
|
||||
function loadStations(station, 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);
|
||||
};
|
||||
if ( !station ) {
|
||||
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: 'station',
|
||||
minlat: S-config['map']['latlngDelta'],
|
||||
maxlat: N+config['map']['latlngDelta'],
|
||||
minlon: W-config['map']['latlngDelta'],
|
||||
maxlon: E+config['map']['latlngDelta'],
|
||||
};
|
||||
} else {
|
||||
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',
|
||||
station: station,
|
||||
};
|
||||
};
|
||||
$.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] && $.inArray(stationID, config['station']['stationBlacklist']) <0 ) {
|
||||
// general station info (1st line)
|
||||
var row = sprintf('<tr><td><a href="#" class="toggle">%s</a></td><td><a href="#" class="toggle">%s</a></td><td class="ar">%7.4f</td><td class="ar">%7.4f</td></tr>' , network, station, Number(lat), Number(lng));
|
||||
// setting up network details (2nd line)
|
||||
row += sprintf('<tr class="tablesorter-childRow station-details"><td colspan="4">%s', networkText[network] || '');
|
||||
row += ( $.inArray(station, bochumStation)+1 ) ? '<br /><em>Operator:</em> Ruhr-University Bochum, Germany</td></tr>' : '</td></tr>' ;
|
||||
if ( network == 'RN' || network == 'Z3' || network == '1A' || network == 'YD' || $.inArray(station, bochumStation)+1 ) {
|
||||
// setting up station details (3rd line)
|
||||
row += '<tr class="tablesorter-childRow station-details"><td colspan="4">';
|
||||
row += stationDetails(station, network, lat, lng, stationID, stationText, $(this));
|
||||
row += '</td></tr>';
|
||||
// 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 += '<tr class="tablesorter-childRow station-download"><td colspan="4">'
|
||||
+ sprintf('Download details: <a download="%s.xml" href="%s" target="_blank">FDSNxml</a> or <a download="%s.sc3" href="%s" target="_blank">SC3ml</a><br /> ', stationID, fdsnxmlURL, stationID, sc3mlURL)
|
||||
+ sprintf('Response files: <a download="%s_response.xml" href="%s" target="_blank">FDSNxml</a>, <a download="%s_response.sc3" href="%s" target="_blank">SC3ml</a> ', stationID, fdsnxmlRespURL, stationID, sc3mlRespURL)
|
||||
+ sprintf('or <a href="%s" download="%s" type="application/octet-stream">datalessSEED</a>', config['ajax']['dlsvURL'] + '/' + dlsvFile, dlsvFile.toLowerCase())
|
||||
+ '</td></tr>';
|
||||
}
|
||||
else {
|
||||
row += '<tr class="tablesorter-childRow station-details"><td colspan="4">Kontaktieren Sie den ';
|
||||
row += ( networkURL[network.toUpperCase()] ) ? '<a href="'+networkURL[network.toUpperCase()]+'" target="_blank">Netzwerkkoordinator</a>' : 'Netzwerkkoordinator';
|
||||
row += ' für weitere Details.</td></tr>';
|
||||
};
|
||||
$('#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
|
||||
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: 'station',
|
||||
minlat: S-config['map']['latlngDelta'],
|
||||
maxlat: N+config['map']['latlngDelta'],
|
||||
minlon: W-config['map']['latlngDelta'],
|
||||
maxlon: E+config['map']['latlngDelta'],
|
||||
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 = '<pre>'
|
||||
+ name + '<br />'
|
||||
+ 'Position: ' + lat + '°N ' + lng + '°E, height: ' + elevation + ' m a.s.l.<br />';
|
||||
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 += '<br />Channel ' + code + ', Samplingrate ' + sampleRate + ' Hz, Sensor ' + sensor;
|
||||
});
|
||||
output += '</pre>';
|
||||
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').on('filterEnd', function(){
|
||||
// toggleFilteredMarkers();
|
||||
// });
|
||||
};
|
||||
|
||||
/**********************************************************************
|
||||
* document ready *
|
||||
**********************************************************************/
|
||||
$(document).ready(function() {
|
||||
loadStations();
|
||||
loadStations('A100A');
|
||||
loadStations('A101B');
|
||||
loadStations('A102A');
|
||||
loadStations('A103A');
|
||||
loadStations('A103B');
|
||||
loadStations('A104A');
|
||||
loadStations('A104B');
|
||||
loadStations('A105A');
|
||||
loadStations('A106B');
|
||||
loadStations('A107C');
|
||||
loadStations('A108A');
|
||||
loadStations('A109A');
|
||||
// loadStations('KERA');
|
||||
// loadStations('KARP');
|
||||
// show / hide station info
|
||||
$('#stationstable').on('click', '.toggle' , 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;
|
||||
});
|
||||
});
|
@ -1,221 +0,0 @@
|
||||
/*************
|
||||
Blue Theme
|
||||
*************/
|
||||
/* overall */
|
||||
.tablesorter-blue {
|
||||
width: 100%;
|
||||
background-color: #fff;
|
||||
margin: 10px 0 15px;
|
||||
text-align: left;
|
||||
border-spacing: 0;
|
||||
border: #cdcdcd 1px solid;
|
||||
border-width: 1px 0 0 1px;
|
||||
}
|
||||
.tablesorter-blue th,
|
||||
.tablesorter-blue td {
|
||||
border: #cdcdcd 1px solid;
|
||||
border-width: 0 1px 1px 0;
|
||||
}
|
||||
|
||||
/* header */
|
||||
.tablesorter-blue th,
|
||||
.tablesorter-blue thead td {
|
||||
font: bold 12px/18px Arial, Sans-serif;
|
||||
color: #000;
|
||||
background-color: #99bfe6;
|
||||
border-collapse: collapse;
|
||||
padding: 4px;
|
||||
text-shadow: 0 1px 0 rgba(204, 204, 204, 0.7);
|
||||
}
|
||||
.tablesorter-blue tbody td,
|
||||
.tablesorter-blue tfoot th,
|
||||
.tablesorter-blue tfoot td {
|
||||
padding: 4px;
|
||||
vertical-align: top;
|
||||
}
|
||||
.tablesorter-blue .header,
|
||||
.tablesorter-blue .tablesorter-header {
|
||||
/* black (unsorted) double arrow */
|
||||
background-image: url(data:image/gif;base64,R0lGODlhFQAJAIAAACMtMP///yH5BAEAAAEALAAAAAAVAAkAAAIXjI+AywnaYnhUMoqt3gZXPmVg94yJVQAAOw==);
|
||||
/* white (unsorted) double arrow */
|
||||
/* background-image: url(data:image/gif;base64,R0lGODlhFQAJAIAAAP///////yH5BAEAAAEALAAAAAAVAAkAAAIXjI+AywnaYnhUMoqt3gZXPmVg94yJVQAAOw==); */
|
||||
/* image */
|
||||
/* background-image: url(images/black-unsorted.gif); */
|
||||
background-repeat: no-repeat;
|
||||
background-position: center right;
|
||||
padding: 4px 18px 4px 4px;
|
||||
white-space: normal;
|
||||
cursor: pointer;
|
||||
}
|
||||
.tablesorter-blue .headerSortUp,
|
||||
.tablesorter-blue .tablesorter-headerSortUp,
|
||||
.tablesorter-blue .tablesorter-headerAsc {
|
||||
background-color: #9fbfdf;
|
||||
/* black asc arrow */
|
||||
background-image: url(data:image/gif;base64,R0lGODlhFQAEAIAAACMtMP///yH5BAEAAAEALAAAAAAVAAQAAAINjI8Bya2wnINUMopZAQA7);
|
||||
/* white asc arrow */
|
||||
/* background-image: url(data:image/gif;base64,R0lGODlhFQAEAIAAAP///////yH5BAEAAAEALAAAAAAVAAQAAAINjI8Bya2wnINUMopZAQA7); */
|
||||
/* image */
|
||||
/* background-image: url(images/black-asc.gif); */
|
||||
}
|
||||
.tablesorter-blue .headerSortDown,
|
||||
.tablesorter-blue .tablesorter-headerSortDown,
|
||||
.tablesorter-blue .tablesorter-headerDesc {
|
||||
background-color: #8cb3d9;
|
||||
/* black desc arrow */
|
||||
background-image: url(data:image/gif;base64,R0lGODlhFQAEAIAAACMtMP///yH5BAEAAAEALAAAAAAVAAQAAAINjB+gC+jP2ptn0WskLQA7);
|
||||
/* white desc arrow */
|
||||
/* background-image: url(data:image/gif;base64,R0lGODlhFQAEAIAAAP///////yH5BAEAAAEALAAAAAAVAAQAAAINjB+gC+jP2ptn0WskLQA7); */
|
||||
/* image */
|
||||
/* background-image: url(images/black-desc.gif); */
|
||||
}
|
||||
.tablesorter-blue thead .sorter-false {
|
||||
background-image: none;
|
||||
cursor: default;
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
/* tfoot */
|
||||
.tablesorter-blue tfoot .tablesorter-headerSortUp,
|
||||
.tablesorter-blue tfoot .tablesorter-headerSortDown,
|
||||
.tablesorter-blue tfoot .tablesorter-headerAsc,
|
||||
.tablesorter-blue tfoot .tablesorter-headerDesc {
|
||||
/* remove sort arrows from footer */
|
||||
background-image: none;
|
||||
}
|
||||
|
||||
/* tbody */
|
||||
.tablesorter-blue td {
|
||||
color: #3d3d3d;
|
||||
background-color: #fff;
|
||||
padding: 4px;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
/* hovered row colors
|
||||
you'll need to add additional lines for
|
||||
rows with more than 2 child rows
|
||||
*/
|
||||
.tablesorter-blue tbody > tr:hover > td,
|
||||
.tablesorter-blue tbody > tr:hover + tr.tablesorter-childRow > td,
|
||||
.tablesorter-blue tbody > tr:hover + tr.tablesorter-childRow + tr.tablesorter-childRow > td,
|
||||
.tablesorter-blue tbody > tr.even:hover > td,
|
||||
.tablesorter-blue tbody > tr.even:hover + tr.tablesorter-childRow > td,
|
||||
.tablesorter-blue tbody > tr.even:hover + tr.tablesorter-childRow + tr.tablesorter-childRow > td {
|
||||
background: #d9d9d9;
|
||||
}
|
||||
.tablesorter-blue tbody > tr.odd:hover > td,
|
||||
.tablesorter-blue tbody > tr.odd:hover + tr.tablesorter-childRow > td,
|
||||
.tablesorter-blue tbody > tr.odd:hover + tr.tablesorter-childRow + tr.tablesorter-childRow > td {
|
||||
background: #bfbfbf;
|
||||
}
|
||||
|
||||
/* table processing indicator */
|
||||
.tablesorter-blue .tablesorter-processing {
|
||||
background-position: center center !important;
|
||||
background-repeat: no-repeat !important;
|
||||
/* background-image: url(../addons/pager/icons/loading.gif) !important; */
|
||||
background-image: url('data:image/gif;base64,R0lGODlhFAAUAKEAAO7u7lpaWgAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQBCgACACwAAAAAFAAUAAACQZRvoIDtu1wLQUAlqKTVxqwhXIiBnDg6Y4eyx4lKW5XK7wrLeK3vbq8J2W4T4e1nMhpWrZCTt3xKZ8kgsggdJmUFACH5BAEKAAIALAcAAAALAAcAAAIUVB6ii7jajgCAuUmtovxtXnmdUAAAIfkEAQoAAgAsDQACAAcACwAAAhRUIpmHy/3gUVQAQO9NetuugCFWAAAh+QQBCgACACwNAAcABwALAAACE5QVcZjKbVo6ck2AF95m5/6BSwEAIfkEAQoAAgAsBwANAAsABwAAAhOUH3kr6QaAcSrGWe1VQl+mMUIBACH5BAEKAAIALAIADQALAAcAAAIUlICmh7ncTAgqijkruDiv7n2YUAAAIfkEAQoAAgAsAAAHAAcACwAAAhQUIGmHyedehIoqFXLKfPOAaZdWAAAh+QQFCgACACwAAAIABwALAAACFJQFcJiXb15zLYRl7cla8OtlGGgUADs=') !important;
|
||||
}
|
||||
|
||||
/* Zebra Widget - row alternating colors */
|
||||
.tablesorter-blue tbody tr.odd td {
|
||||
background-color: #ebf2fa;
|
||||
}
|
||||
.tablesorter-blue tbody tr.even td {
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
/* Column Widget - column sort colors */
|
||||
.tablesorter-blue td.primary,
|
||||
.tablesorter-blue tr.odd td.primary {
|
||||
background-color: #99b3e6;
|
||||
}
|
||||
.tablesorter-blue tr.even td.primary {
|
||||
background-color: #c2d1f0;
|
||||
}
|
||||
.tablesorter-blue td.secondary,
|
||||
.tablesorter-blue tr.odd td.secondary {
|
||||
background-color: #c2d1f0;
|
||||
}
|
||||
.tablesorter-blue tr.even td.secondary {
|
||||
background-color: #d6e0f5;
|
||||
}
|
||||
.tablesorter-blue td.tertiary,
|
||||
.tablesorter-blue tr.odd td.tertiary {
|
||||
background-color: #d6e0f5;
|
||||
}
|
||||
.tablesorter-blue tr.even td.tertiary {
|
||||
background-color: #ebf0fa;
|
||||
}
|
||||
|
||||
/* caption */
|
||||
caption {
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
/* filter widget */
|
||||
.tablesorter-blue .tablesorter-filter-row td {
|
||||
background: #eee;
|
||||
line-height: normal;
|
||||
text-align: center; /* center the input */
|
||||
-webkit-transition: line-height 0.1s ease;
|
||||
-moz-transition: line-height 0.1s ease;
|
||||
-o-transition: line-height 0.1s ease;
|
||||
transition: line-height 0.1s ease;
|
||||
}
|
||||
/* optional disabled input styling */
|
||||
.tablesorter-blue .tablesorter-filter-row .disabled {
|
||||
opacity: 0.5;
|
||||
filter: alpha(opacity=50);
|
||||
cursor: not-allowed;
|
||||
}
|
||||
/* hidden filter row */
|
||||
.tablesorter-blue .tablesorter-filter-row.hideme td {
|
||||
/*** *********************************************** ***/
|
||||
/*** change this padding to modify the thickness ***/
|
||||
/*** of the closed filter row (height = padding x 2) ***/
|
||||
padding: 2px;
|
||||
/*** *********************************************** ***/
|
||||
margin: 0;
|
||||
line-height: 0;
|
||||
cursor: pointer;
|
||||
}
|
||||
.tablesorter-blue .tablesorter-filter-row.hideme .tablesorter-filter {
|
||||
height: 1px;
|
||||
min-height: 0;
|
||||
border: 0;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
/* don't use visibility: hidden because it disables tabbing */
|
||||
opacity: 0;
|
||||
filter: alpha(opacity=0);
|
||||
}
|
||||
/* filters */
|
||||
.tablesorter-blue .tablesorter-filter {
|
||||
width: 98%;
|
||||
height: auto;
|
||||
margin: 0;
|
||||
padding: 4px;
|
||||
background-color: #fff;
|
||||
border: 1px solid #bbb;
|
||||
color: #333;
|
||||
-webkit-box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
-webkit-transition: height 0.1s ease;
|
||||
-moz-transition: height 0.1s ease;
|
||||
-o-transition: height 0.1s ease;
|
||||
transition: height 0.1s ease;
|
||||
}
|
||||
/* rows hidden by filtering (needed for child rows) */
|
||||
.tablesorter .filtered {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* ajax error row */
|
||||
.tablesorter .tablesorter-errorRow td {
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
background-color: #e6bf99;
|
||||
}
|
@ -1,863 +0,0 @@
|
||||
/* Pager widget (beta) for TableSorter 3/31/2014 (v2.15.12) */
|
||||
/*jshint browser:true, jquery:true, unused:false */
|
||||
;(function($){
|
||||
"use strict";
|
||||
var tsp,
|
||||
ts = $.tablesorter;
|
||||
|
||||
ts.addWidget({
|
||||
id: "pager",
|
||||
priority: 55, // load pager after filter widget
|
||||
options : {
|
||||
// output default: '{page}/{totalPages}'
|
||||
// possible variables: {page}, {totalPages}, {filteredPages}, {startRow}, {endRow}, {filteredRows} and {totalRows}
|
||||
pager_output: '{startRow} to {endRow} of {totalRows} rows', // '{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: 10,
|
||||
|
||||
// Save pager page & size if the storage script is loaded (requires $.tablesorter.storage in jquery.tablesorter.widgets.js)
|
||||
pager_savePages: true,
|
||||
|
||||
//defines custom storage key
|
||||
pager_storageKey: 'tablesorter-pager',
|
||||
|
||||
// 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,
|
||||
|
||||
// count child rows towards the set page size? (set true if it is a visible table row within the pager)
|
||||
// if true, child row(s) may not appear to be attached to its parent row, may be split across pages or
|
||||
// may distort the table if rowspan or cellspans are included.
|
||||
pager_countChildRows: 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, // removing rows in larger tables speeds up the sort
|
||||
|
||||
// use this format: "http://mydatabase.com?page={page}&size={size}&{sortList:col}&{filterList:fcol}"
|
||||
// where {page} is replaced by the page number, {size} is replaced by the number of records to show,
|
||||
// {sortList:col} adds the sortList to the url into a "col" array, and {filterList:fcol} adds
|
||||
// the filterList to the url into an "fcol" array.
|
||||
// So a sortList = [[2,0],[3,0]] becomes "&col[2]=0&col[3]=0" in the url
|
||||
// and a filterList = [[2,Blue],[3,13]] becomes "&fcol[2]=Blue&fcol[3]=13" in the url
|
||||
pager_ajaxUrl: null,
|
||||
|
||||
// modify the url after all processing has been applied
|
||||
pager_customAjaxUrl: function(table, url) { return url; },
|
||||
|
||||
// modify the $.ajax object to allow complete control over your ajax requests
|
||||
pager_ajaxObject: {
|
||||
dataType: 'json'
|
||||
},
|
||||
|
||||
// set this to false if you want to block ajax loading on init
|
||||
pager_processAjaxOnInit: true,
|
||||
|
||||
// process ajax so that the following information is returned:
|
||||
// [ total_rows (number), rows (array of arrays), headers (array; optional) ]
|
||||
// example:
|
||||
// [
|
||||
// 100, // total rows
|
||||
// [
|
||||
// [ "row1cell1", "row1cell2", ... "row1cellN" ],
|
||||
// [ "row2cell1", "row2cell2", ... "row2cellN" ],
|
||||
// ...
|
||||
// [ "rowNcell1", "rowNcell2", ... "rowNcellN" ]
|
||||
// ],
|
||||
// [ "header1", "header2", ... "headerN" ] // optional
|
||||
// ]
|
||||
pager_ajaxProcessing: function(ajax){ return [ 0, [], null ]; },
|
||||
|
||||
// css class names of pager arrows
|
||||
pager_css: {
|
||||
container : 'tablesorter-pager',
|
||||
errorRow : '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 selectors
|
||||
pager_selectors: {
|
||||
container : '.pager', // target the pager markup
|
||||
first : '.first', // go to first page arrow
|
||||
prev : '.prev', // previous page arrow
|
||||
next : '.next', // next page arrow
|
||||
last : '.last', // go to last page arrow
|
||||
goto : '.gotoPage', // go to page selector - select dropdown that sets the current page
|
||||
pageDisplay : '.pagedisplay', // location of where the "output" is displayed
|
||||
pageSize : '.pagesize' // page size selector - select dropdown that sets the "size" option
|
||||
}
|
||||
},
|
||||
init: function(table){
|
||||
tsp.init(table);
|
||||
},
|
||||
// only update to complete sorter initialization
|
||||
format: function(table, c){
|
||||
if (!(c.pager && c.pager.initialized)){
|
||||
return tsp.initComplete(table, c);
|
||||
}
|
||||
tsp.moveToPage(table, c.pager, false);
|
||||
},
|
||||
remove: function(table, c){
|
||||
tsp.destroyPager(table, c);
|
||||
}
|
||||
});
|
||||
|
||||
/* pager widget functions */
|
||||
tsp = ts.pager = {
|
||||
|
||||
init: function(table) {
|
||||
// check if tablesorter has initialized
|
||||
if (table.hasInitialized && table.config.pager.initialized) { return; }
|
||||
var t,
|
||||
c = table.config,
|
||||
wo = c.widgetOptions,
|
||||
s = wo.pager_selectors,
|
||||
|
||||
// save pager variables
|
||||
p = c.pager = $.extend({
|
||||
totalPages: 0,
|
||||
filteredRows: 0,
|
||||
filteredPages: 0,
|
||||
currentFilters: [],
|
||||
page: wo.pager_startPage,
|
||||
size: wo.pager_size,
|
||||
startRow: 0,
|
||||
endRow: 0,
|
||||
ajaxCounter: 0,
|
||||
$size: null,
|
||||
last: {}
|
||||
}, c.pager);
|
||||
|
||||
// pager initializes multiple times before table has completed initialization
|
||||
if (p.isInitializing) { return; }
|
||||
|
||||
p.isInitializing = true;
|
||||
if (c.debug) {
|
||||
ts.log('Pager initializing');
|
||||
}
|
||||
|
||||
// added in case the pager is reinitialized after being destroyed.
|
||||
p.$container = $(s.container).addClass(wo.pager_css.container).show();
|
||||
// goto selector
|
||||
p.$goto = p.$container.find(s.goto);
|
||||
// page size selector
|
||||
p.$size = p.$container.find(s.pageSize);
|
||||
p.totalRows = c.$tbodies.eq(0).children().length;
|
||||
p.oldAjaxSuccess = p.oldAjaxSuccess || wo.pager_ajaxObject.success;
|
||||
c.appender = tsp.appender;
|
||||
if (ts.filter && $.inArray('filter', c.widgets) >= 0) {
|
||||
// get any default filter settings (data-value attribute) fixes #388
|
||||
p.currentFilters = c.$table.data('lastSearch') || ts.filter.setDefaults(table, c, wo) || [];
|
||||
// set, but don't apply current filters
|
||||
ts.setFilters(table, p.currentFilters, false);
|
||||
}
|
||||
if (wo.pager_savePages && ts.storage) {
|
||||
t = ts.storage(table, wo.pager_storageKey) || {}; // fixes #387
|
||||
p.page = isNaN(t.page) ? p.page : t.page;
|
||||
p.size = ( isNaN(t.size) ? p.size : t.size ) || 10;
|
||||
$.data(table, 'pagerLastSize', p.size);
|
||||
}
|
||||
// clear initialized flag
|
||||
p.initialized = false;
|
||||
// before initialization event
|
||||
c.$table.trigger('pagerBeforeInitialized', c);
|
||||
|
||||
tsp.enablePager(table, c, false);
|
||||
|
||||
if ( typeof(wo.pager_ajaxUrl) === 'string' ) {
|
||||
// ajax pager; interact with database
|
||||
p.ajax = true;
|
||||
// When filtering with ajax, allow only custom filtering function, disable default filtering since it will be done server side.
|
||||
wo.filter_serversideFiltering = true;
|
||||
c.serverSideSorting = true;
|
||||
tsp.moveToPage(table, p);
|
||||
} else {
|
||||
p.ajax = false;
|
||||
// Regular pager; all rows stored in memory
|
||||
c.$table.trigger("appendCache", [{}, true]);
|
||||
tsp.hideRowsSetup(table, c);
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
initComplete: function(table, c){
|
||||
var p = c.pager;
|
||||
tsp.changeHeight(table, c);
|
||||
tsp.bindEvents(table, c);
|
||||
|
||||
// pager initialized
|
||||
p.initialized = true;
|
||||
p.isInitializing = false;
|
||||
tsp.setPageSize(table, 0, c); // page size 0 is ignored
|
||||
c.$table.trigger('pagerInitialized', c);
|
||||
|
||||
},
|
||||
|
||||
bindEvents: function(table, c){
|
||||
var ctrls, fxn,
|
||||
p = c.pager,
|
||||
wo = c.widgetOptions,
|
||||
s = wo.pager_selectors;
|
||||
|
||||
c.$table
|
||||
.unbind('filterStart filterEnd sortEnd disable enable destroy update updateRows updateAll addRows pageSize '.split(' ').join('.pager '))
|
||||
.bind('filterStart.pager', function(e, filters) {
|
||||
p.currentFilters = filters;
|
||||
p.page = 0; // fixes #456
|
||||
})
|
||||
// update pager after filter widget completes
|
||||
.bind('filterEnd.pager sortEnd.pager', function() {
|
||||
if (p.initialized) {
|
||||
tsp.moveToPage(table, p, false);
|
||||
tsp.updatePageDisplay(table, c, false);
|
||||
tsp.fixHeight(table, c);
|
||||
}
|
||||
})
|
||||
.bind('disable.pager', function(e){
|
||||
e.stopPropagation();
|
||||
tsp.showAllRows(table, c);
|
||||
})
|
||||
.on('enable.pager', function(e){
|
||||
e.stopPropagation();
|
||||
tsp.enablePager(table, c, true);
|
||||
})
|
||||
.on('destroy.pager', function(e){
|
||||
e.stopPropagation();
|
||||
tsp.destroyPager(table, c);
|
||||
})
|
||||
.on('update updateRows updateAll addRows '.split(' ').join('.pager '), function(e){
|
||||
e.stopPropagation();
|
||||
tsp.hideRows(table, c);
|
||||
// make sure widgets are applied - fixes #450
|
||||
c.$table.trigger('applyWidgets');
|
||||
})
|
||||
.on('pageSize.pager', function(e,v){
|
||||
e.stopPropagation();
|
||||
tsp.setPageSize(table, parseInt(v, 10) || 10, c);
|
||||
tsp.hideRows(table, c);
|
||||
tsp.updatePageDisplay(table, c, false);
|
||||
if (p.$size.length) { p.$size.val(p.size); } // twice?
|
||||
})
|
||||
.on('pageSet.pager', function(e,v){
|
||||
e.stopPropagation();
|
||||
p.page = (parseInt(v, 10) || 1) - 1;
|
||||
if (p.$goto.length) { p.$goto.val(c.size); } // twice?
|
||||
tsp.moveToPage(table, p);
|
||||
tsp.updatePageDisplay(table, c, false);
|
||||
});
|
||||
|
||||
// clicked controls
|
||||
ctrls = [ s.first, s.prev, s.next, s.last ];
|
||||
fxn = [ 'moveToFirstPage', 'moveToPrevPage', 'moveToNextPage', 'moveToLastPage' ];
|
||||
p.$container.find(ctrls.join(','))
|
||||
.attr("tabindex", 0)
|
||||
.unbind('click.pager')
|
||||
.bind('click.pager', function(e){
|
||||
e.stopPropagation();
|
||||
var i,
|
||||
$c = $(this),
|
||||
l = ctrls.length;
|
||||
if ( !$c.hasClass(wo.pager_css.disabled) ) {
|
||||
for (i = 0; i < l; i++) {
|
||||
if ($c.is(ctrls[i])) {
|
||||
tsp[fxn[i]](table, p);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if ( p.$goto.length ) {
|
||||
p.$goto
|
||||
.unbind('change')
|
||||
.bind('change', function(){
|
||||
p.page = $(this).val() - 1;
|
||||
tsp.moveToPage(table, p);
|
||||
tsp.updatePageDisplay(table, c, false);
|
||||
});
|
||||
}
|
||||
|
||||
if ( p.$size.length ) {
|
||||
p.$size
|
||||
.unbind('change.pager')
|
||||
.bind('change.pager', function() {
|
||||
p.$size.val( $(this).val() ); // in case there are more than one pagers
|
||||
if ( !$(this).hasClass(wo.pager_css.disabled) ) {
|
||||
tsp.setPageSize(table, parseInt( $(this).val(), 10 ), c);
|
||||
tsp.changeHeight(table, c);
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
// hide arrows at extremes
|
||||
pagerArrows: function(c, disable) {
|
||||
var p = c.pager,
|
||||
dis = !!disable,
|
||||
first = dis || p.page === 0,
|
||||
tp = Math.min( p.totalPages, p.filteredPages ),
|
||||
last = dis || p.page === tp - 1 || p.totalPages === 0,
|
||||
wo = c.widgetOptions,
|
||||
s = wo.pager_selectors;
|
||||
if ( wo.pager_updateArrows ) {
|
||||
p.$container.find(s.first + ',' + s.prev).toggleClass(wo.pager_css.disabled, first).attr('aria-disabled', first);
|
||||
p.$container.find(s.next + ',' + s.last).toggleClass(wo.pager_css.disabled, last).attr('aria-disabled', last);
|
||||
}
|
||||
},
|
||||
|
||||
updatePageDisplay: function(table, c, completed) {
|
||||
var i, pg, s, out,
|
||||
wo = c.widgetOptions,
|
||||
p = c.pager,
|
||||
f = c.$table.hasClass('hasFilters') && !wo.pager_ajaxUrl,
|
||||
t = (c.widgetOptions && c.widgetOptions.filter_filteredRow || 'filtered') + ',' + c.selectorRemove +
|
||||
(wo.pager_countChildRows ? '' : ',.' + c.cssChildRow),
|
||||
sz = p.size || 10; // don't allow dividing by zero
|
||||
p.$size.add(p.$goto).removeClass(wo.pager_css.disabled).removeAttr('disabled').attr('aria-disabled', 'false');
|
||||
p.totalPages = Math.ceil( p.totalRows / sz ); // needed for "pageSize" method
|
||||
p.filteredRows = (f) ? c.$tbodies.eq(0).children('tr').not('.' + t).length : p.totalRows;
|
||||
p.filteredPages = (f) ? Math.ceil( p.filteredRows / sz ) || 1 : p.totalPages;
|
||||
if ( Math.min( p.totalPages, p.filteredPages ) >= 0 ) {
|
||||
t = (p.size * p.page > p.filteredRows);
|
||||
p.startRow = (t) ? 1 : (p.filteredRows === 0 ? 0 : p.size * p.page + 1);
|
||||
p.page = (t) ? 0 : p.page;
|
||||
p.endRow = Math.min( p.filteredRows, p.totalRows, p.size * ( p.page + 1 ) );
|
||||
out = p.$container.find(wo.pager_selectors.pageDisplay);
|
||||
// form the output string (can now get a new output string from the server)
|
||||
s = ( p.ajaxData && p.ajaxData.output ? p.ajaxData.output || wo.pager_output : wo.pager_output )
|
||||
// {page} = one-based index; {page+#} = zero based index +/- value
|
||||
.replace(/\{page([\-+]\d+)?\}/gi, function(m,n){
|
||||
return p.totalPages ? p.page + (n ? parseInt(n, 10) : 1) : 0;
|
||||
})
|
||||
// {totalPages}, {extra}, {extra:0} (array) or {extra : key} (object)
|
||||
.replace(/\{\w+(\s*:\s*\w+)?\}/gi, function(m){
|
||||
var str = m.replace(/[{}\s]/g,''),
|
||||
extra = str.split(':'),
|
||||
data = p.ajaxData,
|
||||
// return zero for default page/row numbers
|
||||
deflt = /(rows?|pages?)$/i.test(str) ? 0 : '';
|
||||
return extra.length > 1 && data && data[extra[0]] ? data[extra[0]][extra[1]] : p[str] || (data ? data[str] : deflt) || deflt;
|
||||
});
|
||||
if (out.length) {
|
||||
out[ (out[0].tagName === 'INPUT') ? 'val' : 'html' ](s);
|
||||
if ( p.$goto.length ) {
|
||||
t = '';
|
||||
pg = Math.min( p.totalPages, p.filteredPages );
|
||||
for ( i = 1; i <= pg; i++ ) {
|
||||
t += '<option>' + i + '</option>';
|
||||
}
|
||||
p.$goto.html(t).val( p.page + 1 );
|
||||
}
|
||||
}
|
||||
}
|
||||
tsp.pagerArrows(c);
|
||||
if (p.initialized && completed !== false) {
|
||||
c.$table.trigger('pagerComplete', c);
|
||||
// save pager info to storage
|
||||
if (wo.pager_savePages && ts.storage) {
|
||||
ts.storage(table, wo.pager_storageKey, {
|
||||
page : p.page,
|
||||
size : p.size
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
fixHeight: function(table, c) {
|
||||
var d, h,
|
||||
p = c.pager,
|
||||
wo = c.widgetOptions,
|
||||
$b = c.$tbodies.eq(0);
|
||||
if (wo.pager_fixedHeight) {
|
||||
$b.find('tr.pagerSavedHeightSpacer').remove();
|
||||
h = $.data(table, 'pagerSavedHeight');
|
||||
if (h) {
|
||||
d = h - $b.height();
|
||||
if ( d > 5 && $.data(table, 'pagerLastSize') === p.size && $b.children('tr:visible').length < p.size ) {
|
||||
$b.append('<tr class="pagerSavedHeightSpacer ' + wo.pager_selectors.remove.replace(/(tr)?\./g,'') + '" style="height:' + d + 'px;"></tr>');
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
changeHeight: function(table, c) {
|
||||
var $b = c.$tbodies.eq(0);
|
||||
$b.find('tr.pagerSavedHeightSpacer').remove();
|
||||
$.data(table, 'pagerSavedHeight', $b.height());
|
||||
tsp.fixHeight(table, c);
|
||||
$.data(table, 'pagerLastSize', c.pager.size);
|
||||
},
|
||||
|
||||
hideRows: function(table, c){
|
||||
if (!c.widgetOptions.pager_ajaxUrl) {
|
||||
var i,
|
||||
lastIndex = 0,
|
||||
p = c.pager,
|
||||
wo = c.widgetOptions,
|
||||
rows = c.$tbodies.eq(0).children(),
|
||||
l = rows.length,
|
||||
s = ( p.page * p.size ),
|
||||
e = s + p.size,
|
||||
f = wo && wo.filter_filteredRow || 'filtered',
|
||||
j = 0; // size counter
|
||||
for ( i = 0; i < l; i++ ){
|
||||
if ( !rows[i].className.match(f) ) {
|
||||
if (j === s && rows[i].className.match(c.cssChildRow)) {
|
||||
// hide child rows @ start of pager (if already visible)
|
||||
rows[i].style.display = 'none';
|
||||
} else {
|
||||
rows[i].style.display = ( j >= s && j < e ) ? '' : 'none';
|
||||
// don't count child rows
|
||||
j += rows[i].className.match(c.cssChildRow + '|' + c.selectorRemove.slice(1)) && !wo.pager_countChildRows ? 0 : 1;
|
||||
if ( j === e && rows[i].style.display !== 'none' && rows[i].className.match(ts.css.cssHasChild) ) {
|
||||
lastIndex = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// add any attached child rows to last row of pager. Fixes part of issue #396
|
||||
if ( lastIndex > 0 && rows[lastIndex].className.match(ts.css.cssHasChild) ) {
|
||||
while ( ++lastIndex < l && rows[lastIndex].className.match(c.cssChildRow) ) {
|
||||
rows[lastIndex].style.display = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
hideRowsSetup: function(table, c){
|
||||
var p = c.pager;
|
||||
p.size = parseInt( p.$size.val(), 10 ) || p.size;
|
||||
$.data(table, 'pagerLastSize', p.size);
|
||||
tsp.pagerArrows(c);
|
||||
if ( !c.widgetOptions.pager_removeRows ) {
|
||||
tsp.hideRows(table, c);
|
||||
c.$table.on('sortEnd.pager filterEnd.pager', function(){
|
||||
tsp.hideRows(table, c);
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
renderAjax: function(data, table, c, xhr, exception){
|
||||
var p = c.pager,
|
||||
wo = c.widgetOptions;
|
||||
// process data
|
||||
if ( $.isFunction(wo.pager_ajaxProcessing) ) {
|
||||
// ajaxProcessing result: [ total, rows, headers ]
|
||||
var i, j, t, hsh, $f, $sh, th, d, l, rr_count,
|
||||
$t = c.$table,
|
||||
tds = '',
|
||||
result = wo.pager_ajaxProcessing(data, table) || [ 0, [] ],
|
||||
hl = $t.find('thead th').length;
|
||||
|
||||
// Clean up any previous error.
|
||||
ts.showError(table);
|
||||
|
||||
if ( exception ) {
|
||||
if (c.debug) {
|
||||
ts.log('Ajax Error', xhr, exception);
|
||||
}
|
||||
ts.showError(table, exception.message + ' (' + xhr.status + ')');
|
||||
c.$tbodies.eq(0).empty();
|
||||
p.totalRows = 0;
|
||||
} else {
|
||||
// process ajax object
|
||||
if (!$.isArray(result)) {
|
||||
p.ajaxData = result;
|
||||
p.totalRows = result.total;
|
||||
th = result.headers;
|
||||
d = result.rows;
|
||||
} else {
|
||||
// allow [ total, rows, headers ] or [ rows, total, headers ]
|
||||
t = isNaN(result[0]) && !isNaN(result[1]);
|
||||
// ensure a zero returned row count doesn't fail the logical ||
|
||||
rr_count = result[t ? 1 : 0];
|
||||
p.totalRows = isNaN(rr_count) ? p.totalRows || 0 : rr_count;
|
||||
d = p.totalRows === 0 ? [""] : result[t ? 0 : 1] || []; // row data
|
||||
th = result[2]; // headers
|
||||
}
|
||||
l = d.length;
|
||||
if (d instanceof jQuery) {
|
||||
// append jQuery object
|
||||
c.$tbodies.eq(0).empty().append(d);
|
||||
} else if (l) {
|
||||
// build table from array
|
||||
for ( i = 0; i < l; i++ ) {
|
||||
tds += '<tr>';
|
||||
for ( j = 0; j < d[i].length; j++ ) {
|
||||
// build tbody cells; watch for data containing HTML markup - see #434
|
||||
tds += /^\s*<td/.test(d[i][j]) ? $.trim(d[i][j]) : '<td>' + d[i][j] + '</td>';
|
||||
}
|
||||
tds += '</tr>';
|
||||
}
|
||||
// add rows to first tbody
|
||||
if (wo.pager_processAjaxOnInit) {
|
||||
c.$tbodies.eq(0).html( tds );
|
||||
} else {
|
||||
wo.pager_processAjaxOnInit = true;
|
||||
}
|
||||
}
|
||||
// only add new header text if the length matches
|
||||
if ( th && th.length === hl ) {
|
||||
hsh = $t.hasClass('hasStickyHeaders');
|
||||
$sh = hsh ? wo.$sticky.children('thead:first').children().children() : '';
|
||||
$f = $t.find('tfoot tr:first').children();
|
||||
// don't change td headers (may contain pager)
|
||||
c.$headers.filter('th').each(function(j){
|
||||
var $t = $(this), icn;
|
||||
// add new test within the first span it finds, or just in the header
|
||||
if ( $t.find('.' + ts.css.icon).length ) {
|
||||
icn = $t.find('.' + ts.css.icon).clone(true);
|
||||
$t.find('.tablesorter-header-inner').html( th[j] ).append(icn);
|
||||
if ( hsh && $sh.length ) {
|
||||
icn = $sh.eq(j).find('.' + ts.css.icon).clone(true);
|
||||
$sh.eq(j).find('.tablesorter-header-inner').html( th[j] ).append(icn);
|
||||
}
|
||||
} else {
|
||||
$t.find('.tablesorter-header-inner').html( th[j] );
|
||||
if (hsh && $sh.length) {
|
||||
$sh.eq(j).find('.tablesorter-header-inner').html( th[j] );
|
||||
}
|
||||
}
|
||||
$f.eq(j).html( th[j] );
|
||||
});
|
||||
}
|
||||
}
|
||||
if (c.showProcessing) {
|
||||
ts.isProcessing(table); // remove loading icon
|
||||
}
|
||||
// make sure last pager settings are saved, prevents multiple server side calls with
|
||||
// the same parameters
|
||||
p.totalPages = Math.ceil( p.totalRows / ( p.size || 10 ) );
|
||||
p.last.totalRows = p.totalRows;
|
||||
p.last.currentFilters = p.currentFilters;
|
||||
p.last.sortList = (c.sortList || []).join(',');
|
||||
tsp.updatePageDisplay(table, c);
|
||||
tsp.fixHeight(table, c);
|
||||
$t.trigger('updateCache', [function(){
|
||||
if (p.initialized) {
|
||||
// apply widgets after table has rendered
|
||||
$t.trigger('applyWidgets');
|
||||
$t.trigger('pagerChange', p);
|
||||
}
|
||||
}]);
|
||||
}
|
||||
if (!p.initialized) {
|
||||
c.$table.trigger('applyWidgets');
|
||||
}
|
||||
},
|
||||
|
||||
getAjax: function(table, c){
|
||||
var counter,
|
||||
url = tsp.getAjaxUrl(table, c),
|
||||
$doc = $(document),
|
||||
wo = c.widgetOptions,
|
||||
p = c.pager;
|
||||
if ( url !== '' ) {
|
||||
if (c.showProcessing) {
|
||||
ts.isProcessing(table, true); // show loading icon
|
||||
}
|
||||
$doc.on('ajaxError.pager', function(e, xhr, settings, exception) {
|
||||
tsp.renderAjax(null, table, c, xhr, exception);
|
||||
$doc.unbind('ajaxError.pager');
|
||||
});
|
||||
counter = ++p.ajaxCounter;
|
||||
wo.pager_ajaxObject.url = url; // from the ajaxUrl option and modified by customAjaxUrl
|
||||
wo.pager_ajaxObject.success = function(data) {
|
||||
// Refuse to process old ajax commands that were overwritten by new ones - see #443
|
||||
if (counter < p.ajaxCounter){
|
||||
return;
|
||||
}
|
||||
tsp.renderAjax(data, table, c);
|
||||
$doc.unbind('ajaxError.pager');
|
||||
if (typeof p.oldAjaxSuccess === 'function') {
|
||||
p.oldAjaxSuccess(data);
|
||||
}
|
||||
};
|
||||
if (c.debug) {
|
||||
ts.log('ajax initialized', wo.pager_ajaxObject);
|
||||
}
|
||||
$.ajax(wo.pager_ajaxObject);
|
||||
}
|
||||
},
|
||||
|
||||
getAjaxUrl: function(table, c) {
|
||||
var p = c.pager,
|
||||
wo = c.widgetOptions,
|
||||
url = (wo.pager_ajaxUrl) ? wo.pager_ajaxUrl
|
||||
// allow using "{page+1}" in the url string to switch to a non-zero based index
|
||||
.replace(/\{page([\-+]\d+)?\}/, function(s,n){ return p.page + (n ? parseInt(n, 10) : 0); })
|
||||
.replace(/\{size\}/g, p.size) : '',
|
||||
sl = c.sortList,
|
||||
fl = p.currentFilters || $(table).data('lastSearch') || [],
|
||||
sortCol = url.match(/\{\s*sort(?:List)?\s*:\s*(\w*)\s*\}/),
|
||||
filterCol = url.match(/\{\s*filter(?:List)?\s*:\s*(\w*)\s*\}/),
|
||||
arry = [];
|
||||
if (sortCol) {
|
||||
sortCol = sortCol[1];
|
||||
$.each(sl, function(i,v){
|
||||
arry.push(sortCol + '[' + v[0] + ']=' + v[1]);
|
||||
});
|
||||
// if the arry is empty, just add the col parameter... "&{sortList:col}" becomes "&col"
|
||||
url = url.replace(/\{\s*sort(?:List)?\s*:\s*(\w*)\s*\}/g, arry.length ? arry.join('&') : sortCol );
|
||||
arry = [];
|
||||
}
|
||||
if (filterCol) {
|
||||
filterCol = filterCol[1];
|
||||
$.each(fl, function(i,v){
|
||||
if (v) {
|
||||
arry.push(filterCol + '[' + i + ']=' + encodeURIComponent(v));
|
||||
}
|
||||
});
|
||||
// if the arry is empty, just add the fcol parameter... "&{filterList:fcol}" becomes "&fcol"
|
||||
url = url.replace(/\{\s*filter(?:List)?\s*:\s*(\w*)\s*\}/g, arry.length ? arry.join('&') : filterCol );
|
||||
p.currentFilters = fl;
|
||||
}
|
||||
if ( $.isFunction(wo.pager_customAjaxUrl) ) {
|
||||
url = wo.pager_customAjaxUrl(table, url);
|
||||
}
|
||||
if (c.debug) {
|
||||
ts.log('Pager ajax url: ' + url);
|
||||
}
|
||||
return url;
|
||||
},
|
||||
|
||||
renderTable: function(table, rows) {
|
||||
var i, $tb,
|
||||
c = table.config,
|
||||
p = c.pager,
|
||||
wo = c.widgetOptions,
|
||||
l = rows && rows.length || 0, // rows may be undefined
|
||||
s = ( p.page * p.size ),
|
||||
e = ( s + p.size );
|
||||
if ( l < 1 ) { return; } // empty table, abort!
|
||||
if ( p.page >= p.totalPages ) {
|
||||
// lets not render the table more than once
|
||||
return tsp.moveToLastPage(table, p);
|
||||
}
|
||||
p.isDisabled = false; // needed because sorting will change the page and re-enable the pager
|
||||
if (p.initialized) { c.$table.trigger('pagerChange', c); }
|
||||
|
||||
if ( !wo.pager_removeRows ) {
|
||||
tsp.hideRows(table, c);
|
||||
} else {
|
||||
if ( e > rows.length ) {
|
||||
e = rows.length;
|
||||
}
|
||||
ts.clearTableBody(table);
|
||||
$tb = ts.processTbody(table, c.$tbodies.eq(0), true);
|
||||
for ( i = s; i < e; i++ ) {
|
||||
$tb.append(rows[i]);
|
||||
}
|
||||
ts.processTbody(table, $tb, false);
|
||||
}
|
||||
|
||||
tsp.updatePageDisplay(table, c);
|
||||
if ( !p.isDisabled ) { tsp.fixHeight(table, c); }
|
||||
|
||||
wo.pager_startPage = p.page;
|
||||
wo.pager_size = p.size;
|
||||
c.$table.trigger('applyWidgets');
|
||||
if (table.isUpdating) {
|
||||
c.$table.trigger('updateComplete');
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
showAllRows: function(table, c){
|
||||
var p = c.pager,
|
||||
wo = c.widgetOptions;
|
||||
if ( p.ajax ) {
|
||||
tsp.pagerArrows(c, true);
|
||||
} else {
|
||||
p.isDisabled = true;
|
||||
$.data(table, 'pagerLastPage', p.page);
|
||||
$.data(table, 'pagerLastSize', p.size);
|
||||
p.page = 0;
|
||||
p.size = p.totalRows;
|
||||
p.totalPages = 1;
|
||||
c.$table
|
||||
.addClass('pagerDisabled')
|
||||
.removeAttr('aria-describedby')
|
||||
.find('tr.pagerSavedHeightSpacer').remove();
|
||||
tsp.renderTable(table, c.rowsCopy);
|
||||
if (c.debug) {
|
||||
ts.log('pager disabled');
|
||||
}
|
||||
}
|
||||
// disable size selector
|
||||
p.$size.add(p.$goto).each(function(){
|
||||
$(this).attr('aria-disabled', 'true').addClass(wo.pager_css.disabled)[0].disabled = true;
|
||||
});
|
||||
},
|
||||
|
||||
moveToPage: function(table, p, pageMoved) {
|
||||
if ( p.isDisabled ) { return; }
|
||||
var c = table.config,
|
||||
l = p.last,
|
||||
pg = Math.min( p.totalPages, p.filteredPages );
|
||||
if ( p.page < 0 ) { p.page = 0; }
|
||||
if ( p.page > ( pg - 1 ) && pg !== 0 ) { p.page = pg - 1; }
|
||||
// fixes issue where one current filter is [] and the other is ['','',''],
|
||||
// making the next if comparison think the filters as different. Fixes #202.
|
||||
l.currentFilters = (l.currentFilters || []).join('') === '' ? [] : l.currentFilters;
|
||||
p.currentFilters = (p.currentFilters || []).join('') === '' ? [] : p.currentFilters;
|
||||
// don't allow rendering multiple times on the same page/size/totalRows/filters/sorts
|
||||
if ( l.page === p.page && l.size === p.size && l.totalRows === p.totalRows &&
|
||||
(l.currentFilters || []).join(',') === (p.currentFilters || []).join(',') &&
|
||||
l.sortList === (c.sortList || []).join(',') ) {
|
||||
return;
|
||||
}
|
||||
if (c.debug) {
|
||||
ts.log('Pager changing to page ' + p.page);
|
||||
}
|
||||
p.last = {
|
||||
page : p.page,
|
||||
size : p.size,
|
||||
// fixes #408; modify sortList otherwise it auto-updates
|
||||
sortList : (c.sortList || []).join(','),
|
||||
totalRows : p.totalRows,
|
||||
currentFilters : p.currentFilters || []
|
||||
};
|
||||
if (p.ajax) {
|
||||
tsp.getAjax(table, c);
|
||||
} else if (!p.ajax) {
|
||||
tsp.renderTable(table, c.rowsCopy);
|
||||
}
|
||||
$.data(table, 'pagerLastPage', p.page);
|
||||
if (p.initialized && pageMoved !== false) {
|
||||
c.$table.trigger('pageMoved', c);
|
||||
if (!p.ajax && table.isUpdating) {
|
||||
c.$table.trigger('updateComplete');
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
setPageSize: function(table, size, c) {
|
||||
var p = c.pager;
|
||||
p.size = size || p.size || 10;
|
||||
p.$size.val(p.size);
|
||||
$.data(table, 'pagerLastPage', p.page);
|
||||
$.data(table, 'pagerLastSize', p.size);
|
||||
p.totalPages = Math.ceil( p.totalRows / p.size );
|
||||
p.filteredPages = Math.ceil( p.filteredRows / p.size );
|
||||
tsp.moveToPage(table, p);
|
||||
},
|
||||
|
||||
moveToFirstPage: function(table, p) {
|
||||
p.page = 0;
|
||||
tsp.moveToPage(table, p);
|
||||
},
|
||||
|
||||
moveToLastPage: function(table, p) {
|
||||
p.page = ( Math.min( p.totalPages, p.filteredPages ) - 1 );
|
||||
tsp.moveToPage(table, p);
|
||||
},
|
||||
|
||||
moveToNextPage: function(table, p) {
|
||||
p.page++;
|
||||
if ( p.page >= ( Math.min( p.totalPages, p.filteredPages ) - 1 ) ) {
|
||||
p.page = ( Math.min( p.totalPages, p.filteredPages ) - 1 );
|
||||
}
|
||||
tsp.moveToPage(table, p);
|
||||
},
|
||||
|
||||
moveToPrevPage: function(table, p) {
|
||||
p.page--;
|
||||
if ( p.page <= 0 ) {
|
||||
p.page = 0;
|
||||
}
|
||||
tsp.moveToPage(table, p);
|
||||
},
|
||||
|
||||
destroyPager: function(table, c){
|
||||
var p = c.pager;
|
||||
tsp.showAllRows(table, c);
|
||||
p.$container.hide(); // hide pager
|
||||
c.appender = null; // remove pager appender function
|
||||
p.initialized = false;
|
||||
c.$table.unbind('destroy.pager sortEnd.pager filterEnd.pager enable.pager disable.pager');
|
||||
if (ts.storage) {
|
||||
ts.storage(table, c.widgetOptions.pager_storageKey, '');
|
||||
}
|
||||
},
|
||||
|
||||
enablePager: function(table, c, triggered){
|
||||
var info, p = c.pager;
|
||||
p.isDisabled = false;
|
||||
p.page = $.data(table, 'pagerLastPage') || p.page || 0;
|
||||
p.size = $.data(table, 'pagerLastSize') || parseInt(p.$size.find('option[selected]').val(), 10) || p.size || 10;
|
||||
p.$size.val(p.size); // set page size
|
||||
p.totalPages = Math.ceil( Math.min( p.totalRows, p.filteredRows ) / p.size );
|
||||
c.$table.removeClass('pagerDisabled');
|
||||
// if table id exists, include page display with aria info
|
||||
if ( table.id ) {
|
||||
info = table.id + '_pager_info';
|
||||
p.$container.find(c.widgetOptions.pager_selectors.pageDisplay).attr('id', info);
|
||||
c.$table.attr('aria-describedby', info);
|
||||
}
|
||||
if ( triggered ) {
|
||||
c.$table.trigger('updateRows');
|
||||
tsp.setPageSize(table, p.size, c);
|
||||
tsp.hideRowsSetup(table, c);
|
||||
tsp.fixHeight(table, c);
|
||||
if (c.debug) {
|
||||
ts.log('pager enabled');
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
appender: function(table, rows) {
|
||||
var c = table.config,
|
||||
wo = c.widgetOptions,
|
||||
p = c.pager;
|
||||
if ( !p.ajax ) {
|
||||
c.rowsCopy = rows;
|
||||
p.totalRows = c.widgetOptions.pager_countChildRows ? c.$tbodies.eq(0).children().length : rows.length;
|
||||
p.size = $.data(table, 'pagerLastSize') || p.size || wo.pager_size || 10;
|
||||
p.totalPages = Math.ceil( p.totalRows / p.size );
|
||||
tsp.moveToPage(table, p, true);
|
||||
// update display here in case all rows are removed
|
||||
tsp.updatePageDisplay(table, c, false);
|
||||
} else {
|
||||
tsp.moveToPage(table, p, true);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
// see #486
|
||||
ts.showError = function(table, message){
|
||||
$(table).each(function(){
|
||||
var $row,
|
||||
c = this.config,
|
||||
errorRow = c.pager && c.pager.cssErrorRow || c.widgetOptions.pager_css && c.widgetOptions.pager_css.errorRow || 'tablesorter-errorRow';
|
||||
if (c) {
|
||||
if (typeof message === 'undefined') {
|
||||
c.$table.find('thead').find(c.selectorRemove).remove();
|
||||
} else {
|
||||
$row = ( /tr\>/.test(message) ? $(message) : $('<tr><td colspan="' + c.columns + '">' + message + '</td></tr>') )
|
||||
.click(function(){
|
||||
$(this).remove();
|
||||
})
|
||||
// add error row to thead instead of tbody, or clicking on the header will result in a parser error
|
||||
.appendTo( c.$table.find('thead:first') )
|
||||
.addClass( errorRow + ' ' + c.selectorRemove.replace(/^[.#]/, '') )
|
||||
.attr({
|
||||
role : 'alert',
|
||||
'aria-live' : 'assertive'
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
})(jQuery);
|