An implementation of Great Circles in Polymaps, porting over code from ModestMaps.js. It falls apart across the Date Line but Joe Golike added some logic around splitting the lines for this visualization of International Searches on Trulia.
Created
June 14, 2011 21:56
-
-
Save shashashasha/1026018 to your computer and use it in GitHub Desktop.
Great Circles
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
org.polymaps.paths = function() { | |
var paths = org.polymaps.geoJson(), | |
mode = "arc", // or "line" | |
storedPaths = []; | |
// a and b are location objects, c is the optional class to apply to them | |
paths.connect = function(a, b, c) { | |
var locations = []; | |
locations.push([a.lon, a.lat]); | |
if (mode == 'arc') { | |
var num = 100; | |
for (var i = 0; i < num; i++) { | |
var loc = paths.interpolate(a, b, i / num); | |
locations.push([loc.lon, loc.lat]); | |
} | |
} else if (mode == 'line') { | |
// ignore | |
} | |
locations.push([b.lon, b.lat]); | |
// create a GeoJson LineString object | |
var feature = { | |
type: "Feature", | |
geometry: { | |
type: "LineString", | |
coordinates: locations | |
}, | |
id: a.lat + a.lon + "," + b.lat + b.lon, | |
properties: { | |
start: a, | |
end: b | |
} | |
}; | |
storedPaths.push(feature); | |
}; | |
paths.refreshPaths = function() { | |
paths.features(storedPaths); | |
}; | |
// interpolation code from modestmaps.js by Tom Carden and Mike Migurski, etc | |
// http://code.google.com/p/modestmaps/source/browse/trunk/js/modestmaps.js | |
paths.interpolate = function(l1, l2, f) { | |
var deg2rad = Math.PI / 180.0, | |
lat1 = l1.lat * deg2rad, | |
lon1 = l1.lon * deg2rad, | |
lat2 = l2.lat * deg2rad, | |
lon2 = l2.lon * deg2rad; | |
var d = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin((lat1-lat2)/2),2) + Math.cos(lat1)*Math.cos(lat2)*Math.pow(Math.sin((lon1-lon2)/2),2))); | |
var bearing = Math.atan2(Math.sin(lon1-lon2)*Math.cos(lat2), Math.cos(lat1)*Math.sin(lat2)-Math.sin(lat1)*Math.cos(lat2)*Math.cos(lon1-lon2)) / -(Math.PI/180); | |
bearing = bearing < 0 ? 360 + bearing : bearing; | |
var A = Math.sin((1-f)*d)/Math.sin(d); | |
var B = Math.sin(f*d)/Math.sin(d); | |
var x = A*Math.cos(lat1)*Math.cos(lon1) + B*Math.cos(lat2)*Math.cos(lon2); | |
var y = A*Math.cos(lat1)*Math.sin(lon1) + B*Math.cos(lat2)*Math.sin(lon2); | |
var z = A*Math.sin(lat1) + B*Math.sin(lat2); | |
var latN = Math.atan2(z,Math.sqrt(Math.pow(x,2)+Math.pow(y,2))); | |
var lonN = Math.atan2(y,x); | |
return { lat:latN/deg2rad, lon:lonN/deg2rad }; | |
}; | |
return paths; | |
}; |
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
<html> | |
<head> | |
<title>Great Circles</title> | |
<script type="text/javascript" src="https://raw.github.com/simplegeo/polymaps/master/polymaps.js"></script> | |
<script type="text/javascript" src="greatcircle.js"></script> | |
<style type="text/css"> | |
body { | |
margin: 0; | |
} | |
svg { | |
width: 100%; | |
height: 100%; | |
} | |
.compass .back { | |
fill: #eee; | |
fill-opacity: .8; | |
} | |
.compass .fore { | |
stroke: #999; | |
stroke-width: 1.5px; | |
} | |
.compass rect.back.fore { | |
fill: #999; | |
fill-opacity: .3; | |
stroke: #eee; | |
stroke-width: 1px; | |
} | |
.compass .direction { | |
fill: none; | |
} | |
.compass .chevron { | |
fill: none; | |
stroke: #999; | |
stroke-width: 5px; | |
} | |
.compass .zoom .chevron { | |
stroke-width: 4px; | |
} | |
.layer path { | |
fill-opacity: 0.0; | |
stroke: #000; | |
stroke-width: 1px; | |
} | |
</style> | |
</head> | |
<body> | |
<div id="map"> | |
</div> | |
<script type="text/javascript"> | |
// 20760 blanker | |
var cloudmadeURL = "http://tile.cloudmade.com/1a1b06b230af4efdbb989ea99e9841af/22677/256/{Z}/{X}/{Y}.png"; | |
var po = org.polymaps, | |
div = document.getElementById("map"); | |
var map = po.map() | |
.container(div.appendChild(po.svg("svg"))) | |
.center({lat: 10, lon: 0}) | |
.zoom(2); | |
map.add(po.image() | |
.url(po.url("http://{S}tile.cloudmade.com" | |
+ "/5814d279db61404b9e52115b06b9e7b3" // http://cloudmade.com/register | |
+ "/22677/256/{Z}/{X}/{Y}.png") | |
.hosts(["a.", "b.", "c.", ""]))); | |
var paths = po.paths(); | |
map.add(paths); | |
// add the compass for navigation | |
map.add(po.compass() | |
.pan("none")); | |
var start = randomLocation(); | |
for (var i = 0; i < 100; i++) { | |
paths.connect(start, randomLocation()); | |
} | |
paths.refreshPaths(); | |
function randomLocation() { | |
return {lat: Math.random() * 90 - 45, lon: Math.random() * 180 - 90}; | |
} | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment