diff --git a/.gitignore b/.gitignore index 25ab2bc..3f32a09 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,6 @@ *.swp *.pyc *.log -js/mobile.js -js/init_plot.js -css/mobile.css -cache.manifest +/index.html +/service-worker.js tiles/ diff --git a/.htaccess b/.htaccess deleted file mode 100644 index 3d763d3..0000000 --- a/.htaccess +++ /dev/null @@ -1,38 +0,0 @@ - - # Compress HTML, CSS, JavaScript, Text, XML and fonts - AddOutputFilterByType DEFLATE application/javascript - AddOutputFilterByType DEFLATE application/rss+xml - AddOutputFilterByType DEFLATE application/vnd.ms-fontobject - AddOutputFilterByType DEFLATE application/x-font - AddOutputFilterByType DEFLATE application/x-font-opentype - AddOutputFilterByType DEFLATE application/x-font-otf - AddOutputFilterByType DEFLATE application/x-font-truetype - AddOutputFilterByType DEFLATE application/x-font-ttf - AddOutputFilterByType DEFLATE application/x-javascript - AddOutputFilterByType DEFLATE application/xhtml+xml - AddOutputFilterByType DEFLATE application/xml - AddOutputFilterByType DEFLATE font/opentype - AddOutputFilterByType DEFLATE font/otf - AddOutputFilterByType DEFLATE font/ttf - AddOutputFilterByType DEFLATE image/svg+xml - AddOutputFilterByType DEFLATE image/x-icon - AddOutputFilterByType DEFLATE text/css - AddOutputFilterByType DEFLATE text/html - AddOutputFilterByType DEFLATE text/javascript - AddOutputFilterByType DEFLATE text/plain - AddOutputFilterByType DEFLATE text/xml - - # Remove browser bugs (only needed for ancient browsers) - BrowserMatch ^Mozilla/4 gzip-only-text/html - BrowserMatch ^Mozilla/4\.0[678] no-gzip - BrowserMatch \bMSIE !no-gzip !gzip-only-text/html - Header append Vary User-Agent - - -AddType text/cache-manifest .manifest -AddType text/cache-manifest .appcache - -AddType application/x-font-woff .woff -AddType application/x-font-ttf .ttf -AddType application/vnd.ms-fontobject .eot -AddType image/svg+xml .svg diff --git a/DEVELOPER_README.md b/DEVELOPER_README.md index e7aba4d..b205943 100644 --- a/DEVELOPER_README.md +++ b/DEVELOPER_README.md @@ -4,6 +4,6 @@ To get a copy of the code and run a test web server: 1. [Fork the repository](https://github.com/projecthorus/sondehub-amateur-tracker/fork) by visiting [https://github.com/projecthorus/sondehub-amateur-tracker/fork](https://github.com/projecthorus/sondehub-amateur-tracker/fork). 2. Clone the repository with your git tool of choice. -3. Run `build.sh` to compile the javascript files. (This requires Java to be installed and in your path.) +3. Run `build.sh` to generate `index.html` and `service-worker.js`. 4. Run `python serve.py` to run a simple web server to (This requires python 3.x) 5. Visit [http://localhost:8000](http://localhost:8000) to view the local version of the server! diff --git a/README.md b/README.md index 74a9359..3e89342 100644 --- a/README.md +++ b/README.md @@ -31,10 +31,11 @@ Pull requests are welcome. ## Installation -Requirements: Java - $ git clone https://github.com/projecthorus/sondehub-amateur-tracker.git $ ./build.sh + $ python serve.py + +Visit [http://localhost:8000](http://localhost:8000) to view the local version of the tracker! ## Original design diff --git a/build.sh b/build.sh index 617720d..a5ebac8 100755 --- a/build.sh +++ b/build.sh @@ -1,48 +1,18 @@ #!/bin/bash -# compile stylesheet -echo -n "Compiling CSS... " -cd css -rm -f mobile.css -cat base.css skeleton.css layout.css habitat-font.css main.css leaflet.css leaflet.fullscreen.css > mobile.tmp -java -jar "../tools/yuicompressor-2.4.8.jar" --type=css mobile.tmp > mobile.css -rm -f mobile.tmp -cd .. -echo "Done!" - -#compile javascript -echo -n "Compiling JavaScript... " -cd js -rm -f mobile.js init_plot.js -# precompiled libs -cat jquery* >> mobile.js +set -e VERSION="`git rev-parse --short HEAD`" - BUILD_DATE="`date -u +%Y-%m-%dT%H:%M:%SZ`" -# compile the rest -java -jar "../tools/yuicompressor-2.4.8.jar" --type=js --disable-optimizations --nomunge iscroll.js >> mobile.js -java -jar "../tools/yuicompressor-2.4.8.jar" --type=js --disable-optimizations --nomunge chasecar.lib.js | sed "s/{VER}/$VERSION/" >> mobile.js -java -jar "../tools/yuicompressor-2.4.8.jar" --type=js --disable-optimizations --nomunge tracker.js >> mobile.js -java -jar "../tools/yuicompressor-2.4.8.jar" --type=js --disable-optimizations --nomunge app.js | sed "s/{VER}/$VERSION/" | sed "s/{BUILD_DATE}/$BUILD_DATE/" >> mobile.js -java -jar "../tools/yuicompressor-2.4.8.jar" --type=js --disable-optimizations --nomunge colour-map.js >> mobile.js -java -jar "../tools/yuicompressor-2.4.8.jar" --type=js --disable-optimizations --nomunge suncalc.js >> mobile.js -java -jar "../tools/yuicompressor-2.4.8.jar" --type=js --disable-optimizations --nomunge format.js >> mobile.js -java -jar "../tools/yuicompressor-2.4.8.jar" --type=js --disable-optimizations --nomunge flight_doc.js >> mobile.js - -#compile plot lib and config -java -jar "../tools/yuicompressor-2.4.8.jar" --type=js --disable-optimizations --nomunge _jquery.flot.js >> init_plot.js -java -jar "../tools/yuicompressor-2.4.8.jar" --type=js --disable-optimizations --nomunge plot_config.js >> init_plot.js - -cd .. +# cache fixes +echo -n "Generating index.html... " +sed -e "s/{VER}/$VERSION/" -e "s/{BUILD_DATE}/$BUILD_DATE/" index.template.html > index.html echo "Done!" -echo -n "Generate cache.manifest..." - - -sed "s/^\(# version\) .*$/\1 $VERSION `date +%s`/" cache.manifest-dev > cache.manifest +echo -n "Generating service-worker.js... " +sed -e "s/{VER}/$VERSION/" service-worker.template.js > service-worker.js echo "Done!" -echo "Build version: $VERSION Build date: $BUILD_DATE" \ No newline at end of file +echo "Build version: $VERSION Build date: $BUILD_DATE" diff --git a/cache.manifest-dev b/cache.manifest-dev deleted file mode 100644 index 701d56c..0000000 --- a/cache.manifest-dev +++ /dev/null @@ -1,75 +0,0 @@ -CACHE MANIFEST -# version {VERSION} - -# gogole maps files -http://maps.google.com/maps/api/js?v=3.22&sensor=false&libraries=map,common,controls,util,marker,onion,kml,ga,infowindow,stats,poly,overlay,weather,weather_impl,geometry&language=en_us&key=AIzaSyCOqkcNey4CCyG4X0X5qxHAhCgD8g5DwXg -http://fonts.googleapis.com/css?family=Roboto:300,400,500,700 -http://maps.gstatic.com/mapfiles/undo_poly.png -http://maps.gstatic.com/mapfiles/mv/imgs8.png -http://maps.gstatic.com/mapfiles/transparent.png -http://maps.gstatic.com/mapfiles/api-3/images/mapcnt3.png -http://maps.gstatic.com/mapfiles/api-3/images/google_white2_hdpi.png -http://maps.gstatic.com/mapfiles/api-3/images/google_white2.png -http://maps.gstatic.com/mapfiles/openhand_8_8.cur - -# app files -img/closedhand.cur -img/openhand.cur -img/logo.png -img/blank.png -img/marker-you.png -img/apple-touch-icon.png -img/markers/hab_nyan.gif -img/markers/nyan.gif -img/markers/antenna-green.png -img/markers/balloon-red.png -img/markers/balloon-blue.png -img/markers/balloon-green.png -img/markers/balloon-purple.png -img/markers/balloon-cyan.png -img/markers/balloon-orange.png -img/markers/balloon-yellow.png -img/markers/balloon-rpi.png -img/markers/car-blue.png -img/markers/car-green.png -img/markers/car-red.png -img/markers/car-yellow.png -img/markers/parachute-blue.png -img/markers/parachute-green.png -img/markers/parachute-red.png -img/markers/parachute-yellow.png -img/markers/parachute-cyan.png -img/markers/parachute-orange.png -img/markers/parachute-purple.png -img/markers/parachute-rpi.png -img/markers/payload-blue.png -img/markers/payload-cyan.png -img/markers/payload-green.png -img/markers/payload-orange.png -img/markers/payload-purple.png -img/markers/payload-red.png -img/markers/payload-yellow.png -img/markers/payload-rpi.png -img/markers/shadow.png -img/markers/target-blue.png -img/markers/target-cyan.png -img/markers/target-green.png -img/markers/target-orange.png -img/markers/target-purple.png -img/markers/target-red.png -img/markers/target-yellow.png -img/hab-spinner.gif -css/mobile.css -js/mobile.js -js/init_plot.js -font/HabitatFont.eot -font/HabitatFont.svg -font/HabitatFont.ttf -font/HabitatFont.woff -font/Roboto-regular.woff - -NETWORK: -* - -FALLBACK: -/ index.html diff --git a/img/markers/balloon-adafruit.png b/img/markers/balloon-adafruit.png deleted file mode 100644 index 4c715f2..0000000 Binary files a/img/markers/balloon-adafruit.png and /dev/null differ diff --git a/img/markers/balloon-blue.png b/img/markers/balloon-blue.png deleted file mode 100644 index 9888487..0000000 Binary files a/img/markers/balloon-blue.png and /dev/null differ diff --git a/img/markers/balloon-buzz.png b/img/markers/balloon-buzz.png deleted file mode 100644 index 17097b5..0000000 Binary files a/img/markers/balloon-buzz.png and /dev/null differ diff --git a/img/markers/balloon-cyan.png b/img/markers/balloon-cyan.png deleted file mode 100644 index 9eae707..0000000 Binary files a/img/markers/balloon-cyan.png and /dev/null differ diff --git a/img/markers/balloon-green.png b/img/markers/balloon-green.png deleted file mode 100644 index 126a0b0..0000000 Binary files a/img/markers/balloon-green.png and /dev/null differ diff --git a/img/markers/balloon-invisible.png b/img/markers/balloon-invisible.png deleted file mode 100644 index 19464e9..0000000 Binary files a/img/markers/balloon-invisible.png and /dev/null differ diff --git a/img/markers/balloon-iss.png b/img/markers/balloon-iss.png deleted file mode 100644 index 23d2a49..0000000 Binary files a/img/markers/balloon-iss.png and /dev/null differ diff --git a/img/markers/balloon-orange.png b/img/markers/balloon-orange.png deleted file mode 100644 index b0c5d09..0000000 Binary files a/img/markers/balloon-orange.png and /dev/null differ diff --git a/img/markers/balloon-purple.png b/img/markers/balloon-purple.png deleted file mode 100644 index e129b1c..0000000 Binary files a/img/markers/balloon-purple.png and /dev/null differ diff --git a/img/markers/balloon-red.png b/img/markers/balloon-red.png deleted file mode 100644 index f079bfe..0000000 Binary files a/img/markers/balloon-red.png and /dev/null differ diff --git a/img/markers/balloon-rob.png b/img/markers/balloon-rob.png deleted file mode 100644 index 819a558..0000000 Binary files a/img/markers/balloon-rob.png and /dev/null differ diff --git a/img/markers/balloon-rpi.png b/img/markers/balloon-rpi.png deleted file mode 100644 index c340631..0000000 Binary files a/img/markers/balloon-rpi.png and /dev/null differ diff --git a/img/markers/balloon-shockpink.png b/img/markers/balloon-shockpink.png deleted file mode 100644 index 49ad112..0000000 Binary files a/img/markers/balloon-shockpink.png and /dev/null differ diff --git a/img/markers/balloon-thereg.png b/img/markers/balloon-thereg.png deleted file mode 100644 index f26068f..0000000 Binary files a/img/markers/balloon-thereg.png and /dev/null differ diff --git a/img/markers/balloon-yellow.png b/img/markers/balloon-yellow.png deleted file mode 100644 index 66fc042..0000000 Binary files a/img/markers/balloon-yellow.png and /dev/null differ diff --git a/img/markers/balloon.svg b/img/markers/balloon.svg new file mode 100755 index 0000000..cd09c3e --- /dev/null +++ b/img/markers/balloon.svg @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/img/markers/car-blue.png b/img/markers/car-blue.png deleted file mode 100644 index 09192f0..0000000 Binary files a/img/markers/car-blue.png and /dev/null differ diff --git a/img/markers/car-green.png b/img/markers/car-green.png deleted file mode 100644 index c42da50..0000000 Binary files a/img/markers/car-green.png and /dev/null differ diff --git a/img/markers/car-purple.png b/img/markers/car-purple.png deleted file mode 100644 index a281513..0000000 Binary files a/img/markers/car-purple.png and /dev/null differ diff --git a/img/markers/car-red.png b/img/markers/car-red.png deleted file mode 100644 index ce44c92..0000000 Binary files a/img/markers/car-red.png and /dev/null differ diff --git a/img/markers/car-teal.png b/img/markers/car-teal.png deleted file mode 100644 index f0e6fe8..0000000 Binary files a/img/markers/car-teal.png and /dev/null differ diff --git a/img/markers/car-yellow.png b/img/markers/car-yellow.png deleted file mode 100644 index 5c35476..0000000 Binary files a/img/markers/car-yellow.png and /dev/null differ diff --git a/img/markers/car.svg b/img/markers/car.svg new file mode 100644 index 0000000..c277ce8 --- /dev/null +++ b/img/markers/car.svg @@ -0,0 +1,88 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/img/markers/parachute-blue.png b/img/markers/parachute-blue.png deleted file mode 100644 index ff4dc5d..0000000 Binary files a/img/markers/parachute-blue.png and /dev/null differ diff --git a/img/markers/parachute-cyan.png b/img/markers/parachute-cyan.png deleted file mode 100644 index bf83a49..0000000 Binary files a/img/markers/parachute-cyan.png and /dev/null differ diff --git a/img/markers/parachute-green.png b/img/markers/parachute-green.png deleted file mode 100644 index f41d7e1..0000000 Binary files a/img/markers/parachute-green.png and /dev/null differ diff --git a/img/markers/parachute-orange.png b/img/markers/parachute-orange.png deleted file mode 100644 index e3f2d16..0000000 Binary files a/img/markers/parachute-orange.png and /dev/null differ diff --git a/img/markers/parachute-purple.png b/img/markers/parachute-purple.png deleted file mode 100644 index adae959..0000000 Binary files a/img/markers/parachute-purple.png and /dev/null differ diff --git a/img/markers/parachute-red.png b/img/markers/parachute-red.png deleted file mode 100644 index 603c60f..0000000 Binary files a/img/markers/parachute-red.png and /dev/null differ diff --git a/img/markers/parachute-rpi.png b/img/markers/parachute-rpi.png deleted file mode 100644 index ad421b6..0000000 Binary files a/img/markers/parachute-rpi.png and /dev/null differ diff --git a/img/markers/parachute-yellow.png b/img/markers/parachute-yellow.png deleted file mode 100644 index 4d85a51..0000000 Binary files a/img/markers/parachute-yellow.png and /dev/null differ diff --git a/img/markers/parachute.svg b/img/markers/parachute.svg new file mode 100644 index 0000000..8b10853 --- /dev/null +++ b/img/markers/parachute.svg @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/img/markers/payload-blue.png b/img/markers/payload-blue.png deleted file mode 100644 index c03caee..0000000 Binary files a/img/markers/payload-blue.png and /dev/null differ diff --git a/img/markers/payload-cyan.png b/img/markers/payload-cyan.png deleted file mode 100644 index 226bfa8..0000000 Binary files a/img/markers/payload-cyan.png and /dev/null differ diff --git a/img/markers/payload-green.png b/img/markers/payload-green.png deleted file mode 100644 index f524a73..0000000 Binary files a/img/markers/payload-green.png and /dev/null differ diff --git a/img/markers/payload-orange.png b/img/markers/payload-orange.png deleted file mode 100644 index 20e5b05..0000000 Binary files a/img/markers/payload-orange.png and /dev/null differ diff --git a/img/markers/payload-purple.png b/img/markers/payload-purple.png deleted file mode 100644 index 80e1e1a..0000000 Binary files a/img/markers/payload-purple.png and /dev/null differ diff --git a/img/markers/payload-red.png b/img/markers/payload-red.png deleted file mode 100644 index 7ad8acc..0000000 Binary files a/img/markers/payload-red.png and /dev/null differ diff --git a/img/markers/payload-rpi.png b/img/markers/payload-rpi.png deleted file mode 100644 index 9f533fb..0000000 Binary files a/img/markers/payload-rpi.png and /dev/null differ diff --git a/img/markers/payload-yellow.png b/img/markers/payload-yellow.png deleted file mode 100644 index e9b7bb5..0000000 Binary files a/img/markers/payload-yellow.png and /dev/null differ diff --git a/img/markers/payload.svg b/img/markers/payload.svg new file mode 100644 index 0000000..b89d7d6 --- /dev/null +++ b/img/markers/payload.svg @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/img/markers/target-blue.png b/img/markers/target-blue.png deleted file mode 100644 index fae5796..0000000 Binary files a/img/markers/target-blue.png and /dev/null differ diff --git a/img/markers/target-cyan.png b/img/markers/target-cyan.png deleted file mode 100644 index ba30743..0000000 Binary files a/img/markers/target-cyan.png and /dev/null differ diff --git a/img/markers/target-green.png b/img/markers/target-green.png deleted file mode 100644 index 56b4682..0000000 Binary files a/img/markers/target-green.png and /dev/null differ diff --git a/img/markers/target-orange.png b/img/markers/target-orange.png deleted file mode 100644 index 4b353b6..0000000 Binary files a/img/markers/target-orange.png and /dev/null differ diff --git a/img/markers/target-purple.png b/img/markers/target-purple.png deleted file mode 100644 index 4510158..0000000 Binary files a/img/markers/target-purple.png and /dev/null differ diff --git a/img/markers/target-red.png b/img/markers/target-red.png deleted file mode 100644 index 5987df9..0000000 Binary files a/img/markers/target-red.png and /dev/null differ diff --git a/img/markers/target-yellow.png b/img/markers/target-yellow.png deleted file mode 100644 index 8dc2d08..0000000 Binary files a/img/markers/target-yellow.png and /dev/null differ diff --git a/img/markers/target.svg b/img/markers/target.svg new file mode 100644 index 0000000..e80875e --- /dev/null +++ b/img/markers/target.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/index.html b/index.template.html similarity index 92% rename from index.html rename to index.template.html index c743538..a215c40 100644 --- a/index.html +++ b/index.template.html @@ -19,10 +19,35 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + - +
@@ -131,9 +156,10 @@

