ReactでプレーンなLeafletとMapbox GL JSとOpenLayersの開発環境を構築してみた

![try-045_05.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/60444/e3fe82b4-a7dd-2276-8550-4820a819a07f.gif)

<br>

![react.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/60444/ea0976de-3db3-8363-7f63-09159dd47013.png)

![leaflet.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/60444/67729a2c-aebe-b7c1-eba3-c43e93fa6181.png)

![mapboxgljs.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/60444/ac9af97c-ba16-82ae-e0fe-38e32427088e.png)

![openlayers.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/60444/02ab5b41-bf1c-7b64-25b9-d30edefb11c0.png)

<br>

### ReactでプレーンなLeafletとMapbox GL JSとOpenLayersの開発環境を構築してみました :tada:  

ReactでLeafletとMapbox GL JSとOpenLayersを利用する時に、ラッパーライブラリを利用しているかたもいると思いますが、今回はプレーンな開発環境を構築してみました！

<br>

## 1. 事前準備

- Reactの環境準備  
    - [React #002 – TypeScript環境構築](https://memo.dayjournal.dev/memo/react-002/)
    - node v14.8.0
    - npm v6.14.8
    - React v16.13.1
    - TypeScript v3.7.5

<br>

## 2. 共通設定

#### tsconfig.json

```json
{
    "compilerOptions": {
        "target": "es5",
        "lib": ["dom", "dom.iterable", "esnext"],
        "allowJs": true,
        "skipLibCheck": true,
        "esModuleInterop": true,
        "allowSyntheticDefaultImports": true,
        "strict": true,
        "forceConsistentCasingInFileNames": true,
        "module": "esnext",
        "moduleResolution": "node",
        "resolveJsonModule": true,
        "isolatedModules": true,
        "noEmit": true,
        "jsx": "react",
        // 暗黙のany型をエラーにしない
        "noImplicitAny": false
    },
    "include": ["src"]
}
```

ライブラリがうまく動作しないので、今回は暗黙のany型をエラーにしない設定をします。

```json
// 暗黙のany型をエラーにしない
"noImplicitAny": false
```

<br>

/src

#### index.tsx

```tsx
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import MapPane from './MapPane';
import * as serviceWorker from './serviceWorker';

ReactDOM.render(
    <React.StrictMode>
        <App />
        <MapPane />
    </React.StrictMode>,
    document.getElementById('root')
);

serviceWorker.unregister();
```

新規作成する「MapPane.tsx」を、「index.tsx」で読み込みます。

```tsx
import MapPane from './MapPane';

<MapPane />
```

<br>

## 3. 各ライブラリ設定

### React x Leaflet

<br>

ライブラリをインストールします。

```shell

npm install leaflet
npm install @types/leaflet
```

<br>

次に、地図を表示させるためのコードを書きます。今回は、「MapPane.tsx」と「MapPane.css」を作成します。  

![try-045_01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/60444/db6534af-d085-9df8-ade7-c4cd984221a7.png)

/src

#### MapPane.tsx

```tsx
import React, { Component } from 'react';
// Leaflet読み込み
import L from 'leaflet';
import 'leaflet/dist/leaflet.css';
import './MapPane.css';

class MapPane extends Component {
    map: any;
    container: any;
    m_streets: any;

    componentDidMount() {
        // 背景地図設定
        this.m_streets = L.tileLayer(
            'https://api.maptiler.com/maps/jp-mierune-streets/256/{z}/{x}/{y}.png?key=[APIキー]',
            {
                attribution:
                    '<a href="https://maptiler.jp/" target="_blank">© MIERUNE</a> <a href="https://www.maptiler.com/copyright/" target="_blank">© MapTiler</a> <a href="https://www.openstreetmap.org/copyright" target="_blank">© OpenStreetMap contributors</a>',
            }
        );

        // マップ設定
        this.map = L.map(this.container, {
            center: [35.681, 139.767],
            zoom: 14,
            zoomControl: true,
            layers: [this.m_streets],
        });
    }

    render() {
        return <div className={'map'} ref={(e) => (this.container = e)} />;
    }
}

export default MapPane;
```

Leaflet関係のライブラリを読み込みます。

```tsx
// Leaflet読み込み
import L from 'leaflet';
import 'leaflet/dist/leaflet.css';
```

背景地図を設定します。

```tsx
// 背景地図設定
this.m_streets = L.tileLayer(
    'https://api.maptiler.com/maps/jp-mierune-streets/256/{z}/{x}/{y}.png?key=[APIキー]',
    {
        attribution:
            '<a href="https://maptiler.jp/" target="_blank">© MIERUNE</a> <a href="https://www.maptiler.com/copyright/" target="_blank">© MapTiler</a> <a href="https://www.openstreetmap.org/copyright" target="_blank">© OpenStreetMap contributors</a>',
    }
);
```

マップを設定します。

```tsx
// マップ設定
this.map = L.map(this.container, {
    center: [35.681, 139.767],
    zoom: 14,
    zoomControl: true,
    layers: [this.m_streets],
});
```

<br>

/src

#### MapPane.css

```css
.map {
    z-index: 0;
    height: 1000px;
    text-align: left;
}
```

<br>

ローカルサーバーで確認

```shell
npm start
```

<br>
       
ローカルサーバーを立ち上げると、マップが表示されます。

![sample01.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/60444/91391bb2-057a-9c97-6fca-05fc6676702c.gif)

<br>

### React x Mapbox GL JS

<br>

ライブラリをインストールします。

```shell
npm install mapbox-gl
npm install @types/mapbox-gl
```

<br>

次に、地図を表示させるためのコードを書きます。今回は、「MapPane.tsx」を作成します。  

![try-045_02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/60444/72688977-caf9-37fa-fd54-e23e4b5b9276.png)

<br>

/src

#### MapPane.tsx

```tsx
import React, { Component } from 'react';
// Mapbox GL JS読み込み
import mapboxgl from 'mapbox-gl';
import 'mapbox-gl/dist/mapbox-gl.css';
import './MapPane.css';

class MapPane extends Component {
    map: any;
    container: any;

    componentDidMount() {
        this.map = new mapboxgl.Map({
            container: this.container,
            style:
                'https://api.maptiler.com/maps/jp-mierune-streets/style.json?key=[APIキー]',
            center: [139.767, 35.681],
            zoom: 13,
        });

        // コントロール関係表示
        this.map.addControl(
            new mapboxgl.NavigationControl({
                visualizePitch: true,
            })
        );
    }

    render() {
        return <div className={'map'} ref={(e) => (this.container = e)} />;
    }
}

export default MapPane;
```

Mapbox GL JS関係のライブラリを読み込みます。

```tsx
// Mapbox GL JS読み込み
import mapboxgl from 'mapbox-gl';
import 'mapbox-gl/dist/mapbox-gl.css';
```

マップを設定します。

```tsx
// マップ設定
this.map = new mapboxgl.Map({
    container: this.container,
    style:
        'https://api.maptiler.com/maps/jp-mierune-streets/style.json?key=[APIキー]',
    center: [139.767, 35.681],
    zoom: 13,
});
```

コントロール関係を表示します。

```tsx
// コントロール関係表示
this.map.addControl(
    new mapboxgl.NavigationControl({
        visualizePitch: true,
    })
);
```

<br>

/src

#### MapPane.css

```css
.map {
    z-index: 0;
    height: 1000px;
    text-align: left;
}
```

<br>

ローカルサーバーで確認

```shell
npm start
```

<br>

ローカルサーバーを立ち上げると、マップが表示されます。

![try-045_05.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/60444/fa06fa6d-5cd7-fd15-a66c-8589eb4eab75.gif)

<br>

### React x OpenLayers

<br>

ライブラリをインストールします。

```shell
npm install ol
npm install @types/ol
```

<br>

次に、地図を表示させるためのコードを書きます。今回は、「MapPane.tsx」と「MapPane.css」を作成します。  

![try-045_03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/60444/9fa4c594-464e-e223-b7bf-e6f6cab0abd7.png)

<br>

/src

#### MapPane.tsx

```tsx
import React, { Component } from 'react';
// OpenLayers読み込み
import Map from 'ol/Map';
import View from 'ol/View';
import TileLayer from 'ol/layer/Tile';
import XYZ from 'ol/source/XYZ';
import { fromLonLat } from 'ol/proj';
import 'ol/ol.css';
import './MapPane.css';

class MapPane extends Component {
    map: any;
    container: any;

    componentDidMount() {
        // マップ設定
        this.map = new Map({
            target: this.container,
            layers: [
                new TileLayer({
                    source: new XYZ({
                        url:
                            'https://api.maptiler.com/maps/jp-mierune-streets/256/{z}/{x}/{y}.png?key=[APIキー]',
                        attributions:
                            '<a href="https://maptiler.jp/" target="_blank">© MIERUNE</a> <a href="https://www.maptiler.com/copyright/" target="_blank">© MapTiler</a> <a href="https://www.openstreetmap.org/copyright" target="_blank">© OpenStreetMap contributors</a>',
                        attributionsCollapsible: false,
                        tileSize: [256, 256],
                        minZoom: 0,
                        maxZoom: 18,
                    }),
                }),
            ],
            view: new View({
                center: fromLonLat([139.767, 35.681]),
                zoom: 14,
            }),
        });
    }

    render() {
        return <div className={'map'} ref={(e) => (this.container = e)} />;
    }
}

export default MapPane;
```

OpenLayers関係のライブラリを読み込みます。

```tsx
// OpenLayers読み込み
import Map from 'ol/Map';
import View from 'ol/View';
import TileLayer from 'ol/layer/Tile';
import XYZ from 'ol/source/XYZ';
import { fromLonLat } from 'ol/proj';
import 'ol/ol.css';
```

マップを設定します。

```tsx
// マップ設定
this.map = new Map({
    target: this.container,
    layers: [
        new TileLayer({
            source: new XYZ({
                url:
                    'https://api.maptiler.com/maps/jp-mierune-streets/256/{z}/{x}/{y}.png?key=[APIキー]',
                attributions:
                    '<a href="https://maptiler.jp/" target="_blank">© MIERUNE</a> <a href="https://www.maptiler.com/copyright/" target="_blank">© MapTiler</a> <a href="https://www.openstreetmap.org/copyright" target="_blank">© OpenStreetMap contributors</a>',
                attributionsCollapsible: false,
                tileSize: [256, 256],
                minZoom: 0,
                maxZoom: 18,
            }),
        }),
    ],
    view: new View({
        center: fromLonLat([139.767, 35.681]),
        zoom: 14,
    }),
});
```

<br>

/src

#### MapPane.css

```css
.map {
    z-index: 0;
    height: 1000px;
    text-align: left;
}
```

<br>

ローカルサーバーで確認

```shell
npm start
```

<br>

ローカルサーバーを立ち上げると、マップが表示されます。

![sample03.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/60444/34a508e6-ccce-c713-c03f-55b006adef41.gif)

<br>

#### ReactでプレーンなLeafletとMapbox GL JSとOpenLayersの開発環境の構築ができました :thumbsup: 

用途により直接読み込むかラッパーライブラリを利用するかの選択は必要となりそうですが、どちらにしてもReactでマップライブラリを利用することが可能です。実案件では、プレーンな機能やプラグインを利用できる今回の直接読み込むパターンを利用するのが自由度が高そうですが、マーカーを表示するなどのシンプルな用途であればラッパーライブラリを利用したほうが手軽で操作しやすいかもしれません :bulb:

#### お好きなマップライブラリでゼヒ試してみてください！

<br>

以前、「[ReactでLeafletとMapbox GL JSとOpenLayersの開発環境を構築してみた](https://qiita.com/dayjournal/items/3571704b671ba2a8c80b)」で紹介したラッパーライブラリの方法と比べてみて頂ければと思います！

<br>

React・Leaflet・Mapbox GL JS・OpenLayersについて、他にも記事を書いています。よろしければぜひ :bow:
<a href="https://memo.dayjournal.dev/memo/tags/react" target="_blank">tags - React</a>
<a href="https://memo.dayjournal.dev/memo/tags/leaflet" target="_blank">tags - Leaflet</a>
<a href="https://memo.dayjournal.dev/memo/tags/mapboxgljs" target="_blank">tags - Mapbox GL JS</a>
<a href="https://memo.dayjournal.dev/memo/tags/openlayers" target="_blank">tags - OpenLayers</a>

<br>
<br>

<a href="https://dayjournal.booth.pm" target="_blank"><img src="https://memo.dayjournal.dev/images/etc/book.png" alt="book"></a>