【HERE】Maps API for JavaScriptを試してみた！

## はじめに
:::note info
この記事は [【HERE WeGo!】ジオファン集まれ！地理空間情報、地図に関する記事を募集しています by HERE Advent Calendar 2022](https://qiita.com/advent-calendar/2022/here) 11日目の記事です。
:::

HEREのMaps API for JavaScriptのうち、HERE Vector Tile、Geocoding、Reverse Geocoding、Routingを試してみました。

### 動作環境
OS: Window 10
HERE Maps API for JavaScript: バージョン 3.1

### HEREとは
地図データ・位置情報テクノロジーのパイオニア企業です。
位置情報プラットフォームとして、地図表示、ルート検索、ジオコーディングなどの位置情報サービスや、HERE SDKやHERE Studioなどの開発者向けのツールなどを提供しています。

https://www.here.com/jp/company/about-us

https://www.here.com/jp/platform

### Maps API for JavaScript
Javascript 用の HERE Maps APIです。
執筆当時に利用可能なサービスは以下の通りでした。たくさんある・・！

>HERE Geofencing
HERE Isoline Routing
HERE Map Attributes
HERE Routing
HERE Routing - Transit
HERE Transit - Next Departures
HERE Transit - Station Search
HERE Vector Tile
HERE Search - Autosuggest
HERE Search - Browse
HERE Search - Discover
HERE Search - Forward Geocoder
HERE Search - Places ID Lookup
HERE Search - Reverse Geocoder

引用元：[HERE Maps API for JavaScript Get Started](https://developer.here.com/documentation/maps/3.1.36.0/dev_guide/topics/quick-start.html)

## 事前準備
私はHEREのソリューションを初めて使うので、HEREのアカウントを登録してAPIキーを作成する必要があります。
手順は以下の記事に丁寧にまとまっています。
この記事を参考に、事前準備を進めてみます :runner: 

https://qiita.com/kekomat/items/d2e29bac84a27c1ec521

### アカウント作成
HEREのソリューションを利用するために、HEREのアカウントを作成します。

#### 料金プラン
HEREの料金プランは無料プランと有料プランがあるようです。
今回は、クレジットカード登録不要で無料のLimited Planで登録しようと思います。

>HERE platform (英語)には、無料のLimited Plan と Base Plan、二つのプラン があります。両プランともにHERE REST APIs, HERE Maps API for JavaScript, 各種管理ツールが利用でき、Stack Overflow 上でのコミュニティベースのサポートや knowledge base にアクセス可能です。Base Planは有償の Developer Support plan を追加いただくことも可能です。

>Limited Plan は、クレジットカードは不要で登録でき、HERE Location Services (*matrix routing と tour planningを除く) 1日1000件のリクエストが可能です。(1秒あたりのリクエスト数 RPS制限があります)。 
Base Plan は、登録時にクレジットカードが必要となりますが、無料利用枠を超えない限り課金されることはありません。この pay-as-you-grow Transaction pricing は、リストに掲載されている全ての HERE Location Services に適用されます。さらに、Data Services, HERE Studio や HERE Lite, Explore and Data SDKsにもアクセス可能です。詳細は下記をご覧ください。

引用元：[HERE platformの利用開始方法
](https://www.here.com/jp/learn/blog/how-to-get-started-with-here-platform)

#### 本人確認
[このページ](https://www.here.com/get-started/pricing)や[このページ](https://developer.here.com/)などから、「Get started for free」ボタンを押します。
ボタンを押すと、本人確認画面が表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2667439/fbcddd2a-9b15-edb0-ff28-101d8b542013.png)

名前、メールアドレス、セキュリティコードを入力します。


以下が個人的に気になった点です。

:::note info
:smile: Good Point
- 遷移前のHERE Base Plan画面は英語なのに、遷移後の本人確認画面は日本語になってる
    - ユーザの国を判断して翻訳してくれてるのかな・・？アカウント登録で母国語なのは安心感があっていいですね！
:::

:::note warn
:worried: Bad Point
- "Get started for free" を押してからのレスポンスがちょっと遅い
    - 初回アクセスは5秒くらい待ちました。2回目以降はキャッシュの影響か3秒程度と早くなりました。
- 本人確認画面で入力フォームに文字を入れて他の入力フォームに移ると、すでに入れた文字がグレーアウトされている
    - 他のサイトではあまり見ない形式だなあと思いました。グレーアウトすると、もう編集できないの？ｱｾｱｾ となりますが、再編集は可能でした。
- 会社名は任意とあるが、入力しないと「別の名前を使用してください。」と出てきて入力必須っぽくなってる
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2667439/951caaf7-3199-26bf-b98e-97721839a92f.png)
    - なぜか、何を入れてもはねられる。。
    - リロードしたり、別のページからアクセスしたり、キャッシュを削除したり、会社名を入れたりと、何度かトライしたらできました。。
:::

本人確認画面の入力に成功すると、認証メールが送信されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2667439/ee68071a-8262-62f8-8982-bde27054b534.png)

#### アカウント認証
認証メールは以下でした。英語でした。
「Verify email」ボタンをクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2667439/4548b91e-88c2-b8ba-fac1-6f47e031dbc0.png)
画面遷移は5秒程度かかりました。

