Where’s Santa?

I had an unusual request from my friend John recently – could I help him map the location of Santa as he goes about his deliveries? Ok, it wasn’t quite like that. He is a member of the Lions, and every December they take out a sleigh with Santa on the back through the streets to the delight of lots of excitable children. The issue was that parents didn’t know exactly when he was going to appear in their streets and were constantly looking and waiting for his arrival. If there was a map of the live position, this would solve that particular problem.

Would GPS be the answer?

My initial thought was that we could use an old GPS dongle that I had lying around and plug that into a laptop. There could then be some code to periodically grab the current location and send that to a server somewhere.

There were several issues with this. Firstly, it was bulky, needing to carry a laptop in a confined space while also maintaining charge. Next, we had the issue of having some code, presumably Python, constantly running to read the location and transmit it requiring connectivity. It would be very accurate but not wholly practical and we quickly abandoned this approach.

An alternative approach

John pointed out that something that they all would have would be a mobile phone which has GPS capabilities which is both portable and easy to charge on the go if required. This seemed like the way to go but how to get the coordinates from the device back to the server?

GeolocationPosition

It turns out Javascript allows you to access the current location (if permission is given) using the GeolocationPosition: coords property. Using this I was able to extract the coordinates and then send them back to a remote server using the following code:

       function setLocation() {
        if (navigator.geolocation) {
            navigator.geolocation.getCurrentPosition((position) => {
                const latitude = position.coords.latitude;
                const longitude = position.coords.longitude;
        
                // Send to server
                fetch('location.php, {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json'
                    },
                    body: JSON.stringify({ latitude, longitude })
                })
                .then(response => response.json())
                .then(data => console.log('Success:', data))
                .catch(error => console.error('Error:', error));
            });
            alert('Location updated');
        } else {
            console.error("Geolocation is not supported by this browser.");
        }
       }

Storing the location

Now that we have the coordinates they needed to be stored somewhere ready for use in the map. This is simply done with a small PHP script to capture the details and save them in a local file.

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    // Get the raw POST data (JSON payload)
    $json_data = file_get_contents('php://input');

    // Decode the JSON data into a PHP array
    $data = json_decode($json_data, true);

    // Check if the data is valid
    if (is_array($data) && isset($data['latitude']) && isset($data['longitude'])) {
        $latitude = $data['latitude'];
        $longitude = $data['longitude'];

        file_put_contents("loc.txt", $latitude.','.$longitude);
    } else {
        // If the data is not valid
        http_response_code(400); // Bad request
    }
} else {
    // If it's not a POST request
    http_response_code(405); // Method Not Allowed
}

Displaying the Map

For the map I used the excellent Leaflet library which allowed me to map a custom icon onto OpenStreetMap.

To do this I built a simple PHP script which retrieved the coordinates from the text file and injected them into two hidden fields which the Javascript could access. These were then passed to Leaflet along with the icon to allow it to work its magic.

latitude = document.getElementById('lat').value;
longitude = document.getElementById('long').value;

const map = L.map('map').setView([latitude, longitude], 15);

L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
    maxZoom: 19,
    attribution: '© OpenStreetMap contributors'
}).addTo(map);

// Define the custom icon
const customIcon = L.icon({
    iconUrl: 'santa.png',   // Replace with the path to your custom image
    iconSize: [38, 38],     // Size of the icon (width, height)
    iconAnchor: [19, 38],   // Point where the icon is anchored on the map
    popupAnchor: [0, -40]   // Point where the popup appears relative to the icon
});

// Add a marker with the custom icon
L.marker([latitude, longitude], { icon: customIcon })
    .addTo(map)
    .bindPopup('Santa is here!')
    .openPopup();

Putting it all together

The code shown here is only snippets but the full code is available on my Github page here.

Santa in action

If you want to try this for yourself you can by pressing the Update Location button but be warned that you are doxing yourself!

Once you have updated your location, refresh the page, and it should be shown below. Remember that this is a public site, so someone else might have updated in the meantime.

Santa sleigh PNG by pngimg.com under a Creative Commons Attribution Non-commercial 4.0 International license (CC BY-NC 4.0)

Leave a Reply

Your email address will not be published. Required fields are marked *