Contribute

github/sondehub-amateur-tracker. Bug reports, suggestions and pull requests are welcome. A huge thanks to RGP for developing the mobile tracker that this site is based on.

- Tracker Revision: + Tracker Revision: {VER}
- Build Date: + Build Date: {BUILD_DATE} +

@@ -380,26 +406,10 @@

Prediction Settings

+ + + + - - - - - - - - - - - - diff --git a/js/app.js b/js/app.js index 2ea1f63..fc84224 100644 --- a/js/app.js +++ b/js/app.js @@ -40,6 +40,10 @@ function lhash_update(history_step) { hash += "&nyan=1"; } + if (document.getElementById("modulationfilter").value != "all"){ + hash += "&mo=" + document.getElementById("modulationfilter").value; + } + hash = encodeURI(hash); // set state if(history_supported) { @@ -132,6 +136,10 @@ function load_hash(no_refresh) { focusID = v; gotoSite(v); break; + case "mo": + document.getElementById("modulationfilter").value = v; + sidebar_update(); + break; } }); @@ -197,7 +205,9 @@ function trackerInit() { if(is_mobile || wvar.enabled) $(".nav .wvar").hide(); if(!is_mobile) { - $.getScript("js/init_plot.js", function() { checkSize(); if(!map) load(); }); + $.getScript("js/_jquery.flot.js", function() { + $.getScript("js/plot_config.js", function() { checkSize(); if(!map) load(); }); + }); if(wvar.graph) $('#telemetry_graph').attr('style',''); return; @@ -205,7 +215,7 @@ function trackerInit() { if(!map) load(); } -// if for some reason, applicationCache is not working, load the app after a 3s timeout +// load the app after a 3s timeout var initTimer = setTimeout(trackerInit, 3000); var listScroll; @@ -362,7 +372,7 @@ var positionUpdateHandle = function(position) { } else { return; } - // add/update marker on the map (tracker.js) + // add/update marker on the map (sondehub.js) updateCurrentPosition(lat, lon); // round the coordinates @@ -435,6 +445,25 @@ var format_time_friendly = function(start, end) { } }; +var format_coordinates = function(lat, lon, name) { + var coords_text; + var ua = navigator.userAgent.toLowerCase(); + + // determine how to link the coordinates to a native app, if on a mobile device + if(ua.indexOf('iphone') > -1) { + coords_text = '' + + roundNumber(lat, 5) + ', ' + roundNumber(lon, 5) +''; + } else if(ua.indexOf('android') > -1) { + coords_text = '' + + roundNumber(lat, 5) + ', ' + roundNumber(lon, 5) +''; + } else { + coords_text = '' + + roundNumber(lat, 5) + ', ' + roundNumber(lon, 5) +''; + } + + return coords_text; +}; + // runs every second var updateTime = function(date) { // update timebox @@ -463,10 +492,6 @@ $(window).ready(function() { updateTime(new Date()); }, 1000); - // Update Tracker version info - $('#build_version').text("{VER}"); - $('#build_date').text("{BUILD_DATE}"); - // resize elements if needed checkSize(); @@ -558,12 +583,6 @@ $(window).ready(function() { $("#main").removeClass("drag"); }); - // confirm dialog when launchnig a native map app with coordinates - //$('#main').on('click', '#launch_mapapp', function() { - // var answer = confirm("Launch your maps app?"); - // return answer; - //}); - // follow vehicle by clicking on data $('#main').on('click', '.row .data', function() { var e = $(this).parent(); @@ -659,7 +678,7 @@ $(window).ready(function() { if(currentPosition && currentPosition.marker) map.addLayer(currentPosition.marker); // turning the switch on } else { - if(callsign.length == null || callsign.length < 3) { alert('Please enter a valid callsign, at least 3 characters'); return; } + if(callsign == null || callsign.length < 3) { alert('Please enter a valid callsign, at least 3 characters'); return; } if(!callsign.match(/^[a-zA-Z0-9\_\-]+$/)) { alert('Invalid characters in callsign (use only a-z,0-9,-,_)'); return; } field.attr('disabled','disabled'); diff --git a/js/chasecar.lib.js b/js/chasecar.lib.js index 5fa079c..bc10056 100644 --- a/js/chasecar.lib.js +++ b/js/chasecar.lib.js @@ -23,7 +23,7 @@ ChaseCar.updatePosition = function(callsign, position) { var _doc = { "software_name": "SondeHub-Amateur", - "software_version": "{VER}", + "software_version": document.body.dataset.version, "uploader_callsign": callsign, "uploader_position": [position.coords.latitude, position.coords.longitude, _position_alt], "uploader_antenna": "Mobile Station", @@ -39,4 +39,4 @@ ChaseCar.updatePosition = function(callsign, position) { dataType: "json", data: JSON.stringify(_doc), }); -}; \ No newline at end of file +}; diff --git a/js/format.js b/js/format.js index 49c6b81..d0ae536 100644 --- a/js/format.js +++ b/js/format.js @@ -63,13 +63,13 @@ function formatData(data) { data[key][i].uploaders = []; data[key][i].uploaders[0] = {} data[key][i].uploaders[0].uploader_callsign = data[key][i].uploader_callsign; - if (data[key][i].snr) { + if (data[key][i].snr && typeof data[key][i].snr === "number") { data[key][i].uploaders[0].snr = + data[key][i].snr.toFixed(1); } - if (data[key][i].rssi) { + if (data[key][i].rssi && typeof data[key][i].rssi === "number") { data[key][i].uploaders[0].rssi = + data[key][i].rssi.toFixed(1); } - if (data[key][i].frequency) { + if (data[key][i].frequency && typeof data[key][i].frequency === "number") { data[key][i].uploaders[0].frequency = + data[key][i].frequency.toFixed(4); } } @@ -85,13 +85,13 @@ function formatData(data) { uploader_callsign = data[key][i].uploaders[entry].uploader_callsign dataTempEntry.callsign[uploader_callsign] = {}; - if (data[key][i].uploaders[entry].snr) { + if (data[key][i].uploaders[entry].snr && typeof data[key][i].uploaders[entry].snr === "number") { dataTempEntry.callsign[uploader_callsign].snr = + data[key][i].uploaders[entry].snr.toFixed(1); } - if (data[key][i].uploaders[entry].rssi) { + if (data[key][i].uploaders[entry].rssi && typeof data[key][i].uploaders[entry].rssi === "number") { dataTempEntry.callsign[uploader_callsign].rssi = + data[key][i].uploaders[entry].rssi.toFixed(1); } - if (data[key][i].uploaders[entry].frequency) { + if (data[key][i].uploaders[entry].frequency && typeof data[key][i].uploaders[entry].frequency === "number") { dataTempEntry.callsign[uploader_callsign].frequency = + data[key][i].uploaders[entry].frequency.toFixed(4); } diff --git a/js/plot_config.js b/js/plot_config.js index f40315a..c8ebcc0 100644 --- a/js/plot_config.js +++ b/js/plot_config.js @@ -77,9 +77,11 @@ function updateLegend(pos) { if(outside && pij !== undefined) { if(!polyMarker) { - try {polyMarker = new L.Marker(vehicles[follow_vehicle].prediction_polyline.getLatLngs()[pij]).addTo(map);} catch (e) {}; + try {polyMarker = new L.Marker(vehicles[follow_vehicle].prediction_polyline[0].getLatLngs()[pij]).addTo(map);} catch (e) {}; + try {polyMarker = new L.Marker(vehicles[follow_vehicle].prediction_polyline[1].getLatLngs()[pij]).addTo(map);} catch (e) {}; } else { - try {polyMarker.setLatLng(vehicles[follow_vehicle].prediction_polyline.getLatLngs()[pij]);} catch (e) {}; + try {polyMarker.setLatLng(vehicles[follow_vehicle].prediction_polyline[0].getLatLngs()[pij]);} catch (e) {}; + try {polyMarker.setLatLng(vehicles[follow_vehicle].prediction_polyline[1].getLatLngs()[pij]);} catch (e) {}; } } diff --git a/js/tracker.js b/js/sondehub.js similarity index 94% rename from js/tracker.js rename to js/sondehub.js index 4928028..45008c6 100644 --- a/js/tracker.js +++ b/js/sondehub.js @@ -9,6 +9,8 @@ var grafana_url = "https://grafana.v2.sondehub.org/d/HJgOZLq7k/basic?"; var grafana_aprs_url = "https://grafana.v2.sondehub.org/d/Lwvk1Hy4k/aprs-telemetry?"; // Grafana dashboard for WSPR flight var grafana_wspr_url = "https://grafana.v2.sondehub.org/d/e4571f1f-b51e-4e02-b97a-dcd198b49560/wspr-balloon-telemetry?"; +// Grafana dashboard for Wenet payloads +var grafana_wenet_url = "https://grafana.v2.sondehub.org/d/ddzty5w2yqt4wc/wenet?" var livedata = "wss://ws-reader.v2.sondehub.org/"; var clientID = "SondeHub-Tracker-" + Math.floor(Math.random() * 10000000000); @@ -62,10 +64,9 @@ var manual_pan = false; // due to complaints it was not visible enough. - 2023-06-03 var car_index = 0; -var car_colors = ["blue", "red", "green", "yellow", "teal", "purple"]; +var car_colors = ["#a6cee3", "#1f78b4", "#fb9a99", "#e31a1c", "#fdbf6f", "#ff7f00", "#cab2d6"]; var balloon_index = 0; -var balloon_colors_name = ["red", "blue", "green", "purple", "orange", "cyan"]; -var balloon_colors = ["#f00", "blue", "green", "#c700e6", "#ff8a0f", "#0fffca"]; +var balloon_colors = ["#d95f02", "#7570b3", "#e7298a", "#e6ab02", "#a6761d", "#666666", "blue", "magenta", "#ffb300", "rebeccapurple"]; var nyan_color_index = 0; var nyan_colors = ['nyan', 'nyan-coin', 'nyan-mon', 'nyan-pirate', 'nyan-cool', 'nyan-tothemax', 'nyan-pumpkin', 'nyan-afro', 'nyan-coin', 'nyan-mummy']; @@ -420,7 +421,7 @@ function makeQuad(x, y, zoom) { // map type list -var osm = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { +var osm = L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', { maxZoom: 19, attribution: '© OpenStreetMap contributors' }); @@ -569,7 +570,6 @@ function clean_refresh(text, force, history_step) { } car_index = 0; - balloon_index = 0; nyan_color_index = 0; stopFollow(force); @@ -666,6 +666,34 @@ function load() { L.control.periodcontrol({ position: 'topleft' }).addTo(map); + L.Control.ModulationFilter = L.Control.extend({ + onAdd: function(map) { + var div = L.DomUtil.create('div'); + + div.innerHTML = ``; + div.innerHTML.onload = setTimeValue(); + + return div; + }, + onRemove: function(map) { + // Nothing to do here + } + }) + + L.control.modulationcontrol = function(opts) { + return new L.Control.ModulationFilter(opts); + } + L.control.modulationcontrol({ position: 'topleft' }).addTo(map); + // update current position if we geolocation is available if(currentPosition) updateCurrentPosition(currentPosition.lat, currentPosition.lon); @@ -866,22 +894,71 @@ function panTo(vcallsign) { } } +function isVehicleFiltered(serial){ + if ( document.getElementById("modulationfilter") && document.getElementById("modulationfilter").value && document.getElementById("modulationfilter").value != "all"){ + if (vehicles[serial]['vehicle_type'] != 'balloon'){ + return false + } else { + if (vehicles[serial] && vehicles[serial]['curr_position'] && + vehicles[serial]['curr_position'] && + vehicles[serial]['curr_position']['data'] && + vehicles[serial]['curr_position']['data']['modulation'] && + vehicles[serial]['curr_position']['data']['modulation'].includes(document.getElementById("modulationfilter").value)) { + return false + } else { + return true + } + } + } + return false; +} + function sidebar_update() { if (offline.get('opt_selective_sidebar')) { for (let serial in vehicles) { - if (map.getBounds().contains(vehicles[serial].marker.getLatLng())) { + if (map.getBounds().contains(vehicles[serial].marker.getLatLng()) && !isVehicleFiltered(serial)) { $("#main .vehicle"+vehicles[serial].uuid).show(); + vehicles[serial].marker.addTo(map); + if (vehicles[serial].marker_shadow) { + vehicles[serial].marker_shadow.addTo(map); + } + + set_polyline_visibility(serial,true) + } else { if (!($("#main .vehicle"+vehicles[serial].uuid).hasClass("follow"))) { $("#main .vehicle"+vehicles[serial].uuid).hide(); - } + if (vehicles[serial].marker) map.removeLayer(vehicles[serial].marker); + if (vehicles[serial].marker_shadow) map.removeLayer(vehicles[serial].marker_shadow); + set_polyline_visibility(serial,false) + } } } } else { for (let serial in vehicles) { - $("#main .vehicle"+vehicles[serial].uuid).show(); + if (!isVehicleFiltered(serial)){ + $("#main .vehicle"+vehicles[serial].uuid).show(); + vehicles[serial].marker.addTo(map); + if (vehicles[serial].marker_shadow){ + vehicles[serial].marker_shadow.addTo(map); + } + + set_polyline_visibility(serial,true) + + } else { + $("#main .vehicle"+vehicles[serial].uuid).hide(); + if (vehicles[serial].marker) map.removeLayer(vehicles[serial].marker); + if (vehicles[serial].marker_shadow) map.removeLayer(vehicles[serial].marker_shadow); + set_polyline_visibility(serial,false) + } + } } + if(offline.get("opt_hide_horizon")) { + showHorizonRings(); + } else { + hideHorizonRings(); + } } function title_case(s) { @@ -1235,7 +1312,7 @@ function updateVehicleInfo(vcallsign, newPosition) { vehicle.marker.setLatLng(latlng); if(!!vehicle.marker.setCourse) { - if (vehicle.curr_position.gps_heading) { + if (vehicle.curr_position.gps_heading && vehicle.marker.rotated) { vehicle.marker.setCourse((vehicle.curr_position.gps_heading !== "") ? parseInt(vehicle.curr_position.gps_heading) : 90); } } @@ -1380,21 +1457,7 @@ function updateVehicleInfo(vcallsign, newPosition) { hrate_text = imp ? (vehicle.horizontal_rate * 196.850394).toFixed(1) + ' ft/min' : vehicle.horizontal_rate.toFixed(1) + ' m/s'; } - var coords_text; - var ua = navigator.userAgent.toLowerCase(); - - // determine how to link the vehicle coordinates to a native app, if on a mobile device - if(ua.indexOf('iphone') > -1) { - coords_text = '' + - roundNumber(newPosition.gps_lat, 5) + ', ' + roundNumber(newPosition.gps_lon, 5) +'' + - ' '; - } else if(ua.indexOf('android') > -1) { - coords_text = '' + - roundNumber(newPosition.gps_lat, 5) + ', ' + roundNumber(newPosition.gps_lon, 5) +'' + - ' '; - } else { - coords_text = roundNumber(newPosition.gps_lat, 5) + ', ' + roundNumber(newPosition.gps_lon, 5); - } + var coords_text = format_coordinates(newPosition.gps_lat, newPosition.gps_lon, vcallsign) + ' '; // format altitude strings var text_alt = Number((imp) ? Math.floor(3.2808399 * parseInt(newPosition.gps_alt)) : parseInt(newPosition.gps_alt)).toLocaleString("us"); @@ -1416,14 +1479,14 @@ function updateVehicleInfo(vcallsign, newPosition) { var current_time = convert_time(newPosition.server_time) - for(var i = 0; i < vehicle.receiver_info.length; i++){ + for(i in vehicle.receiver_info){ if (vehicle.receiver_info[i]["time"] < current_time - 15000) { - vehicle.receiver_info.splice(i,1); + delete vehicle.receiver_info[i]; } } function addReceiver(callsign) { - for(var i = 0; i < vehicle.receiver_info.length; i++){ + for(i in vehicle.receiver_info){ if (vehicle.receiver_info[i]["callsign"] === callsign) { vehicle.receiver_info[i]["time"] = current_time if(newPosition.callsign[callsign].hasOwnProperty('snr')){ @@ -1460,7 +1523,7 @@ function updateVehicleInfo(vcallsign, newPosition) { temp_receiver.frequency = newPosition.callsign[rxcall].frequency.toFixed(4) } } - vehicle.receiver_info.push(temp_receiver) + vehicle.receiver_info[callsign] = temp_receiver; } if($.type(newPosition.callsign) === "string"){ @@ -1473,7 +1536,10 @@ function updateVehicleInfo(vcallsign, newPosition) { addReceiver(rxcall) } - for(var receiver in vehicle.receiver_info){ + var receiver_list_sorted = Object.keys(vehicle.receiver_info).sort(); + + for(var receiver_idx in receiver_list_sorted){ + var receiver = receiver_list_sorted[receiver_idx]; _new_call = "- " + vehicle.receiver_info[receiver].callsign; tempFields = []; if(vehicle.receiver_info[receiver].hasOwnProperty('snr')){ @@ -1533,6 +1599,10 @@ function updateVehicleInfo(vcallsign, newPosition) { if(vehicle.curr_position.data.modulation.includes('WSPR')){ grafana_base_url = grafana_wspr_url; } + + if(vehicle.curr_position.data.modulation.includes('Wenet')){ + grafana_base_url = grafana_wenet_url; + } } if(vehicle.curr_position.data.hasOwnProperty('comment')){ if(vehicle.curr_position.data.comment.includes('WSPR')){ @@ -1636,6 +1706,8 @@ function updateVehicleInfo(vcallsign, newPosition) { // mark vehicles as redrawn vehicle.updated = false; + sidebar_update() + return true; } @@ -1830,9 +1902,11 @@ function set_polyline_visibility(vcallsign, val) { if(vehicle.prediction_polyline) { if (val) { - map.addLayer(vehicle.prediction_polyline); + map.addLayer(vehicle.prediction_polyline[0]); + map.addLayer(vehicle.prediction_polyline[1]); } else { - map.removeLayer(vehicle.prediction_polyline); + map.removeLayer(vehicle.prediction_polyline[0]); + map.removeLayer(vehicle.prediction_polyline[1]); } } if(vehicle.prediction_launch_polyline) { @@ -1862,7 +1936,8 @@ function set_polyline_visibility(vcallsign, val) { function removePrediction(vcallsign) { if(vehicles[vcallsign].prediction_polyline) { - map.removeLayer(vehicles[vcallsign].prediction_polyline); + map.removeLayer(vehicles[vcallsign].prediction_polyline[0]); + map.removeLayer(vehicles[vcallsign].prediction_polyline[1]); vehicles[vcallsign].prediction_polyline = null; } if(vehicles[vcallsign].prediction_target) { @@ -1875,7 +1950,19 @@ function removePrediction(vcallsign) { } } - +// Takes in an SVG for a balloon, parachute, target, car, etc and sets a dynamic-color +// variable which that SVG can use to recolor any relevant elements. +// See balloon.svg, target.svg, etc for examples +function recolorSVG(svg_path, color) { + const xhr = new XMLHttpRequest(); + xhr.open('GET', svg_path, false); + xhr.send(); + + const parser = new DOMParser(); + const svgDocument = parser.parseFromString(xhr.responseText, 'image/svg+xml'); + svgDocument.documentElement.style.setProperty("--dynamic-color", color); + return 'data:image/svg+xml;charset=utf-8,' + encodeURIComponent(svgDocument.documentElement.outerHTML); + } function redrawPrediction(vcallsign) { var vehicle = vehicles[vcallsign]; @@ -1916,19 +2003,33 @@ function redrawPrediction(vcallsign) { vehicle.prediction_path = line; if(vehicle.prediction_polyline !== null) { - vehicle.prediction_polyline.setLatLngs(line); + vehicle.prediction_polyline[0].setLatLngs(line); + vehicle.prediction_polyline[1].setLatLngs(line); } else { - vehicle.prediction_polyline = new L.Wrapped.Polyline(line, { + vehicle.prediction_polyline = [new L.Wrapped.Polyline(line, { color: balloon_colors[vehicle.color_index], - opacity: 0.5, + opacity: 0.8, weight: 3, - }).addTo(map); - vehicle.prediction_polyline.on('click', function (e) { + }), + vehicle.prediction_polyline = new L.Wrapped.Polyline(line, { + opacity: 0.1, + weight: 6, + color: "#000" + })] + vehicle.prediction_polyline[0].on('click', function (e) { mapInfoBox_handle_prediction_path(e); }); + vehicle.prediction_polyline[1].on('click', function (e) { + mapInfoBox_handle_prediction_path(e); + }); + + vehicle.prediction_polyline[0].addTo(map); + vehicle.prediction_polyline[1].addTo(map); + } - vehicle.prediction_polyline.path_length = path_length; + vehicle.prediction_polyline[0].path_length = path_length; + vehicle.prediction_polyline[1].path_length = path_length; var image_src; if(vcallsign != "wb8elk2") { // WhiteStar - Not sure the reasons behind a check for this? Seems odd. May be from when WB8ELK was first doing floater flights? @@ -1936,7 +2037,7 @@ function redrawPrediction(vcallsign) { if(vehicle.prediction_target) { vehicle.prediction_target.setLatLng(latlng); } else { - image_src = host_url + markers_url + "target-" + balloon_colors_name[vehicle.color_index] + ".png"; + image_src = recolorSVG(host_url + markers_url + "target.svg", balloon_colors[vehicle.color_index]); predictionIcon = new L.icon({ iconUrl: image_src, iconSize: [20,20], @@ -2232,7 +2333,7 @@ function mapInfoBox_handle_path_new(data, vehicle, date) { html = "
"; html += "
"+data.vehicle+" ("+date+")
"; html += "
"; - html += "
 "+roundNumber(data.gps_lat, 5) + ', ' + roundNumber(data.gps_lon, 5)+"
