Skip to content
niryuu edited this page May 25, 2026 · 1 revision

アーキテクチャ

embed の全体構造と初期化フロー、グローバル状態、状態フラグの一覧。

二系統の利用方法

A. HTML 宣言的利用 (embed.js)

<div class="geolonia" data-lat="35.68" data-lng="139.76" data-zoom="14"></div>
<script src="https://cdn.geolonia.com/embed?geolonia-api-key=YOUR-API-KEY"></script>
  • embed.js<script> で読み込むと自動的に .geolonia 要素を走査して GeoloniaMap を生成
  • window.geolonia がグローバルに設定される (window.maplibregl / window.mapboxgl も同一参照)
  • プラグインシステム (registerPlugin) で全マップに介入可能

B. プログラム的利用 (embed-core.js)

import { GeoloniaMap, keyring } from '@geolonia/embed/core';

const map = new GeoloniaMap({
  container: '#map',
  center: [139.76, 35.68],
  zoom: 14,
});
  • React wrapper 等で利用
  • 自動 DOM 走査・グローバル登録は行わない
  • pmtiles プロトコル登録のみ自動

詳細は Module-Embed-EntryCore-vs-Wrapper

初期化フロー (embed.js 経由の場合)

[1] <script src=".../embed.js"> ロード
       ↓
[2] embed.ts のトップレベルコード実行 (src/embed.ts:38-49)
       - window.geolonia / window.maplibregl / window.mapboxgl 設定
       - renderGeoloniaMap() 呼び出し
       ↓
[3] renderGeoloniaMap (src/lib/render.ts:12-114)
       ├─ pmtiles プロトコル登録
       ├─ checkPermission() iframe チェック
       │    └─ NG → console.error → 終了
       ├─ keyring.parse() (script tag から API key 抽出)
       ├─ DOMContentLoaded リスナー登録
       ├─ IntersectionObserver 構築
       ├─ document.querySelectorAll('.geolonia[data-lazy-loading="off"]')
       │    └─ 各要素を renderSingleMap() で即時 render
       └─ document.querySelectorAll('.geolonia:not([data-lazy-loading="off"])')
            └─ 各要素を IntersectionObserver で監視 → 可視化時に renderSingleMap()
       ↓
[4] renderSingleMap(target) (render.ts:27-54)
       ├─ new GeoloniaMap(target)
       ├─ map.on('remove') → isRemoved フラグ立てる
       ├─ MutationObserver で target 削除を監視 → map.remove()
       ├─ parseAtts(target) → atts
       ├─ DOMContentLoaded 済 ? plugins 即実行 : alreadyRenderedMaps にキュー
       ↓
[5] new GeoloniaMap(container) (geolonia-map.ts:71-369)
       ├─ getContainer() で HTMLElement 解決
       ├─ container.geoloniaMap があれば return (重複防止)
       ├─ clientHeight=0 警告
       ├─ parseAtts(container, { interactive }) → atts
       ├─ getOptions(container, params, atts) → options
       ├─ container.innerHTML をスナップショット → 空に
       ├─ loader spinner 追加 (atts.loader !== 'off')
       ├─ sessionId 取得、sourcesUrl 構築
       ├─ options.transformRequest を override (URL 書き換え)
       ├─ super(options) で maplibre.Map 初期化 (失敗時 handleErrorMode)
       ├─ __styleExtensionLoadRequired = true
       ├─ コントロール追加 (順序固定):
       │    1. GeoloniaControl
       │    2. CustomAttributionControl
       │    3. FullscreenControl  (条件付き)
       │    4. NavigationControl  (条件付き)
       │    5. GeolocateControl   (条件付き)
       │    6. ScaleControl       (条件付き)
       ├─ map.on('load') → loader 削除、GestureHandling、marker/popup
       ├─ map.on('styledata') → SimpleStyleVector / SimpleStyle / 3D layer 切替
       ├─ map.on('error') → 402 ステータスで handleRestrictedMode
       ├─ container.geoloniaMap = map (シングルトン)
       └─ return map
       ↓
[6] DOMContentLoaded (もしまだ後ならここで)
       ├─ isDOMContentLoaded = true
       └─ alreadyRenderedMaps から各 plugin を実行

各ステップの詳細は対応する 各 Module-* ページ を参照。

モジュール依存関係

embed.ts
  ├─ maplibre-gl
  ├─ lib/geolonia-map (default)
  ├─ lib/geolonia-marker (default)
  ├─ lib/simplestyle ({SimpleStyle})
  ├─ lib/render ({registerPlugin, renderGeoloniaMap})
  ├─ version ({VERSION})
  └─ types ({EmbedAttributes, EmbedPlugin})

embed-core.ts
  ├─ maplibre-gl
  ├─ pmtiles ({Protocol})
  ├─ lib/geolonia-map (default)
  ├─ lib/geolonia-marker (default)
  ├─ lib/simplestyle ({SimpleStyle})
  ├─ lib/simplestyle-vector (default)
  ├─ lib/keyring ({keyring})
  ├─ lib/render ({registerPlugin})
  ├─ version ({VERSION})
  └─ types ({EmbedAttributes, EmbedPlugin})

lib/render.ts
  ├─ maplibre-gl
  ├─ maplibre-gl/dist/maplibre-gl.css
  ├─ ../style.css           ← docs/style.css ?
  ├─ ./geolonia-map (default)
  ├─ ./util ({checkPermission})
  ├─ ./parse-atts (default)
  ├─ ./keyring ({keyring})
  └─ pmtiles ({Protocol})

lib/geolonia-map.ts
  ├─ maplibre-gl (Map, controls, types)
  ├─ ./geolonia-marker (default)
  ├─ ./controls/geolonia-control ({GeoloniaControl})
  ├─ ./CustomAttributionControl (default)
  ├─ @geolonia/mbgl-gesture-handling
  ├─ ./parse-atts (default)
  ├─ ./simplestyle ({SimpleStyle})
  ├─ ./simplestyle-vector (default)
  └─ ./util (大量)

lib/util.ts
  ├─ ./keyring ({keyring})
  └─ maplibre-gl (types)

lib/parse-atts.ts
  ├─ ./keyring ({keyring})
  ├─ ./util ({getLang})
  └─ ../types ({EmbedAttributes})

lib/keyring.ts
  (依存なし)

lib/simplestyle.ts
  ├─ maplibre-gl
  ├─ @mapbox/geojson-extent
  ├─ @turf/center
  └─ ./util ({isURL, sanitizeDescription})

lib/simplestyle-vector.ts
  ├─ maplibre-gl
  ├─ @turf/center
  └─ ./util ({sanitizeDescription})

lib/geolonia-marker.ts
  ├─ maplibre-gl
  ├─ tinycolor2
  ├─ ./marker.svg          (svg-inline-loader で文字列化)
  └─ ./util ({handleMarkerOptions})

lib/controls/geolonia-control.ts
  └─ maplibre-gl (types)

lib/CustomAttributionControl.ts
  ├─ ./maplibre-util ({DOM, bindAll})
  └─ maplibre-gl (types)

lib/maplibre-util.ts
  └─ @mapbox/point-geometry

グローバル状態の総まとめ

モジュール global

状態 場所 リセット手段
window.geolonia embed.ts:47 Geolonia (ページリロード)
window.maplibregl 同上 Geolonia (上書き) 同上
window.mapboxgl 同上 Geolonia (上書き) 同上
keyring (singleton) keyring.ts:134 Keyring keyring.reset() (テスト用)
plugins (module-level Array) render.ts:10 Array<EmbedPlugin> なし (push only)
sessionId (module-level) util.ts:337 string なし (キャッシュ)
pmtiles protocol maplibregl.addProtocol('pmtiles', ...) maplibre 内部 なし

動的プロパティ (DOM 要素に付与)

プロパティ 付与先 場所
container.geoloniaMap .geolonia 要素 geolonia-map.ts:366remove()delete
map._geolonia_restricted_mode_handled map インスタンス (動的) util.ts:367-368

Closure state (renderGeoloniaMap 内)

変数 場所
isDOMContentLoaded boolean render.ts:17
alreadyRenderedMaps Array<{map, target, atts}> render.ts:18
isRemoved unique symbol render.ts:19

