Skip to content

Instantly share code, notes, and snippets.

Last active November 14, 2023 03:46
  • Star 58 You must be signed in to star a gist
  • Fork 37 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save mbostock/899711 to your computer and use it in GitHub Desktop.
Google Maps + D3
license: gpl-3.0
<!DOCTYPE html>
<meta charset="utf-8">
<meta name="viewport" content="initial-scale=1.0, user-scalable=no"/>
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;
<div id="map"></div>
<script src="//"></script>
<script src="//"></script>
// Create the Google Map…
var map = new google.maps.Map("#map").node(), {
zoom: 8,
center: new google.maps.LatLng(37.76487, -122.41948),
mapTypeId: google.maps.MapTypeId.TERRAIN
// Load the station data. When the data comes back, create an overlay.
d3.json("stations.json", function(error, data) {
if (error) throw error;
var overlay = new google.maps.OverlayView();
// Add the container when the overlay is added to the map.
overlay.onAdd = function() {
var layer ="div")
.attr("class", "stations");
// Draw each marker as a separate SVG element.
// We could use a single SVG, but what size would it have?
overlay.draw = function() {
var projection = this.getProjection(),
padding = 10;
var marker = layer.selectAll("svg")
.each(transform) // update existing markers
.attr("class", "marker");
// Add a circle.
.attr("r", 4.5)
.attr("cx", padding)
.attr("cy", padding);
// Add a label.
.attr("x", padding + 7)
.attr("y", padding)
.attr("dy", ".31em")
.text(function(d) { return d.key; });
function transform(d) {
d = new google.maps.LatLng(d.value[1], d.value[0]);
d = projection.fromLatLngToDivPixel(d);
.style("left", (d.x - padding) + "px")
.style("top", (d.y - padding) + "px");
// Bind our overlay to the map…
{"KMAE":[-120.12,36.98,"MADERA MUNICIPAL AIRPORT",[26,1,2,5,6,3,2,1,2,7,29,12,3]],"KSJC":[-121.92,37.37,"SAN JOSE INTERNATIONAL AIRPORT",[28,1,1,1,6,10,5,3,2,4,14,21,7]],"KMCE":[-120.50,37.28,"MERCED MUNICIPAL AIRPORT",[29,1,1,3,7,5,2,1,3,6,12,26,5]],"KMER":[-120.57,37.37,"Merced / Castle Air Force Base",[34,1,1,1,4,5,2,1,1,4,17,22,7]],"KAPC":[-122.28,38.20,"NAPA COUNTY AIRPORT",[23,2,1,6,3,3,8,18,11,13,4,3,5]],"KSUU":[-121.95,38.27,"Fairfield / Travis Air Force Base",[13,7,4,3,3,6,4,13,33,4,1,2,7]],"KSQL":[-122.25,37.52,"San Carlos Airport",[18,3,2,2,3,4,3,2,5,17,16,12,12]],"KSNS":[-121.60,36.67,"SALINAS MUNICIPAL AIRPORT",[21,1,1,6,12,3,1,2,9,21,17,5,1]],"KMOD":[-120.95,37.62,"MODESTO CITY CO SHAM FLD",[27,1,1,2,10,5,1,1,1,3,17,24,8]],"KOAK":[-122.23,37.72,"METRO OAKLAND INTERNATIONAL AIRPORT ",[16,3,3,2,4,6,3,4,9,23,20,6,2]],"KSCK":[-121.23,37.90,"STOCKTON METROPOLITAN AIRPORT ",[21,2,2,3,6,8,2,1,4,15,19,12,4]],"KCCR":[-122.05,38.00,"CONCORD BUCHANAN FIELD",[24,3,2,1,1,5,17,12,9,9,7,6,4]],"KMRY":[-121.85,36.58,"MONTEREY PENINSULA AIRPORT",[26,1,2,9,5,3,4,9,13,14,9,4,1]],"KPAO":[-122.12,37.47,"Palo Alto Airport",[31,3,1,1,2,5,1,1,1,4,10,25,14]],"KSAC":[-121.50,38.50,"SACRAMENTO EXECUTIVE AIRPORT ",[32,1,0,1,3,11,12,16,5,2,4,9,3]],"KHWD":[-122.12,37.67,"HAYWARD AIR TERMINAL",[20,2,7,2,2,6,3,3,6,23,18,6,2]],"KSTS":[-122.82,38.50,"SANTA ROSA SONOMA COUNTY",[46,1,0,1,5,13,10,4,3,3,4,6,3]],"KSMF":[-121.60,38.70,"SACRAMENTO INTERNATIONAL AIRPORT",[19,2,1,2,4,21,18,8,3,2,5,12,4]],"KNUQ":[-122.05,37.43,"MOFFETT FIELD",[35,3,1,1,4,7,2,1,2,5,6,17,15]],"KRHV":[-121.82,37.33,"San Jose / Reid / Hillv",[35,0,0,1,4,4,2,1,1,10,28,11,1]],"KWVI":[-121.78,36.93,"WATSONVILLE MUNICIPAL AIRPORT ",[44,1,2,3,4,5,7,9,8,4,6,5,2]],"KMHR":[-121.30,38.55,"Sacramento, Sacramento Mather Airport",[21,1,1,2,8,15,12,12,7,4,5,7,3]],"KVCB":[-121.95,38.38,"VACAVILLE NUT TREE AIRPORT",[36,2,1,1,2,6,10,18,10,2,2,5,6]],"KSFO":[-122.37,37.62,"SAN FRANCISCO INTERNATIONAL AIRPORT ",[13,3,3,2,3,4,4,4,7,31,20,2,3]],"KLVK":[-121.82,37.70,"LIVERMORE MUNICIPAL AIRPORT ",[32,2,7,3,1,1,2,7,9,17,16,2,1]]}
Copy link

This is a great example, but I really want to make it interactive and I can't figure out how to register click events with this. I'm not sure if the google map is eating them or something, but I'm stuck. My d3 approach was

marker.on('click', function(d,i){

inside overlay.onAdd, but I'm getting nothing in the console when I click. Similar results setting up listeners with or jQuery.

Any suggestions?

Copy link

mickdee commented Nov 19, 2013

Thanks for the great help nickbenes! I've made some progress with dots sized and colored according to data values for each station.

I've also got click events working to swap in new values for each station. The output to a user should look fine, but behind the scenes I'm doing this pretty sloppily at the moment.

Check out the example here:

And the code here:

My next task is getting tooltips to work. I've tried just about every way I can think of but can't successfully get mouseover events to work properly on the svg circles either with d3 or plain ol' css.

Copy link


I am new here so please accept my apologizes in advance if I am asking something wrongly. If possible I would like to ask you for help, I am using the code above in this article to plot two set of circles in a google map with some variations, so I am getting the two sets from two different files, for that I am using 2 overlays, that are added to the map separately, but it is plotting only the first set of circles, if possible could I post my code and the two files anywhere to get any help with that?

Thank you in advance.

Copy link

Has a solution been found for this mouse event problem? I also would like to create some more interaction with my graphs.

Copy link

I've implemented this and the marker shows up. However, when zooming in and out, the marker doesn't update its position (though panning works just fine). Any hint?

cc @mbostock

Copy link

ah, nm, it turns out some css style is needed. In my case, this was needed:

.stations, .stations svg {
  position: absolute;

Copy link

any examples on how to add d3 circles in real time as data is received?

Copy link

I, too, am looking for a solution to mouseover/onclick events for the svg circles. Anyone found anything?

Copy link

I ended up answering my own question. You have to make a couple changes. First make the overlayLayer an overlayMouseTarget like so:

var layer ="div") .attr("class", "stations");

I added the following attr to the circle:

marker.append("svg:circle").attr("r", 4.5).attr("cx", padding).attr("cy", padding).on("click",toggleExpand);

...and then had to define the toggleExpand() method:

function toggleExpand() { if("r") == 4.5) {"r",7) } else {"r",4.5) } }

(please forgive the formatting, I can't make the function look good)

Copy link

adamspe commented May 29, 2015

Thanks for this example it got me heading in the right direction.

I copied it (didn't fork) and made some changes for my own purposes so that I could use a single SVG instead of one per map marker and like several others mentioned so I could have my markers get mouse events (using overlayMouseTarget instead of overlayLayer.

I did a small writeup of my changes here and the end result is here.

Copy link

xvilar commented Sep 4, 2015

I've already loaded data from Elasticsearch, doing a query to ES, into an object called "resp"... I've this values:

"hits": {
"hits": [
"_source": {"location": "43.54526,-5.661926"},
"_source": {"location": "40.41669,-3.700346"}

so values from "resp.hits.hits._source.location" is what i want to draw in the map

I've tried to adapt the code with

var marker = layer.selectAll("svg")


d = new google.maps.LatLng(d.location)
d = new google.maps.LatLng(d.location[1],d.location[0])

It doens't works ¿? Thanks!

Copy link

In some cases, the map is part of a document, that contains some css like the following:
*, *::before, *::after {
box-sizing: border-box;

if you add the above css to the example, the overlay div is still placed but not rendered.
Highlighting each html svg element shows it's in the right location, but the content is not displayed.

any idea why?

Copy link

ashikvs commented Oct 25, 2017

hi mbostock, i took a copy of your code and tweaked it a little bit to get live lat and long from an api, by this i could get live tracking of my car!
but now i want just only the live locations to be plotted on the map , and aviod the trailing points, but i dont know how to remove the trailing points.. can someone tell me how?

Copy link

ashikvs commented Oct 26, 2017

i got the solution to the described problem, we have to remove the existing svg layer us9ing the folowing command"svg").remove();
Thanks anyways :)

Copy link

lipearu commented Nov 2, 2017

if i add the <div id="map"></div> inside another div, the map not show

Copy link

Can someone help me with drawing a line between two points? My main idea is to not just plot nodes but to plot a graph over a map. Since, the above code shows how to plot the nodes, can some one help me with plotting lines between the plotted nodes?
Thank you in advance.

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