--- /dev/null
+README.txt for foxy
+David Rowe
+May 25 2013
+
+
+Introduction
+------------
+
+Simple Google Maps application to plot Fox Hunt bearings. When run on
+a phone it automatically detects position and compass bearing. Placing
+Bearings can be placed with a mouse click on non-mobile devices. The
+bearings are stored in a text file database so can be shared by anyone
+who can reach the server.
+
+* Screen shot: foxy_screenshot.png
+
+* Based on Google maps V3 API.
+
+* Light weight: On the server we have just a few CGIs and a text file
+ database. A browser cookie is used for storing configuration
+ information. The CGIs are a few lines of shell script, so can run
+ on any machine. Installation involves copying a few files and
+ setting a few permissions.
+
+* Foxy will stand alone without the server & CGIs, but bearing storage
+ won't be persistent and bearings can't be shared. Good for demos or
+ when you can't reach the Internet.
+
+BUGS
+----
+
+On mobile devices:
++ Click to add bearings places the bearing at a location offset from the tap location
++ Double click doesn't remove bearings on mobile devices.
+
+Using Foxy
+----------
+
+1/ Point your browser at http://yourserver/foxy.html
+
+2/ If running on your phone your bearing will be updated
+automatically. Click on add bearing to add a bearing from your
+current position to the map.
+
+3/ The "where Am I" button re-centers the map on your current
+position. This is useful when scroll and zooming moves your position.
+
+4/ The "Click to Add Bearing" check box allow manual placement of
+bearings with a mouse click. Useful for demo and development on
+non-mobile devices such as desktops and laptops. This should be
+unchecked on mobile devices as pinching/scrolling often generates
+spurious "click" events leading to unwanted bearings.
+
+5/ Double click on a bearing to delete it.
+
+
+Implementation Notes
+--------------------
+
+Foxy is implemented in Javascript (foxy.html). A simple text database
+file /var/www/foxy/bearings.txt is used to store bearing
+information. Very simple 1 page CGIs written in shell script are used
+to access the bearing database.
+
+A browser cookie is used to store config information like the current
+map centre.
+
+All the CGI scripts assume a hard coded to a path of
+/var/www/foxy/bearings.txt for the bearings.txt database.
+
+
+Files
+-----
+
+ foxy.html - Javascript & HTML code for Foxy
+ foxy.css - style sheet
+
+"cgi-bin" directory:
+
+ addbearing.cgi - adds a bearing to bearings.txt
+ delbearing.cgi - deletes a bearing from bearings.txt
+ getbearings.cgi - reads bearings.txt database
+ cleardb.cgi - clears database, removing all bearings
+
+
+Software
+--------
+
+You need:
+
+1/ A web server. Apache is assumed in the /usr/lib/cgi-bin path below.
+ The paths may be different for other web servers. Note the path
+ to /var/www/foxy is hard coded in the CGI scripts so it's
+ best not to change that.
+
+
+Installation
+------------
+
+1/ Server PC
+
+ $ svn co https://freetel.svn.sourceforge.net/svnroot/freetel/foxy
+ $ cd foxy
+ $ sudo mkdir /var/www/foxy
+ $ sudo chmod 777 /var/www/foxy
+ $ cp foxy.css foxy.html /var/www/foxy
+ $ sudo cp cgi-bin/* /usr/lib/cgi-bin
+
+Tests
+-----
+
+1/ Test reading and writing bearings.txt database with your browser:
+
+ http://localhost/cgi-bin/addbearing.cgi?lat=123&lng=456&bearing=90
+
+ $ cat /var/www/foxy/bearings.txt
+ 123,456,90
+
+ http://localhost/cgi-bin/delbearing.cgi?lat=123&lng=456
+
+ $ cat /var/www/foxy/bearings.txt
+ (empty file)
+
+Debugging
+---------
+
+1/ Monitor Apache log:
+
+ $ tail -f /var/log/apache2/access.log
+
+2/ Use Firebug on Firefox to single step, set breakpoints etc.
+
+3/ Check bearings.txt database, each line is (lat, lng, IP):
+
+ # cat /var/www/foxy/bearings.txt
+
+ -34.88548650005714,138.55225324630737,90
+ -34.88006501016277,138.55394840240479,180
+ -34.87893842193011,138.55278968811035,265
+ -34.882511765792316,138.55210304260254,10
+
+4/ The "foxy001" cookie stores our state. On Firefox 3.5 you
+ can remove the foxy cookie using Edit-Preferences-Privacy, then
+ click on "remove individual cookies".
+
+5/ To manually reset to defaults:
+
+ * move to another page (cookie is saved when we exit page)
+ * rm -f /var/www/foxy/bearings.txt
+ * Delete cookie using step (4) above
--- /dev/null
+#!/bin/sh
+# addbearing.cgi
+# David Rowe 25 May 2013
+#
+# CGI to add a new bearing
+
+cat <<EOF
+Content-type: text/html
+
+<html>
+<head>
+<meta http-equiv="cache-control" content="no-cache">
+<meta http-equiv="pragma" content="no-cache">
+<meta http-equiv="expires" content="-1"></head></head>
+<body>
+EOF
+
+lat=`echo "$QUERY_STRING" | sed -n "s/.*lat=\(.*\)&lng.*/\1/p"`
+lng=`echo "$QUERY_STRING" | sed -n "s/.*lng=\(.*\)&bearing.*/\1/p"`
+bearing=`echo "$QUERY_STRING" | sed -n "s/.*bearing=\(.*\)/\1/p"`
+
+echo $lat,$lng,$bearing >> /var/www/foxy/bearings.txt
+
+echo $QUERY_STRING "<br>"
+echo "<br>"
+echo $lat $lng $bearing
+
+cat <<EOF
+</body>
+</html>
+EOF
--- /dev/null
+#!/bin/sh
+# cleardb.cgi
+# David Rowe 25 May 2013
+#
+# CGI to delete entire bearing database
+
+cat <<EOF
+Content-type: text/html
+
+<html>
+<head>
+<meta http-equiv="cache-control" content="no-cache">
+<meta http-equiv="pragma" content="no-cache">
+<meta http-equiv="expires" content="-1"></head></head>
+<body>
+EOF
+
+# path to node database text file
+
+P=/var/www/foxy
+rm $P/bearings.txt
+
+cat <<EOF
+</body>
+</html>
+EOF
--- /dev/null
+#!/bin/sh
+# delbearing.cgi
+# David Rowe 25 May 2012
+#
+# CGI to delete a bearing
+
+cat <<EOF
+Content-type: text/html
+
+<html>
+<head>
+<meta http-equiv="cache-control" content="no-cache">
+<meta http-equiv="pragma" content="no-cache">
+<meta http-equiv="expires" content="-1"></head></head>
+<body>
+EOF
+
+lat=`echo "$QUERY_STRING" | sed -n "s/lat=\(.*\)&.*/\1/pg"`
+lng=`echo "$QUERY_STRING" | sed -n "s/.*lng=\(.*\)/\1/pg"`
+
+# path to node database text file
+
+P=/var/www/foxy
+
+cat $P/bearings.txt | sed "/$lat,$lng.*/ d" > $P/bearings.tmp
+cp $P/bearings.tmp $P/bearings.txt
+rm $P/bearings.tmp
+
+#echo $QUERY_STRING "<br>"
+#echo "<br>"
+#echo $lat $lng
+
+cat <<EOF
+</body>
+</html>
+EOF
--- /dev/null
+#!/bin/sh
+# getbearings.cgi
+# David Rowe 25 May 2013
+#
+# CGI to return list of bearings from the bearings.txt database text file
+# We use a CGI rather than fetching the text file directly
+# so we can stop Firefox from caching
+
+cat <<EOF
+Content-type: text/html
+
+<html>
+<head>
+<meta http-equiv="cache-control" content="no-cache">
+<meta http-equiv="pragma" content="no-cache">
+<meta http-equiv="expires" content="-1">
+</head>
+<body>
+EOF
+
+BEARINGS=/var/www/foxy/bearings.txt
+
+if [ -f $BEARINGS ] ; then
+ cat $BEARINGS
+fi
+
+cat <<EOF
+</body>
+</html>
+EOF
--- /dev/null
+html,body{
+ margin:0;
+ padding:0;
+ width:100%;
+ height:100%;
+ font-family:Arial, Helvetica, sans-serif;
+}
+
+div#header{
+ vertical-align:middle;
+ border-bottom:1px solid #000;
+}
+div#main-map{
+ width:100%;
+ height:90%;
+ float:top;
+}
+div#bottom{
+ height:10%;
+ float:bottom;
+}
+
+div#dataPanel{
+ width:90%;
+ height:50%;
+ overflow:auto;
+ border:2px solid #DDDDDD;
+}
+input{
+ width:90%;
+}
+
+input.navi{
+ font-size:12px;
+ height:30px;
+ margin-bottom:10px;
+}
+div ul{
+ margin-top:30px;
+ margin-bottom:30px;
+}
+div ul li{
+ display: inline;
+ list-style-type: none;
+ padding-right: 40px;
+ font-size:18px;
+ font-weight:bold;
+}
+
+div ul li.title{
+ font-size:22px;
+ color:#888;
+}
+
+div#header p{
+ color:#888;
+ font-size:14px;
+ padding-left:20px;
+}
+span.instruction{
+ font-weight:bold;
+
+}
+
+.message-box { text-align: center; padding: 5px; color:#545454; width:80%; margin:5px auto; font-size:12px;}
+.clean { background-color: #efefef; border-top: 2px solid #dedede; border-bottom: 2px solid #dedede; }
+.info { background-color: #f7fafd; border-top: 2px solid #b5d3ff; border-bottom: 2px solid #b5d3ff; }
+.ok { background-color: #d7f7c4; border-top: 2px solid #82cb2f; border-bottom: 2px solid #82cb2f; }
+.alert { background-color: #fef5be; border-top: 2px solid #fdd425; border-bottom: 2px solid #fdd425; }
+.error { background-color: #ffcdd1; border-top: 2px solid #e10c0c; border-bottom: 2px solid #e10c0c; }
\ No newline at end of file
--- /dev/null
+<!DOCTYPE html>
+<html>
+<head>
+<meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
+<meta http-equiv="content-type" content="text/html; charset=UTF-8"/>
+<style type="text/css">
+ html { height: 100% }
+ body { height: 100%; margin: 0px; padding: 0px }
+ #map_canvas { height: 100% }
+</style>
+<title>Foxy</title>
+
+<link rel="stylesheet" type="text/css" href="foxy.css">
+<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=true"></script>
+
+<script type="text/javascript">
+
+ /*
+ foxy.html
+ David Rowe
+ May 25 2013
+
+ Simple Google Maps application to plot Fox Hunt bearings.
+
+ See README.txt for more information.
+
+ search/grep on string "idea" for future ideas documented in
+ comments below.
+
+ */
+
+ var map;
+
+ // cookie params
+
+ var cookiename = "foxy0001";
+ var cookieexpy = 7;
+
+ // these are stored in cookie, with default values
+
+ var lat = 0;
+ var lng = 0;
+ var myzoom = 2;
+ var update_enable = 0;
+ var debug_enable = 1;
+ var known_location = true;
+ var bearing = 0.0;
+
+ var bearings = []; // database of bearings we keep in memory
+ // mirrors bearings.txt
+
+ var geolocationSupport;
+ var geolat = 0;
+ var geolng = 0;
+ var hasCompass;
+ var currentHeading;
+ var posMarker;
+
+ //
+ // Initialisation ----------------------------------------------------------------
+ //
+
+ // Called when we load page
+
+ function initialize() {
+
+ // if geolocation supported get our initial location
+
+ if(navigator.geolocation) {
+ geolocationSupport = true;
+
+ navigator.geolocation.getCurrentPosition(function(position) {
+ log("getCurrentPosition");
+ lat = geolat = position.coords.latitude;
+ lng = geolng = position.coords.longitude;
+
+ continueInit();
+ }, function() {
+ continueInit();
+ }, {timeout:5});
+ }
+ }
+
+ function continueInit() {
+ // if we have a compass use it to get bearing
+
+ testForCompass();
+
+ // we use our cookie as persistant storage for map location,
+ // control panel values etc
+
+ getCookie();
+
+ // init map
+
+ var myLatlng = new google.maps.LatLng(lat, lng);
+ var myOptions = {
+ disableDoubleClickZoom: true,
+ zoom: myzoom,
+ center: myLatlng,
+ scaleControl: true,
+ mapTypeId: google.maps.MapTypeId.ROADMAP
+ }
+ map = new google.maps.Map(document.getElementById("main-map"), myOptions);
+
+ // For testing on a desk top it's useful to left click to add
+ // bearings. This sucks on mobile as a pinch or drag can generate a
+ // click event and you get spurious bearings. So it can be disabled
+ // with the 'Click to add bearing' check box
+
+ google.maps.event.addListener(map, 'click', function (event) {
+ if (document.control_panel.click_bearing.checked) {
+ bearing = parseFloat(document.control_panel.bearing.value);
+ placeMarker(event.latLng, bearing, false);
+ }
+ });
+
+ document.control_panel.debug_enable.checked = debug_enable;
+
+ if (geolocationSupport) {
+ posMarker = new google.maps.Marker(
+ {position: myLatlng,
+ map: map});
+ navigator.geolocation.watchPosition(showPosition);
+ }
+
+ // read from bearings.txt database text file on server and init map
+
+ downloadUrl("/cgi-bin/getbearings.cgi", loadBearings);
+ }
+
+
+ // Slurp up bearings.txt when web pages loads
+
+ loadBearings = function(doc, status) {
+ log("loadBearings start");
+
+ // split the document into lines
+
+ var lines = doc.split("\n");
+ for (var i=0; i<lines.length; i++) {
+ if (lines[i].length > 1) {
+
+ // split each line into parts separated by "," and use the contents
+
+ parts = lines[i].split(",");
+ if (parts.length > 1) {
+ var lat = parseFloat(parts[0]);
+ var lng = parseFloat(parts[1]);
+ var bearing = parseFloat(parts[2]);
+
+ addNewBearing(lat, lng, bearing, false);
+ }
+ }
+ }
+
+ log("loadBearings end");
+
+ }
+
+
+ //
+ // Compass Support ----------------------------------------------------------------
+ //
+
+ function startCompass()
+ {
+ window.addEventListener('deviceorientation', onDeviceOrientationChange); // Gyroscope
+ }
+
+ function testForCompass()
+ {
+ var ua = navigator.userAgent.toLowerCase();
+ // Let's do _something_ for unsupported browsers.
+ if (ua.indexOf('firefox') != -1 || ua.indexOf('opera') != -1 || ua.indexOf('msie') != -1)
+ {
+ hasCompass = false;
+ startCompass();
+ }
+ else if (ua.indexOf('iphone os 4') != -1)
+ {
+ hasCompass = false;
+ startCompass();
+ }
+ else if (window.DeviceOrientationEvent)
+ {
+ window.addEventListener('deviceorientation', compassTest);
+ }
+ else
+ {
+ hasCompass = false;
+ startCompass();
+ }
+ }
+
+ function compassTest(event)
+ {
+ window.removeEventListener('deviceorientation', compassTest);
+ if (event.webkitCompassHeading != undefined || event.alpha != null) // Device does have a compass
+ {
+ hasCompass = true;
+ }
+ else
+ {
+ hasCompass = false;
+ }
+ startCompass();
+ }
+
+ // this gets called (a lot) when device orientation changes
+
+ function onDeviceOrientationChange(event) {
+ if (event.webkitCompassHeading != undefined)
+ currentHeading = (360 - event.webkitCompassHeading);
+ else if (event.alpha != null)
+ currentHeading = (270 - event.alpha) * -1;
+ document.control_panel.bearing.value = Math.round(currentHeading);
+ }
+
+ // remove leading and trailing whitespace from a string
+
+ function trim(stringToTrim) {
+ return stringToTrim.replace(/^\s+|\s+$/g,"");
+ }
+
+
+ //
+ // Helper Funtions ----------------------------------------------------------------
+ //
+
+ // calculate distance between two points
+
+ rad = function(x) {return x*Math.PI/180;}
+
+ distHaversine = function(p1, p2) {
+ var R = 6371; // earth's mean radius in km
+ var dLat = rad(p2.lat() - p1.lat());
+ var dLong = rad(p2.lng() - p1.lng());
+
+ var a = Math.sin(dLat/2) * Math.sin(dLat/2) +
+ Math.cos(rad(p1.lat())) * Math.cos(rad(p2.lat())) * Math.sin(dLong/2) * Math.sin(dLong/2);
+ var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
+ var d = R * c;
+
+ return d.toFixed(3);
+ }
+
+ // Converts numeric degrees to radians
+
+ function toRad(deg) {
+ return deg * Math.PI / 180;
+ }
+
+ // Converts radians to numeric (signed) degrees
+
+ function toDeg(rad) {
+ return rad * 180 / Math.PI;
+ }
+
+ // given a bearing and distance calculate end location
+
+ function bearingToLocation(location1, bearing, d) {
+ var lat1 = toRad(location1.lat());
+ var lon1 = toRad(location1.lng());
+ var bearing_rad = toRad(bearing);
+ var R = 6378137;
+
+ var lat2 = Math.asin( Math.sin(lat1)*Math.cos(d/R) +
+ Math.cos(lat1)*Math.sin(d/R)*Math.cos(bearing_rad) );
+ var lon2 = lon1 + Math.atan2(Math.sin(bearing_rad)*Math.sin(d/R)*Math.cos(lat1),
+ Math.cos(d/R)-Math.sin(lat1)*Math.sin(lat2));
+
+ var location2 = new google.maps.LatLng(toDeg(lat2), toDeg(lon2));
+ return location2;
+ }
+
+ function log(message) {
+ if (debug_enable == 1) {
+ message_list = document.getElementById("debugging_messages");
+ log_message = document.createTextNode(message);
+ log_list_item = document.createElement('li');
+ log_list_item.appendChild(log_message);
+ message_list.appendChild(log_list_item);
+ }
+ }
+
+ // this function calls itself every update_time seconds
+ // used for peridoic updates (polling) of network stats
+
+ function showPosition(position) {
+ lat = geolat = position.coords.latitude;
+ lng = geolng = position.coords.longitude;
+ log("showPosition lat=" + lat + " lng=" + lng);
+
+ posMarker.setPosition( new google.maps.LatLng( lat, lng ) );
+ }
+
+ //
+ // GUI Call Backs ----------------------------------------------------------------
+ //
+
+ function addBearing2() {
+ if (geolocationSupport) {
+ if (hasCompass) {
+ bearing = currentHeading;
+ }
+ else {
+ bearing = document.control_panel.bearing.value;
+ }
+ var latlng = new google.maps.LatLng(geolat, geolng);
+ placeMarker(latlng, bearing, false);
+ map.setCenter(latlng);
+ }
+ }
+
+ // rec-center map on curent location if scroll/pinch events screw us up
+
+ function whereAmI() {
+ var latlng = new google.maps.LatLng(geolat, geolng);
+ map.setCenter(latlng);
+ }
+
+ // sets up map for a new bearings
+ // adds bearing to bearings[] array but doesn't write to text file
+
+ function clearDatabase() {
+
+ // call CGI to rm bearings.txt
+
+ downloadUrl("/cgi-bin/cleardb.cgi",function(doc){});
+
+ // delete all existing bearings
+
+ if (bearings) {
+ for (j in bearings) {
+ bearings[j].marker.setMap(null);
+ bearings[j].path.setMap(null);
+ }
+ }
+ bearings = [];
+ }
+
+ function debugClicked() {
+ if (document.control_panel.debug_enable.checked)
+ debug_enable = 1;
+ else
+ debug_enable = 0;
+ }
+
+
+ //
+ // Adding a new Bearing ---------------------------------------------------------
+ //
+
+ function addNewBearing(lat, lng, bearing, isNewBearing) {
+
+ // create the marker at point where bearing starts
+
+ var location = new google.maps.LatLng(lat, lng);
+ var newMarker = new google.maps.Marker(
+ {position: location,
+ map: map});
+
+ // idea: might be useful for "new" bearing indicator
+ // if (isNewBearing) {
+ // newMarker.setAnimation(google.maps.Animation.BOUNCE);
+ //}
+
+ var newInfoWindow = new google.maps.InfoWindow(
+ { content: "put some info here"
+ });
+
+ // creat bearing line coords
+
+ var location2 = bearingToLocation(location, bearing, 100000);
+ var coords = [
+ location,
+ location2
+ ];
+
+ // draw line
+
+ var newPath = new google.maps.Polyline({
+ path: coords,
+ strokeColor: "#080000",
+ strokeOpacity: 0.5,
+ strokeWeight: 5
+ });
+ newPath.setMap(map);
+
+ // add to bearings array
+ // idea: add time stamp to info window? Signal strength? Order
+
+ var newBearing = {marker : newMarker,
+ bearing: newBearing,
+ infowindow: newInfoWindow,
+ path: newPath};
+ bearings.push(newBearing);
+
+ google.maps.event.addListener(newMarker, "dblclick", function() {
+
+ // remove bearing from bearings array
+
+ var new_bearings = [];
+ for (var j=0; j<bearings.length; j++) {
+ if (bearings[j].marker.position != newMarker.position) {
+ new_bearings.push(bearings[j]);
+ }
+ else
+ bearings[j].path.setMap(null);
+ }
+ bearings = new_bearings;
+
+ // delete bearing from text file
+
+ var url;
+ url = "/cgi-bin/delbearing.cgi?" + "lat=" + this.position.lat() + "&" + "lng=" + this.position.lng();
+ downloadUrl(url, function(doc) { });
+ this.setMap(null);
+
+ });
+
+ }
+
+
+ //
+ // Cookie Support ----------------------------------------------------------------
+ //
+
+ // save state (config info) to our cookie
+
+ function setCookie() {
+ var cookietext = cookiename;
+ cookietext += "=" + map.getCenter().lat();
+ cookietext += "|" + map.getCenter().lng() + "|" + map.getZoom();
+ cookietext += "|" + debug_enable;
+ if (cookieexpy) {
+ var exdate=new Date();
+ exdate.setDate(exdate.getDate()+cookieexpy);
+ cookietext += ";expires="+exdate.toGMTString();
+ }
+
+ // write the cookie
+
+ document.cookie = cookietext;
+ }
+
+
+ // Grab a bunch of config info from our cookie
+
+ function getCookie() {
+
+ if (document.cookie.length > 0) {
+ log("cookie found");
+ cookieStart = document.cookie.indexOf(cookiename + "=");
+
+ // lets see if our cookie exists
+
+ if (cookieStart!=-1) {
+ cookieStart += cookiename.length+1;
+ cookieEnd=document.cookie.indexOf(";",cookieStart);
+ if (cookieEnd==-1) {
+ cookieEnd=document.cookie.length;
+ }
+ cookietext = document.cookie.substring(cookieStart,cookieEnd);
+
+ // split the cookie text and create the variables
+
+ bits = cookietext.split("|");
+ lat = parseFloat(bits[0]);
+ lng = parseFloat(bits[1]);
+ myzoom = parseInt(bits[2]);
+ debug_enable = parseInt(bits[3]);
+ }
+ }
+ else {
+ lat = geolat;
+ lng = geolng;
+ myzoom = 12;
+ log("no cookie, lat = " + lat + " lng = " + lng);
+ }
+
+ }
+
+
+ // called when we click to add a bearing on map
+
+ function placeMarker(location, bearing, isNewBearing) {
+ if (isNewBearing == undefined) {
+ isNewBearing = false;
+ }
+
+ addNewBearing(location.lat(), location.lng(), bearing, isNewBearing);
+
+ // save to bearings database by calling a CGI
+
+ var url;
+ url = "/cgi-bin/addbearing.cgi?" + "lat=" + location.lat() + "&" + "lng=" + location.lng() + "&" + "bearing=" + bearing;
+ downloadUrl(url, function(doc) { });
+ }
+
+
+ //
+ // Async html request foo ----------------------------------------------------------------
+ //
+
+ /**
+ * Returns an XMLHttp instance to use for asynchronous
+ * downloading. This method will never throw an exception, but will
+ * return NULL if the browser does not support XmlHttp for any reason.
+ * @return {XMLHttpRequest|Null}
+ */
+ function createXmlHttpRequest() {
+ try {
+ if (typeof ActiveXObject != 'undefined') {
+ return new ActiveXObject('Microsoft.XMLHTTP');
+ } else if (window["XMLHttpRequest"]) {
+ return new XMLHttpRequest();
+ }
+ } catch (e) {
+ changeStatus(e);
+ }
+ return null;
+ };
+
+ /**
+ * This functions wraps XMLHttpRequest open/send function.
+ * It lets you specify a URL and will call the callback if
+ * it gets a status code of 200.
+ * @param {String} url The URL to retrieve
+ * @param {Function} callback The function to call once retrieved.
+ */
+ function downloadUrl(url, callback) {
+ var status = -1;
+ var request = createXmlHttpRequest();
+ if (!request) {
+ return false;
+ }
+
+ request.onreadystatechange = function() {
+ if (request.readyState == 4) {
+ try {
+ status = request.status;
+ } catch (e) {
+ // Usually indicates request timed out in FF.
+ }
+ if (status == 200) {
+ callback(request.responseText, request.status);
+ request.onreadystatechange = function() {};
+ }
+ }
+ }
+ request.open('GET', url, true);
+ try {
+ request.send(null);
+ } catch (e) {
+ changeStatus(e);
+ }
+ };
+
+
+</script>
+
+</head>
+<body onload="initialize()" onunload="setCookie()">
+
+ <div id="main-map">
+ </div>
+
+ <div id="bottom">
+
+ <div id="control">
+ <form name="control_panel">
+ <table>
+ <tr>
+ <td><input type="button" value="Add Bearing" onclick="addBearing2()"></td>
+ <td><input type="text" name="bearing" value="0" size="10" ></td>
+ <td><input type="button" value="Where Am I" onclick="whereAmI()"></td>
+ </tr>
+ <tr>
+ <td>Clear Database</td>
+ <td><input type="button" value="Clear" onclick="clearDatabase()"></td>
+ </tr>
+ <tr>
+ <td>Click to Add Bearing</td>
+ <td><input type="checkbox" name="click_bearing"></td>
+ </tr>
+ <tr>
+ <td>Debug Messages</td>
+ <td><input type="checkbox" name="debug_enable" onclick="debugClicked()"></td>
+ </tr>
+ <tr>
+ <td>Help</td>
+ <td><a href="https://freetel.svn.sourceforge.net/svnroot/freetel/foxy/README.txt">Foxy README</a></td>
+ </tr>
+ </table>
+ </form>
+ </div>
+
+
+ <div id="tests">
+ <h3>Tests</h3>
+ <ol>
+ <li><a href="/cgi-bin/getbearings.cgi">Test bearings.txt database</a><br>
+ </ol>
+ </div>
+
+ <div id="debugging_output">
+ <h3>Debugging Output</h3>
+ <ol id="debugging_messages">
+ </ol>
+ </div>
+ </div>
+
+
+</body>
+</html>
+++ /dev/null
-README.txt for foxy
-David Rowe
-May 25 2013
-
-
-Introduction
-------------
-
-Simple Google Maps application to plot Fox Hunt bearings. When run on
-a phone it automatically detects position and compass bearing. Placing
-Bearings can be placed with a mouse click on non-mobile devices. The
-bearings are stored in a text file database so can be shared by anyone
-who can reach the server.
-
-* Screen shot: foxy_screenshot.png
-
-* Based on Google maps V3 API.
-
-* Light weight: On the server we have just a few CGIs and a text file
- database. A browser cookie is used for storing configuration
- information. The CGIs are a few lines of shell script, so can run
- on any machine. Installation involves copying a few files and
- setting a few permissions.
-
-* Foxy will stand alone without the server & CGIs, but bearing storage
- won't be persistent and bearings can't be shared. Good for demos or
- when you can't reach the Internet.
-
-BUGS
-----
-
-On mobile devices:
-+ Click to add bearings places the bearing at a location offset from the tap location
-+ Double click doesn't remove bearings on mobile devices.
-
-Using Foxy
-----------
-
-1/ Point your browser at http://yourserver/foxy.html
-
-2/ If running on your phone your bearing will be updated
-automatically. Click on add bearing to add a bearing from your
-current position to the map.
-
-3/ The "where Am I" button re-centers the map on your current
-position. This is useful when scroll and zooming moves your position.
-
-4/ The "Click to Add Bearing" check box allow manual placement of
-bearings with a mouse click. Useful for demo and development on
-non-mobile devices such as desktops and laptops. This should be
-unchecked on mobile devices as pinching/scrolling often generates
-spurious "click" events leading to unwanted bearings.
-
-5/ Double click on a bearing to delete it.
-
-
-Implementation Notes
---------------------
-
-Foxy is implemented in Javascript (foxy.html). A simple text database
-file /var/www/foxy/bearings.txt is used to store bearing
-information. Very simple 1 page CGIs written in shell script are used
-to access the bearing database.
-
-A browser cookie is used to store config information like the current
-map centre.
-
-All the CGI scripts assume a hard coded to a path of
-/var/www/foxy/bearings.txt for the bearings.txt database.
-
-
-Files
------
-
- foxy.html - Javascript & HTML code for Foxy
- foxy.css - style sheet
-
-"cgi-bin" directory:
-
- addbearing.cgi - adds a bearing to bearings.txt
- delbearing.cgi - deletes a bearing from bearings.txt
- getbearings.cgi - reads bearings.txt database
- cleardb.cgi - clears database, removing all bearings
-
-
-Software
---------
-
-You need:
-
-1/ A web server. Apache is assumed in the /usr/lib/cgi-bin path below.
- The paths may be different for other web servers. Note the path
- to /var/www/foxy is hard coded in the CGI scripts so it's
- best not to change that.
-
-
-Installation
-------------
-
-1/ Server PC
-
- $ svn co https://freetel.svn.sourceforge.net/svnroot/freetel/foxy
- $ cd foxy
- $ sudo mkdir /var/www/foxy
- $ sudo chmod 777 /var/www/foxy
- $ cp foxy.css foxy.html /var/www/foxy
- $ sudo cp cgi-bin/* /usr/lib/cgi-bin
-
-Tests
------
-
-1/ Test reading and writing bearings.txt database with your browser:
-
- http://localhost/cgi-bin/addbearing.cgi?lat=123&lng=456&bearing=90
-
- $ cat /var/www/foxy/bearings.txt
- 123,456,90
-
- http://localhost/cgi-bin/delbearing.cgi?lat=123&lng=456
-
- $ cat /var/www/foxy/bearings.txt
- (empty file)
-
-Debugging
----------
-
-1/ Monitor Apache log:
-
- $ tail -f /var/log/apache2/access.log
-
-2/ Use Firebug on Firefox to single step, set breakpoints etc.
-
-3/ Check bearings.txt database, each line is (lat, lng, IP):
-
- # cat /var/www/foxy/bearings.txt
-
- -34.88548650005714,138.55225324630737,90
- -34.88006501016277,138.55394840240479,180
- -34.87893842193011,138.55278968811035,265
- -34.882511765792316,138.55210304260254,10
-
-4/ The "foxy001" cookie stores our state. On Firefox 3.5 you
- can remove the foxy cookie using Edit-Preferences-Privacy, then
- click on "remove individual cookies".
-
-5/ To manually reset to defaults:
-
- * move to another page (cookie is saved when we exit page)
- * rm -f /var/www/foxy/bearings.txt
- * Delete cookie using step (4) above
+++ /dev/null
-#!/bin/sh
-# addbearing.cgi
-# David Rowe 25 May 2013
-#
-# CGI to add a new bearing
-
-cat <<EOF
-Content-type: text/html
-
-<html>
-<head>
-<meta http-equiv="cache-control" content="no-cache">
-<meta http-equiv="pragma" content="no-cache">
-<meta http-equiv="expires" content="-1"></head></head>
-<body>
-EOF
-
-lat=`echo "$QUERY_STRING" | sed -n "s/.*lat=\(.*\)&lng.*/\1/p"`
-lng=`echo "$QUERY_STRING" | sed -n "s/.*lng=\(.*\)&bearing.*/\1/p"`
-bearing=`echo "$QUERY_STRING" | sed -n "s/.*bearing=\(.*\)/\1/p"`
-
-echo $lat,$lng,$bearing >> /var/www/foxy/bearings.txt
-
-echo $QUERY_STRING "<br>"
-echo "<br>"
-echo $lat $lng $bearing
-
-cat <<EOF
-</body>
-</html>
-EOF
+++ /dev/null
-#!/bin/sh
-# cleardb.cgi
-# David Rowe 25 May 2013
-#
-# CGI to delete entire bearing database
-
-cat <<EOF
-Content-type: text/html
-
-<html>
-<head>
-<meta http-equiv="cache-control" content="no-cache">
-<meta http-equiv="pragma" content="no-cache">
-<meta http-equiv="expires" content="-1"></head></head>
-<body>
-EOF
-
-# path to node database text file
-
-P=/var/www/foxy
-rm $P/bearings.txt
-
-cat <<EOF
-</body>
-</html>
-EOF
+++ /dev/null
-#!/bin/sh
-# delbearing.cgi
-# David Rowe 25 May 2012
-#
-# CGI to delete a bearing
-
-cat <<EOF
-Content-type: text/html
-
-<html>
-<head>
-<meta http-equiv="cache-control" content="no-cache">
-<meta http-equiv="pragma" content="no-cache">
-<meta http-equiv="expires" content="-1"></head></head>
-<body>
-EOF
-
-lat=`echo "$QUERY_STRING" | sed -n "s/lat=\(.*\)&.*/\1/pg"`
-lng=`echo "$QUERY_STRING" | sed -n "s/.*lng=\(.*\)/\1/pg"`
-
-# path to node database text file
-
-P=/var/www/foxy
-
-cat $P/bearings.txt | sed "/$lat,$lng.*/ d" > $P/bearings.tmp
-cp $P/bearings.tmp $P/bearings.txt
-rm $P/bearings.tmp
-
-#echo $QUERY_STRING "<br>"
-#echo "<br>"
-#echo $lat $lng
-
-cat <<EOF
-</body>
-</html>
-EOF
+++ /dev/null
-#!/bin/sh
-# getbearings.cgi
-# David Rowe 25 May 2013
-#
-# CGI to return list of bearings from the bearings.txt database text file
-# We use a CGI rather than fetching the text file directly
-# so we can stop Firefox from caching
-
-cat <<EOF
-Content-type: text/html
-
-<html>
-<head>
-<meta http-equiv="cache-control" content="no-cache">
-<meta http-equiv="pragma" content="no-cache">
-<meta http-equiv="expires" content="-1">
-</head>
-<body>
-EOF
-
-BEARINGS=/var/www/foxy/bearings.txt
-
-if [ -f $BEARINGS ] ; then
- cat $BEARINGS
-fi
-
-cat <<EOF
-</body>
-</html>
-EOF
+++ /dev/null
-html,body{
- margin:0;
- padding:0;
- width:100%;
- height:100%;
- font-family:Arial, Helvetica, sans-serif;
-}
-
-div#header{
- vertical-align:middle;
- border-bottom:1px solid #000;
-}
-div#main-map{
- width:100%;
- height:90%;
- float:top;
-}
-div#bottom{
- height:10%;
- float:bottom;
-}
-
-div#dataPanel{
- width:90%;
- height:50%;
- overflow:auto;
- border:2px solid #DDDDDD;
-}
-input{
- width:90%;
-}
-
-input.navi{
- font-size:12px;
- height:30px;
- margin-bottom:10px;
-}
-div ul{
- margin-top:30px;
- margin-bottom:30px;
-}
-div ul li{
- display: inline;
- list-style-type: none;
- padding-right: 40px;
- font-size:18px;
- font-weight:bold;
-}
-
-div ul li.title{
- font-size:22px;
- color:#888;
-}
-
-div#header p{
- color:#888;
- font-size:14px;
- padding-left:20px;
-}
-span.instruction{
- font-weight:bold;
-
-}
-
-.message-box { text-align: center; padding: 5px; color:#545454; width:80%; margin:5px auto; font-size:12px;}
-.clean { background-color: #efefef; border-top: 2px solid #dedede; border-bottom: 2px solid #dedede; }
-.info { background-color: #f7fafd; border-top: 2px solid #b5d3ff; border-bottom: 2px solid #b5d3ff; }
-.ok { background-color: #d7f7c4; border-top: 2px solid #82cb2f; border-bottom: 2px solid #82cb2f; }
-.alert { background-color: #fef5be; border-top: 2px solid #fdd425; border-bottom: 2px solid #fdd425; }
-.error { background-color: #ffcdd1; border-top: 2px solid #e10c0c; border-bottom: 2px solid #e10c0c; }
\ No newline at end of file
+++ /dev/null
-<!DOCTYPE html>
-<html>
-<head>
-<meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
-<meta http-equiv="content-type" content="text/html; charset=UTF-8"/>
-<style type="text/css">
- html { height: 100% }
- body { height: 100%; margin: 0px; padding: 0px }
- #map_canvas { height: 100% }
-</style>
-<title>Foxy</title>
-
-<link rel="stylesheet" type="text/css" href="foxy.css">
-<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=true"></script>
-
-<script type="text/javascript">
-
- /*
- foxy.html
- David Rowe
- May 25 2013
-
- Simple Google Maps application to plot Fox Hunt bearings.
-
- See README.txt for more information.
-
- search/grep on string "idea" for future ideas documented in
- comments below.
-
- */
-
- var map;
-
- // cookie params
-
- var cookiename = "foxy0001";
- var cookieexpy = 7;
-
- // these are stored in cookie, with default values
-
- var lat = 0;
- var lng = 0;
- var myzoom = 2;
- var update_enable = 0;
- var debug_enable = 1;
- var known_location = true;
- var bearing = 0.0;
-
- var bearings = []; // database of bearings we keep in memory
- // mirrors bearings.txt
-
- var geolocationSupport;
- var geolat = 0;
- var geolng = 0;
- var hasCompass;
- var currentHeading;
- var posMarker;
-
- //
- // Initialisation ----------------------------------------------------------------
- //
-
- // Called when we load page
-
- function initialize() {
-
- // if geolocation supported get our initial location
-
- if(navigator.geolocation) {
- geolocationSupport = true;
-
- navigator.geolocation.getCurrentPosition(function(position) {
- log("getCurrentPosition");
- lat = geolat = position.coords.latitude;
- lng = geolng = position.coords.longitude;
-
- continueInit();
- }, function() {
- continueInit();
- }, {timeout:5});
- }
- }
-
- function continueInit() {
- // if we have a compass use it to get bearing
-
- testForCompass();
-
- // we use our cookie as persistant storage for map location,
- // control panel values etc
-
- getCookie();
-
- // init map
-
- var myLatlng = new google.maps.LatLng(lat, lng);
- var myOptions = {
- disableDoubleClickZoom: true,
- zoom: myzoom,
- center: myLatlng,
- scaleControl: true,
- mapTypeId: google.maps.MapTypeId.ROADMAP
- }
- map = new google.maps.Map(document.getElementById("main-map"), myOptions);
-
- // For testing on a desk top it's useful to left click to add
- // bearings. This sucks on mobile as a pinch or drag can generate a
- // click event and you get spurious bearings. So it can be disabled
- // with the 'Click to add bearing' check box
-
- google.maps.event.addListener(map, 'click', function (event) {
- if (document.control_panel.click_bearing.checked) {
- bearing = parseFloat(document.control_panel.bearing.value);
- placeMarker(event.latLng, bearing, false);
- }
- });
-
- document.control_panel.debug_enable.checked = debug_enable;
-
- if (geolocationSupport) {
- posMarker = new google.maps.Marker(
- {position: myLatlng,
- map: map});
- navigator.geolocation.watchPosition(showPosition);
- }
-
- // read from bearings.txt database text file on server and init map
-
- downloadUrl("/cgi-bin/getbearings.cgi", loadBearings);
- }
-
-
- // Slurp up bearings.txt when web pages loads
-
- loadBearings = function(doc, status) {
- log("loadBearings start");
-
- // split the document into lines
-
- var lines = doc.split("\n");
- for (var i=0; i<lines.length; i++) {
- if (lines[i].length > 1) {
-
- // split each line into parts separated by "," and use the contents
-
- parts = lines[i].split(",");
- if (parts.length > 1) {
- var lat = parseFloat(parts[0]);
- var lng = parseFloat(parts[1]);
- var bearing = parseFloat(parts[2]);
-
- addNewBearing(lat, lng, bearing, false);
- }
- }
- }
-
- log("loadBearings end");
-
- }
-
-
- //
- // Compass Support ----------------------------------------------------------------
- //
-
- function startCompass()
- {
- window.addEventListener('deviceorientation', onDeviceOrientationChange); // Gyroscope
- }
-
- function testForCompass()
- {
- var ua = navigator.userAgent.toLowerCase();
- // Let's do _something_ for unsupported browsers.
- if (ua.indexOf('firefox') != -1 || ua.indexOf('opera') != -1 || ua.indexOf('msie') != -1)
- {
- hasCompass = false;
- startCompass();
- }
- else if (ua.indexOf('iphone os 4') != -1)
- {
- hasCompass = false;
- startCompass();
- }
- else if (window.DeviceOrientationEvent)
- {
- window.addEventListener('deviceorientation', compassTest);
- }
- else
- {
- hasCompass = false;
- startCompass();
- }
- }
-
- function compassTest(event)
- {
- window.removeEventListener('deviceorientation', compassTest);
- if (event.webkitCompassHeading != undefined || event.alpha != null) // Device does have a compass
- {
- hasCompass = true;
- }
- else
- {
- hasCompass = false;
- }
- startCompass();
- }
-
- // this gets called (a lot) when device orientation changes
-
- function onDeviceOrientationChange(event) {
- if (event.webkitCompassHeading != undefined)
- currentHeading = (360 - event.webkitCompassHeading);
- else if (event.alpha != null)
- currentHeading = (270 - event.alpha) * -1;
- document.control_panel.bearing.value = Math.round(currentHeading);
- }
-
- // remove leading and trailing whitespace from a string
-
- function trim(stringToTrim) {
- return stringToTrim.replace(/^\s+|\s+$/g,"");
- }
-
-
- //
- // Helper Funtions ----------------------------------------------------------------
- //
-
- // calculate distance between two points
-
- rad = function(x) {return x*Math.PI/180;}
-
- distHaversine = function(p1, p2) {
- var R = 6371; // earth's mean radius in km
- var dLat = rad(p2.lat() - p1.lat());
- var dLong = rad(p2.lng() - p1.lng());
-
- var a = Math.sin(dLat/2) * Math.sin(dLat/2) +
- Math.cos(rad(p1.lat())) * Math.cos(rad(p2.lat())) * Math.sin(dLong/2) * Math.sin(dLong/2);
- var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
- var d = R * c;
-
- return d.toFixed(3);
- }
-
- // Converts numeric degrees to radians
-
- function toRad(deg) {
- return deg * Math.PI / 180;
- }
-
- // Converts radians to numeric (signed) degrees
-
- function toDeg(rad) {
- return rad * 180 / Math.PI;
- }
-
- // given a bearing and distance calculate end location
-
- function bearingToLocation(location1, bearing, d) {
- var lat1 = toRad(location1.lat());
- var lon1 = toRad(location1.lng());
- var bearing_rad = toRad(bearing);
- var R = 6378137;
-
- var lat2 = Math.asin( Math.sin(lat1)*Math.cos(d/R) +
- Math.cos(lat1)*Math.sin(d/R)*Math.cos(bearing_rad) );
- var lon2 = lon1 + Math.atan2(Math.sin(bearing_rad)*Math.sin(d/R)*Math.cos(lat1),
- Math.cos(d/R)-Math.sin(lat1)*Math.sin(lat2));
-
- var location2 = new google.maps.LatLng(toDeg(lat2), toDeg(lon2));
- return location2;
- }
-
- function log(message) {
- if (debug_enable == 1) {
- message_list = document.getElementById("debugging_messages");
- log_message = document.createTextNode(message);
- log_list_item = document.createElement('li');
- log_list_item.appendChild(log_message);
- message_list.appendChild(log_list_item);
- }
- }
-
- // this function calls itself every update_time seconds
- // used for peridoic updates (polling) of network stats
-
- function showPosition(position) {
- lat = geolat = position.coords.latitude;
- lng = geolng = position.coords.longitude;
- log("showPosition lat=" + lat + " lng=" + lng);
-
- posMarker.setPosition( new google.maps.LatLng( lat, lng ) );
- }
-
- //
- // GUI Call Backs ----------------------------------------------------------------
- //
-
- function addBearing2() {
- if (geolocationSupport) {
- if (hasCompass) {
- bearing = currentHeading;
- }
- else {
- bearing = document.control_panel.bearing.value;
- }
- var latlng = new google.maps.LatLng(geolat, geolng);
- placeMarker(latlng, bearing, false);
- map.setCenter(latlng);
- }
- }
-
- // rec-center map on curent location if scroll/pinch events screw us up
-
- function whereAmI() {
- var latlng = new google.maps.LatLng(geolat, geolng);
- map.setCenter(latlng);
- }
-
- // sets up map for a new bearings
- // adds bearing to bearings[] array but doesn't write to text file
-
- function clearDatabase() {
-
- // call CGI to rm bearings.txt
-
- downloadUrl("/cgi-bin/cleardb.cgi",function(doc){});
-
- // delete all existing bearings
-
- if (bearings) {
- for (j in bearings) {
- bearings[j].marker.setMap(null);
- bearings[j].path.setMap(null);
- }
- }
- bearings = [];
- }
-
- function debugClicked() {
- if (document.control_panel.debug_enable.checked)
- debug_enable = 1;
- else
- debug_enable = 0;
- }
-
-
- //
- // Adding a new Bearing ---------------------------------------------------------
- //
-
- function addNewBearing(lat, lng, bearing, isNewBearing) {
-
- // create the marker at point where bearing starts
-
- var location = new google.maps.LatLng(lat, lng);
- var newMarker = new google.maps.Marker(
- {position: location,
- map: map});
-
- // idea: might be useful for "new" bearing indicator
- // if (isNewBearing) {
- // newMarker.setAnimation(google.maps.Animation.BOUNCE);
- //}
-
- var newInfoWindow = new google.maps.InfoWindow(
- { content: "put some info here"
- });
-
- // creat bearing line coords
-
- var location2 = bearingToLocation(location, bearing, 100000);
- var coords = [
- location,
- location2
- ];
-
- // draw line
-
- var newPath = new google.maps.Polyline({
- path: coords,
- strokeColor: "#080000",
- strokeOpacity: 0.5,
- strokeWeight: 5
- });
- newPath.setMap(map);
-
- // add to bearings array
- // idea: add time stamp to info window? Signal strength? Order
-
- var newBearing = {marker : newMarker,
- bearing: newBearing,
- infowindow: newInfoWindow,
- path: newPath};
- bearings.push(newBearing);
-
- google.maps.event.addListener(newMarker, "dblclick", function() {
-
- // remove bearing from bearings array
-
- var new_bearings = [];
- for (var j=0; j<bearings.length; j++) {
- if (bearings[j].marker.position != newMarker.position) {
- new_bearings.push(bearings[j]);
- }
- else
- bearings[j].path.setMap(null);
- }
- bearings = new_bearings;
-
- // delete bearing from text file
-
- var url;
- url = "/cgi-bin/delbearing.cgi?" + "lat=" + this.position.lat() + "&" + "lng=" + this.position.lng();
- downloadUrl(url, function(doc) { });
- this.setMap(null);
-
- });
-
- }
-
-
- //
- // Cookie Support ----------------------------------------------------------------
- //
-
- // save state (config info) to our cookie
-
- function setCookie() {
- var cookietext = cookiename;
- cookietext += "=" + map.getCenter().lat();
- cookietext += "|" + map.getCenter().lng() + "|" + map.getZoom();
- cookietext += "|" + debug_enable;
- if (cookieexpy) {
- var exdate=new Date();
- exdate.setDate(exdate.getDate()+cookieexpy);
- cookietext += ";expires="+exdate.toGMTString();
- }
-
- // write the cookie
-
- document.cookie = cookietext;
- }
-
-
- // Grab a bunch of config info from our cookie
-
- function getCookie() {
-
- if (document.cookie.length > 0) {
- log("cookie found");
- cookieStart = document.cookie.indexOf(cookiename + "=");
-
- // lets see if our cookie exists
-
- if (cookieStart!=-1) {
- cookieStart += cookiename.length+1;
- cookieEnd=document.cookie.indexOf(";",cookieStart);
- if (cookieEnd==-1) {
- cookieEnd=document.cookie.length;
- }
- cookietext = document.cookie.substring(cookieStart,cookieEnd);
-
- // split the cookie text and create the variables
-
- bits = cookietext.split("|");
- lat = parseFloat(bits[0]);
- lng = parseFloat(bits[1]);
- myzoom = parseInt(bits[2]);
- debug_enable = parseInt(bits[3]);
- }
- }
- else {
- lat = geolat;
- lng = geolng;
- myzoom = 12;
- log("no cookie, lat = " + lat + " lng = " + lng);
- }
-
- }
-
-
- // called when we click to add a bearing on map
-
- function placeMarker(location, bearing, isNewBearing) {
- if (isNewBearing == undefined) {
- isNewBearing = false;
- }
-
- addNewBearing(location.lat(), location.lng(), bearing, isNewBearing);
-
- // save to bearings database by calling a CGI
-
- var url;
- url = "/cgi-bin/addbearing.cgi?" + "lat=" + location.lat() + "&" + "lng=" + location.lng() + "&" + "bearing=" + bearing;
- downloadUrl(url, function(doc) { });
- }
-
-
- //
- // Async html request foo ----------------------------------------------------------------
- //
-
- /**
- * Returns an XMLHttp instance to use for asynchronous
- * downloading. This method will never throw an exception, but will
- * return NULL if the browser does not support XmlHttp for any reason.
- * @return {XMLHttpRequest|Null}
- */
- function createXmlHttpRequest() {
- try {
- if (typeof ActiveXObject != 'undefined') {
- return new ActiveXObject('Microsoft.XMLHTTP');
- } else if (window["XMLHttpRequest"]) {
- return new XMLHttpRequest();
- }
- } catch (e) {
- changeStatus(e);
- }
- return null;
- };
-
- /**
- * This functions wraps XMLHttpRequest open/send function.
- * It lets you specify a URL and will call the callback if
- * it gets a status code of 200.
- * @param {String} url The URL to retrieve
- * @param {Function} callback The function to call once retrieved.
- */
- function downloadUrl(url, callback) {
- var status = -1;
- var request = createXmlHttpRequest();
- if (!request) {
- return false;
- }
-
- request.onreadystatechange = function() {
- if (request.readyState == 4) {
- try {
- status = request.status;
- } catch (e) {
- // Usually indicates request timed out in FF.
- }
- if (status == 200) {
- callback(request.responseText, request.status);
- request.onreadystatechange = function() {};
- }
- }
- }
- request.open('GET', url, true);
- try {
- request.send(null);
- } catch (e) {
- changeStatus(e);
- }
- };
-
-
-</script>
-
-</head>
-<body onload="initialize()" onunload="setCookie()">
-
- <div id="main-map">
- </div>
-
- <div id="bottom">
-
- <div id="control">
- <form name="control_panel">
- <table>
- <tr>
- <td><input type="button" value="Add Bearing" onclick="addBearing2()"></td>
- <td><input type="text" name="bearing" value="0" size="10" ></td>
- <td><input type="button" value="Where Am I" onclick="whereAmI()"></td>
- </tr>
- <tr>
- <td>Clear Database</td>
- <td><input type="button" value="Clear" onclick="clearDatabase()"></td>
- </tr>
- <tr>
- <td>Click to Add Bearing</td>
- <td><input type="checkbox" name="click_bearing"></td>
- </tr>
- <tr>
- <td>Debug Messages</td>
- <td><input type="checkbox" name="debug_enable" onclick="debugClicked()"></td>
- </tr>
- <tr>
- <td>Help</td>
- <td><a href="https://freetel.svn.sourceforge.net/svnroot/freetel/foxy/README.txt">Foxy README</a></td>
- </tr>
- </table>
- </form>
- </div>
-
-
- <div id="tests">
- <h3>Tests</h3>
- <ol>
- <li><a href="/cgi-bin/getbearings.cgi">Test bearings.txt database</a><br>
- </ol>
- </div>
-
- <div id="debugging_output">
- <h3>Debugging Output</h3>
- <ol id="debugging_messages">
- </ol>
- </div>
- </div>
-
-
-</body>
-</html>