Skip to content

Instantly share code, notes, and snippets.

@Integralist
Created January 31, 2012 12:22
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save Integralist/1710256 to your computer and use it in GitHub Desktop.
Google Maps using native HTML5 geolocation + Audio with Google Places

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).

<!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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment