From 1d4d0a9a74943c8affd528e961f3a35ece3cf7a5 Mon Sep 17 00:00:00 2001 From: atjn Date: Sun, 17 Apr 2022 19:32:20 +0200 Subject: [PATCH] Modernize live map --- docroot/last/config.js | 10 - docroot/last/config.js.sample | 9 - docroot/last/index.html | 89 ++------- docroot/last/last.html | 106 +++++++---- docroot/last/manifest.json | 20 +- docroot/last/map_google.js | 295 ++++++++++------------------- docroot/last/map_leaflet.js | 82 ++------ docroot/last/recorder-logo-192.png | Bin 7098 -> 0 bytes docroot/last/websock.js | 115 +++++------ 9 files changed, 266 insertions(+), 460 deletions(-) delete mode 100644 docroot/last/config.js delete mode 100644 docroot/last/config.js.sample delete mode 100644 docroot/last/recorder-logo-192.png diff --git a/docroot/last/config.js b/docroot/last/config.js deleted file mode 100644 index d93411a..0000000 --- a/docroot/last/config.js +++ /dev/null @@ -1,10 +0,0 @@ - -/* - * Optionally rename the topic in the location popup on the map - */ - -var renames = { - 'jjolie/phone' : 'Jane Jolie', - 'john/android' : "John Smith", - -}; diff --git a/docroot/last/config.js.sample b/docroot/last/config.js.sample deleted file mode 100644 index 3cb9500..0000000 --- a/docroot/last/config.js.sample +++ /dev/null @@ -1,9 +0,0 @@ - -/* - * Optionally rename the topic in the location popup on the map - */ - -var renames = { - 'jjolie/phone' : 'Jane Jolie', - 'john/android' : "John Smith", -}; diff --git a/docroot/last/index.html b/docroot/last/index.html index 928ddfa..d7b32f6 100644 --- a/docroot/last/index.html +++ b/docroot/last/index.html @@ -1,90 +1,35 @@ - + + Recorder Map - - - + - - - - - - - - - + +
-
-
+
+
diff --git a/docroot/last/last.html b/docroot/last/last.html index da0c75b..20fd6db 100644 --- a/docroot/last/last.html +++ b/docroot/last/last.html @@ -1,47 +1,71 @@ - -WebSocket Test - - -

OwnTracks Recorder WebSocket Test

-
+ //let num_messages = 0; + + // location.host localhost:8080 localhost:8083 + // location.pathname /otr/ws.html /ws.html + + const url = getApiUrl("last", { useWebsocket: true }); + + displayMessage(`CONNECTING TO: ${url.href}`); + + const websocket = new WebSocket(url); + websocket.addEventListener("open", () => { + displayMessage('CONNECTED'); + const msg = 'LAST'; + displayMessage('SENT: ' + msg); + websocket.send(msg); + }); + websocket.addEventListener("close", () => { + displayMessage('DISCONNECTED'); + }); + websocket.addEventListener("message", event => { + if (!event.data) { + displayMessage('PING... '); + } else { + displayMessage(escapeHTML `RESPONSE: ${ event.data } `); + debug("RESPONSE:", event.data); + //num_messages++; + } + /* + if (num_messages > 3) { + websocket.send('exit'); + } */ + }); + websocket.addEventListener("error", event => { + console.error(event); + displayMessage(escapeHTML `ERROR: ${ event.data } `); + }); + + + + + +

OwnTracks Recorder WebSocket Test

