Leaflet入門

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: '&copy; 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データの表示
  • カスタム機能の実装

関連記事

お問い合わせ

Leafletを使ったWebGIS開発についてのご相談は、お気軽にお問い合わせください。

  • WebGIS開発相談
  • カスタマイズ支援
  • 研修・トレーニング

お問い合わせはこちら

最終更新: 2025年1月