Leafletは最も人気のある軽量地図ライブラリです。
Leaflet入門【軽量WebGISライブラリの使い方】
この記事では、Leafletの基本から実践的な使い方まで解説します。
Leafletとは
特徴
【Leafletの特徴】 ・軽量(約40KB) ・モバイル対応 ・シンプルなAPI ・豊富なプラグイン ・オープンソース
他ライブラリとの比較
| 項目 | Leaflet | OpenLayers | Google Maps |
|---|---|---|---|
| サイズ | 40KB | 500KB+ | – |
| 学習コスト | 低 | 高 | 中 |
| 機能 | 中 | 高 | 高 |
| 費用 | 無料 | 無料 | 有料プラン有 |
セットアップ
CDNを使用
html
<!DOCTYPE html>
<html>
<head>
<title>Leaflet Map</title>
<!-- CSS -->
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css"
integrity="sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY="
crossorigin="" />
<!-- JavaScript -->
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"
integrity="sha256-20nQCchB9co0qIjJZRGuk2/Z9VM+kNiyxNV1lvTlZBo="
crossorigin=""></script>
<style>
#map { height: 400px; }
</style>
</head>
<body>
<div id="map"></div>
<script src="map.js"></script>
</body>
</html>
npm/yarnを使用
bash
# インストール
npm install leaflet
# または
yarn add leaflet
javascript
// ES Modules
import L from 'leaflet';
import 'leaflet/dist/leaflet.css';
const map = L.map('map').setView([35.6812, 139.7671], 13);
基本操作
地図の作成
javascript
// 基本的な地図作成
var map = L.map('map').setView([35.6812, 139.7671], 13);
// オプション付き
var map = L.map('map', {
center: [35.6812, 139.7671],
zoom: 13,
minZoom: 5,
maxZoom: 18,
zoomControl: true,
scrollWheelZoom: true
});
タイルレイヤー
javascript
// OpenStreetMap
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© OpenStreetMap contributors'
}).addTo(map);
// 地理院タイル
L.tileLayer('https://cyberjapandata.gsi.go.jp/xyz/std/{z}/{x}/{y}.png', {
attribution: '国土地理院',
maxZoom: 18
}).addTo(map);
地図の操作
javascript
// 中心を移動
map.setView([35.6812, 139.7671], 15);
// アニメーション付き移動
map.flyTo([35.6812, 139.7671], 15);
// ズーム操作
map.setZoom(15);
map.zoomIn();
map.zoomOut();
// 範囲にフィット
map.fitBounds([[35.65, 139.70], [35.70, 139.80]]);
現在位置の取得
javascript
// 現在地を取得してマーカーを追加
map.locate({setView: true, maxZoom: 16});
map.on('locationfound', function(e) {
L.marker(e.latlng).addTo(map)
.bindPopup("現在地").openPopup();
});
map.on('locationerror', function(e) {
alert("位置情報を取得できませんでした");
});
図形の描画
マーカー
javascript
// 基本的なマーカー
var marker = L.marker([35.6812, 139.7671]).addTo(map);
// ポップアップ付き
marker.bindPopup("<b>東京駅</b>").openPopup();
// ツールチップ
marker.bindTooltip("東京駅", {permanent: true});
// ドラッグ可能
var draggableMarker = L.marker([35.6812, 139.7671], {
draggable: true
}).addTo(map);
draggableMarker.on('dragend', function(e) {
var latlng = e.target.getLatLng();
console.log("移動先:", latlng.lat, latlng.lng);
});
円
javascript
// 円を描画
var circle = L.circle([35.6812, 139.7671], {
color: 'red',
fillColor: '#f03',
fillOpacity: 0.5,
radius: 500 // メートル
}).addTo(map);
ポリゴン
javascript
// ポリゴンを描画
var polygon = L.polygon([
[35.69, 139.76],
[35.68, 139.77],
[35.67, 139.75],
[35.68, 139.74]
], {
color: 'blue',
fillColor: '#30f',
fillOpacity: 0.5
}).addTo(map);
ポリライン
javascript
// 線を描画
var polyline = L.polyline([
[35.69, 139.76],
[35.68, 139.77],
[35.67, 139.78]
], {
color: 'green',
weight: 5
}).addTo(map);
矩形
javascript
// 矩形を描画
var bounds = [[35.67, 139.74], [35.69, 139.77]];
var rectangle = L.rectangle(bounds, {
color: "#ff7800",
weight: 1
}).addTo(map);
イベント処理
地図イベント
javascript
// クリックイベント
map.on('click', function(e) {
console.log("クリック位置:", e.latlng);
L.marker(e.latlng).addTo(map);
});
// ズーム変更
map.on('zoomend', function() {
console.log("現在のズーム:", map.getZoom());
});
// 移動完了
map.on('moveend', function() {
console.log("中心座標:", map.getCenter());
});
マーカーイベント
javascript
var marker = L.marker([35.6812, 139.7671]).addTo(map);
// クリック
marker.on('click', function() {
alert("マーカーがクリックされました");
});
// マウスオーバー
marker.on('mouseover', function() {
this.openPopup();
});
marker.on('mouseout', function() {
this.closePopup();
});
カスタムイベント
javascript
// ポップアップのイベント
marker.on('popupopen', function() {
console.log("ポップアップが開きました");
});
marker.on('popupclose', function() {
console.log("ポップアップが閉じました");
});
プラグイン活用
Leaflet.draw(図形描画)
html
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet.draw/1.0.4/leaflet.draw.css" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet.draw/1.0.4/leaflet.draw.js"></script>
javascript
// 描画レイヤー
var drawnItems = new L.FeatureGroup();
map.addLayer(drawnItems);
// 描画コントロール
var drawControl = new L.Control.Draw({
edit: {
featureGroup: drawnItems
},
draw: {
polygon: true,
polyline: true,
rectangle: true,
circle: true,
marker: true
}
});
map.addControl(drawControl);
// 描画完了イベント
map.on(L.Draw.Event.CREATED, function(e) {
var layer = e.layer;
drawnItems.addLayer(layer);
});
Leaflet.markercluster
html
<link rel="stylesheet" href="https://unpkg.com/leaflet.markercluster/dist/MarkerCluster.css" />
<script src="https://unpkg.com/leaflet.markercluster/dist/leaflet.markercluster.js"></script>
javascript
var markers = L.markerClusterGroup();
// 大量のマーカーを追加
for (var i = 0; i < 1000; i++) {
var lat = 35.6 + Math.random() * 0.2;
var lng = 139.6 + Math.random() * 0.2;
markers.addLayer(L.marker([lat, lng]));
}
map.addLayer(markers);
Leaflet.fullscreen
html
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet.fullscreen/3.0.0/Control.FullScreen.css" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet.fullscreen/3.0.0/Control.FullScreen.js"></script>
javascript
map.addControl(new L.Control.Fullscreen());
実践テクニック
レイヤーグループ
javascript
// レイヤーグループを作成
var cities = L.layerGroup();
var roads = L.layerGroup();
// マーカーを追加
L.marker([35.6812, 139.7671]).addTo(cities);
L.marker([35.6896, 139.7006]).addTo(cities);
// ポリラインを追加
L.polyline([[35.68, 139.76], [35.69, 139.70]]).addTo(roads);
// レイヤーコントロール
var overlays = {
"都市": cities,
"道路": roads
};
L.control.layers(null, overlays).addTo(map);
cities.addTo(map);
GeoJSONの読み込み
javascript
// fetchでGeoJSONを読み込み
async function loadGeoJSON(url) {
const response = await fetch(url);
const data = await response.json();
L.geoJSON(data, {
style: function(feature) {
return {
color: feature.properties.color || '#3388ff',
weight: 2
};
},
onEachFeature: function(feature, layer) {
if (feature.properties.name) {
layer.bindPopup(feature.properties.name);
}
}
}).addTo(map);
}
loadGeoJSON('data.geojson');
検索機能
javascript
// 簡易検索機能
function searchLocation(keyword) {
// Nominatim APIで検索
fetch(`https://nominatim.openstreetmap.org/search?format=json&q=${keyword}`)
.then(response => response.json())
.then(data => {
if (data.length > 0) {
var result = data[0];
map.setView([result.lat, result.lon], 15);
L.marker([result.lat, result.lon])
.bindPopup(result.display_name)
.addTo(map)
.openPopup();
}
});
}
距離計測
javascript
// 2点間の距離を計算
function calculateDistance(latlng1, latlng2) {
return map.distance(latlng1, latlng2); // メートル
}
// クリックで距離計測
var points = [];
map.on('click', function(e) {
points.push(e.latlng);
L.marker(e.latlng).addTo(map);
if (points.length === 2) {
var distance = calculateDistance(points[0], points[1]);
alert("距離: " + (distance / 1000).toFixed(2) + " km");
L.polyline(points, {color: 'red'}).addTo(map);
points = [];
}
});
まとめ
Leafletの強み
特徴
- 軽量で高速
- シンプルなAPI
- プラグインが豊富
- モバイル対応
基本的な使い方
5ステップ
- CSS/JSを読み込み
- コンテナ要素を作成
- L.map()で地図作成
- L.tileLayer()でタイル追加
- 必要な機能を追加
次のステップ
発展的な活用
- プラグインの活用
- GeoJSONデータの表示
- カスタム機能の実装
関連記事
