From f4c3ff1d1a946939dfaf634b041ca130ab0f7b06 Mon Sep 17 00:00:00 2001 From: Michael Bostock Date: Thu, 7 Apr 2011 20:59:35 -0700 Subject: [PATCH] Use touch event's scale and rotation fields. Thanks to @natevw, I see there are `scale` and `rotation` fields on the touch event that we can use to compute the zoom and angle offsets more easily. Also, this commit updates the example to auto-detect retina displays using the devicePixelRatio field of the current window. --- examples/iphone4/iphone4.js | 10 ++- polymaps.js | 23 +++---- polymaps.min.js | 122 ++++++++++++++++++------------------ src/Map.js | 2 +- src/Touch.js | 19 +++--- src/Transform.js | 2 +- 6 files changed, 88 insertions(+), 90 deletions(-) diff --git a/examples/iphone4/iphone4.js b/examples/iphone4/iphone4.js index c3ff69b..8401fd5 100644 --- a/examples/iphone4/iphone4.js +++ b/examples/iphone4/iphone4.js @@ -1,15 +1,19 @@ var po = org.polymaps; +// Note: po.interact has built-in touch support! var map = po.map() .container(document.getElementById("map").appendChild(po.svg("svg"))) - .add(po.interact()); // built-in touch support + .add(po.interact()); +// Compute zoom offset for retina display. +var dz = Math.log(window.devicePixelRatio || 1) / Math.LN2; + +// CloudMade image tiles, hooray! map.add(po.image() .url(po.url("http://{S}tile.cloudmade.com" + "/1a1b06b230af4efdbb989ea99e9841af" // http://cloudmade.com/register + "/998/256/{Z}/{X}/{Y}.png") - .repeat(false) .hosts(["a.", "b.", "c.", ""])) - .zoom(function(z) { return z + 1; })); // use 2x resolution tiles + .zoom(function(z) { return z + dz; })); // no compass! pinch-to-zoom ftw diff --git a/polymaps.js b/polymaps.js index 918641e..39325f3 100644 --- a/polymaps.js +++ b/polymaps.js @@ -40,7 +40,7 @@ po.transform = function(a, b, c, d, e, f) { transform.zoomFraction = function(x) { if (!arguments.length) return zoomFraction; zoomFraction = x; - zoomDelta = Math.floor(zoomFraction + Math.log(Math.sqrt(a * a + b * b + c * c + d * d)) / Math.log(2)); + zoomDelta = Math.floor(zoomFraction + Math.log(Math.sqrt(a * a + b * b + c * c + d * d)) / Math.LN2); k = Math.pow(2, -zoomDelta); return transform; }; @@ -625,7 +625,7 @@ po.map = function() { l = map.pointLocation({x: (bl.x + tr.x) / 2, y: (bl.y + tr.y) / 2}); // update the zoom level - zoom = zoom + zoomFraction - Math.log(k) / Math.log(2); + zoom = zoom + zoomFraction - Math.log(k) / Math.LN2; rezoom(); // set the new center @@ -1846,6 +1846,8 @@ po.touch = function() { container, rotate = false, last = 0, + zoom, + angle, locations = {}; // touch identifier -> location window.addEventListener("touchmove", touchmove, false); @@ -1863,7 +1865,9 @@ po.touch = function() { } last = t; - // store original touch locations + // store original zoom & touch locations + zoom = map.zoom(); + angle = map.angle(); while (++i < n) { t = e.touches[i]; locations[t.identifier] = map.pointLocation(map.mouse(t)); @@ -1887,16 +1891,9 @@ po.touch = function() { c0 = po.map.locationCoordinate(locations[t0.identifier]), c1 = po.map.locationCoordinate(locations[t1.identifier]), c2 = {row: (c0.row + c1.row) / 2, column: (c0.column + c1.column) / 2, zoom: 0}, - l2 = po.map.coordinateLocation(c2), // center location - px = p0.x - p1.x, - py = p0.y - p1.y, - dp = Math.sqrt(px * px + py * py) / 256, - cx = c0.column - c1.column, - cy = c0.row - c1.row, - dc = Math.sqrt(cx * cx + cy * cy), - z2 = Math.log(dp / dc) / Math.log(2); // zoom level - map.zoomBy(z2 - map.zoom(), p2, l2); - if (rotate) map.angle(Math.atan2(cx, cy) - Math.atan2(px, py)); + l2 = po.map.coordinateLocation(c2); // center location + map.zoomBy(Math.log(e.scale) / Math.LN2 + zoom - map.zoom(), p2, l2); + if (rotate) map.angle(e.rotation / 180 * Math.PI + angle); e.preventDefault(); break; } diff --git a/polymaps.min.js b/polymaps.min.js index ccf41c4..0230fa8 100644 --- a/polymaps.min.js +++ b/polymaps.min.js @@ -1,65 +1,65 @@ if(!org)var org={};if(!org.polymaps)org.polymaps={}; (function(r){function fa(d){var h=d.indexOf(":");return h<0?d:{space:r.ns[d.substring(0,h)],local:d.substring(h+1)}}function S(){for(var d=0;dh.row){var a=d;d=h;h=a}return{x0:d.column,y0:d.row,x1:h.column,y1:h.row,dx:h.column-d.column,dy:h.row-d.row}}function ca(d,h,a,m,f){a=Math.max(a,Math.floor(h.y0)); -m=Math.min(m,Math.ceil(h.y1));if(d.x0==h.x0&&d.y0==h.y0?d.x0+h.dy/d.dy*d.dx0,n=h.dx<0;for(a=a;ah.dy){a=g;g=h;h=a}if(g.dy>d.dy){a=g;g=d;d=a}if(h.dy>d.dy){a=h;h=d;d=a}g.dy&&ca(d,g,m,f,c);h.dy&&ca(d,h,m,f,c)}r.version="2.4.0+1"; -var Y={x:0,y:0};r.ns={svg:"http://www.w3.org/2000/svg",xlink:"http://www.w3.org/1999/xlink"};r.id=function(){var d=0;return function(){return++d}}();r.svg=function(d){return document.createElementNS(r.ns.svg,d)};r.transform=function(d,h,a,m,f,c){var g={},j,n,o;if(!arguments.length){d=1;h=f=a=0;m=1;c=0}g.zoomFraction=function(l){if(!arguments.length)return n;n=l;j=Math.floor(n+Math.log(Math.sqrt(d*d+h*h+a*a+m*m))/Math.log(2));o=Math.pow(2,-j);return g};g.apply=function(l){var i=Math.pow(2,-l.zoom), -u=Math.pow(2,l.zoom-j);return{column:(d*l.column*i+a*l.row*i+f)*u,row:(h*l.column*i+m*l.row*i+c)*u,zoom:l.zoom-j}};g.unapply=function(l){var i=Math.pow(2,-l.zoom),u=Math.pow(2,l.zoom+j);return{column:(l.column*i*m-l.row*i*a-f*m+c*a)/(d*m-h*a)*u,row:(l.column*i*h-l.row*i*d-f*h+c*d)/(a*h-m*d)*u,zoom:l.zoom+j}};g.toString=function(){return"matrix("+[d*o,h*o,a*o,m*o].join(" ")+" 0 0)"};return g.zoomFraction(0)};r.cache=function(d,h){function a(i){l--;h&&h(i);delete g[i.key];if(i.next)i.next.prev=i.prev; -else if(n=i.prev)n.next=null;if(i.prev)i.prev.next=i.next;else if(j=i.next)j.prev=null}function m(){for(var i=n;l>o;i=i.prev){if(!i)break;i.lock||a(i)}}var f={},c={},g={},j=null,n=null,o=64,l=0;f.peek=function(i){return g[[i.zoom,i.column,i.row].join("/")]};f.load=function(i,u){var w=[i.zoom,i.column,i.row].join("/"),A=g[w];if(A){if(A.prev){if(A.prev.next=A.next)A.next.prev=A.prev;else n=A.prev;A.prev=null;A.next=j;j=j.prev=A}A.lock=1;return c[w]=A}A={key:w,column:i.column,row:i.row,zoom:i.zoom,next:j, -prev:null,lock:1};d.call(null,A,u);c[w]=g[w]=A;if(j)j.prev=A;else n=A;j=A;l++;return A};f.unload=function(i){if(!(i in c))return false;var u=c[i];u.lock=0;delete c[i];u.request&&u.request.abort(false)&&a(u);return u};f.locks=function(){return c};f.size=function(i){if(!arguments.length)return o;o=i;m();return f};f.flush=function(){m();return f};f.clear=function(){for(var i in g){var u=g[i];u.request&&u.request.abort(false);h&&h(g[i]);if(u.lock){u.lock=0;u.element.parentNode.removeChild(u.element)}}c= -{};g={};j=n=null;l=0;return f};return f};r.url=function(d){function h(f){var c=f.zoom<0?1:1<=c)return null;return d.replace(/{(.)}/g,function(j,n){switch(n){case "S":return a[(Math.abs(f.zoom)+f.row+g)%a.length];case "Z":return f.zoom;case "X":return g;case "Y":return f.row;case "B":var o=r.map.coordinateLocation({row:f.row,column:g,zoom:f.zoom}),l=r.map.coordinateLocation({row:f.row+1,column:g+1,zoom:f.zoom}),i=Math.ceil(Math.log(f.zoom)/ -Math.LN2);return l.lat.toFixed(i)+","+o.lon.toFixed(i)+","+o.lat.toFixed(i)+","+l.lon.toFixed(i)}return n})}var a=[],m=true;h.template=function(f){if(!arguments.length)return d;d=f;return h};h.hosts=function(f){if(!arguments.length)return a;a=f;return h};h.repeat=function(f){if(!arguments.length)return m;m=f;return h};return h};r.dispatch=function(d){var h={};d.on=function(a,m){for(var f=h[a]||(h[a]=[]),c=0;c=c||!m.length)){f++;m.pop()()}}function h(g){for(var j=0;ju[1])o=u[1];l=o-(o=Math.round(o));i=Math.pow(2,l)}function h(){if(q){var e=45/Math.pow(2,o+l-3),t=Math.max(Math.abs(C*g.x+A*g.y),Math.abs(B*g.x+E*g.y)),s=V(K- -t*e/j.y);t=V(k+t*e/j.y);n.lat=Math.max(s,Math.min(t,n.lat));s=Math.max(Math.abs(C*g.y+A*g.x),Math.abs(B*g.y+E*g.x));n.lon=Math.max(q[0].lon-s*e/j.x,Math.min(q[1].lon+s*e/j.x,n.lon))}}var a={},m,f,c=Y,g=Y,j={x:256,y:256},n={lat:37.76487,lon:-122.41948},o=12,l=0,i=1,u=[1,18],w=0,A=1,C=0,E=1,B=0,K=-180,k=180,q=[{lat:V(K),lon:-Infinity},{lat:V(k),lon:Infinity}];a.locationCoordinate=function(e){e=r.map.locationCoordinate(e);var t=Math.pow(2,o);e.column*=t;e.row*=t;e.zoom+=o;return e};a.coordinateLocation= -r.map.coordinateLocation;a.coordinatePoint=function(e,t){var s=Math.pow(2,o-t.zoom),z=Math.pow(2,o-e.zoom),v=(t.column*s-e.column*z)*j.x*i;s=(t.row*s-e.row*z)*j.y*i;return{x:g.x+A*v-C*s,y:g.y+C*v+A*s}};a.pointCoordinate=function(e,t){var s=Math.pow(2,o-e.zoom),z=(t.x-g.x)/i,v=(t.y-g.y)/i;return{column:e.column*s+(E*z-B*v)/j.x,row:e.row*s+(B*z+E*v)/j.y,zoom:o}};a.locationPoint=function(e){var t=Math.pow(2,o+l-3)/45,s=(e.lon-n.lon)*t*j.x;e=(W(n.lat)-W(e.lat))*t*j.y;return{x:g.x+A*s-C*e,y:g.y+C*s+A* -e}};a.pointLocation=function(e){var t=45/Math.pow(2,o+l-3),s=(e.x-g.x)*t;e=(e.y-g.y)*t;return{lon:n.lon+(E*s-B*e)/j.x,lat:V(W(n.lat)-(B*s+E*e)/j.y)}};var x=r.svg("rect");x.setAttribute("visibility","hidden");x.setAttribute("pointer-events","all");a.container=function(e){if(!arguments.length)return m;m=e;m.setAttribute("class","map");m.appendChild(x);return a.resize()};a.focusableParent=function(){for(var e=m;e;e=e.parentNode)if(e.tabIndex>=0)return e;return window};a.mouse=function(e){var t=(m.ownerSVGElement|| -m).createSVGPoint();if($<0&&(window.scrollX||window.scrollY)){var s=document.body.appendChild(r.svg("svg"));s.style.position="absolute";s.style.top=s.style.left="0px";var z=s.getScreenCTM();$=!(z.f||z.e);document.body.removeChild(s)}if($){t.x=e.pageX;t.y=e.pageY}else{t.x=e.clientX;t.y=e.clientY}return t.matrixTransform(m.getScreenCTM().inverse())};a.size=function(e){if(!arguments.length)return c;f=e;return a.resize()};a.resize=function(){if(f){c=f;S.remove(a)}else{x.setAttribute("width","100%");x.setAttribute("height", -"100%");b=x.getBBox();c={x:b.width,y:b.height};S.add(a)}x.setAttribute("width",c.x);x.setAttribute("height",c.y);g={x:c.x/2,y:c.y/2};h();a.dispatch({type:"resize"});return a};a.tileSize=function(e){if(!arguments.length)return j;j=e;a.dispatch({type:"move"});return a};a.center=function(e){if(!arguments.length)return n;n=e;h();a.dispatch({type:"move"});return a};a.panBy=function(e){var t=45/Math.pow(2,o+l-3),s=e.x*t;e=e.y*t;return a.center({lon:n.lon+(B*e-E*s)/j.x,lat:V(W(n.lat)+(B*s+E*e)/j.y)})};a.centerRange= -function(e){if(!arguments.length)return q;if(q=e){K=q[0].lat>-90?W(q[0].lat):-Infinity;k=q[0].lat<90?W(q[1].lat):Infinity}else{K=-Infinity;k=Infinity}h();a.dispatch({type:"move"});return a};a.zoom=function(e){if(!arguments.length)return o+l;o=e;d();return a.center(n)};a.zoomBy=function(e,t,s){if(arguments.length<2)return a.zoom(o+l+e);if(arguments.length<3)s=a.pointLocation(t);o=o+l+e;d();var z=a.locationPoint(s);return a.panBy({x:t.x-z.x,y:t.y-z.y})};a.zoomRange=function(e){if(!arguments.length)return u; -u=e;return a.zoom(o+l)};a.extent=function(e){if(!arguments.length)return[a.pointLocation({x:0,y:c.y}),a.pointLocation({x:c.x,y:0})];var t=a.locationPoint(e[0]),s=a.locationPoint(e[1]),z=Math.max((s.x-t.x)/c.x,(t.y-s.y)/c.y);t=a.pointLocation({x:(t.x+s.x)/2,y:(t.y+s.y)/2});o=o+l-Math.log(z)/Math.log(2);d();return a.center(t)};a.angle=function(e){if(!arguments.length)return w;w=e;A=Math.cos(w);C=Math.sin(w);E=Math.cos(-w);B=Math.sin(-w);h();a.dispatch({type:"move"});return a};a.add=function(e){e.map(a); +m=Math.min(m,Math.ceil(h.y1));if(d.x0==h.x0&&d.y0==h.y0?d.x0+h.dy/d.dy*d.dx0,o=h.dx<0;for(a=a;ah.dy){a=g;g=h;h=a}if(g.dy>d.dy){a=g;g=d;d=a}if(h.dy>d.dy){a=h;h=d;d=a}g.dy&&ca(d,g,m,f,c);h.dy&&ca(d,h,m,f,c)}r.version="2.4.0+1"; +var Y={x:0,y:0};r.ns={svg:"http://www.w3.org/2000/svg",xlink:"http://www.w3.org/1999/xlink"};r.id=function(){var d=0;return function(){return++d}}();r.svg=function(d){return document.createElementNS(r.ns.svg,d)};r.transform=function(d,h,a,m,f,c){var g={},l,o,n;if(!arguments.length){d=1;h=f=a=0;m=1;c=0}g.zoomFraction=function(k){if(!arguments.length)return o;o=k;l=Math.floor(o+Math.log(Math.sqrt(d*d+h*h+a*a+m*m))/Math.LN2);n=Math.pow(2,-l);return g};g.apply=function(k){var i=Math.pow(2,-k.zoom),s= +Math.pow(2,k.zoom-l);return{column:(d*k.column*i+a*k.row*i+f)*s,row:(h*k.column*i+m*k.row*i+c)*s,zoom:k.zoom-l}};g.unapply=function(k){var i=Math.pow(2,-k.zoom),s=Math.pow(2,k.zoom+l);return{column:(k.column*i*m-k.row*i*a-f*m+c*a)/(d*m-h*a)*s,row:(k.column*i*h-k.row*i*d-f*h+c*d)/(a*h-m*d)*s,zoom:k.zoom+l}};g.toString=function(){return"matrix("+[d*n,h*n,a*n,m*n].join(" ")+" 0 0)"};return g.zoomFraction(0)};r.cache=function(d,h){function a(i){k--;h&&h(i);delete g[i.key];if(i.next)i.next.prev=i.prev; +else if(o=i.prev)o.next=null;if(i.prev)i.prev.next=i.next;else if(l=i.next)l.prev=null}function m(){for(var i=o;k>n;i=i.prev){if(!i)break;i.lock||a(i)}}var f={},c={},g={},l=null,o=null,n=64,k=0;f.peek=function(i){return g[[i.zoom,i.column,i.row].join("/")]};f.load=function(i,s){var w=[i.zoom,i.column,i.row].join("/"),A=g[w];if(A){if(A.prev){if(A.prev.next=A.next)A.next.prev=A.prev;else o=A.prev;A.prev=null;A.next=l;l=l.prev=A}A.lock=1;return c[w]=A}A={key:w,column:i.column,row:i.row,zoom:i.zoom,next:l, +prev:null,lock:1};d.call(null,A,s);c[w]=g[w]=A;if(l)l.prev=A;else o=A;l=A;k++;return A};f.unload=function(i){if(!(i in c))return false;var s=c[i];s.lock=0;delete c[i];s.request&&s.request.abort(false)&&a(s);return s};f.locks=function(){return c};f.size=function(i){if(!arguments.length)return n;n=i;m();return f};f.flush=function(){m();return f};f.clear=function(){for(var i in g){var s=g[i];s.request&&s.request.abort(false);h&&h(g[i]);if(s.lock){s.lock=0;s.element.parentNode.removeChild(s.element)}}c= +{};g={};l=o=null;k=0;return f};return f};r.url=function(d){function h(f){var c=f.zoom<0?1:1<=c)return null;return d.replace(/{(.)}/g,function(l,o){switch(o){case "S":return a[(Math.abs(f.zoom)+f.row+g)%a.length];case "Z":return f.zoom;case "X":return g;case "Y":return f.row;case "B":var n=r.map.coordinateLocation({row:f.row,column:g,zoom:f.zoom}),k=r.map.coordinateLocation({row:f.row+1,column:g+1,zoom:f.zoom}),i=Math.ceil(Math.log(f.zoom)/ +Math.LN2);return k.lat.toFixed(i)+","+n.lon.toFixed(i)+","+n.lat.toFixed(i)+","+k.lon.toFixed(i)}return o})}var a=[],m=true;h.template=function(f){if(!arguments.length)return d;d=f;return h};h.hosts=function(f){if(!arguments.length)return a;a=f;return h};h.repeat=function(f){if(!arguments.length)return m;m=f;return h};return h};r.dispatch=function(d){var h={};d.on=function(a,m){for(var f=h[a]||(h[a]=[]),c=0;c=c||!m.length)){f++;m.pop()()}}function h(g){for(var l=0;ls[1])n=s[1];k=n-(n=Math.round(n));i=Math.pow(2,k)}function h(){if(q){var e=45/Math.pow(2,n+k-3),u=Math.max(Math.abs(C*g.x+A*g.y),Math.abs(B*g.x+E*g.y)),t=V(K- +u*e/l.y);u=V(j+u*e/l.y);o.lat=Math.max(t,Math.min(u,o.lat));t=Math.max(Math.abs(C*g.y+A*g.x),Math.abs(B*g.y+E*g.x));o.lon=Math.max(q[0].lon-t*e/l.x,Math.min(q[1].lon+t*e/l.x,o.lon))}}var a={},m,f,c=Y,g=Y,l={x:256,y:256},o={lat:37.76487,lon:-122.41948},n=12,k=0,i=1,s=[1,18],w=0,A=1,C=0,E=1,B=0,K=-180,j=180,q=[{lat:V(K),lon:-Infinity},{lat:V(j),lon:Infinity}];a.locationCoordinate=function(e){e=r.map.locationCoordinate(e);var u=Math.pow(2,n);e.column*=u;e.row*=u;e.zoom+=n;return e};a.coordinateLocation= +r.map.coordinateLocation;a.coordinatePoint=function(e,u){var t=Math.pow(2,n-u.zoom),z=Math.pow(2,n-e.zoom),v=(u.column*t-e.column*z)*l.x*i;t=(u.row*t-e.row*z)*l.y*i;return{x:g.x+A*v-C*t,y:g.y+C*v+A*t}};a.pointCoordinate=function(e,u){var t=Math.pow(2,n-e.zoom),z=(u.x-g.x)/i,v=(u.y-g.y)/i;return{column:e.column*t+(E*z-B*v)/l.x,row:e.row*t+(B*z+E*v)/l.y,zoom:n}};a.locationPoint=function(e){var u=Math.pow(2,n+k-3)/45,t=(e.lon-o.lon)*u*l.x;e=(W(o.lat)-W(e.lat))*u*l.y;return{x:g.x+A*t-C*e,y:g.y+C*t+A* +e}};a.pointLocation=function(e){var u=45/Math.pow(2,n+k-3),t=(e.x-g.x)*u;e=(e.y-g.y)*u;return{lon:o.lon+(E*t-B*e)/l.x,lat:V(W(o.lat)-(B*t+E*e)/l.y)}};var x=r.svg("rect");x.setAttribute("visibility","hidden");x.setAttribute("pointer-events","all");a.container=function(e){if(!arguments.length)return m;m=e;m.setAttribute("class","map");m.appendChild(x);return a.resize()};a.focusableParent=function(){for(var e=m;e;e=e.parentNode)if(e.tabIndex>=0)return e;return window};a.mouse=function(e){var u=(m.ownerSVGElement|| +m).createSVGPoint();if($<0&&(window.scrollX||window.scrollY)){var t=document.body.appendChild(r.svg("svg"));t.style.position="absolute";t.style.top=t.style.left="0px";var z=t.getScreenCTM();$=!(z.f||z.e);document.body.removeChild(t)}if($){u.x=e.pageX;u.y=e.pageY}else{u.x=e.clientX;u.y=e.clientY}return u.matrixTransform(m.getScreenCTM().inverse())};a.size=function(e){if(!arguments.length)return c;f=e;return a.resize()};a.resize=function(){if(f){c=f;S.remove(a)}else{x.setAttribute("width","100%");x.setAttribute("height", +"100%");b=x.getBBox();c={x:b.width,y:b.height};S.add(a)}x.setAttribute("width",c.x);x.setAttribute("height",c.y);g={x:c.x/2,y:c.y/2};h();a.dispatch({type:"resize"});return a};a.tileSize=function(e){if(!arguments.length)return l;l=e;a.dispatch({type:"move"});return a};a.center=function(e){if(!arguments.length)return o;o=e;h();a.dispatch({type:"move"});return a};a.panBy=function(e){var u=45/Math.pow(2,n+k-3),t=e.x*u;e=e.y*u;return a.center({lon:o.lon+(B*e-E*t)/l.x,lat:V(W(o.lat)+(B*t+E*e)/l.y)})};a.centerRange= +function(e){if(!arguments.length)return q;if(q=e){K=q[0].lat>-90?W(q[0].lat):-Infinity;j=q[0].lat<90?W(q[1].lat):Infinity}else{K=-Infinity;j=Infinity}h();a.dispatch({type:"move"});return a};a.zoom=function(e){if(!arguments.length)return n+k;n=e;d();return a.center(o)};a.zoomBy=function(e,u,t){if(arguments.length<2)return a.zoom(n+k+e);if(arguments.length<3)t=a.pointLocation(u);n=n+k+e;d();var z=a.locationPoint(t);return a.panBy({x:u.x-z.x,y:u.y-z.y})};a.zoomRange=function(e){if(!arguments.length)return s; +s=e;return a.zoom(n+k)};a.extent=function(e){if(!arguments.length)return[a.pointLocation({x:0,y:c.y}),a.pointLocation({x:c.x,y:0})];var u=a.locationPoint(e[0]),t=a.locationPoint(e[1]),z=Math.max((t.x-u.x)/c.x,(u.y-t.y)/c.y);u=a.pointLocation({x:(u.x+t.x)/2,y:(u.y+t.y)/2});n=n+k-Math.log(z)/Math.LN2;d();return a.center(u)};a.angle=function(e){if(!arguments.length)return w;w=e;A=Math.cos(w);C=Math.sin(w);E=Math.cos(-w);B=Math.sin(-w);h();a.dispatch({type:"move"});return a};a.add=function(e){e.map(a); return a};a.remove=function(e){e.map(null);return a};a.dispatch=r.dispatch(a);return a};S.maps=[];S.add=function(d){for(var h=0;hB;A--){u.insertBefore(C[-1],K);u.insertBefore(C[2],C[-4]);for(var k=C[2],q=2;q>-4;)C[q]=C[--q];C[q]=k}}function f(){function B(N){var H=N.zoom,T=H<0?1:1<>Q,row:T>>Q,zoom:U-Q}))&&P.ready){O[P.key]=g.load(J);P.proxyCount++;G.proxyRefs[P.key]=P;break}}O[G.key]=G}}var k=c.map(),q=k.zoom(),x=q-(q=Math.round(q)),e=k.size(),t=k.angle(),s=k.tileSize(),z=k.locationCoordinate(k.center());if(A!=q){if(Aq)m(q);else A=q;for(var v=-4;v<=2;v++){var L=C[v];L.setAttribute("class","zoom"+(v<0?"":"+")+v+" zoom"+(q+v));L.setAttribute("transform","scale("+Math.pow(2,-v)+")")}}u.setAttribute("transform", -"translate("+e.x/2+","+e.y/2+")"+(t?"rotate("+t/Math.PI*180+")":"")+(x?"scale("+Math.pow(2,x)+")":"")+(w?w.zoomFraction(x):""));var I=k.pointCoordinate(z,Y);v=k.pointCoordinate(z,{x:e.x,y:0});q=k.pointCoordinate(z,e);k=k.pointCoordinate(z,{x:0,y:e.y});if(!x&&!t&&!w){z.column=(Math.round(s.x*z.column)+(e.x&1)/2)/s.x;z.row=(Math.round(s.y*z.row)+(e.y&1)/2)/s.y}if(w){I=w.unapply(I);v=w.unapply(v);q=w.unapply(q);k=w.unapply(k);z=w.unapply(z)}var R=o?o(I.zoom)-I.zoom:0;if(R){e=Math.pow(2,R);I.column*= -e;I.row*=e;v.column*=e;v.row*=e;q.column*=e;q.row*=e;k.column*=e;k.row*=e;I.zoom=v.zoom=q.zoom=k.zoom+=R}x=g.locks();var O={};for(var F in x)x[F].proxyCount=0;if(n&&R>-5&&R<3){t=I.zoom<0?1:1<>v<>v<=1;E--)C[E]=u.appendChild(r.svg("g")); -C[0]=u.appendChild(r.svg("g"));c.map=function(B){if(!arguments.length)return i;if(i){if(i==B){u.parentNode.appendChild(u);return c}i.off("move",f).off("resize",f);u.parentNode.removeChild(u)}if(i=B){i.container().appendChild(u);c.init&&c.init(u);i.on("move",f).on("resize",f);f()}return c};c.container=function(){return u};c.levels=function(){return C};c.id=function(B){if(!arguments.length)return l;l=B;u.setAttribute("id",B);return c};c.visible=function(B){if(!arguments.length)return n;(n=B)?u.removeAttribute("visibility"): -u.setAttribute("visibility","hidden");i&&f();return c};c.transform=function(B){if(!arguments.length)return w;w=B;i&&f();return c};c.zoom=function(B){if(!arguments.length)return o;o=typeof B=="function"||B==null?B:function(){return B};i&&f();return c};c.tile=function(B){if(!arguments.length)return j;j=B;i&&f();return c};c.reload=function(){g.clear();i&&f();return c};c.dispatch=r.dispatch(c);c.on("load",function(B){if(B.tile.proxyRefs){for(var K in B.tile.proxyRefs){var k=B.tile.proxyRefs[K];--k.proxyCount<= -0&&g.unload(K)&&k.element.parentNode.removeChild(k.element)}delete B.tile.proxyRefs}});return c};r.image=function(){var d=r.layer(function(a){var m=a.element=r.svg("image"),f=d.map().tileSize();m.setAttribute("preserveAspectRatio","none");m.setAttribute("width",f.x);m.setAttribute("height",f.y);if(typeof h=="function"){m.setAttribute("opacity",0);f=h(a);if(f!=null)a.request=r.queue.image(m,f,function(c){delete a.request;a.ready=true;a.img=c;m.removeAttribute("opacity");d.dispatch({type:"load",tile:a})}); -else{a.ready=true;d.dispatch({type:"load",tile:a})}}else{a.ready=true;h!=null&&m.setAttributeNS(r.ns.xlink,"href",h);d.dispatch({type:"load",tile:a})}},function(a){a.request&&a.request.abort(true)}),h;d.url=function(a){if(!arguments.length)return h;h=typeof a=="string"&&/{.}/.test(a)?r.url(a):a;return d.reload()};return d};r.geoJson=function(d){function h(k){var q={lat:0,lon:0};return function(x){q.lat=x[1];q.lon=x[0];var e=k(q);x.x=e.x;x.y=e.y;return e}}function a(k,q){return k&&k.type in C&&C[k.type](k, -q)}function m(k,q,x){return k.type in E&&E[k.type](k,q,x)}function f(){var k=c.map().zoom(),q=c.cache.locks(),x,e,t,s,z,v,L;if(w=="fixed")for(x in q){if((e=q[x]).scale!=k){L="scale("+Math.pow(2,e.zoom-k)+")";s=-1;for(z=(t=e.features).length;++sB;A--){s.insertBefore(C[-1],K);s.insertBefore(C[2],C[-4]);for(var j=C[2],q=2;q>-4;)C[q]=C[--q];C[q]=j}}function f(){function B(N){var H=N.zoom,T=H<0?1:1<>Q,row:T>>Q,zoom:U-Q}))&&P.ready){O[P.key]=g.load(J);P.proxyCount++;G.proxyRefs[P.key]=P;break}}O[G.key]=G}}var j=c.map(),q=j.zoom(),x=q-(q=Math.round(q)),e=j.size(),u=j.angle(),t=j.tileSize(),z=j.locationCoordinate(j.center());if(A!=q){if(Aq)m(q);else A=q;for(var v=-4;v<=2;v++){var L=C[v];L.setAttribute("class","zoom"+(v<0?"":"+")+v+" zoom"+(q+v));L.setAttribute("transform","scale("+Math.pow(2,-v)+")")}}s.setAttribute("transform", +"translate("+e.x/2+","+e.y/2+")"+(u?"rotate("+u/Math.PI*180+")":"")+(x?"scale("+Math.pow(2,x)+")":"")+(w?w.zoomFraction(x):""));var I=j.pointCoordinate(z,Y);v=j.pointCoordinate(z,{x:e.x,y:0});q=j.pointCoordinate(z,e);j=j.pointCoordinate(z,{x:0,y:e.y});if(!x&&!u&&!w){z.column=(Math.round(t.x*z.column)+(e.x&1)/2)/t.x;z.row=(Math.round(t.y*z.row)+(e.y&1)/2)/t.y}if(w){I=w.unapply(I);v=w.unapply(v);q=w.unapply(q);j=w.unapply(j);z=w.unapply(z)}var R=n?n(I.zoom)-I.zoom:0;if(R){e=Math.pow(2,R);I.column*= +e;I.row*=e;v.column*=e;v.row*=e;q.column*=e;q.row*=e;j.column*=e;j.row*=e;I.zoom=v.zoom=q.zoom=j.zoom+=R}x=g.locks();var O={};for(var F in x)x[F].proxyCount=0;if(o&&R>-5&&R<3){u=I.zoom<0?1:1<>v<>v<=1;E--)C[E]=s.appendChild(r.svg("g")); +C[0]=s.appendChild(r.svg("g"));c.map=function(B){if(!arguments.length)return i;if(i){if(i==B){s.parentNode.appendChild(s);return c}i.off("move",f).off("resize",f);s.parentNode.removeChild(s)}if(i=B){i.container().appendChild(s);c.init&&c.init(s);i.on("move",f).on("resize",f);f()}return c};c.container=function(){return s};c.levels=function(){return C};c.id=function(B){if(!arguments.length)return k;k=B;s.setAttribute("id",B);return c};c.visible=function(B){if(!arguments.length)return o;(o=B)?s.removeAttribute("visibility"): +s.setAttribute("visibility","hidden");i&&f();return c};c.transform=function(B){if(!arguments.length)return w;w=B;i&&f();return c};c.zoom=function(B){if(!arguments.length)return n;n=typeof B=="function"||B==null?B:function(){return B};i&&f();return c};c.tile=function(B){if(!arguments.length)return l;l=B;i&&f();return c};c.reload=function(){g.clear();i&&f();return c};c.dispatch=r.dispatch(c);c.on("load",function(B){if(B.tile.proxyRefs){for(var K in B.tile.proxyRefs){var j=B.tile.proxyRefs[K];--j.proxyCount<= +0&&g.unload(K)&&j.element.parentNode.removeChild(j.element)}delete B.tile.proxyRefs}});return c};r.image=function(){var d=r.layer(function(a){var m=a.element=r.svg("image"),f=d.map().tileSize();m.setAttribute("preserveAspectRatio","none");m.setAttribute("width",f.x);m.setAttribute("height",f.y);if(typeof h=="function"){m.setAttribute("opacity",0);f=h(a);if(f!=null)a.request=r.queue.image(m,f,function(c){delete a.request;a.ready=true;a.img=c;m.removeAttribute("opacity");d.dispatch({type:"load",tile:a})}); +else{a.ready=true;d.dispatch({type:"load",tile:a})}}else{a.ready=true;h!=null&&m.setAttributeNS(r.ns.xlink,"href",h);d.dispatch({type:"load",tile:a})}},function(a){a.request&&a.request.abort(true)}),h;d.url=function(a){if(!arguments.length)return h;h=typeof a=="string"&&/{.}/.test(a)?r.url(a):a;return d.reload()};return d};r.geoJson=function(d){function h(j){var q={lat:0,lon:0};return function(x){q.lat=x[1];q.lon=x[0];var e=j(q);x.x=e.x;x.y=e.y;return e}}function a(j,q){return j&&j.type in C&&C[j.type](j, +q)}function m(j,q,x){return j.type in E&&E[j.type](j,q,x)}function f(){var j=c.map().zoom(),q=c.cache.locks(),x,e,u,t,z,v,L;if(w=="fixed")for(x in q){if((e=q[x]).scale!=j){L="scale("+Math.pow(2,e.zoom-j)+")";t=-1;for(z=(u=e.features).length;++t9&&Math.abs(l.wheelDelta)/w>=50)ba=1;f=u}if(ba==1)i*=0.03;if(!c&&i){u=Date.now();if(u-m>200){i=i>0?+1:-1;m= -u}else i=0}if(i)switch(g){case "mouse":u=n.mouse(l);j||(j=n.pointLocation(u));n.off("move",d).zoomBy(i,u,j).on("move",d);break;case "location":n.zoomBy(i,n.locationPoint(j),j);break;default:n.zoomBy(i);break}l.preventDefault();return false}var a={},m=0,f=0,c=true,g="mouse",j,n,o;a.smooth=function(l){if(!arguments.length)return c;c=l;return a};a.zoom=function(l,i){if(!arguments.length)return g;g=l;j=i;if(n)g=="mouse"?n.on("move",d):n.off("move",d);return a};a.map=function(l){if(!arguments.length)return n; -if(n){o.removeEventListener("mousemove",d,false);o.removeEventListener("mousewheel",h,false);o.removeEventListener("DOMMouseScroll",h,false);o=null;n.off("move",d)}if(n=l){g=="mouse"&&n.on("move",d);o=n.container();o.addEventListener("mousemove",d,false);o.addEventListener("mousewheel",h,false);o.addEventListener("DOMMouseScroll",h,false)}return a};return a};var ba=/WebKit\/533/.test(navigator.userAgent)?-1:0;r.arrow=function(){function d(w){if(!(w.ctrlKey||w.altKey||w.metaKey)){var A=Date.now(), -C=0,E=0;switch(w.keyCode){case 37:if(!c.left){g=A;c.left=1;c.right||(C=l)}break;case 39:if(!c.right){g=A;c.right=1;c.left||(C=-l)}break;case 38:if(!c.up){g=A;c.up=1;c.down||(E=l)}break;case 40:if(!c.down){g=A;c.down=1;c.up||(E=-l)}break;default:return}if(C||E)i.panBy({x:C,y:E});if(!j&&c.left|c.right|c.up|c.down)j=setInterval(m,o);w.preventDefault()}}function h(w){g=Date.now();switch(w.keyCode){case 37:c.left=0;break;case 39:c.right=0;break;case 38:c.up=0;break;case 40:c.down=0;break;default:return}if(j&& -!(c.left|c.right|c.up|c.down))j=clearInterval(j);w.preventDefault()}function a(w){switch(w.charCode){case 45:case 95:i.zoom(Math.ceil(i.zoom())-1);break;case 43:case 61:i.zoom(Math.floor(i.zoom())+1);break;default:return}w.preventDefault()}function m(){if(i)if(!(Date.now()x+e&&H.panBy(R)}function a(y){if(y.shiftKey){F={x0:H.mouse(y)};H.focusableParent().focus();return l(y)}}function m(y){if(F){F.x1=H.mouse(y);N.setAttribute("x",Math.min(F.x0.x,F.x1.x));N.setAttribute("y",Math.min(F.x0.y,F.x1.y));N.setAttribute("width",Math.abs(F.x0.x-F.x1.x));N.setAttribute("height", -Math.abs(F.x0.y-F.x1.y));N.removeAttribute("display")}}function f(){B.setAttribute("class","compass");if(F){if(F.x1){H.extent([H.pointLocation({x:Math.min(F.x0.x,F.x1.x),y:Math.max(F.x0.y,F.x1.y)}),H.pointLocation({x:Math.max(F.x0.x,F.x1.x),y:Math.min(F.x0.y,F.x1.y)})]);N.setAttribute("display","none")}F=null}if(I){clearInterval(I);I=0}}function c(y){return function(){y?this.setAttribute("class","active"):this.removeAttribute("class");R=y}}function g(y){return function(D){B.setAttribute("class","compass active"); -var G=H.zoom();H.zoom(y<0?Math.ceil(G)-1:Math.floor(G)+1);return l(D)}}function j(y){return function(D){H.zoom(y);return l(D)}}function n(){this.setAttribute("class","active")}function o(){this.removeAttribute("class")}function l(y){y.stopPropagation();y.preventDefault();return false}function i(y){var D=Math.SQRT1_2*k,G=k*0.7,J=k*0.2,M=r.svg("g"),P=M.appendChild(r.svg("path")),Q=M.appendChild(r.svg("path"));P.setAttribute("class","direction");P.setAttribute("pointer-events","all");P.setAttribute("d", -"M0,0L"+D+","+D+"A"+k+","+k+" 0 0,1 "+-D+","+D+"Z");Q.setAttribute("class","chevron");Q.setAttribute("d","M"+J+","+(G-J)+"L0,"+G+" "+-J+","+(G-J));Q.setAttribute("pointer-events","none");M.addEventListener("mousedown",d,false);M.addEventListener("mouseover",c(y),false);M.addEventListener("mouseout",c(null),false);M.addEventListener("dblclick",l,false);return M}function u(y){var D=k*0.4,G=D/2,J=r.svg("g"),M=J.appendChild(r.svg("path")),P=J.appendChild(r.svg("path")),Q=J.appendChild(r.svg("path")), -X=J.appendChild(r.svg("path"));M.setAttribute("class","back");M.setAttribute("d","M"+-D+",0V"+-D+"A"+D+","+D+" 0 1,1 "+D+","+-D+"V0Z");P.setAttribute("class","direction");P.setAttribute("d",M.getAttribute("d"));Q.setAttribute("class","chevron");Q.setAttribute("d","M"+-G+","+-D+"H"+G+(y>0?"M0,"+(-D-G)+"V"+-G:""));X.setAttribute("class","fore");X.setAttribute("fill","none");X.setAttribute("d",M.getAttribute("d"));J.addEventListener("mousedown",g(y),false);J.addEventListener("mouseover",n,false);J.addEventListener("mouseout", -o,false);J.addEventListener("dblclick",l,false);return J}function w(y){var D=k*0.2,G=k*0.4,J=r.svg("g"),M=J.appendChild(r.svg("rect")),P=J.appendChild(r.svg("path"));M.setAttribute("pointer-events","all");M.setAttribute("fill","none");M.setAttribute("x",-G);M.setAttribute("y",-0.75*G);M.setAttribute("width",2*G);M.setAttribute("height",1.5*G);P.setAttribute("class","chevron");P.setAttribute("d","M"+-D+",0H"+D);J.addEventListener("mousedown",j(y),false);J.addEventListener("dblclick",l,false);return J} -function A(){var y=k+6,D=y,G=H.size();switch(s){case "top-left":break;case "top-right":y=G.x-y;break;case "bottom-left":D=G.y-D;break;case "bottom-right":y=G.x-y;D=G.y-D;break}B.setAttribute("transform","translate("+y+","+D+")");N.setAttribute("transform","translate("+-y+","+-D+")");for(var J in K)J==H.zoom()?K[J].setAttribute("class","active"):K[J].removeAttribute("class")}function C(){for(;B.lastChild;)B.removeChild(B.lastChild);B.appendChild(N);if(L!="none"){O=B.appendChild(r.svg("g"));O.setAttribute("class", -"pan");var y=O.appendChild(r.svg("circle"));y.setAttribute("class","back");y.setAttribute("r",k);O.appendChild(i({x:0,y:-q})).setAttribute("transform","rotate(0)");O.appendChild(i({x:q,y:0})).setAttribute("transform","rotate(90)");O.appendChild(i({x:0,y:q})).setAttribute("transform","rotate(180)");O.appendChild(i({x:-q,y:0})).setAttribute("transform","rotate(270)");y=O.appendChild(r.svg("circle"));y.setAttribute("fill","none");y.setAttribute("class","fore");y.setAttribute("r",k)}else O=null;if(z!= -"none"){v=B.appendChild(r.svg("g"));v.setAttribute("class","zoom");y=-0.5;if(z=="big"){K={};var D=H.zoomRange()[0];for(y=0;D<=H.zoomRange()[1];D++,y++)(K[D]=v.appendChild(w(D))).setAttribute("transform","translate(0,"+-(y+0.75)*k*0.4+")")}D=L=="none"?0.4:2;v.setAttribute("transform","translate(0,"+k*(/^top-/.test(s)?D+(y+0.5)*0.4:-D)+")");v.appendChild(u(+1)).setAttribute("transform","translate(0,"+-(y+0.5)*k*0.4+")");v.appendChild(u(-1)).setAttribute("transform","scale(-1)")}else v=null;A()}var E= -{},B=r.svg("g"),K={},k=30,q=16,x=0,e=250,t=50,s="top-left",z="small",v,L="small",I,R,O,F,N=r.svg("rect"),H,T,U;B.setAttribute("class","compass");N.setAttribute("class","back fore");N.setAttribute("pointer-events","none");N.setAttribute("display","none");E.radius=function(y){if(!arguments.length)return k;k=y;H&&C();return E};E.speed=function(y){if(!arguments.length)return k;q=y;return E};E.position=function(y){if(!arguments.length)return s;s=y;H&&C();return E};E.pan=function(y){if(!arguments.length)return L; -L=y;H&&C();return E};E.zoom=function(y){if(!arguments.length)return z;z=y;H&&C();return E};E.map=function(y){if(!arguments.length)return H;if(H){T.removeEventListener("mousedown",a,false);T.removeChild(B);T=null;U.removeEventListener("mousemove",m,false);U.removeEventListener("mouseup",f,false);U=null;H.off("move",A).off("resize",A)}if(H=y){T=H.container();T.appendChild(B);T.addEventListener("mousedown",a,false);U=T.ownerDocument.defaultView;U.addEventListener("mousemove",m,false);U.addEventListener("mouseup", -f,false);H.on("move",A).on("resize",A);C()}return E};return E};r.grid=function(){function d(){var f=m.firstChild,c=a.size(),g=a.pointLocation(Y);a.pointLocation(c);var j=Math.pow(2,4-Math.round(a.zoom()));g.lat=Math.floor(g.lat/j)*j;g.lon=Math.ceil(g.lon/j)*j;for(var n;(n=a.locationPoint(g).x)<=c.x;g.lon+=j){f||(f=m.appendChild(r.svg("line")));f.setAttribute("x1",n);f.setAttribute("x2",n);f.setAttribute("y1",0);f.setAttribute("y2",c.y);f=f.nextSibling}for(;(n=a.locationPoint(g).y)<=c.y;g.lat-=j){f|| -(f=m.appendChild(r.svg("line")));f.setAttribute("y1",n);f.setAttribute("y2",n);f.setAttribute("x1",0);f.setAttribute("x2",c.x);f=f.nextSibling}for(;f;){c=f.nextSibling;m.removeChild(f);f=c}}var h={},a,m=r.svg("g");m.setAttribute("class","grid");h.map=function(f){if(!arguments.length)return a;if(a){m.parentNode.removeChild(m);a.off("move",d).off("resize",d)}if(a=f){a.on("move",d).on("resize",d);a.container().appendChild(m);a.dispatch({type:"move"})}return h};return h};r.stylist=function(){function d(f){var c= -f.features.length,g=h.length,j=a.length,n,o,l,i,u,w;for(u=0;u9&&Math.abs(k.wheelDelta)/w>=50)ba=1;f=s}if(ba==1)i*=0.03;if(!c&&i){s=Date.now();if(s-m>200){i=i>0?+1:-1;m= +s}else i=0}if(i)switch(g){case "mouse":s=o.mouse(k);l||(l=o.pointLocation(s));o.off("move",d).zoomBy(i,s,l).on("move",d);break;case "location":o.zoomBy(i,o.locationPoint(l),l);break;default:o.zoomBy(i);break}k.preventDefault();return false}var a={},m=0,f=0,c=true,g="mouse",l,o,n;a.smooth=function(k){if(!arguments.length)return c;c=k;return a};a.zoom=function(k,i){if(!arguments.length)return g;g=k;l=i;if(o)g=="mouse"?o.on("move",d):o.off("move",d);return a};a.map=function(k){if(!arguments.length)return o; +if(o){n.removeEventListener("mousemove",d,false);n.removeEventListener("mousewheel",h,false);n.removeEventListener("DOMMouseScroll",h,false);n=null;o.off("move",d)}if(o=k){g=="mouse"&&o.on("move",d);n=o.container();n.addEventListener("mousemove",d,false);n.addEventListener("mousewheel",h,false);n.addEventListener("DOMMouseScroll",h,false)}return a};return a};var ba=/WebKit\/533/.test(navigator.userAgent)?-1:0;r.arrow=function(){function d(w){if(!(w.ctrlKey||w.altKey||w.metaKey)){var A=Date.now(), +C=0,E=0;switch(w.keyCode){case 37:if(!c.left){g=A;c.left=1;c.right||(C=k)}break;case 39:if(!c.right){g=A;c.right=1;c.left||(C=-k)}break;case 38:if(!c.up){g=A;c.up=1;c.down||(E=k)}break;case 40:if(!c.down){g=A;c.down=1;c.up||(E=-k)}break;default:return}if(C||E)i.panBy({x:C,y:E});if(!l&&c.left|c.right|c.up|c.down)l=setInterval(m,n);w.preventDefault()}}function h(w){g=Date.now();switch(w.keyCode){case 37:c.left=0;break;case 39:c.right=0;break;case 38:c.up=0;break;case 40:c.down=0;break;default:return}if(l&& +!(c.left|c.right|c.up|c.down))l=clearInterval(l);w.preventDefault()}function a(w){switch(w.charCode){case 45:case 95:i.zoom(Math.ceil(i.zoom())-1);break;case 43:case 61:i.zoom(Math.floor(i.zoom())+1);break;default:return}w.preventDefault()}function m(){if(i)if(!(Date.now()x+e&&H.panBy(R)}function a(y){if(y.shiftKey){F={x0:H.mouse(y)};H.focusableParent().focus();return k(y)}}function m(y){if(F){F.x1=H.mouse(y);N.setAttribute("x",Math.min(F.x0.x,F.x1.x));N.setAttribute("y",Math.min(F.x0.y,F.x1.y));N.setAttribute("width",Math.abs(F.x0.x-F.x1.x));N.setAttribute("height",Math.abs(F.x0.y-F.x1.y));N.removeAttribute("display")}}function f(){B.setAttribute("class","compass"); +if(F){if(F.x1){H.extent([H.pointLocation({x:Math.min(F.x0.x,F.x1.x),y:Math.max(F.x0.y,F.x1.y)}),H.pointLocation({x:Math.max(F.x0.x,F.x1.x),y:Math.min(F.x0.y,F.x1.y)})]);N.setAttribute("display","none")}F=null}if(I){clearInterval(I);I=0}}function c(y){return function(){y?this.setAttribute("class","active"):this.removeAttribute("class");R=y}}function g(y){return function(D){B.setAttribute("class","compass active");var G=H.zoom();H.zoom(y<0?Math.ceil(G)-1:Math.floor(G)+1);return k(D)}}function l(y){return function(D){H.zoom(y); +return k(D)}}function o(){this.setAttribute("class","active")}function n(){this.removeAttribute("class")}function k(y){y.stopPropagation();y.preventDefault();return false}function i(y){var D=Math.SQRT1_2*j,G=j*0.7,J=j*0.2,M=r.svg("g"),P=M.appendChild(r.svg("path")),Q=M.appendChild(r.svg("path"));P.setAttribute("class","direction");P.setAttribute("pointer-events","all");P.setAttribute("d","M0,0L"+D+","+D+"A"+j+","+j+" 0 0,1 "+-D+","+D+"Z");Q.setAttribute("class","chevron");Q.setAttribute("d","M"+J+ +","+(G-J)+"L0,"+G+" "+-J+","+(G-J));Q.setAttribute("pointer-events","none");M.addEventListener("mousedown",d,false);M.addEventListener("mouseover",c(y),false);M.addEventListener("mouseout",c(null),false);M.addEventListener("dblclick",k,false);return M}function s(y){var D=j*0.4,G=D/2,J=r.svg("g"),M=J.appendChild(r.svg("path")),P=J.appendChild(r.svg("path")),Q=J.appendChild(r.svg("path")),X=J.appendChild(r.svg("path"));M.setAttribute("class","back");M.setAttribute("d","M"+-D+",0V"+-D+"A"+D+","+D+" 0 1,1 "+ +D+","+-D+"V0Z");P.setAttribute("class","direction");P.setAttribute("d",M.getAttribute("d"));Q.setAttribute("class","chevron");Q.setAttribute("d","M"+-G+","+-D+"H"+G+(y>0?"M0,"+(-D-G)+"V"+-G:""));X.setAttribute("class","fore");X.setAttribute("fill","none");X.setAttribute("d",M.getAttribute("d"));J.addEventListener("mousedown",g(y),false);J.addEventListener("mouseover",o,false);J.addEventListener("mouseout",n,false);J.addEventListener("dblclick",k,false);return J}function w(y){var D=j*0.2,G=j*0.4,J= +r.svg("g"),M=J.appendChild(r.svg("rect")),P=J.appendChild(r.svg("path"));M.setAttribute("pointer-events","all");M.setAttribute("fill","none");M.setAttribute("x",-G);M.setAttribute("y",-0.75*G);M.setAttribute("width",2*G);M.setAttribute("height",1.5*G);P.setAttribute("class","chevron");P.setAttribute("d","M"+-D+",0H"+D);J.addEventListener("mousedown",l(y),false);J.addEventListener("dblclick",k,false);return J}function A(){var y=j+6,D=y,G=H.size();switch(t){case "top-left":break;case "top-right":y= +G.x-y;break;case "bottom-left":D=G.y-D;break;case "bottom-right":y=G.x-y;D=G.y-D;break}B.setAttribute("transform","translate("+y+","+D+")");N.setAttribute("transform","translate("+-y+","+-D+")");for(var J in K)J==H.zoom()?K[J].setAttribute("class","active"):K[J].removeAttribute("class")}function C(){for(;B.lastChild;)B.removeChild(B.lastChild);B.appendChild(N);if(L!="none"){O=B.appendChild(r.svg("g"));O.setAttribute("class","pan");var y=O.appendChild(r.svg("circle"));y.setAttribute("class","back"); +y.setAttribute("r",j);O.appendChild(i({x:0,y:-q})).setAttribute("transform","rotate(0)");O.appendChild(i({x:q,y:0})).setAttribute("transform","rotate(90)");O.appendChild(i({x:0,y:q})).setAttribute("transform","rotate(180)");O.appendChild(i({x:-q,y:0})).setAttribute("transform","rotate(270)");y=O.appendChild(r.svg("circle"));y.setAttribute("fill","none");y.setAttribute("class","fore");y.setAttribute("r",j)}else O=null;if(z!="none"){v=B.appendChild(r.svg("g"));v.setAttribute("class","zoom");y=-0.5; +if(z=="big"){K={};var D=H.zoomRange()[0];for(y=0;D<=H.zoomRange()[1];D++,y++)(K[D]=v.appendChild(w(D))).setAttribute("transform","translate(0,"+-(y+0.75)*j*0.4+")")}D=L=="none"?0.4:2;v.setAttribute("transform","translate(0,"+j*(/^top-/.test(t)?D+(y+0.5)*0.4:-D)+")");v.appendChild(s(+1)).setAttribute("transform","translate(0,"+-(y+0.5)*j*0.4+")");v.appendChild(s(-1)).setAttribute("transform","scale(-1)")}else v=null;A()}var E={},B=r.svg("g"),K={},j=30,q=16,x=0,e=250,u=50,t="top-left",z="small",v,L= +"small",I,R,O,F,N=r.svg("rect"),H,T,U;B.setAttribute("class","compass");N.setAttribute("class","back fore");N.setAttribute("pointer-events","none");N.setAttribute("display","none");E.radius=function(y){if(!arguments.length)return j;j=y;H&&C();return E};E.speed=function(y){if(!arguments.length)return j;q=y;return E};E.position=function(y){if(!arguments.length)return t;t=y;H&&C();return E};E.pan=function(y){if(!arguments.length)return L;L=y;H&&C();return E};E.zoom=function(y){if(!arguments.length)return z; +z=y;H&&C();return E};E.map=function(y){if(!arguments.length)return H;if(H){T.removeEventListener("mousedown",a,false);T.removeChild(B);T=null;U.removeEventListener("mousemove",m,false);U.removeEventListener("mouseup",f,false);U=null;H.off("move",A).off("resize",A)}if(H=y){T=H.container();T.appendChild(B);T.addEventListener("mousedown",a,false);U=T.ownerDocument.defaultView;U.addEventListener("mousemove",m,false);U.addEventListener("mouseup",f,false);H.on("move",A).on("resize",A);C()}return E};return E}; +r.grid=function(){function d(){var f=m.firstChild,c=a.size(),g=a.pointLocation(Y);a.pointLocation(c);var l=Math.pow(2,4-Math.round(a.zoom()));g.lat=Math.floor(g.lat/l)*l;g.lon=Math.ceil(g.lon/l)*l;for(var o;(o=a.locationPoint(g).x)<=c.x;g.lon+=l){f||(f=m.appendChild(r.svg("line")));f.setAttribute("x1",o);f.setAttribute("x2",o);f.setAttribute("y1",0);f.setAttribute("y2",c.y);f=f.nextSibling}for(;(o=a.locationPoint(g).y)<=c.y;g.lat-=l){f||(f=m.appendChild(r.svg("line")));f.setAttribute("y1",o);f.setAttribute("y2", +o);f.setAttribute("x1",0);f.setAttribute("x2",c.x);f=f.nextSibling}for(;f;){c=f.nextSibling;m.removeChild(f);f=c}}var h={},a,m=r.svg("g");m.setAttribute("class","grid");h.map=function(f){if(!arguments.length)return a;if(a){m.parentNode.removeChild(m);a.off("move",d).off("resize",d)}if(a=f){a.on("move",d).on("resize",d);a.container().appendChild(m);a.dispatch({type:"move"})}return h};return h};r.stylist=function(){function d(f){var c=f.features.length,g=h.length,l=a.length,o,n,k,i,s,w;for(s=0;s location window.addEventListener("touchmove", touchmove, false); @@ -21,7 +23,9 @@ po.touch = function() { } last = t; - // store original touch locations + // store original zoom & touch locations + zoom = map.zoom(); + angle = map.angle(); while (++i < n) { t = e.touches[i]; locations[t.identifier] = map.pointLocation(map.mouse(t)); @@ -45,16 +49,9 @@ po.touch = function() { c0 = po.map.locationCoordinate(locations[t0.identifier]), c1 = po.map.locationCoordinate(locations[t1.identifier]), c2 = {row: (c0.row + c1.row) / 2, column: (c0.column + c1.column) / 2, zoom: 0}, - l2 = po.map.coordinateLocation(c2), // center location - px = p0.x - p1.x, - py = p0.y - p1.y, - dp = Math.sqrt(px * px + py * py) / 256, - cx = c0.column - c1.column, - cy = c0.row - c1.row, - dc = Math.sqrt(cx * cx + cy * cy), - z2 = Math.log(dp / dc) / Math.log(2); // zoom level - map.zoomBy(z2 - map.zoom(), p2, l2); - if (rotate) map.angle(Math.atan2(cx, cy) - Math.atan2(px, py)); + l2 = po.map.coordinateLocation(c2); // center location + map.zoomBy(Math.log(e.scale) / Math.LN2 + zoom - map.zoom(), p2, l2); + if (rotate) map.angle(e.rotation / 180 * Math.PI + angle); e.preventDefault(); break; } diff --git a/src/Transform.js b/src/Transform.js index 0cf8f98..551761a 100644 --- a/src/Transform.js +++ b/src/Transform.js @@ -12,7 +12,7 @@ po.transform = function(a, b, c, d, e, f) { transform.zoomFraction = function(x) { if (!arguments.length) return zoomFraction; zoomFraction = x; - zoomDelta = Math.floor(zoomFraction + Math.log(Math.sqrt(a * a + b * b + c * c + d * d)) / Math.log(2)); + zoomDelta = Math.floor(zoomFraction + Math.log(Math.sqrt(a * a + b * b + c * c + d * d)) / Math.LN2); k = Math.pow(2, -zoomDelta); return transform; };