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 6ce501a..0000000 Binary files a/docroot/last/recorder-logo-192.png and /dev/null differ diff --git a/docroot/last/websock.js b/docroot/last/websock.js index 71474f7..b178ce8 100644 --- a/docroot/last/websock.js +++ b/docroot/last/websock.js @@ -1,81 +1,64 @@ -var reconnectTimeout = 3000; -var ws_url; -var ws; -var ws_callback = map_marker; + +import { debug } from "../utils/debug.js"; + +const reconnectTimeout = 3000; function setColor(element, color) { - element.style.border = '2px solid ' + color; + element.style.border = `2px solid ${color}`; } -var out = function(message) { - var div = document.createElement('div'); - div.innerHTML = message; - document.getElementById('output').appendChild(div); +/* +function out(message) { + const div = document.createElement('div'); + div.innerHTML = message; + document.getElementById('output').appendChild(div); }; +*/ -function ws_connect() { +export function ws_connect(ws_url, callback) { - console.log("Connecting to websocket at " + ws_url); + debug("Connecting to websocket at:", ws_url); - ws = new WebSocket(ws_url); + const ws = new WebSocket(ws_url); - ws.onopen = function(ev) { - setColor(maplabel, 'green'); - var msg = 'LAST'; - // out('SENT: ' + msg); - ws.send(msg); - }; + ws.onopen = function() { + setColor(maplabel, 'green'); + const msg = 'LAST'; + // out('SENT: ' + msg); + debug("SENT:", msg); + ws.send(msg); + }; - ws.onclose = function(ev) { - setColor(maplabel, 'red'); - setTimeout(ws_connect, reconnectTimeout); - }; + ws.onclose = function() { + setColor(maplabel, 'red'); + setTimeout(ws_connect(ws_url, callback), reconnectTimeout, ws_url, callback); + }; - ws.onmessage = function(ev) { - if (!ev.data) { - // out('PING... '); - } 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(); - -};