#### アカウント情報入力
自分の住んでいる国を選択して、パスワードを入力します。
ここではメールアドレスはグレーアウトしていて、編集できないようになってました。
利用規約の同意にチェックボックスをつけて、「次へ」ボタンをクリックします。
画面遷移は10秒程度かかりました。。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2667439/00caddcb-3e71-f330-3ed5-855ab02dae9b.png)

#### 請求情報入力
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2667439/28928256-a712-19f8-f470-dc0a21f78303.png)

今回は、「請求の詳細をスキップ」をクリックします。
位置情報サービスのリクエストは1日あたり1000 件までに制限されます。あとで支払情報を追加することも可能です。
画面遷移は5秒程度かかりました。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2667439/f2f1be5f-e0b7-fedc-c42b-d73ef0129663.png)

アカウントを作成できました！！

### Maps API for JavaScriptの利用
HERE プラットフォームにアクセスして、「JavaScript 用の Maps API で始める」をクリックします
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2667439/89b989dc-22d0-fc26-bd33-7886886830c5.png)

利用手順が書かれたポップアップが表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2667439/885685cf-dd06-2080-97a1-193758740fce.png)

アクセスマネージャでアプリを登録したのちに、APIキーを作成する必要があるようです。

https://developer.here.com/documentation/identity-access-management/dev_guide/topics/plat-using-apikeys.html

#### アクセスマネージャでアプリ登録
任意のアプリ名を入力して、「登録」をクリックします。
画面遷移は5秒程度かかりました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2667439/7f88ca3c-b5d5-09e6-89e8-339a0bf92c06.png)

アプリを作成できました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2667439/cbb670aa-2965-613d-51bc-0027bb1de15d.png)

#### APIキー作成
資格情報タブから、「APIキー」をクリックして、「APIキーを作成」ボタンをクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2667439/da7598dc-b84f-d0e0-7802-97bdbdeb14b3.png)

APIキーを作成できました！
1つのアプリで2つまでAPIキーを作成できるようです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2667439/990e3e86-11d8-7866-a062-9f40b5ee0a8b.png)

## HERE Vector Tile
### 機能
HEREプラットフォームからベクタータイルを表示できる機能です。

### ソースコード

```index.html
<!DOCTYPE html>
<html lang="ja">
    <head>
        <meta charset="utf-8" />
        <title>サンプル</title>
        <meta name="description" content="サンプルです" />
        <link href="style.css" rel="stylesheet" />
        <meta name="viewport" content="initial-scale=1.0, width=device-width" />
        <!-- HERE -->
        <link rel="stylesheet" type="text/css" href="https://js.api.here.com/v3/3.1/mapsjs-ui.css" />
        <script type="text/javascript" src="https://js.api.here.com/v3/3.1/mapsjs-core.js"></script>
        <script type="text/javascript" src="https://js.api.here.com/v3/3.1/mapsjs-service.js"></script>
        <script type="text/javascript" src="https://js.api.here.com/v3/3.1/mapsjs-ui.js"></script>
        <script type="text/javascript" src="https://js.api.here.com/v3/3.1/mapsjs-mapevents.js"></script>
    </head>
    <body>
        <div id="mapContainer"></div>
        <script src="main.js"></script>
    </body>
</html>
```

HEREのモジュールを読み込みます。
idがmapContainerとなっているdivタグに地図を埋め込みます。
このあたりはLeafletやMapLibre GL JS、OpenLayersなど他のマップライブラリと同様です。

```style.css
body {
    margin: 0;
    padding: 0;
}
#mapContainer {
    position: absolute;
    top: 0;
    bottom: 0;
    width: 100%;
}
```

スタイルを定義します。
画面いっぱいに地図が表示されるようにしました。

```main.js
// APIキーの設定
var platform = new H.service.Platform({
    apikey: '{YOUR_API_KEY}',
});

// ベクタータイルサービスオブジェクトが日本のデータを提供するコアエンポイントを使用するように設定
var omvService = platform.getOMVService({ path: 'v2/vectortiles/core/mc' });
var baseUrl = 'https://js.api.here.com/v3/3.1/styles/omv/oslo/japan/';

// 日本のデータを表示するためのマップスタイルを設定
var style = new H.map.Style(`${baseUrl}normal.day.yaml`, baseUrl);

//  ベースマップ用のプロバイダとレイヤーを設定
var omvProvider = new H.service.omv.Provider(omvService, style);
var omvlayer = new H.map.layer.TileLayer(omvProvider, { max: 22 });

// 地図を表示
var map = new H.Map(document.getElementById('mapContainer'), omvlayer, {
    zoom: 17,
    center: { lat: 35.4660694, lng: 139.6226196 },
});

// 地図の動作機能（パンやズームなど）の追加
window.addEventListener('resize', () => map.getViewPort().resize());
var behavior = new H.mapevents.Behavior(new H.mapevents.MapEvents(map));
```
'{YOUR_API_KEY}'には上で取得したAPIキーを指定します。

日本固有のデータとマップスタイルを使ってみました。

中心座標の定義の仕方はよいですね。（いつも[lat, lon]? [lon, lat]?と順番が分からなくなるため）

 H.mapevents.Behavior を定義しないと、地図をズームしてもズームレベルに応じてタイルが変わらなかったり、地図を自由に移動できなくなります。このあたりは他のマップライブラリでは意識したことなかったので驚きでした。

### 画面表示
横浜駅周辺を表示してみました。
地図のスタイル、他の地図と比べてオシャレでスマートな感じがします！
どぎつい色がなくて、目に優しい配色ですね。

駅についている◎のシンボル（地図記号でいうと市役所）はラベルもないけどなんだろう。あれ、ズームアウトしたらラベルが表示された。サービスセンターでした。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2667439/8bd90f64-864e-6da0-a08c-077dce6ce345.png)

ベクタータイルだと、建物の高さが分かっていいですね～
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2667439/2b6d76ec-2594-0fce-1082-dc363f1362fd.png)



### 参考
https://developer.here.com/documentation/examples/vector-tiles

https://jp.developer.here.com/documentation/vector-tiles-api/dev_guide/topics/examples/jsla.html

https://developer.here.com/documentation/maps/3.1.36.0/dev_guide/topics/get-started-japan.html

https://developer.here.com/tutorials/js-map-for-japan/


## Geocoding
### 機能
ジオコーディングができる機能です。
ジオコーディングとは、住所や地名から地理座標を取得することです。

### ソースコード
html, cssは上と一緒です。

```main.js
// APIキーの設定
var platform = new H.service.Platform({
    apikey: '{YOUR_API_KEY}',
});

// ベクタータイルサービスオブジェクトが日本のデータを提供するコアエンポイントを使用するように設定
var omvService = platform.getOMVService({ path: 'v2/vectortiles/core/mc' });
var baseUrl = 'https://js.api.here.com/v3/3.1/styles/omv/oslo/japan/';

// 日本のデータを表示するためのマップスタイルを設定
var style = new H.map.Style(`${baseUrl}normal.day.yaml`, baseUrl);

//  ベースマップ用のプロバイダとレイヤーを設定
var omvProvider = new H.service.omv.Provider(omvService, style);
var omvlayer = new H.map.layer.TileLayer(omvProvider, { max: 22 });

// 地図を表示
var map = new H.Map(document.getElementById('mapContainer'), omvlayer, {
    zoom: 17,
    center: { lat: 35.4660694, lng: 139.6226196 },
});

// 地図の動作機能（パンやズームなど）の追加
window.addEventListener('resize', () => map.getViewPort().resize());
var behavior = new H.mapevents.Behavior(new H.mapevents.MapEvents(map));

// ジオコーディングサービスを利用する
var service = platform.getSearchService();

// パラメータを指定してgeocodeメソッドを呼び出す
service.geocode(
    {
        q: '神奈川県横浜市西区高島2丁目14−9',
    },
    (result) => {
        // マーカーを追加
        result.items.forEach((item) => {
            map.addObject(new H.map.Marker(item.position));
        });
    },
    alert
);
```
横浜駅周辺の「アソビル」という商業施設の住所をジオコーディングして、地図上にマーカーを表示します。

### 画面表示
アソビルにマーカーが表示されました！
デフォルトのマーカーが風船みたいで可愛いですね。
LeafletやMapLibre GL JSのデフォルトのマーカーはピン:round_pushpin:なので、HEREはちょっと独特ですね。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2667439/59edd5eb-7947-b409-fbb0-6662d0618be3.png)

### 参考
https://developer.here.com/documentation/geocoding-search-api/dev_guide/index.html

https://developer.here.com/documentation/maps/3.1.36.0/dev_guide/topics/geocoding.html

## Reverse Geocoding
### 機能
逆ジオコーディングができる機能です。
逆ジオコーディングとは、ジオコーディングの逆で、地理座標から住所や地名を取得することです。

### ソースコード
html, cssは上と一緒です。

```main.js
// APIキーの設定
var platform = new H.service.Platform({
    apikey: '{YOUR_API_KEY}',
});

// ベクタータイルサービスオブジェクトが日本のデータを提供するコアエンポイントを使用するように設定
var omvService = platform.getOMVService({ path: 'v2/vectortiles/core/mc' });
var baseUrl = 'https://js.api.here.com/v3/3.1/styles/omv/oslo/japan/';

// 日本のデータを表示するためのマップスタイルを設定
var style = new H.map.Style(`${baseUrl}normal.day.yaml`, baseUrl);

//  ベースマップ用のプロバイダとレイヤーを設定
var omvProvider = new H.service.omv.Provider(omvService, style);
var omvlayer = new H.map.layer.TileLayer(omvProvider, { max: 22 });

// 地図を表示
var map = new H.Map(document.getElementById('mapContainer'), omvlayer, {
    zoom: 17,
    center: { lat: 35.4660694, lng: 139.6226196 },
});

// 地図の動作機能（パンやズームなど）の追加
window.addEventListener('resize', () => map.getViewPort().resize());
var behavior = new H.mapevents.Behavior(new H.mapevents.MapEvents(map));

// ジオコーディングサービスを利用する
var service = platform.getSearchService();

// UIコンポーネントを定義
var ui = H.ui.UI.createDefault(map, omvlayer);

// パラメータを指定してreverseGeocodeメソッドを呼び出す
service.reverseGeocode(
    {
        at: '35.465389644663,139.62502306642',
    },
    (result) => {
        result.items.forEach((item) => {
            // 住所を表示する
            ui.addBubble(
                new H.ui.InfoBubble(item.position, {
                    content: item.address.label,
                })
            );
        });
    },
    alert
);
```

横浜駅周辺の「そごう美術館」の緯度経度を逆ジオコーディングして、地図上に住所を表示します。
[サンプルコード](https://developer.here.com/documentation/maps/3.1.36.0/dev_guide/topics/geocoding.html)では、UIコンポーネントの定義が抜けていてnot defined エラーが出てしまいましたが、定義を追加したところうまく動作しました。

### 画面表示
そごう美術館に住所が表示されました！
郵便番号も取得できるのはよいですね。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2667439/bff8c491-aafc-307d-ea6e-d6601055350f.png)


### 参考
https://developer.here.com/documentation/geocoding-search-api/dev_guide/index.html

https://developer.here.com/documentation/maps/3.1.36.0/dev_guide/topics/geocoding.html

## Routing
### 機能
地点間のルート検索ができる機能です。
TransportModesで移動手段を指定可能です。執筆当時の移動手段のリストは以下です。

