😄

maplibre-glで自前のControlを追加する

に公開

maplibre-glで以下のようなコードでaddControl()すると右上にズームや現在位置取得ボタンが追加されます。

import maplibregl from "maplibre-gl";

const setUiStyle = (map: maplibregl.Map) => {
  // コントロール関係表示
  map.addControl(new maplibregl.NavigationControl());
  // ユーザーの現在地を取得するコントロールを追加
  map.addControl(
    new maplibregl.GeolocateControl({
      positionOptions: {
        enableHighAccuracy: true,
      },
      trackUserLocation: true,
    })
  );
}


自前のボタンを追加する方法に少し悩んだのでそのメモです。

自前のボタンを追加する方法

以下のようなコードでいけました(@mdi/jsは別途npm installして下さい)

import maplibregl from "maplibre-gl";
import { mdiHome } from "@mdi/js";

const getSvgIcon = (title: string, path: string) =>
  `<button>
    <svg viewBox="0 0 24 24">
      <title>${title}</title>
      <path d="${path}"></path>
     </svg>
   </button>`;

class ResetViewControl implements maplibregl.IControl {
  onAdd(map: maplibregl.Map) {
    const div = document.createElement("div");
    div.className = "maplibregl-ctrl maplibregl-ctrl-group";
    div.innerHTML = getSvgIcon("視点リセット", mdiHome);
    div.addEventListener("contextmenu", (e) => e.preventDefault());
    div.addEventListener("click", () => map.flyTo({ bearing:0 , zoom: 10 }));

    return div;
  }
  onRemove(): void {}
}

const setUiStyle = (map: maplibregl.Map) => {
  // 視点リセットボタンを追加
  map.addControl(new ResetViewControl(), "top-right");
}

グルーピングされたボタンを追加する方法

onAdd()の中で親divに子のdivを追加する形でいけます。

import maplibregl from "maplibre-gl";
import { mdiVideo2d, mdiVideo3d } from "@mdi/js";

const getSvgIcon = (title: string, path: string) =>
  `<button>
    <svg viewBox="0 0 24 24">
      <title>${title}</title>
      <path d="${path}"></path>
     </svg>
   </button>`;

class ChangeViewControl implements maplibregl.IControl {
  onAdd(map: maplibregl.Map) {
    const container = document.createElement("div");
    container.className = "maplibregl-ctrl maplibregl-ctrl-group";

    const parallelView = document.createElement("div");
    parallelView.innerHTML = getSvgIcon("2D視点(平行投影)", mdiVideo2d);
    parallelView.addEventListener("contextmenu", (e) => e.preventDefault());
    parallelView.addEventListener("click", () => map.easeTo({ pitch: 0 }));
    container.appendChild(parallelView);

    const perspectiveView = document.createElement("div");
    perspectiveView.innerHTML = getSvgIcon("3D視点(透視投影)", mdiVideo3d);
    perspectiveView.addEventListener("contextmenu", (e) => e.preventDefault());
    perspectiveView.addEventListener("click", () => map.easeTo({ pitch: 60 }));
    container.appendChild(perspectiveView);

    return container;
  }
  onRemove(): void {}
}

const setUiStyle = (map: maplibregl.Map) => {
  // 2D視点ボタン/3D視点ボタンを追加
  map.addControl(new ChangeViewControl(), "top-right");
}

ボタンはaddControl() した順番で上から配置されていきます。

参考記事

Discussion