Mając działający serwer PHP, utworzę w katalogu plik api.php, który będzie odbierał dane od web-aplikacji i zapisywał je w bazie danych. Aplikacja zaś będzie w pliku, właściwie w plikach js.php (wersja dla czystej JavaScript) oraz jq.php (wersja dla jQuery -ale już tylko szkielet, bez wizualizacji).

Czysta JavaScript: /js.php

<!DOCTYPE html>
<html>
<head>
<?php
    /* załatwia wszystko z cookie i DB, ustawia token i url-save
     */
    include('/var/www/gpslogger/comm/comm_cookie.php');
?>

    <style type="text/css">
        
        html, body, 
        #basicMap {
            width: 100%;
            height: 100%;
            margin: 0;
        }

        #mapid { 
            width: 100%;
            height: 100%;
        }
        
    </style>    
    
    <link rel="stylesheet" href="https://unpkg.com/leaflet@1.6.0/dist/leaflet.css"
       integrity="sha512-xwE/Az9zrjBIphAcBb3F6JVqxf46+CDLwfLMHloNu6KEQCAWi6HcDUbeOfBIptF7tcCzusKFjFw2yuvEpDL9wQ==" crossorigin=""/>

    <!-- Make sure you put this AFTER Leaflet's CSS -->
    <script src="https://unpkg.com/leaflet@1.6.0/dist/leaflet.js"
       integrity="sha512-gZwIG9x3wUXg2hdXF6+rVkLF/0Vi9U8D2Ntg4Ga5I5BZpVkVxlJWbSQtXPSiUTtC0TjtGOmxa1AJPuV0CPthew==" crossorigin=""></script>   

    <script>
        
      zoom = 10;
      function init() {
      }

    </script>    

</head>
<body onload="init();">

Czyli pobieram lub tworzę nowy token, który będzie identyfikował przeglądarkę/urządzenie. W tym miejscu można oczywiście dodać Basic-auth, jeśli nasz przeglądarkowy lokalizator miałby być chroniony hasłem.

Ustalam style dla strony i mapy, pobieram style i skrypty dla map leaflet, przygotowuję funkcję init(), która zostanie wykonana po załadowaniu strony.

Przygotuję HTML, który umożliwi wystartowanie śledzenia, przełączenie do wersji jQuery, zobrazuje wartości pozycji, czas po jakim odczytana zostanie następna pozycja, oraz miejsce dla mapy – zobrazowania.

Pure JS<br><br>

<a href="jq.php">jQuery</a><br><br>

<p>Click the button to get your coordinates.</p>

<button id="button_start" onclick="getLocation()">Try It</button>

<div id="div_response">
    
    <p id="p_result"></p>
    <p id="p_gpspos"></p>
    <p id="p_time_repeat_seconds">?</p>

</div>
<div id="mapid"></div>    
<script src="js/js.js"></script>

W pliku js/js.js – skrypt do pobrania pozycji z przeglądarki.

…następnie:

<script>

    var mymap = L.map('mapid').fitWorld();

    L.tileLayer('https://api.mapbox.com/styles/v1/{id}/tiles/{z}/{x}/{y}?access_token={accessToken}', {
        attribution: 'Map data &copy; <a href="https://www.openstreetmap.org/">OpenStreetMap</a> contributors, <a href="https://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>, Imagery © <a href="https://www.mapbox.com/">Mapbox</a>',
        id: 'mapbox/streets-v11',
        tileSize: 512,
        zoomOffset: -1,
        accessToken: '<- tutaj pobrany token dla mapy ->'
    }).addTo(mymap);
    
    var greenIcon = L.icon({
        iconUrl: 'https://qrgo.pl/static/img/favicon-32x32.png',
        iconSize:     [64, 64],
        iconAnchor:   [32, 50],
        popupAnchor:  [-3, -3]
    });    
    
    var marker_web = L.marker([90, 0], {icon: greenIcon}).addTo(mymap);
    
    var app_pos = [90, 0];
    marker_app = L.marker(app_pos).addTo(mymap);
    polyline = L.polyline([]).addTo(mymap); //and polyline.addLatLng([x, y]);

    mymap.on('zoom', function() {
        zoom = mymap.getZoom();
    });

    var myStyle = {
        "color": "#0078ff",
        "weight": 5,
        "opacity": 0.65
    };

    // równocześnie początkowo ustaw mapę wg lokalizacji urządzenia:
    mymap.locate({setView: true, zoom: 5});    

    function showPosition(position) {

        var data_obj = {t: '<?php echo $token_from_cookie; ?>', 
                        lon: position.coords.longitude, 
                        lat: position.coords.latitude, 
                        s: 'pure_js'}; 
        var data_json = JSON.stringify(data_obj); 
//        console.log(data_json);
        if (window.XMLHttpRequest) {// code for IE7+, Firefox, Chrome, Opera, Safari
            xmlhttp = new XMLHttpRequest();
        }
        else {// code for IE6, IE5
            xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
        }

        xmlhttp.open("POST", "<?php echo $url_api; ?>", true);
        xmlhttp.setRequestHeader("Content-type", "application/json");
        xmlhttp.onreadystatechange = respond_webgps_saved;
        xmlhttp.send(data_json);
    }

    /**
     * 
     * @returns {undefined}
     */
    function respond_webgps_saved() {

        var time_repeat_seconds = 10;
        
        if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
            console.log(xmlhttp.responseText);
            var responseObj = JSON.parse(xmlhttp.responseText);
            var p_result = document.getElementById('p_result');
            var p_gpspos = document.getElementById('p_gpspos');
            var p_time_repeat_seconds = document.getElementById('p_time_repeat_seconds');
            var button1 = document.getElementById("button_start");
            if(responseObj.web) {
                var from_web = responseObj.web;
                var from_app = responseObj.app;
                p_result.innerHTML = from_web.dt;
                p_gpspos.innerHTML = 'WEB: ' + from_web.lat + ' ' + from_web.lon 
                        + ' APP: ' + from_app.lat + ' ' + from_app.lon;
                
                var from_web_latlon = [from_web.lat, from_web.lon];
                var from_app_latlon = [from_app.lat, from_app.lon];
                                
                marker_web.setLatLng(from_web_latlon);
                marker_app.setLatLng(from_app_latlon);
                polyline.addLatLng(from_web_latlon);
                button1.disabled = true; 
                if(responseObj.time_repeat_seconds 
                        && Number.isInteger(responseObj.time_repeat_seconds)) {
                    if(responseObj.time_repeat_seconds > 9 
                            && responseObj.time_repeat_seconds < 301) {
                        time_repeat_seconds = responseObj.time_repeat_seconds;
                    }
                }
                p_time_repeat_seconds.innerHTML = time_repeat_seconds;
                setTimeout(function(){ getLocation(); }, time_repeat_seconds * 1000);
            }else{
                p_result.innerHTML = '!';
                p_gpspos.innerHTML = '';
                p_time_repeat_seconds.innerHTML = '-';
                button1.disabled = false; 
            }            
        }
    }

</script>

</body>
</html>

Aby pobrać unikalny token dla mapy Leaflet należy utworzyć darmowe konto:

https://account.mapbox.com/
https://leafletjs.com/examples/mobile/    

Skrypt js/js.js do odpytywania przeglądarki o pozycję:

/** ask browser geolocation
 *
 */
function getLocation() {

    if (navigator.geolocation) {
        navigator.geolocation.getCurrentPosition(showPosition);
    } else { 
        var x = document.getElementById("p_result");
        x.innerHTML = "Geolocation is not supported by this browser.";
    }
}

Po pierwszym wciśnięciu 'Try It’ przeglądarka zapyta o zgodę na udostępnianie lokalizacji stronie:

Zaś sama wizualizacja wygląda tak:

Równocześnie na logu Apache w serwerze odbija się ślad podobny do:

46.204.54.51 - - [08/Jun/2021:16:13:48 +0200] "POST /api.php HTTP/1.1" 200 544 "https://gpslogger.qrgo.pl/js.php" "Mozilla/5.0 (Linux; Android 10; CPH2021) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.210 Mobile Safari/537.36"

… czyli request wysłany z IP 46.204.54.51 metodą POST na /api.php z Androida, przeglądarki Chrome w wersji mobilnej, na który odpowiedziano kodem 200 / OK. Poztcja ląduje w bazie danych.

Wersja jQuery

<!DOCTYPE html>
<html>
<head>

<?php

    /* załatwia wszystko z cookie i DB, ustawia token i url-save
     */
    include('/var/www/gpslogger/comm/comm_cookie.php');
?>
    
    <script
      src="https://code.jquery.com/jquery-3.5.1.min.js"
      integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0="
      crossorigin="anonymous"></script>

    <style type="text/css">
        
        html, body {
            width: 100%;
            height: 100%;
            margin: 0;
        }
        
    </style>
</head>
<body>

jQuery<br><br>
<a href="js.php">pure JS</a><br><br>

<p>Click the button to get your coordinates.</p>

<button id="button1" onclick="getLocation()">Try It</button>

<p id="p_result"></p>

<script src="js/js.js"></script>
    
<script>
    
    /**
     *
     */
    function showPosition(position) {

        var data_obj = { lon: position.coords.longitude, lat: position.coords.latitude, t: '<?php echo $token_from_cookie; ?>', s: 'jQ'}; 

        //console.log(data_obj);

        $.ajax({url: "<?php echo $url_api; ?>", 
            type: 'POST',
            data: JSON.stringify(data_obj),
            dataType: 'json',
            success: function(result){
               // console.log(result);
                document.getElementById('p_result').innerHTML = JSON.stringify(result);
                document.getElementById("button1").disabled = true; 
                setTimeout(function(){ getLocation(); }, 10000);
            }
        });
    }
    
</script>

</body>
</html>

Przy czym wersja ta nie zawiera warstwy prezentacji na mapie.

W logu Apache2 działanie wygląda tak:

46.204.54.51 - - [08/Jun/2021:16:14:04 +0200] "POST /api.php HTTP/1.1" 200 391 "https://gpslogger.qrgo.pl/jq.php" "Mozilla/5.0 (Linux; Android 10; CPH2021) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.210 Mobile Safari/537.36"