Skip to content

Instantly share code, notes, and snippets.

@marufbd
Last active December 26, 2015 18:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save marufbd/7191903 to your computer and use it in GitHub Desktop.
Save marufbd/7191903 to your computer and use it in GitHub Desktop.
Google maps custom overlay with D3 for live position update

###Google maps custom overlay with D3 for live position update

Based on http://bl.ocks.org/mbostock/899711

Demostrates:

  • Live update of gps positions
  • Move to new positions with transition with data update
<!DOCTYPE html>
<html>
<head>
<title>Google maps GpsSensor layer with D3 for live position update</title>
<script src="http://maps.google.com/maps/api/js??v=3.exp&sensor=true"></script>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/d3/3.3.3/d3.min.js"></script>
<script src="./sample_data.js" charset="utf-8"></script>
<style type="text/css">
html, body, #map {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}
.stations, .stations svg {
position: absolute;
}
.stations svg {
width: 60px;
height: 20px;
padding-right: 100px;
font: 10px sans-serif;
}
.stations circle {
fill: brown;
stroke: black;
stroke-width: 1.5px;
}
</style>
</head>
<body>
<div id="map"></div>
<script>
function GPSSensor(initData) {
//state information
var _div = null;
var _data = initData;
var _projection = null;
function transform(d) {
var padding = 10;
d = new google.maps.LatLng(d.Lat, d.Long);
d = _projection.fromLatLngToDivPixel(d);
return d3.select(this)
.style("left", (d.x - padding) + "px")
.style("top", (d.y - padding) + "px");
}
function transformWithEase(d) {
var padding = 10;
d = new google.maps.LatLng(d.Lat, d.Long);
d = _projection.fromLatLngToDivPixel(d);
return d3.select(this)
.transition().duration(300)
.style("left", (d.x - padding) + "px")
.style("top", (d.y - padding) + "px");
}
//superclass methods for google maps
this.onAdd = function() {
_div = d3.select(this.getPanes().overlayLayer)
.append("div")
.attr("class", "stations");
};
this.draw = function () {
var padding = 10;
_projection = this.getProjection();
var marker = _div.selectAll("svg")
.data(_data, function (d) { return d.Key; })
.each(transform) // update existing markers
.enter().append("svg:svg")
.each(transform)
.attr("class", "marker");
// Add a circle.
marker.append("svg:circle")
.attr("r", 4.5)
.attr("cx", padding)
.attr("cy", padding);
// Add a label.
marker.append("svg:text")
.attr("x", padding + 7)
.attr("y", padding)
.attr("dy", ".31em")
.text(function (d) { return d.Key; });
};
this.onRemove = function () {
_div.remove();
};
this.update = function (data) {
//update internal data which drive redrawing on zoom_changed
for (var i = 0; i < data.length; i++) {
var found = false;
for (var j = 0; j < _data.length; j++) {
if (_data[j].Key === data[i].Key) {
found = true;
_data[j].Lat = data[i].Lat;
_data[j].Long = data[i].Long;
}
}
if (!found)
_data.push(data[i]);
}
//this.draw();
_div.selectAll("svg")
.data(_data, function (d) { return d.Key; })
.each(transformWithEase);
};
}
//subclassing
GPSSensor.prototype = new google.maps.OverlayView();
// Create the Google Map
var map = new google.maps.Map(d3.select("#map").node(), {
zoom: 15,
center: new google.maps.LatLng(-33.690126, 150.924187),
mapTypeId: google.maps.MapTypeId.ROADMAP
});
var sensorData = [
sensor1Data[0]
//,sensor2Data[0]
];
var sensorLayer = new GPSSensor(sensorData);
sensorLayer.setMap(map);
//simulate position update by receiving positions at random interval
var d1Cnt = 1, d2Cnt = 1;
(function loop() {
var randTimeout = Math.round(Math.random() * (3000 - 500)) + 500;
setTimeout(function () {
var whichSensor = Math.floor(Math.random() * 2);
if (whichSensor==0 && d1Cnt < sensor1Data.length)
sensorLayer.update([sensor1Data[d1Cnt++]]);
else if (whichSensor==1 && d2Cnt < sensor2Data.length)
sensorLayer.update([sensor2Data[d2Cnt++]]);
loop();
}, randTimeout);
}());
</script>
</body>
</html>
var sensor1Data=[{"Key":"sensor1","DateTime":"2013-09-04T09:25:00+10:00","Lat":-33.697746,"Long":150.948976,"Heading":142.0,"Speed":3},{"Key":"sensor1","DateTime":"2013-09-04T09:25:11+10:00","Lat":-33.697904,"Long":150.949018,"Heading":150.0,"Speed":14},{"Key":"sensor1","DateTime":"2013-09-04T09:25:21+10:00","Lat":-33.697899,"Long":150.949596,"Heading":71.0,"Speed":31},{"Key":"sensor1","DateTime":"2013-09-04T09:25:34+10:00","Lat":-33.697633,"Long":150.950278,"Heading":60.0,"Speed":6},{"Key":"sensor1","DateTime":"2013-09-04T09:25:44+10:00","Lat":-33.698053,"Long":150.95093,"Heading":136.0,"Speed":42},{"Key":"sensor1","DateTime":"2013-09-04T09:25:54+10:00","Lat":-33.699021,"Long":150.951631,"Heading":172.0,"Speed":42},{"Key":"sensor1","DateTime":"2013-09-04T09:26:04+10:00","Lat":-33.699581,"Long":150.951561,"Heading":249.0,"Speed":31},{"Key":"sensor1","DateTime":"2013-09-04T09:26:14+10:00","Lat":-33.699943,"Long":150.950365,"Heading":254.0,"Speed":33},{"Key":"sensor1","DateTime":"2013-09-04T09:26:24+10:00","Lat":-33.699609,"Long":150.949634,"Heading":312.0,"Speed":44},{"Key":"sensor1","DateTime":"2013-09-04T09:26:34+10:00","Lat":-33.698913,"Long":150.948713,"Heading":314.0,"Speed":43},{"Key":"sensor1","DateTime":"2013-09-04T09:26:44+10:00","Lat":-33.697978,"Long":150.947943,"Heading":350.0,"Speed":50},{"Key":"sensor1","DateTime":"2013-09-04T09:26:54+10:00","Lat":-33.696968,"Long":150.947936,"Heading":295.0,"Speed":25},{"Key":"sensor1","DateTime":"2013-09-04T09:27:04+10:00","Lat":-33.697046,"Long":150.946673,"Heading":251.0,"Speed":46},{"Key":"sensor1","DateTime":"2013-09-04T09:27:14+10:00","Lat":-33.697473,"Long":150.945416,"Heading":250.0,"Speed":50},{"Key":"sensor1","DateTime":"2013-09-04T09:27:24+10:00","Lat":-33.697876,"Long":150.943949,"Heading":257.0,"Speed":54},{"Key":"sensor1","DateTime":"2013-09-04T09:27:34+10:00","Lat":-33.697866,"Long":150.942326,"Heading":277.0,"Speed":50},{"Key":"sensor1","DateTime":"2013-09-04T09:27:44+10:00","Lat":-33.697496,"Long":150.941381,"Heading":342.0,"Speed":37},{"Key":"sensor1","DateTime":"2013-09-04T09:27:54+10:00","Lat":-33.696556,"Long":150.941026,"Heading":341.0,"Speed":19},{"Key":"sensor1","DateTime":"2013-09-04T09:28:04+10:00","Lat":-33.696424,"Long":150.940913,"Heading":294.0,"Speed":16},{"Key":"sensor1","DateTime":"2013-09-04T09:28:14+10:00","Lat":-33.696531,"Long":150.939619,"Heading":261.0,"Speed":54},{"Key":"sensor1","DateTime":"2013-09-04T09:28:24+10:00","Lat":-33.696653,"Long":150.938214,"Heading":264.0,"Speed":29},{"Key":"sensor1","DateTime":"2013-09-04T09:28:34+10:00","Lat":-33.696744,"Long":150.937811,"Heading":283.0,"Speed":21},{"Key":"sensor1","DateTime":"2013-09-04T09:28:44+10:00","Lat":-33.695909,"Long":150.937266,"Heading":319.0,"Speed":49},{"Key":"sensor1","DateTime":"2013-09-04T09:28:54+10:00","Lat":-33.695131,"Long":150.935999,"Heading":294.0,"Speed":53},{"Key":"sensor1","DateTime":"2013-09-04T09:29:04+10:00","Lat":-33.694929,"Long":150.934709,"Heading":269.0,"Speed":49},{"Key":"sensor1","DateTime":"2013-09-04T09:29:14+10:00","Lat":-33.695546,"Long":150.933127,"Heading":229.0,"Speed":64},{"Key":"sensor1","DateTime":"2013-09-04T09:29:24+10:00","Lat":-33.696386,"Long":150.931827,"Heading":243.0,"Speed":29},{"Key":"sensor1","DateTime":"2013-09-04T09:29:34+10:00","Lat":-33.695751,"Long":150.931546,"Heading":359.0,"Speed":46},{"Key":"sensor1","DateTime":"2013-09-04T09:29:44+10:00","Lat":-33.694866,"Long":150.931501,"Heading":9.0,"Speed":36},{"Key":"sensor1","DateTime":"2013-09-04T09:29:54+10:00","Lat":-33.693836,"Long":150.931094,"Heading":327.0,"Speed":51},{"Key":"sensor1","DateTime":"2013-09-04T09:30:04+10:00","Lat":-33.692824,"Long":150.929959,"Heading":316.0,"Speed":56},{"Key":"sensor1","DateTime":"2013-09-04T09:30:14+10:00","Lat":-33.691719,"Long":150.929204,"Heading":346.0,"Speed":55},{"Key":"sensor1","DateTime":"2013-09-04T09:30:24+10:00","Lat":-33.690373,"Long":150.928637,"Heading":330.0,"Speed":51},{"Key":"sensor1","DateTime":"2013-09-04T09:30:51+10:00","Lat":-33.690083,"Long":150.928431,"Heading":329.0,"Speed":15},{"Key":"sensor1","DateTime":"2013-09-04T09:31:01+10:00","Lat":-33.689213,"Long":150.927736,"Heading":323.0,"Speed":50},{"Key":"sensor1","DateTime":"2013-09-04T09:31:11+10:00","Lat":-33.688236,"Long":150.926652,"Heading":311.0,"Speed":53},{"Key":"sensor1","DateTime":"2013-09-04T09:31:21+10:00","Lat":-33.688266,"Long":150.925791,"Heading":230.0,"Speed":43},{"Key":"sensor1","DateTime":"2013-09-04T09:31:32+10:00","Lat":-33.688799,"Long":150.924939,"Heading":231.0,"Speed":3},{"Key":"sensor1","DateTime":"2013-09-04T09:32:14+10:00","Lat":-33.688856,"Long":150.924861,"Heading":230.0,"Speed":22},{"Key":"sensor1","DateTime":"2013-09-04T09:32:24+10:00","Lat":-33.689453,"Long":150.924032,"Heading":215.0,"Speed":16},{"Key":"sensor1","DateTime":"2013-09-04T09:32:34+10:00","Lat":-33.689794,"Long":150.924321,"Heading":145.0,"Speed":4},{"Key":"sensor1","DateTime":"2013-09-04T09:32:44+10:00","Lat":-33.689846,"Long":150.924357,"Heading":147.0,"Speed":16},{"Key":"sensor1","DateTime":"2013-09-04T09:32:56+10:00","Lat":-33.690116,"Long":150.924631,"Heading":93.0,"Speed":5},{"Key":"sensor1","DateTime":"2013-09-04T09:33:06+10:00","Lat":-33.689966,"Long":150.924704,"Heading":87.0,"Speed":1},{"Key":"sensor1","DateTime":"2013-09-04T09:33:19+10:00","Lat":-33.689864,"Long":150.924732,"Heading":87.0,"Speed":1}];
var sensor2Data=[{"Key":"sensor2","DateTime":"2013-09-04T09:41:09+10:00","Lat":-33.690126,"Long":150.924187,"Heading":286.0,"Speed":22},{"Key":"sensor2","DateTime":"2013-09-04T09:41:24+10:00","Lat":-33.689758,"Long":150.924869,"Heading":57.0,"Speed":8},{"Key":"sensor2","DateTime":"2013-09-04T09:41:34+10:00","Lat":-33.689363,"Long":150.925171,"Heading":324.0,"Speed":29},{"Key":"sensor2","DateTime":"2013-09-04T09:41:48+10:00","Lat":-33.689008,"Long":150.924869,"Heading":319.0,"Speed":7},{"Key":"sensor2","DateTime":"2013-09-04T09:41:58+10:00","Lat":-33.688389,"Long":150.925307,"Heading":53.0,"Speed":52},{"Key":"sensor2","DateTime":"2013-09-04T09:42:15+10:00","Lat":-33.687908,"Long":150.926064,"Heading":68.0,"Speed":21},{"Key":"sensor2","DateTime":"2013-09-04T09:42:25+10:00","Lat":-33.688493,"Long":150.927111,"Heading":135.0,"Speed":53},{"Key":"sensor2","DateTime":"2013-09-04T09:42:35+10:00","Lat":-33.689559,"Long":150.928136,"Heading":146.0,"Speed":55},{"Key":"sensor2","DateTime":"2013-09-04T09:42:45+10:00","Lat":-33.690834,"Long":150.929006,"Heading":161.0,"Speed":58},{"Key":"sensor2","DateTime":"2013-09-04T09:42:55+10:00","Lat":-33.692134,"Long":150.929547,"Heading":155.0,"Speed":52},{"Key":"sensor2","DateTime":"2013-09-04T09:43:05+10:00","Lat":-33.693269,"Long":150.930692,"Heading":132.0,"Speed":60},{"Key":"sensor2","DateTime":"2013-09-04T09:43:15+10:00","Lat":-33.694543,"Long":150.931611,"Heading":166.0,"Speed":54},{"Key":"sensor2","DateTime":"2013-09-04T09:43:25+10:00","Lat":-33.695896,"Long":150.931636,"Heading":178.0,"Speed":56},{"Key":"sensor2","DateTime":"2013-09-04T09:43:35+10:00","Lat":-33.696059,"Long":150.932322,"Heading":53.0,"Speed":55},{"Key":"sensor2","DateTime":"2013-09-04T09:43:45+10:00","Lat":-33.695139,"Long":150.933694,"Heading":62.0,"Speed":59},{"Key":"sensor2","DateTime":"2013-09-04T09:43:55+10:00","Lat":-33.694844,"Long":150.935238,"Heading":98.0,"Speed":47},{"Key":"sensor2","DateTime":"2013-09-04T09:44:05+10:00","Lat":-33.695446,"Long":150.936783,"Heading":127.0,"Speed":59},{"Key":"sensor2","DateTime":"2013-09-04T09:44:15+10:00","Lat":-33.696499,"Long":150.937849,"Heading":138.0,"Speed":39},{"Key":"sensor2","DateTime":"2013-09-04T09:44:25+10:00","Lat":-33.696484,"Long":150.939318,"Heading":83.0,"Speed":58},{"Key":"sensor2","DateTime":"2013-09-04T09:44:35+10:00","Lat":-33.696318,"Long":150.940849,"Heading":67.0,"Speed":27},{"Key":"sensor2","DateTime":"2013-09-04T09:44:45+10:00","Lat":-33.696946,"Long":150.941224,"Heading":163.0,"Speed":53},{"Key":"sensor2","DateTime":"2013-09-04T09:44:55+10:00","Lat":-33.697781,"Long":150.941828,"Heading":96.0,"Speed":39},{"Key":"sensor2","DateTime":"2013-09-04T09:45:05+10:00","Lat":-33.697906,"Long":150.943258,"Heading":91.0,"Speed":52},{"Key":"sensor2","DateTime":"2013-09-04T09:45:15+10:00","Lat":-33.697646,"Long":150.944784,"Heading":71.0,"Speed":51},{"Key":"sensor2","DateTime":"2013-09-04T09:45:25+10:00","Lat":-33.697219,"Long":150.946111,"Heading":68.0,"Speed":45},{"Key":"sensor2","DateTime":"2013-09-04T09:45:35+10:00","Lat":-33.696919,"Long":150.947521,"Heading":89.0,"Speed":48},{"Key":"sensor2","DateTime":"2013-09-04T09:45:45+10:00","Lat":-33.697184,"Long":150.948046,"Heading":190.0,"Speed":36},{"Key":"sensor2","DateTime":"2013-09-04T09:45:55+10:00","Lat":-33.698413,"Long":150.948128,"Heading":149.0,"Speed":49},{"Key":"sensor2","DateTime":"2013-09-04T09:46:05+10:00","Lat":-33.699179,"Long":150.949118,"Heading":138.0,"Speed":41},{"Key":"sensor2","DateTime":"2013-09-04T09:46:15+10:00","Lat":-33.699896,"Long":150.950166,"Heading":115.0,"Speed":27},{"Key":"sensor2","DateTime":"2013-09-04T09:46:25+10:00","Lat":-33.699619,"Long":150.951386,"Heading":69.0,"Speed":57},{"Key":"sensor2","DateTime":"2013-09-04T09:46:35+10:00","Lat":-33.699071,"Long":150.951633,"Heading":353.0,"Speed":45},{"Key":"sensor2","DateTime":"2013-09-04T09:46:45+10:00","Lat":-33.697946,"Long":150.950795,"Heading":311.0,"Speed":57},{"Key":"sensor2","DateTime":"2013-09-04T09:46:55+10:00","Lat":-33.697844,"Long":150.949824,"Heading":247.0,"Speed":44},{"Key":"sensor2","DateTime":"2013-09-04T09:47:05+10:00","Lat":-33.697846,"Long":150.948998,"Heading":334.0,"Speed":27}];
@marufbd
Copy link
Author

marufbd commented Oct 28, 2013

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment