top of page

GeoJSONのサンプルコードで覚える7つの基本操作

タイマーアイコン.jpeg
この記事は平均8分45秒で読めます
万能の測量機LRTKの説明

著者: LRTKチーム

GeoJSONは、地点、線、面といった地理空間データをJSONで表現するためのデータ形式です。構造は読みやすい一方で、実務では「座標の順番はどちらか」「FeatureとGeometryは何が違うのか」「複数の地物をどうまとめるのか」「検索や更新はどの単位で行うのか」でつまずきやすい形式でもあります。


この記事では、「geojson 使い方」で調べている実務担当者向けに、GeoJSONの基本操作をサンプルコード中心で解説します。業務アプリ、地図画面、現地調査データ、設備管理、区域管理などで応用しやすい考え方に寄せて説明します。


目次

GeoJSONを実務で扱う前に押さえる基本

基本操作1:Pointを作成して地点を表す

基本操作2:LineStringで経路や境界線を表す

基本操作3:Polygonで範囲や区画を表す

基本操作4:Featureで属性情報を持たせる

基本操作5:FeatureCollectionで複数データをまとめる

基本操作6:条件で検索し、必要な地物だけを取り出す

基本操作7:座標を更新し、bboxで範囲を管理する

GeoJSONを実務で使いこなすためのまとめ


GeoJSONを実務で扱う前に押さえる基本

GeoJSONは、地理的な形状をJSON形式で表現するためのデータ形式です。現地で取得した点検地点、道路や配管のルート、管理対象区域、工事範囲、調査区画などを、共通した形で表せます。


最初に押さえたいのは、Geometry、Feature、FeatureCollectionの関係です。Geometryは座標から作られる形そのものです。Pointであれば地点、LineStringであれば線、Polygonであれば面を表します。FeatureはGeometryに名称や種別、状態などの属性情報を付けたものです。FeatureCollectionは複数のFeatureをまとめた入れ物です。実務では、単独のGeometryよりもFeatureCollectionとして一覧管理する場面が多くなります。


GeoJSONで特に間違いやすいのが座標の順番です。一般的な2次元GeoJSONの座標配列では「経度、緯度」の順で書きます。日本国内の地点であれば、`[139.7671, 35.6812]` のように、先に東西方向の値、次に南北方向の値を書きます。この順番を逆にすると、地図上で別の場所に表示されたり、表示範囲外として扱われたりします。


本稿では、RFC 7946に沿った一般的なGeoJSONを前提にします。座標参照系はWGS 84、座標値は経度・緯度の10進度表記として扱います。既存GISデータや外部データを取り込む場合は、座標系と座標順序を確認してください。GeoJSONにはMultiPoint、MultiLineString、MultiPolygon、GeometryCollectionなどもありますが、まずは点・線・面とFeatureCollectionの基本を押さえると応用しやすくなります。


基本操作1:Pointを作成して地点を表す

Pointは、GeoJSONで最も基本的な形状です。現地調査の測点、設備の設置位置、施設の位置、事故や異常の発生地点など、点として管理できる情報に使います。


Pointでは、`type` に `Point` を指定し、`coordinates` に経度と緯度を配列で入れます。高さ情報を扱う場合は3つ目の値として追加できますが、最初は2次元の座標で理解すると扱いやすくなります。


` { "type": "Point", "coordinates": [139.7671, 35.6812] } `


この例では、`139.7671` が経度、`35.6812` が緯度です。地図画面で点を表示するだけならGeometryだけでも位置は表せます。ただし、実務では「この点が何を意味するのか」が必要になるため、後述するFeatureとして属性を付けるのが一般的です。


座標の桁数にも注意します。数値として桁を多く書けば細かい値を表せますが、桁数がそのまま測位精度を保証するわけではありません。必要に応じて、取得方法や精度区分をpropertiesに持たせると管理しやすくなります。


` const longitude = 139.7671; const latitude = 35.6812;


const pointGeometry = { type: "Point", coordinates: [longitude, latitude] }; `