>car: 車のルーティングで、速度制限や進行方向などのリンク ルールと制限に従います。有効な場合、トラフィックを考慮することができます。
carHOV: 車のルーティングと同じですが、HOV (high-occupancy vehicle) の車線と道路も使用できます。
pedestrian: 歩行者用のルーティング。リンクの歩行者の操作性を考慮しますが、トラフィックは無視します。
truck: トラックのルーティング。物理的、危険物、およびトレーラーの制限を考慮します。有効な場合、トラフィックを考慮することができます。
bicycle: 自転車のルーティング。現在はベータ版です。歩行者専用道路網を利用。道路が車と歩行者の両方に開放されている場合、または公園内の歩行者専用道路である場合、その道路は自転車用に開放されていると見なされます。ルーティング アルゴリズムは、一方通行の道路を逆走するなど、サイクリングに開放されていない道路を考慮する場合がありますが、歩行速度のみです。このモードでは交通情報は使用されません。

引用元：[HERE Routing API Transport Mode](https://developer.here.com/documentation/routing/dev_guide/topics/transport-modes.html) を一部日本語訳

### ソースコード
```main.js
// APIキーの設定
var platform = new H.service.Platform({
    apikey: '{YOUR_API_KEY}',
});

// ベクタータイルサービスオブジェクトが日本のデータを提供するコアエンポイントを使用するように設定
var omvService = platform.getOMVService({ path: 'v2/vectortiles/core/mc' });
var baseUrl = 'https://js.api.here.com/v3/3.1/styles/omv/oslo/japan/';

// 日本のデータを表示するためのマップスタイルを設定
var style = new H.map.Style(`${baseUrl}normal.day.yaml`, baseUrl);

//  ベースマップ用のプロバイダとレイヤーを設定
var omvProvider = new H.service.omv.Provider(omvService, style);
var omvlayer = new H.map.layer.TileLayer(omvProvider, { max: 22 });

// 地図を表示
var map = new H.Map(document.getElementById('mapContainer'), omvlayer, {
    zoom: 17,
    center: { lat: 35.4660694, lng: 139.6226196 },
});

// 地図の動作機能（パンやズームなど）の追加
window.addEventListener('resize', () => map.getViewPort().resize());
var behavior = new H.mapevents.Behavior(new H.mapevents.MapEvents(map));

// ルーティングのパラメータを設定
var routingParameters = {
    routingMode: 'fast',
    transportMode: 'pedestrian',
    // スタート地点
    origin: '35.464037228893,139.62207585441',
    // ゴール地点
    destination: '35.465389644663,139.62502306642',
    return: 'polyline',
};

// ルーティングの結果を処理する関数を定義
var onResult = function (result) {
    if (result.routes.length) {
        result.routes[0].sections.forEach((section) => {
            // ルートラインのラインストリングを作成
            let linestring = H.geo.LineString.fromFlexiblePolyline(section.polyline);

            // ルートを表示するためのポリラインを作成
            let routeLine = new H.map.Polyline(linestring, {
                style: { strokeColor: 'blue', lineWidth: 3 },
            });

            // スタート地点のマーカーを表示
            let startMarker = new H.map.Marker(section.departure.place.location);

            // ゴール地点のマーカーを表示
            let endMarker = new H.map.Marker(section.arrival.place.location);

            // ルートのポリラインと、スタート地点とゴール地点のマーカーを追加する
            map.addObjects([routeLine, startMarker, endMarker]);
        });
    }
};

// ルーティングサービス（バージョン8）を利用
var router = platform.getRoutingService(null, 8);

// ルーティングパラメータを指定して calculateRoute()を呼び出す
router.calculateRoute(routingParameters, onResult, function (error) {
    alert(error.message);
});
```

移動手段には歩行者を指定しました。
スタート地点には「アソビル」、ゴール地点には「そごう美術館」の緯度経度を指定しました。

### 画面表示
アソビルからそごう美術館までのルートを表示できました！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2667439/0f38f5cf-0efd-199f-4cd6-cdff1ef877d0.png)

移動手段を車に指定すると、結果が変わりました！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2667439/bff4fb75-0ca1-b97d-a724-a57a4a8b1d04.png)


### 参考
https://developer.here.com/documentation/maps/3.1.36.0/dev_guide/topics/routing.html

https://developer.here.com/documentation/examples/maps-js/services/map-with-route-from-a-to-b

## おわりに
初めてHEREのAPIを使ってみましたが、ベクタータイルもスタイリッシュでジオコーディングやルーティングもできて多機能で面白かったです！
他のAPIも試してみたいですね。