📚

TomTomのスタイルを体験する

2023/04/12に公開

はじめに

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

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

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

地図を表示する

チュートリアルを参考に地図を表示してみましょう。

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

<link rel="stylesheet" href="https://api.tomtom.com/maps-sdk-for-web/cdn/6.x/<version>/maps/maps.css" />
<script src="https://api.tomtom.com/maps-sdk-for-web/cdn/6.x/6.23.0/maps/maps-web.min.js"></script>

CSSを設定します。

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

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

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

JavaScriptのコードは以下のようになります。

const map = tt.map({
  key: YOUR_API_KEY_HERE,
  container: 'map',
  center: [139.768435, 35.681054],
  zoom: 8,
});

map.addControl(new tt.FullscreenControl());
map.addControl(new tt.NavigationControl());

Mapクラスのコンストラクタにはオプションを設定します。最低限、keycontainerは設定する必要があります。この他にもcenterzoomで初期位置等が設定できます。

addControlでは全画面表示、ズーム等のコントロールを表示しています。

スタイルの変更

スタイルはMap Style Specificationで定義されたJSONオブジェクトです。Mapオブジェクト作成時のオプションとしてstyleが設定可能で、JSONファイルのURLやJSONオブジェクトそのものを指定することで設定ができます。またMap#setStyleを使用することで動的にスタイルを変更することも可能です。早速これらを使ってみましょう。

まず、スタイルを選択できるようにします。

<select id="selector">
  <option value="day">Day</option>
  <option value="night">Night</option>
</select>

<select>が隠れないように、CSSを調整します

#map { position: absolute; top: 10; bottom: 0; height: 95%; width: 100%; }

コードでは、まず各スタイルのURLを定義します。Mapオブジェクト作成時にstyleでURLを指定します。また、<select>による選択時にsetStyleでスタイルを切り替えます。

const URLS = {
  day: 'https://api.tomtom.com/style/1/style/21.1.0-*?map=basic_main&traffic_incidents=incidents_day&traffic_flow=flow_relative0&poi=poi_main',
  night: 'https://api.tomtom.com/style/1/style/21.1.0-*?map=basic_night&traffic_incidents=incidents_day&traffic_flow=flow_relative0&poi=poi_main',
};

const map = tt.map({
  key: YOUR_API_KEY_HERE,
  container: 'map',
  style: URLS['day'],
  center: [139.768435, 35.681054],
  zoom: 8,
});

map.addControl(new tt.FullscreenControl());
map.addControl(new tt.NavigationControl());

selector.addEventListener("change", () => {
    map.setStyle(URLS[selector.value]);
});

スタイルのカスタム

Map Stylerというサービスを使用すると、スタイルを編集することができます。ここでは高速道路の色を赤色にします。

左側にレイヤーが並んでいるので、Surface Motorway & Trunkを選択します。

Map Stylerでの編集

中程のPAINT PROPERTIESのColorのExpressionsを以下のように変更します。

[
  "interpolate",
  ["exponential", 1],
  ["zoom"],
  5,
  [
    "match",
    ["get", "category"],
    "motorway",
    "#FF0000", //ここ
    "trunk",
    "hsl(37, 80%, 60%)",
    "hsla(0, 0%, 0%, 0)"
  ],
  9,
  [
    "match",
    ["get", "category"],
    "motorway",
    "#FF0000", //ここ
    "trunk",
    "hsl(47, 100%, 80%)",
    "hsla(0, 0%, 0%, 0)"
  ]
]

変更が右側のプレビューで即座に反映されます。最後にEXPORTをクリックするとスタイルのJSONファイルをダウンロードできます。今回はGist上にファイルを置きました。

さて、このJSONファイルをJavaScriptのコードで読み込めばOKです。当初以下のように実装していました。セレクタで選択されると、default/customのURLを切り替えてsetStyleという挙動です。

const URLS = {
  default: 'https://api.tomtom.com/style/1/style/21.1.0-*?map=basic_main&traffic_incidents=incidents_day&traffic_flow=flow_relative0&poi=poi_main',
  custom: 'https://gist.githubusercontent.com/OttyLab/f4526ddf444b8f4add296ad337bcc601/raw/d220f74a6425ccda1d24da6c3594f7677683b6ac/tomtom_custom.json',
};

const map = tt.map({
  key: YOUR_API_KEY_HERE,
  container: 'map',
  style: URLS['day'],
  center: [139.768435, 35.681054],
  zoom: 8,
});

map.addControl(new tt.FullscreenControl());
map.addControl(new tt.NavigationControl());

selector.addEventListener("change", () => {
    map.setStyle(URLS[selector.value]);
});

しかし、このコードはCORSエラーで動きませんでした。挙動をデバッグしてみるとfetchでGETリクエストする際にTomTom-User-Agentというヘッダが付加されており、これにより単純リクエストではなくなってCORSエラーとなっているようでした。以下の画像がTomTom-User-Agentを付加している場所ですが、外部からこの挙動を変更できそうになかったです。

TomTom-User-Agentヘッダ

そこで今回は以下のように自前でfetchを呼び、予めJSONをダウンロードしておくことで回避しました。

const custom = (async () => {
  const response = await fetch('https://gist.githubusercontent.com/OttyLab/f4526ddf444b8f4add296ad337bcc601/raw/d220f74a6425ccda1d24da6c3594f7677683b6ac/tomtom_custom.json');

  const custom = await response.json();
  
  const URLS = {
  default: 'https://api.tomtom.com/style/1/style/21.1.0-*?map=basic_main&traffic_incidents=incidents_day&traffic_flow=flow_relative0&poi=poi_main',
  custom: custom,
};

  const map = tt.map({
    key: YOUR_API_KEY_HERE,
    container: 'map',
    style: URLS['day'],
    center: [139.768435, 35.681054],
    zoom: 8,
  });

  map.addControl(new tt.FullscreenControl());
  map.addControl(new tt.NavigationControl());

  selector.addEventListener("change", () => {
    map.setStyle(URLS[selector.value]);
  });
})();

自前のサーバにJSONを配置する際は、Access-Control-Allow-Originを正しく設定することでこの問題は回避できます。

Mapbox GL JSとの互換性(番外編)

とくに記述はありませんが、TomTomのStyleはMapboxのスタイルと互換性があります。したがって、Mapbox GL JSでTomTomのスタイルを読み込むと表示できます。左下にMapboxロゴが表示されているのでMapbox GL JS上でスタイルが動いていることがわかります。

実はデバッグをしていて気づいたのですが、Maps SDK for Web V6は内部でMapbox GL JS v1.13.2を使用しています。以下のコードはMaps SDK for Web V6におけるMapオブジェクトの初期化処理の一部ですが、Mapbox GL JSのMapオブジェクトを作成しています。

Mapオブジェクトの初期化

また、以下はMapbox GL JSのテレメトリのコードであると推察されます。

Mapbox GL JS固有のコード

Mapbox GL JSを内部的に使用しているのであればスタイルが同じ形式であるのも、ライブラリの使い方が似ているのも納得できます。

まとめ

TomTomにおけるスタイルはMapbox GL JSと互換性があり、ソースやレイヤーの概念も同じです。したがって、Mapbox GL JSを知っていれば特に違和感なくTomTomも使用できるかと思います。また、Map StylerもMapbox Studioと似た使用感なので学習コストは低いと考えられます。

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

Discussion