@@ -437,23 +437,23 @@ Microsoft Copilotは`?q=`が入力欄に入らなくなる回帰が報告され
437437** 線が通るスポットのピンはクラスタにまとめない** (` pathMemberIds ` )。経路を辿っているときに経由地が「N件」の丸へ吸い込まれると、線だけが残って止まる場所が読めなくなるため。GeoJSONソースの` cluster ` は** ソース単位でしか切り替えられない** ので、実装はクラスタ化しない別ソース(` PATH_PIN_SOURCE_ID ` )に分けて載せる形になっている。踏みやすい点が3つ:
438438
439439- ** どの線を描くかの判断は` drawnLines ` (useMemo)1か所** にまとめ、線を描く処理とこの振り分けの両方が読む。別々に書くと「線は出ているのにピンはクラスタに丸められる」食い違いが起きる
440- - ** ピンと「+N」バッジのレイヤー定義は ` addPinLayers ` で2つのソースに同じものを載せる** (見た目が割れないように)。` showClusterLayers ` の表示切り替えと` MAIN_PIN_LAYERS ` (重ね表示との当たり判定)にも新しいレイヤーを足すこと
441- - ** 重なり件数(` stack ` )は分ける前の全スポットで数え、タップは2つのピンレイヤーをまとめて` queryRenderedFeatures ` で拾う** —— ソースを分けたぶん、同じ座標に経路上のピンと普通のピンが並ぶと、片方の集合しか見ない実装では「+N」も一覧も欠ける
440+ - ** ピンと重なり数のバッジのレイヤー定義は ` addPinLayers ` で2つのソースに同じものを載せる** (見た目が割れないように)。` showClusterLayers ` の表示切り替えと` MAIN_PIN_LAYERS ` (重ね表示との当たり判定)にも新しいレイヤーを足すこと
441+ - ** 重なり件数(` stack ` )は分ける前の全スポットで数え、タップは2つのピンレイヤーをまとめて` queryRenderedFeatures ` で拾う** —— ソースを分けたぶん、同じ座標に経路上のピンと普通のピンが並ぶと、片方の集合しか見ない実装ではバッジの数も一覧も欠ける
442442
443443ルート・訪問順の経路・訪問予定リストのような「巡る順に並んだスポット列」は、Google マップの経路検索(Maps URLs の`dir`)にそのまま渡して開ける(`lib/googleMaps.ts`の`buildGoogleMapsRouteUrl`+`components/GoogleMapsRouteLink.tsx`)。**出発地(origin)は現在地**で、スポットは**最後の1件が目的地(destination)、それ以外が経由地(waypoints)**になる。置き場所は地図のルート・経路の詳細モーダル(`MapView`の`routeDetailView`。ルートCSVのルート/訪問順の経路(その日ぶん)/訪問予定リストの経路すべて)と、訪問予定リストの詳細(`VisitPlanListDetailModal`。`/[type]/spots`とスポット詳細の「訪問予定」から開くもの)。**訪問予定リストは訪問済みの経由スポットを外して渡す**(地図の経路と同じ扱い)。詳細は**見出しの上に何の線か(`kindLabel`=「ルート」/「訪問順の経路」/「訪問予定リスト」)を必ず出す** —— 3種を同じ見た目のモーダルで出しているため、種類が分からないと今どれを見ているのか分からなくなる。各地点には**ランク(シリーズ)のバッジ**も出す(`pointBadge`)。バッジは**そのスポットが属する種別のシリーズ設定**で描く —— 経路には別種別のスポットが混じるので、本体の設定を当てると色もラベルもずれる(手元に無いスポットは出さない)。**詳細のスポット名をタップすると、その位置へ`flyTo`したうえでそのスポットの詳細モーダルを開く** —— 一覧から辿ったときに「そこが何なのか」を見に行くまでを1タップで済ませるため。詳細の出し分けはピンのタップと同じで、本体種別のスポット(`spotById`にある)なら通常のモーダル、別種別なら読み取り専用の方を開く。かつては先頭のスポットを出発地にしていたが、今いる場所からそこまでの経路が出ず使い物にならないため現在地に変えた。
444444
445445現在地は` lib/useRouteOrigin.ts ` の` useRouteOrigin ` (スポット詳細の単一スポットへの経路リンクと共通)で取る。** 位置情報の権限が既に許可されているときだけ** ` getCurrentPosition ` する — モーダルを開いただけで権限ダイアログを出さないため。取れなければ` origin ` を付けずに開き、Google マップ側の判断(多くの場合は現在地)に委ねる。
446446
447447Maps URLsの` waypoints ` は9件までのため、それを超える経路は** 並び順のまま等間隔に間引いて** 渡し(最初と最後のスポットは必ず残る=間引きの添字が両端を含むため)、省いた件数をリンクの下に注記する(黙って切り捨てない)。スポット0件のときはリンク自体を出さない(現在地が出発地のため、** 1件だけでも経路になる** )。座標のみを渡し、スポット名は渡さない(名前で検索されて別の場所に解決されるのを防ぐため)。
448448
449- ### 同じ座標に重なったピン(` stack ` と「+N」バッジ )
449+ ### 同じ座標に重なったピン(` stack ` と重なり数のバッジ )
450450
451451スポットのクラスタsourceは` clusterMaxZoom: 16 ` のため、** それより拡大するとクラスタが解け、座標が同じスポットのピンは完全に重なる** 。上のピンしかタップできず、下にスポットがあること自体に気づけない。アニメ聖地のように「同じ自治体を代表点にした行が複数ある」種別で顕在化する。
452452
453453対策は2つで、** 本体・重ね表示の両方に入れてある** (かつては本体だけだったが、重ねた種別のピンも完全に重なれば下のスポットに気づけないのは同じ):
454454
455- - `buildClusterGeoJSON`が**同じ座標のスポット数を`stack`プロパティ**に持たせ(`countStacks`が`stackKey`=小数第6位=約0.1mまで見て集計)、`STACK_BADGE_LAYER_ID`のsymbolレイヤーがピンの右肩に**「+N」(Nは隠れている件数)**を出す 。`showClusterLayers`の表示切り替え対象にも含めること。**レイヤーの定義は`addStackBadgeLayer`1か所**で、本体(`addPinLayers`経由)と重ね表示(`addOverlaySpotLayers`経由)が同じものを使う —— 違うのは重ね表示が半透明(`text-opacity`)であることだけ。重ね表示側では`overlayIds`の`stackBadge`・`overlayPinLayerIds`(タップの優先順位)・`moveOverlayLayersToTop`(最上位の維持)の3つにも足すこと(どれか1つでも漏らすと、バッジだけ出ない・本体のピンの下に潜る・押しても本体側にタップを取られる、のいずれかになる)。**件数はソースを分ける前の全スポットで数える**(上記「ピンの表示と線の表示を分ける」)
456- - ピンと「+N」バッジのクリックでは 、**押されたスポット自身の座標**(`displayedSpotsRef`から`id`で引き当てた元データ)で表示中の全スポットを引き直して同じ地点の分を集め、2件以上なら先頭を開かず**「この地点のスポット」一覧**(`stack` state。`{ ids, overlayTypeKey }`で、`overlayTypeKey`がnullなら本体・そうでなければその重ね表示種別)を出してどれを開くか選ばせる。**描かれているピンから数えてはいけない** —— 拡大率が低いと相方がクラスタに吸われて描かれず、「+N」が出ているのに一覧が開かない (実際に踏んだ)。**地図から返るフィーチャの座標も使えない** —— GeoJSONソースは内部でタイルに変換されるので座標が拡大率に応じて丸められ(低い拡大率では数十m単位)、同じ地点の判定に使うと一致しない(クラスタ表示を無効にして低倍率で見ているときに再発した)。バッジにもクリックを付けるのは、「+N」の文字をピンの右肩にずらして描いていて 、そこを押すとピンの当たり判定から外れることがあるため。選ぶと通常どおり`handleSpotSelect`に流れるため、作成モード中の追加確認にもそのまま繋がる。**重ね表示のピンも同じ流れ**(`handleOverlaySpotSelect`が`overlayDisplayedRef`=種別ごとの描画中スポットで引き直し、選ぶと`openOverlaySpot`=読み取り専用の詳細/作成モードの追加確認へ流れる)。**一覧の行の名前・ランク・カテゴリはそのスポットが属する種別の設定で解決する**(本体の設定で描くと名前が出ない・ランクのラベルがずれる)。**一覧は横幅を`max-w-sm`に留める一方、高さは`max-h-[85vh]`まで使う**(重なりが数十件になる種別があるため、件数が多いときに画面の高さいっぱいまで伸ばし、はみ出す分だけ一覧側をスクロールさせる)
455+ - `buildClusterGeoJSON`が**同じ座標のスポット数を`stack`プロパティ**に持たせ(`countStacks`が`stackKey`=小数第6位=約0.1mまで見て集計)、`STACK_BADGE_LAYER_ID`のsymbolレイヤーがピンの右肩に**重なっている数**(`2`・`3`…)を出す。**隠れている件数(`+N`)ではなく総数**にしてあるのは、ピンが何枚あるのかをそのまま読めるほうが分かりやすいため。**1件のときは出さない**(`stack > 1`のfilter) —— ほとんどのピンに`1`が付くと、重なっている場所を見つけられない 。`showClusterLayers`の表示切り替え対象にも含めること。**レイヤーの定義は`addStackBadgeLayer`1か所**で、本体(`addPinLayers`経由)と重ね表示(`addOverlaySpotLayers`経由)が同じものを使う —— 違うのは重ね表示が半透明(`text-opacity`)であることだけ。重ね表示側では`overlayIds`の`stackBadge`・`overlayPinLayerIds`(タップの優先順位)・`moveOverlayLayersToTop`(最上位の維持)の3つにも足すこと(どれか1つでも漏らすと、バッジだけ出ない・本体のピンの下に潜る・押しても本体側にタップを取られる、のいずれかになる)。**件数はソースを分ける前の全スポットで数える**(上記「ピンの表示と線の表示を分ける」)
456+ - ピンと重なり数のバッジのクリックでは 、**押されたスポット自身の座標**(`displayedSpotsRef`から`id`で引き当てた元データ)で表示中の全スポットを引き直して同じ地点の分を集め、2件以上なら先頭を開かず**「この地点のスポット」一覧**(`stack` state。`{ ids, overlayTypeKey }`で、`overlayTypeKey`がnullなら本体・そうでなければその重ね表示種別)を出してどれを開くか選ばせる。**描かれているピンから数えてはいけない** —— 拡大率が低いと相方がクラスタに吸われて描かれず、バッジが出ているのに一覧が開かない (実際に踏んだ)。**地図から返るフィーチャの座標も使えない** —— GeoJSONソースは内部でタイルに変換されるので座標が拡大率に応じて丸められ(低い拡大率では数十m単位)、同じ地点の判定に使うと一致しない(クラスタ表示を無効にして低倍率で見ているときに再発した)。バッジにもクリックを付けるのは、数字をピンの右肩にずらして描いていて 、そこを押すとピンの当たり判定から外れることがあるため。選ぶと通常どおり`handleSpotSelect`に流れるため、作成モード中の追加確認にもそのまま繋がる。**重ね表示のピンも同じ流れ**(`handleOverlaySpotSelect`が`overlayDisplayedRef`=種別ごとの描画中スポットで引き直し、選ぶと`openOverlaySpot`=読み取り専用の詳細/作成モードの追加確認へ流れる)。**一覧の行の名前・ランク・カテゴリはそのスポットが属する種別の設定で解決する**(本体の設定で描くと名前が出ない・ランクのラベルがずれる)。**一覧は横幅を`max-w-sm`に留める一方、高さは`max-h-[85vh]`まで使う**(重なりが数十件になる種別があるため、件数が多いときに画面の高さいっぱいまで伸ばし、はみ出す分だけ一覧側をスクロールさせる)
457457
458458座標を少しずらして描く案は採らない(位置を偽ることになるため)。
459459
0 commit comments