フリーダムの日記

GIS(地理情報システム)を中心に技術的なことを書いています。

大容量の GeoJSON を Mapbox と ArcGIS で表示

はじめに

今回は GIS でも馴染みがあるデータのひとつとして GeoJSON を Web アプリケーションで扱う方法として、Mapbox と ArcGIS を例にして紹介したいと思います。

GeoJSON は、Web アプリケーションなどで GIS データを利用する場合は 一番手軽に利用することができます。 GeoJSON は、JSON の拡張版のフォーマットで地理空間情報を手軽に利用することが可能です。そのため、Web アプリケーションを開発するときに利用する 多くの JavaScript ライブラリでは GeoJSON に対応しています。例えば、Mapbox が提供している Mapbox GL JSEsri が提供している ArcGIS API for JavaScript 4.x でも対応しています。

今回はこの両者の JavaScript ライブラリを利用して、パフォーマンスもかねて、比較的大きなデータの GeoJSON を表示してみましたので、それぞれで扱う場合の特徴を踏まえて紹介できればと思います。

今回使用したデータとサンプルアプリは、GitHub に公開しています。Mapbox GL JS と ArcGIS API for JavaScript で GeoJSON を表示しているサンプルです。GeoJSON は、OSM のデータを使用し、ポイント、ライン、ポリゴンの各データを扱いました。容量は 3 つのファイルで約 180 MB ぐらいです。ポイントは、約 30 万件以上の POI データになります。

以下が両者で表示した時のサンプルの動画です。 ちなみに表示に確認した PC は、Mac OS で プロセッサは、2.9 GHz デュアルコア Intel Core i 5 で メモリ 8GB となっており、特別、高性能な PC でもないです。

Mapbox GL JS
Mapbox GL JS サンプルアプリ GeoJSON 表示

ArcGIS API for JavaScript サンプルアプリ GeoJSON 表示
ArcGIS API for JavaScript サンプルアプリ GeoJSON 表示

Mapbox GL JS での GeoJSON を表示

Mapbox GL JS での GeoJSON の表示方法に関しては、 Mapbox GL JS のドキュメントでのサンプルなどを参照していただければと思います。また、Mapbox GL JS は GeoJSON のレンダリングはかなりの高パフォーマンスで、大きなファイルでもかなり高速に表示することができるように設計されています。通常 GeoJSON を表示する場合、一般的な地図ライブラリだと大量なデータを表示できないのですが、Mapbox GL JSの場合は、その GeoJSON を読み込む際に動的にタイル分割して読み込んでいるので大量の GeoJSON でも表示できる仕組みになっています。

その他、データの読み込みと処理時のラグとフリーズを回避するために、Mapbox GL JS では、Web ワーカーを利用しています。メインスレッドを中断することなく、バック グラウンドで計算量の多いコードを実行できる最新のブラウザー機能です。より技術的な詳細に関しては以下を参照していただければと思います。

blog.mapbox.com

github.com

Mapbox GL JS で GeoJSON を表示する部分のソースコードは以下になります。map オブジェクトをロードに各レイヤーの作成から設定までをしています。シンボルの表現は、ArcGIS API for JavaScript を同じにしています。

/**
  * 地図読み込み後実行
  */
map.on('load', function () {

  // ポリゴンのデータソース設定
  map.addSource('polygon_building', {
    type: 'geojson',
    data: DATA_URL.POLYGON_BUILDING
  });

  // ポリゴンのスタイル設定
  map.addLayer({
    "id": "polygon_building",
    "type": "fill",
    "source": "polygon_building",
    "layout": {},
    "paint": {
        'fill-color': "#FFE51F",
        'fill-opacity': 0.5
    }
  });

  // ラインのデータソース設定
  map.addSource('line_highway', {
    type: 'geojson',
    data: DATA_URL.LINE_HIGHWAY
  });

  // ラインのデータソース設定
  map.addLayer({
    "id": "line_highway",
    "type": "line",
    "source": "line_highway",
    "layout": {},
    "paint": {
        'line-width': 3,
        'line-opacity':0.5, 
        'line-color': '#00FFFF'
    }
  });

  // ポイントのデータソース設定
  map.addSource('point_poi', {
    type: 'geojson',
    data: DATA_URL.POINT_POI
  });

  // ポイントのデータソース設定
  map.addLayer({
    "id": "point_poi",
    "type": "circle",
    "source": "point_poi",
    "layout": {},
    "paint": {
      "circle-radius": 5,
      "circle-opacity": 0.5,
      "circle-color": "#7cfc00"
    }
  });

});

ArcGIS API for JavaScript での GeoJSON を表示

ArcGIS API for JavaScript では、GeoJSON Layer があり、それを使用することで簡単に表示することができます。サンプルも提供されています。

developers.arcgis.com

さて、ArcGIS API for JavaScript での GeoJSON のレンダリングですが、実はバージョン 4.17 以前はかなり遅く、Mapbox GL JS が圧倒的に早かったのですが、バージョン 4.17 のリリースでパフォーマンスが改善されており、かなり速くなっています。 クライアントサイドのレイヤーの改善ということでリリースノートにも紹介されています。両者を比較してみた感じですと感覚的にはそれほど大きな差はないような感じでした。ArcGIS API for JavaScript でも Web ワーカーを使用しており、バックグラウンドスレッドのクライアント側のレイヤーでより多くのクエリを実行できるようになっています。

以下の GIF は、Esri のサンプルでバージョン 4.16(左)と バージョン 4.17(右)を使用していますが、4.17 の方が速いことが分かるかと思います。 https://developers.arcgis.com/javascript/latest/73539499318e4d83d6db06847c80b2e6/client-side-layer-improvements-optimized.gif

ArcGIS API for JavaScript で GeoJSON を表示する部分のソースコードは以下になります。シンボルの表現は、Mapbox GL JS と同じにしています。

// Create a Map      
const map = new Map({
  basemap: "streets-night-vector"
});

const view = new MapView({
  container: "viewDiv", 
  map: map,
  zoom: 5,
  center: [138.2294267, 38.0497443]
});

let polgyonRenderer = {
  type: "simple",
  symbol: {
    type: "simple-fill",
    color: [255, 229, 31, 0.5]
  }
};

let lineRenderer = {
  type: "simple",
  symbol: {
    type: "simple-line",
    color: [0, 255, 255, 0.5],
    width: 3
  }
};

let pointRenderer = {
  type: "simple",
  symbol: {
    type: "simple-marker",
    color: [124, 252, 0, 0.5],
    outline: { style: "none", width: 0 },
    size: 5
  }
};

const template = {
  title: "POI Info",
  content: "POI 名前: {name} ",
  fieldInfos: [
    {
      fieldName: "name"
    }
  ]
};

let buildingGeoJSONLayer = new GeoJSONLayer({
  url: DATA_URL.POLYGON_BUILDING,
  renderer: polgyonRenderer 
});

let highwayGeoJSONLayer = new GeoJSONLayer({
  url: DATA_URL.LINE_HIGHWAY,
  renderer: lineRenderer 
});

let poiGeoJSONLayer = new GeoJSONLayer({
  url: DATA_URL.POINT_POI,
  popupTemplate: template,
  renderer: pointRenderer
});

view.map.addMany([
    buildingGeoJSONLayer,
    highwayGeoJSONLayer,
    poiGeoJSONLayer,
]); 

さいごに

今回は GeoJSON を扱ってみました。昔から馴染みのあるデータですが、昨今 Web で大容量のデータを表示したいなどのニーズは増えているかと思います。GeoJSON や CSV などは手軽に扱えるため便利ですよね。ブラウザの進化もありますが、JavaScript のライブラリの改善によって大きなデータでもユーザーは意識することなく表示することができるようになっているのは嬉しいですね。もちろん限界はあるかと思います。その場合は、クライアント側での処理の工夫が必要にはなってくるかと思います。例えば、クラスタリングなども便利な機能ですね。 また、興味深いテーマがあれば紹介できればと思います。