-
Notifications
You must be signed in to change notification settings - Fork 7
Architecture
niryuu edited this page May 25, 2026
·
1 revision
embed の全体構造と初期化フロー、グローバル状態、状態フラグの一覧。
<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) で全マップに介入可能
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-Entry と Core-vs-Wrapper。
[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
| 状態 | 場所 | 型 | リセット手段 |
|---|---|---|---|
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 内部 | なし |
| プロパティ | 付与先 | 場所 |
|---|---|---|
container.geoloniaMap |
.geolonia 要素 |
geolonia-map.ts:366、remove() で delete
|
map._geolonia_restricted_mode_handled |
map インスタンス (動的) | util.ts:367-368 |
| 変数 | 型 | 場所 |
|---|---|---|
isDOMContentLoaded |
boolean |
render.ts:17 |
alreadyRenderedMaps |
Array<{map, target, atts}> |
render.ts:18 |
isRemoved |
unique symbol |
render.ts:19 |
| プロパティ | 型 | 場所 |
|---|---|---|
geoloniaSourcesUrl |
URL |
geolonia-map.ts:68, 197 |
__styleExtensionLoadRequired |
boolean |
geolonia-map.ts:69, 198, 294, 297, 393 |
CustomAttributionControl.ts:27-39 に 12 個のプライベートフィールド (options, _map, _compact, _container, _shadowContainer, _innerContainer, _compactButton, _editLink, _attribHTML, styleId, styleOwner, printQuery, onMediaPrintChange)。
| プロパティ | 型 | 場所 |
|---|---|---|
_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 |
| プロパティ | 型 | 場所 |
|---|---|---|
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 |
| 責務 | 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 | ✓ | ✓ |
map.setStyle(newStyle) → GeoloniaMap.setStyle() override (geolonia-map.ts:376-398):
-
style !== nullならparseAtts(this.getContainer())を再実行 (DOM の最新値取得) -
styleが文字列ならgetStyle(style, atts)で URL 解決 -
this.__styleExtensionLoadRequired = trueで styledata 拡張ロード再起動 super.setStyle.call(this, style, options)- (maplibre 内部で styledata イベント発火)
- 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