$30 off During Our Annual Pro Sale. View Details »

Weiwudi–Serviceworkerframework for map application /weiwudi-2021

Weiwudi–Serviceworkerframework for map application /weiwudi-2021

Weiwudi–Serviceworkerframework for map application
Presentation for PWA Night #32 & FOSS4G Japan 2021

Code for History

October 20, 2021
Tweet

More Decks by Code for History

Other Decks in Technology

Transcript

  1. Weiwudi – Serviceworker framework for map application Kohei Otsuka –

    Code for History 1
  2. Table of contents • What is Code for History? •

    Introduction to PWA • Introduction to web map technology • Introduction to Weiwudi • Coming soon • Future issues / improvements 2 日本語 / English
  3. Code for Historyとは? 3

  4. IT技術を歴史学の問題解決に用いるコミュニ ティ https://code4history.dev/ 4

  5. 特徴 • 強調したいのは、我々にとってIT技術は「手段」であって目的ではな い • 「目的」は歴史学の課題を解決することで、必要であれば非IT的手段 を使うことも辞さない • 最優先するのは常に問題を解決すること 5

  6. PWAの紹介 (Progressive Web App) 6

  7. 7 PWAとは? • “Progressive web app”の略 • オフラインで動作 • プッシュ通知

    • ホーム画面に登録可能 • アプリストアへの登録不要 • ネイティブアプリ的なUI/UX 参考: https://www.slideshare.net/i_Pride/pwa-125881791
  8. 8 PWAとは? • “progressive web app”の略 • オフラインで動作 • ブラウザの背後で“service

    worker”というプロセスが走る • Service workerはページの開始前に必要なファイルを取得しキャッシュする • Service workerはプロセスからの処理要求に従い、アクセスしたファイルや データをIndexedDBなどにキャッシュする • プッシュ通知 • ホーム画面に登録可能 • アプリストアへの登録不要 • ネイティブアプリ的なUI/UX
  9. 9 PWA構成 Serviceworker Web IndexedDBなど Webサーバ リクエスト リクエスト キャッシュ キャッシュされたリソース

    はオフラインで利用可能
  10. Web地図技術の紹介 10

  11. 11 Web地図の投影法 – 球面メルカトル図 法 • Googleが2005年に導出した、世界をWeb地図で表現するための図法 • メルカトル図法の一種で、地球を回転楕円体として扱わず、完全な球とし て扱っているのが特徴

    • Googleは、地球を表現するのにこの図法を使いかつ、人のほとんど住ん でいない緯度85.05度以上を無視すると、地図全体の形が正方形になるこ とに気づいた • メルカトル図法のさらなる利点として、非常に狭い範囲に限定して扱う限 り、地図上の各点での緯度方向/経度方向の縮尺は等しいという特徴を 持っており、全世界的サービスを行うのに便利だった
  12. 12 正方形の地図をタイルとして配信 する仕様 - WMTS • WMTSは、全世界の地図をズームレベルに応じ てタイル状に切り分けて配信する仕様 • ズーム

    0 => 20×20 => 1 タイル • ズーム 1 => 21×21 => 4 タイル • ズーム 20 => 220×220 => 1,099,511,627,776 タイ ル • これらのタイルは次のパラメータにより定義さ れ配信される: {z}, {x} and {y} • 例: https://example.com/{z}/{x}/{y}.png • 一般に、タイル1枚の画像サイズは256ピクセル 四方 (Retinaでは512ピクセルなど) 引用: https://speakerdeck.com/manaboutcouch/ openstreetmap-for-gis-pros
  13. Weiwudiの紹介 13

  14. 14 Web地図をPWA化する際の困難 • PWAを動かすためのhtml、javascriptやcssだけでなく、地図タイ ル画像もキャッシュしなければ、オフラインで動作させることはでき ない • 全世界の兆レベルの地図画像を全部キャッシュするのは当然現実的で はない •

    アプリに必要な範囲、あるいはユーザの望む範囲の地図タイルだけ選 択してキャッシュするには、アプリ作成者は球面メルカトル座標や WMTS仕様を十分に理解し、必要なタイル画像のリストを作成して キャッシュする必要がある
  15. 15 Weiwudi – Web地図タイルを扱うた めのServiceworkerフレームワーク Serviceworker Web 地図API IndexedDB Weiwudi

    地図タイルサーバ • URL変換 • タイル画像を indexedDB に蓄積 タイル画像 タイル画像 タイルリクエスト タイルリクエスト 魏武帝 (Weiwudi)
  16. 16 Weiwudiの使い方 (1): 初期化 • 詳細はこちらの記事にあります: https://qiita.com/kochizufan/items/b2fe0dffd326f79cf6be • WeiwudiはWorkboxを前提として動きます •

    Serviceworker側: • フロントエンドJS: importScripts("https://storage.googleapis.com/workbox-cdn/releases/6.0.2/workbox-sw.js"); importScripts("https://cdn.jsdelivr.net/npm/weiwudi@0.1.4/src/weiwudi_sw.js"); // Weiwudi読み込み import Weiwudi from 'weiwudi'; // Serviceworker登録 try { // Service worker登録 await Weiwudi.registerSW('./sw.js', {scope: './'}); ... } catch(e) { // エラー処理(例 ブラウザがservice worker未対応など) ... }
  17. 17 Weiwudiの使い方 (2): Weiwudiクラスのインスタンス作成 • Weiwudiクラスのインスタンス生成(URLテンプレート登録): // 地図設定をservice workerに登録 //

    WMTSの場合(一般的な例) const map = await Weiwudi.registerMap(‘wmts_map’, { // これは地図ID type: ‘wmts’, // 必須 minLat: 35.0, // 最小緯度, 一括ダウンロードでは必須 maxLat: 35.1, // 最大緯度,一括ダウンロードでは必須 minLng: 135.0, // 最小経度,一括ダウンロードでは必須 maxLng: 135.1, // 最大経度,一括ダウンロードでは必須 minZoom: 17, // 最小ズーム,一括ダウンロードでは必須 maxZoom: 18, // 最大ズーム,一括ダウンロードでは必須 url: ‘https://b.tile.openstreetmap.org/{z}/{x}/{y}.png’ // 必須 }); // 地図APIに登録するURLテンプレートを取得 const map_url = map.url; // https://weiwudi.example.com/api/cache/{map ID}/{z}/{x}/{y} // この“map_url”を地図APIに登録 maxZoom minZoom minLat maxLat maxLng minLng
  18. 18 • 地図タイルの一括ダウンロードを実施: // 全ファイルを取得 map.addEventListener('proceed', (e) => { //

    タイル取得進行中の処理をここに書く }); map.addEventListener('finish', (e) => { // タイル取得完了の処理をここに書く }); map.addEventListener('stop', (e) => { // タイル取得中のエラーによる停止の処理をここに書く }); map.addEventListener('canceled', (e) => { // タイル取得のキャンセル処理をここに書く }); // 取得開始 await map.fetchAll(); Weiwudiの使い方 (3): 地図タイルの一括ダウンロード
  19. 19 • e.parameterの値 • proceed • finish Weiwudiの使い方 (4): 一括ダウンロード中のメッセージオブジェクト

    { type: “proceed”, // イベント種別 message: “Proceeding the tile fetching: wmts_map 80% (800 / 1000)”, // イベントメッセージ percent: 80, // 処理したタイル数の% processed: 800, // 処理したタイルの数 error: 2, // 処理中にネットワークエラーなどの発生した数 total: 1000, // 全部のタイルの数 mapID: “wmts_map” // 処理中の地図ID } { type: "finish", //イベント種別 message: "`Fetched all tiles of wmts_map with 2 error cases", // イベントメッセージ error: 2, // タイル処理中のエラー発生数 total: 1000, // 全部のタイルの数 mapID: "wmts_map" // 処理中の地図ID }
  20. 20 • e.parameterの値 • stop • canceled Weiwudiの使い方 (5): 一括ダウンロード中のメッセージオブジェクト

    { type: "stop", // イベント種別 message: "Fetching stopped: wmts_map 800 / 1000", //イベントメッセージ reason: “...”, // システムからのエラーメッセージ processed: 800, // 処理したタイルの数 total: 1000, // 全部のタイルの数 mapID: "wmts_map" // 処理中の地図ID } { type: "canceled", // イベント種別 message: "Fetching tile of wmts_map is canceled", //イベントメッセージ mapID: "wmts_map" // 処理中の地図ID }
  21. 21 • タイルキャッシュの状況取得 • 状況オブジェクト Weiwudiの使い方 (6): キャッシュの状況取得 // キャッシュ状況取得

    const status = await map.stats(); { count: 0 // キャッシュ中のタイル数 percent: 0 // 全タイル数に対するキャッシュタイルの% size: 0 // キャッシュされているタイルの全容量(バイト) total: 8408 // 全部のタイルの数 }
  22. 22 • fetchAll処理のキャンセル • タイルキャッシュのクリア • 登録している地図設定の削除 Weiwudiの使い方 (7): 他のメソッド

    // fetchAll処理のキャンセル await map.cancel(); // タイルキャッシュのクリア await map.clean(); // 登録している地図設定の削除 await map.remove();
  23. Coming soon 23

  24. 24 • Mbtilesは地図タイルを一括処理するための仕様 • x, y, zをキーとして持つSQLiteの中に全ての地図タイルを格納する • Mbtiles形式のデータは、既存のGIS市場の中で利用されている資産 •

    …しかし主にサーバサイドやモバイルで利用されている • Mbtilesデータを読み込み、画像を展開してindexedDBにWeiwudi 仕様で格納するserviceworkerがあれば普通に便利 • 開発はサブブランチ(sql-wasm)で実施中 Mbtiles (SQLite)を使った一括ダウンロー ド
  25. 25 MbtilesによるWeb地図画像の一括ダウン ロードと展開 Serviceworker Web 地図API IndexedDB Weiwudi 地図タイルサーバ *

    Mbtilesから 画像を展開して indexedDBに 蓄積 Mbtiles Mbtilesリクエスト Mbtiles タイルリクエスト タイル画像
  26. 26 • Mbtilesは地図タイルを一括処理するための仕様 • x, y, zをキーとして持つSQLiteの中に全ての地図タイルを格納する • Mbtiles形式のデータは、既存のGIS市場の中で利用されている資産 •

    …しかし主にサーバサイドやモバイルで利用されている • Mbtilesデータを読み込み、画像を展開してindexedDBにWeiwudi 仕様で格納するserviceworkerがあれば普通に • 開発はサブブランチ(sql-wasm)の中でほぼ完了している(はず) • 全ての地図データをたった1つのファイルでダウンロードできる機能の 存在は、商用の有償地図をPWAに配信するのにとても便利!!! Mbtiles (SQLite)を使った一括ダウンロー ド
  27. 将来の開発/問題 27

  28. 28 • ダウンロードする地図の領域を、一括ダウンロードメソッドの引数として与 えられるようにする • 現在の実装では、地図の設定時にしか領域を定義できない – もっと柔軟な領域指 定が必要 •

    PWAの実装方法をブラッシュアップ • PWA専門家の助けがもっと必要! • ベクタ地図や3D地図への対応が必要 • 最近では、ベクタ地図や3D地図への対応が地図APIのトレンド、そのような仕様 に対応する必要がある • ベクタタイルはラスタタイルと基本的に同じ仕様だが、ベクタ地図はスタイルの 情報がそれに加えて必要 – スタイルの扱い方に詳しくないのでキャッシュの仕方 がわからない • 3Dタイルについては、最近の仕様を把握していない • ベクタ地図/3D地図専門家の助けがもっと必要! 将来の開発 / 問題
  29. End User: kochizufan Github pages: https://code4history.dev/ E-mail: kochizufan@code4history.dev Slide: https://speakerdeck.com/kochizufan/weiwudi-2021

    29
  30. What is Code for History? 30

  31. A community that uses information technology to solve historical problems

    https://code4history.dev/ 31
  32. Characteristics • We want to emphasize that for us, information

    technology is a "means" and not an “objective" • The "objective" is to solve a historical problem, and if necessary, to utilize non-IT means • The first priority is always to solve the problem 32
  33. Introduction to PWA (Progressive Web App) 33

  34. 34 What is PWA? • It is abbreviation of “progressive

    web app” • Working on offline • Push notification • Can be registered on home screen • No need to be registered on App store • UI/UX like native app Refering to https://www.slideshare.net/i_Pride/pwa-125881791
  35. 35 What is PWA? • It is abbreviation of “progressive

    web app” • Working on offline • Another process named “service worker” runs browser’s background • Service worker retrieves and caches files required for operation before starting • Service worker caches files and data accessed during processing in indexedDB or other database according to processing requests • Push notification • Can be registered on home screen • No need to be registered on App store • UI/UX like native app
  36. 36 PWA diagram Serviceworker Web IndexedDB, etc. Web Server Requests

    Requests Cache Cached resources can be used offline
  37. Introduction to web map technology 37

  38. 38 Projection of web maps – Spherical Mercator Projection •

    Google invented a map projection method in 2005 to represent a map of the world on the web • It is a kind of Mercator projection, which is characterized by considering the earth as a perfect sphere rather than a rotating ellipsoid • Google discovered that if they use this projection to map the earth, ignoring latitudes above 85.05, where few people live, the map will be in the shape of a square • As a further advantage, Mercator project are suitable for uniform service around the world because of the property that the latitudinal and longitudinal scales coincide in a very small area
  39. 39 Specification for delivering a square map as tiles -

    WMTS • WMTS is a specification that delivers maps around the world, chopped into tiles according to the zoom level • Zoom 0 => 20×20 => 1 tile • Zoom 1 => 21×21 => 4 tiles • Zoom 20 => 220×220 => 1,099,511,627,776 tiles • Providing these tiles with parameters: {z}, {x} and {y} • E.g.: https://example.com/{z}/{x}/{y}.png • In general, the image size of one tile is 256 pixels square (512 pixels in Retina) Cite from https://speakerdeck.com/manaboutcouch/ openstreetmap-for-gis-pros
  40. Introduction to Weiwudi 40

  41. 41 Difficulties in making Web Map PWA • Not only

    the html, javascript and css to run the PWA, but also the map tile images need to be cached to run the app offline • Caching all of the world's trillion map images is of course impractical • In order to select and cache only the tiles in the range where the app works (or where the user wants to use it), the app author needs to understand the Spherical Mercator coordinates and WMTS specifications, and create and cache a list of necessary tile image URLs
  42. 42 Weiwudi – Serviceworker framework for web map tiles Serviceworker

    Web Map API IndexedDB Weiwudi Map Tile Server • Convert URL • Store tile images to indexedDB Tile images Tile images Tile requests Tile requests 魏武帝 (Weiwudi)
  43. 43 How to use Weiwudi (1): Initialize • All details

    are written in: https://qiita.com/kochizufan/items/b2fe0dffd326f79cf6be • Weiwudi works with Workbox • Serviceworker side: • Frontend JS: importScripts("https://storage.googleapis.com/workbox-cdn/releases/6.0.2/workbox-sw.js"); importScripts("https://cdn.jsdelivr.net/npm/weiwudi@0.1.4/src/weiwudi_sw.js"); // Load Weiwudi import Weiwudi from 'weiwudi'; // Register serviceworker try { // Register service worker await Weiwudi.registerSW('./sw.js', {scope: './'}); ... } catch(e) { // For error cases (E.g. browser doesn't support service worker) ... }
  44. 44 How to use Weiwudi (2): Create Weiwudi class instance

    • Create Weiwudi class instance (Registering URL template): // Register map setting to service worker // WMTS map case (General case) const map = await Weiwudi.registerMap('wmts_map', { // This is map ID type: 'wmts', // Mandatory minLat: 35.0, // Minimum latitude, Mandatory for bulk download maxLat: 35.1, // Maximum latitude, Mandatory for bulk download minLng: 135.0, // Minimum longitude, Mandatory for bulk download maxLng: 135.1, // Maximum longitude, Mandatory for bulk download minZoom: 17, // Minimum zoom, Mandatory for bulk download maxZoom: 18, // Maximum zoom, Mandatory for bulk download url: 'https://b.tile.openstreetmap.org/{z}/{x}/{y}.png' // Mandatory }); // Get url template of cached map const map_url = map.url; // https://weiwudi.example.com/api/cache/{map ID}/{z}/{x}/{y} // Set this "map_url" to map API maxZoom minZoom minLat maxLat maxLng minLng
  45. 45 • Do bulk download of map tiles: // Fetch

    all tiles map.addEventListener('proceed', (e) => { // Write some codes for handling event of proceeding to fetch tiles }); map.addEventListener('finish', (e) => { // Write some codes for handling event of finishing to fetch tiles }); map.addEventListener('stop', (e) => { // Write some codes for handling event of stopping to fetch tiles by some errors }); map.addEventListener('canceled', (e) => { // Write some codes for handling event of cancelling to fetch tiles by user }); // Start fetching await map.fetchAll(); How to use Weiwudi (3): Bulk download map tiles
  46. 46 • Value of e.parameter • proceed • finish How

    to use Weiwudi (4): Message objects during bulk download { type: "proceed", // Type of event message: "Proceeding the tile fetching: wmts_map 80% (800 / 1000)", // Event message percent: 80, // % of processed tiles processed: 800, // Number of processed tiles error: 2, // Number of errors(Network errors, etc.) among processed tiles total: 1000, // Number of total tiles mapID: "wmts_map" // Processing map ID } { type: "finish", // Type of event message: "`Fetched all tiles of wmts_map with 2 error cases", // Event message error: 2, // Number of errors among processed tiles total: 1000, // Number of total tiles mapID: "wmts_map" // Processed map ID }
  47. 47 • Value of e.parameter • stop • canceled How

    to use Weiwudi (5): Message objects during bulk download { type: "stop", // Type of event message: "Fetching stopped: wmts_map 800 / 1000", // Event message reason: "...", // Error message from system processed: 800, // Number of processed tiles total: 1000, // Number of total tiles mapID: "wmts_map" // Processed map ID } { type: "canceled", // Type of event message: "Fetching tile of wmts_map is canceled", // Event message mapID: "wmts_map" // Processed map ID }
  48. 48 • Get current status of tile cache • Status

    object How to use Weiwudi (6): Get current status of cache // Get current caching status const status = await map.stats(); { count: 0 // Number of tiles which are cached percent: 0 // % of cached tiles per total tiles size: 0 // Number of tile bytes which are cached total: 8408 // Number of total tiles }
  49. 49 • Cancel fetchAll process • Clear map tile cache

    • Remove registered map setting How to use Weiwudi (7): Other methods // Cancel fetchAll process await map.cancel(); // Clean all cached tile images await map.clean(); // Remove registered map setting await map.remove();
  50. Coming soon 50

  51. 51 • Mbtiles is specification for bulk handling of map

    tiles • Store all map tile images in SQLite format with x, y, z as key • Mbtiles data are legacies in existing GIS market • …but mainly be used in server side & mobile • Serviceworker which loads mbtiles and extracts it to indexedDB in Weiwudi style is useful • Now developing in sub-branch (sql-wasm) Bulk download using Mbtiles (SQLite)
  52. 52 Bulk downloading and extracting web map tiles from mbtiles

    Serviceworker Web Map API IndexedDB Weiwudi Map Tile Server * Extract images from mbtiles and store them to indexedDB Mbtiles Tile images Tile requests Request mbtiles Mbtiles
  53. 53 • Mbtiles is specification for bulk handling of map

    tiles • Store all map tile images in SQLite format with x, y, z as key • Mbtiles data are legacies in existing GIS market • …but mainly be used in server side & mobile • Serviceworker which loads mbtiles and extracts it to indexedDB in Weiwudi style is useful • Development was almost finished in sub-branch (sql-wasm) • Capability of downloading only one file for whole map data is useful for providing commercial (non-free) map to PWA!!! Bulk download using Mbtiles (SQLite)
  54. Future issues / improvements 54

  55. 55 • Adding the ability to specify the download range

    as a method argument • Currently, download range is only set in configuration – more flexible range support is needed • Brushing up PWA implementation • We need PWA experts’ help! • Being ready to vector map / 3D map • Recently, vector and 3D map APIs have been at the cutting-edge, and we need to support such specifications • Vector tiles are the same spec with raster tiles, but vector need style information – I have no idea how to support it • 3D tiles – I’m not sure for recent specification • We need vector / 3D GIS experts’ help! Future issues / improvements
  56. End User: kochizufan Github pages: https://code4history.dev/ E-mail: kochizufan@code4history.dev Slide: https://speakerdeck.com/kochizufan/weiwudi-2021

    56