<!DOCTYPE html>

<html>

<head>

    <meta charset=”utf-8″ />

    <meta name=”viewport” content=”width=device-width, initial-scale=1.0″>

    <title>Wereldwijde Boot GPS – OpenSeaMap</title>

    <!– Leaflet CSS en JS via CDNJS –>

    <link rel=”stylesheet” href=”https://cloudflare.com” />

    <script src=”https://cloudflare.com“></script>

    <style>

        body { font-family: Arial, sans-serif; margin: 15px; background: #f0f2f5; }

        .dashboard { 

            display: grid; 

            grid-template-columns: repeat(3, 1fr); 

            gap: 10px; 

            background: white; 

            padding: 15px; 

            border-radius: 8px; 

            text-align: center; 

            box-shadow: 0 2px 4px rgba(0,0,0,0.1);

            margin-bottom: 15px;

        }

        .stat { font-size: 1.4em; font-weight: bold; color: #0275d8; display: block; margin-top: 5px; }

        #mijn-kaart { 

            height: 550px; 

            width: 100%; 

            border-radius: 8px; 

            box-shadow: 0 2px 4px rgba(0,0,0,0.1);

        }

        /* CSS animatie voor een vloeiende overgang bij het draaien van de pijl */

        .boot-icon-container {

            transition: transform 0.5s ease-in-out;

        }

    </style>

</head>

<body>

<div class=”dashboard”>

    <div><strong>Snelheid</strong><span id=”speed” class=”stat”>0.0 kn</span></div>

    <div><strong>Koers</strong><span id=”heading” class=”stat”>–°</span></div>

    <div><strong>Status</strong><span id=”method” class=”stat”>Zoeken…</span></div>

</div>

<div id=”mijn-kaart”></div>

<script>

// 1. Initialiseer de kaart met wereldwijde instellingen

var map = L.map(‘mijn-kaart’, {

    worldCopyJump: true, // Zorgt dat markers op de hele wereldbol herhaald worden

    center: [0, 0], // Startpunt op de evenaar totdat GPS start

    zoom: 2

});

// 2. OpenStreetMap als basislaag

L.tileLayer(‘https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png‘, {

    attribution: ‘© OpenStreetMap contributors’,

    maxZoom: 18

}).addTo(map);

// 3. OpenSeaMap als maritieme laag over de hele wereld

L.tileLayer(‘https://openseamap.org{z}/{x}/{y}.png’, {

    attribution: ‘Map data © OpenSeaMap contributors’,

    minZoom: 3,

    maxZoom: 18

}).addTo(map);

// 4. Een functie om het meedraaiende pijl-icoon te genereren

function maakPijlIcoon(koersGraden) {

    // We gebruiken een SVG-pijl die we via CSS ‘rotate’ de juiste kant op sturen

    return L.divIcon({

        className: ‘boot-icon-container’,

        html: `<div style=”transform: rotate(${koersGraden}deg); width: 40px; height: 40px; display: flex; align-items: center; justify-content: center;”>

                <svg width=”40″ height=”40″ viewBox=”0 0 24 24″ fill=”none” xmlns=”http://w3.org“>

                    <!– De cirkel rondom de pijl –>

                    <circle cx=”12″ cy=”12″ r=”10″ fill=”#0275d8″ fill-opacity=”0.2″ stroke=”#0275d8″ stroke-width=”2″/>

                    <!– De navigatiepijl zelf (wijst standaard naar het Noorden / 0 graden) –>

                    <path d=”M12 4L4 18L12 14L20 18L12 4Z” fill=”#0275d8″ stroke=”#ffffff” stroke-width=”1″ stroke-linejoin=”round”/>

                </svg>

               </div>`,

        iconSize: [40, 40],

        iconAnchor: [20, 20] // Het middelpunt van de pijl is het rotatiepunt

    });

}

// Maak een start-marker aan met de pijl naar het noorden (0 graden)

var bootMarker = L.marker([0, 0], { icon: maakPijlIcoon(0) }).addTo(map);

// 5. GPS tracking activeren via de mobiele browser

if (navigator.geolocation) {

    navigator.geolocation.watchPosition(function(pos) {

        var lat = pos.coords.latitude;

        var lng = pos.coords.longitude;

        var speedMs = pos.coords.speed; // Snelheid in m/s

        var heading = pos.coords.heading; // Koers in graden (0-360)

        // Wiskundige omrekening naar knopen

        var speedKnots = (speedMs && speedMs > 0) ? (speedMs * 1.94384).toFixed(1) + ” kn” : “0.0 kn”;

        // Als de telefoon stilligt of geen koers doorgeeft, houden we de pijl op 0 graden

        var actueleKoers = (heading !== null && heading !== undefined) ? Math.round(heading) : 0;

        var headingText = (heading !== null && heading !== undefined) ? actueleKoers + “°” : “–°”;

        // Dashboard updaten

        document.getElementById(‘speed’).innerText = speedKnots;

        document.getElementById(‘heading’).innerText = headingText;

        document.getElementById(‘method’).innerText = “GPS (Live)”;

        // CRUCIAL: Verplaats de marker én centreer de kaart direct op de boot

        var livePos = [lat, lng];

        bootMarker.setLatLng(livePos);

        // Vervang het icoon met de nieuw berekende rotatiehoek

        bootMarker.setIcon(maakPijlIcoon(actueleKoers));

        // Zorg dat de boot exact in het midden blijft staan

        map.setView(livePos, 14); 

    }, function(err) {

        console.warn(“GPS mislukt, we vallen terug op ruwe IP-locatie.”);

        haalIpLocatie();

    }, { 

        enableHighAccuracy: true, // Essentieel om op het water de GPS-chip te forceren

        maximumAge: 0,

        timeout: 12000 

    });

} else {

    haalIpLocatie();

}

// Back-up voor computers/omgevingen zonder GPS-chip

function haalIpLocatie() {

    fetch(‘https://ipapi.co‘)

    .then(res => res.json())

    .then(data => {

        if(data.latitude && data.longitude) {

            document.getElementById(‘method’).innerText = “IP-Locatie”;

            document.getElementById(‘speed’).innerText = “0.0 kn”;

            document.getElementById(‘heading’).innerText = “–°”;

            var ipPos = [data.latitude, data.longitude];

            bootMarker.setLatLng(ipPos);

            bootMarker.setIcon(maakPijlIcoon(0)); // IP-adres geeft geen koers, dus pijl naar het Noorden

            map.setView(ipPos, 11);

        }

    }).catch(e => {

        document.getElementById(‘method’).innerText = “Basis Kaart”;

    });

}

</script>

</body>

</html>