Draw moving vehicle’s polygons real-time on Google Maps

Goal – Polygons on Google Maps

The specific goal of plotting polygons on Google Maps real-time is the goal of this article. Consider the following case.

polygons on google maps

Use case for mapping vehicle’s position in real-time

There was a need to manage a fleet of 5 vehicles from the dispatch center. Each vehicle traveled across town and picked up garbage from ditches and town property. Each vehicle transmitted it’s location (latitude, longitude and elevation) coordinates to the dispatch center. The dispatch center collected the coordinates and built polygons as vehicle moved across town. The overall goal was for the vehicle to tell the dispatch center where it is and for the dispatch center to call the vehicle operator if it was going on the same route that was already covered by another vehicle already.

Code on GitHub and Zedfox.us

Let’s get going with code. You can download the full code from https://github.com/zedfoxus/google-maps-demo. A working example of plotting polygons in real-time on Google Maps is also available.

This example uses static data source of polygons in the form of 4 pairs of lat/lon/elevation data as follows. Each pair is a different color. Take the first pair of coordinates. It has longitude, latitude and elevation. These 4 pairs make a polygon. Your application may gather this information from the database in real time by making Ajax calls. For simplicity, a static data source has been used in this example.

-90.00012,45.00045,0 -90.00012,45.00046,0 -89.99988,45.00046,0 -89.99988,45.00045,0

HTML of page that shows vehicle position

Let’s look at the HTML page that shows the map in full-screen. A button to re-draw the map has also been placed on the map as a top-centered drawing toolbar.

<!DOCTYPE html>
<html>
<head>
    <meta name="viewport" content="initial-scale=1.0, user-scalable=no">
    <meta charset="utf-8">
    <title>Draw continuous real-time polygons</title>
    <style>
        img { 
            max-width: 100%; 
        }
        #map-canvas img { 
            max-width: none; 
        }
        html, body, #map-canvas {
            height: 100%;
            margin: 0px;
            padding: 0px;
        }
    </style>
    <script src="https://maps.googleapis.com/maps/api/js?v=3.exp&sensor=false&libraries=drawing,geometry"></script>
    <script type="text/javascript" src="http://code.jquery.com/jquery-1.11.0.min.js"></script>
    <script type="text/javascript" src="real-time-polygons-example.js"></script>
</head>
<body>
    <div id="map-canvas"></div>
    <div id="drawagain"><input type="button" value="Draw Again" onclick="drawAgain()"></div>
<body>
</html>

Notice the line with drawagain div. That button will be placed in the top center part of the map.

Set up map

Initialization of the map:

    var myMap;
    var myObject = new Array();
    var myInterval;
    var intervalCounter = 0;
    var myInfoWindow;
    var centerpoint;

    // although we are using a static data source consisting of 4 pairs of
    // lat/lon/elevation, we could have used an Ajax call to get such data
    // from a database or a middleware or API. This array is just to show
    // an example of polygon data source
    var dataSource = [
    "-90.00012,45.00045,0 -90.00012,45.00046,0 -89.99988,45.00046,0 -89.99988,45.00045,0",
    "-89.99919,45.00111,0 -89.99919,45.00119,0 -89.99896,45.00119,0 -89.99896,45.00111,0",
    "-89.99826,45.00197,0 -89.99826,45.00206,0 -89.99803,45.00206,0 -89.99803,45.00197,0",
    "-89.99733,45.00283,0 -89.99733,45.00292,0 -89.99710,45.00292,0 -89.99710,45.00283,0",
    "-89.99641,45.00370,0 -89.99641,45.00379,0 -89.99617,45.00379,0 -89.99617,45.00370,0",
    "-89.99965,45.00068,0 -89.99965,45.00076,0 -89.99942,45.00076,0 -89.99942,45.00068,0",
    "-89.99872,45.00154,0 -89.99872,45.00163,0 -89.99849,45.00163,0 -89.99849,45.00154,0",
    "-89.99780,45.00240,0 -89.99780,45.00249,0 -89.99757,45.00249,0 -89.99757,45.00240,0",
    "-89.99687,45.00327,0 -89.99687,45.00335,0 -89.99664,45.00335,0 -89.99664,45.00327,0",
    "-89.99594,45.00358,0 -89.99594,45.00349,0 -89.99617,45.00349,0 -89.99617,45.00358,0",
    "-90.00012,45.00271,0 -90.00012,45.00279,0 -89.99988,45.00279,0 -89.99988,45.00271,0",
    "-89.99594,45.00453,0 -89.99594,45.00444,0 -89.99617,45.00444,0 -89.99617,45.00453,0",
    "-89.99647,45.00944,0 -89.99644,45.00942,0 -89.99666,45.00938,0 -89.99668,45.00937,0",
    "-89.99687,45.00936,0 -89.99687,45.00928,0 -89.99710,45.00928,0 -89.99710,45.00936,0"
    ];

    // set up the map by creating map options (which contains a center point)
    function initialize() {
        centerpoint = new google.maps.LatLng(45.00495,-90.00052);
        var mapOptions = {
            zoom: 16,
            center: centerpoint,
            mapTypeId: google.maps.MapTypeId.SATELLITE
        }
        myMap = new google.maps.Map(
            document.getElementById('map-canvas'), 
            mapOptions
        );

        // initialize an information window that can be constantly reused
        myInfoWindow = new google.maps.InfoWindow();

        // draw the button to try again
        createSelectionControl();

        // start the animation to display each polygon
        myInterval = setInterval(function() { drawPolygon(); }, 500);
    }

    $(document).ready(function() {
        initialize();
    });

    /**
     * Make sure that the input box is set a control centered on the map
     */
    function createSelectionControl() {
        var dd = document.getElementById('drawagain');
        myMap.controls[google.maps.ControlPosition.TOP_CENTER].push(dd);
    }

