Created
November 13, 2012 17:27
-
-
Save feesta/4067147 to your computer and use it in GitHub Desktop.
A compass showing points and their distances from the current location. Pass points in using the URL.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta name="viewport" content="width=device-width initial-scale=1.0 user-scalable=no minimum-scale=1.0 maximum-scale=1.0" /> | |
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script> | |
<script type="text/javascript" src="http://cdnjs.cloudflare.com/ajax/libs/raphael/2.1.0/raphael-min.js"></script> | |
<!--<script type="text/javascript" src="kinetic-v4.0.4.min.js"></script>--> | |
<script type="text/javascript"> | |
// use native app wrappers to send phone bearing to the page | |
// rotate compass when the bearing changes | |
// | |
var data_internal = [ | |
{lat:37.809, lon:-122.477, name:"Golden Gate Bridge"}, | |
{lat:37.778, lon:-122.390, name:"AT&T Park"}, | |
{lat:37.756, lon:-122.421, name:"Home"}, | |
{lat:37.798, lon:-122.425, name:"Angelica's"}, | |
{lat:37.795, lon:-122.403, name:"Transamerica Building"}, | |
{lat:37.774, lon:-122.434, name:"Adrian & Augustin's"} | |
]; | |
var data = [], hasData = false; | |
//var urlstring = "lat=37.809/lon=-122.477/name=Golden Gate Bridge&&lat=37.778/lon=-122.390/name=AT&T Park&&lat=37.756/lon=-122.421/name=Home&&lat=37.798/lon=-122.425/name=Angelica's&&lat=37.795/lon=-122.403/name=Transamerica Building&&lat=37.774/lon=-122.434/name=Adrian & Augustin's"; | |
var urlstring = "#name=Golden%20Gate%20Bridge/lat=37.809/lon=-122.477&&name=AT&T%20Park/lat=37.778/lon=-122.39&&name=Home/lat=37.756/lon=-122.421&&name=Angelica's/lat=37.798/lon=-122.425&&name=Transamerica%20Building/lat=37.795/lon=-122.403&&name=Adrian%20&%20Augustin's/lat=37.774/lon=-122.434&&name=Twin%20Peaks/lat=37.753/lon=-122.448&&name=Zoo/lat=37.734/lon=-122.504&&"; | |
var radius, page_width; | |
//var stage, layer; | |
var paper; | |
$(function(){ | |
fromurl(); | |
page_width = $(window).width() < 720 ? $(window).width() : 720; | |
radius1 = page_width * .3; | |
radius2 = page_width * .33; | |
radius3 = page_width * .36; | |
//$("body").append("<span>"+page_width + "</span>"); | |
//page_width = 400; | |
/* | |
stage = new Kinetic.Stage({ | |
container: 'box', | |
width: page_width, | |
height: page_width | |
}); | |
layer = new Kinetic.Layer(); | |
var circle = new Kinetic.Circle({ | |
x:page_width / 2, | |
y:page_width / 2, | |
width:radius*2, | |
height:radius*2, | |
fill:'white', | |
opacity:0.3, | |
stroke:'#ddd', | |
strokeWidth:10 | |
}); | |
var northpoint = new Kinetic.Circle({ | |
x:page_width / 2, | |
y:page_width / 2 - radius, | |
width:5, | |
height:5, | |
stroke:'#333', | |
strokeWidth:2 | |
}); | |
layer.add(circle); | |
layer.add(northpoint); | |
stage.add(layer); | |
*/ | |
paper = Raphael("container", page_width, page_width); | |
var circle1 = paper.circle(page_width / 2, page_width / 2, radius1); | |
circle1.attr({ | |
opacity:0.5, | |
stroke:'#333', | |
"stroke-width":2 | |
}); | |
var circle2 = paper.circle(page_width / 2, page_width / 2, radius2); | |
circle2.attr({ | |
opacity:0.4, | |
stroke:'#333', | |
"stroke-width":2 | |
}); | |
var circle3 = paper.circle(page_width / 2, page_width / 2, radius3); | |
circle3.attr({ | |
opacity:0.2, | |
stroke:'#333', | |
"stroke-width":2 | |
}); | |
var pathstring = "M" + (Math.round(page_width / 2)) + " " + (page_width / 2 - radius1) + "L" + (Math.round(page_width / 2)) + " " + (page_width / 2 - radius3); | |
var northpoint = paper.path(pathstring); | |
northpoint.attr({ | |
stroke:'#000', | |
opacity:0.2, | |
"stroke-width":6 | |
}); | |
navigator.geolocation.getCurrentPosition(gotLocation); | |
//if (!hasData) { | |
var new_point = $("#new-point-template"); | |
new_point.clone().attr("id",null).appendTo("#default"); | |
$("#add-point-field").on("click", function() { | |
new_point.clone().attr("id","").appendTo("#default"); | |
}); | |
$("#generate-url").on("click", function() { | |
console.info('create url'); | |
var url = "#"; | |
$(".new-point-field:not(#new-point-template)").each(function() { | |
var name = $(this).find(".name").val(); | |
var lat = parseFloat($(this).find(".lat").val()); | |
var lon = parseFloat($(this).find(".lon").val()); | |
if (!name || !lat || !lon) return; | |
console.info(this, name, lat, lon); | |
url += "name=" + name + "/lat=" + lat + "/lon=" + lon + "&&"; | |
}); | |
if (url) $("#point-url").attr("href", encodeURI(url)).text(encodeURI(url)); | |
}); | |
$(window).on("click", ".remove-point-field", function() { | |
$(this).parent().remove(); | |
}); | |
//} | |
}); | |
function fromurl() { | |
console.info("fromurl"); | |
var hash = decodeURI(location.hash.substr(1)), | |
points_raw = hash.split("&&"); | |
var new_point = $("#new-point-template"); | |
for (var i = 0; i < points_raw.length; i++) { | |
var point = {}; | |
var components = points_raw[i].split("/"); | |
if (components.length == 1) continue; | |
for (var j = 0; j < components.length; j++) { | |
var component = components[j].split("="); | |
if (component.length == 1) continue; | |
point[component[0]] = component[1]; | |
} | |
if (point.name && point.lat && point.lon) { | |
data.push(point); | |
var point_field = new_point.clone().attr("id",null); | |
point_field.find(".name").val(point.name); | |
point_field.find(".lat").val(point.lat); | |
point_field.find(".lon").val(point.lon); | |
point_field.appendTo("#default"); | |
} | |
} | |
/* json = hash.substr(hash.indexOf('json=')) | |
.split('&')[0] | |
.split('=')[1]; | |
if (json) { | |
data = decodeURIComponent(json); | |
console.info('data from url:', data); | |
} else { | |
console.info('nothing from url'); | |
} | |
*/ | |
if (!data.length) { | |
hasData = false; | |
$("#default").show(); | |
$("#container").hide(); | |
} else hasData = true; | |
} | |
function gotLocation(location) { | |
//console.info('location', location.coords, location); | |
//$("body").prepend("<span>Location:" + location.coords.latitude+ ", " + location.coords.longitude + " " + location.coords.heading + "</span>"); | |
for (var i = 0; i < data.length; i++) { | |
var point = data[i]; | |
//console.info(point); | |
var dist = distance(location.coords.latitude, location.coords.longitude, parseFloat(point.lat), parseFloat(point.lon)); | |
console.info(dist, data[i].name); | |
var x, y; | |
if (dist.distance < 0.08) { | |
x = y = page_width / 2; | |
} else if (dist.distance < .5) { | |
x = radius1 * Math.sin(dist.bearing) + page_width / 2; | |
y = radius1 * -Math.cos(dist.bearing) + page_width / 2; | |
} else if (dist.distance < 2) { | |
x = radius2 * Math.sin(dist.bearing) + page_width / 2; | |
y = radius2 * -Math.cos(dist.bearing) + page_width / 2; | |
} else { | |
x = radius3 * Math.sin(dist.bearing) + page_width / 2; | |
y = radius3 * -Math.cos(dist.bearing) + page_width / 2; | |
} | |
addCircle(x,y); | |
$("<div class='place'><span class='place-name'>" + data[i].name + "</span> <span class='place-distance'>" + dist.distance.toFixed(1) + " mi</span></div>").offset({left:x+12, top:y-8}).appendTo("#container"); | |
} | |
} | |
function addCircle(x,y) { | |
/* | |
var circle = new Kinetic.Circle({ | |
x:x, | |
y:y, | |
width:10, | |
height:10, | |
opacity:.6, | |
fill:'red' | |
}); | |
layer.add(circle); | |
stage.add(layer); | |
*/ | |
var circle = paper.circle(x,y,7); | |
circle.attr({ | |
opacity:.8, | |
fill:'red', | |
stroke:'transparent' | |
}); | |
} | |
function distance (lat1, lon1, lat2, lon2) { | |
//var R = 6371; // km | |
var R = 3959; // miles | |
var dLat = (lat2-lat1).toRad(); | |
var dLon = (lon2-lon1).toRad(); | |
var lat1 = lat1.toRad(); | |
var lat2 = lat2.toRad(); | |
var a = Math.sin(dLat/2) * Math.sin(dLat/2) + | |
Math.sin(dLon/2) * Math.sin(dLon/2) * Math.cos(lat1) * Math.cos(lat2); | |
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a)); | |
var d = R * c; | |
var y = Math.sin(dLon) * Math.cos(lat2); | |
var x = Math.cos(lat1) * Math.sin(lat2) - | |
Math.sin(lat1) * Math.cos(lat2) * Math.cos(dLon); | |
var bearing = Math.atan2(y, x); | |
return {distance:d, bearing:bearing}; | |
} | |
/** Converts numeric degrees to radians */ | |
if (typeof(Number.prototype.toRad) === "undefined") { | |
Number.prototype.toRad = function() { | |
return this * Math.PI / 180; | |
} | |
} | |
/** Converts radians to numeric (signed) degrees */ | |
if (typeof Number.prototype.toDeg == 'undefined') { | |
Number.prototype.toDeg = function() { | |
return this * 180 / Math.PI; | |
} | |
} | |
function fromAndroid(rad) { | |
//$("body").prepend("<div>angle: " + rad + "</div>"); | |
$("#container").css("-webkit-transform", "rotate(" + -rad + "rad)"); | |
} | |
</script> | |
<style> | |
body {font-family:sans-serif; margin:0; padding:0;} | |
/*canvas {border:1px solid #ddd;}*/ | |
#container {position:absolute; top:0; left:0; /*-webkit-transform: rotate(0deg);*/} | |
#default {font-size:12px; display:none;} | |
.place {font-size:16px; color:#333; position:absolute;} | |
.place-name {font-weight:bold;} | |
.place-distance {font-weight:normal;} | |
#new-point-template {display:none;} | |
</style> | |
</head> | |
<body> | |
<div id="container"> | |
</div> | |
<div id="default"> | |
<a href="#name=Golden%20Gate%20Bridge/lat=37.809/lon=-122.477&&name=AT&T%20Park/lat=37.778/lon=-122.39&&name=Home/lat=37.756/lon=-122.421&&name=Angelica's/lat=37.798/lon=-122.425&&name=Transamerica%20Building/lat=37.795/lon=-122.403&&name=Adrian%20&%20Augustin's/lat=37.774/lon=-122.434&&name=Twin%20Peaks/lat=37.753/lon=-122.448&&name=Zoo/lat=37.734/lon=-122.504&&u">Load with sample data</a><br> | |
<button id="add-point-field">+</button> | |
<button id="generate-url">Generate URL</button> | |
<a id="point-url"></a> | |
<div id='new-point-template' class="new-point-field"> | |
<input type='text' class='name' placeholder='name'> | |
<input type='text' class='lat' placeholder='latitude'> | |
<input type='text' class='lon' placeholder='longitude'> | |
<button class='remove-point-field'>remove</button> | |
</div> | |
</div> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment