Turf.jsを使ったマップグリッド配置とセルごとのステータス管理
公開日: 2026/03/13 / 更新日: 2026/03/28
地図上の任意の範囲のステータスを管理するためのアプリに使うロジックを考えた。
- 任意の範囲を地図上にグリッドで指定
- 任意のイベントを起点にセルのステータスを更新
ユーザーがポリゴンからセルを生成する計算は、Turf.jsを使ってクライアントサイドで実行する。
マップ上に正n角形(今回は3角形)を表示させる。
//中心点と半径と頂点の数を設定
const center = turf.point([139.7671, 35.6812]);
const radius = 5;
const vertexCount = 3;
const angleStep = 360 / vertexCount;
//頂点座標格納用にリストを用意
const co0rdinates = [];
//頂点の回数分だけ角度をずらしながらそれぞれの頂点の座標をリストに格納していく
for (let i = 0; i < vertexCount; i++) {
const bearing = i * angleStep;
const destPoint = turf.destination(center, radius, bearing, { units: "kilometers" });
coordinates.push(destPoint.geometry.coordinates); }
//GeoJSONのルールで、図形を完成させるためにリストの最後に1個めの頂点座標(coordinates[0])をもう一度追加する必要がある
coordinates.push(coordinates[0]);
//Polygonデータとして
const polygon = turf.polygon([coordinates]);ユーザーは各頂点をドラッグ&ドロップで地図上の任意の範囲をマスクすることができる。
(このロジックはLeafLetなどの描画側の処理も絡むためコードは割愛)

生成されたn角形からグリッドを生成する
//せるのサイズを10m四方で指定
const gridSizeKm = Math.sqrt(100) / 1000;
//外接する長方形を計算する
const bounds = turf.bbox(trianglePolygon) as [minLng, minLat, maxLng, maxLat];
//その長方形全体にgridSizeKmで指定したようなグリッドを追加
const generated = turf.squareGrid(bounds, gridSizeKm, { units: "kilometers" });
//作った全セルの中から、前に生成した図形にかかっているセルだけ残す
const maskedCells = generated.features.filter((cell) =>
turf.booleanIntersects(cell, polygon)
); 
生成されたセルにgrid-keyを付与する。(セルの座標配列を文字列化して作成。)
このgrid-keyとそのステータスをAPIに送信してDBを更新する仕組み。

現状、DBが保持するのはポリゴンの頂点座標とステータスに変更があったセルの情報だけだが、使用するにつれてデータが膨らみ、描画のための読み込みに時間がかかる可能性がある。
対策として、全ポリゴンのセルのうち半数以上が変更されたときを境に、逆に変更なしのセルを取得するように切り替える作戦は有効だが、平均通信データ量は1/2でありいずれ限界が来そう。
更新済みセルのgrid-keyをうまいこと計算して個別のセルをいくつかの長方形として処理してからするという方法ならば通信データ量を大きく削減できるが簡単には具体的なロジックが思いつかいない。
実際の運用を見据えるとまだ検討する箇所が多いが、地図を塗りつぶしていくようなアプリに使える機能をTurf.jsを使って計算するロジックについて簡単にまとめた。
ライター
HARLYA
無能アリ
趣味でフルスタック開発をしている。巨人の肩に乗りまくりで四捨五入すればエンドユーザー。