[Backend Project 🚀] Realtime Device track | Map with node.js express and socket.io | Maps | Leaflet

Create a folder in VS code and

npm init -y

then create ‘app.js‘ inside of this folder and make sure we change package.json —> main —> ‘app.js‘.

npm i express ejs
npm i socket.io

we write the basic code for express

const express = require('express');
const app = express()

app.get('/' , function (req,res){
    res.render('index')
})

app.listen(3000)

After that add socket.io and server and socket.io connected

const express = require('express');
const app = express()
const http = require('http')


const socketio = require('socket.io');

const server = http.createServer(app)

const io = socketio(server)
app.get('/' , function (req,res){
    res.render('index')
})

server.listen(3000)

Then perform the EJS(EJS, or Embedded JavaScript, is a popular template engine for Node. js and web development)

const express = require('express');
const app = express()
const http = require('http')
const path = require('path');

const socketio = require('socket.io');

const server = http.createServer(app)

const io = socketio(server)


app.set('view engine', "ejs")
app.set(express.static(path.join(__dirname,"public")))
app.get('/' , function (req,res){
    res.render('index')
})

server.listen(3000)

🔧 Why use EJS?

Because it allows dynamic HTML rendering on the server side.

🔷 Key Features:

  • Simple syntax (<%= %> for output, <% %> for logic)

  • Integrates easily with Express

  • Generates HTML with dynamic data before sending to the client.

then add leaflet (min.js and min.css)→» Leaflet is a JavaScript library that provides a public API for creating interactive maps in web applications

then add our actual js file

<script src="/js/script.js"></script>

go to the leaflet css and js cdn and add this to the index.ejs

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Realtime Tracking App</title>
    <link rel="stylesheet" href="/css/style.css">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.4/leaflet.min.css" integrity="sha512-h9FcoyWjHcOcmEVkxOfTLnmZFWIH0iZhZT1H2TbOq55xssQGEJHEaIm+PgoUaZbRvQTNTluNOEfb1ZRy6D3BOw==" crossorigin="anonymous" referrerpolicy="no-referrer" />


</head>
<body>
    <div id="map">


    </div>

    <script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.4/leaflet.min.js" integrity="sha512-puJW3E/qXDqYp9IfhAI54BJEaWIfloJ7JWs7OeD5i6ruC9JZL1gERT1wjtwXFlh7CjE7ZJ+/vcRZRkIYIb6p4g==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>


    <script src="/js/script.js"></script>
</body>
</html>

Why use .min.js and .min.css files?

“min” stands for minified.

Minification = removing:

  • Whitespace

  • Line breaks

  • Comments

  • Unnecessary characters (without changing functionality)

Benefits of minified files:

  1. Smaller file size
    → Reduces download time
    → Faster page load speed

  2. Better performance
    → Saves bandwidth
    → Important for users with slow connections

  3. Same functionality
    → Code logic remains unchanged
    → Only readability is reduced (hard to read for humans)

And after that we add socketio cdn

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Realtime Tracking App</title>
    <link rel="stylesheet" href="/css/style.css">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.4/leaflet.min.css" integrity="sha512-h9FcoyWjHcOcmEVkxOfTLnmZFWIH0iZhZT1H2TbOq55xssQGEJHEaIm+PgoUaZbRvQTNTluNOEfb1ZRy6D3BOw==" crossorigin="anonymous" referrerpolicy="no-referrer" />


</head>
<body>
    <div id="map">


    </div>

    <script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.4/leaflet.min.js" integrity="sha512-puJW3E/qXDqYp9IfhAI54BJEaWIfloJ7JWs7OeD5i6ruC9JZL1gERT1wjtwXFlh7CjE7ZJ+/vcRZRkIYIb6p4g==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>



    <script src="https://cdn.socket.io/4.8.1/socket.io.min.js" integrity="sha384-mkQ3/7FUtcGyoppY6bz/PORYoGqOl7/aSUMn2ymDOJcapfS6PHqxhRTMh1RR0Q6+" crossorigin="anonymous"></script>


    <script src="/js/script.js"></script>
</body>
</html>

Note:- 1) check if the browser supports geolocation.

  1. Set options fot high accuracy, a 5-second timeout, and no caching.

  2. Use watchPosition to track the users location continuously.

  3. Emit the latitudes and longitude via a socket with “send-location“, Log any errors to the console.

  4. Initialize a map centered at corrdinates (0,0) with a zoom level of 15 using leaflet, Add OpenStreetMap tiles to map create an empty object markers.

  5. When receiving location data via the socket, extract id , latts and longs and center the map on the new coordinates.

  6. if a marker for the id exists update its position, otherwise, create a new marker at the given coordinates and add it to the map. When a user disconnects, remove their marker from the map and delete it from markers.

then we want to apply the geolocation in script.js

const socket = io();

// console.log('hey');


// that is already install in our window object
if(navigator.geolocation){
    navigator.geolocation.watchPosition((position)=>{
        const {latitude , longitude} = position.coords;
        // i'm emitting an event the frontend from here to backend
        socket.emit("send-location" , {latitude , longitude})

    }, (error)=>{
        console.error('error')
    },{
        // setitng for the watchposition
        enableHighAccuracy : true,
        timeout : 5000,
        maximumAge: 0
    }

) // whenever the person move watch the position
}