変数名は、`x` や `y` だけでなく、`longitude` と `latitude` のように意味が分かる名前にすると安全です。GeoJSONの入口で座標順序を明確にしておくと、後続の表示や保存でもミスを減らせます。


基本操作2:LineStringで経路や境界線を表す

LineStringは、複数の座標を順番につないで線を表すGeometryです。道路、歩行ルート、河川、配管、ケーブル、測線、境界線など、連続した線として扱う情報に使います。


LineStringのcoordinatesは、Pointの座標配列をさらに配列で並べた形です。ひとつひとつの座標は `[経度, 緯度]` で、全体としては `[[経度, 緯度], [経度, 緯度], ...]` という構造になります。LineStringには2点以上の座標が必要です。


` { "type": "LineString", "coordinates": [ [139.7600, 35.6800], [139.7650, 35.6820], [139.7700, 35.6810] ] } `


LineStringでは順番が重要です。同じ座標を使っていても、並び順が変われば線の進み方が変わります。移動経路、点検順路、流れの向き、施工順などを表す場合、座標の順番は業務上の意味を持ちます。


` const routeCoordinates = [ [139.7600, 35.6800], [139.7650, 35.6820], [139.7700, 35.6810] ];


if (routeCoordinates.length < 2) { throw new Error("LineStringには2点以上の座標が必要です"); }


const routeGeometry = { type: "LineString", coordinates: routeCoordinates }; `


複数の地点をまとめたいだけなら、PointのFeatureを複数作ってFeatureCollectionに入れるほうが自然です。一方、それらの地点を順番につないだ経路として扱いたい場合はLineStringが適しています。途中で枝分かれする道路網や複数の独立した線を扱う場合は、Featureを分ける、MultiLineStringを使う、ネットワーク用の別構造で管理するなど、要件に応じた設計が必要です。


基本操作3:Polygonで範囲や区画を表す

Polygonは、閉じた面を表すGeometryです。敷地、行政区域、工事範囲、調査区画、立入制限範囲、管理対象エリアなど、面として扱う情報に使います。PointやLineStringよりcoordinatesの階層が一段深くなるため、構造をよく確認しましょう。


Polygonでは、外周を表す座標の並びをリングとして扱います。リングは閉じている必要があり、最初の座標と最後の座標を同じ値にします。GeoJSONの線形リングは、閉じたLineStringとして4つ以上の位置を持つ必要があります。


` { "type": "Polygon", "coordinates": [ [ [139.7600, 35.6800], [139.7700, 35.6800], [139.7700, 35.6900], [139.7600, 35.6900], [139.7600, 35.6800] ] ] } `


`coordinates` の中にさらに配列があり、その中に座標が並んでいる点に注目してください。Polygonではリングの配列を並べます。これは、穴のある面を表す場合に、外周リングに加えて内側のリングを追加できるようにするためです。最初のリングが外周、次以降のリングが穴です。


` { "type": "Polygon", "coordinates": [ [ [139.7600, 35.6800], [139.7800, 35.6800], [139.7800, 35.7000], [139.7600, 35.7000], [139.7600, 35.6800] ], [ [139.7660, 35.6860], [139.7720, 35.6860], [139.7720, 35.6920], [139.7660, 35.6920], [139.7660, 35.6860] ] ] } `


処理コードでPolygonを作る場合は、最初と最後の座標が一致しているか、閉じた後に4つ以上の位置を持つかを確認すると安全です。


` function samePosition(a, b) { return a[0] === b[0] && a[1] === b[1]; }


function closeRingIfNeeded(ring) { if (ring.length < 3) { throw new Error("Polygonのリングには少なくとも3つの異なる頂点が必要です"); }


const first = ring[0]; const last = ring[ring.length - 1];


const closedRing = samePosition(first, last) ? ring : [...ring, first];


if (closedRing.length < 4) { throw new Error("Polygonのリングは閉じた状態で4点以上が必要です"); }


return closedRing; }


const outerRing = closeRingIfNeeded([ [139.7600, 35.6800], [139.7700, 35.6800], [139.7700, 35.6900], [139.7600, 35.6900] ]);


const areaGeometry = { type: "Polygon", coordinates: [outerRing] }; `


Polygonでは、座標の順序や面の重なりにも注意が必要です。RFC 7946では、外周リングは反時計回り、穴は時計回りという右手法則が示されています。ただし、既存データや利用環境によっては向きが混在していても読み込める場合があります。公開・連携用に出力するデータでは、リングの向きをそろえておくと相互運用性を保ちやすくなります。


基本操作4:Featureで属性情報を持たせる

Geometryだけでも地理的な形状は表せますが、実務では形状だけでは不十分です。地点であれば名称、種別、管理番号、状態、更新日、担当区分などが必要になります。こうした属性情報をGeometryと一緒に扱うために使うのがFeatureです。


Featureは、`type` に `Feature` を指定し、`geometry` にPointやLineStringやPolygonを入れ、`properties` に属性情報を入れる構造です。必要に応じて `id` を付けることもできます。idはデータを一意に識別するために使いやすく、更新や削除の対象を指定するときに役立ちます。


` { "type": "Feature", "id": "point001", "geometry": { "type": "Point", "coordinates": [139.7671, 35.6812] }, "properties": { "name": "点検地点A", "category": "設備", "status": "未確認" } } `


propertiesには、文字列、数値、真偽値、配列、入れ子構造などを使えます。仕様上はpropertiesがnullになる場合もありますが、実務で検索や集計を行うなら、できるだけ一貫したオブジェクトとして設計するほうが扱いやすくなります。「未確認」「未チェック」「未実施」のように同じ意味の値が混在すると、後の検索や集計が難しくなります。


` const inspectionPoint = { type: "Feature", id: "point001", geometry: { type: "Point", coordinates: [139.7671, 35.6812] }, properties: { name: "点検地点A", category: "設備", status: "未確認", priority: 2 } }; `


表示色やアイコン種別のような情報をpropertiesに入れることもできますが、それが業務データなのか表示設定なのかを整理しておくことが大切です。たとえば、`status` が「未確認」だから表示時に目立たせる設計であれば、GeoJSON側には業務状態だけを持たせ、見た目は表示側で決めるほうが再利用しやすい場合があります。


基本操作5:FeatureCollectionで複数データをまとめる

FeatureCollectionは、複数のFeatureをひとつにまとめるための構造です。点検地点が100件ある、設備線が複数ある、管理区域が複数ある、といった場合に、それぞれをFeatureとして作り、features配列に並べます。


` { "type": "FeatureCollection", "features": [ { "type": "Feature", "id": "point001", "geometry": { "type": "Point", "coordinates": [139.7671, 35.6812] }, "properties": { "name": "点検地点A", "category": "設備", "status": "未確認" } }, { "type": "Feature", "id": "point002", "geometry": { "type": "Point", "coordinates": [139.7700, 35.6840] }, "properties": { "name": "点検地点B", "category": "設備", "status": "確認済み" } } ] } `


ひとつのFeatureCollectionにPoint、LineString、Polygonを混ぜることはできます。ただし、混在させると検索や表示の条件分岐が増えます。用途が明確に分かれるなら、点、線、面を別のデータとして管理するほうが分かりやすい場合もあります。


` const records = [ { id: "point001", name: "点検地点A", longitude: 139.7671, latitude: 35.6812, status: "未確認" }, { id: "point002", name: "点検地点B", longitude: 139.7700, latitude: 35.6840, status: "確認済み" } ];


const features = records.map((record) => { return { type: "Feature", id: record.id, geometry: { type: "Point", coordinates: [record.longitude, record.latitude] }, properties: { name: record.name, status: record.status } }; });


const collection = { type: "FeatureCollection", features: features }; `


FeatureCollectionを設計するときは、全Featureに共通する属性キーをそろえることが大切です。あるFeatureには `status` があり、別のFeatureには `state` がある状態になると、後から条件検索を行うときに手間が増えます。また、データ量が大きくなるほど、分割、絞り込み、簡略化、必要範囲だけの取得といった工夫が必要になります。


基本操作6:条件で検索し、必要な地物だけを取り出す

