Malcolm Meyer
GIS Specialist | City of Zanesville
Notes: I have been at the City of Zanesville for about a year, before that I had a host of other GIS positions and have been in the GIS field for almost ten years. Also, I am not a developer, but I do play one at work.
Your GIS origin story in two minutes or less...
Notes: I graduated from the College of Wooster with a degree in Sociology and Urban Planning, and after several years in AmeriCorps I decided to go back to school to get my master's degree in International Affairs. I took several geography courses in graduate school at Ohio University, and that is where I got interested in GIS.
Set of components to allow a website to behave more like a native application
Notes: there are many examples of PWAs in the wild and we will look at some of those later, but it is important to note that as with all web technologies, browser support is varied and the tools to work with PWAs are rapidly changing.
Native App Behaviors
Custom App Colors
Caching & Offline Support
*Push Notifications
Notes: We will not cover push notifications in this presentation, as that requires a separate server or service. There is a wealth of information online if you are interested in going further with PWAs.
Android
Chrome
Chromebooks
iOS
Windows Store
<iframe src="https://www.pwastats.com" width="100%" height="500px"></iframe>
Notes: PWA Stats highlights some popular PWAs. Before we get into building our own PWA, let's look at how the Chrome Dev Tools can be used to test out PWA functionality using the website petlove.com.br.
- Cached Assets for Landing Pages & Map UI
- Offline Maps for Field Use - No App Required
- User Convenience - App Drawer/Homescreen
Notes: So why would we want to bring this PWA functionality to web maps? First, it can give us more control over the caching of static assets like css and javascript in our maps or map portals. Also it can allow us to create installable applications without the user needing to download a separate app. Now let's look at how the sample PWA map I built for this workshop looks and take a look at the install process.
https://pwa-trails.netlify.com
<iframe src="https://pwa-trails.netlify.com" width="100%" height="400px"></iframe>Notes: This is a very basic web map, showing the various trails in one of the Franklin County MetroParks. What's different about this map is that it is a fully functional Progressive Web App. It can be installed on any device and used completely offline. The park already has paper maps, but of course a paper map does not give you the ability to show your GPS position while you're hiking the trails. Also, this area has very bad cell service, so having a map that can work offline is very important. I was actually a park ranger here for a short time, and in those two years we did have someone get lost on the trail. If they would have had a map such as this, it might have been easier for them to find a way out on their own. Now let's look at the install process for this app.
Notes: This is how the install process looks on an Android device. To get the install prompt on other devices you will have to write some additional JavaScript code.
Notes: Here you can see the app is actually listed in the app drawer in addition to the homescreen. This can make it a lot easier for users to get to your application.
Notes: This is how you would go about installing this app in windows from Chrome.
Notes: Here you can see that, as outlined in red, the app is completely offline, but is still usable.
Notes: And here is the app as it looks launched from the windows desktop as a standalone PWA.
Notes: https://www.smashingmagazine.com/2016/02/making-a-service-worker/
/*
https://github.com/reyemtm/pwa-maps/archive/master.zip
*/
/*
unzip and then open this folder in with VS Code
CTRL + '`' to open the terminal
*/
npm install
npm run build
npm start
Notes: First we need to download the GitHub repository for this project. Then we will install the dependencies. Finally we will build the very basic web map and run it through a PWA audit to see how it fares. The app will be located in the 'public' folder. Now when your app launched, if it did not launch in Chrome, please copy the url and open that url in Chrome. You should have a map that looks like this - next slide.
Notes: We have a basic web map. This map is using Mapbox GL JS as the mapping API, and we are not going to go into depth in learning this API. The documentation online is very good and can get you started with mapping using Mapbox GL JS. So now that we have a working map, let's run it through the same PWA audit that we ran the petlove site through. When we run the map through the PWA audit, while we do get some positive results, it is missing the key features of a PWA: the manifest.json and service worker.
//CTRL + SHIFT + i then Audit Tab
- Progressive Web App Audit in Chrome
- Check 'Offline' in the Applcation Tab
Notes: So again we are going to do the PWA Audit in Chrome as well as test the offline capability.
- No manifest
- No service worker
- App does not work offline
- manifest.json
- service-worker.js
- *Mobile First Design
- *Progressive Enhancement
Notes: From the results of the audit we see that we need to add a manifest.json file and the service worker. These, along with a mobile first design and progressive enhancement, are the keys to a PWA. Since our application is a simple web map, we do not need to worry too much about the second two aspects here. We will focus on getting the core functionality of the PWA working.
/* https://tomitm.github.io/appmanifest/ */
{
"name": "Clear Creek Trail Map",
"short_name": "CC Maps",
"scope": "/",
"start_url": "/",
"icons": [
{
"src": "/img/trails512.png",
"type": "image/png",
"sizes": "512x512"
}
],
"background_color": "#d8e8c8",
"theme_color": "#d8e8c8",
"display": "standalone"
}
Notes: Create a manifest.json file in your public folder, and give it a name, short name and colors. If you want to look for a new icon you can, and you can use the above link to take a 512x512 image and make all the appropriate sizes for your PWA. Let's take a short break while you create this file. You can create the entire file using the url if you prefer. Just remember to copy all the assets to you public folder.
- Passes manifest tests
- No service-worker
- No offline support
...intercept and handle network requests, including programmatically managing a cache of responses.
/*
Create an empty sw.js file in the root of 'public'.
In your index.html you will already see the following
code in the head of the document.
*/
<!--register the service worker-->
<script>
if ('serviceWorker' in navigator) {
navigator.serviceWorker
.register('/sw.js')
.then(function () {
console.log("Service Worker Registered");
});
}
</script>
- Installable
- PWA optimized
- Still no offline support
- No service worker caching
https://css-tricks.com/serviceworker-for-offline/
npm run cache
/*
this will simply copy a prepared sw.js file to the public folder
*/
/* the cache is added after the install event */
6 self.addEventListener("install", function(event) {
/* requests are fulfilled with the cache, then the network */
38 self.addEventListener("fetch", function(event) {
/* when a new sw.js is activated the cache is refreshed */
141 self.addEventListener("activate", function(event) {
Notes: take a look at the service worker file and go through the various functions
- Installable
- PWA optimized
- Offline support
- But that's not much of a map...
- And that's a lot of code
Automate the creation of the service worker
npm install workbox-cli # this is already installed
Commands
npm run workbox-wizard # workbox wizard
npm run workbox-cache # workbox generateSW workbox-config.js
/*
you could use the native cli commands if installed globally
*/
Notes: I just added some simple node scripts to run the workbox-cli without needing to install it globally. Workbox replaces the now deprecated sw-precache tool, also by Google. Now we can examine this new sw.js file. All the event logic is taken by an separate Google script. The sw.js file simply lists the cached assets.
- Use raw vector tile files
- Use GeoJSON for any additional map layers
- Download a prepared OpenMapTiles extract
- Create a GeoJSON to clip the extract
- Install the mbtiles-extracts Node JS Package
- Edit it to allow for not passing in a property name
- Unpack raw vector tiles from mbtiles
- Result is hundreds of small files which must be cached
Cleveland Metro Area - 17 MB
Cuyahoga County - 6 MB
City of Columbus - 7.5 MB
OVRDC Region (12 Counties) - 16 MB
Notes: Is anyone familiar with vector tiles? OpenMapTiles provides tools to build custom extracts of OpenStreetMap and pre-built area extracts
npm run copy
/*
this will copy the OpenMapTiles data, the basemap style and the trails GeoJSON data to the public folder
*/
Replace the blank style with "bright.json"
var map = new mapboxgl.Map({
container: "map",
style: "bright.json",
hash: true,
center: [-82.58844, 39.5933],
zoom: 6
});
/* This will change your basemap, but will not add the trails layer. If we have time we will do that manually, otherwise you can work on this on your own.*/
Delete the .netlify
folder!!
npm run deploy
/*
login
choose the public folder when asked
*/
Once your site is live, replace http://127.0.0.1
in your bright.json file with the secure url of your new site
npm run workbox-cache
npm run deploy