新型コロナ感染箇所マップを作ってみる【FastAPI/PostGIS/deck.gl(React)】（データ表示編）

こちらの記事は[新型コロナ感染箇所マップを作ってみる【FastAPI/PostGIS/deck.gl(React)】（データ加工編）](https://qiita.com/nokonoko_1203/items/579fc0133d0a2184da42)の続きです。

上の記事をご覧になってからお読みください！

# Reactの環境構築

ここまででcsvの元データをAPIからGeoJSON形式で吐き出せるようになっていると思いますので、そのデータを利用して地図上にコロナウイルス感染者の位置を表示できるようにしていきましょう！

まずはReactのプロジェクトを簡単に作成できる`create-react-app`を実行するための`Node.js`がインストールされているか確認しましょう

```shell-session
$node -v
v12.13.1

$npm -v
6.12.1
```

上記2つのコマンドを入力してバージョンの数字が表示されればインストールされています。

コマンドがないよー！なんて怒られた場合にはインストールされていませんので[NodebrewでNodeをインストールする](https://qiita.com/mame_daifuku/items/373daf5f49ee585ea498)なんかを参考にして`nodebrew`のインストール→`nodebrew`から`Node.js`をインストール→`npm`のインストールを行っていきましょう！

`npm`のインストールまで終わったら`covid_sample`に移動し、以下のコマンドでReactのプロジェクトを作成していきます。

```shell-session
$npm install -g create-react-app
$npx create-react-app .
```

これで`covid_sample`自体がReactのプロジェクトになります。（コマンド最後の`.`はカレントディレクトリにプロジェクトを作成するという意味で、ここに何か任意の名前を入れると、`covid_sample`以下にその名前でディレクトリが作成されます）

```
$npm start
```

のコマンド入力後、`localhost:3000`へブラウザからアクセスし、以下のような画面が表示されればプロジェクトの作成成功です！

![スクリーンショット 2020-04-01 8.06.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/203944/eea1f9cf-9255-8880-1a97-097d81e851cb.png)

# deck.glの環境構築

[deck.gl](https://deck.gl/#/)は自動車配車サービスのUberが作成した大規模なデータセットの視覚的・探索的データ分析のためのWebGLを利用したフレームワークで、React上で動作させることを想定されています。（最近はpureJSでもちゃんと動くみたいですが）

めっちゃかっこいいです。

データさえあれば、以下のサンプルのように地図上に美しくデータを表現することができます。

- [HexagonLayer](https://deck.gl/#/examples/core-layers/hexagon-layer)

![スクリーンショット 2020-04-01 8.14.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/203944/16e195d4-8ff2-7276-4860-1b67d8b84159.png)

- [LineLayer](https://deck.gl/#/examples/core-layers/line-layer)

![スクリーンショット 2020-04-01 8.16.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/203944/82498f5a-7962-e58b-1d20-7958236b6eeb.png)

今回はこのdeck.glを利用して地図上にデータを表示させていきましょう！

(ちなみに！！！！！今回扱うデータはただのポイントデータ（箇所ごとに緯度経度の位置情報があるだけのデータ）なので上のサンプルのようにかっこよくはなりません！！！！！！！すいません！！！！)

deck.glを利用するために以下の2つのコマンドを入力しましょう。

```shell-session
$npm install deck.gl
$npm install react-map-gl
```

下の`react-map-gl`はこちらもUberが作ったもので、`Mapbox GL JS`というWebGIS界隈では非常に有名なライブラリのReact用ラッパーになります。

今回は背景地図の表示に利用していきます。

これでいよいよ開発環境が整ったので、アプリケーションを作成していきましょう！

# アプリケーションの作成

## mapboxの登録とトークンの発行

[mapbox](https://www.mapbox.com/)とは、Google マップのようなサービスですが、JavaScriptやネイティブ用のSDKが公開されており、自由に、簡単にカスタマイズできる地図サービスのことです。

今回は背景地図としてmapboxを利用していきますので、トップページから会員登録・マイページに表示されるトークンをコピーしておいてください。

![スクリーンショット 2020-04-02 7.37.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/203944/59a2bec3-0df7-0a68-a167-f00e3e07b5bc.png)

## 背景地図の表示

`src`というディレクトリが出来ているはずなのでそちらに移動しましょう。

Reactのプロジェクトでは基本的にこの`src`以下のファイル群をいじっていきます。

`src`ディレクトリの構成は以下のような感じになっていると思いますが、今回編集するファイルは`App.js`のみになります。

```shell-session:tree
.
├── App.css
├── App.js
├── App.test.js
├── index.css
├── index.js
├── logo.svg
├── serviceWorker.js
└── setupTests.js
```

ということでゴリゴリ修正していきましょう！

```jsx:src/App.js
// Reactのインポート
import React from 'react';
// deck.glを利用
import DeckGL from '@deck.gl/react';
// geojsonを使うのでGeoJsonLayerを利用
import {GeoJsonLayer} from '@deck.gl/layers';
// 背景地図の表示にMapbox GL JSのラッパーを利用
import {StaticMap, Popup} from 'react-map-gl';


// 先ほど取得したトークンを文字列で格納
const MAPBOX_ACCESS_TOKEN = <MAPBOX_ACCESS_TOKEN>;

// 初期表示位置などを指定
const initialViewState = {
  longitude: 139.7212733,
  latitude: 35.6606213,
  zoom: 8,
  pitch: 45,
  bearing: 0
};

// 最近は関数ベースのコンポーネントが主流だが、サンプルに合わせてクラスベース
class App extends React.Component {
  // コンストラクターでデータを格納するstateを定義
  constructor(props) {
    super(props);
    this.state = {
      geojsonPoint: null,
    };
  }

  // コンポーネントがマウントされてから動作するメソッド
  // APIにアクセスしてデータを取得しておく
  componentDidMount() {
    fetch("http://0.0.0.0:8000/")
      .then(res => res.json())
      .then(
        (result) => {
          this.setState({
            geojsonPoint: result
          });
          console.log("result", result);
        },
        (error) => {
          console.log(error)
        }
      )
  }

  // ポップアップを表示させるためのメソッド
  _renderTooltip() {
    // hoveredObjectはホバーしている地物の情報
    const {hoveredObject} = this.state || {};
    console.log("hoveredObject", hoveredObject);
    if (hoveredObject !== undefined) {
      return (
        // react-map-glのPopupコンポーネントを利用してポップアップを表示
        <Popup
          longitude={hoveredObject.geometry.coordinates[0]}
          latitude={hoveredObject.geometry.coordinates[1]}>
          <div>
            <p>id:{hoveredObject.properties.id}</p>
            <p>年齢:{hoveredObject.properties.age}</p>
            <p>確定日:{hoveredObject.properties.fixed_data}</p>
          </div>
        </Popup>
      )
    }
  }

  // レンダリング用のメソッド
  render() {
    // コンストラクターで定義したstateからGeoJSONを取得
    const geojsonPoint = this.state.geojsonPoint;
    console.log("geojsonPoint: ", geojsonPoint);
    const layers = [
      new GeoJsonLayer({
        // 任意のid
        id: 'point_layer',
        // GeoJSONを指定
        data: geojsonPoint,
        // pointの半径
        getRadius: d => 2000,
        // 地物のカラーをRGBaで指定
        // aは透過度で0~255から指定
        getFillColor: d => [245, 36, 36, 150],
        pickable: true,
        // 地物にホバーした時に発生するイベント
        // stateを更新する
        onHover: info => this.setState({
          hoveredObject: info.object,
        })
      }),
    ];

    return (
      <>
        {/*DeckGLコンポーネントに必要な情報を渡す*/}
        <DeckGL
          initialViewState={initialViewState}
          controller={true}
          layers={layers}
        >
          {/*利用したいmapboxのスタイルとトークンを渡す*/}
          <StaticMap
            mapStyle="mapbox://styles/mapbox/dark-v9"
            mapboxApiAccessToken={MAPBOX_ACCESS_TOKEN}>
            {/*ポップアップ用の関数も入れる*/}
            {this._renderTooltip()}
          </StaticMap>
        </DeckGL>
      </>
    );
  }
}

export default App;
```

Reactの基本的な解説などは別記事に書こうと思っていますが、Reactでは基本的にコンポーネントの戻り値はJSXというJavaScript内にHTMLを埋め込むような記法で書いていきます。

なので、Appクラスのrenderメソッドの戻り値はHTMLのタグのようなものがずらっと並んでいます。

しかし、実際にはトランスパイルされてJavaScriptに変換されるので

```
<DeckGL initialViewState={initialViewState}></DeckGL>
```

のようにタグの中にpropsと呼ばれる変数のようなものを渡して表示を動的に切り替えることが出来ます！

その他、どういう処理を行なっているのか…という部分はコード中にコメントを書いているので参考にしてみてください！

注意する点としては

- [新型コロナ感染箇所マップを作ってみる【FastAPI/PostGIS/deck.gl(React)】（データ加工編）](https://qiita.com/nokonoko_1203/items/579fc0133d0a2184da42)で作成した、dockerコンテナが立ち上がっているか
- `http://0.0.0.0:8000/`にアクセスしてGeoJSONが返ってくるか
- mapboxのトークンは記入されているか

だけ気をつけてもらえればあとはちゃんと表示されるはずです！

# ブラウザで表示させてみる

ここまで出来たらあとは表示させるだけです！

`$npm start`でサーバーを起動させて`localhost:3000`に接続してみましょう！

![mov.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/203944/e96e3ece-4888-de7e-b646-17a2107503e5.gif)

こんな感じで地図上にポイントが表示されて、ホバーすると情報が表示されるようになったと思います！！！

# 最後に

こんな感じで情報の収集・加工・配信・表示まで一連で行なってきましたが、データさえあれば簡単に可視化できるのが、最近のフレームワークの良いところですね！

また、データの加工段階でQGISなどのGISソフトなどを使えば都道府県ごとの人数をヒートマップで可視化などいろんなことができると思いますのでみなさんどんどんGISやっていきましょう！