【JavaScript】Leaflet Drawプラグインを使って地図上に円や矩形を描く

今回は、Leaflet を使って表示した地図上に自由に円や矩形を描く方法についてです。
単純に、円や矩形を地図に表示させるだけなら、Leaflet の標準機能にもありますが、今回は、ユーザの任意の位置・サイズの円や矩形や直線を描きたかったので、プラグインを追加しました。

プラグインの API リファレンスはこちらから確認できます。

Leaflet Draw Documentation
https://leaflet.github.io/Leaflet.draw/docs/leaflet-draw-latest.html

 

実装にあたり、参考にさせていただいた記事はこちらから。

Leafletにあれこれ描く – bl.ocks.org
http://bl.ocks.org/TetsuyaKimotsuki/0156c511e3217edf58beb206633308f8

サンプルコードは下記のとおりですが…ほぼ上記サイトから転載させていただきました。

<html lang="ja">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <script src="https://code.jquery.com/jquery-2.1.1.min.js"></script>
    <link rel="stylesheet" href="https://unpkg.com/leaflet@1.7.1/dist/leaflet.css" integrity="sha512-xodZBNTC5n17Xt2atTPuE1HxjVMSvLVW9ocqUKLsCC5CXdbqCmblAshOMAS6/keqq/sMZMZ19scR4PsZChSR7A==" crossorigin=""/>
    <script src="https://unpkg.com/leaflet@1.7.1/dist/leaflet.js" integrity="sha512-XQoYMqMTK8LvdxXYG3nZ448hOEQiglfqkJs1NOQV44cWnUrBc8PkAOcXy20w0vlaXaVUearIOBhiXZ5V3ynxwA==" crossorigin=""></script>
    <link rel='stylesheet' href='https://cdnjs.cloudflare.com/ajax/libs/leaflet.draw/0.4.9/leaflet.draw-src.css' />
    <script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet.draw/0.4.9/leaflet.draw-src.js"></script>
    <style>
      #map { height: 100%; }
    </style>
  </head>
  <body>
    <div id="map"></div>
    <script>
      const map = L.map('map', {
        center: [34.797345395117546, 137.5804696201213],
        zoom: 13,
      });
      const tiles = L.tileLayer('https://cyberjapandata.gsi.go.jp/xyz/std/{z}/{x}/{y}.png', {
        attribution: "<a href='https://maps.gsi.go.jp/development/ichiran.html' target='_blank'>地理院タイル</a>"
      }).addTo(map);

      let drawnItems = new L.FeatureGroup().addTo(map);
      const drawControl = new L.Control.Draw({
        draw: {
          circle: {
            feet: false
          },
        },
        edit: {
          featureGroup: drawnItems,
        },
      }).addTo(map);

      map.on(L.Draw.Event.CREATED, function (e) {
        drawnItems.addLayer(e.layer);
        e.layer.feature = e.layer.feature || {};
        e.layer.feature.properties = e.layer.feature.properties || {};
        e.layer.feature.properties.note = e.layer.feature.properties.note || "";
        e.layer.feature.type = "Feature";
        popup = e.layer.bindPopup("");
        setFeatureProperties(e.layer);
        popup.on("popupopen", function (p) {
          $('#note_' + p.target._leaflet_id).attr('value', p.target.feature.properties.note).focus();
        });
        popup.on("popupclose", function (p) {
          p.target.feature.properties.note = $('#note_' + p.target._leaflet_id).val();
        });
      });

      map.on(L.Draw.Event.EDITED, function (e) {
        e.layers.eachLayer(function (layer) {
          setFeatureProperties(layer);
        });
      });

      const setFeatureProperties = function (layer) {
        // 線と多角形と四角形
        if (layer instanceof L.Polyline) {
          var latlngs = layer._defaultShape ? layer._defaultShape() : layer.getLatLngs();
          if (latlngs.length >= 2) {
            var distance = 0;
            for (var i = 0; i < latlngs.length - 1; i++) {
              distance += latlngs[i].distanceTo(latlngs[i + 1]);
            }
            layer.feature.properties.distance = distance.toFixed(2) + " m"; // ex. distance 3728.81 m
          }
          layer.feature.properties.drawtype = L.Draw.Polyline.TYPE;
        }
        // 多角形と四角形
        if (layer instanceof L.Polygon) {
          var latlngs = layer._defaultShape ? layer._defaultShape() : layer.getLatLngs();
          var area = L.GeometryUtil.geodesicArea(latlngs);
          layer.feature.properties.area = L.GeometryUtil.readableArea(area, true); // ex. area 174.19 ha
          layer.feature.properties.drawtype = L.Draw.Polygon.TYPE;
        }
        // 四角形
        if (layer instanceof L.Rectangle) {
          layer.feature.properties.drawtype = L.Draw.Rectangle.TYPE;
        }
        // 円
        if (layer instanceof L.Circle) {
          layer.feature.properties.radius = layer.getRadius().toFixed(2) + " m"; // ex. radius 1097.02 m
          layer.feature.properties.drawtype = L.Draw.Circle.TYPE;
        }
        // マーカー
        if (layer instanceof L.Marker) {
          layer.feature.properties.drawtype = L.Draw.Marker.TYPE;
        }
        // popup時の表示内容の差し替え
        var contents = "";
        for (var key in layer.feature.properties) {
          if (key != 'note' && key != 'drawtype') {
            contents = contents + key + " " + layer.feature.properties[key] + "<br />";
          }
        }
        contents += "note <input type='text' class='notes' id='note_" + layer._leaflet_id + "' value=''>";
        layer.setPopupContent(contents);
      };
    </script>
  </body>
</html>

実装した地図はこんな感じです。
なお、地図のタイルを国土地理院のものに変更していますので…少し図形の線が見にくいです。

円と直線を描いてみました。
ちなみに、円を描くときはドラッグ開始位置を中心として描きます。

実際に触ってみましたが、実装したい機能にかなり近いです!
あとは、図形を描画した緯度経度を取得する機能を実装したり、図形の色を変更したりする処理を追加したいです。

 

以上、Leaflet の Leaflet Draw プラグインを使い、地図上でマウスをドラッグして円や矩形を描画する方法についてでした。
ご参考になれば幸いです。

>株式会社シーポイントラボ

株式会社シーポイントラボ

TEL:053-543-9889
営業時間:9:00~18:00(月〜金)
住所:〒432-8003
   静岡県浜松市中央区和地山3-1-7
   浜松イノベーションキューブ 315
※ご来社の際はインターホンで「316」をお呼びください

CTR IMG