-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.html
522 lines (474 loc) · 22.3 KB
/
index.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
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
s<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>reveal.js - The HTML Presentation Framework</title>
<meta name="description" content="A framework for easily creating beautiful presentations using HTML">
<meta name="author" content="Hakim El Hattab">
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, minimal-ui">
<link rel="stylesheet" href="css/reveal.css">
<link rel="stylesheet" href="css/theme/blood.css" id="theme">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css">
<style> .reveal i.fa { font-family:FontAwesome; font-style: normal; } </style>
<!-- Code syntax highlighting -->
<link rel="stylesheet" href="lib/css/zenburn.css">
<!-- Printing and PDF exports -->
<script>
var link = document.createElement( 'link' );
link.rel = 'stylesheet';
link.type = 'text/css';
link.href = window.location.search.match( /print-pdf/gi ) ? 'css/print/pdf.css' : 'css/print/paper.css';
document.getElementsByTagName( 'head' )[0].appendChild( link );
</script>
<!--[if lt IE 9]>
<script src="lib/js/html5shiv.js"></script>
<![endif]-->
</head>
<body>
<div class="reveal">
<!-- Any section element inside of this container is displayed as a slide -->
<div class="slides">
<section>
<h1>Offline Mobile Map Solutions</h1>
<h3>Nick Peihl, San Juan County</h3>
<p>
<small><a href="http://npeihl.com">npeihl.com</a> / <a href="http://twitter.com/npeihl">@npeihl</a></small>
</p>
<aside class="notes">
Today I'm here to talk about offline mobile map solutions currently in experimentation at San Juan County.
</aside>
</section>
<section>
<h2>About San Juan County</h2>
<aside class="notes">
</aside>
</section>
<section>
<h3>Total Population: ~16,000</h3>
<aside class="notes">
</aside>
</section>
<section>
<h3>San Juan</h3>
<img src="img/sanjuan.png"/>
<aside class="notes">
San Juan has county seat, Friday Harbor. Also the island I live and work on.
</aside>
</section>
<section>
<h3>Orcas</h3>
<img src="img/orcas.png"/>
</section>
<section>
<h3>Lopez</h3>
<img src="img/lopez.png"/>
</section>
<section>
<h3>Shaw</h3>
<img src="img/shaw.png"/>
</section>
<section>
<h3>Others</h3>
<img src="img/other.png"/>
<aside class="notes">
Those who desire to be even more remote, live on outer islands
</aside>
</section>
<section>
<img src="img/sanjuan.png"/>
<aside class="notes ">
Also, San Juan has a [next slide]
</aside>
</section>
<section>
<figure>
<img src="img/camel.png"/>
<figcaption><a href="https://commons.wikimedia.org/wiki/File%3ACamel.png">picture: Camel</a> credit:KnowItSome <a href="https://creativecommons.org/licenses/by-sa/3.0/deed.en">CC BY-SA 3.0</a> </figcaption>
</figure>
<aside class="notes">
camel. [next slide]
</aside>
</section>
<section>
<figure>
<img src="img/camel-bite.jpg"/>
<figcaption>
<a href="https://www.flickr.com/photos/frted/5823411014">picture: Bactrian Camel Smiling</a> credit:frted <a href="https://creativecommons.org/licenses/by-sa/2.0/">CC BY-SA 2.0</a>
</figcaption>
</figure>
<aside class="notes">
Please don't feed it.
</aside>
</section>
<section>
<h2>Getting to the islands</h2>
<aside class="notes">
How do I get there? Two ways.
</aside>
</section>
<section>
<figure>
<img src="img/kenmore.jpg"/>
<figcaption>
<a href="https://commons.wikimedia.org/wiki/File:Kenmore_Air_Cessna_Grand_Caravan.jpg">picture: Kenmore Air Cessna Grand Caravan</a> credit: Michael Hays <a href="https://creativecommons.org/licenses/by/2.0/deed.en">CC BY-2.0</a>
</figcaption>
</figure>
<aside class="notes">
Take a small plane
</aside>
</section>
<section>
<figure>
<img src="img/Samish.jpg"/>
<figcaption>
<a href="https://commons.wikimedia.org/wiki/File:Samish.JPG">picture: Samish</a> credit: Snowy Ferries <a href="https://creativecommons.org/licenses/by-sa/4.0/deed.en">CC BY-SA 4.0</a>
</figcaption>
</figure>
<aside class="notes">
Take a ferry. Most folks take a ferry.
</aside>
</section>
<section>
<figure>
<img src="img/scenic-byway.jpg">
</figure>
<aside class="notes">
Our economy is heavily tourism-driven. So tourists get on the ferry and want to Tweet or Instagram their photos and are met with this...
</aside>
</section>
<section>
<img src="img/no-service.png"/>
<aside class="notes">
Lousy data service on the ferry. Want to go for a drive out of town? Make sure you pack paper maps. Opportunity?
</aside>
</section>
<section>
<h2>Case Studies</h2>
<aside class="notes">
So that's some background. At the County we're experimenting with solutions to get around this dis-connectivity issue.
</aside>
</section>
<section>
<h2>Case Study 1</h2>
<p>Public Works needs to collect data points from several locations in field</p>
<aside class="notes">
Public Works calls me and asks what to do? They need aerial photos to help orient themselves.
</aside>
</section>
<section>
<h2>Assets</h2>
<ul>
<li>Android phones w GPS</li>
<li>Aerial Imagery TMS (2013)</li>
</ul>
<aside class="notes">
Well, what have we got? Android phones with GPS and a tiled map service of 2013 aerial imagery running on ArcGIS Server.
</aside>
</section>
<section>
<h2>Limitations</h2>
<ul>
<li>No mobile data service</li>
<li>Low storage space</li>
<li>No mobile app dev</li>
</ul>
<aside class="notes">
Locations are remote so no data service and can't use online maps.
Android phones have little storage space, so we can't load the entire 36GB aerial photo set on them.
And I'm not a mobile app developer. I could try, but it would take me a long time.
</aside>
</section>
<section>
<h2>Solution</h2>
<aside class="notes">
So I did some research on possible existing solutions.
</aside>
</section>
<section>
<figure>
<img src="img/geopaparazzi.jpg"/>
<figcaption>
<a href="http://geopaparazzi.github.io/geopaparazzi/">Geopaparazzi</a>
</figcaption>
</figure>
<aside class="notes">
I found the Geopaparazzi Android app.
</aside>
</section>
<section>
<h2>Geopaparazzi</h2>
<ul>
<li>Open Source App</li>
<li>Collect GPS locations and paths</li>
<li>Reads MBTiles</li>
</ul>
<aside class="notes">
It's open source (neat!)
It can collect GPS locations and paths
And it can load tile caches stored locally as an MBTiles database.
</aside>
</section>
<section>
<h2>MBTiles</h2>
<blockquote cite="https://github.com/mapbox/mbtiles-spec">
MBTiles is a specification for storing tiled map data in SQLite databases for immediate usage and for transfer.
</blockquote>
<a href="https://github.com/mapbox/mbtiles-spec">Details</a>
<aside class="notes">
MBTiles was created by Mapbox for storing tiled maps.
</aside>
</section>
<section>
<h2>.mapurl files</h2>
<pre class="stretch"><code class="ini" data-trim>
url=http://tile.openstreetmap.org/ZZZ/XXX/YYY.png
minzoom=0
maxzoom=19
center=11.42 46.8
type=google
format=png
defaultzoom=13
mbtiles=defaulttiles/_mapnik.mbtiles
description=Mapnik - Openstreetmap Slippy Map Tileserver
</code></pre>
<a href="https://github.com/geopaparazzi/geopaparazzi/wiki/.mapurl-parameters">parameter details</a>
<aside class="notes">
Geopaparazzi uses parameters in .mapurl files to pull in data. The .mapurl files go into the device's storage/maps directory.
url parameter - URL to TMS with ZZZ XXX and YYY standing in for zoom level, tile column and tile row, respectively.
minzoom, maxzoom - sets the zoom levels
center - sets the longitude and latitude to open to
defaultzoom - the zoom level the map defaults to on open
mbtiles - this is the subdirectory/filename in the device's storage/maps directory where the tiles are cached
</aside>
</section>
<section>
<h3>Tiled ArcGIS Service example</h3>
<pre class="stretch"><code class="ini" data-trim>
url=http://sjcgis.org/arcgis/rest/services/Basemaps/Aerials_2013_WM/MapServer/tile/ZZZ/YYY/XXX
minzoom=10
maxzoom=19
center=-123.0 48.5
type=google
bounds=-123.395004 48.354880 -122.417221 48.749851
format=jpg
defaultzoom=13
mbtiles=defaulttiles/_sjc-aerial2013.mbtiles
description=San Juan County WA Aerials 2013
</code></pre>
<aside class="notes">
Esri flips the X and Y in their URLs compared to most other tiled map services.
</aside>
</section>
<section>
<h2>Workflow</h2>
<h3>Before leaving office...</h3>
<ol>
<li>Add .mapurl file to device</li>
<li>Open Geopaparazzi and load .mapurl source</li>
<li>Pan to location(s) for field work</li>
<li>Zoom to all levels in location(s)</li>
<li>Tiles are saved on device for offline use</li>
</ol>
<aside class="notes">
Can verify tiles exist by going into airplane mode before leaving office. After collecting points in the field, staff comes back to the office and exports collected points and paths to GPX.
</aside>
</section>
<section>
<h2>Advantages</h2>
<ul>
<li>Very stable app</li>
<li>Small storage footprint</li>
<li>Fairly easy setup</li>
</ul>
</section>
<section>
<h2>Disadvantages</h2>
<ul>
<li>TMS must be Slippy Map specs (Web Mercator)</li>
<li>Pre-cache all locations</li>
<li>Limited to single visible tile source (<a href="https://github.com/geopaparazzi/geopaparazzi/issues/286">issue 286</a>)</li>
</ul>
<aside class="notes">
Tiled map service must be cached as web mercator and use the Slippy Map zoom levels.
Only pre-cached locations are available. Can't change your mind once in the field, unless you find mobile data connectivity (4G, etc.).
You can also only display one tile source at a time in Geoopaparazzi.
I'd love to have two, so I could display a separate reference overlay on top of aerials. Could burn in, but increases time to cache entire dataset by tens of hours per month.
</aside>
</section>
<section>
<h2>Case Study 2</h2>
<p>Appraisers from Assessor's Office getting lost in field</p>
<aside class="notes">
Appraisers collecting data in field need help finding addresses, driveways in remote locations
</aside>
</section>
<section>
<h2>Assets</h2>
<ul>
<li>iPad Air w GPS & 64GB</li>
<li>Aerial Imagery TMS</li>
<li>Reference Overlay TMS</li>
</ul>
<aside class="notes">
The iPads will run the field assessment software, but they don't have offline maps.
As stated, we have an aerial imagery TMS which is static and doesn't need recaching.
And we have a reference overlay TMS which is updated and recached often.
</aside>
</section>
<section>
<h2>Limitations</h2>
<ul>
<li>No mobile data service</li>
<li>No mobile app dev</li>
</ul>
<aside class="notes">
Again, we have no mobile data service while in field. And we don't have a iOS developer on staff.
</aside>
</section>
<section>
<h2>Solution</h2>
<aside class="notes">
So I did more research and came up with another solution.
</aside>
</section>
<section>
<img src="img/mbtiles-gps.png"/><br/>
<a href="https://itunes.apple.com/us/app/mbtiles-gps/id592703465?mt=8">MBTiles GPS</a>
<aside class="notes">
MBTiles GPS App on iTunes is free. And it can display from more than one tile source at the same time.
</aside>
</section>
<section>
<img src="img/pbs-logo.png"/><br/>
<a href="https://geopbs.codeplex.com/">Portable Basemap Server</a>
<aside class="notes">
Since we have more storage space, why not put the entire tile set on there? I found Portable Basemap Server (Windows only) which can convert from an ArcGIS Server tile cache to MBTiles. This requires admin access to the server hosting the ArcGIS service.
</aside>
</section>
<section>
<h3>But I don't have admin access</h3>
</section>
<section>
<pre class="stretch"><code class="JavaScript" data-trim>
var tilelive = require("tilelive");
require("tilelive-http")(tilelive);
require("mbtiles").registerProtocols(tilelive);
var template = "http://tile.openstreetmap.org/{z}/{x}/{y}.png";
var scheme = tilelive.Scheme.create("scanline", {
minzoom: 12,
maxzoom: 15,
bbox: [-122.578926,47.509548,-122.051926,47.684575]
});
var copyTask = new tilelive.CopyTask(template, "mbtiles://./osm-sea.mbtiles", scheme);
copyTask.formats = ["tile"];
copyTask.start(function(err) {
if (err) {
throw err;
}
});
copyTask.on("progress", console.log);
copyTask.on("finished", function() {
console.log("Done!");
});
</code></pre>
<a href="https://github.com/mojodna/tilelive-http">tilelive-http</a>
<aside class="notes">
CUGOS member Seth Fitzsimmons wrote tilelive-http which has a great example which may work. Just remember... [next]
</aside>
</section>
<section>
<h1><em>DON'T</em></h1>
<h1><em>BE</em></h1>
<h1><em>EVIL</em></h1>
</section>
<section>
<h3>Adhere to usage restrictions and licenses</h3>
<aside class="notes">
Some aerial imagery or basemaps are protected by copyright or other restrictions. Do your homework and make sure you aren't violating those.
</aside>
</section>
<section>
<h3>Limit your bbox and levels</h3>
<pre class="stretch"><code class="JavaScript" data-trim>
/* DON'T DO THIS */
var scheme = tilelive.Scheme.create("scanline", {
minzoom: 0,
maxzoom: 19,
bbox: [-180,-90,180,90]
});
var copyTask = new tilelive.CopyTask(template, "mbtiles://./all-the-things.mbtiles", scheme);
copyTask.formats = ["tile"];
copyTask.start(function(err) {
if (err) {
throw err;
}
});
copyTask.on("progress", console.log);
copyTask.on("finished", function() {
console.log("I've taken over the world!");
});
</code></pre>
<aside class="notes">
Don't get greedy. Limit the bbox and levels only to what you need. Otherwise you're hammering servers and will quickly run into usage limits or IP bans. The example above would download about 54TB.
</aside>
</section>
<section>
<h2>MBTiles GPS</h2>
<img src="img/mbtiles-gps-screenshot.jpg"/>
<aside class="notes">
Here's what it looks like after the MBTiles databases have been created and loaded into the MBTiles app. Since we've generated this countywide, there is no need to do the same prep work as needed with the Android solution. Both the aerial background and the reference overlay can be seen here.
</aside>
</section>
<section>
<h2>Advantages</h2>
<ul>
<li>Countywide offline tiles</li>
<li>Multiple tile sources visible</li>
<li>No prep work</li>
</ul>
</section>
<section>
<h2>Disadvantages</h2>
<ul>
<li>TMS must be Slippy Map specs</li>
<li>Unstable app</li>
<li>Moderately difficult setup</li>
</ul>
</section>
<section>
<h2>Questions?</h2>
<ul>
<li><a href="http://npeihl.com/offline-maps-presentation">npeihl.com/offline-maps-presentation</a></li>
<li>Website: <a href="http://www.npeihl.com/">npeihl.com</a></li>
<li>Twitter: <a href="http://twitter.com/npeihl">@npeihl</a></li>
<li>Email: <a href="mailto:nickpeihl@gmail.com">nickpeihl@gmail.com</a></li>
</ul>
</section>
</div>
</div>
<script src="lib/js/head.min.js"></script>
<script src="js/reveal.js"></script>
<script>
// Full list of configuration options available at:
// https://github.com/hakimel/reveal.js#configuration
Reveal.initialize({
controls: true,
progress: true,
history: false,
center: true,
transition: 'none', // none/fade/slide/convex/concave/zoom
// Optional reveal.js plugins
dependencies: [
{ src: 'lib/js/classList.js', condition: function() { return !document.body.classList; } },
{ src: 'plugin/markdown/marked.js', condition: function() { return !!document.querySelector( '[data-markdown]' ); } },
{ src: 'plugin/markdown/markdown.js', condition: function() { return !!document.querySelector( '[data-markdown]' ); } },
{ src: 'plugin/highlight/highlight.js', async: true, condition: function() { return !!document.querySelector( 'pre code' ); }, callback: function() { hljs.initHighlightingOnLoad(); } },
{ src: 'plugin/zoom-js/zoom.js', async: true },
{ src: 'plugin/notes/notes.js', async: true }
]
});
</script>
</body>
</html>