GeoJSONを実務で扱うと、未確認の点検地点だけを表示したい、特定カテゴリの設備だけを抽出したい、優先度が高いものだけを一覧化したい、といった要件が出てきます。このとき基本になるのが、FeatureCollectionのfeatures配列を条件で絞り込む操作です。


属性による検索では、主にpropertiesを見ます。たとえば、`status` が `未確認` のFeatureだけを取り出す場合、次のようにfilterを使います。


` const unconfirmedFeatures = collection.features.filter((feature) => { const props = feature.properties ?? {}; return props.status === "未確認"; });


const unconfirmedCollection = { type: "FeatureCollection", features: unconfirmedFeatures }; `


複数条件で検索する場合は、propertiesの値を組み合わせます。条件が増えるほど、属性名と値のルールがそろっていることの重要性が高まります。


` const targetFeatures = collection.features.filter((feature) => { const props = feature.properties ?? {};


return props.category === "設備" && props.priority >= 2; });


const targetCollection = { type: "FeatureCollection", features: targetFeatures }; `


位置による絞り込みを行う場合は、Geometryのcoordinatesを参照します。Pointであれば、coordinatesから経度と緯度を取り出し、指定した範囲内にあるかを判定できます。


` const bounds = { minLongitude: 139.7600, minLatitude: 35.6800, maxLongitude: 139.7800, maxLatitude: 35.7000 };


const featuresInBounds = collection.features.filter((feature) => { if (!feature.geometry || feature.geometry.type !== "Point") { return false; }


const coordinates = feature.geometry.coordinates; const longitude = coordinates[0]; const latitude = coordinates[1];


return longitude >= bounds.minLongitude && longitude <= bounds.maxLongitude && latitude >= bounds.minLatitude && latitude <= bounds.maxLatitude; });


const boundedCollection = { type: "FeatureCollection", features: featuresInBounds }; `


LineStringやPolygonの場合は、単純にひとつの座標だけを見ればよいわけではありません。線や面が範囲と交差しているか、完全に含まれるか、一部だけ重なるか、といった判断が必要になります。最初はPointで考え方を理解し、線や面ではより慎重な判定を使うとよいです。


基本操作7:座標を更新し、bboxで範囲を管理する

GeoJSONは作成して終わりではありません。現地確認の結果として位置を修正したり、線形を更新したり、範囲を変更したりすることがあります。対象を安全に更新するには、idなどの一意な識別子を持たせておくことが重要です。


` const updatedCollection = { type: "FeatureCollection", features: collection.features.map((feature) => { if (feature.id !== "point001") { return feature; }


return {
  ...feature,
  geometry: {
    ...feature.geometry,
    coordinates: [139.7680, 35.6818]
  },
  properties: {
    ...(feature.properties ?? {}),
    status: "確認済み",
    updatedAt: "2026-05-25"
  }
};

}) }; `


この例では、`point001` の座標を更新し、同時に状態と更新日も変更しています。元のFeatureを直接変更するのではなく、新しいFeatureCollectionを作る形にすると、変更前後の比較や履歴管理を行いやすくなります。


LineStringの座標を更新する場合は、coordinates配列に点を追加、削除、移動します。順番が意味を持つため、どこに追加するかを明確にする必要があります。


` const routeFeature = { type: "Feature", id: "route001", geometry: { type: "LineString", coordinates: [ [139.7600, 35.6800], [139.7700, 35.6810] ] }, properties: { name: "巡回ルートA" } };


const newCoordinate = [139.7650, 35.6820];


const updatedRouteFeature = { ...routeFeature, geometry: { ...routeFeature.geometry, coordinates: [ routeFeature.geometry.coordinates[0], newCoordinate, routeFeature.geometry.coordinates[1] ] } }; `


Polygonを更新する場合は、リングの閉じ方に注意します。外周の座標を変更した結果、最初と最後の座標が一致しなくなると、面として不完全になります。座標更新後にリングを再確認する処理を入れておくと安全です。


座標更新とあわせて覚えたいのがbboxです。bboxは、GeoJSONの地物や集合全体を囲む座標範囲を表す情報です。日付変更線をまたがない一般的な2次元データでは、`[最小経度, 最小緯度, 最大経度, 最大緯度]` の形で扱うと理解しやすいです。


` { "type": "Feature", "id": "area001", "bbox": [139.7600, 35.6800, 139.7700, 35.6900], "geometry": { "type": "Polygon", "coordinates": [ [ [139.7600, 35.6800], [139.7700, 35.6800], [139.7700, 35.6900], [139.7600, 35.6900], [139.7600, 35.6800] ] ] }, "properties": { "name": "管理区域A" } } `


bboxは手で書くこともできますが、座標を更新するたびに手作業で直すのは現実的ではありません。処理でcoordinatesをたどり、最小経度、最小緯度、最大経度、最大緯度を計算するほうが安全です。


` function collectPositions(coordinates, positions = []) { if (typeof coordinates[0] === "number") { positions.push(coordinates); return positions; }


coordinates.forEach((item) => { collectPositions(item, positions); });


return positions; }


function calculateBbox(geometry) { const positions = collectPositions(geometry.coordinates);


if (positions.length === 0) { throw new Error("bboxを計算できる座標がありません"); }


const longitudes = positions.map((position) => position[0]); const latitudes = positions.map((position) => position[1]);


return [ Math.min(...longitudes), Math.min(...latitudes), Math.max(...longitudes), Math.max(...latitudes) ]; }


const bbox = calculateBbox(areaGeometry); `


bboxはあくまで外接する矩形範囲であり、実際の形状そのものではありません。厳密な内外判定にbboxだけを使うのは適切ではありません。一方で、候補を大まかに絞る用途には便利です。まずbboxで候補を減らし、その後に詳細な形状判定を行う考え方は、大量データを扱うときに役立ちます。


GeoJSONを実務で使いこなすためのまとめ

GeoJSONの使い方は、Point、LineString、Polygonの3つの基本Geometryを理解するところから始まります。Pointは地点、LineStringは線、Polygonは面を表します。それぞれのGeometryをFeatureで包み、propertiesに属性情報を持たせることで、単なる図形ではなく、検索や更新ができる業務データとして扱えるようになります。


複数のFeatureを扱うときはFeatureCollectionが基本です。現地調査の結果、設備台帳、管理区域、作業対象リストなどをまとめる場合、FeatureCollectionにそろえておくと、表示、保存、通信、検索の処理を共通化しやすくなります。propertiesのキー名や値のルールを統一しておくことも重要です。


検索では、propertiesによる属性検索と、coordinatesやbboxによる位置検索を組み合わせます。更新では、idで対象を特定し、Geometryのcoordinatesを正しく変更します。Pointであれば座標の差し替え、LineStringであれば座標列の追加や移動、Polygonであればリングの閉じ方を保った更新が必要です。


GeoJSONは軽量で読みやすい形式ですが、実務で安定して使うには、座標順序、座標系、配列階層、属性設計、識別子、更新ルールを丁寧に扱う必要があります。今回紹介した7つの基本操作を押さえれば、地図に点を出すだけの段階から、線や面を含む地理空間データ管理へ進むための土台ができます。


現場で取得した位置情報をGeoJSONとして管理する場合は、入力する位置データの品質も重要です。取得方法、測位精度、更新日時、担当者、確認状態などをpropertiesで整理しておくと、地図表示だけでなく、台帳連携、検索、更新履歴の管理にも活用しやすくなります。まずは小さなFeatureCollectionから始め、運用しながら属性ルールと更新手順を整えていくことが、GeoJSONを実務で使いこなすための現実的な進め方です。


LRTKで現場の測量精度・作業効率を飛躍的に向上

LRTKシリーズは、建設・土木・測量分野における高精度なGNSS測位を実現し、作業時間短縮や生産性の大幅な向上を可能にします。国土交通省が推進するi-Constructionにも対応しており、建設業界のデジタル化促進に最適なソリューションです。

LRTKの詳細については、下記のリンクよりご覧ください。

 

製品に関するご質問やお見積り、導入検討に関するご相談は、

こちらのお問い合わせフォームよりお気軽にご連絡ください。ぜひLRTKで、貴社の現場を次のステージへと進化させましょう。

bottom of page