📌

ArcGISのスタイルを体験する

2023/04/14に公開

はじめに

この記事ではArcGISにおけるスタイルの挙動を確認します。具体的にはArcGIS Maps SDK for JavaScriptを使って地図を表示し、どのようにスタイルを使うのかを見ていきます。

この記事は以下の企画の子記事です。他サービスの記事へのリンクがあるので、ぜひ合わせてご参照ください。

https://zenn.dev/ottylab/articles/2b0c9d8e918a5a

地図を表示する

チュートリアルのDisplay a mapを参考にまずは地図を表示してみましょう。

まず、以下のライブラリを読み込みます。

<link rel="stylesheet" href="https://js.arcgis.com/4.26/esri/themes/light/main.css">
<script src="https://js.arcgis.com/4.26/"></script>

CSSを設定します。

<style>
  body { margin: 0; padding: 0; }
  #map { position: absolute; top: 0; bottom: 0; width: 100%; }
</style>

次に地図を表示する場所を作ります。

<div id="map"></div>

JavaScriptのコードは以下のようになります。まず、アクセストークンをesriConfig.apiKeyに設定します。次にMapクラスのコンストラクタでオプションを設定します。ここではベースマップの種類を指定しています。さらにMapViewクラスで描画に関する設定を行います。ArcGISは他のライブラリと違い、地図のデータに関する機能(Map)と表示に関する機能(MapView)が分離されています。こうすることで表示部分をSceneViewに変えると3D表示に切り替えることができたりします。

require(["esri/config", "esri/Map", "esri/views/MapView"], (
  esriConfig,
  Map,
  MapView
) => {
  esriConfig.apiKey = YOUR_API_KEY_HERE;

  const map = new Map({
    basemap: "arcgis-topographic"
  });
  
  const view = new MapView({
    container: "map",
    map: map,
    zoom: 4,
    center: [15, 65]
  });
});

結果は以下のとおりです。

ローダー

ところで、requireという関数を初めて見たので調べました。これはAMD(Asynchronous Module Definition)と呼ばれるライブラリのローダーの機能でした(spec)。requireの引数にロードしたい機能名を配列で渡すと、コールバック関数の引数にその実体が渡されるようです。

ただし、ArcGISのGitHubのREADMEを見ると、AMDモジュールではなくESモジュールの仕様が推奨されています。そこで、ESモジュールで記述する方法も試してみます。まず、<script src="https://js.arcgis.com/4.26/"></script>は不要なので消します。次にJavaScriptのコードを以下のように記述します。

import config from "https://js.arcgis.com/4.26/@arcgis/core/config.js";
import Map from "https://js.arcgis.com/4.26/@arcgis/core/Map.js";
import MapView from "https://js.arcgis.com/4.26/@arcgis/core/views/MapView.js";

config.apiKey = YOUR_API_KEY_HERE;

const map = new Map({
  basemap: "arcgis-topographic"
});

const view = new MapView({
  container: "map",
  map: map,
  zoom: 4,
  center: [15, 65]
});

詳しい解説はこちらをご参照ください。この解説によるとCDNによる読み込みはパフォーマンスが良くないそうなのでご注意ください。

The ES modules CDN is for testing only, it is not optimized for performance. For best performance in a production application, build the @arcgis/core modules locally.

結果は以下のとおりです。

以降の説明ではESモジュールで実装します。

スタイルの変更

ArcGISではベースマップの上に自由にレイヤーを重ねることで独自の地図を作成します。そこで、このベースマップのスタイルを編集する方法を確認します。ArcGISはMapbox StyleとEsri Web Mapの二種類のJSONスタイルをサポートしています。

ArcGISはVector Tile Style Editorというサービスを提供しており、これを利用することでWeb上のUIで直感的にスタイルを編集できます。また、編集したスタイルはEsriのサーバにホストされ、ArcGIS Maps SDK for JavaScriptから使用できます。

Vector Tile Style Editor (VTSE)でスタイルを編集

それでは早速、高速道路の色を赤色に変更してみましょう。

「Start editing」ボタンをクリックして開始します。最近作成したスタイルの一覧画面に遷移しますが、そこで右上の「+New style」ボタンをクリックします。デザインのベースとなる地図を選択しますが、ここでは「World Topographic Map (for Developers)」を使用しました。

東京周辺をズームし、高速道路をクリックします。当該レイヤー(Road/Freeway Motorway/0 (Line))が選択された状態になるので、AppearanceのColorを#ff00000に変更します。即座にプレビューの地図に反映されます。

VTSEで高速道路の色を変更

左にあるメニューで「Save as」をクリックし保存します。Share with:Everyone (Public)を選択することでJavaScriptから使用できるようになります。

スタイルの使用

それでは早速先程のスタイルを使ってみましょう。VectorTileLayerおよびBasemapクラスを使用するのでインポートします。

import VectorTileLayer from "https://js.arcgis.com/4.26/@arcgis/core/layers/VectorTileLayer.js";
import Basemap from "https://js.arcgis.com/4.26/@arcgis/core/Basemap.js";

まず、作成したスタイルからVectorTileLayerを作成します。VTSEの編集画面のURLに含まれる32文字のHEX値がidです。

const vectorTileLayer = new VectorTileLayer({
  portalItem: {
    id: "2fa2c405a9674404a56a4db80d22341e"
  }
});

つぎにVectorTileLayerからBasemapを作成します。

const basemap = new Basemap({
  baseLayers: [vectorTileLayer]
});

そしてそのBasemapMapに渡せばOKです。

const map = new Map({
  basemap: basemap
});

結果は以下のとおりです。

Mapbox形式のスタイルを読み込んでいるのにVectorTileLayerという名称で少し混乱したかもしれません(私は混乱しました)。複数レイヤー集まったものがスタイルなのに、それにレイヤーという名称で良いのか?という違和感です。

しかし、ArcGIS Maps SDK for JavaScriptではスタイルを一つのレイヤーとして扱います。ベースマップとして使われるレイヤーはbasemap layer、ユーザーが作成したデータ等を表示するレイヤーをoperational layerとよび、それぞれ管理されます。

つまり、スタイル編集時に作成したレイヤーはJavaScriptのコード上ではレイヤーとして扱えないということになります。

スタイルを動的に変更

Mapクラスのリファレンスを見たところ、BasemapはMapオブジェクトの作成時に指定し、その後変更するためのメソットがありませんでした。そこで、セレクタ選択時にMapオブジェクトを作成し直します。

IDSWorld Topographic Map (for Developers)とVTSEで編集したスタイルのIDを入れます。createMap関数は先程同様、VectorTileLayerBasemapMapを作成します。セレクタが選択されると、それに応じてcreateMapが呼び出されます。

const IDS = {
  default: "42df0d22517e49ad84edcee4c093857d",
  custom: "2fa2c405a9674404a56a4db80d22341e"
};

const selector = document.getElementById("selector");

const createMap = (id) => {
  const vectorTileLayer = new VectorTileLayer({
    portalItem: {
      id
    }
  });

  const basemap = new Basemap({
    baseLayers: [vectorTileLayer]
  });

  const map = new Map({
    basemap: basemap
  });

  const view = new MapView({
    container: "map",
    map: map,
    zoom: 12,
    center: [139.768435, 35.681054]
  });  
}

selector.addEventListener("change", (id) => {
  createMap(IDS[selector.value]);
});

createMap(IDS['default']);

結果は以下のとおりです。

また、Basemapの変更には専用のUIが用意されているのでこれらを使用するのが便利です。

ソース + レイヤー = スタイル(番外編)

Mapboxの記事にもあった、スタイルを手動で作成する方法を試してみます。VectorTileLayerはJSONのスタイルを直接受け取ることもできるので、以下のように記述するだけでOKです。スタイルの記法自体はMapboxと同じです。

const vectorTileLayer = new VectorTileLayer({
  style: {
    version: 8,
    sources: {
      esri: {
        type: "vector",

        tiles: [
          `https://basemaps-api.arcgis.com/arcgis/rest/services/World_Basemap_v2/VectorTileServer/tile/{z}/{y}/{x}.pbf?token=${config.apiKey}`
        ]
      }
    },
    layers: [
      {
        id: "road",
        type: "line",
        source: "esri",
        "source-layer": "Road",
        paint: {
          "line-color": "#00ff00",
          "line-width": 3
        }
      }
    ]
  }
});

結果は以下のとおりです。

まとめ

ArcGISではMapboxのスタイルが採用され、VTSEを用いて直感的に編集することができます。Mapbox Studioと似たツールでわかりやすいです。スタイル自体はJavaScriptのコード上では一つのレイヤーとして扱われる点はMapboxと異なるので注意が必要です。

他にもWebダッシュボード等のツール・ドキュメント・サンプルも豊富で使い勝手の良いサービスだと思いました。

GitHubで編集を提案
マップボックス・ジャパン合同会社

Discussion