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.
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.