then we create map like structure— in script.js

L.map('map').setView([0,0], 10) // 0,0 means center of the world, 10x zoom

Creates a Leaflet map instance in the HTML element with id "map"
Sets the initial view of the map to:

  • Latitude: 0

  • Longitude: 0

  • Zoom level: 10

🔢 Zoom level example scale:

Zoom levelView
1World view
5Continent view
10City view
15Streets and buildings clearly visible
20Extremely detailed, house-level view
const map = L.map('map').setView([0,0], 10)

L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" , {
    attribution : 'OpenStreetMap' // optional

}).addTo(map)

now except the location in the backend which was emitted

in app.js

io.on('connection', function(socket){
    socket.on('send-location' , function (data){
        // backend --> frontend
        io.emit('recieve-location' , {id : socket.id , ...data})
    })
    console.log('connected');
});

We are sending the send-location, What ever we receive on backend from there we sent receive-location back to frontend.

In script.js

const markers = {} // emapty obeject marker

socket.on('recieve-location' , (data)=>{
    const {id,latitude , longitude} = data;
    map.setView([latitude ,longitude] ,16 )

    if(markers[id]){
        markers[id].setLatLng([latitude,longitude])
    }

    else{
        markers[id] = L.marker([latitude,longitude]).addTo(map)
    }
})

now we saw our maker as well and updated with accuracy and precision. Now we talk about what if the user is disconnect in both client and server side (app.js and script.js)

app.js

io.on('connection', function(socket){

     // Send the connected user's socket id to them
    socket.emit('your-id', socket.id);

    socket.on('send-location' , function (data){
        // backend --> frontend
        io.emit('recieve-location' , {id : socket.id , ...data})
    })

    // for disconnect the user
    socket.on("disconnect" , function(){
        io.emit('user-disconnect' , socket.id)
    })
});

script.js

//for disconnect the user
socket.on('user-disconnect' , (id)=>{
    if(markers[id]){
        map.removeLayer(markers[id]);
        delete markers[id]

    }

})

Full code for client and server

app.js

// Server file



const express = require('express');
const app = express()
const http = require('http')
const path = require('path');

const socketio = require('socket.io');

const server = http.createServer(app)

const io = socketio(server)


app.set('view engine', "ejs")
app.use(express.static(path.join(__dirname,"public")));


io.on('connection', function(socket){

     // Send the connected user's socket id to them
    socket.emit('your-id', socket.id);

    socket.on('send-location' , function (data){
        // backend --> frontend
        io.emit('recieve-location' , {id : socket.id , ...data})
    })

    // for disconnect the user
    socket.on("disconnect" , function(){
        io.emit('user-disconnect' , socket.id)
    })
});


app.get('/' , function (req,res){
    res.render("index")
})

server.listen(3000);

script.js

// Client file

const socket = io();
let myId; // store your own socket id

// console.log('hey');

socket.on('your-id', (id) => {
    myId = id;
    // console.log('My Socket ID:', myId);
});

// that is already install in our window object
if(navigator.geolocation){
    navigator.geolocation.watchPosition((position)=>{
        const {latitude , longitude} = position.coords;
        // i'm emitting an event the frontend from here to backend
        // console.log('My Location: ' , latitude,longitude);

        socket.emit("send-location" , {latitude , longitude})

    }, (error)=>{
        console.error('Geolocation error' , error);
    },{
        // setitng for the watchposition
        enableHighAccuracy : true, // Uses GPS if available for more accurate location
        timeout : 5000,
        maximumAge: 0 //Does not use cached location, always gets fresh data
    }

) // whenever the person move watch the position
}


const map = L.map('map').setView([0,0], 16)

L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" , {
    attribution : 'OpenStreetMap'

}).addTo(map)


const markers = {} // empty object to track user markers by socket.id

socket.on('recieve-location' , (data)=>{
    const {id,latitude , longitude} = data;

    // Only set view for your own location
    if(id === myId){
        map.setView([latitude, longitude]);
    }


    if(markers[id]){
        markers[id].setLatLng([latitude,longitude])
    }

    else{
        markers[id] = L.marker([latitude,longitude]).addTo(map);
        markers[id].bindPopup(`User: ${id}`).openPopup();
    }
})


//for disconnect the user
socket.on('user-disconnect' , (id)=>{
    if(markers[id]){
        map.removeLayer(markers[id]);
        delete markers[id]

    }

})

Open these two different browsers

"In conclusion, creating a real-time device tracking system with Node.js, Express, Socket.io, and Leaflet boosts your technical skills and enables you to develop dynamic, interactive applications, preparing you to handle complex challenges and innovate in web development."

GITHUB:-https://github.com/Sayan447/Tracker-using-node-and-socket.io

0
Subscribe to my newsletter

Read articles from Sayan Chakraborty directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Sayan Chakraborty
Sayan Chakraborty

"Programming is a craft, more than it is science" said by someone, supported by me 🤣