microReticulumTbeam/tools/livetrack/fieldtest_map.html

157 lines
4.6 KiB
HTML
Raw Normal View History

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Fieldtest Positions</title>
<!-- Leaflet (swap to your local staged copies if preferred)
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css">
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script> -->
<link rel="stylesheet" href="https://ryzdesk/lib/leaflet.css">
<script src="https://ryzdesk/lib/leaflet.js"></script>
<style>
html, body { height: 100%; margin: 0; }
#map { height: 100%; width: 100%; }
.legend {
position: absolute; z-index: 1000; background: rgba(255,255,255,0.85);
padding: 8px; margin: 10px; border-radius: 6px; font-family: sans-serif;
font-size: 13px;
}
.node-label {
background: rgba(255,255,255,0.85);
border: 1px solid rgba(0,0,0,0.25);
color: #000;
font-weight: 700;
padding: 1px 6px;
border-radius: 4px;
box-shadow: 0 1px 3px rgba(0,0,0,0.25);
}
</style>
</head>
<body>
<div class="legend">
WS: <span id="ws_state">connecting</span><br>
Last: <span id="last_msg"></span>
</div>
<div id="map"></div>
<script>
// --- Map init (center near your sample points; adjust as desired)
const map = L.map('map').setView([44.93655, -123.02185], 17);
// Basemap: replace with your own tile server if you have one
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 20,
attribution: '&copy; OpenStreetMap contributors'
}).addTo(map);
// Node colors (bright, readable)
const nodeStyle = {
B: { color: '#00e5ff' }, // cyan-ish
C: { color: '#ffea00' }, // yellow
D: { color: '#ff3d00' }, // orange/red
E: { color: '#76ff03' }, // green
};
// One persistent "current" marker per node (bright + labeled)
const currentMarkers = {}; // node -> L.CircleMarker
function addFadingDot(node, lat, lon) {
const style = nodeStyle[node] || { color: '#ffffff' };
// Bright at birth
const m = L.circleMarker([lat, lon], {
radius: 7,
color: style.color,
weight: 2,
fillColor: style.color,
fillOpacity: 1.0,
opacity: 1.0
}).addTo(map);
// Fade steps: 5s -> 2/3, 10s -> 1/3, 15s -> remove
setTimeout(() => {
m.setStyle({ fillOpacity: 0.66, opacity: 0.66 });
}, 5000);
setTimeout(() => {
m.setStyle({ fillOpacity: 0.33, opacity: 0.33 });
}, 10000);
setTimeout(() => {
map.removeLayer(m);
}, 15000);
}
function upsertCurrentMarker(node, lat, lon) {
const style = nodeStyle[node] || { color: '#ffffff' };
if (!currentMarkers[node]) {
const m = L.circleMarker([lat, lon], {
radius: 9,
color: style.color,
weight: 2,
fillColor: style.color,
fillOpacity: 1.0,
opacity: 1.0
}).addTo(map);
// Permanent label next to the current marker
m.bindTooltip(node, {
permanent: true,
direction: 'right',
offset: [10, 0],
className: 'node-label'
});
currentMarkers[node] = m;
} else {
currentMarkers[node].setLatLng([lat, lon]);
// reassert brightness in case you later add effects
currentMarkers[node].setStyle({ fillOpacity: 1.0, opacity: 1.0 });
}
}
function parseMsg(line) {
// "C,44.936454,-123.021923,65.40"
const parts = line.trim().split(',');
if (parts.length < 4) return null;
const node = parts[0];
const lat = parseFloat(parts[1]);
const lon = parseFloat(parts[2]);
const alt = parseFloat(parts[3]); // not used yet, but keep it
if (!node || Number.isNaN(lat) || Number.isNaN(lon)) return null;
return { node, lat, lon, alt };
}
// --- WebSocket
const wsStateEl = document.getElementById('ws_state');
const lastMsgEl = document.getElementById('last_msg');
//const wsUrl = `ws://${location.hostname}:3000/stream`;
//const ws = new WebSocket(wsUrl);
const wsScheme = (location.protocol === 'https:') ? 'wss' : 'ws';
const wsUrl = (wsScheme === 'ws')
? `ws://${location.hostname}:3000/stream`
: `wss://${location.host}/stream`;
const ws = new WebSocket(wsUrl);
//const ws = new WebSocket('ws://localhost:3000/stream'); // temporary test
ws.onopen = () => wsStateEl.textContent = 'open';
ws.onclose = () => wsStateEl.textContent = 'closed';
ws.onerror = () => wsStateEl.textContent = 'error';
ws.onmessage = (ev) => {
const line = ev.data;
lastMsgEl.textContent = line;
const msg = parseMsg(line);
if (!msg) return;
addFadingDot(msg.node, msg.lat, msg.lon);
upsertCurrentMarker(msg.node, msg.lat, msg.lon);
};
</script>
</body>
</html>