Created
September 4, 2011 11:18
-
-
Save andrewharvey/1192690 to your computer and use it in GitHub Desktop.
A web map based on Polymaps delivering a 3D experience for viewing NearMap aerial imagery
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!-- | |
This page licensed CC0 http://creativecommons.org/publicdomain/zero/1.0/ | |
Some of the javascript code based of examples at http://polymaps.org/ex/ | |
This is just a prototype/technology test. It probably isn't the cleanest solution... | |
TODO: | |
* Ctrl + click and drag should rotate the map just like the keys do | |
* add perspective option | |
--> | |
<html> | |
<head> | |
<!-- We are using a patched polymaps.js, which can be generated by taking | |
http://github.com/simplegeo/polymaps/zipball/v2.5.0 and applying ./Layer.diff | |
to src/Layer.js, then bulding again. | |
--> | |
<script type="text/javascript" src="/javascript/polymaps/polymaps.min.js"></script> | |
<style type="text/css"> | |
html, body { | |
height: 100%; | |
} | |
body { | |
margin: 0; | |
background: #E5E0D9; | |
} | |
svg { | |
display: block; | |
overflow: hidden; | |
width: 100%; | |
height: 100%; | |
} | |
.text-strip { | |
position: absolute; | |
background: white; | |
opacity: 0.8; | |
font-size: small; | |
box-shadow: 0 0 5px white; | |
} | |
#copyright { | |
right: 0; | |
bottom: 0; | |
} | |
#view-status { | |
left: 0; | |
bottom: 0; | |
} | |
</style> | |
</head> | |
<body id="map"> | |
<div id="view-status" class="text-strip">↔ 0° ↕1 <b>↑</b>Vert</div> | |
<div id="copyright" class="text-strip">Aerial Imagery © <a href="http://www.nearmap.com/">NearMap</a>, used under their <a href="http://www.nearmap.com/products/community-licence">Community License</a></div> | |
<script type="text/javascript"> | |
// the polymaps object | |
var po = org.polymaps; | |
// tweak these to control how fine grain movements are | |
var pitch_step = 0.05; | |
var spin_step = (1/32)*Math.PI; | |
// set up the SVG containers for the map, we need them so we can apply transformations to them | |
var div = document.getElementById("map"), | |
svg = div.appendChild(po.svg("svg")), | |
g = svg.appendChild(po.svg("g")); | |
// define the map layers | |
var nearmap_tile_url = "http://www.nearmap.com/maps/z={Z}&x={X}&y={Y}&nml="; | |
var vert = po.image().url(po.url(nearmap_tile_url + "Vert")); | |
var north = po.image().url(po.url(nearmap_tile_url + "N__")); | |
var south = po.image().url(po.url(nearmap_tile_url + "S__")).tileTransform("rotate(180) translate(-256 -256)"); | |
var east = po.image().url(po.url(nearmap_tile_url + "E__")).tileTransform("rotate(90) translate(0 -256)"); | |
var west = po.image().url(po.url(nearmap_tile_url + "W__")).tileTransform("rotate(270) translate(-256 0)"); | |
var currentLayer = vert; | |
// set up the map | |
var map = po.map() | |
.container(g) | |
.add(currentLayer) | |
.add(po.interact()) | |
.center({lat: -33.852098, lon: 151.210670}) | |
.zoomRange([10, 24]) | |
.zoom(17); | |
// rot is longitude of the view (0 is looking north, PI is looking south, PI/2 is looking west, -PI/2 is looking east) | |
var rot = 0; | |
// pitch is latitude, 1 is looking straight down, 0 is flat across the plane, 0.5 is looking at 45 degrees | |
var pitch = 1; | |
// which keys were pressed down? | |
var key = {left: 0, right: 0, up: 0, down: 0}; | |
// tweak these to control the camera movement speed | |
var repeatTimer, | |
repeatDelay = 250, | |
repeatInterval = 50; | |
function keydown(e) { | |
if (e.type != "keydown" || e.ctrlKey || e.altKey || e.metaKey) return; | |
switch (e.keyCode) { | |
case 65: // left | |
key.left = 1; | |
break; | |
case 69: // right | |
key.right = 1; | |
break; | |
case 188: // up | |
key.up = 1; | |
break; | |
case 79: // down | |
key.down = 1; | |
break; | |
} | |
// move the camera based on what keys are pressed | |
updateView(); | |
if (!repeatTimer && (key.left | key.right | key.up | key.down)) { | |
repeatTimer = setInterval(updateView, repeatInterval); | |
} | |
e.preventDefault(); | |
} | |
function keyup(e) { | |
switch (e.keyCode) { | |
case 65: key.left = 0; break; | |
case 69: key.right = 0; break; | |
case 188: key.up = 0; break; | |
case 79: key.down = 0; break; | |
default: return; | |
} | |
if (repeatTimer && !(key.left | key.right | key.up | key.down)) { | |
repeatTimer = clearInterval(repeatTimer); | |
} | |
e.preventDefault(); | |
} | |
// change the current map layer to newLayer | |
function changeMapLayer(newLayer) { | |
map.remove(currentLayer); | |
currentLayer = newLayer; | |
map.add(currentLayer); | |
} | |
// move the camera based key status | |
function updateView() { | |
if (!map) return; | |
// set new rot and pitch values | |
if (key.right) | |
rot += spin_step; | |
if (key.left) | |
rot += -spin_step; | |
if (key.up) | |
pitch += pitch_step; | |
if (key.down) | |
pitch -= pitch_step; | |
// set limits on the pitch | |
if (pitch > 1) | |
pitch = 1; | |
if (pitch < 0.5) | |
pitch = 0.5; | |
// cap the rot between -PI and PI | |
rot = ((rot + Math.PI) % (2*Math.PI)) - Math.PI; | |
if (rot < -Math.PI) | |
rot += 2*Math.PI; | |
var cx = map.size().x / 2; | |
var cy = map.size().y / 2; | |
// change the layer based on the current pitch | |
if (pitch < 0.8) { | |
// change the layer based on the current rot | |
if ((rot <= (Math.PI/4)) && (rot >= -(Math.PI/4)) && currentLayer != north) { | |
changeMapLayer(north); | |
}else if ((rot < (3*Math.PI/4)) && (rot > (Math.PI/4)) && currentLayer != west) { | |
changeMapLayer(west); | |
}else if ((rot >= (3*Math.PI/4)) || (rot <= (-3*Math.PI/4)) && currentLayer != south) { | |
changeMapLayer(south); | |
}else if ((rot < (-Math.PI/4)) && (rot > (-3*Math.PI/4)) && currentLayer != east) { | |
changeMapLayer(east); | |
} | |
} | |
if ((pitch >= 0.8) && (currentLayer != vert)) { | |
changeMapLayer(vert) | |
} | |
// fill the info bar with details of the current view | |
var layerName; | |
if (currentLayer == vert) | |
layerName = "Vert"; | |
if (currentLayer == north) | |
layerName = "North"; | |
if (currentLayer == south) | |
layerName = "South"; | |
if (currentLayer == east) | |
layerName = "East"; | |
if (currentLayer == west) | |
layerName = "West"; | |
document.getElementById("view-status").innerHTML = "↔" + (rot*180/Math.PI).toFixed(0) + "° ↕" + pitch.toFixed(2) + " <b>↑</b>" + layerName; | |
// rotate the map | |
if (rot) map.angle(rot); | |
/* | |
* transform attribute | |
* eg. transform="translate(10,10) scale(1 2)" | |
* | |
* matrix(<a> <b> <c> <d> <e> <f>) | |
* translate(<tx> [<ty>]) | |
* scale(<sx> [<sy>]) | |
* rotate(<rotate-angle> [<cx> <cy>]) | |
* ...with angle in degrees | |
* skewX(<skew-angle>) | |
* skewY(<skew-angle>) | |
*/ | |
g.setAttribute("transform", | |
"translate(" + cx + " " + cy + ") " + | |
"scale(1 " + pitch + ") " + | |
"translate(" + -cx + " " + -cy + ")"); | |
} | |
window.addEventListener("keydown", keydown, true); | |
window.addEventListener("keyup", keyup, true); | |
</script> | |
</body> | |
</html> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--- Layer.js 2011-04-10 21:10:40.000000000 +1000 | |
+++ Layer.js 2011-09-04 21:11:11.371804701 +1000 | |
@@ -8,6 +8,7 @@ | |
map, | |
container = po.svg("g"), | |
transform, | |
+ tileTransform, | |
levelZoom, | |
levels = {}; | |
@@ -210,9 +211,11 @@ | |
for (var key in newLocks) { | |
var t = newLocks[key], | |
k = Math.pow(2, t.level = t.zoom - tileCenter.zoom); | |
+ if (tileTransform == undefined) | |
+ tileTransform = ""; | |
t.element.setAttribute("transform", "translate(" | |
+ (t.x = tileSize.x * (t.column - tileCenter.column * k)) + "," | |
- + (t.y = tileSize.y * (t.row - tileCenter.row * k)) + ")"); | |
+ + (t.y = tileSize.y * (t.row - tileCenter.row * k)) + ") " + tileTransform); | |
} | |
// remove tiles that are no longer visible | |
@@ -302,6 +305,13 @@ | |
if (map) move(); | |
return layer; | |
}; | |
+ | |
+ layer.tileTransform = function(x) { | |
+ if (!arguments.length) return tileTransform; | |
+ tileTransform = x; | |
+ if (map) move(); | |
+ return layer; | |
+ }; | |
layer.zoom = function(x) { | |
if (!arguments.length) return zoom; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment