Wednesday, February 8, 2012

Bing Maps and HTML5 (Part 1 - Basic)


I've just finished a working prototype of a very basic interaction between Bing Maps and Node.js.

The idea is very simple: open a map, fetch a bunch of coordinates (using websockets) and display them.

The end result should be something like this:





The Server:

The server is implemented in Node.js:
var io = require('socket.io').listen(88);

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

    var coordinates = new Array();

    coordinates[0] = { lat: 40.723697, lon: -8.468368 };
    coordinates[1] = { lat: 37.829701, lon: -7.943891 };
    coordinates[2] = { lat: 41.552968, lon: -8.309867 };
    coordinates[3] = { lat: 41.509392, lon: -6.859326 };
    coordinates[4] = { lat: 39.946475, lon: -7.50164 };
    coordinates[5] = { lat: 40.204391, lon: -8.33593 };
    coordinates[6] = { lat: 38.603914, lon: -7.841794 };
    coordinates[7] = { lat: 37.243653, lon: -8.131754 };
    coordinates[8] = { lat: 40.641346, lon: -7.229598 };
    coordinates[9] = { lat: 39.717187, lon: -8.775258 };
    coordinates[10] = { lat: 38.998077, lon: -9.163589 };
    coordinates[11] = { lat: 39.190066, lon: -7.620413 };
    coordinates[12] = { lat: 41.224799, lon: -8.352842 };
    coordinates[13] = { lat: 39.293463, lon: -8.477529 };
    coordinates[14] = { lat: 38.318513, lon: -8.653012 };
    coordinates[15] = { lat: 41.877865, lon: -8.507078 };
    coordinates[16] = { lat: 41.555004, lon: -7.631723 };
    coordinates[17] = { lat: 40.798902, lon: -7.870874 };

    socket.emit('coordinates', JSON.stringify(coordinates));

});

To create the socket I've used the library Socket.IO. It handles the websocket protocol and provides a great API.

A socket is thus created, listening at port 88:
var io = require('socket.io').listen(88);
Note: In this post one may assume that Socket.IO => WebSockets. That is not true. In fact, Socket.IO works in older browsers by doing some magic with Ajax requests, Flash sockets if available, etc. Anyway, and assuming that everyone here uses a "nice" browser like an updated Chrome or Firefox, we'll accept that Socket.IO creates WebSockets :)

When a connection is established, the server returns an event named "coordinates" to the client, including an array with 18 coordinates (which, by curiosity, correspond to the geographic center of the Portuguese Districts). The array is serialized as a JSON string.
socket.emit('coordinates', JSON.stringify(coordinates));

The Client:

The full-source code for the client is as follows:

<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <title>NodeJS + WebSockets (using socket.io)</title>

    <style type="text/css">
        
        .map 
        {
           width: 400px;
           height: 400px; 
           position: relative;
        }
        
    </style>

    <script type="text/javascript" src="socket.io.js"></script>
    <script type="text/javascript" src="jquery-1.4.2.js"></script>

    <script type="text/javascript">

        var bingMaps = 
            'http://ecn.dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=7.0';

        $(function () {

            var MM;
            var map;

            $.ajax({
                url: bingMaps ,
                dataType: 'jsonp',
                jsonp: 'onscriptload',
                success: function (data) {

                    MM = Microsoft.Maps;

                    map = new MM.Map($('#mapDiv')[0], {
                        credentials: "BING MAPS KEY GOES HERE",
                        showCopyright: false,
                        showDashboard: false,
                        mapTypeId: Microsoft.Maps.MapTypeId.road,
                        showLogo: false,
                        showMapTypeSelector: false,
                        showScalebar: false,
                        center: new Microsoft.Maps.Location(39.5, -8.5),
                        zoom: 6
                    });

                    var socket = io.connect('http://localhost:88');
                    socket.on('coordinates', function (data) {

                        var obj = JSON.parse(data);

                        for (var i = 0; i < obj.length; i++) {
                            var pushpin = new MM.Pushpin(
                                                 new MM.Location(obj[i].lat, 
                                                                 obj[i].lon));
                            map.entities.push(pushpin);
                        }
                    });
                }
            });
        });
    </script>
</head>
<body>
    <div id="mapDiv" class="map"/>
</body>
</html>

The map is loaded asynchronously and, after which, a WebSocket is created and connected to the server (also using the Socket.IO library)
var socket = io.connect('http://localhost:88');

Afterwards, we subscribe the "coordinates" event, convert the received JSON to an array and create a Bing Maps pushpin for each coordinate.
socket.on('coordinates', function (data) {

    var obj = JSON.parse(data);

    for (var i = 0; i < obj.length; i++) {
        var pushpin = new MM.Pushpin(new MM.Location(obj[i].lat, obj[i].lon));
        map.entities.push(pushpin);
    }
});

I've purposely omitted the details regarding installing/running node.js, installing the socket.io module, etc, as there are several tutorials out there that cover this very well. But, if necessary, I'll include these steps here.

In my next post I'm going to going to evolve this example so that the coordinates are not hardcoded in the server, but fetched from a MongoDB database, and displayed using HTML5 Canvas.

Go to Part 2

3 comments:

  1. Hi Pedro, not sure if my previous comment made it, so apologies if duplicated. Trying to replicate the above for my own project using jquery 2.2.1. Not working, per (unanswered) question on StackOverflow http://stackoverflow.com/questions/25964851/jquery-ajax-parsererror-xampp-win8-1-ie11-chrome. Was wondering if you could help point me in the right direction so I can focus on node and mongodb. Cheers, Adam

    ReplyDelete
  2. Just answered you on Stackoverflow

    ReplyDelete
    Replies
    1. Thanks for the clarification and quick response. I can get all this working now - satisfying to see the Node server working first time out!

      Delete