Skip to content

Instantly share code, notes, and snippets.

@jrgcubano
Forked from donmccurdy/.block
Created December 20, 2018 17:54
Show Gist options
  • Save jrgcubano/8ff2ca665db42f6d073e283aa88af918 to your computer and use it in GitHub Desktop.
Save jrgcubano/8ff2ca665db42f6d073e283aa88af918 to your computer and use it in GitHub Desktop.
Google Maps + D3 Overlay
license: mit

Google Maps, with a random SVG overlay drawn by D3.

References:

Google Maps API Constraints

  • draw() is not called when map pans, only on zoom.
  • None of the layers are sized reasonably for a WebGL context.
  • The pan events are not synced to rAF. If they're even synchronous in all browsers.

Map Styles

Forked from Neutral Blue, by Adam Krogh.

<!DOCTYPE html>
<meta charset="utf-8">
<title>Google Maps + D3 Overlay</title>
<style>
html, body {
margin: 0;
padding: 0;
background: #002732;
}
</style>
<script src="https://d3js.org/d3.v4.min.js"></script>
<body>
<div id="map" style="width: 960px; height: 500px;"></div>
<script>
window.initMap = function() {
var el = document.querySelector('#map');
var google = window.google;
// http://www.colourlovers.com/palette/937624/Dance_To_Forget
var colors = ['#FF4E50','#FC913A','#F9D423','#EDE574','#E1F5C4','#FF4E50','#FC913A','#F9D423'];
function SVGOverlay (map) {
this.map = map;
this.svg = null;
this.coords = [];
this.onPan = this.onPan.bind(this);
this.setMap(map);
}
SVGOverlay.prototype = new google.maps.OverlayView();
SVGOverlay.prototype.onAdd = function () {
this.svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
this.svg.style.position = 'absolute';
this.svg.style.top = 0;
this.svg.style.left = 0;
this.svg.style.width = '960px';
this.svg.style.height = '500px';
this.svg.style.pointerEvents = 'none';
var bounds = this.map.getBounds(),
center = bounds.getCenter(),
ne = bounds.getNorthEast(),
sw = bounds.getSouthWest();
for (var i = 0; i < 40; i++) {
this.coords.push({
id: i,
color: colors[i % colors.length],
latLng: new google.maps.LatLng(
center.lat() + (Math.random() - 0.5) * Math.abs(ne.lat() - sw.lat()),
center.lng() + (Math.random() - 0.5) * Math.abs(ne.lng() - sw.lng())
)
});
}
var proj = this.getProjection();
d3.select(this.svg)
.attr('width', 960)
.attr('height', 500)
.append('g')
.attr('class', 'coords')
.selectAll('circle')
.data(this.coords, (d) => d.id)
.enter().append('circle')
.attr('cx', (d) => proj.fromLatLngToContainerPixel(d.latLng).x)
.attr('cy', (d) => proj.fromLatLngToContainerPixel(d.latLng).y)
.attr('r', 5)
.attr('fill', (d) => d.color);
this.onPan();
document.body.appendChild(this.svg);
this.map.addListener('center_changed', this.onPan);
};
SVGOverlay.prototype.onPan = function () {
var proj = this.getProjection();
d3.select(this.svg)
.select('.coords')
.selectAll('circle')
.data(this.coords)
.attr('cx', (d) => proj.fromLatLngToContainerPixel(d.latLng).x)
.attr('cy', (d) => proj.fromLatLngToContainerPixel(d.latLng).y);
};
SVGOverlay.prototype.onRemove = function () {
this.map.removeListener('center_changed', this.onPan);
this.svg.parentNode.removeChild(this.svg);
this.svg = null;
};
SVGOverlay.prototype.draw = function () {
console.log('draw');
};
var map = new google.maps.Map(el, {
center: new google.maps.LatLng(-34.397, 150.644),
zoom: 8,
disableDefaultUI: true,
backgroundColor: '#002732'
});
fetch('map-styles.json')
.then((response) => response.json())
.then(function (styles) {
map.mapTypes.set('neutral-blue', new google.maps.StyledMapType(styles));
map.setMapTypeId('neutral-blue');
});
var overlay = new SVGOverlay(map);
};
</script>
<script src="https://maps.googleapis.com/maps/api/js?v=3&amp;libraries=places&amp;key=AIzaSyDaoLdV31Y5ls8ABBpuAQt9t8RzMDfOMiM&amp;callback=initMap"></script>
</body>
[
{
"featureType": "all",
"elementType": "labels.text",
"stylers": [
{
"visibility": "off"
}
]
},
{
"featureType": "all",
"elementType": "labels.text.fill",
"stylers": [
{
"color": "#ffffff"
}
]
},
{
"featureType": "all",
"elementType": "labels.text.stroke",
"stylers": [
{
"visibility": "on"
},
{
"color": "#3e606f"
},
{
"weight": 2
},
{
"gamma": 0.84
}
]
},
{
"featureType": "all",
"elementType": "labels.icon",
"stylers": [
{
"visibility": "off"
}
]
},
{
"featureType": "administrative",
"elementType": "geometry",
"stylers": [
{
"weight": 0.6
},
{
"color": "#1a3541"
}
]
},
{
"featureType": "administrative.locality",
"elementType": "labels.text",
"stylers": [
{
"visibility": "off"
}
]
},
{
"featureType": "landscape",
"elementType": "geometry",
"stylers": [
{
"color": "#2c5a71"
}
]
},
{
"featureType": "poi",
"elementType": "geometry",
"stylers": [
{
"color": "#406d80"
}
]
},
{
"featureType": "poi.park",
"elementType": "geometry",
"stylers": [
{
"color": "#2c5a71"
}
]
},
{
"featureType": "road",
"elementType": "geometry",
"stylers": [
{
"color": "#29768a"
},
{
"lightness": -37
}
]
},
{
"featureType": "transit",
"elementType": "geometry",
"stylers": [
{
"color": "#406d80"
}
]
},
{
"featureType": "water",
"elementType": "geometry",
"stylers": [
{
"color": "#193341"
}
]
}
]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment