to kort
This commit is contained in:
parent
15ae829fd6
commit
c1fb4d67bc
|
|
@ -1,406 +0,0 @@
|
||||||
const COLORS = {
|
|
||||||
"Bil 1": "#ff0000",
|
|
||||||
"Bil 2": "#00c853",
|
|
||||||
"Bil 3": "#2979ff",
|
|
||||||
"Bil 4": "#2979ff",
|
|
||||||
"Bil 5": "#2979ff"
|
|
||||||
};
|
|
||||||
|
|
||||||
const map = L.map("map").setView([55.6761, 12.5683], 13);
|
|
||||||
|
|
||||||
L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", {
|
|
||||||
attribution: "© OpenStreetMap contributors",
|
|
||||||
maxZoom: 19
|
|
||||||
}).addTo(map);
|
|
||||||
|
|
||||||
const statusEl = document.getElementById("status");
|
|
||||||
const alertsEl = document.getElementById("presenceAlerts");
|
|
||||||
const playBtn = document.getElementById("playBtn");
|
|
||||||
const pauseBtn = document.getElementById("pauseBtn");
|
|
||||||
const resetBtn = document.getElementById("resetBtn");
|
|
||||||
|
|
||||||
function carIcon(color) {
|
|
||||||
return L.divIcon({
|
|
||||||
className: "",
|
|
||||||
iconSize: [24, 24],
|
|
||||||
iconAnchor: [12, 12],
|
|
||||||
html: `
|
|
||||||
<div class="car" data-role="car">
|
|
||||||
<svg viewBox="0 0 24 24" aria-hidden="true">
|
|
||||||
<path
|
|
||||||
d="M12 2 L20 22 L12 18 L4 22 Z"
|
|
||||||
fill="${color}"
|
|
||||||
stroke="#ffffff"
|
|
||||||
stroke-width="1.5"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
</div>
|
|
||||||
`
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function setHeading(marker, deg) {
|
|
||||||
const el = marker.getElement();
|
|
||||||
if (!el) return;
|
|
||||||
const car = el.querySelector("[data-role=car]");
|
|
||||||
if (!car) return;
|
|
||||||
car.style.transform = `rotate(${deg}deg)`;
|
|
||||||
}
|
|
||||||
|
|
||||||
function fmtTs(ts) {
|
|
||||||
return `${ts}s`;
|
|
||||||
}
|
|
||||||
|
|
||||||
function popupHtml(name, state) {
|
|
||||||
return `
|
|
||||||
<div style="font:13px/1.4 system-ui,sans-serif;min-width:190px;">
|
|
||||||
<div style="font-weight:600;margin-bottom:6px;">${name}</div>
|
|
||||||
<div><strong>Tid:</strong> ${fmtTs(state.current.ts)}</div>
|
|
||||||
<div><strong>Lat:</strong> ${state.displayLat.toFixed(5)}</div>
|
|
||||||
<div><strong>Lon:</strong> ${state.displayLon.toFixed(5)}</div>
|
|
||||||
<div><strong>Hastighed:</strong> ${state.current.speedMps} m/s</div>
|
|
||||||
<div><strong>Retning:</strong> ${state.displayHeading.toFixed(0)}°</div>
|
|
||||||
<div><strong>Usikkerhed:</strong> ${state.current.uncertaintyM} m</div>
|
|
||||||
<div><strong>På kortet:</strong> ${state.presenceStateLabel || "ja"}</div>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
function smoothstep(t) {
|
|
||||||
t = Math.max(0, Math.min(1, t));
|
|
||||||
return t * t * (3 - 2 * t);
|
|
||||||
}
|
|
||||||
|
|
||||||
function lerp(a, b, t) {
|
|
||||||
return a + (b - a) * t;
|
|
||||||
}
|
|
||||||
|
|
||||||
function lerpAngleDeg(a, b, t) {
|
|
||||||
let d = ((b - a + 540) % 360) - 180;
|
|
||||||
return (a + d * t + 360) % 360;
|
|
||||||
}
|
|
||||||
|
|
||||||
function buildVehicleBuckets(events) {
|
|
||||||
const out = {};
|
|
||||||
for (const e of events) {
|
|
||||||
if (!out[e.vehicle]) out[e.vehicle] = [];
|
|
||||||
out[e.vehicle].push({ ...e });
|
|
||||||
}
|
|
||||||
for (const k of Object.keys(out)) {
|
|
||||||
out[k].sort((a, b) => a.ts - b.ts);
|
|
||||||
}
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
function metersBetween(lat1, lon1, lat2, lon2) {
|
|
||||||
const meanLatRad = ((lat1 + lat2) / 2) * Math.PI / 180;
|
|
||||||
const metersPerDegLat = 111320;
|
|
||||||
const metersPerDegLon = 111320 * Math.cos(meanLatRad);
|
|
||||||
|
|
||||||
const dLatM = (lat2 - lat1) * metersPerDegLat;
|
|
||||||
const dLonM = (lon2 - lon1) * metersPerDegLon;
|
|
||||||
|
|
||||||
return Math.hypot(dLatM, dLonM);
|
|
||||||
}
|
|
||||||
|
|
||||||
function clamp(value, min, max) {
|
|
||||||
return Math.max(min, Math.min(max, value));
|
|
||||||
}
|
|
||||||
|
|
||||||
function distanceToBoundsMeters(lat, lon, bounds) {
|
|
||||||
const south = bounds.getSouth();
|
|
||||||
const north = bounds.getNorth();
|
|
||||||
const west = bounds.getWest();
|
|
||||||
const east = bounds.getEast();
|
|
||||||
|
|
||||||
const clampedLat = clamp(lat, south, north);
|
|
||||||
const clampedLon = clamp(lon, west, east);
|
|
||||||
|
|
||||||
return metersBetween(lat, lon, clampedLat, clampedLon);
|
|
||||||
}
|
|
||||||
|
|
||||||
function getPresenceState(lat, lon, uncertaintyM) {
|
|
||||||
const bounds = map.getBounds();
|
|
||||||
const centerInside = bounds.contains([lat, lon]);
|
|
||||||
|
|
||||||
if (centerInside) {
|
|
||||||
return {
|
|
||||||
code: "inside",
|
|
||||||
label: "ja"
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (uncertaintyM > 0) {
|
|
||||||
const distToBounds = distanceToBoundsMeters(lat, lon, bounds);
|
|
||||||
if (distToBounds <= uncertaintyM) {
|
|
||||||
return {
|
|
||||||
code: "possible",
|
|
||||||
label: "muligvis"
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
code: "outside",
|
|
||||||
label: "nej"
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const vehicleEvents = buildVehicleBuckets(VEHICLE_EVENTS);
|
|
||||||
const vehicleNames = Object.keys(vehicleEvents);
|
|
||||||
|
|
||||||
const vehicles = {};
|
|
||||||
|
|
||||||
for (const name of vehicleNames) {
|
|
||||||
const first = vehicleEvents[name][0];
|
|
||||||
const color = COLORS[name] || "#2979ff";
|
|
||||||
|
|
||||||
const marker = L.marker([first.lat, first.lon], {
|
|
||||||
icon: carIcon(color)
|
|
||||||
}).addTo(map);
|
|
||||||
|
|
||||||
const trail = L.polyline([[first.lat, first.lon]], {
|
|
||||||
color,
|
|
||||||
weight: 3,
|
|
||||||
opacity: 0.85
|
|
||||||
}).addTo(map);
|
|
||||||
|
|
||||||
let uncertaintyCircle = null;
|
|
||||||
if (name === "Bil 2") {
|
|
||||||
uncertaintyCircle = L.circle([first.lat, first.lon], {
|
|
||||||
radius: first.uncertaintyM,
|
|
||||||
color: color,
|
|
||||||
weight: 2,
|
|
||||||
dashArray: "6,6",
|
|
||||||
opacity: 0.7,
|
|
||||||
fillColor: color,
|
|
||||||
fillOpacity: 0.08
|
|
||||||
}).addTo(map);
|
|
||||||
}
|
|
||||||
|
|
||||||
vehicles[name] = {
|
|
||||||
name,
|
|
||||||
color,
|
|
||||||
events: vehicleEvents[name],
|
|
||||||
marker,
|
|
||||||
trail,
|
|
||||||
uncertaintyCircle,
|
|
||||||
currentIndex: 0,
|
|
||||||
current: first,
|
|
||||||
next: vehicleEvents[name][1] || null,
|
|
||||||
displayLat: first.lat,
|
|
||||||
displayLon: first.lon,
|
|
||||||
displayHeading: first.headingDeg,
|
|
||||||
lastTrailLat: first.lat,
|
|
||||||
lastTrailLon: first.lon,
|
|
||||||
presenceState: "inside",
|
|
||||||
presenceStateLabel: "ja"
|
|
||||||
};
|
|
||||||
|
|
||||||
marker.bindPopup(popupHtml(name, vehicles[name]));
|
|
||||||
setHeading(marker, first.headingDeg);
|
|
||||||
}
|
|
||||||
|
|
||||||
let simTime = 0;
|
|
||||||
let lastFrameTime = null;
|
|
||||||
let running = true;
|
|
||||||
const TIME_SCALE = 0.175;
|
|
||||||
|
|
||||||
function resetDemo() {
|
|
||||||
simTime = 0;
|
|
||||||
lastFrameTime = null;
|
|
||||||
|
|
||||||
for (const name of vehicleNames) {
|
|
||||||
const v = vehicles[name];
|
|
||||||
const first = v.events[0];
|
|
||||||
|
|
||||||
v.currentIndex = 0;
|
|
||||||
v.current = first;
|
|
||||||
v.next = v.events[1] || null;
|
|
||||||
v.displayLat = first.lat;
|
|
||||||
v.displayLon = first.lon;
|
|
||||||
v.displayHeading = first.headingDeg;
|
|
||||||
v.lastTrailLat = first.lat;
|
|
||||||
v.lastTrailLon = first.lon;
|
|
||||||
v.presenceState = "inside";
|
|
||||||
v.presenceStateLabel = "ja";
|
|
||||||
|
|
||||||
v.marker.setLatLng([first.lat, first.lon]);
|
|
||||||
setHeading(v.marker, first.headingDeg);
|
|
||||||
v.marker.setPopupContent(popupHtml(name, v));
|
|
||||||
|
|
||||||
v.trail.setLatLngs([[first.lat, first.lon]]);
|
|
||||||
v.trail.setStyle({ opacity: 0.85 });
|
|
||||||
|
|
||||||
if (v.uncertaintyCircle) {
|
|
||||||
v.uncertaintyCircle.setLatLng([first.lat, first.lon]);
|
|
||||||
v.uncertaintyCircle.setRadius(first.uncertaintyM);
|
|
||||||
v.uncertaintyCircle.setStyle({ opacity: 0.7, fillOpacity: 0.08 });
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!map.hasLayer(v.marker)) {
|
|
||||||
v.marker.addTo(map);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
updateStatus();
|
|
||||||
}
|
|
||||||
|
|
||||||
function advanceVehiclePointers(v) {
|
|
||||||
while (v.next && simTime >= v.next.ts) {
|
|
||||||
v.currentIndex += 1;
|
|
||||||
v.current = v.events[v.currentIndex];
|
|
||||||
v.next = v.events[v.currentIndex + 1] || null;
|
|
||||||
|
|
||||||
v.trail.addLatLng([v.current.lat, v.current.lon]);
|
|
||||||
v.lastTrailLat = v.current.lat;
|
|
||||||
v.lastTrailLon = v.current.lon;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateVehicleDisplay(v) {
|
|
||||||
advanceVehiclePointers(v);
|
|
||||||
|
|
||||||
let lat = v.current.lat;
|
|
||||||
let lon = v.current.lon;
|
|
||||||
let heading = v.current.headingDeg;
|
|
||||||
|
|
||||||
if (v.next) {
|
|
||||||
const dt = v.next.ts - v.current.ts;
|
|
||||||
const raw = dt > 0 ? (simTime - v.current.ts) / dt : 1;
|
|
||||||
const t = smoothstep(raw);
|
|
||||||
|
|
||||||
lat = lerp(v.current.lat, v.next.lat, t);
|
|
||||||
lon = lerp(v.current.lon, v.next.lon, t);
|
|
||||||
heading = lerpAngleDeg(v.current.headingDeg, v.next.headingDeg, t);
|
|
||||||
} else {
|
|
||||||
const age = simTime - v.current.ts;
|
|
||||||
const predictFor = Math.min(age, 8);
|
|
||||||
const meters = v.current.speedMps * predictFor;
|
|
||||||
|
|
||||||
const rad = v.current.headingDeg * Math.PI / 180;
|
|
||||||
const northM = Math.cos(rad) * meters;
|
|
||||||
const eastM = Math.sin(rad) * meters;
|
|
||||||
|
|
||||||
const metersPerDegLat = 111320;
|
|
||||||
const metersPerDegLon = 111320 * Math.cos(v.current.lat * Math.PI / 180);
|
|
||||||
|
|
||||||
lat = v.current.lat + northM / metersPerDegLat;
|
|
||||||
lon = v.current.lon + eastM / metersPerDegLon;
|
|
||||||
heading = v.current.headingDeg;
|
|
||||||
}
|
|
||||||
|
|
||||||
v.displayLat = lat;
|
|
||||||
v.displayLon = lon;
|
|
||||||
v.displayHeading = heading;
|
|
||||||
|
|
||||||
const presence = getPresenceState(lat, lon, v.current.uncertaintyM);
|
|
||||||
v.presenceState = presence.code;
|
|
||||||
v.presenceStateLabel = presence.label;
|
|
||||||
|
|
||||||
if (presence.code === "inside") {
|
|
||||||
if (!map.hasLayer(v.marker)) {
|
|
||||||
v.marker.addTo(map);
|
|
||||||
}
|
|
||||||
v.marker.setLatLng([lat, lon]);
|
|
||||||
setHeading(v.marker, heading);
|
|
||||||
v.trail.setStyle({ opacity: 0.85 });
|
|
||||||
} else {
|
|
||||||
if (map.hasLayer(v.marker)) {
|
|
||||||
map.removeLayer(v.marker);
|
|
||||||
}
|
|
||||||
v.trail.setStyle({ opacity: 0.25 });
|
|
||||||
}
|
|
||||||
|
|
||||||
v.marker.setPopupContent(popupHtml(v.name, v));
|
|
||||||
|
|
||||||
if (v.uncertaintyCircle) {
|
|
||||||
v.uncertaintyCircle.setLatLng([lat, lon]);
|
|
||||||
v.uncertaintyCircle.setRadius(v.current.uncertaintyM);
|
|
||||||
|
|
||||||
if (presence.code === "inside") {
|
|
||||||
v.uncertaintyCircle.setStyle({ opacity: 0.7, fillOpacity: 0.08 });
|
|
||||||
} else if (presence.code === "possible") {
|
|
||||||
v.uncertaintyCircle.setStyle({ opacity: 0.35, fillOpacity: 0.03 });
|
|
||||||
} else {
|
|
||||||
v.uncertaintyCircle.setStyle({ opacity: 0.15, fillOpacity: 0.01 });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateAlerts() {
|
|
||||||
const possibleVehicles = vehicleNames
|
|
||||||
.map(name => vehicles[name])
|
|
||||||
.filter(v => v.presenceState === "possible");
|
|
||||||
|
|
||||||
if (possibleVehicles.length === 0) {
|
|
||||||
alertsEl.innerHTML = "";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
alertsEl.innerHTML = possibleVehicles.map(v => `
|
|
||||||
<div class="alert-item">
|
|
||||||
<strong>${v.name}: mulig tilstedeværelse</strong>
|
|
||||||
Estimatet er udenfor kortet, men usikkerheden overlapper det viste område.
|
|
||||||
</div>
|
|
||||||
`).join("");
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateStatus() {
|
|
||||||
const total = VEHICLE_EVENTS.length;
|
|
||||||
const passed = VEHICLE_EVENTS.filter(e => e.ts <= simTime).length;
|
|
||||||
|
|
||||||
statusEl.textContent =
|
|
||||||
`Simuleret tid: ${simTime.toFixed(1)} s\n` +
|
|
||||||
`Events passeret: ${passed} / ${total}\n` +
|
|
||||||
`Afspilning: 2x`;
|
|
||||||
|
|
||||||
updateAlerts();
|
|
||||||
}
|
|
||||||
|
|
||||||
function tick(now) {
|
|
||||||
if (!running) return;
|
|
||||||
|
|
||||||
if (lastFrameTime === null) {
|
|
||||||
lastFrameTime = now;
|
|
||||||
}
|
|
||||||
|
|
||||||
const dtReal = (now - lastFrameTime) / 1000;
|
|
||||||
lastFrameTime = now;
|
|
||||||
simTime += dtReal / TIME_SCALE;
|
|
||||||
|
|
||||||
for (const name of vehicleNames) {
|
|
||||||
updateVehicleDisplay(vehicles[name]);
|
|
||||||
}
|
|
||||||
|
|
||||||
updateStatus();
|
|
||||||
requestAnimationFrame(tick);
|
|
||||||
}
|
|
||||||
|
|
||||||
playBtn.addEventListener("click", () => {
|
|
||||||
if (running) return;
|
|
||||||
running = true;
|
|
||||||
lastFrameTime = null;
|
|
||||||
requestAnimationFrame(tick);
|
|
||||||
});
|
|
||||||
|
|
||||||
pauseBtn.addEventListener("click", () => {
|
|
||||||
running = false;
|
|
||||||
});
|
|
||||||
|
|
||||||
resetBtn.addEventListener("click", () => {
|
|
||||||
running = false;
|
|
||||||
resetDemo();
|
|
||||||
running = true;
|
|
||||||
requestAnimationFrame(tick);
|
|
||||||
});
|
|
||||||
|
|
||||||
map.on("moveend zoomend", () => {
|
|
||||||
for (const name of vehicleNames) {
|
|
||||||
updateVehicleDisplay(vehicles[name]);
|
|
||||||
}
|
|
||||||
updateStatus();
|
|
||||||
});
|
|
||||||
|
|
||||||
resetDemo();
|
|
||||||
requestAnimationFrame(tick);
|
|
||||||
|
|
@ -1,61 +0,0 @@
|
||||||
const VEHICLE_EVENTS = [
|
|
||||||
{ vehicle: "Bil 3", ts: 0, lat: 55.6780, lon: 12.5600, speedMps: 8, headingDeg: 190, uncertaintyM: 0 },
|
|
||||||
{ vehicle: "Bil 2", ts: 2, lat: 55.6748, lon: 12.5650, speedMps: 9, headingDeg: 45, uncertaintyM: 1200 },
|
|
||||||
{ vehicle: "Bil 1", ts: 4, lat: 55.6761, lon: 12.5683, speedMps: 12, headingDeg: 90, uncertaintyM: 0 },
|
|
||||||
{ vehicle: "Bil 4", ts: 5, lat: 55.6728, lon: 12.5710, speedMps: 7, headingDeg: 330, uncertaintyM: 0 },
|
|
||||||
{ vehicle: "Bil 5", ts: 6, lat: 55.6795, lon: 12.5845, speedMps: 11, headingDeg: 260, uncertaintyM: 0 },
|
|
||||||
|
|
||||||
{ vehicle: "Bil 3", ts: 12, lat: 55.6772, lon: 12.5603, speedMps: 8, headingDeg: 195, uncertaintyM: 0 },
|
|
||||||
{ vehicle: "Bil 2", ts: 13, lat: 55.6760, lon: 12.5670, speedMps: 10, headingDeg: 50, uncertaintyM: 1000 },
|
|
||||||
{ vehicle: "Bil 1", ts: 15, lat: 55.6762, lon: 12.5720, speedMps: 13, headingDeg: 95, uncertaintyM: 0 },
|
|
||||||
{ vehicle: "Bil 4", ts: 16, lat: 55.6736, lon: 12.5698, speedMps: 8, headingDeg: 340, uncertaintyM: 0 },
|
|
||||||
{ vehicle: "Bil 5", ts: 18, lat: 55.6793, lon: 12.5815, speedMps: 12, headingDeg: 255, uncertaintyM: 0 },
|
|
||||||
|
|
||||||
{ vehicle: "Bil 3", ts: 24, lat: 55.6765, lon: 12.5610, speedMps: 9, headingDeg: 200, uncertaintyM: 0 },
|
|
||||||
{ vehicle: "Bil 2", ts: 26, lat: 55.6772, lon: 12.5692, speedMps: 11, headingDeg: 55, uncertaintyM: 900 },
|
|
||||||
{ vehicle: "Bil 1", ts: 27, lat: 55.6763, lon: 12.5758, speedMps: 14, headingDeg: 100, uncertaintyM: 0 },
|
|
||||||
{ vehicle: "Bil 4", ts: 28, lat: 55.6746, lon: 12.5688, speedMps: 8, headingDeg: 350, uncertaintyM: 0 },
|
|
||||||
{ vehicle: "Bil 5", ts: 29, lat: 55.6790, lon: 12.5784, speedMps: 12, headingDeg: 250, uncertaintyM: 0 },
|
|
||||||
|
|
||||||
{ vehicle: "Bil 3", ts: 38, lat: 55.6758, lon: 12.5620, speedMps: 9, headingDeg: 210, uncertaintyM: 0 },
|
|
||||||
{ vehicle: "Bil 2", ts: 40, lat: 55.6785, lon: 12.5716, speedMps: 12, headingDeg: 60, uncertaintyM: 850 },
|
|
||||||
{ vehicle: "Bil 1", ts: 41, lat: 55.6764, lon: 12.5798, speedMps: 14, headingDeg: 105, uncertaintyM: 0 },
|
|
||||||
{ vehicle: "Bil 4", ts: 42, lat: 55.6757, lon: 12.5682, speedMps: 9, headingDeg: 0, uncertaintyM: 0 },
|
|
||||||
{ vehicle: "Bil 5", ts: 43, lat: 55.6786, lon: 12.5753, speedMps: 11, headingDeg: 245, uncertaintyM: 0 },
|
|
||||||
|
|
||||||
{ vehicle: "Bil 3", ts: 50, lat: 55.6752, lon: 12.5634, speedMps: 10, headingDeg: 220, uncertaintyM: 0 },
|
|
||||||
{ vehicle: "Bil 2", ts: 54, lat: 55.6796, lon: 12.5744, speedMps: 12, headingDeg: 70, uncertaintyM: 800 },
|
|
||||||
{ vehicle: "Bil 1", ts: 55, lat: 55.6766, lon: 12.5837, speedMps: 15, headingDeg: 110, uncertaintyM: 0 },
|
|
||||||
{ vehicle: "Bil 4", ts: 56, lat: 55.6769, lon: 12.5682, speedMps: 9, headingDeg: 10, uncertaintyM: 0 },
|
|
||||||
{ vehicle: "Bil 5", ts: 57, lat: 55.6781, lon: 12.5722, speedMps: 10, headingDeg: 240, uncertaintyM: 0 },
|
|
||||||
|
|
||||||
{ vehicle: "Bil 3", ts: 66, lat: 55.6747, lon: 12.5652, speedMps: 10, headingDeg: 230, uncertaintyM: 0 },
|
|
||||||
{ vehicle: "Bil 2", ts: 68, lat: 55.6804, lon: 12.5776, speedMps: 11, headingDeg: 85, uncertaintyM: 950 },
|
|
||||||
{ vehicle: "Bil 1", ts: 69, lat: 55.6768, lon: 12.5875, speedMps: 14, headingDeg: 115, uncertaintyM: 0 },
|
|
||||||
{ vehicle: "Bil 4", ts: 70, lat: 55.6781, lon: 12.5688, speedMps: 10, headingDeg: 20, uncertaintyM: 0 },
|
|
||||||
{ vehicle: "Bil 5", ts: 72, lat: 55.6776, lon: 12.5692, speedMps: 10, headingDeg: 235, uncertaintyM: 0 },
|
|
||||||
|
|
||||||
{ vehicle: "Bil 3", ts: 82, lat: 55.6744, lon: 12.5673, speedMps: 9, headingDeg: 240, uncertaintyM: 0 },
|
|
||||||
{ vehicle: "Bil 2", ts: 84, lat: 55.6810, lon: 12.5808, speedMps: 10, headingDeg: 100, uncertaintyM: 1100 },
|
|
||||||
{ vehicle: "Bil 1", ts: 85, lat: 55.6770, lon: 12.5912, speedMps: 13, headingDeg: 120, uncertaintyM: 0 },
|
|
||||||
{ vehicle: "Bil 4", ts: 87, lat: 55.6792, lon: 12.5700, speedMps: 10, headingDeg: 30, uncertaintyM: 0 },
|
|
||||||
{ vehicle: "Bil 5", ts: 88, lat: 55.6771, lon: 12.5662, speedMps: 9, headingDeg: 230, uncertaintyM: 0 },
|
|
||||||
|
|
||||||
{ vehicle: "Bil 3", ts: 96, lat: 55.6742, lon: 12.5696, speedMps: 8, headingDeg: 250, uncertaintyM: 0 },
|
|
||||||
{ vehicle: "Bil 2", ts: 98, lat: 55.6812, lon: 12.5842, speedMps: 10, headingDeg: 115, uncertaintyM: 1200 },
|
|
||||||
{ vehicle: "Bil 1", ts: 99, lat: 55.6772, lon: 12.5948, speedMps: 12, headingDeg: 125, uncertaintyM: 0 },
|
|
||||||
{ vehicle: "Bil 4", ts: 101,lat: 55.6800, lon: 12.5716, speedMps: 9, headingDeg: 40, uncertaintyM: 0 },
|
|
||||||
{ vehicle: "Bil 5", ts: 102,lat: 55.6766, lon: 12.5634, speedMps: 9, headingDeg: 225, uncertaintyM: 0 },
|
|
||||||
|
|
||||||
{ vehicle: "Bil 3", ts: 112,lat: 55.6742, lon: 12.5720, speedMps: 8, headingDeg: 260, uncertaintyM: 0 },
|
|
||||||
{ vehicle: "Bil 2", ts: 114,lat: 55.6811, lon: 12.5877, speedMps: 9, headingDeg: 125, uncertaintyM: 1000 },
|
|
||||||
{ vehicle: "Bil 1", ts: 115,lat: 55.6775, lon: 12.5982, speedMps: 11, headingDeg: 130, uncertaintyM: 0 },
|
|
||||||
{ vehicle: "Bil 4", ts: 117,lat: 55.6806, lon: 12.5736, speedMps: 8, headingDeg: 50, uncertaintyM: 0 },
|
|
||||||
{ vehicle: "Bil 5", ts: 118,lat: 55.6761, lon: 12.5608, speedMps: 8, headingDeg: 220, uncertaintyM: 0 },
|
|
||||||
|
|
||||||
{ vehicle: "Bil 3", ts: 128,lat: 55.6744, lon: 12.5742, speedMps: 7, headingDeg: 270, uncertaintyM: 0 },
|
|
||||||
{ vehicle: "Bil 2", ts: 130,lat: 55.6808, lon: 12.5910, speedMps: 8, headingDeg: 130, uncertaintyM: 950 },
|
|
||||||
{ vehicle: "Bil 1", ts: 131,lat: 55.6778, lon: 12.6016, speedMps: 10, headingDeg: 135, uncertaintyM: 0 },
|
|
||||||
{ vehicle: "Bil 4", ts: 133,lat: 55.6809, lon: 12.5758, speedMps: 7, headingDeg: 60, uncertaintyM: 0 },
|
|
||||||
{ vehicle: "Bil 5", ts: 134,lat: 55.6756, lon: 12.5584, speedMps: 8, headingDeg: 215, uncertaintyM: 0 }
|
|
||||||
];
|
|
||||||
|
|
@ -1,19 +0,0 @@
|
||||||
--- data.js
|
|
||||||
+++ data.js
|
|
||||||
@@ -53,5 +53,15 @@
|
|
||||||
{ vehicle: "Bil 3", ts: 128,lat: 55.6744, lon: 12.5742, speedMps: 7, headingDeg: 270, uncertaintyM: 0 },
|
|
||||||
{ vehicle: "Bil 2", ts: 130,lat: 55.6808, lon: 12.5910, speedMps: 8, headingDeg: 130, uncertaintyM: 950 },
|
|
||||||
{ vehicle: "Bil 1", ts: 131,lat: 55.6778, lon: 12.6016, speedMps: 10, headingDeg: 135, uncertaintyM: 0 },
|
|
||||||
{ vehicle: "Bil 4", ts: 133,lat: 55.6809, lon: 12.5758, speedMps: 7, headingDeg: 60, uncertaintyM: 0 },
|
|
||||||
- { vehicle: "Bil 5", ts: 134,lat: 55.6756, lon: 12.5584, speedMps: 8, headingDeg: 215, uncertaintyM: 0 }
|
|
||||||
+ { vehicle: "Bil 5", ts: 134,lat: 55.6756, lon: 12.5584, speedMps: 8, headingDeg: 215, uncertaintyM: 0 },
|
|
||||||
+
|
|
||||||
+ { vehicle: "Bil 6", ts: 8, lat: 55.7080, lon: 12.5050, speedMps: 0, headingDeg: 90, uncertaintyM: 15000 },
|
|
||||||
+ { vehicle: "Bil 6", ts: 44, lat: 55.7080, lon: 12.5050, speedMps: 0, headingDeg: 90, uncertaintyM: 15000 },
|
|
||||||
+ { vehicle: "Bil 6", ts: 90, lat: 55.7080, lon: 12.5050, speedMps: 0, headingDeg: 90, uncertaintyM: 15000 },
|
|
||||||
+ { vehicle: "Bil 6", ts: 134,lat: 55.7080, lon: 12.5050, speedMps: 0, headingDeg: 90, uncertaintyM: 15000 },
|
|
||||||
+
|
|
||||||
+ { vehicle: "Bil 7", ts: 10, lat: 55.7065, lon: 12.6175, speedMps: 0, headingDeg: 270, uncertaintyM: 2800 },
|
|
||||||
+ { vehicle: "Bil 7", ts: 46, lat: 55.7065, lon: 12.6175, speedMps: 0, headingDeg: 270, uncertaintyM: 2800 },
|
|
||||||
+ { vehicle: "Bil 7", ts: 92, lat: 55.7065, lon: 12.6175, speedMps: 0, headingDeg: 270, uncertaintyM: 2800 },
|
|
||||||
+ { vehicle: "Bil 7", ts: 134,lat: 55.7065, lon: 12.6175, speedMps: 0, headingDeg: 270, uncertaintyM: 2800 }
|
|
||||||
|
|
@ -1,75 +0,0 @@
|
||||||
<!doctype html>
|
|
||||||
<html lang="da">
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
|
||||||
<title>Vehicle stream demo</title>
|
|
||||||
|
|
||||||
<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>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
html, body {
|
|
||||||
height: 100%;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#map {
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hud {
|
|
||||||
position: absolute;
|
|
||||||
top: 10px;
|
|
||||||
left: 10px;
|
|
||||||
z-index: 1000;
|
|
||||||
background: rgba(255,255,255,0.95);
|
|
||||||
padding: 10px 12px;
|
|
||||||
border-radius: 8px;
|
|
||||||
border: 1px solid #ccc;
|
|
||||||
font: 13px/1.35 system-ui, sans-serif;
|
|
||||||
box-shadow: 0 2px 8px rgba(0,0,0,0.08);
|
|
||||||
}
|
|
||||||
|
|
||||||
.hud button {
|
|
||||||
margin-right: 8px;
|
|
||||||
padding: 6px 10px;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hud .status {
|
|
||||||
margin-top: 8px;
|
|
||||||
white-space: pre-line;
|
|
||||||
}
|
|
||||||
|
|
||||||
.car {
|
|
||||||
width: 24px;
|
|
||||||
height: 24px;
|
|
||||||
transform-origin: 12px 12px;
|
|
||||||
will-change: transform;
|
|
||||||
filter: drop-shadow(0 1px 1px rgba(0,0,0,.35));
|
|
||||||
}
|
|
||||||
|
|
||||||
.car svg {
|
|
||||||
display: block;
|
|
||||||
width: 24px;
|
|
||||||
height: 24px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="map"></div>
|
|
||||||
|
|
||||||
<div class="hud">
|
|
||||||
<div>
|
|
||||||
<button id="playBtn">Play</button>
|
|
||||||
<button id="pauseBtn">Pause</button>
|
|
||||||
<button id="resetBtn">Reset</button>
|
|
||||||
</div>
|
|
||||||
<div class="status" id="status"></div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script src="data.js"></script>
|
|
||||||
<script src="app.js"></script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
127.0.0.1 - - [07/Apr/2026 13:34:37] "GET /kort7.html HTTP/1.1" 200 -
|
||||||
37
kort7/patch
37
kort7/patch
|
|
@ -1,37 +0,0 @@
|
||||||
--- a/kort6.html
|
|
||||||
+++ b/kort6.html
|
|
||||||
@@ -41,6 +41,24 @@
|
|
||||||
.hud .status {
|
|
||||||
margin-top: 8px;
|
|
||||||
white-space: pre-line;
|
|
||||||
}
|
|
||||||
+
|
|
||||||
+ .hud .alerts {
|
|
||||||
+ margin-top: 8px;
|
|
||||||
+ display: grid;
|
|
||||||
+ gap: 6px;
|
|
||||||
+ max-width: 320px;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ .alert-item {
|
|
||||||
+ padding: 8px 10px;
|
|
||||||
+ border-radius: 8px;
|
|
||||||
+ border: 1px solid #e0b100;
|
|
||||||
+ background: rgba(255,248,204,0.96);
|
|
||||||
+ color: #5f4b00;
|
|
||||||
+ font: 12px/1.35 system-ui,sans-serif;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ .alert-item strong { display:block; margin-bottom:2px; }
|
|
||||||
|
|
||||||
.car {
|
|
||||||
width: 24px;
|
|
||||||
height: 24px;
|
|
||||||
@@ -86,6 +104,7 @@
|
|
||||||
<button id="resetBtn">Reset</button>
|
|
||||||
</div>
|
|
||||||
<div class="status" id="status"></div>
|
|
||||||
+ <div class="alerts" id="presenceAlerts"></div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script src="data.js"></script>
|
|
||||||
20
kort7/patch2
20
kort7/patch2
|
|
@ -1,20 +0,0 @@
|
||||||
--- a/data.js
|
|
||||||
+++ b/data.js
|
|
||||||
@@ -53,5 +53,15 @@
|
|
||||||
{ vehicle: "Bil 3", ts: 128,lat: 55.6744, lon: 12.5742, speedMps: 7, headingDeg: 270, uncertaintyM: 0 },
|
|
||||||
{ vehicle: "Bil 2", ts: 130,lat: 55.6808, lon: 12.5910, speedMps: 8, headingDeg: 130, uncertaintyM: 950 },
|
|
||||||
{ vehicle: "Bil 1", ts: 131,lat: 55.6778, lon: 12.6016, speedMps: 10, headingDeg: 135, uncertaintyM: 0 },
|
|
||||||
{ vehicle: "Bil 4", ts: 133,lat: 55.6809, lon: 12.5758, speedMps: 7, headingDeg: 60, uncertaintyM: 0 },
|
|
||||||
- { vehicle: "Bil 5", ts: 134,lat: 55.6756, lon: 12.5584, speedMps: 8, headingDeg: 215, uncertaintyM: 0 }
|
|
||||||
+ { vehicle: "Bil 5", ts: 134,lat: 55.6756, lon: 12.5584, speedMps: 8, headingDeg: 215, uncertaintyM: 0 },
|
|
||||||
+
|
|
||||||
+ { vehicle: "Bil 6", ts: 8, lat: 55.7080, lon: 12.5050, speedMps: 0, headingDeg: 90, uncertaintyM: 15000 },
|
|
||||||
+ { vehicle: "Bil 6", ts: 44, lat: 55.7080, lon: 12.5050, speedMps: 0, headingDeg: 90, uncertaintyM: 15000 },
|
|
||||||
+ { vehicle: "Bil 6", ts: 90, lat: 55.7080, lon: 12.5050, speedMps: 0, headingDeg: 90, uncertaintyM: 15000 },
|
|
||||||
+ { vehicle: "Bil 6", ts: 134,lat: 55.7080, lon: 12.5050, speedMps: 0, headingDeg: 90, uncertaintyM: 15000 },
|
|
||||||
+
|
|
||||||
+ { vehicle: "Bil 7", ts: 10, lat: 55.7065, lon: 12.6175, speedMps: 0, headingDeg: 270, uncertaintyM: 2800 },
|
|
||||||
+ { vehicle: "Bil 7", ts: 46, lat: 55.7065, lon: 12.6175, speedMps: 0, headingDeg: 270, uncertaintyM: 2800 },
|
|
||||||
+ { vehicle: "Bil 7", ts: 92, lat: 55.7065, lon: 12.6175, speedMps: 0, headingDeg: 270, uncertaintyM: 2800 },
|
|
||||||
+ { vehicle: "Bil 7", ts: 134,lat: 55.7065, lon: 12.6175, speedMps: 0, headingDeg: 270, uncertaintyM: 2800 }
|
|
||||||
];
|
|
||||||
11
kort7/patch3
11
kort7/patch3
|
|
@ -1,11 +0,0 @@
|
||||||
--- a/app.js
|
|
||||||
+++ b/app.js
|
|
||||||
@@ -77,7 +77,7 @@
|
|
||||||
}).addTo(map);
|
|
||||||
|
|
||||||
let uncertaintyCircle = null;
|
|
||||||
- if (name === "Bil 2") {
|
|
||||||
+ if (first.uncertaintyM > 0) {
|
|
||||||
uncertaintyCircle = L.circle([first.lat, first.lon], {
|
|
||||||
radius: first.uncertaintyM,
|
|
||||||
color: color,
|
|
||||||
Loading…
Reference in New Issue