ネコと和解せよ

技術的なあれこれの備忘録のつもり

Leaflet中のD3.jsでマウスイベントが発火しない

tl;dr

  • Leaflet側でSVGレイヤー全体でマウスイベントが無効化するように設定されている
  • D3.js側で要素を追加するとき pointer-events: auto; を設定してやれば良い

Leaflet中のD3.jsでマウスイベントが発火しなかったので、発火させるためにやったことの低クオリティ備忘録

マップの例

例えば地図上に円を描画し、その円をクリックしたらその地名をalertで表示したいとする

おおよそ以下のようなコードになると思う

index.html

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8"/>
        <title>Map Leaflet + D3.js Example Code</title>
        <link rel="stylesheet" href="https://unpkg.com/leaflet@1.5.1/dist/leaflet.css"
              integrity="sha512-xwE/Az9zrjBIphAcBb3F6JVqxf46+CDLwfLMHloNu6KEQCAWi6HcDUbeOfBIptF7tcCzusKFjFw2yuvEpDL9wQ=="
              crossorigin=""/>
        <link rel="stylesheet" href="index.css"/>
    </head>

    <body>
        <div id="map"></div>
        <script src="https://unpkg.com/leaflet@1.5.1/dist/leaflet.js"
                integrity="sha512-GffPMF3RvMeYyc1LWMHtK8EbPv0iNZ8/oTtHPx9/cc2ILxQ+u905qIwdpULaqDkyBKgOaB57QTMg7ztg8Jm2Og=="
                crossorigin=""></script>
        <script src='//unpkg.com/d3@5.0.0/dist/d3.min.js'></script>
        <script src="index.js"></script>
    </body>

</html>

index.css

html, body, #map {
    width: 100%;
    height: 100%;
    margin: 0;
}

index.js

const map = L.map('map', {center: [35.6820476, 139.7630145], zoom: 13})

L.tileLayer('http://cyberjapandata.gsi.go.jp/xyz/blank/{z}/{x}/{y}.png', {
}).addTo(map)

L.svg().addTo(map)

// D3にsvg要素を選択
const svg = d3.select('#map').select('svg')

const data = [
  {name: "東京", coordinates: [35.6789864, 139.7656329]},
  {name: "新橋", coordinates: [35.6656639,139.7540808]},
  {name: "九段下", coordinates: [35.6757755, 139.7576306]},
  {name: "霞ヶ関", coordinates: [35.6619728,139.7367411]},
]

data.forEach(function (d, i) {
  d.LatLng = new L.LatLng(d.coordinates[0], d.coordinates[1])
  d.id = i
})

let gtags = svg.selectAll('g').data(data)
gtags = gtags.enter().append('g').merge(gtags)

gtags.append('circle')
  .attr("cx",0)
  .attr("cy",0)
  .attr("r",20)
  .attr("fill","green")
  .attr("fill-opacity", 0.4)
  .attr("stroke-width", 1)

gtags.on('click', function (d) {
    alert(d.name)
  })

const transformMap = function () {
  gtags.attr('transform', function (d) {
    const point = map.latLngToLayerPoint(d.LatLng)
    return 'translate(' + point.x + ',' + point.y + ')'
  })
}
transformMap()

map.on('moveend', transformMap)

以下の部分でクリックイベントを設定している

gtags.on('click', function (d) {
    alert(d.name)
  })

しかし上記のコードのままだとクリックイベントは発火しない

実は以下でSVGレイヤーを追加した時点でLeaflet側でマウスイベントを無効化しているらしく、クリックイベントが発火しない状態だった

L.svg().addTo(map)

なのでクリックイベントを設定している箇所を以下のように書き換えるとクリックイベントが発火するようになる(発火するようになった)

gtags.attr("style", "pointer-events: auto;")
  .on('click', function (d) {
    alert(d.name)
  })

参考