Skip to content

Add OverlayBand and OverlayStacking for one overlay stacking order - #31

Open
wf9a5m75 wants to merge 1 commit into
developfrom
fix/overlay-stacking-order
Open

wf9a5m75 wants to merge 1 commit into
developfrom
fix/overlay-stacking-order

Conversation

@wf9a5m75

@wf9a5m75 wf9a5m75 commented Nov 8, 2026 •

Copy link
Copy Markdown
Contributor

なぜ

利用者の決定で、すべてのプロバイダ・3 プラットフォームで、オーバーレイを下から次の順に重ねます。

  1. ラスターレイヤー(RasterLayerState)
  2. GroundImage
  3. ポリゴン(ネイティブのポリゴンと、ポリゴンのタイルレイヤーが同じ帯)
  4. サークル
  5. ポリライン
  6. マーカー(ネイティブのマーカーと、マーカーのタイルレイヤーが同じ帯)

追加した順・送り直した順(clearOverlays の後など)・デザイン変更の後に左右されません。帯の中は zIndex、同じ zIndex なら渡された順です。

プロバイダごとに重なり順がばらばらでした(TomTom のラスターがポリゴンを覆う、送り直した GroundImage がポリゴンより上に来る、GL 系でサークルがポリゴンの下になる、など)。

何を変えたか

  • OverlayBand と OverlayStacking を足しました(@_spi(MapConductorDriver)。アプリ向けの公開 API には出ません。api-surface は変化なし)。
    • insertionIndex(for:among:ceiling:): 既存のレイヤーの中で差し込む位置(nil はベースマップのレイヤー)。ceiling は、ラスターを下のオーバーレイより下に落とさずにベースマップのラベルの下に保つためのもの。
    • band(ofStyleLayerId:): MapLibre・Mapbox・MapTiler・Mappls が使うスタイルレイヤー id の帯(接頭辞が共通)。
    • rasterKey(stateId:zIndex:): ラスターの経路に乗るレイヤーの帯(アプリのラスター、マーカータイル、feat/polygon-tiling が入ったときのポリゴンタイル)。
    • globalZIndex(_:): 種類をまたいで 1 つの数で比べる SDK(Google の zIndex、HERE の drawOrder)向けの Int32。帯の間隔は 4096、zIndex は ±2047 に丸めます(1e8 幅では Google が実機でサークルをポリラインの上に描きました)。
  • OverlayStackingTests は 720 通りの追加順をすべて確かめます。前の MapLibre の差し込み方に戻すと 4 件落ちます。

直す前と後(このプラットフォームのプロバイダ)

プロバイダ 直す前 直した後
ArcGIS サークルがポリゴンの下。送り直した GroundImage がラスターの下 帯の順(マーカータイルのみ図形の下=制約)
Google Maps 同じ zIndex で追加の順。送り直した GroundImage がポリゴンを覆う 帯の順(globalZIndex)
HERE 追加の順。ポリラインはポリゴン・ラスターの下。送り直したラスターがポリゴンを覆う 帯の順
Mapbox 追加の順(送り直した GroundImage がポリゴンを覆う)。Standard でラスターが一番上 帯の順
MapKit ラスター・GroundImage がポリゴン類を覆う。同じレベルの中は追加の順 帯の順
MapLibre / Mappls 追加の順(送り直したサークルがポリラインを覆う) 帯の順
MapTiler 追加の順。ラスターがマーカーまで覆う 帯の順
OpenMobileMaps 送り直すと GroundImage がラスターの下に来ることがある。マーカータイルがポリゴンの下 帯の順(ラスター帯の中の zIndex は効かないまま)
TomTom ラスターがマーカー以外を覆う ラスターは図形の下。図形どうしは制約で追加の順のまま
Longdo (変更なし) 変更なし(制約)

SDK の制約で守れないもの

  • Android HERE: ポリラインはポリゴンの下に描かれます(DrawOrderType も試しましたが効果がありませんでした)。
  • iOS TomTom: annotation(ネイティブ図形)に描画順が無く、ポリラインがポリゴン類の下、ポリゴン類(ポリゴン・サークル・GroundImage)どうしは追加の順。
  • ArcGIS(Android / iOS / web 3D): GraphicsOverlay は常に operational layer の上に描かれるので、マーカータイル(operational layer)はポリゴンより下。
  • MapKit JS: GroundImage は図形の上(z-order の手段が無い)。
  • iOS Longdo: 変更なし(SDK に順を決める手段が無い)。
  • Android OpenMobileMaps / iOS OpenMobileMaps: ラスター帯の中の zIndex は効かない(入れ直すと描かれなくなるため既存のレイヤーを動かさない)。
  • Android MapTiler: ベースマップのレイヤー一覧が取れないので、ラスターはラベルの上。
  • Google Maps: 同じ zIndex どうしの順は SDK 任せ。

地図のラベルとの関係(今のまま)

