$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

    View Slide

  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

    View Slide

  3. Code for Historyとは?
    3

    View Slide

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

    View Slide

  5. 特徴
    • 強調したいのは、我々にとってIT技術は「手段」であって目的ではな

    • 「目的」は歴史学の課題を解決することで、必要であれば非IT的手段
    を使うことも辞さない
    • 最優先するのは常に問題を解決すること
    5

    View Slide

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

    View Slide

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

    View Slide

  8. 8
    PWAとは?
    • “progressive web app”の略
    • オフラインで動作
    • ブラウザの背後で“service worker”というプロセスが走る
    • Service workerはページの開始前に必要なファイルを取得しキャッシュする
    • Service workerはプロセスからの処理要求に従い、アクセスしたファイルや
    データをIndexedDBなどにキャッシュする
    • プッシュ通知
    • ホーム画面に登録可能
    • アプリストアへの登録不要
    • ネイティブアプリ的なUI/UX

    View Slide

  9. 9
    PWA構成
    Serviceworker
    Web
    IndexedDBなど
    Webサーバ
    リクエスト リクエスト
    キャッシュ
    キャッシュされたリソース
    はオフラインで利用可能

    View Slide

  10. Web地図技術の紹介
    10

    View Slide

  11. 11
    Web地図の投影法 – 球面メルカトル図

    • Googleが2005年に導出した、世界をWeb地図で表現するための図法
    • メルカトル図法の一種で、地球を回転楕円体として扱わず、完全な球とし
    て扱っているのが特徴
    • Googleは、地球を表現するのにこの図法を使いかつ、人のほとんど住ん
    でいない緯度85.05度以上を無視すると、地図全体の形が正方形になるこ
    とに気づいた
    • メルカトル図法のさらなる利点として、非常に狭い範囲に限定して扱う限
    り、地図上の各点での緯度方向/経度方向の縮尺は等しいという特徴を
    持っており、全世界的サービスを行うのに便利だった

    View Slide

  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

    View Slide

  13. Weiwudiの紹介
    13

    View Slide

  14. 14
    Web地図をPWA化する際の困難
    • PWAを動かすためのhtml、javascriptやcssだけでなく、地図タイ
    ル画像もキャッシュしなければ、オフラインで動作させることはでき
    ない
    • 全世界の兆レベルの地図画像を全部キャッシュするのは当然現実的で
    はない
    • アプリに必要な範囲、あるいはユーザの望む範囲の地図タイルだけ選
    択してキャッシュするには、アプリ作成者は球面メルカトル座標や
    WMTS仕様を十分に理解し、必要なタイル画像のリストを作成して
    キャッシュする必要がある

    View Slide

  15. 15
    Weiwudi – Web地図タイルを扱うた
    めのServiceworkerフレームワーク
    Serviceworker
    Web
    地図API
    IndexedDB
    Weiwudi
    地図タイルサーバ
    • URL変換
    • タイル画像を
    indexedDB
    に蓄積
    タイル画像
    タイル画像
    タイルリクエスト タイルリクエスト
    魏武帝 (Weiwudi)

    View Slide

  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/[email protected]/src/weiwudi_sw.js");
    // Weiwudi読み込み
    import Weiwudi from 'weiwudi';
    // Serviceworker登録
    try {
    // Service worker登録
    await Weiwudi.registerSW('./sw.js', {scope: './'});
    ...
    } catch(e) {
    // エラー処理(例 ブラウザがservice worker未対応など)
    ...
    }

    View Slide

  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

    View Slide

  18. 18
    • 地図タイルの一括ダウンロードを実施:
    // 全ファイルを取得
    map.addEventListener('proceed', (e) => {
    // タイル取得進行中の処理をここに書く
    });
    map.addEventListener('finish', (e) => {
    // タイル取得完了の処理をここに書く
    });
    map.addEventListener('stop', (e) => {
    // タイル取得中のエラーによる停止の処理をここに書く
    });
    map.addEventListener('canceled', (e) => {
    // タイル取得のキャンセル処理をここに書く
    });
    // 取得開始
    await map.fetchAll();
    Weiwudiの使い方 (3):
    地図タイルの一括ダウンロード

    View Slide

  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
    }

    View Slide

  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
    }

    View Slide

  21. 21
    • タイルキャッシュの状況取得
    • 状況オブジェクト
    Weiwudiの使い方 (6):
    キャッシュの状況取得
    // キャッシュ状況取得
    const status = await map.stats();
    {
    count: 0 // キャッシュ中のタイル数
    percent: 0 // 全タイル数に対するキャッシュタイルの%
    size: 0 // キャッシュされているタイルの全容量(バイト)
    total: 8408 // 全部のタイルの数
    }

    View Slide

  22. 22
    • fetchAll処理のキャンセル
    • タイルキャッシュのクリア
    • 登録している地図設定の削除
    Weiwudiの使い方 (7):
    他のメソッド
    // fetchAll処理のキャンセル
    await map.cancel();
    // タイルキャッシュのクリア
    await map.clean();
    // 登録している地図設定の削除
    await map.remove();

    View Slide

  23. Coming soon
    23

    View Slide

  24. 24
    • Mbtilesは地図タイルを一括処理するための仕様
    • x, y, zをキーとして持つSQLiteの中に全ての地図タイルを格納する
    • Mbtiles形式のデータは、既存のGIS市場の中で利用されている資産
    • …しかし主にサーバサイドやモバイルで利用されている
    • Mbtilesデータを読み込み、画像を展開してindexedDBにWeiwudi
    仕様で格納するserviceworkerがあれば普通に便利
    • 開発はサブブランチ(sql-wasm)で実施中
    Mbtiles (SQLite)を使った一括ダウンロー

    View Slide

  25. 25
    MbtilesによるWeb地図画像の一括ダウン
    ロードと展開
    Serviceworker
    Web
    地図API
    IndexedDB
    Weiwudi
    地図タイルサーバ
    * Mbtilesから
    画像を展開して
    indexedDBに
    蓄積
    Mbtiles
    Mbtilesリクエスト
    Mbtiles
    タイルリクエスト
    タイル画像

    View Slide

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

    View Slide

  27. 将来の開発/問題
    27

    View Slide

  28. 28
    • ダウンロードする地図の領域を、一括ダウンロードメソッドの引数として与
    えられるようにする
    • 現在の実装では、地図の設定時にしか領域を定義できない – もっと柔軟な領域指
    定が必要
    • PWAの実装方法をブラッシュアップ
    • PWA専門家の助けがもっと必要!
    • ベクタ地図や3D地図への対応が必要
    • 最近では、ベクタ地図や3D地図への対応が地図APIのトレンド、そのような仕様
    に対応する必要がある
    • ベクタタイルはラスタタイルと基本的に同じ仕様だが、ベクタ地図はスタイルの
    情報がそれに加えて必要 – スタイルの扱い方に詳しくないのでキャッシュの仕方
    がわからない
    • 3Dタイルについては、最近の仕様を把握していない
    • ベクタ地図/3D地図専門家の助けがもっと必要!
    将来の開発 / 問題

    View Slide

  29. End
    User: kochizufan
    Github pages: https://code4history.dev/
    E-mail: [email protected]
    Slide: https://speakerdeck.com/kochizufan/weiwudi-2021 29

    View Slide

  30. What is Code for History?
    30

    View Slide

  31. A community that uses information
    technology to solve historical problems
    https://code4history.dev/
    31

    View Slide

  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

    View Slide

  33. Introduction to PWA
    (Progressive Web App)
    33

    View Slide

  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

    View Slide

  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

    View Slide

  36. 36
    PWA diagram
    Serviceworker
    Web
    IndexedDB, etc.
    Web Server
    Requests Requests
    Cache
    Cached resources can
    be used offline

    View Slide

  37. Introduction to web map
    technology
    37

    View Slide

  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

    View Slide

  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

    View Slide

  40. Introduction to Weiwudi
    40

    View Slide

  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

    View Slide

  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)

    View Slide

  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/[email protected]/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)
    ...
    }

    View Slide

  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

    View Slide

  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

    View Slide

  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
    }

    View Slide

  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
    }

    View Slide

  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
    }

    View Slide

  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();

    View Slide

  50. Coming soon
    50

    View Slide

  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)

    View Slide

  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

    View Slide

  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)

    View Slide

  54. Future issues / improvements
    54

    View Slide

  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

    View Slide

  56. End
    User: kochizufan
    Github pages: https://code4history.dev/
    E-mail: [email protected]
    Slide: https://speakerdeck.com/kochizufan/weiwudi-2021 56

    View Slide