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="//cdn.leafletjs.com/leaflet-0.6.3/leaflet.css" />
<script src="//cdn.leafletjs.com/leaflet-0.6.3/leaflet.js"></script>
<script src="//d3js.org/d3.v3.min.js"></script>
<script src="//d3js.org/d3.geo.projection.v0.min.js" charset="utf-8"></script>
<script src="//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="//stamen.com">Stamen Design</a>, <a href="//creativecommons.org/licenses/by/3.0">CC BY 3.0</a> — Map data © <a href="//openstreetmap.org">OpenStreetMap</a> contributors';
var stamen = new L.TileLayer('//{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>