Display global views using a Hammer projection with d3.js, everything else in a web mercator with Leaflet.js.
Edit: now with additional smoke and mirrors.
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"> | |
<link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet-0.6.3/leaflet.css" /> | |
<script src="http://cdn.leafletjs.com/leaflet-0.6.3/leaflet.js"></script> | |
<script src="http://d3js.org/d3.v3.min.js"></script> | |
<script src="http://d3js.org/d3.geo.projection.v0.min.js" charset="utf-8"></script> | |
<script src="http://d3js.org/topojson.v1.min.js"></script> | |
<style type="text/css"> | |
.countries { | |
stroke: #000; | |
fill: #FEFBFB; | |
stroke-width: 0.5; | |
} | |
#map { | |
height:500px; | |
width:100%; | |
} | |
#zoom { | |
position: absolute; | |
margin-top:10px; | |
margin-left:10px; | |
} | |
</style> | |
</head> | |
<body> | |
<div id="zoom" class="leaflet-control-zoom leaflet-bar leaflet-control"> | |
<a class="leaflet-control-zoom-in" href="#" title="Zoom in" id="zoomIn">+</a> | |
<a class="leaflet-control-zoom-out leaflet-disabled" href="#" title="Zoom out">-</a> | |
</div> | |
<div id="svgMap"></div> | |
<div id="map"></div> | |
<script type="text/javascript"> | |
var map = new L.Map('map', { | |
center: new L.LatLng(7, 0), | |
zoom: 2, | |
maxZoom:10, | |
minZoom: 2 | |
}); | |
var attrib = 'Map tiles by <a href="http://stamen.com">Stamen Design</a>, <a href="http://creativecommons.org/licenses/by/3.0">CC BY 3.0</a> — Map data © <a href="http://openstreetmap.org">OpenStreetMap</a> contributors'; | |
var stamen = new L.TileLayer('http://{s}.tile.stamen.com/toner-background/{z}/{x}/{y}.png', {attribution: attrib}).addTo(map); | |
map.on('moveend', function(d) { | |
var zoom = map.getZoom(); | |
if (zoom < 3) { | |
d3.select("#map").style("width", 0); | |
d3.select("#svgMap").style("display", "block"); | |
d3.selectAll("path").attr("d", path); | |
} | |
}); | |
d3.select("#map").style("width", 0); | |
var width = window.innerWidth, | |
height = 500; | |
var projection = d3.geo.hammer() | |
.scale(165) | |
.translate([width / 2, height / 2]) | |
.precision(.1); | |
var mercator = d3.geo.mercator() | |
.scale(165) | |
.precision(.1) | |
.translate([width / 2, height / 2]); | |
var path = d3.geo.path() | |
.projection(projection); | |
function changeMaps(mouse) { | |
var coords = mouse, | |
projected = mercator.invert(coords); | |
d3.select("#svgMap").style("display", "none"); | |
d3.select("#map").style("width", "100%"); | |
map.invalidateSize(); | |
map.setView([parseInt(projected[1]), parseInt(projected[0])], 3, {animate:false}); | |
} | |
var zoom = d3.behavior.zoom() | |
.on("zoom",function() { | |
if (d3.event.sourceEvent.wheelDelta > 0) { | |
changeMaps(d3.mouse(this)); | |
} | |
}); | |
var svg = d3.select("#svgMap").append("svg") | |
.attr("width", width) | |
.attr("height", height) | |
.call(zoom) | |
.on("click", function() { | |
changeMaps(d3.mouse(this)); | |
}); | |
svg.append("defs").append("path") | |
.datum({type: "Sphere"}) | |
.attr("id", "sphere") | |
.attr("d", path); | |
svg.append("use") | |
.attr("class", "fill") | |
.attr("xlink:href", "#sphere"); | |
d3.json("countries.json", function(error, data) { | |
svg.append("path") | |
.datum(topojson.feature(data, data.objects.countries)) | |
.attr("class", "countries") | |
.attr("d", path); | |
}); | |
d3.select("#zoomIn").on("click", function() { | |
d3.event.stopPropagation(); | |
d3.select("#svgMap").style("display", "none"); | |
d3.select("#map").style("width", "100%"); | |
map.invalidateSize(); | |
map.setView([7,0], 3, {animate:false}); | |
}); | |
</script> | |
</body> | |
</html> |