Instance state (GeoloniaMap)

プロパティ 場所
geoloniaSourcesUrl URL geolonia-map.ts:68, 197
__styleExtensionLoadRequired boolean geolonia-map.ts:69, 198, 294, 297, 393

Instance state (CustomAttributionControl)

CustomAttributionControl.ts:27-39 に 12 個のプライベートフィールド (options, _map, _compact, _container, _shadowContainer, _innerContainer, _compactButton, _editLink, _attribHTML, styleId, styleOwner, printQuery, onMediaPrintChange)。

Instance state (SimpleStyle)

プロパティ 場所
_loadingPromise Promise<unknown> simplestyle.ts:19 (URL 取得時)
callFitBounds boolean simplestyle.ts:20
geojson GeoJSON simplestyle.ts:21
map maplibregl.Map simplestyle.ts:22
options { id, cluster, heatmap, clusterColor, ... } simplestyle.ts:23
_eventHandlers Array<{event, layer, handler}> simplestyle.ts:24

Instance state (SimpleStyleVector)

プロパティ 場所
sourceName string ('vt-geolonia-simple-style' 固定) simplestyle-vector.ts:13, 16
url string simplestyle-vector.ts:15 (constructor 引数)
initialZoomDone boolean (closure内、simplestyle-vector.ts:26) addTo 内 closure

2 つのエントリポイントの責務差

責務 embed.ts embed-core.ts
pmtiles プロトコル登録 renderGeoloniaMap() 内 import 時 (module top-level)
window.geolonia 設定
window.maplibregl / mapboxgl 後方互換
renderGeoloniaMap() 自動実行
公開 export: GeoloniaMap, GeoloniaMarker, SimpleStyle
公開 export: SimpleStyleVector
公開 export: keyring
公開 export: registerPlugin

setStyle() 後の挙動

map.setStyle(newStyle)GeoloniaMap.setStyle() override (geolonia-map.ts:376-398):

  1. style !== null なら parseAtts(this.getContainer()) を再実行 (DOM の最新値取得)
  2. style が文字列なら getStyle(style, atts) で URL 解決
  3. this.__styleExtensionLoadRequired = true で styledata 拡張ロード再起動
  4. super.setStyle.call(this, style, options)
  5. (maplibre 内部で styledata イベント発火)
  6. styledata ハンドラ (geolonia-map.ts:291) が再実行 → SimpleStyle/3D 等を再適用

マップ削除フロー

container 削除 (DOM operation)
   ↓
MutationObserver (parentNode 監視) (render.ts:37-45)
   ├─ removedNodes に target が含まれる ?
   └─ Yes → map.remove() (cf. map[isRemoved] チェック後)

または明示的に
   map.remove()
      ↓
   GeoloniaMap.remove() override (geolonia-map.ts:400-405)
      ├─ container = this.getContainer()
      ├─ super.remove.call(this)
      └─ delete container.geoloniaMap

状態フラグの遷移図

__styleExtensionLoadRequired
  初期: true (constructor)
  styledata 拡張処理開始時: false (再入防止)
  setStyle() 呼び出し時: true (再起動)

isDOMContentLoaded
  初期: false
  DOMContentLoaded 受領時: true (1 回限り)

alreadyRenderedMaps
  Push: DOMContentLoaded 前の renderSingleMap で
  Clear: DOMContentLoaded ハンドラ実行後 (splice(0, length))

isRemoved (Symbol)
  Set: map.on('remove') で map[isRemoved] = true
  Check: MutationObserver と DOMContentLoaded ハンドラで !map[isRemoved] 判定

map._geolonia_restricted_mode_handled
  Set: handleRestrictedMode で true 設定
  再入防止: 既に true なら何もしない

詳細ドキュメント参照

  • 各モジュールの内部: 各 Module-* ページ
  • 全 data-* 属性: Data-Attributes
  • URL 書き換え仕様: URL-Rewrite-Spec
  • ハードコード定数: Constants
  • 未文書化規約: Hidden-Spec
  • 怪しいロジック: Suspicious-Logic
  • embed-core 分離方針: Core-vs-Wrapper

Clone this wiki locally