いきなり日曜大工

好きなことを好きなだけやる

Leaflet 拡張基礎編 #6 ズームコントロールのカスタマイズ

L.Control.Zoom

L.Control.Zoom は 地図描画時にデフォルトで表示されるズームコントロールです。L.Control のサブクラスとしてあらかじめ提供されています。

デフォルトのズームコントロール(左上)

今回はこのズームコントロールの見た目や挙動のカスタマイズをしてみます。

デフォルトのズームコントロール

地図コンテナ L.Map はデフォルトのオプションが

    zoomControl: true

になっているので、そのままなら上の図のようなズームコントローラが表示されます。

このとき Leaflet はズームコントロール部分の HTML を地図のコントロール領域内に以下のように出力します。

<div id="map" class="leaflet-container ...">
  <div class="leaflet-pane leaflet-map-pane"></div>
  <div class="leaflet-control-container">
    <div class="leaflet-top leaflet-left">
      <div class="leaflet-control-zoom leaflet-bar leaflet-control">
        <a class="leaflet-control-zoom-in" href="#" 
           title="Zoom in" role="button" aria-label="Zoom in">+</a>
        <a class="leaflet-control-zoom-out" href="#" 
           title="Zoom out" role="button" aria-label="Zoom out">-</a>
      </div>
    </div>
    <div class="leaflet-top leaflet-right"></div>
    <div class="leaflet-bottom leaflet-left"></div>
    <div class="leaflet-bottom leaflet-right"></div>
  </div>
</div>

5~10行目が L.Control.Zoom の部分です。ズームインとズームアウトのボタンは A タグで、ラベルはテキストになっています。

自分でカスタマイズしたズームコントロールを使いたい場合やそもそもズームコントロールがいらないので出力を抑制したいという場合は、L.Map のインスタンス生成時に

const map = L.map('map', {
    // ズームコントローラの生成を抑制
    zoomControl: false
});

とし、自前のものを使う場合は改めて定義します。

L.Control.Zoom の簡単なカスタマイズ

オプション指定によるテキストのカスタマイズ

L.Control.Zoom 固有のオプション は4つあって、ボタンのラベルと title 属性の値を任意の文字列にできます。

// デフォルトのズームコントロールは false になっているものとする
L.control.zoom({
    // ボタンのラベルを+-から変更
    zoomInText: '▲',
    zoomOutText: '▼',
    // title 属性を日本語化
    zoomInTitle: 'ズームイン',
    zoomOutTitle: 'ズームアウト'
}).addTo(map);
ボタンラベルとツールチップ(title 属性によるもの)を変更

スタイルのカスタマイズ

ボタンのスタイルを変更したい場合は、先に挙げた HTML 部分を参考に適宜スタイルシートを定義して好みの見た目にします。

.leaflet-bar.leaflet-control-zoom a {
  background-color: #445;
  color: #fff;
}
スタイルシートでカスタマイズ

L.Control.Zoom の拡張

L.Control.Zoom に設定できるオプションやスタイルシート以外の部分を変えたい場合は、このクラスを独自拡張することになります。

今回はズームコントロールの DOM 要素を一部変更、具体的にはズームコントロールボタンの title 属性を独自定義のツールチップ data-tooltip 属性に置き換えます。

イメージとしては、デフォルトのこんな HTML を

  <div class="leaflet-control-zoom leaflet-bar leaflet-control">
    <a class="leaflet-control-zoom-in" href="#" 
       title="Zoom in" role="button" aria-label="Zoom in">+</a>
    <a class="leaflet-control-zoom-out" href="#" 
       title="Zoom out" role="button" aria-label="Zoom out">-</a>
  </div>

  <div class="leaflet-control-zoom leaflet-bar leaflet-control">
    <a class="leaflet-control-zoom-in" href="#" 
       data-tooltip="Zoom in" role="button" aria-label="Zoom in">+</a>
    <a class="leaflet-control-zoom-out" href="#" 
       data-tooltip="Zoom out" role="button" aria-label="Zoom out">-</a>
  </div>

こんなふうに変更して、ツールチップの表示はスタイルシートで管理したいということです。

サブクラスを作成

Leaflet のソースコード leaflet-src.js(現在の最新版は 1.5.1)から L.Control.Zoom が ボタンの DOM 要素を生成している部分を見てみると、

    _createButton: function (html, title, className, container, fn) {
        var link = create$1('a', className, container);
        link.innerHTML = html;
        link.href = '#';
        link.title = title;
        link.setAttribute('role', 'button');
        link.setAttribute('aria-label', title);

        disableClickPropagation(link);
        on(link, 'click', stop);
        on(link, 'click', fn, this);
        on(link, 'click', this._refocusOnMap, this);

        return link;
    },

このメソッドを書き換えて title 属性の定義を無くして data-tooltip 属性に内容を書き換えたものを作り、このメソッドを新しいサブクラスのものとして置き換えます。このソースコードはクラスの階層やメソッドの名前などがパッケージ化されたものと所々違っているので、そのあたりはソースコードをよく読んで辻褄を合わせるようにしまして、

L.Control.Zoom.BtoW = L.Control.Zoom.extend({
    _createButton: function(html, title, className, container, fn) {
        const link = L.DomUtil.create('a', className, container);
        link.innerHTML = html;
        link.href = '#';
        link.setAttribute('role', 'button');
        link.setAttribute('aria-label', title);
        link.setAttribute('data-tooltip', title);

        L.DomEvent.disableClickPropagation(link);
        L.DomEvent.on(link, 'click', L.DomEvent.stop);
        L.DomEvent.on(link, 'click', fn, this);
        L.DomEvent.on(link, 'click', this._refocusOnMap, this);

        return link;
    }
});
L.control.zoom.botw = function(opts) {
    return new L.Control.Zoom.BotW(opts);
};

こんな感じに。元の5行目を削って、新しい方に8行目を追加しただけです。これで L.Control.Zoom を部分的にマイメソッドに書き換えたサブクラスができました。

ではこれを毎度ながら OpenStreetMap のサンプルに読み込んで、新たに追加した data-tooltip 属性をスタイルシートで表示させるようにしてみます。

独自ツールチップ版

Leaflet Demo – L.Control.Zoom.BotW

ゲーム地図の方にも追加、前回作った全画面表示コントロールとボタンやツールチップなどの UI のスタイルシートの定義を統一しました(今のところスタイルシートは結構あやしい)。

BotW Demo #3 – Zoom Control

地図にとりあえずつけたかったベーシックな機能はだいたいこんなところです。

Leaflet の拡張もだいたいやってみたというところで、ここまでを Leaflet 拡張基礎編として、次回からは実世界でいうところの地物となるマーカーのアイコン作成などに入ります。