× Contact
Home ☰ Menu

Real time location sharing with Node.js and Socket.IO on Google Maps

2017. 10. 20. 13:13

Node.js

Socket.IO

Express

JavaScript

JQuery

AJAX

HTML

CSS

In this tutorial I will show the easiest way to retrieve users location from their browser using HTML5 Geolocation API. I will also show you a secondary way to get the user location through IP address. This is useful if users denied the HTML5 Geolocation requests.

Here is the demo. If you would like to test it, just open this link and share with your friends.

What do we need?

First of all we need to install Node.js to our server. We also need to install socket.io to use web sockets. To install Socket.IO simply run this command in your Node folder:

npm install socket.io

To learn more, you can find more information at the official Socket.IO website. After installing the Socket.IO we are ready to create the frontend side.

Create the Frontend

Now we should create the client side. This is the basic website source code without any JavaScript code. As you can see, we need to use the Socket.IO client side JavaScript file, the jQuery 2.1.4 library and we also need the Google Maps Api JavaScript. You have to create a new Google Maps App and replace the XXXXXXX to your own App key. Create a new html document, I called it: index.html

<!DOCTYPE html>
<html>
	<head>
		<title>Geolocation</title>
		<meta name="viewport" content="initial-scale=1.0, user-scalable=no">
		<meta charset="utf-8">
		<script src="/socket.io/socket.io.js"></script>
		<script src="/map/js/jquery-2.1.4.min.js"></script>
		<script src="https://maps.googleapis.com/maps/api/js?key=XXXXXXXXXXXXXXXXXXXcallback=initMap" async defer></script>
		<style>
			html, body {
				height: 100%;
				margin: 0;
				padding: 0;
			}
			#map {
				height: 100%;
			}
		</style>
	</head>
	<body>
		<div id="map"></div>
		<script type="text/javascript">
			// Scripts
		</script>
	</body>
</html>
The source code is very simple. We have a div tag, which has a ‘map’ id. It is hundred percent width and tall so it fills the whole screen. Now we should initialize the map.
var map;
function initMap() {
	map = new google.maps.Map(document.getElementById('map'), {
		center: {lat: 49.037, lng: 14.974},
		zoom: 2
	});
}

I set up a very low zoom level to see each continent easily. The initMap function runs when the browser opens the page. Now we need to get the users’ location.

To retrieve users’ location we use the HTML5 Geolocation API. However, if the user denies the access from the HTML Geolocation API, we can get the user’s location through IP address. It is not as precise as the Geolocation detection, but it is useful. Through IP location we can detect the user’s location by city.

function getLocation() {
	if (navigator.geolocation) {
		navigator.geolocation.getCurrentPosition(showPosition, hidePosition);
	}else{ 
		alert("Geolocation is not supported by this browser. Now we trying to get your location through your IP address.");
		ipPosition();
	}
}
function showPosition(position) {
	pos = {
		lat: parseFloat(position.coords.latitude),
		lng: parseFloat(position.coords.longitude)
	};
}
function hidePosition(position) {
	alert('User denied the access of the position. Now we trying to get your location through your IP address.');
	ipPosition();
}
function ipPosition(){
	$.get("http://ipinfo.io", function (response) {
		var loc = response.loc.split(',');
		pos = {
			lat: parseFloat(loc[0]),
			lng: parseFloat(loc[1])
		};
	}, "jsonp");
}
getLocation();

On page load we call the getLocation function. The browser built in Geolocation ask the user to enable the current position. If the user allows it, Geolocation calls the showPosition function and we receive the position through the pos object. If the user denies the access of the position, the function calls the ipPosition function which makes an Ajax query from ipinfo.io with the user’s IP address. In the response we receive the position.

Notice: With Firefox browser you can’t recieve the IP location if you click to deny after the browser asks you to enable the Geolocation. Firefox calls the ipPosition if you click to the “never for this site” option. More information on this link: Share location- "Not Now" Doesn't fire error callback

When a user visits the page the script gets the location. Now we need to create Markers. Markers point to the position on the Map. These functions will be called after a user connected to the server.

var markers = [];
var getMarkerUniqueId= function(lat, lng) {
	return lat + '_' + lng;
}
function addMarker(location) { // Adds a marker to the map and push to the array.
	var markerId = getMarkerUniqueId(location.lat, location.lng); // that will be used to cache this marker in markers object.
	var marker = new google.maps.Marker({
		position: location,
		map: map,
		animation: google.maps.Animation.DROP,
		id: markerId
	});
	markers[markerId] = marker;
}
var removeMarker = function(marker, markerId) {
	marker.setMap(null); // set markers setMap to null to remove it from map
	delete markers[markerId]; // delete marker instance from markers object
};

We call the socket.io, then we should use the document ready function, because we need some jQuery codes. When the user connects to the server the connect function generates a client id. This is very important in order to identify the client to the server. We also have a setInterval function called check_pos, which checks the user’s activity in every half seconds. If a position is created it sends two sockets to the server side:

socket.emit('new_user', {pos: pos});

If everything works fine, the server will receive the user’s position (pos).

var socket = io();
$(document).ready(function(){
	check_pos = setInterval(function(){ //create a loop and wait for the response
		if(typeof pos != 'undefined'){ //while the position is not defined the loop is checking every half seconds
			socket.emit('new_user', {pos: pos});
			clearInterval(check_pos);
		}
	}, 500);
	socket.on('already', function(data){
		$.each( data.visitors, function( key, pos ) {
			addMarker(pos);
		});
	});
	socket.on('connected', function(data){
		$("#users_count").html("<strong>" + data.users_count +"</strong>" + " connected users");
		$("#users_count").css({'visibility': 'visible'});
		addMarker(data.pos);
	});
	socket.on('disconnected', function(data){
		//we can now delete this position:
		var markerId = getMarkerUniqueId(data.del.lat, data.del.lng); // get marker id by using clicked point's coordinate
		var marker = markers[markerId]; // find marker
		removeMarker(marker, markerId); // remove it
		$("#users_count").html("<strong>" + data.users_count +"</strong>" + " connected users");
	});
});

Create the Backend

Finally, we can make the last step. You should know some basics about the Node.js to understand this code. To learn more, please check out this link: Node.js Docs

We create an object called visitors. As you can see, the new_user function is called from the client side. When the sockets arrive to the server we store them in the visitors object. After this, we send back the position to all connected clients through the connected function. If you check it, you will see that the connected function gets the latitude and the longitude of the position and send them to the marker creator function.

Lastly, if the user is disconnected, the server detects the action and removes it from the visitors object. At the same time, the client will disappear from all of the client’s map. Create a new javascript file, I called it: map.js

var express = require('express');
var app = express();
var server = require('http').Server(app);
var io = require('socket.io')(server);

server.listen(3000, function(){
	console.log('MAP started on port: 3000');
});
app.get('/', function(req, res){
	res.sendFile(__dirname + '/map/index.html');
	app.use(express.static('.'));
});

var visitors = {};
io.on('connection', function(socket){
	socket.on('new_user', function(data){
		if(parseInt(Object.keys(visitors).length) > 0)
			socket.emit('already', {visitors: visitors});
		visitors[socket.id] = data.pos;
		io.emit('connected', { pos: data.pos, users_count: Object.keys(visitors).length });
		console.log('someone CONNECTED:');
		console.log(visitors);
	});
	socket.on('disconnect', function(){
		if(visitors[socket.id]){
			var todel = visitors[socket.id];
			delete visitors[socket.id];
			io.emit('disconnected', { del: todel, users_count: Object.keys(visitors).length }); 	
		}
		console.log('someone DISCONNECTED:');
		console.log(visitors);
	});
}); 

Peter Sipos

I am a Web developer. I am developing in web languages like: PHP, HTML, JavaScript, jQuery, NodeJS. In the following posts you can learn some useful techniques.

6 articles available

More articles