mirror of
https://github.com/owntracks/recorder.git
synced 2026-08-27 16:57:21 +00:00
Modernize live map
This commit is contained in:
@@ -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",
|
||||
|
||||
};
|
||||
@@ -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",
|
||||
};
|
||||
+17
-72
@@ -1,90 +1,35 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<html lang="en-US">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Recorder Map</title>
|
||||
<meta name="viewport" content="width=device-width, height=device-height, user-scalable=no, initial-scale=1.0" />
|
||||
|
||||
<meta name="mobile-web-app-capable" content="yes">
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
<link rel="manifest" href="manifest.json">
|
||||
<link rel="icon" sizes="192x192" href="../static/recorder.png" />
|
||||
<link rel="apple-touch-icon" href="../static/recorder.png" />
|
||||
<style type="text/css">
|
||||
html { height: 100% }
|
||||
body { height: 100%; margin: 0px; padding: 0px }
|
||||
body { font-size: 80%; margin: 0; padding: 0; }
|
||||
|
||||
td { border-bottom: 1px solid; border-right: 1px dotted;}
|
||||
|
||||
#map-canvas { height: 100% }
|
||||
#wrapper { position: relative; height: 100%; }
|
||||
#maplabel { position: absolute; top: 10px; left: 120px; z-index: 99;
|
||||
background: white;
|
||||
font-size: 1.2em;
|
||||
padding: 4px;
|
||||
border: 2px solid gray;
|
||||
}
|
||||
.extrainfo { font-size: 80%; }
|
||||
.latlon { color: gray; }
|
||||
.block1 { float: left; }
|
||||
.block2 { border 1px solid; background-color: white; width: 40px; height: 40px; float: right; margin-left: 20px; margin-right: 0px; padding-right: 0; }
|
||||
.img-circle { border-radius: 50%; border: 1px solid #CACACA; }
|
||||
.latlon { color: gray; }
|
||||
|
||||
<link rel="icon" sizes="192x192" href="../static/recorder.png">
|
||||
<link rel="apple-touch-icon" href="../static/recorder.png">
|
||||
<style>
|
||||
body { font-size: 80%; }
|
||||
td { border-bottom: 1px solid; border-right: 1px dotted; }
|
||||
</style>
|
||||
<link rel="stylesheet" href="../utils/map.css">
|
||||
|
||||
<script
|
||||
src="https://code.jquery.com/jquery-3.1.1.min.js"
|
||||
integrity="sha256-hVVnYaiADRTO2PzUGmuLJr8BLUSjGIZsDYGmIJLv2b8="
|
||||
crossorigin="anonymous">
|
||||
</script>
|
||||
<script src="../static/apikey.js"></script>
|
||||
<script src="map_google.js"></script>
|
||||
<script src="map_leaflet.js"></script>
|
||||
<script src="websock.js"></script>
|
||||
<script src="config.js"></script>
|
||||
<script src="../static/js/moment.min.js"></script>
|
||||
<script src="../static/js/mustache.js"></script>
|
||||
<script>
|
||||
function loadMapsAPI() {
|
||||
var script = document.createElement('script');
|
||||
script.type = 'text/javascript';
|
||||
if (typeof apiKey != 'undefined' && apiKey != "" ) {
|
||||
script.src = 'https://maps.googleapis.com/maps/api/js?v=3' +
|
||||
'&key=' + apiKey +'&callback=initialize_googlemaps';
|
||||
} else {
|
||||
$("head").append("<link rel='stylesheet' href='../static/leaflet/leaflet.css' type='text/css' />");
|
||||
|
||||
// Dynamic script loading from http://stackoverflow.com/a/8578840
|
||||
(function(d, s, id){
|
||||
var js, fjs = d.getElementsByTagName(s)[0];
|
||||
if (d.getElementById(id)){ return; }
|
||||
js = d.createElement(s); js.id = id;
|
||||
js.onload = function(){
|
||||
initialize_leaflet();
|
||||
};
|
||||
js.src = "../static/leaflet/leaflet.js";
|
||||
fjs.parentNode.insertBefore(js, fjs);
|
||||
}(document, 'script', 'leaflet'));
|
||||
}
|
||||
|
||||
document.body.appendChild(script);
|
||||
|
||||
|
||||
}
|
||||
|
||||
document.addEventListener("DOMContentLoaded", function(event) {
|
||||
loadMapsAPI();
|
||||
});
|
||||
|
||||
</script>
|
||||
<script src="../static/apikey.js"></script>
|
||||
<script type="module">
|
||||
import { getApiUrl } from "../utils/network.js";
|
||||
import { loadMapSolution } from "../utils/map.js";
|
||||
|
||||
const ws_url = getApiUrl("last", { useWebsocket: true });
|
||||
loadMapSolution(ws_url);
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="output"></div>
|
||||
<div id="wrapper">
|
||||
<div id="map-canvas"></div>
|
||||
<div id="maplabel"></div>
|
||||
<div id="map-canvas"></div>
|
||||
<div id="maplabel"></div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
+65
-41
@@ -1,47 +1,71 @@
|
||||
<!DOCTYPE html>
|
||||
<meta charset="utf-8" />
|
||||
<title>WebSocket Test</title>
|
||||
<script language="javascript" type="text/javascript">
|
||||
<html lang="en-US">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>WebSocket Test</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="mobile-web-app-capable" content="yes">
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
<link rel="icon" sizes="192x192" href="static/recorder.png">
|
||||
<link rel="apple-touch-icon" href="static/recorder.png">
|
||||
|
||||
<script type="module">
|
||||
|
||||
var out = function(message) {
|
||||
var div = document.createElement('div');
|
||||
div.innerHTML = message;
|
||||
document.getElementById('output').appendChild(div);
|
||||
};
|
||||
import { debug } from "../utils/debug.js";
|
||||
|
||||
import { getApiUrl } from "../utils/network.js";
|
||||
import { escapeHTML } from "../utils/misc.js";
|
||||
|
||||
window.onload = function() {
|
||||
var url = 'ws://' + location.host + '/ws/last';
|
||||
var num_messages = 0;
|
||||
function displayMessage(message) {
|
||||
const div = document.createElement('div');
|
||||
div.innerHTML = message;
|
||||
document.getElementById('output').appendChild(div);
|
||||
};
|
||||
|
||||
websocket = new WebSocket(url);
|
||||
websocket.onopen = function(ev) {
|
||||
out('CONNECTED');
|
||||
var msg = 'LAST';
|
||||
out('SENT: ' + msg);
|
||||
websocket.send(msg);
|
||||
};
|
||||
websocket.onclose = function(ev) {
|
||||
out('DISCONNECTED');
|
||||
};
|
||||
websocket.onmessage = function(ev) {
|
||||
if (!ev.data) {
|
||||
out('<span style="color: blue;">PING... </span>');
|
||||
} else {
|
||||
out('<span style="color: blue;">RESPONSE: ' + ev.data + ' </span>');
|
||||
num_messages++;
|
||||
}
|
||||
/*
|
||||
if (num_messages > 3) {
|
||||
websocket.send('exit');
|
||||
} */
|
||||
};
|
||||
websocket.onerror = function(ev) {
|
||||
out('<span style="color: red; ">ERROR: </span> ' + ev.data);
|
||||
};
|
||||
};
|
||||
</script>
|
||||
<style> div {font: small Verdana; } </style>
|
||||
<h2>OwnTracks Recorder WebSocket Test</h2>
|
||||
|
||||
<div id="output"></div>
|
||||
//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('<span style="color: blue;">PING... </span>');
|
||||
} else {
|
||||
displayMessage(escapeHTML `<span style="color: blue;">RESPONSE: ${ event.data } </span>`);
|
||||
debug("RESPONSE:", event.data);
|
||||
//num_messages++;
|
||||
}
|
||||
/*
|
||||
if (num_messages > 3) {
|
||||
websocket.send('exit');
|
||||
} */
|
||||
});
|
||||
websocket.addEventListener("error", event => {
|
||||
console.error(event);
|
||||
displayMessage(escapeHTML `<span style="color: red;">ERROR: ${ event.data } </span>`);
|
||||
});
|
||||
|
||||
</script>
|
||||
<style> div {font: small Verdana; } </style>
|
||||
</head>
|
||||
<body>
|
||||
<h2>OwnTracks Recorder WebSocket Test</h2>
|
||||
|
||||
<div id="output"></div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
+10
-10
@@ -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"
|
||||
}
|
||||
|
||||
+104
-191
@@ -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 = "<b>{{userdev}}</b><br/>{{addr}}<br/><span class='extrainfo'>{{ghash}} <span class='latlon'>({{lat}},{{lon}}) v={{vel}}, c={{cog}}</span> {{fulldate}}</span>";
|
||||
shortdesc = "{{{userdev}}} {{addr}}";
|
||||
} else {
|
||||
htmldesc = "<b>{{userdev}}</b><br/>{{lat}}, {{lon}}<br/><span class='extrainfo'>{{ghash}} <span class='latlon'>({{lat}},{{lon}}) v={{vel}}, c={{cog}}</span> {{fulldate}}</span>";
|
||||
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 + "</div><div class='block2' id='avatar'><img class='img-circle' src='data:image/png;base64,{{ facedata }}' height='35' width='35' /></div>";
|
||||
} else {
|
||||
htmldesc = htmldesc + "</div><div class='block2' id='avatar'></div>";
|
||||
}
|
||||
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);
|
||||
|
||||
+21
-61
@@ -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: '© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
|
||||
attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> 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 + "<div style='float:right;' id='avatar'><img class='img-circle' src='data:image/png;base64,{{ facedata }}' height='35' width='35' /></div>";
|
||||
}
|
||||
|
||||
if (loc.addr) {
|
||||
htmldesc = htmldesc + "<b>{{userdev}}</b><br/>{{addr}}<br/><span class='extrainfo'>{{ghash}} <span class='latlon'>({{lat}},{{lon}}) v={{vel}}, c={{cog}}</span> {{fulldate}}</span>";
|
||||
shortdesc = "{{{userdev}}} {{addr}}";
|
||||
} else {
|
||||
htmldesc = htmldesc + "<b>{{userdev}}</b><br/>{{lat}}, {{lon}}<br/><span class='extrainfo'>{{ghash}} <span class='latlon'>({{lat}},{{lon}}) v={{vel}}, c={{cog}}</span> {{fulldate}}</span>";
|
||||
shortdesc = shortdesc + "{{{userdev}}} {{lat}},{{lon}}";
|
||||
}
|
||||
|
||||
|
||||
var result = {}
|
||||
result.short = Mustache.render(shortdesc, data);
|
||||
result.htmldesc = Mustache.render(htmldesc, data);
|
||||
return result;
|
||||
}
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 6.9 KiB |
+49
-66
@@ -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('<span style="color: blue;">PING... </span>');
|
||||
} else {
|
||||
// out('<span style="color: blue;">RESPONSE: ' + ev.data + ' </span>');
|
||||
try {
|
||||
var loc = JSON.parse(ev.data);
|
||||
ws.onmessage = function(event) {
|
||||
if (!event.data) {
|
||||
// out('<span style="color: blue;">PING... </span>');
|
||||
debug("PING... ");
|
||||
} else {
|
||||
// out('<span style="color: blue;">RESPONSE: ' + ev.data + ' </span>');
|
||||
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('<span style="color: red; ">ERROR: </span> ' + ev.data);
|
||||
};
|
||||
ws.onerror = function(event) {
|
||||
// out('<span style="color: red; ">ERROR: </span> ' + 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();
|
||||
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user