+ +
+ diff --git a/docroot/last/manifest.json b/docroot/last/manifest.json index f4a3933..f91a4d2 100644 --- a/docroot/last/manifest.json +++ b/docroot/last/manifest.json @@ -1,14 +1,14 @@ { - "name" : "Recorder map", - "icons" : [ + "name": "Recorder map", + "icons": [ { - "src" : "recorder-logo-192.png", - "sizes" : "192x192", - "type" : "image/png", - "density" : "4.0" - } + "src": "../static/recorder.png", + "sizes": "192x192", + "type": "image/png", + "density": "4.0" + } ], - "start_url" : "index.html", - "display" : "standalone", - "orientation" : "portrait" + "start_url": "index.html", + "display": "standalone", + "orientation": "portrait" } diff --git a/docroot/last/map_google.js b/docroot/last/map_google.js index 3b56d1c..00a5ad9 100644 --- a/docroot/last/map_google.js +++ b/docroot/last/map_google.js @@ -1,221 +1,134 @@ -var map; -var do_fit = false; -var markers = {}; -var livemarkers = true; -function initialize_googlemaps() { - var lat = 50.098280; - var lon = 10.187189; - var params = getSearchParameters(); +import { ws_connect } from "./websock.js"; - var center = new google.maps.LatLng(lat,lon); +import { debug } from "../utils/debug.js"; +import { generatePopupHTML } from "../utils/map.js"; +import { openSingularMarker, fitBounds, markerStyle, clog } from "../utils/map_google.js"; +import { getCosmeticLocation, getCosmeticName } from "../utils/misc.js"; - do_fit = (params.fit) ? true : false; +let map; +let do_fit = false; +const markers = {}; +const livemarkers = true; - mapOptions = { - center: center, - zoom: 3, // 9, - maxZoom: 18, // don't overzoom (should this be configurable?) - mapTypeId: google.maps.MapTypeId.ROADMAP, - scrollwheel: false, - disableDefaultUI: false, - panControl: false, - scaleControl: false, - streetViewControl: true, - overviewMapControl: true, - }; +export function initialize(ws_url) { - map = new google.maps.Map(document.getElementById("map-canvas"), mapOptions); + const params = new URL(window.location).searchParams; + do_fit = Boolean(params.get("fit")); - /* Create the DIV to hold the control and call constructor */ - var buttonControlDiv = document.createElement('div'); - var buttonControl = new ButtonControl(buttonControlDiv, map); + const mapOptions = { + center: new google.maps.LatLng(50.098280, 10.187189), + zoom: 3, // 9, + maxZoom: 18, // don't overzoom (should this be configurable?) + mapTypeId: google.maps.MapTypeId.ROADMAP, + scrollwheel: false, + disableDefaultUI: false, + panControl: false, + scaleControl: false, + streetViewControl: true, + overviewMapControl: true, + }; - buttonControlDiv.index = 1; - map.controls[google.maps.ControlPosition.BOTTOM_LEFT].push(buttonControlDiv); + map = new google.maps.Map(document.getElementById("map-canvas"), mapOptions); - ws_go(); // Connect to websocket and start listening + /* Create the DIV to hold the control and call constructor */ + const buttonControlDiv = document.createElement('div'); + const buttonControl = new ButtonControl(buttonControlDiv); + + buttonControlDiv.index = 1; + map.controls[google.maps.ControlPosition.BOTTOM_LEFT].push(buttonControlDiv); + + ws_connect(ws_url, map_marker); // Connect to websocket and start listening } -function ButtonControl(controlDiv, map) { +function ButtonControl(controlDiv) { - // Set CSS for the control border. - var controlUI = document.createElement('div'); - controlUI.style.backgroundColor = '#fff'; - controlUI.style.border = '2px solid #fff'; - controlUI.style.borderRadius = '3px'; - controlUI.style.boxShadow = '0 2px 6px rgba(0,0,0,.3)'; - controlUI.style.cursor = 'pointer'; - controlUI.style.marginBottom = '22px'; - controlUI.style.textAlign = 'center'; - controlUI.title = 'Click to toggle Autozoom (zoom to fit)'; - controlDiv.appendChild(controlUI); + // Set CSS for the control border. + const controlUI = document.createElement('div'); + controlUI.style.backgroundColor = '#fff'; + controlUI.style.border = '2px solid #fff'; + controlUI.style.borderRadius = '3px'; + controlUI.style.boxShadow = '0 2px 6px rgba(0,0,0,.3)'; + controlUI.style.cursor = 'pointer'; + controlUI.style.marginBottom = '22px'; + controlUI.style.textAlign = 'center'; + controlUI.title = 'Click to toggle Autozoom (zoom to fit)'; + controlDiv.appendChild(controlUI); - // Set CSS for the control interior. - var controlText = document.createElement('div'); - controlText.style.color = (do_fit) ? 'rgb(0,153,0)' : 'rgb(25,25,25)'; - controlText.style.fontFamily = 'Roboto,Arial,sans-serif'; - controlText.style.fontSize = '16px'; - controlText.style.lineHeight = '38px'; - controlText.style.paddingLeft = '4px'; - controlText.style.paddingRight = '4px'; - controlText.innerHTML = 'Autozoom'; - controlUI.appendChild(controlText); + // Set CSS for the control interior. + const controlText = document.createElement('div'); + controlText.style.color = (do_fit) ? 'rgb(0,153,0)' : 'rgb(25,25,25)'; + controlText.style.fontFamily = 'Roboto,Arial,sans-serif'; + controlText.style.fontSize = '16px'; + controlText.style.lineHeight = '38px'; + controlText.style.paddingLeft = '4px'; + controlText.style.paddingRight = '4px'; + controlText.innerHTML = 'Autozoom'; + controlUI.appendChild(controlText); - // Setup the click event listener. - controlUI.addEventListener('click', function() { - do_fit = !do_fit; - controlText.style.color = (do_fit) ? 'rgb(0,153,0)' : 'rgb(25,25,25)'; - if (do_fit) { - fitbounds(); - } - }); -} - -function clog(upd, id, s) { - var ident = id || 'unknown'; - - console.log(upd + ": " + ident + " " + s); -} - -/* http://stackoverflow.com/questions/5448545/ */ -function getSearchParameters() { - var prmstr = window.location.search.substr(1); - return prmstr != null && prmstr != "" ? transformToAssocArray(prmstr) : {}; -} - -function transformToAssocArray( prmstr ) { - var params = {}; - var prmarr = prmstr.split("&"); - for ( var i = 0; i < prmarr.length; i++) { - var tmparr = prmarr[i].split("="); - params[tmparr[0]] = tmparr[1]; + // Setup the click event listener. + controlUI.addEventListener('click', function() { + do_fit = !do_fit; + controlText.style.color = (do_fit) ? 'rgb(0,153,0)' : 'rgb(25,25,25)'; + if (do_fit) { + fitBounds(map, markers); } - return params; -} - - -/* - * Close all the infowindows in the `markers' object, and then open the - * infowindow in the specified marker. - */ - -function refreshmarkers(m) { - for (var k in markers) { - markers[k]['infowindow'].close(); - } - m['infowindow'].open(map, m); -} - -function fitbounds() { - var bounds = new google.maps.LatLngBounds(); - for (var k in markers) { - bounds.extend(markers[k].getPosition()); - } - map.setCenter(bounds.getCenter()); /* Center to geometric center of all markers */ - map.fitBounds(bounds); + }); } /* * `loc' is a location object obtained via Websockets from the recorder */ +function map_marker(loc) { + debug("Format marker:", loc); -function map_marker(loc) -{ - var id = loc.topic.replace(/\//g, '-'); - var htmldesc; - var shortdesc; - var s = loc.topic.split('/'); - var username = (s[0]) ? s[1] : s[2]; /* cater for leading / in topic */ - var device = (s[0]) ? s[2] : s[3]; /* cater for leading / in topic */ + const id = loc.topic.replaceAll("/", '-'); - console.log(loc); + const title = `${ getCosmeticName(loc) } ${ getCosmeticLocation(loc) }`; + const htmldesc = generatePopupHTML(loc); - var dt = moment.utc(loc.tst * 1000).local(); + const LatLng = new google.maps.LatLng(loc.lat, loc.lon); + if (markers.hasOwnProperty(id)) { + clog("UPD", id, loc); + const m = markers[id]; + + m.setPosition(LatLng); + m.setTitle(title); - var userdev = username + "/" + device; - userdev = renames[userdev] ? renames[userdev] : userdev; - userdev = loc.name ? loc.name : userdev; + /* Grab the InfoWindow of this marker and change content */ + m.infowindow.setContent(htmldesc); + if (livemarkers) { + openSingularMarker(map, markers, m); + } + } else { + clog("NEW", id, loc); - var data = { - userdev: userdev, - ghash: loc.ghash ? loc.ghash : 'unknown', - addr: loc.addr, - lat: loc.lat, - lon: loc.lon, - fulldate: dt.format("DD MMM YYYY HH:mm:ss"), - facedata: loc.face, - vel: loc.vel, - cog: loc.cog, - }; + const m = new google.maps.Marker({ + position: LatLng, + map, + title: title, + // icon: "marker.php?tid=" + id, + // icon: "red-marker.png" + icon: markerStyle, + }); - if (loc.addr) { - htmldesc = "{{userdev}}
{{addr}}
{{ghash}} ({{lat}},{{lon}}) v={{vel}}, c={{cog}} {{fulldate}}"; - shortdesc = "{{{userdev}}} {{addr}}"; - } else { - htmldesc = "{{userdev}}
{{lat}}, {{lon}}
{{ghash}} ({{lat}},{{lon}}) v={{vel}}, c={{cog}} {{fulldate}}"; - shortdesc = "{{{userdev}}} {{lat}},{{lon}}"; - } + /* Create a new InfoWindow for this marker, and add listener */ + m.infowindow = new google.maps.InfoWindow({ + content: htmldesc, + }); + google.maps.event.addListener(m, "click", function() { + this.infowindow.open(map, this); + }); + if (livemarkers) { + openSingularMarker(map, markers, m); + } - if (loc.face) { - htmldesc = htmldesc + "
"; - } else { - htmldesc = htmldesc + "
"; - } + markers[id] = m; + } - loc.description = Mustache.render(shortdesc, data); - loc.htmldesc = Mustache.render(htmldesc, data); - - if (markers.hasOwnProperty(id)) { - clog("UPD", id, JSON.stringify(loc)); - m = markers[id]; - var LatLng = new google.maps.LatLng(loc.lat, loc.lon); - m.setPosition(LatLng); - m.setTitle(loc.description); - - /* Grab the InfoWindow of this marker and change content */ - m['infowindow'].setContent(loc.htmldesc); - if (livemarkers) { - refreshmarkers(m); - } - } else { - clog("NEW", id, JSON.stringify(loc)); - var circle ={ - path: google.maps.SymbolPath.CIRCLE, - fillColor: '#ff0000', - fillOpacity: .9, - scale: 5.5, - strokeColor: 'white', - strokeWeight: 2 - }; - - var LatLng = new google.maps.LatLng(loc.lat, loc.lon); - var m = new google.maps.Marker({ - position: LatLng, - map: map, - title: loc.description, - // icon: "marker.php?tid=" + id, - // icon: "red-marker.png" - icon: circle - }); - - /* Create a new InfoWindow for this marker, and add listener */ - m['infowindow'] = new google.maps.InfoWindow({ - content: loc.htmldesc - }); - google.maps.event.addListener(m, "click", function(e) { - this['infowindow'].open(map, this); - }); - if (livemarkers) { - refreshmarkers(m); - } - - markers[id] = m; - } - - if (do_fit) { - fitbounds(); - } + if (do_fit) { + fitBounds(map, markers); + } } // google.maps.event.addDomListener(window, 'load', initialize); diff --git a/docroot/last/map_leaflet.js b/docroot/last/map_leaflet.js index ce18061..da351f4 100644 --- a/docroot/last/map_leaflet.js +++ b/docroot/last/map_leaflet.js @@ -1,85 +1,45 @@ -function initialize_leaflet() { - var markerLayer; - var markers={}; - var map = L.map('map-canvas').setView([0.0, 0.0], 1); +import { ws_connect } from "./websock.js"; + +import { debug } from "../utils/debug.js"; +import { generatePopupHTML } from "../utils/map.js"; +import { markerStyle } from "../utils/map_leaflet.js"; + +export function initialize(ws_url) { + + let markerLayer; + const markers = {}; + const map = L.map('map-canvas').setView([0.0, 0.0], 1); L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { - attribution: '© OpenStreetMap contributors' + attribution: '© OpenStreetMap contributors', }).addTo(map); - function osm_map_marker(loc) - { - console.log("Updating marker"); - var id = loc.topic.replace(/\//g, '-'); + function osm_map_marker(loc) { + debug("Updating marker"); + const id = loc.topic.replaceAll("/", '-'); if (!markers.hasOwnProperty(id)) { - markers[id] = L.marker([loc.lat, loc.lon]); + markers[id] = L.circleMarker([loc.lat, loc.lon], markerStyle); markerLayer.addLayer(markers[id]); if (loc.face) { - markers[id]._face=loc.face; + markers[id]._face = loc.face; } } markers[id].setLatLng({lat: loc.lat, lng: loc.lon}); - loc.face=markers[id]._face; - var description = formatPopup(loc); + loc.face = markers[id]._face; + const description = generatePopupHTML(loc); - markers[id].bindPopup(description.htmldesc).openPopup() + markers[id].bindPopup(description).openPopup(); map.fitBounds(markerLayer.getBounds()); } - markerLayer = new L.FeatureGroup(); map.addLayer(markerLayer); - ws_go(osm_map_marker); // Connect to websocket and start listening + ws_connect(ws_url, osm_map_marker); // Connect to websocket and start listening } - -function formatPopup(loc) { - var htmldesc=""; - var shortdesc=""; - var s = loc.topic.split('/'); - var username = (s[0]) ? s[1] : s[2]; /* cater for leading / in topic */ - var device = (s[0]) ? s[2] : s[3]; /* cater for leading / in topic */ - - var dt = moment.utc(loc.tst * 1000).local(); - - var userdev = username + "/" + device; - userdev = renames[userdev] ? renames[userdev] : userdev; - userdev = loc.name ? loc.name : userdev; - - var data = { - userdev: userdev, - ghash: loc.ghash ? loc.ghash : 'unknown', - addr: loc.addr, - lat: loc.lat, - lon: loc.lon, - fulldate: dt.format("DD MMM YYYY HH:mm:ss"), - facedata: loc.face, - vel: loc.vel, - cog: loc.cog, - }; - - - if (loc.face) { - htmldesc = htmldesc + "
"; - } - - if (loc.addr) { - htmldesc = htmldesc + "{{userdev}}
{{addr}}
{{ghash}} ({{lat}},{{lon}}) v={{vel}}, c={{cog}} {{fulldate}}"; - shortdesc = "{{{userdev}}} {{addr}}"; - } else { - htmldesc = htmldesc + "{{userdev}}
{{lat}}, {{lon}}
{{ghash}} ({{lat}},{{lon}}) v={{vel}}, c={{cog}} {{fulldate}}"; - shortdesc = shortdesc + "{{{userdev}}} {{lat}},{{lon}}"; - } - - - var result = {} - result.short = Mustache.render(shortdesc, data); - result.htmldesc = Mustache.render(htmldesc, data); - return result; -} diff --git a/docroot/last/recorder-logo-192.png b/docroot/last/recorder-logo-192.png deleted file mode 100644 index 6ce501a73976f8db95792ea7df7ba77ae8c87c6d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7098 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... '); - } else { - // out('RESPONSE: ' + ev.data + ' '); - try { - var loc = JSON.parse(ev.data); + ws.onmessage = function(event) { + if (!event.data) { + // out('PING... '); + debug("PING... "); + } else { + // out('RESPONSE: ' + ev.data + ' '); + try { + const loc = JSON.parse(event.data); + debug("RESPONSE:", loc); - if (loc['_label']) { - document.getElementById('maplabel').textContent = loc['_label']; - } + if (loc._label) { + document.getElementById('maplabel').textContent = loc._label; + } - if (loc['_type'] == 'location') { - ws_callback(loc); - } - } catch (x) { - ; - } - } - }; + if (loc._type === 'location') { + callback(loc); + } + } catch (error) { + debug("Could not parse:", event.data, error); + } + } + }; - ws.onerror = function(ev) { - // out('ERROR: ' + ev.data); - }; + ws.onerror = function(event) { + // out('ERROR: ' + ev.data); + console.error("ERROR:", event.data); + }; } - -function ws_go(callback) { - // var url = 'ws://' + location.host + '/ws/last'; - // console.log(JSON.stringify(location)); - - if (typeof callback != 'undefined') { - ws_callback=callback; - } - - var url = ("https:" == document.location.protocol ? "wss://" : "ws://") + location.host + "/"; - var parts = location.pathname.split('/'); - for (var i = 1; i < parts.length - 2; i++) { - url = url + parts[i] + "/"; - } - url = url + "ws/last"; - - console.log("Websocket URI: " + url); - - - ws_url = url; - ws_connect(); - -};