Check out the code createSelectionControl. That function will put our button on the top center part of the map. Once the map has initialized, a timer starts in the background that fires up drawPolygon() function every 500 ms (half-a-second). Let’s take a look at what that does.

Draw polygons twice a second on Google Map

    /**
     * Draw polygons on the map
     */
    function drawPolygon() {
        // get an item from the array, parse information and then have the
        // parser display the polygon on the map
        parseInformation(dataSource[intervalCounter]);

        // if we have gone through all of our array items, let's stop
        // the interval
        intervalCounter++;
        if (intervalCounter >= dataSource.length) {
            clearInterval(myInterval);
        }
    }

    /**
     * Parse information that's available in the array and draw it on the
     * screen; also populate it in myObject array
     * 
     * @param string data 4 pairs of Lat/Lon/Elev information as string
     */
    function parseInformation(data) {
        var polygon = setupPolygon(data);
        myObject.push(
            new google.maps.Polygon({
                paths: polygon,
                strokeColor: '#00ff00',
                strokeOpacity: 0.8,
                strokeWeight: 2,
                fillColor: '#00ff00',
                fillOpacity: 0.35
            })
        );
        var obj = myObject[myObject.length - 1];
        obj.setMap(myMap);
        google.maps.event.addListener(obj, 'click', showInformation);
    }

    /**
     * Given 4 pairs of lat/lon/elev information, split each pair by space
     * and from each pair, split by a comma to get lat, lon and elevation.
     * Use that information to draw a polygon
     * 
     * @param string latlonstr 4 pairs of Lat/Lon/Elev information as string
     *
     * @returns array Google Map lat lon for each pair of lat/lon/elev
     */
    function setupPolygon(latlonstr) {
        var latlonstr = latlonstr.trim();
        var individualPoints = latlonstr.split(' ');
        var individualPointsLength = individualPoints.length;
        var point = new Array();
        var returnData = new Array();
        for (var i = 0; i < individualPointsLength; i++) {
            point = individualPoints[i].split(',');
            returnData[i] = new google.maps.LatLng(
                parseFloat(point[1]), 
                parseFloat(point[0])
            );
        }
        return returnData;
    }

drawPolygon will ask parseInformation function to take one item after another from our array of polygon strings and do something with it. After it is done with all items in the array, it clears out the repeated-firing of drawPolygon. The function parseInformation asks setupPolygon to decode the lat/lon from the string for each pair and create a Google Map LatLng object out of it. The polygon string containing 4 pair of lat/lon will now become an array of 4 LatLng items.

parseInformation uses this array to create a Google Polygon object and draw it on the map using setMap method built into Google Maps API. Also, an information window is associated with the newly created polygon so that when it is clicked, an information window will pop up.

Show Info Window when polygon is clicked

Let’s see what the information will contain:

    /**
     * Show information box when a polygon is clicked
     */
    function showInformation(event) {
        var message = getMessage(this, false);
        myInfoWindow.setOptions({ content: message });
        myInfoWindow.setPosition(event.latLng);
        myInfoWindow.open(myMap);
    }

    /**
     * Get appropriate message for a given polygon
     * 
     * @param polygon polygon Google Map polygon object
     * 
     * @return Message appropriate for the polygon
     */
    function getMessage(polygon) {
        var coordinates = polygon.getPath().getArray();

        var message = '<div>This polygon has ' + coordinates.length 
            + ' points</div>' + '<div>Area is ' + GetArea(polygon) 
            + ' acres</div>';

        var coordinateMessage = '<p>My coordinates are: <br>';
        var consoleCoordinates = '';
        for (var i = 0; i < coordinates.length; i++) {
            coordinateMessage += coordinates[i].lat() 
                + ', ' + coordinates[i].lng() + '<br>';
            consoleCoordinates += 'new google.maps.LatLng(' 
                + coordinates[i].lat() 
                + ', ' + coordinates[i].lng() + '),\n';
        }
        message += coordinateMessage;

        return message;
    }

    /**
     * Get area of a polygon in acres
     */
    function GetArea(poly) {
        var result = parseFloat(google.maps.geometry.spherical.computeArea(
            poly.getPath()
        )) * 0.000247105;
        return result.toFixed(4);
    }

showInformation function will call getMessage, which will construct a message of coordinates. This information will show up in the info window when polygon is clicked.

Redraw the map

The drawing happens rather fast. To redraw, the button in the top-center of the map can be clicked. It will call drawAgain function, which will clear the map and redraw the polygons.

    /**
     * Draw the polygons again
     */
    function drawAgain() {
        intervalCounter = 0;
        clearMap();
        clearInterval(myInterval);
        myInterval = setInterval(function() { drawPolygon(); }, 500);   
    }

Using this kind of a system, a real-time vehicle monitoring system was constructed. Similar approach can be taken to display point data. Additionally, dispatch units can be given this software with subtle enhancements that can allow them to click on a map where a vehicle has not traveled and put a comment in. When the vehicle approaches this point, the message shows up on their in-vehicle-monitor.

Hope this example helps audiences in drawing polygons in near real-time on Google Maps.