TransWikia.com

Adding a position.watch and update feature to live map with leaflet.js?

Geographic Information Systems Asked by larry chambers on February 28, 2021

I have an app working in node.js that locates a user and plots their location on a leaflet map. When others connect it shows them too. It keeps their marker live as long as they move the mouse.

I would like to change a couple of things but not sure where to start:

  1. Update the users marker when they move.
  2. Keep the marker live as long as the connection is live, not as long as they are moving the mouse or moving in general as they may stop on the jorney.

I know I can use the watch feature but not sure where to add it.I will include the application.js code with is where the map locate and placing the marker code is.

The application.js

$(function() {
    // generate unique user id
    var userId = Math.random().toString(16).substring(2,15);
    var socket = io.connect('/');
    socket.emit('little_newbie', username);
    var map;


    var info = $('#infobox');
    var doc = $(document);

    // custom marker's icon styles
    var tinyIcon = L.Icon.extend({
        options: {
            shadowUrl: '../assets/marker-shadow.png',
            iconSize: [25, 39],
            iconAnchor:   [12, 36],
            shadowSize: [41, 41],
            shadowAnchor: [12, 38],
            popupAnchor: [0, -30]
        }
    });
    var redIcon = new tinyIcon({ iconUrl: '../assets/marker-red.png' });
    var yellowIcon = new tinyIcon({ iconUrl: '../assets/marker-yellow.png' });

    var sentData = {};
    var connects = {};
    var markers = {};
    var active = false;

    socket.on('load:coords', function(data) {
        if (!(data.id in connects)) {
            setMarker(data);
        }

        connects[data.id] = data;
        connects[data.id].updated = $.now();
    });

    // check whether browser supports geolocation api
    if (navigator.geolocation) {
        navigator.geolocation.getCurrentPosition(positionSuccess, positionError, { enableHighAccuracy: true });
    } else {
        $('.map').text('Your browser is out of fashion, there's no geolocation!');
    }

    function positionSuccess(position) {
        var lat = position.coords.latitude;
        var lng = position.coords.longitude;
        var acr = position.coords.accuracy;


        // mark user's position
        var userMarker = L.marker([lat, lng], {
            icon: redIcon
        });
        // uncomment for static debug
        // userMarker = L.marker([51.45, 30.050], { icon: redIcon });

        // load leaflet map

    map = L.map('map').fitWorld();

    L.tileLayer('https://api.tiles.mapbox.com/v4/{id}/{z}/{x}/{y}.png?access_token=pk.eyJ1IjoibWFwYm94IiwiYSI6ImNpejY4NXVycTA2emYycXBndHRqcmZ3N3gifQ.rJcFIG214AriISLbB6B5aw', {
        maxZoom: 18,
        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'
    }).addTo(map);

        userMarker.addTo(map);
        userMarker.bindPopup('<p>You are here ' + username + '</p>').openPopup();

        var emit = $.now();
        // send coords on when user is active
        doc.on('mousemove', function() {
            active = true;

            sentData = {
                id: userId,
                active: active,
                coords: [{
                    lat: lat,
                    lng: lng,
                    acr: acr,
                    name: username
                }]
            };

            if ($.now() - emit > 1) {
                socket.emit('send:coords', sentData);
                emit = $.now();
            }
        });
    }

    doc.bind('mouseup mouseleave', function() {
        active = false;
    });

    // showing markers for connections
    function setMarker(data) {
        for (var i = 0; i < data.coords.length; i++) {

            var num = +$("#count").text() + 1;
            $("#count").text(num);

            var marker = L.marker([data.coords[i].lat, data.coords[i].lng], { icon: yellowIcon }).addTo(map);
            marker.bindPopup('<p>One more external user is here!</p>' + data.coords[i].name);
            markers[data.id] = marker;
        }
    }

    // handle geolocation api errors
    function positionError(error) {
        var errors = {
            1: 'Authorization fails', // permission denied
            2: 'Can't detect your location', //position unavailable
            3: 'Connection timeout' // timeout
        };
        showError('Error:' + errors[error.code]);
    }

    function showError(msg) {
        info.addClass('error').text(msg);

        doc.click(function() {
            info.removeClass('error');
        });
    }

    // delete inactive users every 15 sec
    setInterval(function() {
        for (var ident in connects){
            if ($.now() - connects[ident].updated > 200000) {
            var num = +$("#count").text() - 1;
            $("#count").text(num);
                delete connects[ident];
                map.removeLayer(markers[ident]);
            }
        }
    }, 15000);
});

One Answer

Fully working, rewritten. Just adding it to show how it should of been done from the start and to help anyone else that wants to do something similar

server.js

var http = require('http');
var Static = require('node-static');
var app = http.createServer(handler);
var io = require('socket.io').listen(app);
var port = 8080;
var active = false;
var update = false;
var users = [];

var files = new Static.Server('./public');

function handler(request, response) {
    request.on('end', function() {
        files.serve(request, response);
    }).resume();
}

io.on('connection', (socket) => {
    var addedUser = false;
    socket.on('add user', (username) => {
        if (addedUser) return;
        socket.username = username;
        var new_count = users.length;
        console.log(new_count);
        var new_user = {
            username: username,
            active: active,
            lat: null,
            lng: null,
            update: false
        };

        users.push(new_user);
        console.log(users);
    });

    socket.on('new_coords', (data) => {
        var New_Details = {
            username: data.username,
            active: data.active,
            lat: data.new_lat,
            lng: data.new_lng,
            update: true
        };

        var checkuser = data.username;
        result = users.map(obj => obj.username).indexOf(checkuser) >= 0;

        if (result === true) {
            objIndex = users.findIndex((obj => obj.username == data.username));
            users[objIndex].lat = data.new_lat;
            users[objIndex].lng = data.new_lng;
            users[objIndex].active = data.active;
            users[objIndex].update = true;

            var to_send = {
                username: data.username,
                active: true,
                lat: data.new_lat,
                lng: data.new_lng,
                update: true
            };

            console.log(data.username + ' has just updated their location');
            var new_count = users.length;
            console.log(new_count);
            console.log(users);

            socket.broadcast.emit('updatecoords', to_send);

            objIndex = users.findIndex((obj => obj.username == data.username));
            users[objIndex].update = false;
        }
    });
         socket.on('load_init', (data) => {
        socket.emit('load_init', users);
    })

    socket.on('disconnect', () => {

        for (var i = 0; i < users.length; i++)
            if (users[i].username === socket.username) {
                socket.broadcast.emit('remove_marker', {
                    username: users[i].username
                });
                users.splice(i, 1);
                break;
            }
        var new_count = users.length;
        console.log(new_count);
        console.log('remove marker');
    });
});

app.listen(port);
console.log('Your server goes on localhost:' + port); 

and viewer.html

<!DOCTYPE html>
<html>
<head>
    <title>Multiple user tracker</title>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0">
    <link rel="stylesheet" href="https://unpkg.com/[email protected]/dist/leaflet.css" />
    <script src="https://unpkg.com/[email protected]/dist/leaflet.js"></script>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    <script src="/socket.io/socket.io.js"></script>
    <script>
        var username = prompt('What's your username?');
        var tinyIcon = L.Icon.extend({
            options: {
                shadowUrl: '../assets/marker-shadow.png',
                iconSize: [25, 39],
                iconAnchor: [12, 36],
                shadowSize: [41, 41],
                shadowAnchor: [12, 38],
                popupAnchor: [0, -30]
            }
        });

        var redIcon = new tinyIcon({
            iconUrl: '../assets/marker-red.png'
        });
        var yellowIcon = new tinyIcon({
            iconUrl: '../assets/marker-yellow.png'
        });
        socket = io.connect('/');
        socket.emit('add user', username);
    </script>
    <style>
        body {
            padding: 0;
            margin: 0;
        }

        html,
        body,
        #map {
            height: 100vh;
            width: 100vw;
        }
    </style>
</head>
<body>
    <div id="map"></div>

      <script>
        function initializeMapAndLocator() {       
            var markers = {};
            var mymarker;
            var map = L.map('map');
            googleStreets = L.tileLayer('https://{s}.google.com/vt/lyrs=m&x={x}&y={y}&z={z}', {
                maxZoom: 18,
                subdomains: ['mt0', 'mt1', 'mt2', 'mt3']
            }).addTo(map);

            map.locate({
                setView: true,
                maxZoom: 20
            });

            function onLocationFound(e) {
                var radius = e.accuracy / 2;
                map.locate({
                    setView: false,
                    timeout: 60000,
                    enableHighAccuracy: true
                });

                var newlatlng = e.latlng;
                const new_lat = newlatlng.lat;
                const new_lng = newlatlng.lng;

                var Details = {
                    username: username,
                    active: true,
                    new_lat: new_lat,
                    new_lng: new_lng,
                    update: true
                };

                socket.emit('new_coords', Details);
                if (map.hasLayer(mymarker)) {
                    map.removeLayer(mymarker);
                }

                mymarker = new L.Marker(e.latlng, {
                    icon: yellowIcon,
                    draggable: true
                });

                map.addLayer(mymarker);
                mymarker.bindPopup('<p>You are here ' + username + '</p>').openPopup();
            }

            map.on('locationfound', onLocationFound);

            socket.on('load_init', function(data) {
                for (var i = 0; i < data.length; i++) {
                    if (data[i].lat != null) {
                        markers[data[i].username] = new L.marker([data[i].lat, data[i].lng], {
                            draggable: true,
                            icon: redIcon
                        });
                        map.addLayer(markers[data[i].username]);
                        markers[data[i].username].bindPopup('Online :' + data[i].username);
                    }
                }
            });

            socket.on('updatecoords', function(data) {

                if (map.hasLayer(markers[data.username])) {
                    map.removeLayer(markers[data.username]);
                }

                markers[data.username] = new L.marker([data.lat, data.lng], {
                    draggable: true,
                    icon: redIcon
                });
                map.addLayer(markers[data.username]);
                markers[data.username].bindPopup(data.username + ' is on the move').openPopup();
            });

            socket.on('remove_marker', function(data) {
                map.removeLayer(markers[data.username]);
            });

        }
        socket.emit('load_init');

        initializeMapAndLocator();
    </script>
</body>
</html>

Answered by larry chambers on February 28, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP