地図検索アプリのソースをMapBoxからOpenLayersに差し替える

以前、MonacaとNCMBを使った地図検索アプリを作りました。

- [Monaca × NCMBで位置情報検索アプリを作る（その1：画面と仕様について）](https://blog.mbaas.nifcloud.com/entry/2021/10/19/110301)
- [Monaca × NCMBで位置情報検索アプリを作る（その2：位置情報データのインポート）](https://blog.mbaas.nifcloud.com/entry/2021/10/19/110449)
- [Monaca × NCMBで位置情報検索アプリを作る（その3：位置情報検索と地図表示）](https://blog.mbaas.nifcloud.com/entry/2021/10/19/110508)

この時にはMapBoxの地図を表示していますので、MapBoxのアカウント取得が必要でした。今回は地図ライブラリをOpenLayersに変更し、アカウント取得不要にしてみました。

そのMapBox版とOpenLayers版との差分について解説します。

![0941 localhost - 0321120515.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/d3d5cec4-d34b-4652-947f-000e8255e365.jpeg)

## コード

実際のコードは[NCMBMania/monaca-map-app-openlayers](https://github.com/NCMBMania/monaca-map-app-openlayers)にあります。実装時の参考にしてください。

## 読み込むライブラリの違い

MapBox版では以下のJavaScript、CSSを読み込みます。

```html
<link href='https://api.mapbox.com/mapbox-gl-js/v2.3.1/mapbox-gl.css' rel='stylesheet' />
<script src='https://api.mapbox.com/mapbox-gl-js/v2.3.1/mapbox-gl.js'></script>
```

OpenLayersでは以下になります（これは開発用途なので、プロダクションではDLした上で使うのがお勧めです。

```html
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/ol@v7.3.0/ol.css">
<script src="https://cdn.jsdelivr.net/npm/ol@v7.3.0/dist/ol.js"></script>
```

## 地図の初期化

MapBox版は以下のように初期化を行います。MapBoxのAPIキーは必須です。

```jsx
mapboxgl.accessToken = mapboxAccessToken;
map = new mapboxgl.Map({
  container: 'map',
  style: 'mapbox://styles/mapbox/streets-v11',
  center: [139.7454329, 35.6585805], // 東京タワーの位置情報
  zoom: 14
});
```

それに対してOpenLayersでは以下のようになります。コード量は多くなります。

```jsx
// OpenLayerを準備
map = new ol.Map({
  target: 'map',
  layers: [
    new ol.layer.Tile({
      source: new ol.source.XYZ({
        url: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png'
      })
    })
  ],
  view: new ol.View({
    center: ol.proj.fromLonLat([139.7454329, 35.6585805]), // 東京タワーの位置情報
    zoom: 14,
  })
});
// マーカー用のVectorLayerを作成
const markerLayer = new ol.layer.Vector({
  source: new ol.source.Vector(),
});
map.addLayer(markerLayer);
```

## 地図をタップした際の位置情報取得

MapBoxの場合は、タップイベントから緯度経度が簡単に取得できます。

```jsx
const {lng, lat } =  e.lngLat;
```

それに対してOpenLayersではcoordinateから変換が必要です。

```jsx
const [lng, lat] = ol.proj.toLonLat(e.coordinate);
```

## 地図にマーカーを追加する

MapBox版は分かりやすいです。

```jsx
const marker = new mapboxgl.Marker()
  .setLngLat([lng, lat])
  .addTo(map);
```

OpenLayersの場合はちょっと複雑です。あらかじめレイヤーを追加しておき、そのレイヤーに対してマーカーを追加します。

```jsx
const markerStyle = new ol.style.Style({
  image: new ol.style.Icon({
    anchor: [0.5, 1],
    src: 'assets/icons/marker.png',
  }),
});

const marker = new ol.Feature({
  geometry: new ol.geom.Point(coordinate),
});
marker.setStyle(markerStyle);
map.getLayers().getArray()[1].getSource().addFeature(marker);
```

## マーカーを削除する

MapBox版はマーカーオブジェクトを消す、という分かりやすい書き方です。

```jsx

marker.remove();
```

OpenLayersの場合は該当マーカーをレイヤーから消すという指定です。

```jsx
map.getLayers().getArray()[1].getSource().removeFeature(marker);
```

## マーカーから位置情報を取得する

NCMBの位置情報検索は緯度経度が必要なので、マーカーから位置情報を取得します。MapBox版は次のようになります。

```jsx
const {lng, lat} = marker._lngLat
```

OpenLayersの場合はかなり複雑です。もっと良い取得方法があるかも知れません。

```jsx
const [lng, lat] = ol.proj.toLonLat(marker.getGeometry().flatCoordinates);
```

## まとめ

OpenLayersの場合、若干コード量が多いのとMapBoxと比べて操作が分かりづらいのが難点かも知れません。アイコン画像もあらかじめ用意しておく必要があります。

しかし、アカウント取得やAPIキーなしで使えるのは魅力的です。関数などで複雑そうに見える部分を隠せれば、OpenLayersを使って地図表示を行うのは良さそうです。