forked from diveintomark/diveintohtml5
-
Notifications
You must be signed in to change notification settings - Fork 0
/
geolocation.html
380 lines (284 loc) · 30.5 KB
/
geolocation.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
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
<!DOCTYPE html>
<meta charset=utf-8>
<title>Geolocation - Dive Into HTML5</title>
<!--[if lt IE 9]><script src=j/html5.js></script><![endif]-->
<link rel=icon href=favicon.ico>
<link rel=alternate type=application/atom+xml href=https://github.com/diveintomark/diveintohtml5/commits/master.atom>
<link rel=stylesheet href=screen.css>
<style>
body{counter-reset:h1 6}
</style>
<link rel=stylesheet media='only screen and (max-device-width: 480px)' href=mobile.css>
<link rel=prefetch href=index.html>
<p>You are here: <a href=index.html>Home</a> <span class=u>‣</span> <a href=table-of-contents.html#geolocation>Dive Into <abbr>HTML5</abbr></a> <span class=u>‣</span>
<h1><br>You Are Here<br>(And So Is Everybody Else)</h1>
<p id=toc>
<p class=a>❧
<h2 id=divingin>Diving In</h2>
<p class=f><img src=i/aoc-g.png alt=G width=106 height=103>eolocation is the art of figuring out where you are in the world and (optionally) sharing that information with people you trust. There is more than one way to figure out where you are — your <abbr>IP</abbr> address, your wireless network connection, which cell tower your phone is talking to, or dedicated <abbr>GPS</abbr> hardware that calculates latitude and longitude from information sent by satellites in the sky.
<div class=pf>
<h4>Ask Professor Markup</h4>
<div class=inner>
<blockquote class=note>
<p><span>☞</span>Q: Geolocation sounds scary. Can I turn it off?<br>
A: Privacy is an obvious concern when you’re talking about sharing your physical location with a remote web server. The <a href=http://www.w3.org/TR/geolocation-API/#security>geolocation <abbr>API</abbr> explicitly states</a>: “User Agents must not send location information to Web sites without the express permission of the user.” In other words, sharing your location is always opt-in. If you don’t want to, you don’t have to.
</blockquote>
</div>
</div>
<p class=a>❧
<h2 id=w3c>The Geolocation API</h2>
<p>The <a href=http://www.w3.org/TR/geolocation-API/>geolocation <abbr>API</abbr></a> lets you share your location with trusted web sites. The latitude and longitude are available to JavaScript on the page, which in turn can send it back to the remote web server and do fancy location-aware things like finding local businesses or showing your location on a map.
<p>As you can see from the following table, the geolocation <abbr>API</abbr> is supported by most browsers on the desktop and mobile devices. Additionally, some older browsers and devices can be supported by wrapper libraries, as we’ll see later in this chapter.
<table class=bc>
<caption>Geolocation <abbr>API</abbr> support</caption>
<thead>
<tr><th title="Internet Explorer">IE<th title="Mozilla Firefox">Firefox<th title="Apple Safari">Safari<th title="Google Chrome">Chrome<th>Opera<th>iPhone<th>Android
<tbody>
<tr><td>9.0+<td>3.5+<td>5.0+<td>5.0+<td>10.6+<td>3.0+<td>2.0+
</table>
<p>Along with support for the standard geolocation <abbr>API</abbr>, there are a plethora of device-specific <abbr>API</abbr>s on other mobile platforms. I’ll cover all that later in this chapter.
<p class=a>❧
<h2 id=the-code>Show Me The Code</h2>
<p>The geolocation <abbr>API</abbr> centers around a new property on the global <code>navigator</code> object: <code>navigator.geolocation</code>. <p>The simplest use of the geolocation <abbr>API</abbr> looks like this:
<pre><code>function get_location() {
<mark>navigator.geolocation.getCurrentPosition</mark>(show_map);
}</code></pre>
<p>That has no detection, no error handling, and no options. Your web application should probably include at least the first two of those. To <a href=detect.html#geolocation>detect support for the geolocation <abbr>API</abbr></a>, you can use <a href=http://www.modernizr.com/>Modernizr</a>:
<pre style="float:left;padding-left:0"><code>function get_location() {
if (<mark>Modernizr.geolocation</mark>) {
navigator.geolocation.getCurrentPosition(show_map);
} else {
// no native support; maybe try Gears?
}
}</code></pre>
<p class="legend right" style="margin-top:2.5em"><span class=arrow> ⇜</span> I CAN HAS GEO?
<p class=clear>What you do without geolocation support is up to you. I’ll explain the Gears fallback option in a minute, but first I want to talk about what happens <em>during</em> that call to <code>getCurrentPosition()</code>. As <a href=#divingin>I mentioned at the beginning of this chapter</a>, geolocation support is <em>opt-in</em>. That means your browser will never force you to reveal your current physical location to a remote server. The user experience differs from browser to browser. In Mozilla Firefox, calling the <code>getCurrentPosition()</code> function of the geolocation <abbr>API</abbr> will cause the browser to pop up an “infobar” at the top of the browser window. The infobar looks like this:
<p class=c><img src=i/geolocation-opt-in.png alt="Geolocation opt-in infobar" width=737 height=32>
<p>There’s a lot going on here. You, as the end user,
<ul>
<li>are told that a website wants to know your location
<li>are told <em>which</em> website wants to know your location
<li>can click through to <a href=http://www.mozilla.com/en-US/firefox/geolocation/>Mozilla’s “Location-Aware Browsing” help page</a> which explains what the heck is going on (short story: Google provides the location and stores your data in accordance with its <a href=http://www.google.com/intl/en/privacy/lsf.html>Location Service Privacy Policy</a>)
<li>can choose to share your location
<li>can choose <em>not</em> to share your location
<li>can tell your browser to remember your choice (either way, share or don’t share) so you never see this infobar again on this website
</ul>
<p>Furthermore, this infobar is
<ul>
<li>non-modal, so it won’t prevent you from switching to another browser window or tab
<li>tab-specific, so it will disappear if you switch to another browser window or tab and reappear when you switch back to the original tab
<li>unconditional, so there is no way for a website to bypass it
<li>blocking, so there is no chance that the website can determine your location while it’s waiting for your answer
</ul>
<p>You just saw the JavaScript code that causes this infobar to appear. It’s a single function call which takes a callback function (which I called <code>show_map</code>). The call to <code>getCurrentPosition()</code> will return immediately, but that doesn’t mean that you have access to the user’s location. The first time you are guaranteed to have location information is in the callback function. The callback function looks like this:
<pre><code>function show_map(position) {
var latitude = position.coords.latitude;
var longitude = position.coords.longitude;
// let's show a map or do something interesting!
}</code></pre>
<p>The callback function will be called with a single parameter, an object with two properties: <code>coords</code> and <code>timestamp</code>. The timestamp is just that, the date and time when the location was calculated. (Since this is all happening asynchronously, you can’t really know when that will happen in advance. It might take some time for the user to read the infobar and agree to share their location. Devices with dedicated <abbr>GPS</abbr> hardware may take some more time to connect to a <abbr>GPS</abbr> satellite. And so on.) The <code>coords</code> object has properties like <code>latitude</code> and <code>longitude</code> which are exactly what they sound like: the user’s physical location in the world.
<table class=st>
<caption>Position Object</caption>
<tr class=ho><th>Property<th>Type<th>Notes
<tr class=zebra><th><code>coords.latitude</code><td>double<td>decimal degrees
<tr><th><code>coords.longitude</code><td>double<td>decimal degrees
<tr class=zebra><th><code>coords.altitude</code><td>double or <code>null</code><td>meters above the <a href=http://en.wikipedia.org/wiki/Reference_ellipsoid>reference ellipsoid</a>
<tr><th><code>coords.accuracy</code><td>double<td>meters
<tr class=zebra><th><code>coords.altitudeAccuracy</code><td>double or <code>null</code><td>meters
<tr><th><code>coords.heading</code><td>double or <code>null</code><td>degrees clockwise from <a href=http://en.wikipedia.org/wiki/True_north>true north</a>
<tr class=zebra><th><code>coords.speed</code><td>double or <code>null</code><td>meters/second
<tr><th><code>timestamp</code><td>DOMTimeStamp<td>like a <code>Date()</code> object
</table>
<p class=ss style="margin-top:1.75em"><img src=i/openclipart.org_johnny_automatic_riding_a_bike.png width=196 height=239 alt="boy riding a bicycle">
<p>Only three of the properties are guaranteed to be there (<code>coords.latitude</code>, <code>coords.longitude</code>, and <code>coords.accuracy</code>). The rest might come back <code>null</code>, depending on the capabilities of your device and the backend positioning server that it talks to. The <code>heading</code> and <code>speed</code> properties are calculated based on the user’s previous position, if possible.
<p class=a>❧
<h2 id=errors>Handling Errors</h2>
<p>Geolocation is complicated. Things can go wrong. I’ve mentioned the “user consent” angle already. If your web application wants the user’s location but the user doesn’t want to give it to you, you’re screwed. The user always wins. But what does that look like in code? It looks like the second argument to the <code>getCurrentPosition()</code> function: an error handling callback function.
<pre><code>navigator.geolocation.getCurrentPosition(
show_map, <mark>handle_error</mark>)</code></pre>
<p>If anything goes wrong, your error callback function will be called with a <code>PositionError</code> object.
<table class=st>
<caption>PositionError Object</caption>
<tr class=ho><th>Property<th>Type<th>Notes
<tr class=zebra><th><code>code</code><td>short<td>an enumerated value
<tr><th><code>message</code><td>DOMString<td>not intended for end users
</table>
<p>The <code>code</code> property will be one of
<ul>
<li><code>PERMISSION_DENIED</code> (<code>1</code>) if the user clicks that “Don’t Share” button or otherwise denies you access to their location.
<li><code>POSITION_UNAVAILABLE</code> (<code>2</code>) if the network is down or the positioning satellites can’t be contacted.
<li><code>TIMEOUT</code> (<code>3</code>) if the network is up but it takes too long to calculate the user’s position. How long is “too long”? I’ll show you how to define that in the next section.
<li><code>UNKNOWN_ERROR</code> (<code>0</code>) if anything else goes wrong.
</ul>
<p class="legend top" style="padding-left:8.5em"><span class=arrow>↶</span> Be gracious in defeat
<pre><code>function handle_error(err) {
if (<mark>err.code</mark> == 1) {
// user said no!
}
}</code></pre>
<div class=pf>
<h4>Ask Professor Markup</h4>
<div class=inner>
<blockquote class=note>
<p><span>☞</span>Q: Does the geolocation <abbr>API</abbr> work on the International Space Station, on the moon, or on other planets?<br>
A: <a href=http://www.w3.org/TR/geolocation-API/#coordinates_interface>The geolocation specification states</a>, “The geographic coordinate reference system used by the attributes in this interface is the World Geodetic System (2d) [WGS84]. No other reference system is supported.” The International Space Station is orbiting Earth, so <a href=http://twitter.com/Astro_TJ>astronauts on the station</a> can describe their location by latitude, longitude, and altitude. However, the World Geodetic System is Earth-centric, so it can’t be used to describe locations on the moon or on other planets.
</blockquote>
</div>
</div>
<p class=a>❧
<h2 id=options>Choices! I Demand Choices!</h2>
<p>Some popular mobile devices — like the iPhone and Android phones — support <em>two</em> methods of figuring out where you are. The first method triangulates your position based on your relative proximity to different cellular towers operated by your phone carrier. This method is fast and doesn’t require any dedicated <abbr>GPS</abbr> hardware, but it only gives you a rough idea of where you are. Depending on how many cell towers are in your area, “a rough idea” could be as little as one city block or as much as a kilometer in every direction.
<p style="float:left;margin:1.75em 1.75em 1.75em 0"><img src=i/openclipart.org_johnny_automatic_young_girl_pointing.png alt="young girl pointing" width=336 height=229>
<p>The second method actually uses dedicated <abbr>GPS</abbr> hardware on your device to talk to dedicated <abbr>GPS</abbr> positioning satellites that are orbiting the Earth. <abbr>GPS</abbr> can usually pinpoint your location within a few meters. The downside is that the dedicated <abbr>GPS</abbr> chip on your device draws a lot of power, so phones and other general purpose mobile devices usually turn off the chip until it’s needed. That means there will be a startup delay while the chip is initializing its connection with the <abbr>GPS</abbr> satellites in the sky. If you’ve ever used Google Maps on an iPhone or other smartphone, you’ve seen both methods in action. First you see a large circle that approximates your position (finding the nearest cell tower), then a smaller circle (triangulating with other cell towers), then a single dot with an exaction position (given by <abbr>GPS</abbr> satellites).
<p>The reason I mention this is that, depending on your web application, you may not need high accuracy. If you’re just looking for nearby movie listings, a “low accuracy” location is probably good enough. There aren’t <em>that</em> many movie theaters, even in dense cities, and you’ll probably be listing more than one of them anyway. On the other hand, if you’re giving turn by turn directions in real time, you really <em>do</em> need to know exactly where the user is so you can say “turn right in 20 meters” or whatever.
<p>The <code>getCurrentPosition()</code> function has an optional third argument, <a href=http://www.w3.org/TR/geolocation-API/#position-options>a <code>PositionOptions</code> object</a>. There are three properties you can set in a <code>PositionOptions</code> object. All the properties are optional. You can set any or all or none of them.
<table class=st>
<caption>PositionOptions Object</caption>
<tr class=ho><th>Property<th>Type<th>Default<th>Notes
<tr class=zebra><th><code>enableHighAccuracy</code><td>Boolean<td>false<td>true might be slower
<tr><th><code>timeout</code><td>long<td>(no default)<td>in milliseconds
<tr class=zebra><th><code>maximumAge</code><td>long<td>0<td>in milliseconds
</table>
<p>The <code>enableHighAccuracy</code> property is exactly what it sounds like. If true, and the device can support it, and the user consents to sharing their exact location, then the device will try to provide it. Both iPhones and Android phones have separate permissions for low- and high-accuracy positioning, so it is possible that calling <code>getCurrentPosition()</code> with <code>enableHighAccuracy:true</code> will fail, but calling with <code>enableHighAccuracy:false</code> would succeed.
<p>The <code>timeout</code> property is the number of milliseconds your web application is willing to wait for a position. This timer doesn’t start counting down until <em>after</em> the user gives permission to even try to calculate their position. You’re not timing the user; you’re timing the network.
<p>The <code>maximumAge</code> property allows the device to answer immediately with a cached position. For example, let’s say you call <code>getCurrentPosition()</code> for the first time, the user consents, and your success callback function is called with a position that was calculated at exactly 10:00 AM. Exactly one minute later, at 10:01 AM, you call <code>getCurrentPosition()</code> again with a <code>maximumAge</code> property of <code>75000</code>.
<pre><code>navigator.geolocation.getCurrentPosition(
success_callback, error_callback, <mark>{maximumAge: 75000}</mark>);</code></pre>
<p>What you’re saying is that you don’t necessarily need the user’s <em>current</em> location. You would be satisfied with knowing where they were 75 seconds ago (75000 milliseconds). The device knows where the user was 60 seconds ago (60000 milliseconds), because it calculated their location after the first time you called <code>getCurrentPosition()</code>. So the device doesn’t bother to recalculate the user’s current location. It just returns exactly the same information it returned the first time: same latitude and longitude, same accuracy, and same timestamp (10:00 AM).
<p class=ss><img src=i/openclipart.org_maven_Galileo_Galilei.png alt="old man looking through telescope" width=208 height=508>
<p>Before you ask for the user’s location, you should think about just how much accuracy you need, and set <code>enableHighAccuracy</code> accordingly. If you need to find their location more than once, you should think about how old the information could be and still be useful, and set <code>maximumAge</code> accordingly. If you need to find their location <em>continuously</em>, then <code>getCurrentPosition()</code> is not for you. You need to upgrade to <code>watchPosition()</code>.
<p>The <code>watchPosition()</code> function has the same structure as <code>getCurrentPosition()</code>. It takes two callback functions, a required one for success and an optional one for error conditions, and it can also take an optional <code>PositionOptions</code> object that has all the same properties you just learned about. The difference is that your callback function will be called <em>every time the user’s location changes</em>. There is no need to actively poll their position. The device will determine the optimal polling interval, and it will call your callback function whenever it determines that the user’s position has changed. You can use this to update a visible marker on a map, provide instructions on where to go next, or whatever you like. It’s entirely up to you.
<p>The <code>watchPosition()</code> function itself returns a number. You should probably store this number somewhere. If you ever want to stop watching the user’s location change, you can call the <code>clearWatch()</code> method and pass it this number, and the device will stop calling your callback function. If you’ve ever used the <code>setInterval()</code> and <code>clearInterval()</code> functions in JavaScript, this works the same way.
<p class=a>❧
<h2 id=ie>What About IE?</h2>
<p>Prior to version 9 (technically 9.0RC1), Internet Explorer did not support the <a href=#w3c><abbr>W3C</abbr> geolocation <abbr>API</abbr></a> that I’ve just described. But don’t despair! <a href=http://tools.google.com/gears/>Gears</a> is an open source browser plugin from Google that works on Windows, Mac, Linux, Windows Mobile, and Android. It provides features for older browsers. One of the features that Gears provides is a geolocation <abbr>API</abbr>. It’s not quite the same as the <abbr>W3C</abbr> geolocation <abbr>API</abbr>, but it serves the same purpose.
<p>While we’re on the subject of legacy platforms, I should point out that many older mobile phone platforms had their own device-specific geolocation <abbr>API</abbr>s. <a href="http://www.tonybunce.com/2008/05/08/Blackberry-Browser-Amp-GPS.aspx">BlackBerry</a>, <a href="http://www.forum.nokia.com/infocenter/index.jsp?topic=/Web_Developers_Library/GUID-4DDE31C7-EC0D-4EEC-BC3A-A0B0351154F8.html">Nokia</a>, <a href="http://developer.palm.com/index.php?option=com_content&view=article&id=1673#GPS-getCurrentPosition">Palm</a>, and <a href=http://bondi.omtp.org/1.0/apis/geolocation.html><abbr title="Open Mobile Terminal Platform">OMTP</abbr> BONDI</a> all provide their own geolocation <abbr>API</abbr>s. Of course, they all work differently from Gears, which in turn works differently from the <abbr>W3C</abbr> geolocation <abbr>API</abbr>. Wheeeeee!
<p class=a>❧
<h2 id=geo-js>geo.js to the Rescue</h2>
<p><a href=http://code.google.com/p/geo-location-javascript/><code>geo.js</code></a> is an open source, <abbr>MIT</abbr>-licensed JavaScript library that smooths over the differences between the <abbr>W3C</abbr> geolocation <abbr>API</abbr>, the Gears <abbr>API</abbr>, and the <abbr>API</abbr>s provided by mobile platforms. To use it, you’ll need to add two <code><script></code> elements at the bottom of your page. (Technically, you could put them anywhere, but scripts in your <code><head></code> will make your page load more slowly. So don’t do that!)
<p>The first script is <a href=http://code.google.com/apis/gears/gears_init.js><code>gears_init.js</code></a>, which initializes Gears if it’s installed. The second script is <a href=http://geo-location-javascript.googlecode.com/svn/trunk/js/geo.js><code>geo.js</code></a>.
<pre style="float:left"><code><!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Dive Into HTML5</title>
</head>
<body>
...
<mark><script src="gears_init.js"></script>
<script src="geo.js"></script></mark>
</body>
</html>
</code></pre>
<p class="legend right" style="margin-top:11.2em"><span class=arrow> ⇜</span> Don’t let it go to your <head>
<p class=clear>Now you’re ready to use whichever geolocation <abbr>API</abbr> is installed.
<pre><code>if (geo_position_js.init()) {
geo_position_js.getCurrentPosition(geo_success, geo_error);
}
</code></pre>
<p>Let’s take that one step at a time. First, you need to explicitly call an <code>init()</code> function. The <code>init()</code> function returns <code>true</code> if a supported geolocation <abbr>API</abbr> is available.
<pre><code>if (<mark>geo_position_js.init()</mark>) {</code></pre>
<p>Calling the <code>init()</code> function does not actually find your location. It just verifies that finding your location is possible. To actually find your location, you need to call the <code>getCurrentPosition()</code> function.
<pre><code> <mark>geo_position_js.getCurrentPosition</mark>(geo_success, geo_error);</code></pre>
<p>The <code>getCurrentPosition()</code> function will trigger your browser to ask for your permission to find and share your location. If geolocation is being provided by Gears, this will pop up a dialog asking if your trust the web site to use Gears. If your browser natively supports the geolocation <abbr>API</abbr>, the dialog will look different. For example, Firefox 3.5 natively supports the geolocation <abbr>API</abbr>. If you try to find your location in Firefox 3.5, it will display an infobar at the top of the page asking whether you want to share your location with this web site.
<p>The <code>getCurrentPosition()</code> function takes two callback functions as arguments. If the <code>getCurrentPosition()</code> function was successful in finding your location — that is, you gave your permission and the geolocation <abbr>API</abbr> actually worked its magic — it will call the function passed in as the first argument. In this example, the success callback function is called <code>geo_success</code>.
<pre><code> geo_position_js.getCurrentPosition(<mark>geo_success</mark>, geo_error);</code></pre>
<p>The success callback function takes a single argument, which contains the position information.
<p class="legend top" style="padding-left:6em"><span class=arrow>↶</span> Success callback
<pre><code>function geo_success(p) {
alert("Found you at latitude " + p.coords.latitude +
", longitude " + p.coords.longitude);
}</code></pre>
<p>If the <code>getCurrentPosition()</code> function could not find your location — either because you declined to give your permission, or the geolocation <abbr>API</abbr> failed for some reason — it will call the function passed in as the second argument. In this example, the failure callback function is called <code>geo_error</code>.
<pre><code> geo_position_js.getCurrentPosition(geo_success, <mark>geo_error</mark>);</code></pre>
<p>The failure callback function takes no arguments.
<p class="legend top" style="padding-left:6em"><span class=arrow>↶</span> Failure callback
<pre><code>function geo_error() {
alert("Could not find you!");
}</code></pre>
<p><code>geo.js</code> does not currently support the <code>watchPosition()</code> function. If you need continuous location information, you’ll need to actively poll <code>getCurrentPosition()</code> yourself.
<p class=a>❧
<h2 id=putting-it-all-together>A Complete, Live Example</h2>
<p>Here is a live example of using <a href=#geo-js><code>geo.js</code></a> to attempt to get your location and display a map of your immediate surroundings:
<p style="margin:0 auto;width:194px" id=geo-wrapper><img src=i/openclipart.org_johnny_automatic_globe_man.png alt="man with a globe for a head" width=194 height=317><br><span id=live-geolocation></span>
<p>How does it work? Let’s take a look. On page load, this page calls <code>geo_position_js.init()</code> to determine whether geolocation is available through any of the interfaces that <code>geo.js</code> supports. If so, it sets up a link you can click to look up your location. Clicking that link calls the <code>lookup_location()</code> function, shown here:
<pre><code>function lookup_location() {
geo_position_js.getCurrentPosition(show_map, show_map_error);
}</code></pre>
<p>If you give your consent to track your location, <em>and</em> the backend service was actually able to determine your location, <code>geo.js</code> calls the first callback function, <code>show_map()</code>, with a single argument, <code>loc</code>. The <code>loc</code> object has a <code>coords</code> property which contains latitude, longitude, and accuracy information. (This example doesn’t use the accuracy information.) The rest of the <code>show_map()</code> function uses the Google Maps API to set up an embedded map.
<pre><code>function show_map(loc) {
$("#geo-wrapper").css({'width':'320px','height':'350px'});
var map = new GMap2(document.getElementById("geo-wrapper"));
var center = new GLatLng(<mark>loc.coords.latitude</mark>, <mark>loc.coords.longitude</mark>);
map.setCenter(center, 14);
map.addControl(new GSmallMapControl());
map.addControl(new GMapTypeControl());
map.addOverlay(new GMarker(center, {draggable: false, title: "You are here (more or less)"}));
}</code></pre>
<p>If <code>geo.js</code> is unable to determine your location, it calls the second callback function, <code>show_map_error()</code>.
<pre><code>function show_map_error() {
$("#live-geolocation").html('Unable to determine your location.');
}</code></pre>
<p class=a>❧
<h2 id=further-reading>Further Reading</h2>
<ul>
<li><a href=http://www.w3.org/TR/geolocation-API/><abbr>W3C</abbr> geolocation <abbr>API</abbr></a>
<li><a href=http://tools.google.com/gears/>Gears</a>
<li><a href=http://www.tonybunce.com/2008/05/08/Blackberry-Browser-Amp-GPS.aspx>BlackBerry geolocation <abbr>API</abbr></a>
<li><a href="http://www.forum.nokia.com/infocenter/index.jsp?topic=/Web_Developers_Library/GUID-4DDE31C7-EC0D-4EEC-BC3A-A0B0351154F8.html">Nokia geolocation <abbr>API</abbr></a>
<li><a href="http://developer.palm.com/index.php?option=com_content&view=article&id=1673#GPS-getCurrentPosition">Palm geolocation <abbr>API</abbr></a>
<li><a href=http://bondi.omtp.org/1.0/apis/geolocation.html><abbr title="Open Mobile Terminal Platform">OMTP</abbr> BONDI geolocation <abbr>API</abbr></a>
<li><a href=http://code.google.com/p/geo-location-javascript/>geo.js</a>, the geolocation <abbr>API</abbr> wrapper script
<li><a href=http://msdn.microsoft.com/en-us/ie/ff468705.aspx#_HTML5_geolocation>Internet Explorer 9 Guide for Developers: Geolocation</a>
</ul>
<p class=a>❧
<p>This has been “You Are Here (And So Is Everybody Else).” The <a href=table-of-contents.html>full table of contents</a> has more if you’d like to keep reading.
<div class=pf>
<h4>Did You Know?</h4>
<div class=moneybags>
<blockquote><p>In association with Google Press, O’Reilly is distributing this book in a variety of formats, including paper, ePub, Mobi, and <abbr>DRM</abbr>-free <abbr>PDF</abbr>. The paid edition is called “HTML5: Up & Running,” and it is available now. This chapter is included in the paid edition.
<p>If you liked this chapter and want to show your appreciation, you can <a href="http://www.amazon.com/HTML5-Up-Running-Mark-Pilgrim/dp/0596806027?ie=UTF8&tag=diveintomark-20&creativeASIN=0596806027">buy “HTML5: Up & Running” with this affiliate link</a> or <a href=http://oreilly.com/catalog/9780596806033>buy an electronic edition directly from O’Reilly</a>. You’ll get a book, and I’ll get a buck. I do not currently accept direct donations.
</blockquote>
</div>
</div>
<p class=c>Copyright MMIX–MMXI <a href=about.html>Mark Pilgrim</a>
<form action=http://www.google.com/cse><div><input type=hidden name=cx value=014021643941856155761:6jgee_nxreo><input type=hidden name=ie value=UTF-8><input type=search name=q size=25 placeholder="powered by Google™"> <input type=submit name=sa value=Search></div></form>
<script src=j/jquery.js></script>
<script src=j/modernizr.js></script>
<script src=j/gears_init.js></script>
<script src=j/geo.js></script>
<script src=j/dih5.js></script>
<script src="http://maps.google.com/maps?file=api&v=2&sensor=false&key=ABQIAAAA9KK0oCozk3pdOlGYD6hrthR5pnyo8QWLgiiZq1vJ3YhZL8oiJBQk9j0jg4PxEDmO36mYgldwXseYGw"></script>
<script>
function supports(bool, suffix) {
var s = "Your browser ";
if (bool) {
s += "supports " + suffix + ".";
} else {
s += "does not support " + suffix + ". :(";
}
return s;
}
function lookup_location() {
geo_position_js.getCurrentPosition(show_map, show_map_error);
}
function show_map(loc) {
$("#geo-wrapper").css({'width':'320px','height':'350px'});
var map = new GMap2(document.getElementById("geo-wrapper"));
var center = new GLatLng(loc.coords.latitude,loc.coords.longitude);
map.setCenter(center, 14);
map.addControl(new GSmallMapControl());
map.addControl(new GMapTypeControl());
map.addOverlay(new GMarker(center, {draggable: false, title: "You are here (more or less)"}));
}
function show_map_error() {
$("#live-geolocation").html('Unable to determine your location.');
}
$(function() {
if (geo_position_js.init()) {
$("#live-geolocation").html(supports(true, "geolocation") + ' <a href="#" onclick="lookup_location();return false">Click to look up your location</a>.');
} else {
$("#live-geolocation").html(supports(false, "geolocation"));
}
});
</script>