MapLibre入門【オープンソースのベクタータイル地図】

MapLibre入門【オープンソースのベクタータイル地図】のアイキャッチ画像
目次

MapLibreは、美しいベクタータイル地図を表示できるオープンソースライブラリです。

この記事では、MapLibreの基礎から実践的な使い方まで解説します。


MapLibreとは

概要

MapLibre GL JSは、Mapbox GL JSからフォークされたオープンソースの地図ライブラリです。

【特徴】
・ベクタータイル対応
・美しい地図表現
・高速な描画
・完全にオープンソース
・3D表示対応

Leafletとの違い

項目 MapLibre Leaflet
タイル形式 ベクター ラスター
描画速度 高速 普通
スタイル 柔軟 制限あり
3D対応 ×
ファイルサイズ 大きい 小さい

ベクタータイルのメリット

・スムーズなズーム
・動的なスタイル変更
・高速な描画
・軽量なデータ
・回転・傾斜表示

セットアップ

CDNを使用

<!DOCTYPE html>
<html>
<head>
    <title>MapLibre Map</title>
    <script src="https://unpkg.com/maplibre-gl@3.6.2/dist/maplibre-gl.js"></script>
    <link href="https://unpkg.com/maplibre-gl@3.6.2/dist/maplibre-gl.css" rel="stylesheet" />
    <style>
        body { margin: 0; padding: 0; }
        #map { width: 100%; height: 100vh; }
    </style>
</head>
<body>
    <div id="map"></div>
    <script src="map.js"></script>
</body>
</html>

npm/yarnを使用

npm install maplibre-gl
import maplibregl from 'maplibre-gl';
import 'maplibre-gl/dist/maplibre-gl.css';

const map = new maplibregl.Map({
    container: 'map',
    style: 'https://demotiles.maplibre.org/style.json',
    center: [139.7671, 35.6812],
    zoom: 13
});

基本操作

地図の作成

// 基本的な地図作成
var map = new maplibregl.Map({
    container: 'map',                // コンテナID
    style: 'style.json',             // スタイルJSON
    center: [139.7671, 35.6812],     // 中心座標 [lng, lat]
    zoom: 13,                        // ズームレベル
    pitch: 0,                        // 傾き
    bearing: 0                       // 回転
});

地理院タイルの利用

var map = new maplibregl.Map({
    container: 'map',
    style: {
        version: 8,
        sources: {
            'gsi-std': {
                type: 'raster',
                tiles: [
                    'https://cyberjapandata.gsi.go.jp/xyz/std/{z}/{x}/{y}.png'
                ],
                tileSize: 256,
                attribution: '国土地理院'
            }
        },
        layers: [{
            id: 'gsi-std-layer',
            type: 'raster',
            source: 'gsi-std'
        }]
    },
    center: [139.7671, 35.6812],
    zoom: 13
});

ナビゲーションコントロール

// ズームコントロール
map.addControl(new maplibregl.NavigationControl());

// 位置情報コントロール
map.addControl(new maplibregl.GeolocateControl({
    positionOptions: {
        enableHighAccuracy: true
    },
    trackUserLocation: true
}));

// スケールバー
map.addControl(new maplibregl.ScaleControl({
    maxWidth: 200,
    unit: 'metric'
}));

// フルスクリーン
map.addControl(new maplibregl.FullscreenControl());

地図の操作

// 移動
map.flyTo({
    center: [139.7671, 35.6812],
    zoom: 15,
    pitch: 45,
    bearing: 30
});

// ジャンプ(アニメーションなし)
map.jumpTo({
    center: [139.7671, 35.6812],
    zoom: 15
});

// 範囲にフィット
map.fitBounds([
    [139.70, 35.65],  // 南西
    [139.80, 35.70]   // 北東
]);

スタイルのカスタマイズ

スタイルJSON

{
    "version": 8,
    "name": "Custom Style",
    "sources": {
        "osm": {
            "type": "raster",
            "tiles": ["https://tile.openstreetmap.org/{z}/{x}/{y}.png"],
            "tileSize": 256
        }
    },
    "layers": [
        {
            "id": "osm-layer",
            "type": "raster",
            "source": "osm"
        }
    ]
}

動的なスタイル変更

// レイヤーの追加
map.on('load', function() {
    // ソースを追加
    map.addSource('my-data', {
        type: 'geojson',
        data: 'data.geojson'
    });

    // レイヤーを追加
    map.addLayer({
        id: 'my-layer',
        type: 'circle',
        source: 'my-data',
        paint: {
            'circle-radius': 10,
            'circle-color': '#ff0000'
        }
    });
});

// レイヤーのスタイル変更
map.setPaintProperty('my-layer', 'circle-color', '#0000ff');

// レイヤーの表示/非表示
map.setLayoutProperty('my-layer', 'visibility', 'none');
map.setLayoutProperty('my-layer', 'visibility', 'visible');

フィルタリング

// フィルターを設定
map.setFilter('my-layer', ['==', 'type', 'office']);

// 複合条件
map.setFilter('my-layer', [
    'all',
    ['==', 'type', 'office'],
    ['>=', 'floor', 10]
]);

データソースの追加

GeoJSONソース

map.addSource('points', {
    type: 'geojson',
    data: {
        type: 'FeatureCollection',
        features: [
            {
                type: 'Feature',
                geometry: {
                    type: 'Point',
                    coordinates: [139.7671, 35.6812]
                },
                properties: {
                    name: '東京駅'
                }
            }
        ]
    }
});

map.addLayer({
    id: 'points-layer',
    type: 'circle',
    source: 'points',
    paint: {
        'circle-radius': 8,
        'circle-color': '#007cbf'
    }
});

マーカーの追加

// マーカーを作成
var marker = new maplibregl.Marker()
    .setLngLat([139.7671, 35.6812])
    .addTo(map);

// ポップアップ付きマーカー
var popup = new maplibregl.Popup({ offset: 25 })
    .setText('東京駅');

var markerWithPopup = new maplibregl.Marker()
    .setLngLat([139.7671, 35.6812])
    .setPopup(popup)
    .addTo(map);

カスタムマーカー

// HTML要素でカスタムマーカー
var el = document.createElement('div');
el.className = 'custom-marker';
el.style.backgroundImage = 'url(marker.png)';
el.style.width = '32px';
el.style.height = '32px';

new maplibregl.Marker(el)
    .setLngLat([139.7671, 35.6812])
    .addTo(map);

3D表示

地形の3D表示

var map = new maplibregl.Map({
    container: 'map',
    style: {
        version: 8,
        sources: {
            'terrain': {
                type: 'raster-dem',
                url: 'terrain-source-url'
            },
            'satellite': {
                type: 'raster',
                tiles: ['satellite-tiles-url/{z}/{x}/{y}.jpg'],
                tileSize: 256
            }
        },
        terrain: {
            source: 'terrain',
            exaggeration: 1.5
        },
        layers: [
            {
                id: 'satellite-layer',
                type: 'raster',
                source: 'satellite'
            }
        ]
    },
    center: [138.7274, 35.3606],  // 富士山
    zoom: 12,
    pitch: 60
});

建物の3D表示

map.addLayer({
    id: '3d-buildings',
    source: 'composite',
    'source-layer': 'building',
    type: 'fill-extrusion',
    minzoom: 15,
    paint: {
        'fill-extrusion-color': '#aaa',
        'fill-extrusion-height': ['get', 'height'],
        'fill-extrusion-base': ['get', 'min_height'],
        'fill-extrusion-opacity': 0.6
    }
});

カメラ操作

// 3D視点で移動
map.flyTo({
    center: [139.7671, 35.6812],
    zoom: 16,
    pitch: 60,
    bearing: 45,
    duration: 2000
});

// アニメーション
function rotateCamera() {
    map.rotateTo(map.getBearing() + 1, { duration: 100 });
    requestAnimationFrame(rotateCamera);
}
rotateCamera();

実践活用

イベント処理

// クリックイベント
map.on('click', function(e) {
    console.log('クリック位置:', e.lngLat);

    new maplibregl.Popup()
        .setLngLat(e.lngLat)
        .setHTML('<p>クリックされました</p>')
        .addTo(map);
});

// レイヤーのクリック
map.on('click', 'my-layer', function(e) {
    var feature = e.features[0];
    new maplibregl.Popup()
        .setLngLat(e.lngLat)
        .setHTML(feature.properties.name)
        .addTo(map);
});

// ホバー効果
map.on('mouseenter', 'my-layer', function() {
    map.getCanvas().style.cursor = 'pointer';
});

map.on('mouseleave', 'my-layer', function() {
    map.getCanvas().style.cursor = '';
});

画像のエクスポート

// 地図を画像として取得
function exportMap() {
    var canvas = map.getCanvas();
    var dataURL = canvas.toDataURL('image/png');

    var link = document.createElement('a');
    link.download = 'map.png';
    link.href = dataURL;
    link.click();
}

レスポンシブ対応

// ウィンドウリサイズ時に地図をリサイズ
window.addEventListener('resize', function() {
    map.resize();
});

まとめ

MapLibreの強み

・ベクタータイル対応
・美しい地図表現
・3D表示対応
・完全にオープンソース

使い分け

【MapLibreを選ぶ場合】
・美しい地図が必要
・3D表示が必要
・動的なスタイル変更が必要

【Leafletを選ぶ場合】
・シンプルな地図表示
・軽量さを重視
・既存プラグインを活用

関連記事


お問い合わせ

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

お問い合わせはこちら →


最終更新: 2025年1月

この記事をシェア

関連デモ・ツール

技術選定からご相談ください

発注範囲が決まっていなくても、現在の業務と判断したいことから整理します。

相談内容を送る

GIS・AI・業務自動化に関するご相談は お問い合わせページ からお気軽にどうぞ。