Real-time Geographical Data Visualization with Node.js, Socket.IO and Leaflet
Submitted by admin on Thursday, December 22, 2016 - 22:18.
Data visualisation is becoming an increasingly important subject. As the complexity an volumes of data increase, it is getting harder and harder to make sense of bare arrays of numbers without relevant visualisation models. Let me give you a good example. Right now I work in China. Few months ago there appeared a new startup: bycicle sharing service that used GPS sensors on each bike to track it in the city. Now let's imagine, you need analyse how evenly your bikes are distributed around the city and how many of them are in motion right now. Doing that with excel spreadsheet would be a nightmare. A natural way to deal with this kind of corrdinates data would be to show points as map overlay.
In this post I will show you how to do it: show realtime geographical data with a help of Leaflet (for maps), Node.js (for server-side code) and Socket.io (for establishing real-time connection).
Here's the project layout that I will be using for this example:
As you see this is a very simple express.js application that serves files from 'public' folder and also emits random coordinates to each connected client each 1000 milliseconds. What are those numbers in coordinates? This is roughly the middle of USA. I took this territory as an example.
Now let's create a client-side application that can receive and draw the corodinates on the map. We'll use Leaflet to render map, so let's start from initializing Leaflet and pointing our map to USA. Here's the contents of index.html file:
Notice that we load Socket.io and Leaflet before we load our main script. This way we make sure that the objects required to visualize data are in place. The only HTML element that we put inside of body is a map div. In our main.css file we'll give it width and height, so that it is displayed on the page:
As you see, we use Open Street Map as the source of our map tiles (you can use the other map, since Leaflet supports many different providers). We put the map in exactly the same place where the server is generating random coordinates.
If you reload the page at this point, you will see the map showing up on the screen. Now let's add some markers to show our geographical trends! We'll have to subscribe to 'coords' event that the server is sending and put the marker in a right place.
Refresh the page and voila! The points are appearing on the map! As the final touch, if your events have the "area of effect", you can draw them as circles with certain radius and colors instead of default pointy markers. To do that, replace the body of drawMarker() function with the following code:
Adjust colors and radius to fit your needs and you have a great tool to visualise real-time geographical data!
- public -- files served from HTTP server
- vnd -- third party libraries
- leaflet -- leaflet files
- js -- our client-side JS sources
- main.js -- main client file
- css -- our css files
- main.css -- main css file
- index.html -- client entry point
- node_modules -- node.js dependencies
- package.json -- project metadata
- main.js -- main server-side entry point
Let's start from building a simple HTTP server that also accepts Socket.io connections. Install express and socket.io and put the following code in main.js:
- const express = require('express');
- const http = require('http');
- const app = express();
- const httpServer = http.createServer(app);
- const io = require('socket.io')(httpServer);
- app.use(express.static(`${__dirname}/public`));
- setInterval(() => {
- io.emit('coords', {
- lat: 37 + Math.random() * 20 - 10,
- lng: -96 + Math.random() * 40 - 20
- });
- }, 1000);
- httpServer.listen(3002, () => {
- console.log('Listening on 0.0.0.0:3002')
- });
#map {
width: 600px;
height: 450px;
margin: 10px auto;
}
Now, when all the elements are prepared, it is time to initialize the map! Add this code to main.js file (client-side):
- var map;
- (function init() {
- initMap();
- })();
- function initMap() {
- console.log('Initializing map');
- map = L.map('map').setView([37, -96], 4);
- // Set up map source
- L.tileLayer(
- 'http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
- attribution: 'Open Street Map',
- maxZoom: 18
- }).addTo(map);
- }
- var map;
- var sock = io();
- (function init() {
- initMap();
- sock.on('coords', function(c) {
- drawMarker(c.lat, c.lng);
- });
- })();
- function drawMarker(lat, lng) {
- L.marker([lat, lng]).addTo(map);
- }
- function initMap() {
- console.log('Initializing map');
- map = L.map('map').setView([37, -96], 4);
- // Set up map source
- L.tileLayer(
- 'http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
- attribution: 'Open Street Map',
- maxZoom: 18
- }).addTo(map);
- }
- L.circle([lat, lng], {
- color: 'steelblue',
- fillColor: 'steelblue',
- fillOpacity: 0.5,
- radius: 50000
- }).addTo(map);
Add new comment
- 1037 views