Skip to content

Instantly share code, notes, and snippets.

@feesta
Created November 13, 2012 17:27
Show Gist options
  • Save feesta/4067147 to your computer and use it in GitHub Desktop.
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.
<!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