Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Illustrate embedding geojson/topojson geometry into a google maps overlay using d3.geo.projection.

Based on http://bl.ocks.org/mbostock/899711 which uses D3 to draw elements into a google maps overlay layer, but doesn't use d3.geo machinery to draw map geometry. This gist illustrates how to align a D3 mercator projection with google maps so we can do standard d3 mapping stuff on top of the google API.

<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="initial-scale=1.0, user-scalable=no"/>
<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=true"></script>
<script type="text/javascript" src="http://d3js.org/d3.v3.min.js"></script>
<script type="text/javascript" src="http://d3js.org/queue.v1.min.js"></script>
<script src="http://d3js.org/topojson.v1.min.js"></script>
<style type="text/css">
html, body {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}
#map {
margin: 0;
padding: 0;
}
#d3map {
/*pointer-events: none;*/
-webkit-transform: none;
position: relative;
top: 0px;
left: 0px;
}
#countries path {
stroke-width: 1px;
vector-effect: non-scaling-stroke;
fill: none;
stroke: #333;
}
</style>
</head>
<body>
<script type="text/javascript">
var width = 600,
height = 400,
div = d3.select('body')
.append('div')
.attr('id','map')
.style('width', width + 'px')
.style('height', height + 'px');
// Create the Google Map…
var map = new google.maps.Map(div.node(), {
zoom: 2,
center: new google.maps.LatLng(37.76487, -122.41948),
mapTypeId: google.maps.MapTypeId.TERRAIN,
minZoom: 2 // stuff goes wrong if we allow world wraparound
});
// Load the data. When the data comes back, create an overlay.
queue()
.defer(d3.json, "world-110m.json")
.await(ready);
var svg, overlay;
function ready(error, world) {
var countries = topojson.feature(world, world.objects.countries).features,
land = topojson.feature(world, world.objects.land);
overlay = new google.maps.OverlayView();
overlay.onAdd = function() {
// create an SVG over top of it.
svg = d3.select(overlay.getPanes().overlayLayer)
.append('div')
.attr('id','d3map')
.style('width', width + 'px')
.style('height', height + 'px')
.append('svg')
.attr('width', width)
.attr('height', height);
svg.append('g')
.attr('id','countries')
.selectAll('path')
.data(countries)
.enter().append('path')
.attr('class','country');
overlay.draw = redraw;
google.maps.event.addListener(map, 'bounds_changed', redraw);
google.maps.event.addListener(map, 'center_changed', redraw);
};
overlay.setMap(map);
}
function redraw() {
var bounds = map.getBounds(),
ne = bounds.getNorthEast(),
sw = bounds.getSouthWest(),
projection = d3.geo.mercator()
.rotate([-bounds.getCenter().lng(),0])
.translate([0,0])
//.center([0,0])
.scale(1),
path = d3.geo.path()
.projection(projection);
var p1 = projection([ne.lng(),ne.lat()]),
p2 = projection([sw.lng(),sw.lat()]);
svg.select('#countries').attr('transform',
'scale('+width/(p1[0]-p2[0])+','+height/(p2[1]-p1[1])+')'+
'translate('+(-p2[0])+','+(-p1[1])+') ');
svg.selectAll('path').attr('d', path);
}
</script>
</body>
</html>
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
@rlancer
Copy link

rlancer commented Jul 30, 2014

It doesn't pan right.

@succinct
Copy link

succinct commented Jan 14, 2015

I'm also noticing an issue with panning. The overlay layer moves at a different scale than the underlaying map, so it "floats" on top of it. Any idea what might fix this?

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