今のままにしています。GL 系(MapLibre・Mapbox・Mappls・MapTiler)はラスターをベースマップの最初のラベルの下、他のオーバーレイはラベルの上です(MapTiler のラスターは、前はすべての上でしたが、他の GL 系に合わせてラベルの下に移りました)。Google はラベルを常にオーバーレイの上に描きます(変更なし)。MapKit だけは変わります: 帯の順を守るために全部を同じレベルに置く必要があり、ラスターと GroundImage が .aboveLabels から .aboveRoads(ラベルの下)へ移りました。ポリゴン・サークル・ポリラインは前からラベルの下です。逆に全部を .aboveLabels にすると、ポリゴン類がラベルの上へ移ります。今回は前者で、利用者の判断で承認済みです。

検証

2026-11-08 に develop(fix/mapview-teardown、fix/geodesic-polygon-fill、fix/clear-followups、refactor/polygon-controller などのマージ後)の上に載せ直してから確かめています。

  • ios-sdk-core の単体テスト 368 件すべて成功(OverlayStackingTests は 720 通りの追加順。前の MapLibre の差し込み方に戻すと 4 件落ちます)。api-surface は変化なし(@_spi)。
  • 10 プロバイダとも、同じブランチの core と組み合わせて api-surface.sh check が通りました(Longdo は develop のまま+stacking の core でビルド)。
  • develop + fix/clear-strategy + この PR 一式を合わせたアプリが実機向けにビルドでき、iPad 実機で MapLibre / MapKit を撮り直しました。普通に追加・逆の順・clearOverlays → 送り直し・デザイン変更 のどれでも、下から ラスター < GroundImage < ポリゴン < サークル < ポリライン < マーカー でした。
  • 載せ直す前に、全プロバイダを直す前・直した後で撮っています(core の PR の表)。

確認できていないもの

  • 載せ直した後に撮り直したのは MapLibre / MapKit のみです。develop で動いたのはポリゴンの densify だけで、レイヤーの差し込みには触れていないため、他は載せ直す前の撮影を有効としています。
  • ios-for-googlemaps の iOS 16/17 のビルドの問題は既存のまま(develop でも同じ)。
  • feat/polygon-tiling(未マージ)のポリゴンタイルは rasterKey(stateId:) でポリゴンの帯に入る用意だけしてあり、実物では確かめていません。

関連 PR(fix/overlay-stacking-order の一式)

マージの順番:

  1. fix/clear-strategy の一式(先に入れる想定。衝突はしないことを git merge-tree で確認済み)
  2. 各プラットフォームの core(android-sdk-core / ios-sdk-core / js-sdk-core)
  3. そのプラットフォームのプロバイダ(core の新しいヘルパーを使うので、core より先に入れるとビルドが通りません)
  • Android MapTiler は fix/maptiler-overlay-restore の上に載せています(同じ削除処理を両方が書き換えたため)。先に restore の PR(Remove style layers and sources by object so they can come back android-for-maptiler#17)を入れてください。
  • web はさらに js-sdk-core の npm 公開と、各 react-for-* の依存の引き上げが前提です(npm 公開はまだしない、という決定なので、web のプロバイダ PR はそれまで保留です)。

Every provider is to stack overlays, bottom to top, as raster layers <
ground images < polygons (and polygon tiles) < circles < polylines <
markers (and marker tiles), whatever order they were added or re-sent
in (after clearOverlays(), after a design change). zIndex orders within
a band; equal keys keep the order they were passed in.

Providers had drifted: GL providers appended each layer on top, so a
circle re-sent after clearOverlays() covered the polyline; Google and
HERE compared raw zIndex across kinds (all 0, so add order decided).

OverlayStacking gives the providers one place to compute it:
- insertionIndex(for:among:ceiling:) - where a layer goes among the
  existing ones (nil entries are basemap layers); ceiling keeps rasters
  under the basemap labels without dropping them below lower overlays.
- band(ofStyleLayerId:) - the band of the style layer ids MapLibre,
  Mapbox, MapTiler and Mappls use (they share the prefixes).
- rasterKey(stateId:zIndex:) - the band of a layer that rides the raster
  path: app rasters, marker tiles (marker-tile-...), and PolygonTiler's
  mc-polygon-tiles (polygon band) once feat/polygon-tiling lands.
- globalZIndex(_:) - one Int32 for SDKs that compare a single number
  across kinds (Google zIndex, HERE drawOrder). Bands are 4096 apart,
  zIndex clamped to +-2047: with 1e8-wide bands Google drew a circle
  over a polyline on the device, as if the values were clamped.

@_spi(MapConductorDriver): driver-only, not in the app-facing API
(api-surface check unchanged).

OverlayStackingTests checks all 720 add orders. Swapping in the old
MapLibre insertion (raster below the labels, ground image below the
first vector overlay, everything else on top) fails four of its tests.
This was referenced Nov 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant