✨
[GIS]MapLibre GL JS を使用したWebマップ上での距離測定について(備忘録)
1.はじめに
・GISとは地理情報システム(Geographic Information System)の略称です。
・地球上に存在する地形物や事象をコンピュータ上の地図に可視化し、空間データの管理・検索・分析等を可能にします。
2.サンプルプログラム
index.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset='utf-8'>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="style.css" rel="stylesheet" />
<!-- MapLibre GL JS -->
<link rel='stylesheet' href='https://unpkg.com/maplibre-gl@5.1.0/dist/maplibre-gl.css' />
<script src='https://unpkg.com/maplibre-gl@5.1.0/dist/maplibre-gl.js'></script>
</head>
<body>
<!-- 地図を表示する要素 -->
<div id="map"></div>
<!-- 距離を表示する要素 -->
<div id="distance" class="distance-container"></div>
<!-- turfライブラリをインポート -->
<script src="https://cdn.jsdelivr.net/npm/@turf/turf@6/turf.min.js"></script>
<script src="main.js"></script>
</body>
style.css
body {
margin: 0;
padding: 0;
}
html,
body,
#map {
height: 100%;
}
.distance-container {
position: absolute;
top: 10px;
left: 10px;
z-index: 1;
}
.distance-container > * {
background-color: rgba(0, 0, 0, 0.5);
color: #fff;
font-size: 11px;
line-height: 18px;
display: block;
margin: 0;
padding: 5px 10px;
border-radius: 3px;
}
main.js
// 地図を初期化
const map = new maplibregl.Map({
container: 'map', // 地図を表示するHTMLの要素idを指定
style: 'https://api.maptiler.com/maps/jp-mierune-streets/style.json?key=xxxxx', // 地図のスタイル
center: [139.767066, 35.6813], // 中心座標(経度, 緯度)
zoom: 15 // ズームレベル
});
// 距離を表示するHTML要素を取得
const distanceContainer = document.getElementById('distance');
// 測定機能を保持するためのGeoJSONオブジェクト
const geojson = {
'type': 'FeatureCollection',
'features': []
};
// 座標間の線を描画するために使用
const linestring = {
'type': 'Feature',
'geometry': {
'type': 'LineString',
'coordinates': []
}
};
map.on('load', () => {
map.addSource('geojson', {
'type': 'geojson',
'data': geojson
});
// 地図上でクリックした地点に描画される円(circle)のレイヤ―を定義
map.addLayer({
id: 'measure-points',
type: 'circle', // レイヤーの種類
source: 'geojson',
paint: {
'circle-radius': 5,
'circle-color': '#000'
},
filter: ['in', '$type', 'Point']
});
// 地図上で線を描画するためのレイヤー
map.addLayer({
id: 'measure-lines',
type: 'line',
source: 'geojson',
layout: {
'line-cap': 'round',
'line-join': 'round'
},
paint: {
'line-color': '#000',
'line-width': 2.5
},
filter: ['in', '$type', 'LineString']
});
// クリックした地点のmeasure-pointsレイヤーに関するフィーチャーを取得
map.on('click', (e) => {
const features = map.queryRenderedFeatures(e.point, {
layers: ['measure-points']
});
if (geojson.features.length > 1) geojson.features.pop();
// 距離を表示するHTML要素をクリア
distanceContainer.innerHTML = '';
// クリックして描画された円を削除
if (features.length) {
const id = features[0].properties ? features[0].properties.id : null;
if (id) {
geojson.features = geojson.features.filter((point) => {
return point.properties.id !== id;
});
}
} else {
// クリックして描画された円をGeoJSONのfeaturesに追加
const point = {
'type': 'Feature',
'geometry': {
'type': 'Point',
'coordinates': [e.lngLat.lng, e.lngLat.lat]
},
'properties': {
'id': String(new Date().getTime())
}
};
geojson.features.push(point);
}
// featuresが2個以上(つまり円が2個以上)のとき、円の間に線を描画し、距離を計測
if (geojson.features.length > 1) {
linestring.geometry.coordinates = geojson.features.map(
(point) => {
return point.geometry.coordinates;
}
);
geojson.features.push(linestring);
// 距離表示HTMLエレメントに総距離を表示
const value = document.createElement('pre');
value.textContent =
`Total distance: ${
turf.length(linestring).toLocaleString()
} km`;
distanceContainer.appendChild(value);
}
map.getSource('geojson').setData(geojson);
});
});
// マウス操作時の挙動
map.on('mousemove', (e) => {
// 円が描画されているか検出
const features = map.queryRenderedFeatures(e.point, {
layers: ['measure-points']
});
map.getCanvas().style.cursor = features.length ?
'pointer' : // 地図上に描画された円にカーソルを重ねた際、カーソルをポインターに変更
'crosshair'; // それ以外では、カーソルは十字
});
・表示画面
3.実行環境
・OS: Windows 11(バージョン 24H2)
・ブラウザ: Microsoft Edge(バージョン 133.0.3065.82)
・エディタ: Visual Studio Code(バージョン 1.97)
・MapLibre GL JS: バージョン 5.1.0
4.参考
・GISとは?メリットや活用例をわかりやすく解説
・用語解説
・地図表示
・Measure distances
・Mapbox Newsletter WEEKLY TIPSの解説 -「距離を測定」
・第9回「防災マップの作成④空間演算による距離計測と避難所到達圏の可視化」
Discussion