public
Last active

Google Maps using native HTML5 geolocation + Audio with Google Places

  • Download Gist
Description.md
Markdown

We had a meeting with a new client to discuss a mobile app (client had asked for an app that worked on the "iPhone"). This app needed to play back audio depending on the users location (specifically if they were within 5 miles of the relevant location).

We decided that we would try and guide the client to build a mobile web app and so I knocked together a quick prototype of a Google Map that used a JavaScript version of it's Places API to load McDonald restaurants within 1 mile of the users current location. I used native browser geolocation to determine the users location. I started to include the watchPosition method which would have been used to demonstrate the app tracking our location but wasn't added in the end because we realised we wouldn't be able to properly demo that :-)

I dropped in custom markers onto the map and also decided to exclude IE9 from the demo because we had noticed issues with its geolocation algorithm (I checked online for any feedback I could find and apparently Microsofts database of Wifi locations just wasn't as good as other browsers and so the results were hideously off base).

map.html
HTML
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237
<!doctype html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title>Google Map Prototype</title>
<style type="text/css">
body {
margin: 0;
padding: 0;
}
/* We use set width/height dimensions because using percentages causes iOS resources to be exhausted!? */
#map {
height: 500px;
left: 50%;
margin: -225px 0 0 -350px;
position: absolute;
top: 50%;
width: 700px;
}
#audiofile {
display: none;
/* iOS devices aren't hiding the element so we use a CSS3 trick to get the element out of view! */
-webkit-transform: translate(-999em, 0);
-moz-transform: translate(-999em, 0);
-o-transform: translate(-999em, 0);
transform: translate(-999em, 0);
}
</style>
</head>
<body>
<audio id="audiofile" controls preload="auto" autobuffer>
<source src="sample.mp3" />
<source src="sample.ogg" />
</audio>
<div id="map"></div>
<!--
Not using just standard Google Maps
<script src="http://maps.google.com/maps/api/js?sensor=true"></script>
-->
<!--
Now using Places library which also loads the Maps api
Reference: https://code.google.com/apis/maps/documentation/javascript/places.html
-->
<script src="http://maps.googleapis.com/maps/api/js?libraries=places&sensor=true"></script>
<script type="text/javascript">
// Set-up new map instance (no location details specified yet)
var map = new google.maps.Map(document.getElementById('map'), {
mapTypeControl: true,
mapTypeControlOptions: {
style: google.maps.MapTypeControlStyle.DROPDOWN_MENU
},
mapTypeId: google.maps.MapTypeId.ROADMAP,
streetViewControl: true
}),
infowindow = new google.maps.InfoWindow(),
marker,
latlng,
watchID,
audioelement = document.getElementById('audiofile');
/**
* Following property indicates whether the current rendering engine is Trident (i.e. Internet Explorer)
*
* @return v { Integer|undefined } if IE then returns the version, otherwise returns 'undefined' to indicate NOT a IE browser
*/
var isIE = (function() {
var undef,
v = 3,
div = document.createElement('div'),
all = div.getElementsByTagName('i');
while (
div.innerHTML = '<!--[if gt IE ' + (++v) + ']><i></i><![endif]-->',
all[0]
);
return v > 4 ? v : undef;
}());
var whichPrefix = (function(){
// check if the browser supports CSS animation
var temp = document.createElement('div'),
prefixes = 'Webkit Moz O ms Khtml'.split(' '),
prefix = false;
for(var i = 0, len = prefixes.length; i < len; i++) {
if(temp.style[prefixes[i] + 'Transform'] !== undefined) {
prefix = prefixes[i];
break;
}
}
return prefix;
}());
function isHostMethod(object, property) {
var type = typeof object[property];
return type == 'function' || // For Safari 3 typeof result being 'function' instead of 'object'
(type == 'object' && !!object[property]) || // Protect against ES3 'null' typeof result being 'object'
type == 'unknown' || // For IE < 9 when Microsoft used ActiveX objects for Native Functions
type == 'string'; // typeof for 'document.body[outerHTML]' results in 'string'
}
function isHostObject(object, property) {
// object[property] protects against ES3 specification which allows null to be typeof 'object'
// so we check if 'object' is returned and that object[property] coerces to true
// then we group both checks (&& operator returns 2nd expression if 1st expression evaluates to true) and convert result into boolean
return !!(typeof(object[property]) == 'object' && object[property]);
}
function createMarker(place) {
var placeLoc = place.geometry.location,
logo = new google.maps.MarkerImage('marker-mcdonalds.png', new google.maps.Size(73,75), new google.maps.Point(0,0)),
marker = new google.maps.Marker({
map: map,
position: place.geometry.location,
icon: logo
}),
content = '<strong>' + place.name + '</strong><br>' + place.vicinity + '<br><a href="#" id="audiolink">Show audio player</a><br><br>';
google.maps.event.addListener(marker, 'click', function() {
infowindow.setContent(content);
infowindow.open(map, this);
});
}
function processLocation(position) {
// Get position
var lat = position.coords.latitude,
lng = position.coords.longitude,
latlng = new google.maps.LatLng(lat, lng);
// Set map location
map.setOptions({
center: latlng,
scrollwheel: false,
zoom: 12
});
// Add marker to map
marker = new google.maps.Marker({
position: latlng,
map: map,
title: 'Test Title'
});
// Event listener for users current location marker
google.maps.event.addListener(marker, 'click', function() {
infowindow.setContent('This is your current location!<br>We\'re now showing you all the McDonald\'s in a 5 mile radius');
infowindow.open(map, this);
});
// Open the window when the app has loaded
google.maps.event.trigger(marker, 'click', function() {
infowindow.setContent('This is your current location!<br>We\'re now showing you all the McDonald\'s in a 5 mile radius');
infowindow.open(map, this);
});
// Request any McDonald's within 1 mile (in meters) from the current location
var request = {
location: latlng,
radius: 8046.72, // 5 miles => http://www.unitconversion.org/length/meters-to-miles-conversion.html
types: ['food'],
name: 'McDonald'
};
// Create the Places request
var service = new google.maps.places.PlacesService(map);
service.search(request, function(results, status){
if (status == google.maps.places.PlacesServiceStatus.OK) {
for (var i = 0; i < results.length; i++) {
var place = results[i];
createMarker(results[i]);
}
}
});
}
// Doesn't appear to be executed??
function handleLocationErrors(err) {
switch(err.code) {
case err.PERMISSION_DENIED:
alert('You have decided not to share your location information');
break;
case err.POSITION_UNAVAILABLE:
alert('I\'m sorry but we could not detect your location');
break;
case err.TIMEOUT:
alert('I\'m sorry but the system timed out while waiting to retrieve your location information');
break;
default:
alert('I\'m sorry but an unknown error occurred');
break;
}
}
// Handle audio playback
function handleAudio(e) {
var targ = e.target,
audio;
if (targ.id === 'audiolink') {
// Make a copy of the <audio> element hidden in the page
audio = audioelement.cloneNode(true);
// Remove the link and replace with an audio tag
targ.parentNode.replaceChild(audio, targ);
audio.style.display = 'block';
if (whichPrefix !== false) {
audio.style[whichPrefix + 'Transform'] = 'translate(0, 0)';
}
}
}
// Bind Event Delegation to links
document.body.addEventListener('click', handleAudio, false);
// Because of IE9's rubbish implementation of geolocation makes it as useful as the basic ip address lookup polyfills (so not very useful)
if(isHostObject(navigator, 'geolocation') || isIE > 9) {
// This will ask the user to authorise the request for their location (only if geolocation is natively supported)
navigator.geolocation.getCurrentPosition(processLocation, handleLocationErrors);
// If the user starts moving around then watch their position
watchID = navigator.geolocation.watchPosition(function(){
// DO SOMETHING
});
} else {
alert('I\'m sorry, your device isn\'t capable of supporting the geolocation api which is required for this application to work correctly');
}
</script>
</body>
</html>

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.