今回は、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 プラグインを使い、地図上でマウスをドラッグして円や矩形を描画する方法についてでした。
ご参考になれば幸いです。