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.