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

GeoloniaMarker — カスタム SVG マーカー

src/lib/geolonia-marker.ts (53 行)。maplibregl.Marker のサブクラスで、Geolonia デフォルトの SVG マーカー (赤色しずく型) を提供する。

公開 API

export default class GeoloniaMarker extends maplibregl.Marker {
  constructor(options?: MarkerOptions, legacyOptions?: MarkerOptions);
}

MarkerOptions は maplibre-gl の標準型 ({ element?, color?, draggable?, offset?, anchor?, ... })。

第 2 引数 legacyOptions の目的

旧 API: new GeoloniaMarker(htmlElement, { color: '...' }) のように第 1 引数に HTMLElement、第 2 引数に options。

新 API: new GeoloniaMarker({ element: htmlElement, color: '...' })

handleMarkerOptions(options, legacyOptions) (util.ts:201-215) で:

  • options が HTMLElement なら { element: options, ...legacyOptions } にマージ
  • options が falsy なら legacyOptions を使う
  • それ以外 options をそのまま使う

(現状のコードベースで legacyOptions を実際に使っている呼び出し箇所は確認した範囲では無いが、API 後方互換のため残されている。)

Constructor (geolonia-marker.ts:14-52)

constructor(options: MarkerOptions = {}, legacyOptions: MarkerOptions = {}) {
  options = handleMarkerOptions(options, legacyOptions);

  if (!options || !options.element) {
    // デフォルト SVG マーカー生成
    const markerElement = document.createElement('div');
    markerElement.className = 'geolonia-default-marker';
    markerElement.innerHTML = markerSVG;

    markerElement.style.margin = '0';
    markerElement.style.padding = '0';
    markerElement.style.width = '26px';
    markerElement.style.height = '34px';

    const markerObj = markerElement.querySelector('svg');
    markerObj.style.width = '100%';
    markerObj.style.height = '100%';

    options.element = markerElement;

    if (options.color) {
      (markerElement.querySelector('.left') as HTMLElement).style.fill = options.color;
      (markerElement.querySelector('.right') as HTMLElement).style.fill =
        tinycolor(options.color).darken().toString();
    } else {
      const defaultColor = '#E4402F';
      (markerElement.querySelector('.left') as HTMLElement).style.fill = defaultColor;
      (markerElement.querySelector('.right') as HTMLElement).style.fill =
        tinycolor(defaultColor).darken().toString();
    }

    options.offset = [0, -15];
  }

  super(options);
  return this;
}

フロー

  1. handleMarkerOptions で options 正規化
  2. options.element が未指定ならデフォルト SVG マーカーを生成:
    • <div class="geolonia-default-marker"> を作る
    • innerHTML = markerSVG (marker.svg を svg-inline-loader で文字列化したもの)
    • inline style で 26×34 px に固定
    • 内部の <svg> 要素を 100% に伸ばす
  3. options.color (data-marker-color から渡る) があれば SVG の .left / .right クラス要素に fill 適用:
    • .left.style.fill = color
    • .right.style.fill = tinycolor(color).darken().toString()
  4. なければ '#E4402F' (デフォルト) を同じロジックで適用
  5. options.offset = [0, -15] (マーカー画像のアンカー位置調整)
  6. super(options) で maplibre.Marker のコンストラクタ呼び出し

SVG ファイル構造の暗黙要件

assets/marker.svg 内に**.left クラスと .right クラスを持つ要素が必須**。これが無いと markerElement.querySelector('.left')null を返し、.style.fill = ... で TypeError。

書き直し時にマーカー SVG を差し替えるなら、この class 構造を維持するか、参照箇所も変更する必要あり。

tinycolor2 の .darken()

引数なしの darken() はデフォルト 10% 暗くする (tinycolor2 のドキュメント参照)。#E4402F → 約 #c52e1e のような色になる。マーカーの右半分を影として表現。

offset の意味

[0, -15] は marker SVG の anchor (デフォルト center) を上方向 -15px ずらす。

  • SVG は 34px 高さなので、中央が y=17、底辺が y=34
  • offset -15 で底辺がアンカーに近くなる
  • 一般的な「先端 (足元) を緯度経度に合わせる」配置

呼び出し箇所

場所 用途
embed.ts:7,40,54 Marker として named/wrapped export
embed-core.ts:15 GeoloniaMarker として export
geolonia-map.ts:14 Marker として import (geolonia-marker.ts の default)
geolonia-map.ts:266,274,284 constructor 内、data-marker="on" 時の marker 生成

geolonia-map.ts:266new Marker({ element: container, offset: offset as PointLike }) は custom marker (DOM 要素を直接渡す) の場合。 geolonia-map.ts:274:284new Marker({ color: atts.markerColor }) がデフォルト SVG マーカー。

CSS class 名

class 場所 用途
geolonia-default-marker marker root div スタイリングフック (現状 CSS 未定義の可能性あり)
geolonia-clickable-marker popup 付き marker geolonia-map.ts:282 でクラス追加

.left / .right は SVG 内部の要素クラス (CSS 用ではなくスクリプトから参照されるためのフック)。

怪しい点

  • デフォルト色 '#E4402F' が hardcoded (geolonia-marker.ts:40)。parse-atts.ts:41 と重複定義
  • SVG 内 .left / .right の query が DOM 構造に強く依存
  • legacyOptions が現状使われていない可能性 (デッドコード?)

書き直し時の指針

  • maps-core (lib) 側に置く
  • マーカー色のデフォルトを共通定数に集約 (parse-atts と統一)
  • SVG 内部の class フックを documented した上で残すか、CSS 変数化するか検討

Clone this wiki locally