"; + html += "
 "+format_coordinates(data.gps_lat, data.gps_lon, data.vehicle)+"
"; var imp = offline.get('opt_imperial'); var text_alt = Number((imp) ? Math.floor(3.2808399 * parseInt(data.gps_alt)) : parseInt(data.gps_alt)).toLocaleString("us"); @@ -2331,20 +2432,7 @@ function mapInfoBox_handle_prediction(event) { altitude = Math.round(data.alt) + " m"; } - var coords_text; - var ua = navigator.userAgent.toLowerCase(); - - // determine how to link the vehicle coordinates to a native app, if on a mobile device - if(ua.indexOf('iphone') > -1) { - coords_text = '' + - roundNumber(data.lat, 5) + ', ' + roundNumber(data.lon, 5) + ''; - } else if(ua.indexOf('android') > -1) { - coords_text = '' + - roundNumber(data.lat, 5) + ', ' + roundNumber(data.lon, 5) +''; - } else { - coords_text = '' + - roundNumber(data.lat, 5) + ', ' + roundNumber(data.lon, 5) +''; - } + var coords_text = format_coordinates(data.lat, data.lon, "Prediction"); mapInfoBox.setContent("
" +
                         formatDate(new Date(parseInt(data.time) * 1000), true) + "\n\n" +
@@ -2425,10 +2513,10 @@ var marker_rotate_setup = function(marker, image_src) {
     else {
         marker.iconImg = new Image();
         icon_cache[image_src] = marker.iconImg;
-        marker.iconImg.onload = function() {
+        marker.iconImg.addEventListener("load", function() {
             if(!marker.rotated) marker.setCourse(90);
             marker.setLatLng(marker.getLatLng());
-        };
+        })
         marker.iconImg.src = image_src;
     }
 };
@@ -2462,7 +2550,7 @@ function addPosition(position) {
         if(vcallsign.search(/(chase)/i) != -1) {
             vehicle_type = "car";
             color_index = car_index++ % car_colors.length;
-            image_src = host_url + markers_url + "car-" + car_colors[color_index] + ".png";
+            image_src = recolorSVG(host_url + markers_url + "car.svg", car_colors[color_index]);
             image_src_size = [55,25];
             image_src_offset = [0,-25];
 
@@ -2527,8 +2615,7 @@ function addPosition(position) {
             vehicle_type = "balloon";
             color_index = balloon_index++ % balloon_colors.length;
 
-            image_src = host_url + markers_url + "balloon-" +
-                        ((vcallsign == "PIE") ? "rpi" : balloon_colors_name[color_index]) + ".png";
+            image_src = recolorSVG(host_url + markers_url + "balloon.svg", balloon_colors[color_index]);
             image_src_size = [46,84];
             image_src_offset = [-35,-46];
 
@@ -2573,7 +2660,7 @@ function addPosition(position) {
             };
 
             marker.shadow = marker_shadow;
-            marker.balloonColor = (vcallsign == "PIE") ? "rpi" : balloon_colors_name[color_index];
+            marker.balloonColor = balloon_colors[color_index];
             marker.mode = 'balloon';
             marker.setMode = function(mode) {
                 if(this.mode == mode) return;
@@ -2586,9 +2673,9 @@ function addPosition(position) {
                     map.removeLayer(vehicle.subhorizon_circle);
                     map.removeLayer(vehicle.horizon_circle_title);
                     map.removeLayer(vehicle.subhorizon_circle_title);
-
+                    img_src = recolorSVG(host_url + markers_url + "payload.svg", this.balloonColor);
                     img = new L.icon ({
-                        iconUrl: host_url + markers_url + "payload-" + this.balloonColor + ".png",
+                        iconUrl: img_src,
                         iconSize: [17,18],
                         iconAnchor: [8,14],
                         tooltipAnchor: [0,-20],
@@ -2604,15 +2691,17 @@ function addPosition(position) {
                     }
 
                     if(mode == "parachute") {
+                        img_src = recolorSVG(host_url + markers_url + "parachute.svg", this.balloonColor);
                         img = new L.icon ({
-                            iconUrl: host_url + markers_url + "parachute-" + this.balloonColor + ".png",
+                            iconUrl: img_src,
                             iconSize: [46,84],
                             tooltipAnchor: [0,-98],
                             iconAnchor: [23,90],
                         });
                     } else {
+                        img_src = recolorSVG(host_url + markers_url + "balloon.svg", this.balloonColor);
                         img = new L.icon ({
-                            iconUrl: host_url + markers_url + "balloon-" + this.balloonColor + ".png",
+                            iconUrl: img_src,
                             iconSize: [46,84],
                             tooltipAnchor: [0,-98],
                             iconAnchor: [23,90],
@@ -2723,7 +2812,12 @@ function addPosition(position) {
                     color: balloon_colors[color_index],
                     opacity: 1,
                     weight: 3,
-                }).addTo(map)
+                }).addTo(map),
+                new L.Polyline(point, {
+                    color: "#fff",
+                    opacity: 0.6,
+                    weight: 6,
+                })
             ];
         }
 
@@ -2835,8 +2929,11 @@ function addPosition(position) {
         vehicle_info.kill = function() {
             $(".vehicle"+vehicle_info.uuid).remove();
             potentialobjects = [marker, marker_shadow, landing_marker, horizon_circle, horizon_circle_title, subhorizon_circle, subhorizon_circle_title, polyline];
-            if (map.hasLayer(vehicle_info["prediction_polyline"])) { 
-                map.removeLayer(vehicle_info["prediction_polyline"]);
+            if (vehicle_info["prediction_polyline"] && map.hasLayer(vehicle_info["prediction_polyline"][0])) { 
+                map.removeLayer(vehicle_info["prediction_polyline"][0]);
+            }
+            if (vehicle_info["prediction_polyline"] && map.hasLayer(vehicle_info["prediction_polyline"][1])) { 
+                map.removeLayer(vehicle_info["prediction_polyline"][1]);
             }
             if (map.hasLayer(vehicle_info["prediction_launch_polyline"])) { 
                 map.removeLayer(vehicle_info["prediction_launch_polyline"]);
@@ -4071,21 +4168,26 @@ function refreshUI() {
 function hideHorizonRings(){
     for(var vcallsign in vehicles) {
         if(vehicles[vcallsign].vehicle_type == "balloon"){
-            map.removeLayer(vehicles[vcallsign].horizon_circle);
-            map.removeLayer(vehicles[vcallsign].subhorizon_circle);
-            map.removeLayer(vehicles[vcallsign].horizon_circle_title);
-            map.removeLayer(vehicles[vcallsign].subhorizon_circle_title);
+            if (vehicles[vcallsign].horizon_circle) map.removeLayer(vehicles[vcallsign].horizon_circle);
+            if (vehicles[vcallsign].subhorizon_circle) map.removeLayer(vehicles[vcallsign].subhorizon_circle);
+            if (vehicles[vcallsign].horizon_circle_titl) map.removeLayer(vehicles[vcallsign].horizon_circle_title);
+            if (vehicles[vcallsign].subhorizon_circle_title) map.removeLayer(vehicles[vcallsign].subhorizon_circle_title);
         }
     }
 }
 
 function showHorizonRings(){
     for(var vcallsign in vehicles) {
-        if(vehicles[vcallsign].vehicle_type == "balloon"){
+        if(vehicles[vcallsign].vehicle_type == "balloon" && (!isVehicleFiltered(vcallsign))){
             map.addLayer(vehicles[vcallsign].horizon_circle);
             map.addLayer(vehicles[vcallsign].subhorizon_circle);
             map.addLayer(vehicles[vcallsign].horizon_circle_title);
             map.addLayer(vehicles[vcallsign].subhorizon_circle_title);
+        } else if ( vehicles[vcallsign].vehicle_type == "balloon" ) {
+            if (vehicles[vcallsign].horizon_circle) map.removeLayer(vehicles[vcallsign].horizon_circle);
+            if (vehicles[vcallsign].subhorizon_circle) map.removeLayer(vehicles[vcallsign].subhorizon_circle);
+            if (vehicles[vcallsign].horizon_circle_title) map.removeLayer(vehicles[vcallsign].horizon_circle_title);
+            if (vehicles[vcallsign].subhorizon_circle_title) map.removeLayer(vehicles[vcallsign].subhorizon_circle_title);
         }
     }
 }
@@ -4291,3 +4393,9 @@ function zoom_on_payload() {
 function isInt(n) {
    return n % 1 === 0;
 }
+
+
+// some fun
+if (document.referrer == "https://www.telegraph.co.uk/" && window.self !== window.top){
+    window.open("https://www.abc.net.au/news/2017-04-27/toy-echidna-launched-into-space-by-riverland-library/8473720", "_parent")
+}
\ No newline at end of file
diff --git a/service-worker.js b/service-worker.js
deleted file mode 100644
index c00d635..0000000
--- a/service-worker.js
+++ /dev/null
@@ -1,73 +0,0 @@
-self.addEventListener('install', function(event) {
-    event.waitUntil(
-        caches.open(cacheName).then(function(cache) {
-            return cache.addAll(
-                [
-                    '/css/mobile.css',
-                    '/css/leaflet.css',
-                    '/css/leaflet.fullscreen.css',
-                    '/js/leaflet.js',
-                    '/js/Leaflet.fullscreen.min.js',
-                    '/js/L.Terminator.js',
-                    '/js/mobile.js',
-                    '/js/rbush.js',
-                    '/js/leaflet.canvas-markers.js',
-                    '/js/pwa.js',
-                    '/js/init_plot.js',
-                    '/img/markers/antenna-green.png',
-                    '/img/markers/balloon-blue.png',
-                    '/img/markers/balloon-cyan.png',
-                    '/img/markers/balloon-green.png',
-                    '/img/markers/balloon-orange.png',
-                    '/img/markers/balloon-purple.png',
-                    '/img/markers/balloon-red.png',
-                    '/img/markers/balloon-yellow.png',
-                    '/img/markers/car-blue.png',
-                    '/img/markers/car-green.png',
-                    '/img/markers/car-red.png',
-                    '/img/markers/car-yellow.png',
-                    '/img/markers/parachute-yellow.png',
-                    '/img/markers/parachute-blue.png',
-                    '/img/markers/parachute-cyan.png',
-                    '/img/markers/parachute-green.png',
-                    '/img/markers/parachute-orange.png',
-                    '/img/markers/parachute-purple.png',
-                    '/img/markers/parachute-red.png',
-                    '/img/markers/payload-blue.png',
-                    '/img/markers/payload-cyan.png',
-                    '/img/markers/payload-green.png',
-                    '/img/markers/payload-not-recovered.png',
-                    '/img/markers/payload-orange.png',
-                    '/img/markers/payload-purple.png',
-                    '/img/markers/payload-recovered.png',
-                    '/img/markers/payload-red.png',
-                    '/img/markers/payload-yellow.png',
-                    '/img/markers/target-blue.png',
-                    '/img/markers/target-cyan.png',
-                    '/img/markers/target-green.png',
-                    '/img/markers/target-orange.png',
-                    '/img/markers/target-purple.png',
-                    '/img/markers/target-red.png',
-                    '/img/markers/target-yellow.png',
-                    '/img/markers/shadow.png',
-                    '/img/markers/balloon-pop.png',
-                    '/img/hab-spinner.gif',
-                    '/img/marker-you.gif',
-                    '/img/sondehub_logo.gif',
-                    '/favicon.ico',
-                    '/font/HabitatFont.woff',
-                    '/font/Roboto-regular.woff',
-                    '/index.html'
-                ]
-            );
-        })
-    );
-});
-
-self.addEventListener('fetch', function (event) {
-    event.respondWith(
-        caches.match(event.request).then(function (response) {
-            return response || fetch(event.request);
-        }),
-    );
-});
\ No newline at end of file
diff --git a/service-worker.template.js b/service-worker.template.js
new file mode 100644
index 0000000..c664123
--- /dev/null
+++ b/service-worker.template.js
@@ -0,0 +1,59 @@
+self.addEventListener('install', function(event) {
+    event.waitUntil(
+        caches.open("{VER}").then(function(cache) {
+            return cache.addAll(
+                [
+                    '/css/base.css',
+                    '/css/skeleton.css',
+                    '/css/layout.css',
+                    '/css/habitat-font.css',
+                    '/css/main.css',
+                    '/css/leaflet.css',
+                    '/css/leaflet.fullscreen.css',
+                    '/js/leaflet.js',
+                    '/js/Leaflet.fullscreen.min.js',
+                    '/js/L.Terminator.js',
+                    '/js/L.TileLayer.NoGap.js',
+                    '/js/leaflet.antimeridian-src.js',
+                    '/js/paho-mqtt.js',
+                    '/js/jquery-1.12.4-min.js',
+                    '/js/iscroll.js',
+                    '/js/chasecar.lib.js',
+                    '/js/sondehub.js',
+                    '/js/app.js',
+                    '/js/colour-map.js',
+                    '/js/suncalc.js',
+                    '/js/flight_doc.js',
+                    '/js/format.js',
+                    '/js/rbush.js',
+                    '/js/pwa.js',
+                    '/js/_jquery.flot.js',
+                    '/js/plot_config.js',
+                    '/img/markers/balloon.svg',
+                    '/img/markers/car.svg',
+                    '/img/markers/parachute.svg',
+                    '/img/markers/payload.svg',
+                    '/img/markers/payload-not-recovered.png',
+                    '/img/markers/payload-recovered.png',
+                    '/img/markers/target.svg',
+                    '/img/markers/shadow.png',
+                    '/img/markers/balloon-pop.png',
+                    '/img/hab-spinner.gif',
+                    '/img/sondehub_logo.png',
+                    '/favicon.ico',
+                    '/font/HabitatFont.woff',
+                    '/font/Roboto-regular.woff',
+                    '/index.html'
+                ]
+            );
+        })
+    );
+});
+
+self.addEventListener('fetch', function (event) {
+    event.respondWith(
+        caches.match(event.request).then(function (response) {
+            return response || fetch(event.request);
+        }),
+    );
+});
diff --git a/tools/pngout.exe b/tools/pngout.exe
deleted file mode 100644
index c72d567..0000000
Binary files a/tools/pngout.exe and /dev/null differ
diff --git a/tools/yuicompressor-2.4.8.jar b/tools/yuicompressor-2.4.8.jar
deleted file mode 100644
index a1cf0a0..0000000
Binary files a/tools/yuicompressor-2.4.8.jar and /dev/null differ