Created
September 27, 2010 20:09
-
-
Save RandomEtc/599724 to your computer and use it in GitHub Desktop.
Modest Maps JS - Smooth Efficient Zooming and Panning
This file contains 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
http://www.win.tue.nl/~vanwijk/zoompan.pdf for Modest Maps JS |
This file contains 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
<html> | |
<head> | |
<title>Modest Maps JS - Smooth Efficient Zooming and Panning</title> | |
<script type="text/javascript" src="http://github.com/stamen/modestmaps-js/raw/master/modestmaps.js"></script> | |
<script type="text/javascript"> | |
var map; | |
function initMap() { | |
var container = document.getElementById('container'); | |
var template = 'http://{S}tile.openstreetmap.org/{Z}/{X}/{Y}.png'; | |
var subdomains = [ 'a.', 'b.', 'c.', '']; | |
var provider = new com.modestmaps.TemplatedMapProvider(template, subdomains); | |
map = new com.modestmaps.Map('map', provider); | |
map.setCenterZoom(new com.modestmaps.Location(37.811530, -122.2666097), 14); | |
animateCenterZoom(new com.modestmaps.Location(51.514, -0.113), 18); | |
} | |
function animateCenterZoom(l1, z1) { | |
var start = map.provider.locationCoordinate(map.getCenter()).zoomTo(0), | |
end = map.provider.locationCoordinate(l1).zoomTo(0); | |
var c0 = { x: start.column, y: start.row }, | |
c1 = { x: end.column, y: end.row }; | |
// how much world can we see at zoom 0? | |
var topLeft = map.pointCoordinate(new com.modestmaps.Point(0,0)).zoomTo(0); | |
var bottomRight = map.pointCoordinate(map.dimensions).zoomTo(0); | |
var w0 = Math.max(bottomRight.column-topLeft.column, bottomRight.row-topLeft.row); | |
// z1 is ds times bigger than this zoom: | |
var ds = Math.pow(2, z1 - map.getZoom()); | |
// so how much world at zoom z1? | |
var w1 = w0 / ds; | |
// GO! | |
animateStep(c0, w0, c1, w1); | |
} | |
/* | |
From "Smooth and efficient zooming and panning" | |
by Jarke J. van Wijk and Wim A.A. Nuij | |
You only need to understand section 3 (equations 1 through 5) | |
and then you can skip to equation 9, implemented below: | |
*/ | |
function sq(n) { return n*n; } | |
function dist(a,b) { return Math.sqrt(sq(b.x-a.x)+sq(b.y-a.y)); } | |
function lerp1(a,b,p) { return a + ((b-a) * p) } | |
function lerp2(a,b,p) { return { x: lerp1(a.x,b.x,p), y: lerp1(a.y,b.y,p) }; } | |
function cosh(x) { return (Math.pow(Math.E,x) + Math.pow(Math.E,-x)) / 2; } | |
function sinh(x) { return (Math.pow(Math.E,x) - Math.pow(Math.E,-x)) / 2; } | |
function tanh(x) { return sinh(x) / cosh(x); } | |
function animateStep(c0,w0,c1,w1,V,rho) { | |
// see section 6 for user testing to derive these values (they can be tuned) | |
if (V === undefined) V = 0.9; | |
if (rho === undefined) rho = 1.42 | |
// simple interpolation of positions will be fine: | |
var u0 = 0, | |
u1 = dist(c0,c1); | |
// i = 0 or 1 | |
function b(i) { | |
var n = sq(w1) - sq(w0) + ((i ? -1 : 1) * Math.pow(rho,4) * sq(u1-u0)); | |
var d = 2 * (i ? w1 : w0) * sq(rho) * (u1-u0); | |
return n / d; | |
} | |
// give this a b(0) or b(1) | |
function r(b) { | |
return Math.log(-b + Math.sqrt(sq(b)+1)); | |
} | |
var r0 = r(b(0)), | |
r1 = r(b(1)), | |
S = (r1-r0) / rho; // "distance" | |
function u(s) { | |
var a = w0/sq(rho), | |
b = a * cosh(r0) * tanh(rho*s + r0), | |
c = a * sinh(r0); | |
return b - c + u0; | |
} | |
function w(s) { | |
return w0 * cosh(r0) / cosh(rho*s + r0); | |
} | |
var t0 = Date.now(); | |
var interval = setInterval(function() { | |
var t1 = Date.now(); | |
var t = (t1 - t0) / 1000.0; | |
var s = V * t; | |
if (s > S) { | |
s = S; | |
clearInterval(interval); | |
} | |
var us = u(s); | |
var pos = lerp2(c0,c1,(us-u0)/(u1-u0)); | |
applyPos(pos, w(s)); | |
}, 40); | |
} | |
function applyPos(pos,w) { | |
var c = new com.modestmaps.Coordinate(pos.y,pos.x,0); | |
var l = map.provider.coordinateLocation(c); | |
// how much world can we see at zoom 0? | |
var topLeft = map.pointCoordinate(new com.modestmaps.Point(0,0)).zoomTo(0); | |
var bottomRight = map.pointCoordinate(map.dimensions).zoomTo(0); | |
var w0 = Math.max(bottomRight.column-topLeft.column, bottomRight.row-topLeft.row); | |
// so what's our new zoom? | |
var z = map.getZoom() + (Math.log(w0/w) / Math.LN2) | |
map.setCenterZoom(l,z); | |
} | |
</script> | |
<style type="text/css"> | |
body { | |
margin: 0; | |
padding: 0; | |
border: 0 | |
} | |
#map { | |
width: 100%; | |
height: 100%; | |
} | |
</style> | |
</head> | |
<body onload="initMap()"> | |
<div id="map"> | |
</div> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment