応用
ハウツー 大量の点をクラスタリングするには
数百〜数千の点を地図に載せると、点が重なって見づらくなります。クラスタリングを有効にすると、近い点を自動でまとめて件数ラベルを表示し、拡大すると個別の点に分かれます。
コード
マーカーの配列を MarkerClusterer に渡すと、近い点を自動でまとめてくれます。
import "maplibre-gl/dist/maplibre-gl.css";
import "@geolonia/maps-core/css";
import { geolonia } from "@geolonia/maps-suite";
const map = new geolonia.maps.Map(document.getElementById("map"), {
apiKey: "YOUR-API-KEY",
center: { lat: 35.67, lng: 139.74 },
zoom: 10,
});
const res = await fetch("/data/dense-points.geojson");
const gj = await res.json();
const markers = gj.features.map(
(f) =>
new geolonia.maps.Marker({
position: { lng: f.geometry.coordinates[0], lat: f.geometry.coordinates[1] },
}),
);
new geolonia.maps.MarkerClusterer({ map, markers });Markerはmapを渡さずに作ります(取り外した状態)。地図への取り付けはMarkerClustererが管理します。MarkerClusterer({ map, markers }):近いマーカーを件数付きのクラスターにまとめ、ズームすると分かれます。- GeoJSON の
coordinatesは[経度, 緯度]の順なので、positionに詰め替えるときの順序に注意してください。
Source に cluster を付けると、maplibre がクラスターを作ります。描き方は自分で決めるので、クラスターの丸・件数のラベル・まとまらなかった点の3つのレイヤを置きます。
import "maplibre-gl/dist/maplibre-gl.css";
import "@geolonia/maps-core/css";
import { createRoot } from "react-dom/client";
import { Layer, Map, Source } from "@geolonia/maps-react";
createRoot(document.getElementById("root")).render(
<Map
apiKey="YOUR-API-KEY"
center={[139.74, 35.67]}
zoom={10}
containerStyle={{ width: "100%", height: "100vh" }}
>
<Source
id="spots"
type="geojson"
data="/data/dense-points.geojson"
cluster
clusterRadius={50}
>
<Layer
id="clusters"
type="circle"
filter={["has", "point_count"]}
paint={{
"circle-color": "#e2543a",
"circle-radius": ["step", ["get", "point_count"], 16, 10, 22, 50, 30],
"circle-opacity": 0.85,
}}
/>
<Layer
id="cluster-count"
type="symbol"
filter={["has", "point_count"]}
layout={{
"text-field": ["get", "point_count_abbreviated"],
"text-font": ["Noto Sans Regular"],
"text-size": 12,
}}
paint={{ "text-color": "#ffffff" }}
/>
<Layer
id="unclustered"
type="circle"
filter={["!", ["has", "point_count"]]}
paint={{
"circle-color": "#e2543a",
"circle-radius": 6,
"circle-stroke-width": 1.5,
"circle-stroke-color": "#ffffff",
}}
/>
</Source>
</Map>,
);cluster:Sourceが受け取るのは maplibre のソース定義そのままなので、clusterとclusterRadius(まとめる距離、ピクセル)がそのまま使えます。filter:point_countを持つ地物がクラスター、持たない地物が単独の点です。この2つを別のレイヤで描き分けます。point_count_abbreviated:件数を短く整えた値です。1200が1.2kのようになります。text-font:Geolonia のスタイルに含まれるフォントを指定します。maplibre の既定のフォント名は含まれていないため、省略すると件数が出ません。
結果
上のコードは、それぞれのタブの下でそのまま動いています。300点のデータがクラスタリングされて表示され、拡大するとクラスターが分かれて個別の点になります。
うまくいかないとき
- クラスターにならず全部バラバラ →
data-cluster="on"が書かれているか確認。値は"on"です("true"ではありません)。 - 何も出ない →
data-geojsonのパスが正しいか確認。GeoJSON ファイルがサーバー上に存在し、アクセスできる必要があります。