Monday, October 11, 2010

Vehicle Tracking With The JavaScript API

Recently, we have been investigating alternatives to our current AVL solution. The problems with our current solution are licensing costs (big $$ per workstation) and ease of use. I thought that I'd give it a try with ESRI's JavaScript API and this is what I came up with.


The vehicles are graphics that are refreshed from the server every 5 seconds using the JavaScript setTimeout() function. I was surprised at how quickly the browser could clear the graphics and reload them from the server. It looks like they are animated instead of reloaded. Here's a sample of the code that I used:

function AddVehicleGraphics(){ SANDY.qt.execute(SANDY.q, function(fSet){ function sortGraphics(a,b){ return (a.attributes.fleetID < b.attributes.fleetID) ? -1 : 1; } // record bread crumbs, if any dojo.forEach(SANDY.crumbsVehicles, function(key){ var crumbGraphic = dojo.filter(SANDY.avlGraphicsLayer.graphics, function(item){ return item.attributes.mapKey == key; })[0]; SANDY.avlGraphicsLayer.remove(crumbGraphic); // required to allow appropriate refresh on history graphics layer crumbGraphic.setInfoTemplate(SANDY.crumbsTipTemplate); crumbGraphic.setSymbol(SANDY.crumbSymbol); // get associate graphics layer var gLayer = SANDY.mapDij.map.getLayer(key); gLayer.add(crumbGraphic); }); // clear graphics layer SANDY.avlGraphicsLayer.clear(); SANDY.chartsDij.clearContent(); // sort the graphics alphabetically so they are sorted when adding to active vehicles table. fSet.features.sort(sortGraphics); dojo.forEach(fSet.features, function(g){ var symbol; switch (g.attributes.defaultIcon) { case "PLOW TRUCK": symbol = dojo.clone(SANDY.truckSymbol); break; case "SWEEPER": symbol = dojo.clone(SANDY.sweeperSymbol); break; case "SUV": symbol = dojo.clone(SANDY.puSymbol); break; } // rotate symbol symbol.setAngle(g.attributes.headingDegrees); g.setSymbol(symbol); // round mph g.attributes.speedMPH = Math.round(g.attributes.speedMPH); // add to graphics layer SANDY.avlGraphicsLayer.add(g); // add to vehicles list / bold all vehicles that have updated in the last 30 minutes var content; var activeCutOff = new Date().setMinutes(new Date().getMinutes() - 30); if (new Date(g.attributes.timeAtCoordinate) > activeCutOff){ content = "<b>" + g.attributes.fleetID + "</b>"; } else { content = g.attributes.fleetID; } SANDY.chartsDij._addContent(content); // update date updated text var now = new Date(); dojo.byId("update-date").innerHTML = now.toLocaleTimeString(); dojo.style("update-date-background", "backgroundColor", "white"); }); if (fSet.features.length === 0){ SANDY.chartsDij._addContent(SANDY.noVehiclesMsg); } }, function(error){ // change background to indicate error dojo.style("update-date-background", "backgroundColor", "red"); }); }


The other cool thing that I was able to do in this project was link to live UDOT traffic cameras. After getting permission from them, I was able to determine the unique URL for each of them from the CommuterLink website and build a feature class with their locations and urls. It was easy after that to publish them as a map service and load them as graphics onto my map. I used a custom infoTip window from ESRI's code gallery and some mouse events to show the camera images.




// camera graphics dojo.connect(SANDY.mapDij.map.graphics, "onMouseOver", function(evt){ // store old symbol to save for mouse out function SANDY.origSymbol = evt.graphic.symbol; // get orig color rgb's var r = SANDY.origSymbol.color.r; var g = SANDY.origSymbol.color.g; var b = SANDY.origSymbol.color.b; // highlight opacity var a = 0.5; // change symbol to highlight symbol var biggerSize = evt.graphic.symbol.size + 4; evt.graphic.setSymbol(dojo.clone(evt.graphic.symbol).setSize(biggerSize).setColor([r, g, b, a])); SANDY.iTip.setContent(evt.graphic.getContent()); SANDY.iTip.show(evt.screenPoint, SANDY.mapDij.map.height, SANDY.mapDij.map.width); }); dojo.connect(SANDY.mapDij.map.graphics, "onMouseOut", function(evt){ // change symbol back evt.graphic.setSymbol(SANDY.origSymbol); SANDY.iTip.hide(); }); dojo.connect(SANDY.mapDij.map.graphics, "onClick", function(evt){ // hide infowindow SANDY.mapDij.map.infoWindow.hide(); });


The next step after we upgrade to ArcGIS Server 10 is to use the new TimeSlider dijit to enable users to view historical data. Sadly, because I'm changing jobs, I will not be around to implement this cool functionality.  :(

Any other suggestions? Anyone else using the JavaScript API for vehicle tracking? I'd love to hear your experiences.

No comments:

Post a Comment