polymaps/0000775000175000017500000000000011740647111011666 5ustar daviddavidpolymaps/Makefile0000664000175000017500000000137411740647057013344 0ustar daviddavidJS_FILES = \ src/start.js \ src/ns.js \ src/Id.js \ src/Svg.js \ src/Transform.js \ src/Cache.js \ src/Url.js \ src/Dispatch.js \ src/Queue.js \ src/Map.js \ src/Layer.js \ src/Image.js \ src/GeoJson.js \ src/Dblclick.js \ src/Drag.js \ src/Wheel.js \ src/Arrow.js \ src/Hash.js \ src/Touch.js \ src/Interact.js \ src/Compass.js \ src/Grid.js \ src/Stylist.js \ src/end.js JS_COMPILER = \ java -jar lib/google-compiler/compiler-20100616.jar \ --charset UTF-8 all: polymaps.min.js polymaps.js %.min.js: %.js $(JS_COMPILER) < $^ > $@ polymaps.min.js: polymaps.js rm -f $@ $(JS_COMPILER) < polymaps.js >> $@ polymaps.js: $(JS_FILES) Makefile rm -f $@ cat $(JS_FILES) >> $@ chmod a-w $@ clean: rm -rf polymaps.js polymaps.min.js polymaps/src/0000775000175000017500000000000011740644523012461 5ustar daviddavidpolymaps/src/start.js0000664000175000017500000000022011740644523014146 0ustar daviddavidif (!org) var org = {}; if (!org.polymaps) org.polymaps = {}; (function(po){ po.version = "2.5.1"; // semver.org var zero = {x: 0, y: 0}; polymaps/src/ns.js0000664000175000017500000000036611740644523013444 0ustar daviddavidpo.ns = { svg: "http://www.w3.org/2000/svg", xlink: "http://www.w3.org/1999/xlink" }; function ns(name) { var i = name.indexOf(":"); return i < 0 ? name : { space: po.ns[name.substring(0, i)], local: name.substring(i + 1) }; } polymaps/src/Cache.js0000664000175000017500000000444111740644523014025 0ustar daviddavidpo.cache = function(load, unload) { var cache = {}, locks = {}, map = {}, head = null, tail = null, size = 64, n = 0; function remove(tile) { n--; if (unload) unload(tile); delete map[tile.key]; if (tile.next) tile.next.prev = tile.prev; else if (tail = tile.prev) tail.next = null; if (tile.prev) tile.prev.next = tile.next; else if (head = tile.next) head.prev = null; } function flush() { for (var tile = tail; n > size; tile = tile.prev) { if (!tile) break; if (tile.lock) continue; remove(tile); } } cache.peek = function(c) { return map[[c.zoom, c.column, c.row].join("/")]; }; cache.load = function(c, projection) { var key = [c.zoom, c.column, c.row].join("/"), tile = map[key]; if (tile) { if (tile.prev) { tile.prev.next = tile.next; if (tile.next) tile.next.prev = tile.prev; else tail = tile.prev; tile.prev = null; tile.next = head; head.prev = tile; head = tile; } tile.lock = 1; locks[key] = tile; return tile; } tile = { key: key, column: c.column, row: c.row, zoom: c.zoom, next: head, prev: null, lock: 1 }; load.call(null, tile, projection); locks[key] = map[key] = tile; if (head) head.prev = tile; else tail = tile; head = tile; n++; return tile; }; cache.unload = function(key) { if (!(key in locks)) return false; var tile = locks[key]; tile.lock = 0; delete locks[key]; if (tile.request && tile.request.abort(false)) remove(tile); return tile; }; cache.locks = function() { return locks; }; cache.size = function(x) { if (!arguments.length) return size; size = x; flush(); return cache; }; cache.flush = function() { flush(); return cache; }; cache.clear = function() { for (var key in map) { var tile = map[key]; if (tile.request) tile.request.abort(false); if (unload) unload(map[key]); if (tile.lock) { tile.lock = 0; tile.element.parentNode.removeChild(tile.element); } } locks = {}; map = {}; head = tail = null; n = 0; return cache; }; return cache; }; polymaps/src/end.js0000664000175000017500000000002211740644523013557 0ustar daviddavid})(org.polymaps); polymaps/src/Drag.js0000664000175000017500000000213311740644523013673 0ustar daviddavidpo.drag = function() { var drag = {}, map, container, dragging; function mousedown(e) { if (e.shiftKey) return; dragging = { x: e.clientX, y: e.clientY }; map.focusableParent().focus(); e.preventDefault(); document.body.style.setProperty("cursor", "move", null); } function mousemove(e) { if (!dragging) return; map.panBy({x: e.clientX - dragging.x, y: e.clientY - dragging.y}); dragging.x = e.clientX; dragging.y = e.clientY; } function mouseup(e) { if (!dragging) return; mousemove(e); dragging = null; document.body.style.removeProperty("cursor"); } drag.map = function(x) { if (!arguments.length) return map; if (map) { container.removeEventListener("mousedown", mousedown, false); container = null; } if (map = x) { container = map.container(); container.addEventListener("mousedown", mousedown, false); } return drag; }; window.addEventListener("mousemove", mousemove, false); window.addEventListener("mouseup", mouseup, false); return drag; }; polymaps/src/Stylist.js0000664000175000017500000000325111740644523014473 0ustar daviddavidpo.stylist = function() { var attrs = [], styles = [], title; function stylist(e) { var ne = e.features.length, na = attrs.length, ns = styles.length, f, // feature d, // data o, // element x, // attr or style or title descriptor v, // attr or style or title value i, j; for (i = 0; i < ne; ++i) { if (!(o = (f = e.features[i]).element)) continue; d = f.data; for (j = 0; j < na; ++j) { v = (x = attrs[j]).value; if (typeof v === "function") v = v.call(null, d); v == null ? (x.name.local ? o.removeAttributeNS(x.name.space, x.name.local) : o.removeAttribute(x.name)) : (x.name.local ? o.setAttributeNS(x.name.space, x.name.local, v) : o.setAttribute(x.name, v)); } for (j = 0; j < ns; ++j) { v = (x = styles[j]).value; if (typeof v === "function") v = v.call(null, d); v == null ? o.style.removeProperty(x.name) : o.style.setProperty(x.name, v, x.priority); } if (v = title) { if (typeof v === "function") v = v.call(null, d); while (o.lastChild) o.removeChild(o.lastChild); if (v != null) o.appendChild(po.svg("title")).appendChild(document.createTextNode(v)); } } } stylist.attr = function(n, v) { attrs.push({name: ns(n), value: v}); return stylist; }; stylist.style = function(n, v, p) { styles.push({name: n, value: v, priority: arguments.length < 3 ? null : p}); return stylist; }; stylist.title = function(v) { title = v; return stylist; }; return stylist; }; polymaps/src/Interact.js0000664000175000017500000000057411740644523014576 0ustar daviddavid// Default map controls. po.interact = function() { var interact = {}, drag = po.drag(), wheel = po.wheel(), dblclick = po.dblclick(), touch = po.touch(), arrow = po.arrow(); interact.map = function(x) { drag.map(x); wheel.map(x); dblclick.map(x); touch.map(x); arrow.map(x); return interact; }; return interact; }; polymaps/src/Touch.js0000664000175000017500000000427311740644523014107 0ustar daviddavidpo.touch = function() { var touch = {}, map, container, rotate = false, last = 0, zoom, angle, locations = {}; // touch identifier -> location window.addEventListener("touchmove", touchmove, false); function touchstart(e) { var i = -1, n = e.touches.length, t = Date.now(); // doubletap detection if ((n == 1) && (t - last < 300)) { var z = map.zoom(); map.zoomBy(1 - z + Math.floor(z), map.mouse(e.touches[0])); e.preventDefault(); } last = t; // 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)); } } function touchmove(e) { switch (e.touches.length) { case 1: { // single-touch pan var t0 = e.touches[0]; map.zoomBy(0, map.mouse(t0), locations[t0.identifier]); e.preventDefault(); break; } case 2: { // double-touch pan + zoom + rotate var t0 = e.touches[0], t1 = e.touches[1], p0 = map.mouse(t0), p1 = map.mouse(t1), p2 = {x: (p0.x + p1.x) / 2, y: (p0.y + p1.y) / 2}, // center point 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 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; } } } touch.rotate = function(x) { if (!arguments.length) return rotate; rotate = x; return touch; }; touch.map = function(x) { if (!arguments.length) return map; if (map) { container.removeEventListener("touchstart", touchstart, false); container = null; } if (map = x) { container = map.container(); container.addEventListener("touchstart", touchstart, false); } return touch; }; return touch; }; polymaps/src/Arrow.js0000664000175000017500000000535311740644523014117 0ustar daviddavidpo.arrow = function() { var arrow = {}, key = {left: 0, right: 0, up: 0, down: 0}, last = 0, repeatTimer, repeatDelay = 250, repeatInterval = 50, speed = 16, map, parent; function keydown(e) { if (e.ctrlKey || e.altKey || e.metaKey) return; var now = Date.now(), dx = 0, dy = 0; switch (e.keyCode) { case 37: { if (!key.left) { last = now; key.left = 1; if (!key.right) dx = speed; } break; } case 39: { if (!key.right) { last = now; key.right = 1; if (!key.left) dx = -speed; } break; } case 38: { if (!key.up) { last = now; key.up = 1; if (!key.down) dy = speed; } break; } case 40: { if (!key.down) { last = now; key.down = 1; if (!key.up) dy = -speed; } break; } default: return; } if (dx || dy) map.panBy({x: dx, y: dy}); if (!repeatTimer && (key.left | key.right | key.up | key.down)) { repeatTimer = setInterval(repeat, repeatInterval); } e.preventDefault(); } function keyup(e) { last = Date.now(); switch (e.keyCode) { case 37: key.left = 0; break; case 39: key.right = 0; break; case 38: key.up = 0; break; case 40: key.down = 0; break; default: return; } if (repeatTimer && !(key.left | key.right | key.up | key.down)) { repeatTimer = clearInterval(repeatTimer); } e.preventDefault(); } function keypress(e) { switch (e.charCode) { case 45: case 95: map.zoom(Math.ceil(map.zoom()) - 1); break; // - _ case 43: case 61: map.zoom(Math.floor(map.zoom()) + 1); break; // = + default: return; } e.preventDefault(); } function repeat() { if (!map) return; if (Date.now() < last + repeatDelay) return; var dx = (key.left - key.right) * speed, dy = (key.up - key.down) * speed; if (dx || dy) map.panBy({x: dx, y: dy}); } arrow.map = function(x) { if (!arguments.length) return map; if (map) { parent.removeEventListener("keypress", keypress, false); parent.removeEventListener("keydown", keydown, false); parent.removeEventListener("keyup", keyup, false); parent = null; } if (map = x) { parent = map.focusableParent(); parent.addEventListener("keypress", keypress, false); parent.addEventListener("keydown", keydown, false); parent.addEventListener("keyup", keyup, false); } return arrow; }; arrow.speed = function(x) { if (!arguments.length) return speed; speed = x; return arrow; }; return arrow; }; polymaps/src/Dispatch.js0000664000175000017500000000165011740644523014560 0ustar daviddavidpo.dispatch = function(that) { var types = {}; that.on = function(type, handler) { var listeners = types[type] || (types[type] = []); for (var i = 0; i < listeners.length; i++) { if (listeners[i].handler == handler) return that; // already registered } listeners.push({handler: handler, on: true}); return that; }; that.off = function(type, handler) { var listeners = types[type]; if (listeners) for (var i = 0; i < listeners.length; i++) { var l = listeners[i]; if (l.handler == handler) { l.on = false; listeners.splice(i, 1); break; } } return that; }; return function(event) { var listeners = types[event.type]; if (!listeners) return; listeners = listeners.slice(); // defensive copy for (var i = 0; i < listeners.length; i++) { var l = listeners[i]; if (l.on) l.handler.call(that, event); } }; }; polymaps/src/Id.js0000664000175000017500000000012611740644523013352 0ustar daviddavidpo.id = (function() { var id = 0; return function() { return ++id; }; })(); polymaps/src/Svg.js0000664000175000017500000000012111740644523013550 0ustar daviddavidpo.svg = function(type) { return document.createElementNS(po.ns.svg, type); }; polymaps/src/Layer.js0000664000175000017500000002641711740644523014105 0ustar daviddavidpo.layer = function(load, unload) { var layer = {}, cache = layer.cache = po.cache(load, unload).size(512), tile = true, visible = true, zoom, id, map, container = po.svg("g"), transform, levelZoom, levels = {}; container.setAttribute("class", "layer"); for (var i = -4; i <= -1; i++) levels[i] = container.appendChild(po.svg("g")); for (var i = 2; i >= 1; i--) levels[i] = container.appendChild(po.svg("g")); levels[0] = container.appendChild(po.svg("g")); function zoomIn(z) { var end = levels[0].nextSibling; for (; levelZoom < z; levelZoom++) { // -4, -3, -2, -1, +2, +1, =0 // current order // -3, -2, -1, +2, +1, =0, -4 // insertBefore(-4, end) // -3, -2, -1, +1, =0, -4, +2 // insertBefore(+2, end) // -3, -2, -1, =0, -4, +2, +1 // insertBefore(+1, end) // -4, -3, -2, -1, +2, +1, =0 // relabel container.insertBefore(levels[-4], end); container.insertBefore(levels[2], end); container.insertBefore(levels[1], end); var t = levels[-4]; for (var dz = -4; dz < 2;) levels[dz] = levels[++dz]; levels[dz] = t; } } function zoomOut(z) { var end = levels[0].nextSibling; for (; levelZoom > z; levelZoom--) { // -4, -3, -2, -1, +2, +1, =0 // current order // -4, -3, -2, +2, +1, =0, -1 // insertBefore(-1, end) // +2, -4, -3, -2, +1, =0, -1 // insertBefore(+2, -4) // -4, -3, -2, -1, +2, +1, =0 // relabel container.insertBefore(levels[-1], end); container.insertBefore(levels[2], levels[-4]); var t = levels[2]; for (var dz = 2; dz > -4;) levels[dz] = levels[--dz]; levels[dz] = t; } } function move() { var map = layer.map(), // in case the layer is removed mapZoom = map.zoom(), mapZoomFraction = mapZoom - (mapZoom = Math.round(mapZoom)), mapSize = map.size(), mapAngle = map.angle(), tileSize = map.tileSize(), tileCenter = map.locationCoordinate(map.center()); // set the layer zoom levels if (levelZoom != mapZoom) { if (levelZoom < mapZoom) zoomIn(mapZoom); else if (levelZoom > mapZoom) zoomOut(mapZoom); else levelZoom = mapZoom; for (var z = -4; z <= 2; z++) { var l = levels[z]; l.setAttribute("class", "zoom" + (z < 0 ? "" : "+") + z + " zoom" + (mapZoom + z)); l.setAttribute("transform", "scale(" + Math.pow(2, -z) + ")"); } } // set the layer transform container.setAttribute("transform", "translate(" + (mapSize.x / 2) + "," + (mapSize.y / 2) + ")" + (mapAngle ? "rotate(" + mapAngle / Math.PI * 180 + ")" : "") + (mapZoomFraction ? "scale(" + Math.pow(2, mapZoomFraction) + ")" : "") + (transform ? transform.zoomFraction(mapZoomFraction) : "")); // get the coordinates of the four corners var c0 = map.pointCoordinate(tileCenter, zero), c1 = map.pointCoordinate(tileCenter, {x: mapSize.x, y: 0}), c2 = map.pointCoordinate(tileCenter, mapSize), c3 = map.pointCoordinate(tileCenter, {x: 0, y: mapSize.y}); // round to pixel boundary to avoid anti-aliasing artifacts if (!mapZoomFraction && !mapAngle && !transform) { tileCenter.column = (Math.round(tileSize.x * tileCenter.column) + (mapSize.x & 1) / 2) / tileSize.x; tileCenter.row = (Math.round(tileSize.y * tileCenter.row) + (mapSize.y & 1) / 2) / tileSize.y; } // layer-specific coordinate transform if (transform) { c0 = transform.unapply(c0); c1 = transform.unapply(c1); c2 = transform.unapply(c2); c3 = transform.unapply(c3); tileCenter = transform.unapply(tileCenter); } // layer-specific zoom transform var tileLevel = zoom ? zoom(c0.zoom) - c0.zoom : 0; if (tileLevel) { var k = Math.pow(2, tileLevel); c0.column *= k; c0.row *= k; c1.column *= k; c1.row *= k; c2.column *= k; c2.row *= k; c3.column *= k; c3.row *= k; c0.zoom = c1.zoom = c2.zoom = c3.zoom += tileLevel; } // tile-specific projection function projection(c) { var zoom = c.zoom, max = zoom < 0 ? 1 : 1 << zoom, column = c.column % max, row = c.row; if (column < 0) column += max; return { locationPoint: function(l) { var c = po.map.locationCoordinate(l), k = Math.pow(2, zoom - c.zoom); return { x: tileSize.x * (k * c.column - column), y: tileSize.y * (k * c.row - row) }; } }; } // record which tiles are visible var oldLocks = cache.locks(), newLocks = {}; // reset the proxy counts for (var key in oldLocks) { oldLocks[key].proxyCount = 0; } // load the tiles! if (visible && tileLevel > -5 && tileLevel < 3) { var ymax = c0.zoom < 0 ? 1 : 1 << c0.zoom; if (tile) { scanTriangle(c0, c1, c2, 0, ymax, scanLine); scanTriangle(c2, c3, c0, 0, ymax, scanLine); } else { var x = Math.floor((c0.column + c2.column) / 2), y = Math.max(0, Math.min(ymax - 1, Math.floor((c1.row + c3.row) / 2))), z = Math.min(4, c0.zoom); x = x >> z << z; y = y >> z << z; scanLine(x, x + 1, y); } } // scan-line conversion function scanLine(x0, x1, y) { var z = c0.zoom, z0 = 2 - tileLevel, z1 = 4 + tileLevel; for (var x = x0; x < x1; x++) { var t = cache.load({column: x, row: y, zoom: z}, projection); if (!t.ready && !(t.key in newLocks)) { t.proxyRefs = {}; var c, full, proxy; // downsample high-resolution tiles for (var dz = 1; dz <= z0; dz++) { full = true; for (var dy = 0, k = 1 << dz; dy <= k; dy++) { for (var dx = 0; dx <= k; dx++) { proxy = cache.peek(c = { column: (x << dz) + dx, row: (y << dz) + dy, zoom: z + dz }); if (proxy && proxy.ready) { newLocks[proxy.key] = cache.load(c); proxy.proxyCount++; t.proxyRefs[proxy.key] = proxy; } else { full = false; } } } if (full) break; } // upsample low-resolution tiles if (!full) { for (var dz = 1; dz <= z1; dz++) { proxy = cache.peek(c = { column: x >> dz, row: y >> dz, zoom: z - dz }); if (proxy && proxy.ready) { newLocks[proxy.key] = cache.load(c); proxy.proxyCount++; t.proxyRefs[proxy.key] = proxy; break; } } } } newLocks[t.key] = t; } } // position tiles for (var key in newLocks) { var t = newLocks[key], k = Math.pow(2, t.level = t.zoom - tileCenter.zoom); t.element.setAttribute("transform", "translate(" + (t.x = tileSize.x * (t.column - tileCenter.column * k)) + "," + (t.y = tileSize.y * (t.row - tileCenter.row * k)) + ")"); } // remove tiles that are no longer visible for (var key in oldLocks) { if (!(key in newLocks)) { var t = cache.unload(key); t.element.parentNode.removeChild(t.element); delete t.proxyRefs; } } // append tiles that are now visible for (var key in newLocks) { var t = newLocks[key]; if (t.element.parentNode != levels[t.level]) { levels[t.level].appendChild(t.element); if (layer.show) layer.show(t); } } // flush the cache, clearing no-longer-needed tiles cache.flush(); // dispatch the move event layer.dispatch({type: "move"}); } // remove proxy tiles when tiles load function cleanup(e) { if (e.tile.proxyRefs) { for (var proxyKey in e.tile.proxyRefs) { var proxyTile = e.tile.proxyRefs[proxyKey]; if ((--proxyTile.proxyCount <= 0) && cache.unload(proxyKey)) { proxyTile.element.parentNode.removeChild(proxyTile.element); } } delete e.tile.proxyRefs; } } layer.map = function(x) { if (!arguments.length) return map; if (map) { if (map == x) { container.parentNode.appendChild(container); // move to end return layer; } map.off("move", move).off("resize", move); container.parentNode.removeChild(container); } map = x; if (map) { map.container().appendChild(container); if (layer.init) layer.init(container); map.on("move", move).on("resize", move); move(); } return layer; }; layer.container = function() { return container; }; layer.levels = function() { return levels; }; layer.id = function(x) { if (!arguments.length) return id; id = x; container.setAttribute("id", x); return layer; }; layer.visible = function(x) { if (!arguments.length) return visible; if (visible = x) container.removeAttribute("visibility") else container.setAttribute("visibility", "hidden"); if (map) move(); return layer; }; layer.transform = function(x) { if (!arguments.length) return transform; transform = x; if (map) move(); return layer; }; layer.zoom = function(x) { if (!arguments.length) return zoom; zoom = typeof x == "function" || x == null ? x : function() { return x; }; if (map) move(); return layer; }; layer.tile = function(x) { if (!arguments.length) return tile; tile = x; if (map) move(); return layer; }; layer.reload = function() { cache.clear(); if (map) move(); return layer; }; layer.dispatch = po.dispatch(layer); layer.on("load", cleanup); return layer; }; // scan-line conversion function edge(a, b) { if (a.row > b.row) { var t = a; a = b; b = t; } return { x0: a.column, y0: a.row, x1: b.column, y1: b.row, dx: b.column - a.column, dy: b.row - a.row }; } // scan-line conversion function scanSpans(e0, e1, ymin, ymax, scanLine) { var y0 = Math.max(ymin, Math.floor(e1.y0)), y1 = Math.min(ymax, Math.ceil(e1.y1)); // sort edges by x-coordinate if ((e0.x0 == e1.x0 && e0.y0 == e1.y0) ? (e0.x0 + e1.dy / e0.dy * e0.dx < e1.x1) : (e0.x1 - e1.dy / e0.dy * e0.dx < e1.x0)) { var t = e0; e0 = e1; e1 = t; } // scan lines! var m0 = e0.dx / e0.dy, m1 = e1.dx / e1.dy, d0 = e0.dx > 0, // use y + 1 to compute x0 d1 = e1.dx < 0; // use y + 1 to compute x1 for (var y = y0; y < y1; y++) { var x0 = m0 * Math.max(0, Math.min(e0.dy, y + d0 - e0.y0)) + e0.x0, x1 = m1 * Math.max(0, Math.min(e1.dy, y + d1 - e1.y0)) + e1.x0; scanLine(Math.floor(x1), Math.ceil(x0), y); } } // scan-line conversion function scanTriangle(a, b, c, ymin, ymax, scanLine) { var ab = edge(a, b), bc = edge(b, c), ca = edge(c, a); // sort edges by y-length if (ab.dy > bc.dy) { var t = ab; ab = bc; bc = t; } if (ab.dy > ca.dy) { var t = ab; ab = ca; ca = t; } if (bc.dy > ca.dy) { var t = bc; bc = ca; ca = t; } // scan span! scan span! if (ab.dy) scanSpans(ca, ab, ymin, ymax, scanLine); if (bc.dy) scanSpans(ca, bc, ymin, ymax, scanLine); } polymaps/src/Grid.js0000664000175000017500000000311111740644523013700 0ustar daviddavidpo.grid = function() { var grid = {}, map, g = po.svg("g"); g.setAttribute("class", "grid"); function move(e) { var p, line = g.firstChild, size = map.size(), nw = map.pointLocation(zero), se = map.pointLocation(size), step = Math.pow(2, 4 - Math.round(map.zoom())); // Round to step. nw.lat = Math.floor(nw.lat / step) * step; nw.lon = Math.ceil(nw.lon / step) * step; // Longitude ticks. for (var x; (x = map.locationPoint(nw).x) <= size.x; nw.lon += step) { if (!line) line = g.appendChild(po.svg("line")); line.setAttribute("x1", x); line.setAttribute("x2", x); line.setAttribute("y1", 0); line.setAttribute("y2", size.y); line = line.nextSibling; } // Latitude ticks. for (var y; (y = map.locationPoint(nw).y) <= size.y; nw.lat -= step) { if (!line) line = g.appendChild(po.svg("line")); line.setAttribute("y1", y); line.setAttribute("y2", y); line.setAttribute("x1", 0); line.setAttribute("x2", size.x); line = line.nextSibling; } // Remove extra ticks. while (line) { var next = line.nextSibling; g.removeChild(line); line = next; } } grid.map = function(x) { if (!arguments.length) return map; if (map) { g.parentNode.removeChild(g); map.off("move", move).off("resize", move); } if (map = x) { map.on("move", move).on("resize", move); map.container().appendChild(g); map.dispatch({type: "move"}); } return grid; }; return grid; }; polymaps/src/Image.js0000664000175000017500000000236511740644523014047 0ustar daviddavidpo.image = function() { var image = po.layer(load, unload), url; function load(tile) { var element = tile.element = po.svg("image"), size = image.map().tileSize(); element.setAttribute("preserveAspectRatio", "none"); element.setAttribute("width", size.x); element.setAttribute("height", size.y); if (typeof url == "function") { element.setAttribute("opacity", 0); var tileUrl = url(tile); if (tileUrl != null) { tile.request = po.queue.image(element, tileUrl, function(img) { delete tile.request; tile.ready = true; tile.img = img; element.removeAttribute("opacity"); image.dispatch({type: "load", tile: tile}); }); } else { tile.ready = true; image.dispatch({type: "load", tile: tile}); } } else { tile.ready = true; if (url != null) element.setAttributeNS(po.ns.xlink, "href", url); image.dispatch({type: "load", tile: tile}); } } function unload(tile) { if (tile.request) tile.request.abort(true); } image.url = function(x) { if (!arguments.length) return url; url = typeof x == "string" && /{.}/.test(x) ? po.url(x) : x; return image.reload(); }; return image; }; polymaps/src/Compass.js0000664000175000017500000002227411740644523014433 0ustar daviddavidpo.compass = function() { var compass = {}, g = po.svg("g"), ticks = {}, r = 30, speed = 16, last = 0, repeatDelay = 250, repeatInterval = 50, position = "top-left", // top-left, top-right, bottom-left, bottom-right zoomStyle = "small", // none, small, big zoomContainer, panStyle = "small", // none, small panTimer, panDirection, panContainer, drag, dragRect = po.svg("rect"), map, container, window; g.setAttribute("class", "compass"); dragRect.setAttribute("class", "back fore"); dragRect.setAttribute("pointer-events", "none"); dragRect.setAttribute("display", "none"); function panStart(e) { g.setAttribute("class", "compass active"); if (!panTimer) panTimer = setInterval(panRepeat, repeatInterval); if (panDirection) map.panBy(panDirection); last = Date.now(); return cancel(e); } function panRepeat() { if (panDirection && (Date.now() > last + repeatDelay)) { map.panBy(panDirection); } } function mousedown(e) { if (e.shiftKey) { drag = {x0: map.mouse(e)}; map.focusableParent().focus(); return cancel(e); } } function mousemove(e) { if (!drag) return; drag.x1 = map.mouse(e); dragRect.setAttribute("x", Math.min(drag.x0.x, drag.x1.x)); dragRect.setAttribute("y", Math.min(drag.x0.y, drag.x1.y)); dragRect.setAttribute("width", Math.abs(drag.x0.x - drag.x1.x)); dragRect.setAttribute("height", Math.abs(drag.x0.y - drag.x1.y)); dragRect.removeAttribute("display"); } function mouseup(e) { g.setAttribute("class", "compass"); if (drag) { if (drag.x1) { map.extent([ map.pointLocation({ x: Math.min(drag.x0.x, drag.x1.x), y: Math.max(drag.x0.y, drag.x1.y) }), map.pointLocation({ x: Math.max(drag.x0.x, drag.x1.x), y: Math.min(drag.x0.y, drag.x1.y) }) ]); dragRect.setAttribute("display", "none"); } drag = null; } if (panTimer) { clearInterval(panTimer); panTimer = 0; } } function panBy(x) { return function() { x ? this.setAttribute("class", "active") : this.removeAttribute("class"); panDirection = x; }; } function zoomBy(x) { return function(e) { g.setAttribute("class", "compass active"); var z = map.zoom(); map.zoom(x < 0 ? Math.ceil(z) - 1 : Math.floor(z) + 1); return cancel(e); }; } function zoomTo(x) { return function(e) { map.zoom(x); return cancel(e); }; } function zoomOver() { this.setAttribute("class", "active"); } function zoomOut() { this.removeAttribute("class"); } function cancel(e) { e.stopPropagation(); e.preventDefault(); return false; } function pan(by) { var x = Math.SQRT1_2 * r, y = r * .7, z = r * .2, g = po.svg("g"), dir = g.appendChild(po.svg("path")), chv = g.appendChild(po.svg("path")); dir.setAttribute("class", "direction"); dir.setAttribute("pointer-events", "all"); dir.setAttribute("d", "M0,0L" + x + "," + x + "A" + r + "," + r + " 0 0,1 " + -x + "," + x + "Z"); chv.setAttribute("class", "chevron"); chv.setAttribute("d", "M" + z + "," + (y - z) + "L0," + y + " " + -z + "," + (y - z)); chv.setAttribute("pointer-events", "none"); g.addEventListener("mousedown", panStart, false); g.addEventListener("mouseover", panBy(by), false); g.addEventListener("mouseout", panBy(null), false); g.addEventListener("dblclick", cancel, false); return g; } function zoom(by) { var x = r * .4, y = x / 2, g = po.svg("g"), back = g.appendChild(po.svg("path")), dire = g.appendChild(po.svg("path")), chev = g.appendChild(po.svg("path")), fore = g.appendChild(po.svg("path")); back.setAttribute("class", "back"); back.setAttribute("d", "M" + -x + ",0V" + -x + "A" + x + "," + x + " 0 1,1 " + x + "," + -x + "V0Z"); dire.setAttribute("class", "direction"); dire.setAttribute("d", back.getAttribute("d")); chev.setAttribute("class", "chevron"); chev.setAttribute("d", "M" + -y + "," + -x + "H" + y + (by > 0 ? "M0," + (-x - y) + "V" + -y : "")); fore.setAttribute("class", "fore"); fore.setAttribute("fill", "none"); fore.setAttribute("d", back.getAttribute("d")); g.addEventListener("mousedown", zoomBy(by), false); g.addEventListener("mouseover", zoomOver, false); g.addEventListener("mouseout", zoomOut, false); g.addEventListener("dblclick", cancel, false); return g; } function tick(i) { var x = r * .2, y = r * .4, g = po.svg("g"), back = g.appendChild(po.svg("rect")), chev = g.appendChild(po.svg("path")); back.setAttribute("pointer-events", "all"); back.setAttribute("fill", "none"); back.setAttribute("x", -y); back.setAttribute("y", -.75 * y); back.setAttribute("width", 2 * y); back.setAttribute("height", 1.5 * y); chev.setAttribute("class", "chevron"); chev.setAttribute("d", "M" + -x + ",0H" + x); g.addEventListener("mousedown", zoomTo(i), false); g.addEventListener("dblclick", cancel, false); return g; } function move() { var x = r + 6, y = x, size = map.size(); switch (position) { case "top-left": break; case "top-right": x = size.x - x; break; case "bottom-left": y = size.y - y; break; case "bottom-right": x = size.x - x; y = size.y - y; break; } g.setAttribute("transform", "translate(" + x + "," + y + ")"); dragRect.setAttribute("transform", "translate(" + -x + "," + -y + ")"); for (var i in ticks) { i == map.zoom() ? ticks[i].setAttribute("class", "active") : ticks[i].removeAttribute("class"); } } function draw() { while (g.lastChild) g.removeChild(g.lastChild); g.appendChild(dragRect); if (panStyle != "none") { panContainer = g.appendChild(po.svg("g")); panContainer.setAttribute("class", "pan"); var back = panContainer.appendChild(po.svg("circle")); back.setAttribute("class", "back"); back.setAttribute("r", r); var s = panContainer.appendChild(pan({x: 0, y: -speed})); s.setAttribute("transform", "rotate(0)"); var w = panContainer.appendChild(pan({x: speed, y: 0})); w.setAttribute("transform", "rotate(90)"); var n = panContainer.appendChild(pan({x: 0, y: speed})); n.setAttribute("transform", "rotate(180)"); var e = panContainer.appendChild(pan({x: -speed, y: 0})); e.setAttribute("transform", "rotate(270)"); var fore = panContainer.appendChild(po.svg("circle")); fore.setAttribute("fill", "none"); fore.setAttribute("class", "fore"); fore.setAttribute("r", r); } else { panContainer = null; } if (zoomStyle != "none") { zoomContainer = g.appendChild(po.svg("g")); zoomContainer.setAttribute("class", "zoom"); var j = -.5; if (zoomStyle == "big") { ticks = {}; for (var i = map.zoomRange()[0], j = 0; i <= map.zoomRange()[1]; i++, j++) { (ticks[i] = zoomContainer.appendChild(tick(i))) .setAttribute("transform", "translate(0," + (-(j + .75) * r * .4) + ")"); } } var p = panStyle == "none" ? .4 : 2; zoomContainer.setAttribute("transform", "translate(0," + r * (/^top-/.test(position) ? (p + (j + .5) * .4) : -p) + ")"); zoomContainer.appendChild(zoom(+1)).setAttribute("transform", "translate(0," + (-(j + .5) * r * .4) + ")"); zoomContainer.appendChild(zoom(-1)).setAttribute("transform", "scale(-1)"); } else { zoomContainer = null; } move(); } compass.radius = function(x) { if (!arguments.length) return r; r = x; if (map) draw(); return compass; }; compass.speed = function(x) { if (!arguments.length) return r; speed = x; return compass; }; compass.position = function(x) { if (!arguments.length) return position; position = x; if (map) draw(); return compass; }; compass.pan = function(x) { if (!arguments.length) return panStyle; panStyle = x; if (map) draw(); return compass; }; compass.zoom = function(x) { if (!arguments.length) return zoomStyle; zoomStyle = x; if (map) draw(); return compass; }; compass.map = function(x) { if (!arguments.length) return map; if (map) { container.removeEventListener("mousedown", mousedown, false); container.removeChild(g); container = null; window.removeEventListener("mousemove", mousemove, false); window.removeEventListener("mouseup", mouseup, false); window = null; map.off("move", move).off("resize", move); } if (map = x) { container = map.container(); container.appendChild(g); container.addEventListener("mousedown", mousedown, false); window = container.ownerDocument.defaultView; window.addEventListener("mousemove", mousemove, false); window.addEventListener("mouseup", mouseup, false); map.on("move", move).on("resize", move); draw(); } return compass; }; return compass; }; polymaps/src/Wheel.js0000664000175000017500000000574611740644523014077 0ustar daviddavidpo.wheel = function() { var wheel = {}, timePrev = 0, last = 0, smooth = true, zoom = "mouse", location, map, container; function move(e) { location = null; } // mousewheel events are totally broken! // https://bugs.webkit.org/show_bug.cgi?id=40441 // not only that, but Chrome and Safari differ in re. to acceleration! var inner = document.createElement("div"), outer = document.createElement("div"); outer.style.visibility = "hidden"; outer.style.top = "0px"; outer.style.height = "0px"; outer.style.width = "0px"; outer.style.overflowY = "scroll"; inner.style.height = "2000px"; outer.appendChild(inner); document.body.appendChild(outer); function mousewheel(e) { var delta = e.wheelDelta || -e.detail, point; /* Detect the pixels that would be scrolled by this wheel event. */ if (delta) { if (smooth) { try { outer.scrollTop = 1000; outer.dispatchEvent(e); delta = 1000 - outer.scrollTop; } catch (error) { // Derp! Hope for the best? } delta *= .005; } /* If smooth zooming is disabled, batch events into unit steps. */ else { var timeNow = Date.now(); if (timeNow - timePrev > 200) { delta = delta > 0 ? +1 : -1; timePrev = timeNow; } else { delta = 0; } } } if (delta) { switch (zoom) { case "mouse": { point = map.mouse(e); if (!location) location = map.pointLocation(point); map.off("move", move).zoomBy(delta, point, location).on("move", move); break; } case "location": { map.zoomBy(delta, map.locationPoint(location), location); break; } default: { // center map.zoomBy(delta); break; } } } e.preventDefault(); return false; // for Firefox } wheel.smooth = function(x) { if (!arguments.length) return smooth; smooth = x; return wheel; }; wheel.zoom = function(x, l) { if (!arguments.length) return zoom; zoom = x; location = l; if (map) { if (zoom == "mouse") map.on("move", move); else map.off("move", move); } return wheel; }; wheel.map = function(x) { if (!arguments.length) return map; if (map) { container.removeEventListener("mousemove", move, false); container.removeEventListener("mousewheel", mousewheel, false); container.removeEventListener("MozMousePixelScroll", mousewheel, false); container = null; map.off("move", move); } if (map = x) { if (zoom == "mouse") map.on("move", move); container = map.container(); container.addEventListener("mousemove", move, false); container.addEventListener("mousewheel", mousewheel, false); container.addEventListener("MozMousePixelScroll", mousewheel, false); } return wheel; }; return wheel; }; polymaps/src/Map.js0000664000175000017500000002266011740644523013542 0ustar daviddavidpo.map = function() { var map = {}, container, size, sizeActual = zero, sizeRadius = zero, // sizeActual / 2 tileSize = {x: 256, y: 256}, center = {lat: 37.76487, lon: -122.41948}, zoom = 12, zoomFraction = 0, zoomFactor = 1, // Math.pow(2, zoomFraction) zoomRange = [1, 18], angle = 0, angleCos = 1, // Math.cos(angle) angleSin = 0, // Math.sin(angle) angleCosi = 1, // Math.cos(-angle) angleSini = 0, // Math.sin(-angle) ymin = -180, // lat2y(centerRange[0].lat) ymax = 180; // lat2y(centerRange[1].lat) var centerRange = [ {lat: y2lat(ymin), lon: -Infinity}, {lat: y2lat(ymax), lon: Infinity} ]; map.locationCoordinate = function(l) { var c = po.map.locationCoordinate(l), k = Math.pow(2, zoom); c.column *= k; c.row *= k; c.zoom += zoom; return c; }; map.coordinateLocation = po.map.coordinateLocation; map.coordinatePoint = function(tileCenter, c) { var kc = Math.pow(2, zoom - c.zoom), kt = Math.pow(2, zoom - tileCenter.zoom), dx = (c.column * kc - tileCenter.column * kt) * tileSize.x * zoomFactor, dy = (c.row * kc - tileCenter.row * kt) * tileSize.y * zoomFactor; return { x: sizeRadius.x + angleCos * dx - angleSin * dy, y: sizeRadius.y + angleSin * dx + angleCos * dy }; }; map.pointCoordinate = function(tileCenter, p) { var kt = Math.pow(2, zoom - tileCenter.zoom), dx = (p.x - sizeRadius.x) / zoomFactor, dy = (p.y - sizeRadius.y) / zoomFactor; return { column: tileCenter.column * kt + (angleCosi * dx - angleSini * dy) / tileSize.x, row: tileCenter.row * kt + (angleSini * dx + angleCosi * dy) / tileSize.y, zoom: zoom }; }; map.locationPoint = function(l) { var k = Math.pow(2, zoom + zoomFraction - 3) / 45, dx = (l.lon - center.lon) * k * tileSize.x, dy = (lat2y(center.lat) - lat2y(l.lat)) * k * tileSize.y; return { x: sizeRadius.x + angleCos * dx - angleSin * dy, y: sizeRadius.y + angleSin * dx + angleCos * dy }; }; map.pointLocation = function(p) { var k = 45 / Math.pow(2, zoom + zoomFraction - 3), dx = (p.x - sizeRadius.x) * k, dy = (p.y - sizeRadius.y) * k; return { lon: center.lon + (angleCosi * dx - angleSini * dy) / tileSize.x, lat: y2lat(lat2y(center.lat) - (angleSini * dx + angleCosi * dy) / tileSize.y) }; }; function rezoom() { if (zoomRange) { if (zoom < zoomRange[0]) zoom = zoomRange[0]; else if (zoom > zoomRange[1]) zoom = zoomRange[1]; } zoomFraction = zoom - (zoom = Math.round(zoom)); zoomFactor = Math.pow(2, zoomFraction); } function recenter() { if (!centerRange) return; var k = 45 / Math.pow(2, zoom + zoomFraction - 3); // constrain latitude var y = Math.max(Math.abs(angleSin * sizeRadius.x + angleCos * sizeRadius.y), Math.abs(angleSini * sizeRadius.x + angleCosi * sizeRadius.y)), lat0 = y2lat(ymin - y * k / tileSize.y), lat1 = y2lat(ymax + y * k / tileSize.y); center.lat = Math.max(lat0, Math.min(lat1, center.lat)); // constrain longitude var x = Math.max(Math.abs(angleSin * sizeRadius.y + angleCos * sizeRadius.x), Math.abs(angleSini * sizeRadius.y + angleCosi * sizeRadius.x)), lon0 = centerRange[0].lon - x * k / tileSize.x, lon1 = centerRange[1].lon + x * k / tileSize.x; center.lon = Math.max(lon0, Math.min(lon1, center.lon)); } // a place to capture mouse events if no tiles exist var rect = po.svg("rect"); rect.setAttribute("visibility", "hidden"); rect.setAttribute("pointer-events", "all"); map.container = function(x) { if (!arguments.length) return container; container = x; container.setAttribute("class", "map"); container.appendChild(rect); return map.resize(); // infer size }; map.focusableParent = function() { for (var p = container; p; p = p.parentNode) { if (p.tabIndex >= 0) return p; } return window; }; map.mouse = function(e) { var point = (container.ownerSVGElement || container).createSVGPoint(); if ((bug44083 < 0) && (window.scrollX || window.scrollY)) { var svg = document.body.appendChild(po.svg("svg")); svg.style.position = "absolute"; svg.style.top = svg.style.left = "0px"; var ctm = svg.getScreenCTM(); bug44083 = !(ctm.f || ctm.e); document.body.removeChild(svg); } if (bug44083) { point.x = e.pageX; point.y = e.pageY; } else { point.x = e.clientX; point.y = e.clientY; } return point.matrixTransform(container.getScreenCTM().inverse()); }; map.size = function(x) { if (!arguments.length) return sizeActual; size = x; return map.resize(); // size tiles }; map.resize = function() { if (!size) { rect.setAttribute("width", "100%"); rect.setAttribute("height", "100%"); b = rect.getBBox(); sizeActual = {x: b.width, y: b.height}; resizer.add(map); } else { sizeActual = size; resizer.remove(map); } rect.setAttribute("width", sizeActual.x); rect.setAttribute("height", sizeActual.y); sizeRadius = {x: sizeActual.x / 2, y: sizeActual.y / 2}; recenter(); map.dispatch({type: "resize"}); return map; }; map.tileSize = function(x) { if (!arguments.length) return tileSize; tileSize = x; map.dispatch({type: "move"}); return map; }; map.center = function(x) { if (!arguments.length) return center; center = x; recenter(); map.dispatch({type: "move"}); return map; }; map.panBy = function(x) { var k = 45 / Math.pow(2, zoom + zoomFraction - 3), dx = x.x * k, dy = x.y * k; return map.center({ lon: center.lon + (angleSini * dy - angleCosi * dx) / tileSize.x, lat: y2lat(lat2y(center.lat) + (angleSini * dx + angleCosi * dy) / tileSize.y) }); }; map.centerRange = function(x) { if (!arguments.length) return centerRange; centerRange = x; if (centerRange) { ymin = centerRange[0].lat > -90 ? lat2y(centerRange[0].lat) : -Infinity; ymax = centerRange[0].lat < 90 ? lat2y(centerRange[1].lat) : Infinity; } else { ymin = -Infinity; ymax = Infinity; } recenter(); map.dispatch({type: "move"}); return map; }; map.zoom = function(x) { if (!arguments.length) return zoom + zoomFraction; zoom = x; rezoom(); return map.center(center); }; map.zoomBy = function(z, x0, l) { if (arguments.length < 2) return map.zoom(zoom + zoomFraction + z); // compute the location of x0 if (arguments.length < 3) l = map.pointLocation(x0); // update the zoom level zoom = zoom + zoomFraction + z; rezoom(); // compute the new point of the location var x1 = map.locationPoint(l); return map.panBy({x: x0.x - x1.x, y: x0.y - x1.y}); }; map.zoomRange = function(x) { if (!arguments.length) return zoomRange; zoomRange = x; return map.zoom(zoom + zoomFraction); }; map.extent = function(x) { if (!arguments.length) return [ map.pointLocation({x: 0, y: sizeActual.y}), map.pointLocation({x: sizeActual.x, y: 0}) ]; // compute the extent in points, scale factor, and center var bl = map.locationPoint(x[0]), tr = map.locationPoint(x[1]), k = Math.max((tr.x - bl.x) / sizeActual.x, (bl.y - tr.y) / sizeActual.y), 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.LN2; rezoom(); // set the new center return map.center(l); }; map.angle = function(x) { if (!arguments.length) return angle; angle = x; angleCos = Math.cos(angle); angleSin = Math.sin(angle); angleCosi = Math.cos(-angle); angleSini = Math.sin(-angle); recenter(); map.dispatch({type: "move"}); return map; }; map.add = function(x) { x.map(map); return map; }; map.remove = function(x) { x.map(null); return map; }; map.dispatch = po.dispatch(map); return map; }; function resizer(e) { for (var i = 0; i < resizer.maps.length; i++) { resizer.maps[i].resize(); } } resizer.maps = []; resizer.add = function(map) { for (var i = 0; i < resizer.maps.length; i++) { if (resizer.maps[i] == map) return; } resizer.maps.push(map); }; resizer.remove = function(map) { for (var i = 0; i < resizer.maps.length; i++) { if (resizer.maps[i] == map) { resizer.maps.splice(i, 1); return; } } }; // Note: assumes single window (no frames, iframes, etc.)! if (window.addEventListener) { window.addEventListener("resize", resizer, false); window.addEventListener("load", resizer, false); } // See http://wiki.openstreetmap.org/wiki/Mercator function y2lat(y) { return 360 / Math.PI * Math.atan(Math.exp(y * Math.PI / 180)) - 90; } function lat2y(lat) { return 180 / Math.PI * Math.log(Math.tan(Math.PI / 4 + lat * Math.PI / 360)); } po.map.locationCoordinate = function(l) { var k = 1 / 360; return { column: (l.lon + 180) * k, row: (180 - lat2y(l.lat)) * k, zoom: 0 }; }; po.map.coordinateLocation = function(c) { var k = 45 / Math.pow(2, c.zoom - 3); return { lon: k * c.column - 180, lat: y2lat(180 - k * c.row) }; }; // https://bugs.webkit.org/show_bug.cgi?id=44083 var bug44083 = /WebKit/.test(navigator.userAgent) ? -1 : 0; polymaps/src/Url.js0000664000175000017500000000261711740644523013567 0ustar daviddavidpo.url = function(template) { var hosts = [], repeat = true; function format(c) { var max = c.zoom < 0 ? 1 : 1 << c.zoom, column = c.column; if (repeat) { column = c.column % max; if (column < 0) column += max; } else if ((column < 0) || (column >= max)) { return null; } return template.replace(/{(.)}/g, function(s, v) { switch (v) { case "S": return hosts[(Math.abs(c.zoom) + c.row + column) % hosts.length]; case "Z": return c.zoom; case "X": return column; case "Y": return c.row; case "B": { var nw = po.map.coordinateLocation({row: c.row, column: column, zoom: c.zoom}), se = po.map.coordinateLocation({row: c.row + 1, column: column + 1, zoom: c.zoom}), pn = Math.ceil(Math.log(c.zoom) / Math.LN2); return se.lat.toFixed(pn) + "," + nw.lon.toFixed(pn) + "," + nw.lat.toFixed(pn) + "," + se.lon.toFixed(pn); } } return v; }); } format.template = function(x) { if (!arguments.length) return template; template = x; return format; }; format.hosts = function(x) { if (!arguments.length) return hosts; hosts = x; return format; }; format.repeat = function(x) { if (!arguments.length) return repeat; repeat = x; return format; }; return format; }; polymaps/src/Queue.js0000664000175000017500000000451311740644523014106 0ustar daviddavidpo.queue = (function() { var queued = [], active = 0, size = 6; function process() { if ((active >= size) || !queued.length) return; active++; queued.pop()(); } function dequeue(send) { for (var i = 0; i < queued.length; i++) { if (queued[i] == send) { queued.splice(i, 1); return true; } } return false; } function request(url, callback, mimeType) { var req; function send() { req = new XMLHttpRequest(); if (mimeType && req.overrideMimeType) { req.overrideMimeType(mimeType); } req.open("GET", url, true); req.onreadystatechange = function(e) { if (req.readyState == 4) { active--; if (req.status < 300) callback(req); process(); } }; req.send(null); } function abort(hard) { if (dequeue(send)) return true; if (hard && req) { req.abort(); return true; } return false; } queued.push(send); process(); return {abort: abort}; } function text(url, callback, mimeType) { return request(url, function(req) { if (req.responseText) callback(req.responseText); }, mimeType); } /* * We the override MIME type here so that you can load local files; some * browsers don't assign a proper MIME type for local files. */ function json(url, callback) { return request(url, function(req) { if (req.responseText) callback(JSON.parse(req.responseText)); }, "application/json"); } function xml(url, callback) { return request(url, function(req) { if (req.responseXML) callback(req.responseXML); }, "application/xml"); } function image(image, src, callback) { var img; function send() { img = document.createElement("img"); img.onerror = function() { active--; process(); }; img.onload = function() { active--; callback(img); process(); }; img.src = src; image.setAttributeNS(po.ns.xlink, "href", src); } function abort(hard) { if (dequeue(send)) return true; if (hard && img) { img.src = "about:"; return true; } // cancels request return false; } queued.push(send); process(); return {abort: abort}; } return {text: text, xml: xml, json: json, image: image}; })(); polymaps/src/Dblclick.js0000664000175000017500000000137311740644523014532 0ustar daviddavidpo.dblclick = function() { var dblclick = {}, zoom = "mouse", map, container; function handle(e) { var z = map.zoom(); if (e.shiftKey) z = Math.ceil(z) - z - 1; else z = 1 - z + Math.floor(z); zoom === "mouse" ? map.zoomBy(z, map.mouse(e)) : map.zoomBy(z); } dblclick.zoom = function(x) { if (!arguments.length) return zoom; zoom = x; return dblclick; }; dblclick.map = function(x) { if (!arguments.length) return map; if (map) { container.removeEventListener("dblclick", handle, false); container = null; } if (map = x) { container = map.container(); container.addEventListener("dblclick", handle, false); } return dblclick; }; return dblclick; }; polymaps/src/GeoJson.js0000664000175000017500000002136411740644523014371 0ustar daviddavidpo.geoJson = function(fetch) { var geoJson = po.layer(load, unload), container = geoJson.container(), url, clip = true, clipId = "org.polymaps." + po.id(), clipHref = "url(#" + clipId + ")", clipPath = container.insertBefore(po.svg("clipPath"), container.firstChild), clipRect = clipPath.appendChild(po.svg("rect")), scale = "auto", zoom = null, features; container.setAttribute("fill-rule", "evenodd"); clipPath.setAttribute("id", clipId); if (!arguments.length) fetch = po.queue.json; function projection(proj) { var l = {lat: 0, lon: 0}; return function(coordinates) { l.lat = coordinates[1]; l.lon = coordinates[0]; var p = proj(l); coordinates.x = p.x; coordinates.y = p.y; return p; }; } function geometry(o, proj) { return o && o.type in types && types[o.type](o, proj); } var types = { Point: function(o, proj) { var p = proj(o.coordinates), c = po.svg("circle"); c.setAttribute("r", 4.5); c.setAttribute("transform", "translate(" + p.x + "," + p.y + ")"); return c; }, MultiPoint: function(o, proj) { var g = po.svg("g"), c = o.coordinates, p, // proj(c[i]) x, // svg:circle i = -1, n = c.length; while (++i < n) { x = g.appendChild(po.svg("circle")); x.setAttribute("r", 4.5); x.setAttribute("transform", "translate(" + (p = proj(c[i])).x + "," + p.y + ")"); } return g; }, LineString: function(o, proj) { var x = po.svg("path"), d = ["M"], c = o.coordinates, p, // proj(c[i]) i = -1, n = c.length; while (++i < n) d.push((p = proj(c[i])).x, ",", p.y, "L"); d.pop(); if (!d.length) return; x.setAttribute("d", d.join("")); return x; }, MultiLineString: function(o, proj) { var x = po.svg("path"), d = [], ci = o.coordinates, cj, // ci[i] i = -1, j, n = ci.length, m; while (++i < n) { cj = ci[i]; j = -1; m = cj.length; d.push("M"); while (++j < m) d.push((p = proj(cj[j])).x, ",", p.y, "L"); d.pop(); } if (!d.length) return; x.setAttribute("d", d.join("")); return x; }, Polygon: function(o, proj) { var x = po.svg("path"), d = [], ci = o.coordinates, cj, // ci[i] i = -1, j, n = ci.length, m; while (++i < n) { cj = ci[i]; j = -1; m = cj.length - 1; d.push("M"); while (++j < m) d.push((p = proj(cj[j])).x, ",", p.y, "L"); d[d.length - 1] = "Z"; } if (!d.length) return; x.setAttribute("d", d.join("")); return x; }, MultiPolygon: function(o, proj) { var x = po.svg("path"), d = [], ci = o.coordinates, cj, // ci[i] ck, // cj[j] i = -1, j, k, n = ci.length, m, l; while (++i < n) { cj = ci[i]; j = -1; m = cj.length; while (++j < m) { ck = cj[j]; k = -1; l = ck.length - 1; d.push("M"); while (++k < l) d.push((p = proj(ck[k])).x, ",", p.y, "L"); d[d.length - 1] = "Z"; } } if (!d.length) return; x.setAttribute("d", d.join("")); return x; }, GeometryCollection: function(o, proj) { var g = po.svg("g"), i = -1, c = o.geometries, n = c.length, x; while (++i < n) { x = geometry(c[i], proj); if (x) g.appendChild(x); } return g; } }; function rescale(o, e, k) { return o.type in rescales && rescales[o.type](o, e, k); } var rescales = { Point: function (o, e, k) { var p = o.coordinates; e.setAttribute("transform", "translate(" + p.x + "," + p.y + ")" + k); }, MultiPoint: function (o, e, k) { var c = o.coordinates, i = -1, n = p.length, x = e.firstChild, p; while (++i < n) { p = c[i]; x.setAttribute("transform", "translate(" + p.x + "," + p.y + ")" + k); x = x.nextSibling; } } }; function load(tile, proj) { var g = tile.element = po.svg("g"); tile.features = []; proj = projection(proj(tile).locationPoint); function update(data) { var updated = []; /* Fetch the next batch of features, if so directed. */ if (data.next) tile.request = fetch(data.next.href, update); /* Convert the GeoJSON to SVG. */ switch (data.type) { case "FeatureCollection": { for (var i = 0; i < data.features.length; i++) { var feature = data.features[i], element = geometry(feature.geometry, proj); if (element) updated.push({element: g.appendChild(element), data: feature}); } break; } case "Feature": { var element = geometry(data.geometry, proj); if (element) updated.push({element: g.appendChild(element), data: data}); break; } default: { var element = geometry(data, proj); if (element) updated.push({element: g.appendChild(element), data: {type: "Feature", geometry: data}}); break; } } tile.ready = true; updated.push.apply(tile.features, updated); geoJson.dispatch({type: "load", tile: tile, features: updated}); } if (url != null) { tile.request = fetch(typeof url == "function" ? url(tile) : url, update); } else { update({type: "FeatureCollection", features: features || []}); } } function unload(tile) { if (tile.request) tile.request.abort(true); } function move() { var zoom = geoJson.map().zoom(), tiles = geoJson.cache.locks(), // visible tiles key, // key in locks tile, // locks[key] features, // tile.features i, // current feature index n, // current feature count, features.length feature, // features[i] k; // scale transform if (scale == "fixed") { for (key in tiles) { if ((tile = tiles[key]).scale != zoom) { k = "scale(" + Math.pow(2, tile.zoom - zoom) + ")"; i = -1; n = (features = tile.features).length; while (++i < n) rescale((feature = features[i]).data.geometry, feature.element, k); tile.scale = zoom; } } } else { for (key in tiles) { i = -1; n = (features = (tile = tiles[key]).features).length; while (++i < n) rescale((feature = features[i]).data.geometry, feature.element, ""); delete tile.scale; } } } geoJson.url = function(x) { if (!arguments.length) return url; url = typeof x == "string" && /{.}/.test(x) ? po.url(x) : x; if (url != null) features = null; if (typeof url == "string") geoJson.tile(false); return geoJson.reload(); }; geoJson.features = function(x) { if (!arguments.length) return features; if (features = x) { url = null; geoJson.tile(false); } return geoJson.reload(); }; geoJson.clip = function(x) { if (!arguments.length) return clip; if (clip) container.removeChild(clipPath); if (clip = x) container.insertBefore(clipPath, container.firstChild); var locks = geoJson.cache.locks(); for (var key in locks) { if (clip) locks[key].element.setAttribute("clip-path", clipHref); else locks[key].element.removeAttribute("clip-path"); } return geoJson; }; var __tile__ = geoJson.tile; geoJson.tile = function(x) { if (arguments.length && !x) geoJson.clip(x); return __tile__.apply(geoJson, arguments); }; var __map__ = geoJson.map; geoJson.map = function(x) { if (x && clipRect) { var size = x.tileSize(); clipRect.setAttribute("width", size.x); clipRect.setAttribute("height", size.y); } return __map__.apply(geoJson, arguments); }; geoJson.scale = function(x) { if (!arguments.length) return scale; if (scale = x) geoJson.on("move", move); else geoJson.off("move", move); if (geoJson.map()) move(); return geoJson; }; geoJson.show = function(tile) { if (clip) tile.element.setAttribute("clip-path", clipHref); else tile.element.removeAttribute("clip-path"); geoJson.dispatch({type: "show", tile: tile, features: tile.features}); return geoJson; }; geoJson.reshow = function() { var locks = geoJson.cache.locks(); for (var key in locks) geoJson.show(locks[key]); return geoJson; }; return geoJson; }; polymaps/src/Hash.js0000664000175000017500000000332011740644523013700 0ustar daviddavidpo.hash = function() { var hash = {}, s0, // cached location.hash lat = 90 - 1e-8, // allowable latitude range map; var parser = function(map, s) { var args = s.split("/").map(Number); if (args.length < 3 || args.some(isNaN)) return true; // replace bogus hash else { var size = map.size(); map.zoomBy(args[0] - map.zoom(), {x: size.x / 2, y: size.y / 2}, {lat: Math.min(lat, Math.max(-lat, args[1])), lon: args[2]}); } }; var formatter = function(map) { var center = map.center(), zoom = map.zoom(), precision = Math.max(0, Math.ceil(Math.log(zoom) / Math.LN2)); return "#" + zoom.toFixed(2) + "/" + center.lat.toFixed(precision) + "/" + center.lon.toFixed(precision); }; function move() { var s1 = formatter(map); if (s0 !== s1) location.replace(s0 = s1); // don't recenter the map! } function hashchange() { if (location.hash === s0) return; // ignore spurious hashchange events if (parser(map, (s0 = location.hash).substring(1))) move(); // replace bogus hash } hash.map = function(x) { if (!arguments.length) return map; if (map) { map.off("move", move); window.removeEventListener("hashchange", hashchange, false); } if (map = x) { map.on("move", move); window.addEventListener("hashchange", hashchange, false); location.hash ? hashchange() : move(); } return hash; }; hash.parser = function(x) { if (!arguments.length) return parser; parser = x; return hash; }; hash.formatter = function(x) { if (!arguments.length) return formatter; formatter = x; return hash; }; return hash; }; polymaps/src/Transform.js0000664000175000017500000000236711740644523015002 0ustar daviddavidpo.transform = function(a, b, c, d, e, f) { var transform = {}, zoomDelta, zoomFraction, k; if (!arguments.length) { a = 1; c = 0; e = 0; b = 0; d = 1; f = 0; } 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.LN2); k = Math.pow(2, -zoomDelta); return transform; }; transform.apply = function(x) { var k0 = Math.pow(2, -x.zoom), k1 = Math.pow(2, x.zoom - zoomDelta); return { column: (a * x.column * k0 + c * x.row * k0 + e) * k1, row: (b * x.column * k0 + d * x.row * k0 + f) * k1, zoom: x.zoom - zoomDelta }; }; transform.unapply = function(x) { var k0 = Math.pow(2, -x.zoom), k1 = Math.pow(2, x.zoom + zoomDelta); return { column: (x.column * k0 * d - x.row * k0 * c - e * d + f * c) / (a * d - b * c) * k1, row: (x.column * k0 * b - x.row * k0 * a - e * b + f * a) / (c * b - d * a) * k1, zoom: x.zoom + zoomDelta }; }; transform.toString = function() { return "matrix(" + [a * k, b * k, c * k, d * k].join(" ") + " 0 0)"; }; return transform.zoomFraction(0); }; polymaps/polymaps.js0000444000175000017500000017713511740646757014121 0ustar daviddavidif (!org) var org = {}; if (!org.polymaps) org.polymaps = {}; (function(po){ po.version = "2.5.1"; // semver.org var zero = {x: 0, y: 0}; po.ns = { svg: "http://www.w3.org/2000/svg", xlink: "http://www.w3.org/1999/xlink" }; function ns(name) { var i = name.indexOf(":"); return i < 0 ? name : { space: po.ns[name.substring(0, i)], local: name.substring(i + 1) }; } po.id = (function() { var id = 0; return function() { return ++id; }; })(); po.svg = function(type) { return document.createElementNS(po.ns.svg, type); }; po.transform = function(a, b, c, d, e, f) { var transform = {}, zoomDelta, zoomFraction, k; if (!arguments.length) { a = 1; c = 0; e = 0; b = 0; d = 1; f = 0; } 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.LN2); k = Math.pow(2, -zoomDelta); return transform; }; transform.apply = function(x) { var k0 = Math.pow(2, -x.zoom), k1 = Math.pow(2, x.zoom - zoomDelta); return { column: (a * x.column * k0 + c * x.row * k0 + e) * k1, row: (b * x.column * k0 + d * x.row * k0 + f) * k1, zoom: x.zoom - zoomDelta }; }; transform.unapply = function(x) { var k0 = Math.pow(2, -x.zoom), k1 = Math.pow(2, x.zoom + zoomDelta); return { column: (x.column * k0 * d - x.row * k0 * c - e * d + f * c) / (a * d - b * c) * k1, row: (x.column * k0 * b - x.row * k0 * a - e * b + f * a) / (c * b - d * a) * k1, zoom: x.zoom + zoomDelta }; }; transform.toString = function() { return "matrix(" + [a * k, b * k, c * k, d * k].join(" ") + " 0 0)"; }; return transform.zoomFraction(0); }; po.cache = function(load, unload) { var cache = {}, locks = {}, map = {}, head = null, tail = null, size = 64, n = 0; function remove(tile) { n--; if (unload) unload(tile); delete map[tile.key]; if (tile.next) tile.next.prev = tile.prev; else if (tail = tile.prev) tail.next = null; if (tile.prev) tile.prev.next = tile.next; else if (head = tile.next) head.prev = null; } function flush() { for (var tile = tail; n > size; tile = tile.prev) { if (!tile) break; if (tile.lock) continue; remove(tile); } } cache.peek = function(c) { return map[[c.zoom, c.column, c.row].join("/")]; }; cache.load = function(c, projection) { var key = [c.zoom, c.column, c.row].join("/"), tile = map[key]; if (tile) { if (tile.prev) { tile.prev.next = tile.next; if (tile.next) tile.next.prev = tile.prev; else tail = tile.prev; tile.prev = null; tile.next = head; head.prev = tile; head = tile; } tile.lock = 1; locks[key] = tile; return tile; } tile = { key: key, column: c.column, row: c.row, zoom: c.zoom, next: head, prev: null, lock: 1 }; load.call(null, tile, projection); locks[key] = map[key] = tile; if (head) head.prev = tile; else tail = tile; head = tile; n++; return tile; }; cache.unload = function(key) { if (!(key in locks)) return false; var tile = locks[key]; tile.lock = 0; delete locks[key]; if (tile.request && tile.request.abort(false)) remove(tile); return tile; }; cache.locks = function() { return locks; }; cache.size = function(x) { if (!arguments.length) return size; size = x; flush(); return cache; }; cache.flush = function() { flush(); return cache; }; cache.clear = function() { for (var key in map) { var tile = map[key]; if (tile.request) tile.request.abort(false); if (unload) unload(map[key]); if (tile.lock) { tile.lock = 0; tile.element.parentNode.removeChild(tile.element); } } locks = {}; map = {}; head = tail = null; n = 0; return cache; }; return cache; }; po.url = function(template) { var hosts = [], repeat = true; function format(c) { var max = c.zoom < 0 ? 1 : 1 << c.zoom, column = c.column; if (repeat) { column = c.column % max; if (column < 0) column += max; } else if ((column < 0) || (column >= max)) { return null; } return template.replace(/{(.)}/g, function(s, v) { switch (v) { case "S": return hosts[(Math.abs(c.zoom) + c.row + column) % hosts.length]; case "Z": return c.zoom; case "X": return column; case "Y": return c.row; case "B": { var nw = po.map.coordinateLocation({row: c.row, column: column, zoom: c.zoom}), se = po.map.coordinateLocation({row: c.row + 1, column: column + 1, zoom: c.zoom}), pn = Math.ceil(Math.log(c.zoom) / Math.LN2); return se.lat.toFixed(pn) + "," + nw.lon.toFixed(pn) + "," + nw.lat.toFixed(pn) + "," + se.lon.toFixed(pn); } } return v; }); } format.template = function(x) { if (!arguments.length) return template; template = x; return format; }; format.hosts = function(x) { if (!arguments.length) return hosts; hosts = x; return format; }; format.repeat = function(x) { if (!arguments.length) return repeat; repeat = x; return format; }; return format; }; po.dispatch = function(that) { var types = {}; that.on = function(type, handler) { var listeners = types[type] || (types[type] = []); for (var i = 0; i < listeners.length; i++) { if (listeners[i].handler == handler) return that; // already registered } listeners.push({handler: handler, on: true}); return that; }; that.off = function(type, handler) { var listeners = types[type]; if (listeners) for (var i = 0; i < listeners.length; i++) { var l = listeners[i]; if (l.handler == handler) { l.on = false; listeners.splice(i, 1); break; } } return that; }; return function(event) { var listeners = types[event.type]; if (!listeners) return; listeners = listeners.slice(); // defensive copy for (var i = 0; i < listeners.length; i++) { var l = listeners[i]; if (l.on) l.handler.call(that, event); } }; }; po.queue = (function() { var queued = [], active = 0, size = 6; function process() { if ((active >= size) || !queued.length) return; active++; queued.pop()(); } function dequeue(send) { for (var i = 0; i < queued.length; i++) { if (queued[i] == send) { queued.splice(i, 1); return true; } } return false; } function request(url, callback, mimeType) { var req; function send() { req = new XMLHttpRequest(); if (mimeType && req.overrideMimeType) { req.overrideMimeType(mimeType); } req.open("GET", url, true); req.onreadystatechange = function(e) { if (req.readyState == 4) { active--; if (req.status < 300) callback(req); process(); } }; req.send(null); } function abort(hard) { if (dequeue(send)) return true; if (hard && req) { req.abort(); return true; } return false; } queued.push(send); process(); return {abort: abort}; } function text(url, callback, mimeType) { return request(url, function(req) { if (req.responseText) callback(req.responseText); }, mimeType); } /* * We the override MIME type here so that you can load local files; some * browsers don't assign a proper MIME type for local files. */ function json(url, callback) { return request(url, function(req) { if (req.responseText) callback(JSON.parse(req.responseText)); }, "application/json"); } function xml(url, callback) { return request(url, function(req) { if (req.responseXML) callback(req.responseXML); }, "application/xml"); } function image(image, src, callback) { var img; function send() { img = document.createElement("img"); img.onerror = function() { active--; process(); }; img.onload = function() { active--; callback(img); process(); }; img.src = src; image.setAttributeNS(po.ns.xlink, "href", src); } function abort(hard) { if (dequeue(send)) return true; if (hard && img) { img.src = "about:"; return true; } // cancels request return false; } queued.push(send); process(); return {abort: abort}; } return {text: text, xml: xml, json: json, image: image}; })(); po.map = function() { var map = {}, container, size, sizeActual = zero, sizeRadius = zero, // sizeActual / 2 tileSize = {x: 256, y: 256}, center = {lat: 37.76487, lon: -122.41948}, zoom = 12, zoomFraction = 0, zoomFactor = 1, // Math.pow(2, zoomFraction) zoomRange = [1, 18], angle = 0, angleCos = 1, // Math.cos(angle) angleSin = 0, // Math.sin(angle) angleCosi = 1, // Math.cos(-angle) angleSini = 0, // Math.sin(-angle) ymin = -180, // lat2y(centerRange[0].lat) ymax = 180; // lat2y(centerRange[1].lat) var centerRange = [ {lat: y2lat(ymin), lon: -Infinity}, {lat: y2lat(ymax), lon: Infinity} ]; map.locationCoordinate = function(l) { var c = po.map.locationCoordinate(l), k = Math.pow(2, zoom); c.column *= k; c.row *= k; c.zoom += zoom; return c; }; map.coordinateLocation = po.map.coordinateLocation; map.coordinatePoint = function(tileCenter, c) { var kc = Math.pow(2, zoom - c.zoom), kt = Math.pow(2, zoom - tileCenter.zoom), dx = (c.column * kc - tileCenter.column * kt) * tileSize.x * zoomFactor, dy = (c.row * kc - tileCenter.row * kt) * tileSize.y * zoomFactor; return { x: sizeRadius.x + angleCos * dx - angleSin * dy, y: sizeRadius.y + angleSin * dx + angleCos * dy }; }; map.pointCoordinate = function(tileCenter, p) { var kt = Math.pow(2, zoom - tileCenter.zoom), dx = (p.x - sizeRadius.x) / zoomFactor, dy = (p.y - sizeRadius.y) / zoomFactor; return { column: tileCenter.column * kt + (angleCosi * dx - angleSini * dy) / tileSize.x, row: tileCenter.row * kt + (angleSini * dx + angleCosi * dy) / tileSize.y, zoom: zoom }; }; map.locationPoint = function(l) { var k = Math.pow(2, zoom + zoomFraction - 3) / 45, dx = (l.lon - center.lon) * k * tileSize.x, dy = (lat2y(center.lat) - lat2y(l.lat)) * k * tileSize.y; return { x: sizeRadius.x + angleCos * dx - angleSin * dy, y: sizeRadius.y + angleSin * dx + angleCos * dy }; }; map.pointLocation = function(p) { var k = 45 / Math.pow(2, zoom + zoomFraction - 3), dx = (p.x - sizeRadius.x) * k, dy = (p.y - sizeRadius.y) * k; return { lon: center.lon + (angleCosi * dx - angleSini * dy) / tileSize.x, lat: y2lat(lat2y(center.lat) - (angleSini * dx + angleCosi * dy) / tileSize.y) }; }; function rezoom() { if (zoomRange) { if (zoom < zoomRange[0]) zoom = zoomRange[0]; else if (zoom > zoomRange[1]) zoom = zoomRange[1]; } zoomFraction = zoom - (zoom = Math.round(zoom)); zoomFactor = Math.pow(2, zoomFraction); } function recenter() { if (!centerRange) return; var k = 45 / Math.pow(2, zoom + zoomFraction - 3); // constrain latitude var y = Math.max(Math.abs(angleSin * sizeRadius.x + angleCos * sizeRadius.y), Math.abs(angleSini * sizeRadius.x + angleCosi * sizeRadius.y)), lat0 = y2lat(ymin - y * k / tileSize.y), lat1 = y2lat(ymax + y * k / tileSize.y); center.lat = Math.max(lat0, Math.min(lat1, center.lat)); // constrain longitude var x = Math.max(Math.abs(angleSin * sizeRadius.y + angleCos * sizeRadius.x), Math.abs(angleSini * sizeRadius.y + angleCosi * sizeRadius.x)), lon0 = centerRange[0].lon - x * k / tileSize.x, lon1 = centerRange[1].lon + x * k / tileSize.x; center.lon = Math.max(lon0, Math.min(lon1, center.lon)); } // a place to capture mouse events if no tiles exist var rect = po.svg("rect"); rect.setAttribute("visibility", "hidden"); rect.setAttribute("pointer-events", "all"); map.container = function(x) { if (!arguments.length) return container; container = x; container.setAttribute("class", "map"); container.appendChild(rect); return map.resize(); // infer size }; map.focusableParent = function() { for (var p = container; p; p = p.parentNode) { if (p.tabIndex >= 0) return p; } return window; }; map.mouse = function(e) { var point = (container.ownerSVGElement || container).createSVGPoint(); if ((bug44083 < 0) && (window.scrollX || window.scrollY)) { var svg = document.body.appendChild(po.svg("svg")); svg.style.position = "absolute"; svg.style.top = svg.style.left = "0px"; var ctm = svg.getScreenCTM(); bug44083 = !(ctm.f || ctm.e); document.body.removeChild(svg); } if (bug44083) { point.x = e.pageX; point.y = e.pageY; } else { point.x = e.clientX; point.y = e.clientY; } return point.matrixTransform(container.getScreenCTM().inverse()); }; map.size = function(x) { if (!arguments.length) return sizeActual; size = x; return map.resize(); // size tiles }; map.resize = function() { if (!size) { rect.setAttribute("width", "100%"); rect.setAttribute("height", "100%"); b = rect.getBBox(); sizeActual = {x: b.width, y: b.height}; resizer.add(map); } else { sizeActual = size; resizer.remove(map); } rect.setAttribute("width", sizeActual.x); rect.setAttribute("height", sizeActual.y); sizeRadius = {x: sizeActual.x / 2, y: sizeActual.y / 2}; recenter(); map.dispatch({type: "resize"}); return map; }; map.tileSize = function(x) { if (!arguments.length) return tileSize; tileSize = x; map.dispatch({type: "move"}); return map; }; map.center = function(x) { if (!arguments.length) return center; center = x; recenter(); map.dispatch({type: "move"}); return map; }; map.panBy = function(x) { var k = 45 / Math.pow(2, zoom + zoomFraction - 3), dx = x.x * k, dy = x.y * k; return map.center({ lon: center.lon + (angleSini * dy - angleCosi * dx) / tileSize.x, lat: y2lat(lat2y(center.lat) + (angleSini * dx + angleCosi * dy) / tileSize.y) }); }; map.centerRange = function(x) { if (!arguments.length) return centerRange; centerRange = x; if (centerRange) { ymin = centerRange[0].lat > -90 ? lat2y(centerRange[0].lat) : -Infinity; ymax = centerRange[0].lat < 90 ? lat2y(centerRange[1].lat) : Infinity; } else { ymin = -Infinity; ymax = Infinity; } recenter(); map.dispatch({type: "move"}); return map; }; map.zoom = function(x) { if (!arguments.length) return zoom + zoomFraction; zoom = x; rezoom(); return map.center(center); }; map.zoomBy = function(z, x0, l) { if (arguments.length < 2) return map.zoom(zoom + zoomFraction + z); // compute the location of x0 if (arguments.length < 3) l = map.pointLocation(x0); // update the zoom level zoom = zoom + zoomFraction + z; rezoom(); // compute the new point of the location var x1 = map.locationPoint(l); return map.panBy({x: x0.x - x1.x, y: x0.y - x1.y}); }; map.zoomRange = function(x) { if (!arguments.length) return zoomRange; zoomRange = x; return map.zoom(zoom + zoomFraction); }; map.extent = function(x) { if (!arguments.length) return [ map.pointLocation({x: 0, y: sizeActual.y}), map.pointLocation({x: sizeActual.x, y: 0}) ]; // compute the extent in points, scale factor, and center var bl = map.locationPoint(x[0]), tr = map.locationPoint(x[1]), k = Math.max((tr.x - bl.x) / sizeActual.x, (bl.y - tr.y) / sizeActual.y), 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.LN2; rezoom(); // set the new center return map.center(l); }; map.angle = function(x) { if (!arguments.length) return angle; angle = x; angleCos = Math.cos(angle); angleSin = Math.sin(angle); angleCosi = Math.cos(-angle); angleSini = Math.sin(-angle); recenter(); map.dispatch({type: "move"}); return map; }; map.add = function(x) { x.map(map); return map; }; map.remove = function(x) { x.map(null); return map; }; map.dispatch = po.dispatch(map); return map; }; function resizer(e) { for (var i = 0; i < resizer.maps.length; i++) { resizer.maps[i].resize(); } } resizer.maps = []; resizer.add = function(map) { for (var i = 0; i < resizer.maps.length; i++) { if (resizer.maps[i] == map) return; } resizer.maps.push(map); }; resizer.remove = function(map) { for (var i = 0; i < resizer.maps.length; i++) { if (resizer.maps[i] == map) { resizer.maps.splice(i, 1); return; } } }; // Note: assumes single window (no frames, iframes, etc.)! if (window.addEventListener) { window.addEventListener("resize", resizer, false); window.addEventListener("load", resizer, false); } // See http://wiki.openstreetmap.org/wiki/Mercator function y2lat(y) { return 360 / Math.PI * Math.atan(Math.exp(y * Math.PI / 180)) - 90; } function lat2y(lat) { return 180 / Math.PI * Math.log(Math.tan(Math.PI / 4 + lat * Math.PI / 360)); } po.map.locationCoordinate = function(l) { var k = 1 / 360; return { column: (l.lon + 180) * k, row: (180 - lat2y(l.lat)) * k, zoom: 0 }; }; po.map.coordinateLocation = function(c) { var k = 45 / Math.pow(2, c.zoom - 3); return { lon: k * c.column - 180, lat: y2lat(180 - k * c.row) }; }; // https://bugs.webkit.org/show_bug.cgi?id=44083 var bug44083 = /WebKit/.test(navigator.userAgent) ? -1 : 0; po.layer = function(load, unload) { var layer = {}, cache = layer.cache = po.cache(load, unload).size(512), tile = true, visible = true, zoom, id, map, container = po.svg("g"), transform, levelZoom, levels = {}; container.setAttribute("class", "layer"); for (var i = -4; i <= -1; i++) levels[i] = container.appendChild(po.svg("g")); for (var i = 2; i >= 1; i--) levels[i] = container.appendChild(po.svg("g")); levels[0] = container.appendChild(po.svg("g")); function zoomIn(z) { var end = levels[0].nextSibling; for (; levelZoom < z; levelZoom++) { // -4, -3, -2, -1, +2, +1, =0 // current order // -3, -2, -1, +2, +1, =0, -4 // insertBefore(-4, end) // -3, -2, -1, +1, =0, -4, +2 // insertBefore(+2, end) // -3, -2, -1, =0, -4, +2, +1 // insertBefore(+1, end) // -4, -3, -2, -1, +2, +1, =0 // relabel container.insertBefore(levels[-4], end); container.insertBefore(levels[2], end); container.insertBefore(levels[1], end); var t = levels[-4]; for (var dz = -4; dz < 2;) levels[dz] = levels[++dz]; levels[dz] = t; } } function zoomOut(z) { var end = levels[0].nextSibling; for (; levelZoom > z; levelZoom--) { // -4, -3, -2, -1, +2, +1, =0 // current order // -4, -3, -2, +2, +1, =0, -1 // insertBefore(-1, end) // +2, -4, -3, -2, +1, =0, -1 // insertBefore(+2, -4) // -4, -3, -2, -1, +2, +1, =0 // relabel container.insertBefore(levels[-1], end); container.insertBefore(levels[2], levels[-4]); var t = levels[2]; for (var dz = 2; dz > -4;) levels[dz] = levels[--dz]; levels[dz] = t; } } function move() { var map = layer.map(), // in case the layer is removed mapZoom = map.zoom(), mapZoomFraction = mapZoom - (mapZoom = Math.round(mapZoom)), mapSize = map.size(), mapAngle = map.angle(), tileSize = map.tileSize(), tileCenter = map.locationCoordinate(map.center()); // set the layer zoom levels if (levelZoom != mapZoom) { if (levelZoom < mapZoom) zoomIn(mapZoom); else if (levelZoom > mapZoom) zoomOut(mapZoom); else levelZoom = mapZoom; for (var z = -4; z <= 2; z++) { var l = levels[z]; l.setAttribute("class", "zoom" + (z < 0 ? "" : "+") + z + " zoom" + (mapZoom + z)); l.setAttribute("transform", "scale(" + Math.pow(2, -z) + ")"); } } // set the layer transform container.setAttribute("transform", "translate(" + (mapSize.x / 2) + "," + (mapSize.y / 2) + ")" + (mapAngle ? "rotate(" + mapAngle / Math.PI * 180 + ")" : "") + (mapZoomFraction ? "scale(" + Math.pow(2, mapZoomFraction) + ")" : "") + (transform ? transform.zoomFraction(mapZoomFraction) : "")); // get the coordinates of the four corners var c0 = map.pointCoordinate(tileCenter, zero), c1 = map.pointCoordinate(tileCenter, {x: mapSize.x, y: 0}), c2 = map.pointCoordinate(tileCenter, mapSize), c3 = map.pointCoordinate(tileCenter, {x: 0, y: mapSize.y}); // round to pixel boundary to avoid anti-aliasing artifacts if (!mapZoomFraction && !mapAngle && !transform) { tileCenter.column = (Math.round(tileSize.x * tileCenter.column) + (mapSize.x & 1) / 2) / tileSize.x; tileCenter.row = (Math.round(tileSize.y * tileCenter.row) + (mapSize.y & 1) / 2) / tileSize.y; } // layer-specific coordinate transform if (transform) { c0 = transform.unapply(c0); c1 = transform.unapply(c1); c2 = transform.unapply(c2); c3 = transform.unapply(c3); tileCenter = transform.unapply(tileCenter); } // layer-specific zoom transform var tileLevel = zoom ? zoom(c0.zoom) - c0.zoom : 0; if (tileLevel) { var k = Math.pow(2, tileLevel); c0.column *= k; c0.row *= k; c1.column *= k; c1.row *= k; c2.column *= k; c2.row *= k; c3.column *= k; c3.row *= k; c0.zoom = c1.zoom = c2.zoom = c3.zoom += tileLevel; } // tile-specific projection function projection(c) { var zoom = c.zoom, max = zoom < 0 ? 1 : 1 << zoom, column = c.column % max, row = c.row; if (column < 0) column += max; return { locationPoint: function(l) { var c = po.map.locationCoordinate(l), k = Math.pow(2, zoom - c.zoom); return { x: tileSize.x * (k * c.column - column), y: tileSize.y * (k * c.row - row) }; } }; } // record which tiles are visible var oldLocks = cache.locks(), newLocks = {}; // reset the proxy counts for (var key in oldLocks) { oldLocks[key].proxyCount = 0; } // load the tiles! if (visible && tileLevel > -5 && tileLevel < 3) { var ymax = c0.zoom < 0 ? 1 : 1 << c0.zoom; if (tile) { scanTriangle(c0, c1, c2, 0, ymax, scanLine); scanTriangle(c2, c3, c0, 0, ymax, scanLine); } else { var x = Math.floor((c0.column + c2.column) / 2), y = Math.max(0, Math.min(ymax - 1, Math.floor((c1.row + c3.row) / 2))), z = Math.min(4, c0.zoom); x = x >> z << z; y = y >> z << z; scanLine(x, x + 1, y); } } // scan-line conversion function scanLine(x0, x1, y) { var z = c0.zoom, z0 = 2 - tileLevel, z1 = 4 + tileLevel; for (var x = x0; x < x1; x++) { var t = cache.load({column: x, row: y, zoom: z}, projection); if (!t.ready && !(t.key in newLocks)) { t.proxyRefs = {}; var c, full, proxy; // downsample high-resolution tiles for (var dz = 1; dz <= z0; dz++) { full = true; for (var dy = 0, k = 1 << dz; dy <= k; dy++) { for (var dx = 0; dx <= k; dx++) { proxy = cache.peek(c = { column: (x << dz) + dx, row: (y << dz) + dy, zoom: z + dz }); if (proxy && proxy.ready) { newLocks[proxy.key] = cache.load(c); proxy.proxyCount++; t.proxyRefs[proxy.key] = proxy; } else { full = false; } } } if (full) break; } // upsample low-resolution tiles if (!full) { for (var dz = 1; dz <= z1; dz++) { proxy = cache.peek(c = { column: x >> dz, row: y >> dz, zoom: z - dz }); if (proxy && proxy.ready) { newLocks[proxy.key] = cache.load(c); proxy.proxyCount++; t.proxyRefs[proxy.key] = proxy; break; } } } } newLocks[t.key] = t; } } // position tiles for (var key in newLocks) { var t = newLocks[key], k = Math.pow(2, t.level = t.zoom - tileCenter.zoom); t.element.setAttribute("transform", "translate(" + (t.x = tileSize.x * (t.column - tileCenter.column * k)) + "," + (t.y = tileSize.y * (t.row - tileCenter.row * k)) + ")"); } // remove tiles that are no longer visible for (var key in oldLocks) { if (!(key in newLocks)) { var t = cache.unload(key); t.element.parentNode.removeChild(t.element); delete t.proxyRefs; } } // append tiles that are now visible for (var key in newLocks) { var t = newLocks[key]; if (t.element.parentNode != levels[t.level]) { levels[t.level].appendChild(t.element); if (layer.show) layer.show(t); } } // flush the cache, clearing no-longer-needed tiles cache.flush(); // dispatch the move event layer.dispatch({type: "move"}); } // remove proxy tiles when tiles load function cleanup(e) { if (e.tile.proxyRefs) { for (var proxyKey in e.tile.proxyRefs) { var proxyTile = e.tile.proxyRefs[proxyKey]; if ((--proxyTile.proxyCount <= 0) && cache.unload(proxyKey)) { proxyTile.element.parentNode.removeChild(proxyTile.element); } } delete e.tile.proxyRefs; } } layer.map = function(x) { if (!arguments.length) return map; if (map) { if (map == x) { container.parentNode.appendChild(container); // move to end return layer; } map.off("move", move).off("resize", move); container.parentNode.removeChild(container); } map = x; if (map) { map.container().appendChild(container); if (layer.init) layer.init(container); map.on("move", move).on("resize", move); move(); } return layer; }; layer.container = function() { return container; }; layer.levels = function() { return levels; }; layer.id = function(x) { if (!arguments.length) return id; id = x; container.setAttribute("id", x); return layer; }; layer.visible = function(x) { if (!arguments.length) return visible; if (visible = x) container.removeAttribute("visibility") else container.setAttribute("visibility", "hidden"); if (map) move(); return layer; }; layer.transform = function(x) { if (!arguments.length) return transform; transform = x; if (map) move(); return layer; }; layer.zoom = function(x) { if (!arguments.length) return zoom; zoom = typeof x == "function" || x == null ? x : function() { return x; }; if (map) move(); return layer; }; layer.tile = function(x) { if (!arguments.length) return tile; tile = x; if (map) move(); return layer; }; layer.reload = function() { cache.clear(); if (map) move(); return layer; }; layer.dispatch = po.dispatch(layer); layer.on("load", cleanup); return layer; }; // scan-line conversion function edge(a, b) { if (a.row > b.row) { var t = a; a = b; b = t; } return { x0: a.column, y0: a.row, x1: b.column, y1: b.row, dx: b.column - a.column, dy: b.row - a.row }; } // scan-line conversion function scanSpans(e0, e1, ymin, ymax, scanLine) { var y0 = Math.max(ymin, Math.floor(e1.y0)), y1 = Math.min(ymax, Math.ceil(e1.y1)); // sort edges by x-coordinate if ((e0.x0 == e1.x0 && e0.y0 == e1.y0) ? (e0.x0 + e1.dy / e0.dy * e0.dx < e1.x1) : (e0.x1 - e1.dy / e0.dy * e0.dx < e1.x0)) { var t = e0; e0 = e1; e1 = t; } // scan lines! var m0 = e0.dx / e0.dy, m1 = e1.dx / e1.dy, d0 = e0.dx > 0, // use y + 1 to compute x0 d1 = e1.dx < 0; // use y + 1 to compute x1 for (var y = y0; y < y1; y++) { var x0 = m0 * Math.max(0, Math.min(e0.dy, y + d0 - e0.y0)) + e0.x0, x1 = m1 * Math.max(0, Math.min(e1.dy, y + d1 - e1.y0)) + e1.x0; scanLine(Math.floor(x1), Math.ceil(x0), y); } } // scan-line conversion function scanTriangle(a, b, c, ymin, ymax, scanLine) { var ab = edge(a, b), bc = edge(b, c), ca = edge(c, a); // sort edges by y-length if (ab.dy > bc.dy) { var t = ab; ab = bc; bc = t; } if (ab.dy > ca.dy) { var t = ab; ab = ca; ca = t; } if (bc.dy > ca.dy) { var t = bc; bc = ca; ca = t; } // scan span! scan span! if (ab.dy) scanSpans(ca, ab, ymin, ymax, scanLine); if (bc.dy) scanSpans(ca, bc, ymin, ymax, scanLine); } po.image = function() { var image = po.layer(load, unload), url; function load(tile) { var element = tile.element = po.svg("image"), size = image.map().tileSize(); element.setAttribute("preserveAspectRatio", "none"); element.setAttribute("width", size.x); element.setAttribute("height", size.y); if (typeof url == "function") { element.setAttribute("opacity", 0); var tileUrl = url(tile); if (tileUrl != null) { tile.request = po.queue.image(element, tileUrl, function(img) { delete tile.request; tile.ready = true; tile.img = img; element.removeAttribute("opacity"); image.dispatch({type: "load", tile: tile}); }); } else { tile.ready = true; image.dispatch({type: "load", tile: tile}); } } else { tile.ready = true; if (url != null) element.setAttributeNS(po.ns.xlink, "href", url); image.dispatch({type: "load", tile: tile}); } } function unload(tile) { if (tile.request) tile.request.abort(true); } image.url = function(x) { if (!arguments.length) return url; url = typeof x == "string" && /{.}/.test(x) ? po.url(x) : x; return image.reload(); }; return image; }; po.geoJson = function(fetch) { var geoJson = po.layer(load, unload), container = geoJson.container(), url, clip = true, clipId = "org.polymaps." + po.id(), clipHref = "url(#" + clipId + ")", clipPath = container.insertBefore(po.svg("clipPath"), container.firstChild), clipRect = clipPath.appendChild(po.svg("rect")), scale = "auto", zoom = null, features; container.setAttribute("fill-rule", "evenodd"); clipPath.setAttribute("id", clipId); if (!arguments.length) fetch = po.queue.json; function projection(proj) { var l = {lat: 0, lon: 0}; return function(coordinates) { l.lat = coordinates[1]; l.lon = coordinates[0]; var p = proj(l); coordinates.x = p.x; coordinates.y = p.y; return p; }; } function geometry(o, proj) { return o && o.type in types && types[o.type](o, proj); } var types = { Point: function(o, proj) { var p = proj(o.coordinates), c = po.svg("circle"); c.setAttribute("r", 4.5); c.setAttribute("transform", "translate(" + p.x + "," + p.y + ")"); return c; }, MultiPoint: function(o, proj) { var g = po.svg("g"), c = o.coordinates, p, // proj(c[i]) x, // svg:circle i = -1, n = c.length; while (++i < n) { x = g.appendChild(po.svg("circle")); x.setAttribute("r", 4.5); x.setAttribute("transform", "translate(" + (p = proj(c[i])).x + "," + p.y + ")"); } return g; }, LineString: function(o, proj) { var x = po.svg("path"), d = ["M"], c = o.coordinates, p, // proj(c[i]) i = -1, n = c.length; while (++i < n) d.push((p = proj(c[i])).x, ",", p.y, "L"); d.pop(); if (!d.length) return; x.setAttribute("d", d.join("")); return x; }, MultiLineString: function(o, proj) { var x = po.svg("path"), d = [], ci = o.coordinates, cj, // ci[i] i = -1, j, n = ci.length, m; while (++i < n) { cj = ci[i]; j = -1; m = cj.length; d.push("M"); while (++j < m) d.push((p = proj(cj[j])).x, ",", p.y, "L"); d.pop(); } if (!d.length) return; x.setAttribute("d", d.join("")); return x; }, Polygon: function(o, proj) { var x = po.svg("path"), d = [], ci = o.coordinates, cj, // ci[i] i = -1, j, n = ci.length, m; while (++i < n) { cj = ci[i]; j = -1; m = cj.length - 1; d.push("M"); while (++j < m) d.push((p = proj(cj[j])).x, ",", p.y, "L"); d[d.length - 1] = "Z"; } if (!d.length) return; x.setAttribute("d", d.join("")); return x; }, MultiPolygon: function(o, proj) { var x = po.svg("path"), d = [], ci = o.coordinates, cj, // ci[i] ck, // cj[j] i = -1, j, k, n = ci.length, m, l; while (++i < n) { cj = ci[i]; j = -1; m = cj.length; while (++j < m) { ck = cj[j]; k = -1; l = ck.length - 1; d.push("M"); while (++k < l) d.push((p = proj(ck[k])).x, ",", p.y, "L"); d[d.length - 1] = "Z"; } } if (!d.length) return; x.setAttribute("d", d.join("")); return x; }, GeometryCollection: function(o, proj) { var g = po.svg("g"), i = -1, c = o.geometries, n = c.length, x; while (++i < n) { x = geometry(c[i], proj); if (x) g.appendChild(x); } return g; } }; function rescale(o, e, k) { return o.type in rescales && rescales[o.type](o, e, k); } var rescales = { Point: function (o, e, k) { var p = o.coordinates; e.setAttribute("transform", "translate(" + p.x + "," + p.y + ")" + k); }, MultiPoint: function (o, e, k) { var c = o.coordinates, i = -1, n = p.length, x = e.firstChild, p; while (++i < n) { p = c[i]; x.setAttribute("transform", "translate(" + p.x + "," + p.y + ")" + k); x = x.nextSibling; } } }; function load(tile, proj) { var g = tile.element = po.svg("g"); tile.features = []; proj = projection(proj(tile).locationPoint); function update(data) { var updated = []; /* Fetch the next batch of features, if so directed. */ if (data.next) tile.request = fetch(data.next.href, update); /* Convert the GeoJSON to SVG. */ switch (data.type) { case "FeatureCollection": { for (var i = 0; i < data.features.length; i++) { var feature = data.features[i], element = geometry(feature.geometry, proj); if (element) updated.push({element: g.appendChild(element), data: feature}); } break; } case "Feature": { var element = geometry(data.geometry, proj); if (element) updated.push({element: g.appendChild(element), data: data}); break; } default: { var element = geometry(data, proj); if (element) updated.push({element: g.appendChild(element), data: {type: "Feature", geometry: data}}); break; } } tile.ready = true; updated.push.apply(tile.features, updated); geoJson.dispatch({type: "load", tile: tile, features: updated}); } if (url != null) { tile.request = fetch(typeof url == "function" ? url(tile) : url, update); } else { update({type: "FeatureCollection", features: features || []}); } } function unload(tile) { if (tile.request) tile.request.abort(true); } function move() { var zoom = geoJson.map().zoom(), tiles = geoJson.cache.locks(), // visible tiles key, // key in locks tile, // locks[key] features, // tile.features i, // current feature index n, // current feature count, features.length feature, // features[i] k; // scale transform if (scale == "fixed") { for (key in tiles) { if ((tile = tiles[key]).scale != zoom) { k = "scale(" + Math.pow(2, tile.zoom - zoom) + ")"; i = -1; n = (features = tile.features).length; while (++i < n) rescale((feature = features[i]).data.geometry, feature.element, k); tile.scale = zoom; } } } else { for (key in tiles) { i = -1; n = (features = (tile = tiles[key]).features).length; while (++i < n) rescale((feature = features[i]).data.geometry, feature.element, ""); delete tile.scale; } } } geoJson.url = function(x) { if (!arguments.length) return url; url = typeof x == "string" && /{.}/.test(x) ? po.url(x) : x; if (url != null) features = null; if (typeof url == "string") geoJson.tile(false); return geoJson.reload(); }; geoJson.features = function(x) { if (!arguments.length) return features; if (features = x) { url = null; geoJson.tile(false); } return geoJson.reload(); }; geoJson.clip = function(x) { if (!arguments.length) return clip; if (clip) container.removeChild(clipPath); if (clip = x) container.insertBefore(clipPath, container.firstChild); var locks = geoJson.cache.locks(); for (var key in locks) { if (clip) locks[key].element.setAttribute("clip-path", clipHref); else locks[key].element.removeAttribute("clip-path"); } return geoJson; }; var __tile__ = geoJson.tile; geoJson.tile = function(x) { if (arguments.length && !x) geoJson.clip(x); return __tile__.apply(geoJson, arguments); }; var __map__ = geoJson.map; geoJson.map = function(x) { if (x && clipRect) { var size = x.tileSize(); clipRect.setAttribute("width", size.x); clipRect.setAttribute("height", size.y); } return __map__.apply(geoJson, arguments); }; geoJson.scale = function(x) { if (!arguments.length) return scale; if (scale = x) geoJson.on("move", move); else geoJson.off("move", move); if (geoJson.map()) move(); return geoJson; }; geoJson.show = function(tile) { if (clip) tile.element.setAttribute("clip-path", clipHref); else tile.element.removeAttribute("clip-path"); geoJson.dispatch({type: "show", tile: tile, features: tile.features}); return geoJson; }; geoJson.reshow = function() { var locks = geoJson.cache.locks(); for (var key in locks) geoJson.show(locks[key]); return geoJson; }; return geoJson; }; po.dblclick = function() { var dblclick = {}, zoom = "mouse", map, container; function handle(e) { var z = map.zoom(); if (e.shiftKey) z = Math.ceil(z) - z - 1; else z = 1 - z + Math.floor(z); zoom === "mouse" ? map.zoomBy(z, map.mouse(e)) : map.zoomBy(z); } dblclick.zoom = function(x) { if (!arguments.length) return zoom; zoom = x; return dblclick; }; dblclick.map = function(x) { if (!arguments.length) return map; if (map) { container.removeEventListener("dblclick", handle, false); container = null; } if (map = x) { container = map.container(); container.addEventListener("dblclick", handle, false); } return dblclick; }; return dblclick; }; po.drag = function() { var drag = {}, map, container, dragging; function mousedown(e) { if (e.shiftKey) return; dragging = { x: e.clientX, y: e.clientY }; map.focusableParent().focus(); e.preventDefault(); document.body.style.setProperty("cursor", "move", null); } function mousemove(e) { if (!dragging) return; map.panBy({x: e.clientX - dragging.x, y: e.clientY - dragging.y}); dragging.x = e.clientX; dragging.y = e.clientY; } function mouseup(e) { if (!dragging) return; mousemove(e); dragging = null; document.body.style.removeProperty("cursor"); } drag.map = function(x) { if (!arguments.length) return map; if (map) { container.removeEventListener("mousedown", mousedown, false); container = null; } if (map = x) { container = map.container(); container.addEventListener("mousedown", mousedown, false); } return drag; }; window.addEventListener("mousemove", mousemove, false); window.addEventListener("mouseup", mouseup, false); return drag; }; po.wheel = function() { var wheel = {}, timePrev = 0, last = 0, smooth = true, zoom = "mouse", location, map, container; function move(e) { location = null; } // mousewheel events are totally broken! // https://bugs.webkit.org/show_bug.cgi?id=40441 // not only that, but Chrome and Safari differ in re. to acceleration! var inner = document.createElement("div"), outer = document.createElement("div"); outer.style.visibility = "hidden"; outer.style.top = "0px"; outer.style.height = "0px"; outer.style.width = "0px"; outer.style.overflowY = "scroll"; inner.style.height = "2000px"; outer.appendChild(inner); document.body.appendChild(outer); function mousewheel(e) { var delta = e.wheelDelta || -e.detail, point; /* Detect the pixels that would be scrolled by this wheel event. */ if (delta) { if (smooth) { try { outer.scrollTop = 1000; outer.dispatchEvent(e); delta = 1000 - outer.scrollTop; } catch (error) { // Derp! Hope for the best? } delta *= .005; } /* If smooth zooming is disabled, batch events into unit steps. */ else { var timeNow = Date.now(); if (timeNow - timePrev > 200) { delta = delta > 0 ? +1 : -1; timePrev = timeNow; } else { delta = 0; } } } if (delta) { switch (zoom) { case "mouse": { point = map.mouse(e); if (!location) location = map.pointLocation(point); map.off("move", move).zoomBy(delta, point, location).on("move", move); break; } case "location": { map.zoomBy(delta, map.locationPoint(location), location); break; } default: { // center map.zoomBy(delta); break; } } } e.preventDefault(); return false; // for Firefox } wheel.smooth = function(x) { if (!arguments.length) return smooth; smooth = x; return wheel; }; wheel.zoom = function(x, l) { if (!arguments.length) return zoom; zoom = x; location = l; if (map) { if (zoom == "mouse") map.on("move", move); else map.off("move", move); } return wheel; }; wheel.map = function(x) { if (!arguments.length) return map; if (map) { container.removeEventListener("mousemove", move, false); container.removeEventListener("mousewheel", mousewheel, false); container.removeEventListener("MozMousePixelScroll", mousewheel, false); container = null; map.off("move", move); } if (map = x) { if (zoom == "mouse") map.on("move", move); container = map.container(); container.addEventListener("mousemove", move, false); container.addEventListener("mousewheel", mousewheel, false); container.addEventListener("MozMousePixelScroll", mousewheel, false); } return wheel; }; return wheel; }; po.arrow = function() { var arrow = {}, key = {left: 0, right: 0, up: 0, down: 0}, last = 0, repeatTimer, repeatDelay = 250, repeatInterval = 50, speed = 16, map, parent; function keydown(e) { if (e.ctrlKey || e.altKey || e.metaKey) return; var now = Date.now(), dx = 0, dy = 0; switch (e.keyCode) { case 37: { if (!key.left) { last = now; key.left = 1; if (!key.right) dx = speed; } break; } case 39: { if (!key.right) { last = now; key.right = 1; if (!key.left) dx = -speed; } break; } case 38: { if (!key.up) { last = now; key.up = 1; if (!key.down) dy = speed; } break; } case 40: { if (!key.down) { last = now; key.down = 1; if (!key.up) dy = -speed; } break; } default: return; } if (dx || dy) map.panBy({x: dx, y: dy}); if (!repeatTimer && (key.left | key.right | key.up | key.down)) { repeatTimer = setInterval(repeat, repeatInterval); } e.preventDefault(); } function keyup(e) { last = Date.now(); switch (e.keyCode) { case 37: key.left = 0; break; case 39: key.right = 0; break; case 38: key.up = 0; break; case 40: key.down = 0; break; default: return; } if (repeatTimer && !(key.left | key.right | key.up | key.down)) { repeatTimer = clearInterval(repeatTimer); } e.preventDefault(); } function keypress(e) { switch (e.charCode) { case 45: case 95: map.zoom(Math.ceil(map.zoom()) - 1); break; // - _ case 43: case 61: map.zoom(Math.floor(map.zoom()) + 1); break; // = + default: return; } e.preventDefault(); } function repeat() { if (!map) return; if (Date.now() < last + repeatDelay) return; var dx = (key.left - key.right) * speed, dy = (key.up - key.down) * speed; if (dx || dy) map.panBy({x: dx, y: dy}); } arrow.map = function(x) { if (!arguments.length) return map; if (map) { parent.removeEventListener("keypress", keypress, false); parent.removeEventListener("keydown", keydown, false); parent.removeEventListener("keyup", keyup, false); parent = null; } if (map = x) { parent = map.focusableParent(); parent.addEventListener("keypress", keypress, false); parent.addEventListener("keydown", keydown, false); parent.addEventListener("keyup", keyup, false); } return arrow; }; arrow.speed = function(x) { if (!arguments.length) return speed; speed = x; return arrow; }; return arrow; }; po.hash = function() { var hash = {}, s0, // cached location.hash lat = 90 - 1e-8, // allowable latitude range map; var parser = function(map, s) { var args = s.split("/").map(Number); if (args.length < 3 || args.some(isNaN)) return true; // replace bogus hash else { var size = map.size(); map.zoomBy(args[0] - map.zoom(), {x: size.x / 2, y: size.y / 2}, {lat: Math.min(lat, Math.max(-lat, args[1])), lon: args[2]}); } }; var formatter = function(map) { var center = map.center(), zoom = map.zoom(), precision = Math.max(0, Math.ceil(Math.log(zoom) / Math.LN2)); return "#" + zoom.toFixed(2) + "/" + center.lat.toFixed(precision) + "/" + center.lon.toFixed(precision); }; function move() { var s1 = formatter(map); if (s0 !== s1) location.replace(s0 = s1); // don't recenter the map! } function hashchange() { if (location.hash === s0) return; // ignore spurious hashchange events if (parser(map, (s0 = location.hash).substring(1))) move(); // replace bogus hash } hash.map = function(x) { if (!arguments.length) return map; if (map) { map.off("move", move); window.removeEventListener("hashchange", hashchange, false); } if (map = x) { map.on("move", move); window.addEventListener("hashchange", hashchange, false); location.hash ? hashchange() : move(); } return hash; }; hash.parser = function(x) { if (!arguments.length) return parser; parser = x; return hash; }; hash.formatter = function(x) { if (!arguments.length) return formatter; formatter = x; return hash; }; return hash; }; po.touch = function() { var touch = {}, map, container, rotate = false, last = 0, zoom, angle, locations = {}; // touch identifier -> location window.addEventListener("touchmove", touchmove, false); function touchstart(e) { var i = -1, n = e.touches.length, t = Date.now(); // doubletap detection if ((n == 1) && (t - last < 300)) { var z = map.zoom(); map.zoomBy(1 - z + Math.floor(z), map.mouse(e.touches[0])); e.preventDefault(); } last = t; // 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)); } } function touchmove(e) { switch (e.touches.length) { case 1: { // single-touch pan var t0 = e.touches[0]; map.zoomBy(0, map.mouse(t0), locations[t0.identifier]); e.preventDefault(); break; } case 2: { // double-touch pan + zoom + rotate var t0 = e.touches[0], t1 = e.touches[1], p0 = map.mouse(t0), p1 = map.mouse(t1), p2 = {x: (p0.x + p1.x) / 2, y: (p0.y + p1.y) / 2}, // center point 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 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; } } } touch.rotate = function(x) { if (!arguments.length) return rotate; rotate = x; return touch; }; touch.map = function(x) { if (!arguments.length) return map; if (map) { container.removeEventListener("touchstart", touchstart, false); container = null; } if (map = x) { container = map.container(); container.addEventListener("touchstart", touchstart, false); } return touch; }; return touch; }; // Default map controls. po.interact = function() { var interact = {}, drag = po.drag(), wheel = po.wheel(), dblclick = po.dblclick(), touch = po.touch(), arrow = po.arrow(); interact.map = function(x) { drag.map(x); wheel.map(x); dblclick.map(x); touch.map(x); arrow.map(x); return interact; }; return interact; }; po.compass = function() { var compass = {}, g = po.svg("g"), ticks = {}, r = 30, speed = 16, last = 0, repeatDelay = 250, repeatInterval = 50, position = "top-left", // top-left, top-right, bottom-left, bottom-right zoomStyle = "small", // none, small, big zoomContainer, panStyle = "small", // none, small panTimer, panDirection, panContainer, drag, dragRect = po.svg("rect"), map, container, window; g.setAttribute("class", "compass"); dragRect.setAttribute("class", "back fore"); dragRect.setAttribute("pointer-events", "none"); dragRect.setAttribute("display", "none"); function panStart(e) { g.setAttribute("class", "compass active"); if (!panTimer) panTimer = setInterval(panRepeat, repeatInterval); if (panDirection) map.panBy(panDirection); last = Date.now(); return cancel(e); } function panRepeat() { if (panDirection && (Date.now() > last + repeatDelay)) { map.panBy(panDirection); } } function mousedown(e) { if (e.shiftKey) { drag = {x0: map.mouse(e)}; map.focusableParent().focus(); return cancel(e); } } function mousemove(e) { if (!drag) return; drag.x1 = map.mouse(e); dragRect.setAttribute("x", Math.min(drag.x0.x, drag.x1.x)); dragRect.setAttribute("y", Math.min(drag.x0.y, drag.x1.y)); dragRect.setAttribute("width", Math.abs(drag.x0.x - drag.x1.x)); dragRect.setAttribute("height", Math.abs(drag.x0.y - drag.x1.y)); dragRect.removeAttribute("display"); } function mouseup(e) { g.setAttribute("class", "compass"); if (drag) { if (drag.x1) { map.extent([ map.pointLocation({ x: Math.min(drag.x0.x, drag.x1.x), y: Math.max(drag.x0.y, drag.x1.y) }), map.pointLocation({ x: Math.max(drag.x0.x, drag.x1.x), y: Math.min(drag.x0.y, drag.x1.y) }) ]); dragRect.setAttribute("display", "none"); } drag = null; } if (panTimer) { clearInterval(panTimer); panTimer = 0; } } function panBy(x) { return function() { x ? this.setAttribute("class", "active") : this.removeAttribute("class"); panDirection = x; }; } function zoomBy(x) { return function(e) { g.setAttribute("class", "compass active"); var z = map.zoom(); map.zoom(x < 0 ? Math.ceil(z) - 1 : Math.floor(z) + 1); return cancel(e); }; } function zoomTo(x) { return function(e) { map.zoom(x); return cancel(e); }; } function zoomOver() { this.setAttribute("class", "active"); } function zoomOut() { this.removeAttribute("class"); } function cancel(e) { e.stopPropagation(); e.preventDefault(); return false; } function pan(by) { var x = Math.SQRT1_2 * r, y = r * .7, z = r * .2, g = po.svg("g"), dir = g.appendChild(po.svg("path")), chv = g.appendChild(po.svg("path")); dir.setAttribute("class", "direction"); dir.setAttribute("pointer-events", "all"); dir.setAttribute("d", "M0,0L" + x + "," + x + "A" + r + "," + r + " 0 0,1 " + -x + "," + x + "Z"); chv.setAttribute("class", "chevron"); chv.setAttribute("d", "M" + z + "," + (y - z) + "L0," + y + " " + -z + "," + (y - z)); chv.setAttribute("pointer-events", "none"); g.addEventListener("mousedown", panStart, false); g.addEventListener("mouseover", panBy(by), false); g.addEventListener("mouseout", panBy(null), false); g.addEventListener("dblclick", cancel, false); return g; } function zoom(by) { var x = r * .4, y = x / 2, g = po.svg("g"), back = g.appendChild(po.svg("path")), dire = g.appendChild(po.svg("path")), chev = g.appendChild(po.svg("path")), fore = g.appendChild(po.svg("path")); back.setAttribute("class", "back"); back.setAttribute("d", "M" + -x + ",0V" + -x + "A" + x + "," + x + " 0 1,1 " + x + "," + -x + "V0Z"); dire.setAttribute("class", "direction"); dire.setAttribute("d", back.getAttribute("d")); chev.setAttribute("class", "chevron"); chev.setAttribute("d", "M" + -y + "," + -x + "H" + y + (by > 0 ? "M0," + (-x - y) + "V" + -y : "")); fore.setAttribute("class", "fore"); fore.setAttribute("fill", "none"); fore.setAttribute("d", back.getAttribute("d")); g.addEventListener("mousedown", zoomBy(by), false); g.addEventListener("mouseover", zoomOver, false); g.addEventListener("mouseout", zoomOut, false); g.addEventListener("dblclick", cancel, false); return g; } function tick(i) { var x = r * .2, y = r * .4, g = po.svg("g"), back = g.appendChild(po.svg("rect")), chev = g.appendChild(po.svg("path")); back.setAttribute("pointer-events", "all"); back.setAttribute("fill", "none"); back.setAttribute("x", -y); back.setAttribute("y", -.75 * y); back.setAttribute("width", 2 * y); back.setAttribute("height", 1.5 * y); chev.setAttribute("class", "chevron"); chev.setAttribute("d", "M" + -x + ",0H" + x); g.addEventListener("mousedown", zoomTo(i), false); g.addEventListener("dblclick", cancel, false); return g; } function move() { var x = r + 6, y = x, size = map.size(); switch (position) { case "top-left": break; case "top-right": x = size.x - x; break; case "bottom-left": y = size.y - y; break; case "bottom-right": x = size.x - x; y = size.y - y; break; } g.setAttribute("transform", "translate(" + x + "," + y + ")"); dragRect.setAttribute("transform", "translate(" + -x + "," + -y + ")"); for (var i in ticks) { i == map.zoom() ? ticks[i].setAttribute("class", "active") : ticks[i].removeAttribute("class"); } } function draw() { while (g.lastChild) g.removeChild(g.lastChild); g.appendChild(dragRect); if (panStyle != "none") { panContainer = g.appendChild(po.svg("g")); panContainer.setAttribute("class", "pan"); var back = panContainer.appendChild(po.svg("circle")); back.setAttribute("class", "back"); back.setAttribute("r", r); var s = panContainer.appendChild(pan({x: 0, y: -speed})); s.setAttribute("transform", "rotate(0)"); var w = panContainer.appendChild(pan({x: speed, y: 0})); w.setAttribute("transform", "rotate(90)"); var n = panContainer.appendChild(pan({x: 0, y: speed})); n.setAttribute("transform", "rotate(180)"); var e = panContainer.appendChild(pan({x: -speed, y: 0})); e.setAttribute("transform", "rotate(270)"); var fore = panContainer.appendChild(po.svg("circle")); fore.setAttribute("fill", "none"); fore.setAttribute("class", "fore"); fore.setAttribute("r", r); } else { panContainer = null; } if (zoomStyle != "none") { zoomContainer = g.appendChild(po.svg("g")); zoomContainer.setAttribute("class", "zoom"); var j = -.5; if (zoomStyle == "big") { ticks = {}; for (var i = map.zoomRange()[0], j = 0; i <= map.zoomRange()[1]; i++, j++) { (ticks[i] = zoomContainer.appendChild(tick(i))) .setAttribute("transform", "translate(0," + (-(j + .75) * r * .4) + ")"); } } var p = panStyle == "none" ? .4 : 2; zoomContainer.setAttribute("transform", "translate(0," + r * (/^top-/.test(position) ? (p + (j + .5) * .4) : -p) + ")"); zoomContainer.appendChild(zoom(+1)).setAttribute("transform", "translate(0," + (-(j + .5) * r * .4) + ")"); zoomContainer.appendChild(zoom(-1)).setAttribute("transform", "scale(-1)"); } else { zoomContainer = null; } move(); } compass.radius = function(x) { if (!arguments.length) return r; r = x; if (map) draw(); return compass; }; compass.speed = function(x) { if (!arguments.length) return r; speed = x; return compass; }; compass.position = function(x) { if (!arguments.length) return position; position = x; if (map) draw(); return compass; }; compass.pan = function(x) { if (!arguments.length) return panStyle; panStyle = x; if (map) draw(); return compass; }; compass.zoom = function(x) { if (!arguments.length) return zoomStyle; zoomStyle = x; if (map) draw(); return compass; }; compass.map = function(x) { if (!arguments.length) return map; if (map) { container.removeEventListener("mousedown", mousedown, false); container.removeChild(g); container = null; window.removeEventListener("mousemove", mousemove, false); window.removeEventListener("mouseup", mouseup, false); window = null; map.off("move", move).off("resize", move); } if (map = x) { container = map.container(); container.appendChild(g); container.addEventListener("mousedown", mousedown, false); window = container.ownerDocument.defaultView; window.addEventListener("mousemove", mousemove, false); window.addEventListener("mouseup", mouseup, false); map.on("move", move).on("resize", move); draw(); } return compass; }; return compass; }; po.grid = function() { var grid = {}, map, g = po.svg("g"); g.setAttribute("class", "grid"); function move(e) { var p, line = g.firstChild, size = map.size(), nw = map.pointLocation(zero), se = map.pointLocation(size), step = Math.pow(2, 4 - Math.round(map.zoom())); // Round to step. nw.lat = Math.floor(nw.lat / step) * step; nw.lon = Math.ceil(nw.lon / step) * step; // Longitude ticks. for (var x; (x = map.locationPoint(nw).x) <= size.x; nw.lon += step) { if (!line) line = g.appendChild(po.svg("line")); line.setAttribute("x1", x); line.setAttribute("x2", x); line.setAttribute("y1", 0); line.setAttribute("y2", size.y); line = line.nextSibling; } // Latitude ticks. for (var y; (y = map.locationPoint(nw).y) <= size.y; nw.lat -= step) { if (!line) line = g.appendChild(po.svg("line")); line.setAttribute("y1", y); line.setAttribute("y2", y); line.setAttribute("x1", 0); line.setAttribute("x2", size.x); line = line.nextSibling; } // Remove extra ticks. while (line) { var next = line.nextSibling; g.removeChild(line); line = next; } } grid.map = function(x) { if (!arguments.length) return map; if (map) { g.parentNode.removeChild(g); map.off("move", move).off("resize", move); } if (map = x) { map.on("move", move).on("resize", move); map.container().appendChild(g); map.dispatch({type: "move"}); } return grid; }; return grid; }; po.stylist = function() { var attrs = [], styles = [], title; function stylist(e) { var ne = e.features.length, na = attrs.length, ns = styles.length, f, // feature d, // data o, // element x, // attr or style or title descriptor v, // attr or style or title value i, j; for (i = 0; i < ne; ++i) { if (!(o = (f = e.features[i]).element)) continue; d = f.data; for (j = 0; j < na; ++j) { v = (x = attrs[j]).value; if (typeof v === "function") v = v.call(null, d); v == null ? (x.name.local ? o.removeAttributeNS(x.name.space, x.name.local) : o.removeAttribute(x.name)) : (x.name.local ? o.setAttributeNS(x.name.space, x.name.local, v) : o.setAttribute(x.name, v)); } for (j = 0; j < ns; ++j) { v = (x = styles[j]).value; if (typeof v === "function") v = v.call(null, d); v == null ? o.style.removeProperty(x.name) : o.style.setProperty(x.name, v, x.priority); } if (v = title) { if (typeof v === "function") v = v.call(null, d); while (o.lastChild) o.removeChild(o.lastChild); if (v != null) o.appendChild(po.svg("title")).appendChild(document.createTextNode(v)); } } } stylist.attr = function(n, v) { attrs.push({name: ns(n), value: v}); return stylist; }; stylist.style = function(n, v, p) { styles.push({name: n, value: v, priority: arguments.length < 3 ? null : p}); return stylist; }; stylist.title = function(v) { title = v; return stylist; }; return stylist; }; })(org.polymaps); polymaps/README.mkd0000664000175000017500000000532311740644523013327 0ustar daviddavid# Polymaps Polymaps is a free JavaScript library for making dynamic, interactive maps in modern web browsers. See for more details. This is the `master` branch, which contains the Polymaps source code. If you're looking for the Polymaps website, you should checkout the `gh-pages` branch instead. ## Viewing Examples You'll find lots of Polymaps examples in the suitably-named `examples` directory. Open any of the HTML files there in your browser to view the examples, or open them in your text editor of choice to view the source. Most of the examples are replicated on the [Polymaps website](http://polymaps.org), though a few of them are only visible locally. Some of the examples depend on third-party libraries, such as jQuery. These third-party libraries are not required to use Polymaps but can certainly make it easier! All third-party libraries should be stored in the `lib` directory, with an associated `LICENSE` file and optional `README`. ## Filing Bugs We use GitHub to track issues with Polymaps. You can search for existing issues, and file new issues, here: You are welcome to file issues either for bugs in the source code, feature requests, or issues with the Polymaps website. ## Support If you have questions or problems regarding Polymaps, you can get help by joining the `#polymaps` IRC channel on irc.freenode.net. You are also welcome to send GitHub messages or tweets to `mbostock`. ## Build Instructions You do not need to build Polymaps in order to view the examples; a compiled copy of Polymaps (`polymaps.js` and `polymaps.min.js`) is included in the repository. To edit and build a new version of Polymaps, you must first install Java and GNU Make. If you are on Mac OS X, you can install Make as part of the UNIX tools included with [XCode](http://developer.apple.com/technologies/xcode.html). Once you've setup your development environment, you can rebuild Polymaps by running the following command from the repo's root directory: make The Polymaps build process is exceptionally simple. First, all the JavaScript files are concatenated (using `cat`); the order of files is important to preserve dependencies. This produces the file `polymaps.js`. Second, this file is put through Google's [Closure Compiler](http://code.google.com/closure/compiler/) to minify the JavaScript, resulting in a smaller `polymaps.min.js`. If you are doing development, it is highly recommended that you use the non-minified JavaScript for easier debugging. The minified JavaScript is only intended for production, where file size matters. Note that the development version is marked as read-only so that you don't accidentally overwrite your edits after a re-build. polymaps/polymaps.min.js0000664000175000017500000010005111740647057014660 0ustar daviddavidif(!org)var org={};if(!org.polymaps)org.polymaps={}; (function(r){function ea(d){var h=d.indexOf(":");return h<0?d:{space:r.ns[d.substring(0,h)],local:d.substring(h+1)}}function R(){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 ba(d,h,a,m,e){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,t=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&&ba(d,g,m,e,c);h.dy&&ba(d,h,m,e,c)}r.version="2.5.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,e,c){var g={},k,t,n;if(!arguments.length){d=1;h=e=a=0;m=1;c=0}g.zoomFraction=function(l){if(!arguments.length)return t;t=l;k=Math.floor(t+Math.log(Math.sqrt(d*d+h*h+a*a+m*m))/Math.LN2);n=Math.pow(2,-k);return g};g.apply=function(l){var i=Math.pow(2,-l.zoom),q= Math.pow(2,l.zoom-k);return{column:(d*l.column*i+a*l.row*i+e)*q,row:(h*l.column*i+m*l.row*i+c)*q,zoom:l.zoom-k}};g.unapply=function(l){var i=Math.pow(2,-l.zoom),q=Math.pow(2,l.zoom+k);return{column:(l.column*i*m-l.row*i*a-e*m+c*a)/(d*m-h*a)*q,row:(l.column*i*h-l.row*i*d-e*h+c*d)/(a*h-m*d)*q,zoom:l.zoom+k}};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){l--;h&&h(i);delete g[i.key];if(i.next)i.next.prev=i.prev; else if(t=i.prev)t.next=null;if(i.prev)i.prev.next=i.next;else if(k=i.next)k.prev=null}function m(){for(var i=t;l>n;i=i.prev){if(!i)break;i.lock||a(i)}}var e={},c={},g={},k=null,t=null,n=64,l=0;e.peek=function(i){return g[[i.zoom,i.column,i.row].join("/")]};e.load=function(i,q){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 t=A.prev;A.prev=null;A.next=k;k=k.prev=A}A.lock=1;return c[w]=A}A={key:w,column:i.column,row:i.row,zoom:i.zoom,next:k, prev:null,lock:1};d.call(null,A,q);c[w]=g[w]=A;if(k)k.prev=A;else t=A;k=A;l++;return A};e.unload=function(i){if(!(i in c))return false;var q=c[i];q.lock=0;delete c[i];q.request&&q.request.abort(false)&&a(q);return q};e.locks=function(){return c};e.size=function(i){if(!arguments.length)return n;n=i;m();return e};e.flush=function(){m();return e};e.clear=function(){for(var i in g){var q=g[i];q.request&&q.request.abort(false);h&&h(g[i]);if(q.lock){q.lock=0;q.element.parentNode.removeChild(q.element)}}c= {};g={};k=t=null;l=0;return e};return e};r.url=function(d){function h(e){var c=e.zoom<0?1:1<=c)return null;return d.replace(/{(.)}/g,function(k,t){switch(t){case "S":return a[(Math.abs(e.zoom)+e.row+g)%a.length];case "Z":return e.zoom;case "X":return g;case "Y":return e.row;case "B":var n=r.map.coordinateLocation({row:e.row,column:g,zoom:e.zoom}),l=r.map.coordinateLocation({row:e.row+1,column:g+1,zoom:e.zoom}),i=Math.ceil(Math.log(e.zoom)/ Math.LN2);return l.lat.toFixed(i)+","+n.lon.toFixed(i)+","+n.lat.toFixed(i)+","+l.lon.toFixed(i)}return t})}var a=[],m=true;h.template=function(e){if(!arguments.length)return d;d=e;return h};h.hosts=function(e){if(!arguments.length)return a;a=e;return h};h.repeat=function(e){if(!arguments.length)return m;m=e;return h};return h};r.dispatch=function(d){var h={};d.on=function(a,m){for(var e=h[a]||(h[a]=[]),c=0;c=c||!m.length)){e++;m.pop()()}}function h(g){for(var k=0;kq[1])n=q[1];l=n-(n=Math.round(n));i=Math.pow(2,l)}function h(){if(o){var f=45/Math.pow(2,n+l-3),u=Math.max(Math.abs(C*g.x+ A*g.y),Math.abs(B*g.x+E*g.y)),s=V(K-u*f/k.y);u=V(j+u*f/k.y);t.lat=Math.max(s,Math.min(u,t.lat));s=Math.max(Math.abs(C*g.y+A*g.x),Math.abs(B*g.y+E*g.x));t.lon=Math.max(o[0].lon-s*f/k.x,Math.min(o[1].lon+s*f/k.x,t.lon))}}var a={},m,e,c=Y,g=Y,k={x:256,y:256},t={lat:37.76487,lon:-122.41948},n=12,l=0,i=1,q=[1,18],w=0,A=1,C=0,E=1,B=0,K=-180,j=180,o=[{lat:V(K),lon:-Infinity},{lat:V(j),lon:Infinity}];a.locationCoordinate=function(f){f=r.map.locationCoordinate(f);var u=Math.pow(2,n);f.column*=u;f.row*=u;f.zoom+= n;return f};a.coordinateLocation=r.map.coordinateLocation;a.coordinatePoint=function(f,u){var s=Math.pow(2,n-u.zoom),z=Math.pow(2,n-f.zoom),v=(u.column*s-f.column*z)*k.x*i;s=(u.row*s-f.row*z)*k.y*i;return{x:g.x+A*v-C*s,y:g.y+C*v+A*s}};a.pointCoordinate=function(f,u){var s=Math.pow(2,n-f.zoom),z=(u.x-g.x)/i,v=(u.y-g.y)/i;return{column:f.column*s+(E*z-B*v)/k.x,row:f.row*s+(B*z+E*v)/k.y,zoom:n}};a.locationPoint=function(f){var u=Math.pow(2,n+l-3)/45,s=(f.lon-t.lon)*u*k.x;f=(W(t.lat)-W(f.lat))*u*k.y; return{x:g.x+A*s-C*f,y:g.y+C*s+A*f}};a.pointLocation=function(f){var u=45/Math.pow(2,n+l-3),s=(f.x-g.x)*u;f=(f.y-g.y)*u;return{lon:t.lon+(E*s-B*f)/k.x,lat:V(W(t.lat)-(B*s+E*f)/k.y)}};var x=r.svg("rect");x.setAttribute("visibility","hidden");x.setAttribute("pointer-events","all");a.container=function(f){if(!arguments.length)return m;m=f;m.setAttribute("class","map");m.appendChild(x);return a.resize()};a.focusableParent=function(){for(var f=m;f;f=f.parentNode)if(f.tabIndex>=0)return f;return window}; a.mouse=function(f){var u=(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($){u.x=f.pageX;u.y=f.pageY}else{u.x=f.clientX;u.y=f.clientY}return u.matrixTransform(m.getScreenCTM().inverse())};a.size=function(f){if(!arguments.length)return c;e=f;return a.resize()};a.resize=function(){if(e){c=e;R.remove(a)}else{x.setAttribute("width", "100%");x.setAttribute("height","100%");b=x.getBBox();c={x:b.width,y:b.height};R.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(f){if(!arguments.length)return k;k=f;a.dispatch({type:"move"});return a};a.center=function(f){if(!arguments.length)return t;t=f;h();a.dispatch({type:"move"});return a};a.panBy=function(f){var u=45/Math.pow(2,n+l-3),s=f.x*u;f=f.y*u;return a.center({lon:t.lon+(B*f-E*s)/k.x,lat:V(W(t.lat)+ (B*s+E*f)/k.y)})};a.centerRange=function(f){if(!arguments.length)return o;if(o=f){K=o[0].lat>-90?W(o[0].lat):-Infinity;j=o[0].lat<90?W(o[1].lat):Infinity}else{K=-Infinity;j=Infinity}h();a.dispatch({type:"move"});return a};a.zoom=function(f){if(!arguments.length)return n+l;n=f;d();return a.center(t)};a.zoomBy=function(f,u,s){if(arguments.length<2)return a.zoom(n+l+f);if(arguments.length<3)s=a.pointLocation(u);n=n+l+f;d();var z=a.locationPoint(s);return a.panBy({x:u.x-z.x,y:u.y-z.y})};a.zoomRange=function(f){if(!arguments.length)return q; q=f;return a.zoom(n+l)};a.extent=function(f){if(!arguments.length)return[a.pointLocation({x:0,y:c.y}),a.pointLocation({x:c.x,y:0})];var u=a.locationPoint(f[0]),s=a.locationPoint(f[1]),z=Math.max((s.x-u.x)/c.x,(u.y-s.y)/c.y);u=a.pointLocation({x:(u.x+s.x)/2,y:(u.y+s.y)/2});n=n+l-Math.log(z)/Math.LN2;d();return a.center(u)};a.angle=function(f){if(!arguments.length)return w;w=f;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(f){f.map(a); return a};a.remove=function(f){f.map(null);return a};a.dispatch=r.dispatch(a);return a};R.maps=[];R.add=function(d){for(var h=0;hB;A--){q.insertBefore(C[-1],K);q.insertBefore(C[2],C[-4]);for(var j=C[2],o=2;o>-4;)C[o]=C[--o];C[o]=j}}function e(){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(),o=j.zoom(),x=o-(o=Math.round(o)),f=j.size(),u=j.angle(),s=j.tileSize(),z=j.locationCoordinate(j.center());if(A!=o){if(Ao)m(o);else A=o;for(var v=-4;v<=2;v++){var L=C[v];L.setAttribute("class","zoom"+(v<0?"":"+")+v+" zoom"+(o+v));L.setAttribute("transform", "scale("+Math.pow(2,-v)+")")}}q.setAttribute("transform","translate("+f.x/2+","+f.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:f.x,y:0});o=j.pointCoordinate(z,f);j=j.pointCoordinate(z,{x:0,y:f.y});if(!x&&!u&&!w){z.column=(Math.round(s.x*z.column)+(f.x&1)/2)/s.x;z.row=(Math.round(s.y*z.row)+(f.y&1)/2)/s.y}if(w){I=w.unapply(I);v=w.unapply(v);o=w.unapply(o);j=w.unapply(j);z=w.unapply(z)}var S= n?n(I.zoom)-I.zoom:0;if(S){f=Math.pow(2,S);I.column*=f;I.row*=f;v.column*=f;v.row*=f;o.column*=f;o.row*=f;j.column*=f;j.row*=f;I.zoom=v.zoom=o.zoom=j.zoom+=S}x=g.locks();var O={};for(var F in x)x[F].proxyCount=0;if(t&&S>-5&&S<3){u=I.zoom<0?1:1<>v<>v<=1;E--)C[E]=q.appendChild(r.svg("g"));C[0]=q.appendChild(r.svg("g"));c.map=function(B){if(!arguments.length)return i;if(i){if(i==B){q.parentNode.appendChild(q);return c}i.off("move",e).off("resize",e);q.parentNode.removeChild(q)}if(i=B){i.container().appendChild(q);c.init&&c.init(q);i.on("move",e).on("resize",e);e()}return c};c.container=function(){return q};c.levels=function(){return C};c.id=function(B){if(!arguments.length)return l;l=B;q.setAttribute("id",B);return c};c.visible=function(B){if(!arguments.length)return t; (t=B)?q.removeAttribute("visibility"):q.setAttribute("visibility","hidden");i&&e();return c};c.transform=function(B){if(!arguments.length)return w;w=B;i&&e();return c};c.zoom=function(B){if(!arguments.length)return n;n=typeof B=="function"||B==null?B:function(){return B};i&&e();return c};c.tile=function(B){if(!arguments.length)return k;k=B;i&&e();return c};c.reload=function(){g.clear();i&&e();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"),e=d.map().tileSize();m.setAttribute("preserveAspectRatio","none");m.setAttribute("width",e.x);m.setAttribute("height",e.y);if(typeof h=="function"){m.setAttribute("opacity",0);e=h(a);if(e!=null)a.request=r.queue.image(m,e,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 o={lat:0,lon:0};return function(x){o.lat=x[1];o.lon=x[0];var f=j(o);x.x=f.x;x.y=f.y;return f}}function a(j, o){return j&&j.type in C&&C[j.type](j,o)}function m(j,o,x){return j.type in E&&E[j.type](j,o,x)}function e(){var j=c.map().zoom(),o=c.cache.locks(),x,f,u,s,z,v,L;if(w=="fixed")for(x in o){if((f=o[x]).scale!=j){L="scale("+Math.pow(2,f.zoom-j)+")";s=-1;for(z=(u=f.features).length;++s 200){q=q>0?+1:-1;m=w}else q=0}if(q)switch(c){case "mouse":w=k.mouse(i);g||(g=k.pointLocation(w));k.off("move",d).zoomBy(q,w,g).on("move",d);break;case "location":k.zoomBy(q,k.locationPoint(g),g);break;default:k.zoomBy(q);break}i.preventDefault();return false}var a={},m=0,e=true,c="mouse",g,k,t,n=document.createElement("div"),l=document.createElement("div");l.style.visibility="hidden";l.style.top="0px";l.style.height="0px";l.style.width="0px";l.style.overflowY="scroll";n.style.height="2000px";l.appendChild(n); document.body.appendChild(l);a.smooth=function(i){if(!arguments.length)return e;e=i;return a};a.zoom=function(i,q){if(!arguments.length)return c;c=i;g=q;if(k)c=="mouse"?k.on("move",d):k.off("move",d);return a};a.map=function(i){if(!arguments.length)return k;if(k){t.removeEventListener("mousemove",d,false);t.removeEventListener("mousewheel",h,false);t.removeEventListener("MozMousePixelScroll",h,false);t=null;k.off("move",d)}if(k=i){c=="mouse"&&k.on("move",d);t=k.container();t.addEventListener("mousemove", d,false);t.addEventListener("mousewheel",h,false);t.addEventListener("MozMousePixelScroll",h,false)}return a};return a};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(!k&&c.left| c.right|c.up|c.down)k=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(k&&!(c.left|c.right|c.up|c.down))k=clearInterval(k);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+f&&H.panBy(S)}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 e(){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");S=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 k(y){return function(D){H.zoom(y);return l(D)}}function t(){this.setAttribute("class","active")}function n(){this.removeAttribute("class")}function l(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",l,false);return M}function q(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",t,false);J.addEventListener("mouseout",n,false);J.addEventListener("dblclick",l,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",k(y),false);J.addEventListener("dblclick",l,false);return J}function A(){var y=j+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",j);O.appendChild(i({x:0,y:-o})).setAttribute("transform","rotate(0)");O.appendChild(i({x:o,y:0})).setAttribute("transform","rotate(90)");O.appendChild(i({x:0,y:o})).setAttribute("transform","rotate(180)");O.appendChild(i({x:-o,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(s)?D+(y+0.5)*0.4:-D)+")");v.appendChild(q(+1)).setAttribute("transform", "translate(0,"+-(y+0.5)*j*0.4+")");v.appendChild(q(-1)).setAttribute("transform","scale(-1)")}else v=null;A()}var E={},B=r.svg("g"),K={},j=30,o=16,x=0,f=250,u=50,s="top-left",z="small",v,L="small",I,S,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;o=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",e,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",e,false);H.on("move",A).on("resize",A);C()}return E};return E};r.grid=function(){function d(){var e=m.firstChild,c=a.size(),g=a.pointLocation(Y);a.pointLocation(c);var k=Math.pow(2,4-Math.round(a.zoom()));g.lat=Math.floor(g.lat/k)*k;g.lon=Math.ceil(g.lon/k)*k;for(var t;(t=a.locationPoint(g).x)<=c.x;g.lon+=k){e||(e=m.appendChild(r.svg("line")));e.setAttribute("x1",t);e.setAttribute("x2",t);e.setAttribute("y1", 0);e.setAttribute("y2",c.y);e=e.nextSibling}for(;(t=a.locationPoint(g).y)<=c.y;g.lat-=k){e||(e=m.appendChild(r.svg("line")));e.setAttribute("y1",t);e.setAttribute("y2",t);e.setAttribute("x1",0);e.setAttribute("x2",c.x);e=e.nextSibling}for(;e;){c=e.nextSibling;m.removeChild(e);e=c}}var h={},a,m=r.svg("g");m.setAttribute("class","grid");h.map=function(e){if(!arguments.length)return a;if(a){m.parentNode.removeChild(m);a.off("move",d).off("resize",d)}if(a=e){a.on("move",d).on("resize",d);a.container().appendChild(m); a.dispatch({type:"move"})}return h};return h};r.stylist=function(){function d(e){var c=e.features.length,g=h.length,k=a.length,t,n,l,i,q,w;for(q=0;q