Using zoom transitions with tiles.
Last active
February 14, 2016 16:59
-
-
Save jhubley/2cdd35cd2f1401412a6b to your computer and use it in GitHub Desktop.
zoom transitions with map tiles
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<meta charset="utf-8"> | |
<style> | |
body { | |
margin: 0; | |
} | |
#container { | |
position: relative; | |
overflow: hidden; | |
} | |
#map{ | |
width:100%; | |
height:100%; | |
} | |
.layer { | |
position: absolute; | |
} | |
.tile { | |
pointer-events: none; | |
position: absolute; | |
width: 256px; | |
height: 256px; | |
} | |
.info { | |
position: absolute; | |
bottom: 0px; | |
left: 0px; | |
padding: 20px; | |
background: #000; | |
color: #fff; | |
width: 100%; | |
z-index: 1000; | |
} | |
</style> | |
<body> | |
<script src="http://d3js.org/d3.v3.min.js"></script> | |
<script src="http://d3js.org/d3.geo.tile.v0.min.js"></script> | |
<div id="canvas"> | |
<div id="container"> | |
<div id="map"> | |
<div class="layer"></div> | |
</div> | |
</div> | |
</div> | |
<script> | |
var width = Math.max(960, window.innerWidth), | |
height = Math.max(500, window.innerHeight), | |
prefix = prefixMatch(["webkit", "ms", "Moz", "O"]); | |
var tile = d3.geo.tile() | |
.size([width, height]); | |
var tiles, image; | |
var sf = [-122.417, 37.775], | |
belowsf = [-122.510962, 37.580284]; | |
var projection = d3.geo.mercator() | |
.scale((1 << 18) / 2 / Math.PI) | |
.translate([width / 2, height / 2]); | |
var center = projection(sf); | |
var map = d3.select("#map"); | |
var layer = d3.select(".layer"); | |
var zoom = d3.behavior.zoom() | |
.scale(projection.scale() * 2 * Math.PI) | |
.translate([width - center[0], height - center[1]]) | |
.on("zoom", zoomed); | |
var canvas = d3.select("#canvas") | |
.style("width", width + "px") | |
.style("height", height + "px"); | |
var container = d3.select("#container") | |
.style("width", width + "px") | |
.style("height", height + "px") | |
.on("mousemove", mousemoved); | |
canvas | |
.call(zoomTo(sf).event) | |
.transition() | |
.duration(10000) | |
.each(jump); | |
var info = map.append("div") | |
.attr("class", "info"); | |
function zoomTo(place) { | |
projection = d3.geo.mercator() | |
.scale((1 << 18) / 2 / Math.PI) | |
.translate([width / 2, height / 2]) | |
center = projection(place); | |
return zoom | |
.scale(projection.scale() * 2 * Math.PI) | |
.translate([width - center[0], height - center[1]]); | |
// zoomed(); | |
} | |
function jump() { | |
var t = d3.select(this); | |
(function repeat() { | |
t = t.transition() | |
.call(zoomTo(belowsf).event) | |
.transition() | |
.call(zoomTo(sf).event) | |
.each("end", repeat); | |
})(); | |
} | |
//zoomed(); | |
function mousemoved() { | |
info.text(formatLocation(projection.invert(d3.mouse(this)), zoom.scale())); | |
} | |
function zoomed() { | |
projection | |
.scale(zoom.scale() / 2 / Math.PI) | |
.translate(zoom.translate()); | |
tiles = tile | |
.scale(zoom.scale()) | |
.translate(zoom.translate()) | |
(); | |
image = layer | |
.style(prefix + "transform", matrix3d(tiles.scale, tiles.translate)) | |
.selectAll(".tile") | |
.data(tiles, function(d) { return d; }); | |
image.exit() | |
.remove(); | |
image.enter().append("img") | |
.attr("class", "tile") | |
.attr("src", function(d) { return "http://" + ["a", "b", "c"][Math.random() * 3 | 0] + ".basemaps.cartocdn.com/light_all/" + d[2] + "/" + d[0] + "/" + d[1] + ".png"; }) | |
.style("left", function(d) { return (d[0] << 8) + "px"; }) | |
.style("top", function(d) { return (d[1] << 8) + "px"; }); | |
} | |
function matrix3d(scale, translate) { | |
var k = scale / 256, r = scale % 1 ? Number : Math.round; | |
return "matrix3d(" + [k, 0, 0, 0, 0, k, 0, 0, 0, 0, k, 0, r(translate[0] * scale), r(translate[1] * scale), 0, 1 ] + ")"; | |
} | |
function prefixMatch(p) { | |
var i = -1, n = p.length, s = document.body.style; | |
while (++i < n) if (p[i] + "Transform" in s) return "-" + p[i].toLowerCase() + "-"; | |
return ""; | |
} | |
function formatLocation(p, k) { | |
var format = d3.format("." + Math.floor(Math.log(k) / 2 - 2) + "f"); | |
return (p[1] < 0 ? format(-p[1]) + "°S" : format(p[1]) + "°N") + " " | |
+ (p[0] < 0 ? format(-p[0]) + "°W" : format(p[0]) + "°E"); | |
} | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment