📝
MapLibre GL JSで経路に矢印を表示する方法
はじめに
配達用の地図システムなどで経路を表示する場合、向きを明確にするために矢印を表示したい場合があります
例えば、大阪を適当に1周するような経路表示を想定します
線だけではどちらがスタート地点なのかがわかりません
また、拡大してしまうとどちらの向きに移動するのかがわかりません
こういった問題を解消するために、経路上に矢印を表示する方法を紹介します
矢印の追加方法
まずは線を表示する
線のデータをソースとして登録し、それを表示するレイヤーを追加します
const route = [
[135.4955900233997, 34.698450748884916],
[135.5005439639132, 34.698188783671206],
[135.50128743433436, 34.69639866583216],
[135.50097878125513, 34.69250430212237],
[135.50371989069944, 34.692114414923196],
[135.50517207344322, 34.69201907509368],
[135.5067346883476, 34.69176937501961],
[135.50876779691947, 34.691084504323605],
[135.51017727306348, 34.690281926158484],
[135.51168045399163, 34.6902112989023],
[135.51738129391993, 34.6897788176345],
[135.5222559135254, 34.69149447689167],
[135.52256448265857, 34.689619683390085],
[135.52244327398563, 34.68931806964845],
[135.5217032631404, 34.68924463309281],
[135.5201594473576, 34.688287329158555],
[135.52012436063646, 34.68817192739066],
[135.52013074004032, 34.687760151589615],
[135.52076043953252, 34.68565653541521],
[135.5214808717457, 34.68319659987836],
[135.51730414967503, 34.68336802479903],
[135.5116905444989, 34.683482875606586],
[135.50650281412805, 34.683548993751245],
[135.4987086550054, 34.68362987184963],
[135.4977549053385, 34.68375483012705],
[135.49699707082655, 34.68372144593622],
[135.49671784813788, 34.68867668369645],
[135.49619590243265, 34.69240192172987],
[135.49539818925896, 34.69669024706072],
];
map.on('load', () => {
map.addSource('route', {
type: 'geojson',
data: {
type: 'Feature',
geometry: {
type: 'LineString',
coordinates: route
},
properties: {},
}
});
map.addLayer({
id: 'route',
type: 'line',
source: 'route',
paint: {
'line-color': '#00F',
'line-width': 8
}
});
});
画像を用意する
簡単な形状ですが、右向きの三角形を画像として作成します
画像を読み込み、線の上に表示する
先ほど作成した矢印の画像を読み込みます
読み込みが完了したら、矢印表示用のレイヤーを追加します
map.loadImage(
'arrow.png',
(error, image) => {
if (error) throw error;
map.addImage('arrow', image);
map.addLayer({
id: 'directions',
type: 'symbol',
source: 'route',
paint: {},
layout: {
'symbol-placement': 'line',
'icon-image': 'arrow',
'symbol-spacing': 150
}
})
}
);
symbol-spacing
で矢印の間隔を調整することができます(デフォルト値は250px)
今回の例ではデフォルトだと間隔が広く感じたので、少し狭くしました
参考:https://maplibre.org/maplibre-style-spec/layers/#layout-symbol-symbol-spacing
画像に関して注意事項
画像を右向きで作成しなかった場合はicon-rotate
で適宜回転させてください
例えば上向きの画像を作成した場合は下記のように90度回転させる必要があります
layout: {
'symbol-placement': 'line',
'icon-image': 'arrow',
'symbol-spacing': 150,
'icon-rotate': 90
}
最後に
全体のソースは以下の通りです
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<script src="https://unpkg.com/maplibre-gl@latest/dist/maplibre-gl.js"></script>
<link href="https://unpkg.com/maplibre-gl@latest/dist/maplibre-gl.css" rel="stylesheet" />
</head>
<body>
<div id="map" style="width: 1000px; height: 1000px"></div>
<script>
const map = new maplibregl.Map({
container: 'map',
style: 'https://gsi-cyberjapan.github.io/gsivectortile-mapbox-gl-js/std.json',
center: [135.5005439639132, 34.698188783671206],
zoom: 17,
minZoom: 4,
maxZoom: 17,
});
const route = [
[135.4955900233997, 34.698450748884916],
[135.5005439639132, 34.698188783671206],
[135.50128743433436, 34.69639866583216],
[135.50097878125513, 34.69250430212237],
[135.50371989069944, 34.692114414923196],
[135.50517207344322, 34.69201907509368],
[135.5067346883476, 34.69176937501961],
[135.50876779691947, 34.691084504323605],
[135.51017727306348, 34.690281926158484],
[135.51168045399163, 34.6902112989023],
[135.51738129391993, 34.6897788176345],
[135.5222559135254, 34.69149447689167],
[135.52256448265857, 34.689619683390085],
[135.52244327398563, 34.68931806964845],
[135.5217032631404, 34.68924463309281],
[135.5201594473576, 34.688287329158555],
[135.52012436063646, 34.68817192739066],
[135.52013074004032, 34.687760151589615],
[135.52076043953252, 34.68565653541521],
[135.5214808717457, 34.68319659987836],
[135.51730414967503, 34.68336802479903],
[135.5116905444989, 34.683482875606586],
[135.50650281412805, 34.683548993751245],
[135.4987086550054, 34.68362987184963],
[135.4977549053385, 34.68375483012705],
[135.49699707082655, 34.68372144593622],
[135.49671784813788, 34.68867668369645],
[135.49619590243265, 34.69240192172987],
[135.49539818925896, 34.69669024706072],
];
map.on('load', () => {
map.addSource('route', {
type: 'geojson',
data: {
type: 'Feature',
geometry: {
type: 'LineString',
coordinates: route
},
properties: {},
}
});
map.addLayer({
id: 'route',
type: 'line',
source: 'route',
paint: {
'line-color': '#00F',
'line-width': 8
}
});
map.loadImage(
'arrow.png',
(error, image) => {
if (error) throw error;
map.addImage('arrow', image);
map.addLayer({
id: 'directions',
type: 'symbol',
source: 'route',
paint: {},
layout: {
'symbol-placement': 'line',
'icon-image': 'arrow',
'symbol-spacing': 150
}
})
}
);
});
</script>
</body>
</html>
Discussion