Skip to content

Stop the styleReady flip-flop; put raster overlays under the basemap's labels - #18

Merged
wf9a5m75 merged 2 commits into
developfrom
fix/clear-followups
Nov 8, 2026
Merged

wf9a5m75 merged 2 commits into
developfrom
fix/clear-followups

Conversation

@wf9a5m75

@wf9a5m75 wf9a5m75 commented Nov 8, 2026 •

Copy link
Copy Markdown
Contributor

なぜ

何も操作していない地図でも、styleReady が約 0.3 秒ごとに true / false を往復し続けていました。

  • 再同期のたびに、全ソースへの setData と、マーカーレイヤーへの moveLayer が走っていました。
  • moveLayer は位置が変わらなくても style を変更扱いにするので、毎回 styledata が出ます。そのとき直前の setData でソースが読み込み中だと isStyleLoaded() が false になり、styleReady が false に落ちます。
  • 続く idle で true に戻って再同期し、また同じ書き込みをする、の繰り返しでした。6 種類の再同期がどれも書き込んでいたので、1 つ止めただけでは止まりませんでした。

無駄な再描画に加えて、styleReady が false の間に来た削除が待たされる(#17 の GroundImage の件)原因にもなっていました。

何を変えたか

  • bringMarkerLayersToFront: マーカーレイヤーがすでに最上段にあるとき、または前回自分で並べたときから順序が変わっていないときは動かしません。
  • setSourceFeatures(新設): 前回と同じ地物オブジェクトが同じ順で、同じソースへ書かれる場合は setData を飛ばします。デザイン変更で style を差し替えるとソースのオブジェクトが新しくなるので、その場合は必ず書き直します。

ラスターの重なり順(2 つ目の commit)

clear 後に全部を送り直すと、ラスターがポリゴン・ポリライン・サークルより上に描かれていました。ラスターの source が作り直される更新でも同じでした。

  • clear してもポリゴン類のレイヤーは style に残り、ソースが空になるだけです。TomTom だけ、ラスターを style の最上段に積んでいました。
  • 他の GL 系 5 本は以前の「Put raster overlays under the basemap's labels」で、ベースマップの最初のラベル層の下に入れるようになっていて、TomTom はそこから漏れていました。
  • TomTom にも同じ規則を入れました。見た目は他の 5 本とそろいます(他の 5 本で起きていないことはレイヤー順で確かめました)。

検証

  • 単体テスト ResyncWritesNothing.test.mjs を足しました。直す前に落ち、直した後に通ることを確かめています。RasterLayerOrder.test.mjs も足しました。 既存のテストもすべて通っています。

  • Playwright で、何も操作しない状態の 10 秒間の往復回数と再描画回数を数えました。

    往復回数 再描画
    直す前 maplibre 52 / mapbox 44 / mappls 47 / maptiler 50 / tomtom 44 / longdo 26 86〜129 回
    直した後 6 本とも 0 0 回

    送り直した後とデザイン変更の後も往復は 0 回でした。デザイン変更の後にオーバーレイが戻ることも、レイヤー一覧とスクリーンショットで確かめています。

  • api-surface は ok です(private メンバーの追加だけ)。

関連 PR(fix/clear-followups の一式)

それぞれ独立していて、マージの順番の制約はありません(web の変更は js-sdk-core の新しい版を必要としません)。

styleReady flipped between true and false about every 0.3 s on a map
that was doing nothing (26-52 flips in 10 s on the clearOverlays test
page, with the map re-rendering ~100 times in that window). The loop:
a styledata arriving while a GeoJSON source is still loading sets
styleReady to false, the idle that follows sets it back and resyncs
every overlay, and each resync called setData on every source and
moveLayer on the marker layers. moveLayer marks the style changed even
when the layer stays where it was, so another styledata came while the
just-rewritten sources were loading, and so on. Stopping any single
controller's resync did not end it, because they all wrote.

bringMarkerLayersToFront now moves nothing when the marker layers are
already on top (or the order is still the one it last produced), and
the layers write through setSourceFeatures, which skips setData when
the features are the same objects as the last write to that same
source. Renderers build a new feature for every change, so identity
means "unchanged"; a style swap creates new source objects, so a lost
source is always written again and design changes still restore the
overlays.

ResyncWritesNothing.test.mjs pins both, plus "a resync with nothing to
do touches nothing" and "after a style swap it rebuilds".
…ders do

After clearOverlays() and sending the same overlays again, the raster
was drawn over the polygons. clearOverlays() leaves the polygon,
polyline and circle layers in the style with empty sources, and this
renderer appended a new raster layer at the top of the style, so the
raster now came after them. The same happened on any update that
replaced the raster's source object (remove + add), which a re-render
does.

maplibre, mapbox, mappls, maptiler and longdo got "insert below the
style's first label layer" in "Put raster overlays under the basemap's
labels"; TomTom was left out. This brings the same rule here, which
also puts the raster under the basemap's labels as on the others.

RasterLayerOrder.test.mjs covers the add-after-clear and the
source-replacement cases. The API snapshot gains the private member.
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