MapLibreは、美しいベクタータイル地図を表示できるオープンソースライブラリです。
MapLibre入門【オープンソースのベクタータイル地図】
この記事では、MapLibreの基礎から実践的な使い方まで解説します。
MapLibreとは
概要
MapLibre GL JSは、Mapbox GL JSからフォークされたオープンソースの地図ライブラリです。
【特徴】 ・ベクタータイル対応 ・美しい地図表現 ・高速な描画 ・完全にオープンソース ・3D表示対応
Leafletとの違い
| 項目 | MapLibre | Leaflet |
|---|---|---|
| タイル形式 | ベクター | ラスター |
| 描画速度 | 高速 | 普通 |
| スタイル | 柔軟 | 制限あり |
| 3D対応 | ○ | × |
| ファイルサイズ | 大きい | 小さい |
ベクタータイルのメリット
メリット
- スムーズなズーム
- 動的なスタイル変更
- 高速な描画
- 軽量なデータ
- 回転・傾斜表示
セットアップ
CDNを使用
html
<!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を使用
bash
npm install maplibre-gl
javascript
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
});
基本操作
地図の作成
javascript
// 基本的な地図作成
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 // 回転
});
地理院タイルの利用
javascript
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
});
ナビゲーションコントロール
javascript
// ズームコントロール
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());
地図の操作
javascript
// 移動
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
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"
}
]
}
動的なスタイル変更
javascript
// レイヤーの追加
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');
フィルタリング
javascript
// フィルターを設定
map.setFilter('my-layer', ['==', 'type', 'office']);
// 複合条件
map.setFilter('my-layer', [
'all',
['==', 'type', 'office'],
['>=', 'floor', 10]
]);
データソースの追加
GeoJSONソース
javascript
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'
}
});
マーカーの追加
javascript
// マーカーを作成
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);
カスタムマーカー
javascript
// 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表示
javascript
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表示
javascript
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
}
});
カメラ操作
javascript
// 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();
実践活用
イベント処理
javascript
// クリックイベント
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 = '';
});
画像のエクスポート
javascript
// 地図を画像として取得
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();
}
レスポンシブ対応
javascript
// ウィンドウリサイズ時に地図をリサイズ
window.addEventListener('resize', function() {
map.resize();
});
まとめ
MapLibreの強み
特徴
- ベクタータイル対応
- 美しい地図表現
- 3D表示対応
- 完全にオープンソース
使い分け
MapLibreを選ぶ場合
- 美しい地図が必要
- 3D表示が必要
- 動的なスタイル変更が必要
Leafletを選ぶ場合
- シンプルな地図表示
- 軽量さを重視
- 既存プラグインを活用
関連記事
