kort/kort5.html

241 lines
4.7 KiB
HTML

<!doctype html>
<html lang="da">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>GPS 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%;
}
.car{
width:24px;
height:24px;
transform-origin:12px 12px;
}
.car svg{
width:24px;
height:24px;
}
</style>
</head>
<body>
<div id="map"></div>
<script>
/* --------- 10 koordinatsæt --------- */
const FRAMES=[
{"Bil 1":{lat:55.6761,lon:12.5683},"Bil 2":{lat:55.6748,lon:12.5650},"Bil 3":{lat:55.6780,lon:12.5600},"Bil 4":{lat:55.6728,lon:12.5710},"Bil 5":{lat:55.6795,lon:12.5845}},
{"Bil 1":{lat:55.6762,lon:12.5720},"Bil 2":{lat:55.6760,lon:12.5670},"Bil 3":{lat:55.6772,lon:12.5603},"Bil 4":{lat:55.6736,lon:12.5698},"Bil 5":{lat:55.6793,lon:12.5815}},
{"Bil 1":{lat:55.6763,lon:12.5758},"Bil 2":{lat:55.6772,lon:12.5692},"Bil 3":{lat:55.6765,lon:12.5610},"Bil 4":{lat:55.6746,lon:12.5688},"Bil 5":{lat:55.6790,lon:12.5784}},
{"Bil 1":{lat:55.6764,lon:12.5798},"Bil 2":{lat:55.6785,lon:12.5716},"Bil 3":{lat:55.6758,lon:12.5620},"Bil 4":{lat:55.6757,lon:12.5682},"Bil 5":{lat:55.6786,lon:12.5753}},
{"Bil 1":{lat:55.6766,lon:12.5837},"Bil 2":{lat:55.6796,lon:12.5744},"Bil 3":{lat:55.6752,lon:12.5634},"Bil 4":{lat:55.6769,lon:12.5682},"Bil 5":{lat:55.6781,lon:12.5722}},
{"Bil 1":{lat:55.6768,lon:12.5875},"Bil 2":{lat:55.6804,lon:12.5776},"Bil 3":{lat:55.6747,lon:12.5652},"Bil 4":{lat:55.6781,lon:12.5688},"Bil 5":{lat:55.6776,lon:12.5692}},
{"Bil 1":{lat:55.6770,lon:12.5912},"Bil 2":{lat:55.6810,lon:12.5808},"Bil 3":{lat:55.6744,lon:12.5673},"Bil 4":{lat:55.6792,lon:12.5700},"Bil 5":{lat:55.6771,lon:12.5662}},
{"Bil 1":{lat:55.6772,lon:12.5948},"Bil 2":{lat:55.6812,lon:12.5842},"Bil 3":{lat:55.6742,lon:12.5696},"Bil 4":{lat:55.6800,lon:12.5716},"Bil 5":{lat:55.6766,lon:12.5634}},
{"Bil 1":{lat:55.6775,lon:12.5982},"Bil 2":{lat:55.6811,lon:12.5877},"Bil 3":{lat:55.6742,lon:12.5720},"Bil 4":{lat:55.6806,lon:12.5736},"Bil 5":{lat:55.6761,lon:12.5608}},
{"Bil 1":{lat:55.6778,lon:12.6016},"Bil 2":{lat:55.6808,lon:12.5910},"Bil 3":{lat:55.6744,lon:12.5742},"Bil 4":{lat:55.6809,lon:12.5758},"Bil 5":{lat:55.6756,lon:12.5584}}
];
/* --------- farver --------- */
const COLORS={
"Bil 1":"#ff0000",
"Bil 2":"#00c853",
"Bil 3":"#2979ff",
"Bil 4":"#2979ff",
"Bil 5":"#2979ff"
};
/* --------- kort --------- */
const map=L.map("map").setView([55.6761,12.5683],13);
L.tileLayer(
"https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
{attribution:"© OpenStreetMap"}
).addTo(map);
/* --------- ikon --------- */
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">
<path d="M12 2 L20 22 L12 18 L4 22 Z"
fill="${color}"
stroke="#ffffff"
stroke-width="1.5"/>
</svg>
</div>
`
});
}
/* --------- bearing --------- */
function bearing(p0,p1){
const dy=p1.lat-p0.lat;
const dx=p1.lon-p0.lon;
const a=Math.atan2(dx,dy)*180/Math.PI;
return (a+360)%360;
}
function setHeading(marker,deg){
const el=marker.getElement();
if(!el)return;
const car=el.querySelector("[data-role=car]");
car.style.transform=`rotate(${deg}deg)`;
}
/* --------- markers --------- */
const markers={};
const trails={};
const uncertainty={};
const cars=Object.keys(FRAMES[0]);
for(const name of cars){
const p=FRAMES[0][name];
markers[name]=L.marker(
[p.lat,p.lon],
{icon:carIcon(COLORS[name])}
).addTo(map);
trails[name]=L.polyline(
[[p.lat,p.lon]],
{color:COLORS[name],weight:3}
).addTo(map);
/* usikkerhed kun for grøn bil */
if(name==="Bil 2"){
uncertainty[name]=L.circle(
[p.lat,p.lon],
{
radius:1200,
color:"#00c853",
fillColor:"#00c853",
fillOpacity:0.15,
weight:1
}
).addTo(map);
}
markers[name].bindPopup(name);
}
/* --------- animation --------- */
let frame=0;
let start=performance.now();
const STEP=1500;
function lerp(a,b,t){
return a+(b-a)*t;
}
function smooth(t){
return t*t*(3-2*t);
}
function tick(now){
const next=frame+1;
if(next>=FRAMES.length)return;
let t=(now-start)/STEP;
if(t>1)t=1;
t=smooth(t);
for(const name of cars){
const p0=FRAMES[frame][name];
const p1=FRAMES[next][name];
const lat=lerp(p0.lat,p1.lat,t);
const lon=lerp(p0.lon,p1.lon,t);
const hdg=bearing(p0,p1);
markers[name].setLatLng([lat,lon]);
setHeading(markers[name],hdg);
if(uncertainty[name]){
uncertainty[name].setLatLng([lat,lon]);
}
}
if(t>=1){
frame++;
start=now;
for(const name of cars){
const p=FRAMES[frame][name];
trails[name].addLatLng([p.lat,p.lon]);
}
}
requestAnimationFrame(tick);
}
requestAnimationFrame(tick);
</script>
</body>
</html>