DECK.GLを使ってGoogleMapタイムラインをビジュアライズしてみよう！#5 (最終回) 〜GoogleMapタイムラインデータの組み込み〜

[前回](https://qiita.com/koeri3/items/b1ff402f356a4821f637)に引き続き、DECK.GLを使ってGoogleMapのタイムラインをビジュアル化してみよう！の第５弾の記事です。
今回でこのシリーズは最終回です！

[前回](https://qiita.com/koeri3/items/b1ff402f356a4821f637)はDeckGLにマップコンポーネントを組み込んだものをブラウザで確認できました。
とは言ってもまだダミーデータの表示しかできていないので、今回は実際にタイムラインデータを表示したいと思います。



# 目次
本記事は全５回に渡り説明していきます。

1. [ReactとDECK.GLの環境構築](https://qiita.com/koeri3/items/8dc468ad9f910bdf244b)
2. [基本的なReactのコードをブラウザで確認](https://qiita.com/koeri3/items/a245f7cb50e77ebf3167)
3. [DECK.GLを使った簡単なデータの表示](https://qiita.com/koeri3/items/c4c92408cf7aa0d54b7c)
4. [マップコンポーネントの表示](https://qiita.com/koeri3/items/b1ff402f356a4821f637)
5. GoogleMapタイムラインデータ表示   **←今回はコレ**


# Google Mapタイムラインデータのダウンロード
まず始めに、GoogleMapからタイムラインデータをダウンロードしましょう！

## Google Mapにアクセス
まずGoogle Mapにアクセスします。
左上のメニューアイコンをクリックすると下記のメニューが表示されるので、`Your timeline(タイムライン)`をクリックしましょう。
※Googleにログインしてから実施してください
![GoogleMap-Timeline-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431109/c2e5f69c-ccd6-ed53-7e4f-548742eebf5c.png)

そうすると、下記のようなタイムライン画面に遷移します。
右下の歯車アイコン（`Map(地図)`の左）をクリックし、`Download a copy of all your data(すべてのデータのコピーをダウンロード)`をクリックします。
![GoogleMap-Timeline-2 copy.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431109/4b0e4a07-624c-29c3-5bd3-b5ec68bc882c.png)

## ダウンロードデータの選択
そしたらダウンロードするデータを選択する画面に遷移するので、`Location History(ロケーション履歴)`にチェックを入れて、一番下にある「`Next step(次のステップ)`」ボタンをクリックします。
![Screen Shot 2019-12-14 at 0.43.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431109/eb1613c9-a6f8-17be-c872-98ba72c333f0.png)

次に、アーカイブのファイル形式と、アーカイブをダウンロードするかクラウドに保存するかを選択する画面に遷移するので、好きな方法を選択します。
※ 私は「メールで受け取る」「１回限りのアーカイブ」「zip形式」を選択しました
![Screen Shot 2019-12-14 at 0.49.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431109/42a1b49a-1351-9ba4-54ef-ca3a37815c66.png)


選択したら「`Create archive(アーカイブを作成)`」ボタンをクリック！
これでデータダウンロードは完了です。
サイズにもよりますが、私の場合はすぐに（１分もしないくらい）アーカイブ完了のメールが届きました。

## データの確認
メールにタイムラインデータが届いたら、早速ダウンロードして中身を見てみましょう！

zipファイルを解凍すると、中にはhtmlファイルとjsonファイルが格納されています。
htmlファイルにはデータの説明が、jsonファイルには実際のタイムラインデータが入っています。
![Screen Shot 2019-12-14 at 1.00.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431109/03bd7199-28fa-2cb1-79a4-bb28f9592d02.png)


jsonファイルの中身はこんな感じ。

```json:ロケーション履歴.json
{
  "locations" : [ {
    "timestampMs" : "1534792059283",
    "latitudeE7" : 378718885,
    "longitudeE7" : -1222666563,
    "accuracy" : 65,
    "altitude" : 59,
    "verticalAccuracy" : 10
  }, {
   ...
  }]
}
```

## データのフォーマット

データの説明はHTMLに記載がありますが、このようなデータが含まれています。

| key       | 説明    
|:-----------------|:-----------------|
| locations               | All location records.　|
| timestampMs(int64)      | Timestamp (UTC) in milliseconds for the recorded location.　|
| latitudeE7(int32)       | The latitude value of the location in E7 format (degrees multiplied by 10**7 and rounded to the nearest integer). |
| longitudeE7(int32)      | The longitude value of the location in E7 format (degrees multiplied by 10**7 and rounded to the nearest integer). |
| accuracy(int32)         | Approximate location accuracy radius in meters. |
| velocity(int32)         | Speed in meters per second. |
| heading(int32)          | Degrees east of true north. | 
| altitude(int32)         | Meters above the WGS84 reference ellipsoid. | 
| verticalAccuracy(int32) | Vertical accuracy calculated in meters. | 
| activity                | Information about the activity at the location. | 
| timestampMs(int64)      | Timestamp (UTC) in milliseconds for the recorded activity. | 
| type                    | Description of the activity type. | 
| confidence(int32)       | Confidence associated with the specified activity type. | 


# Google Mapタイムラインデータの組み込み
それでは早速タイムラインデータを組み込んでいきましょう！！

## データの読み込み
`src`フォルダの中に`data`フォルダを作成し、その中にダウンロードしたjsonファイルを`locations.json`という名前で格納しましょう。
こんな感じ :point_down_tone2:
![Screen Shot 2019-12-16 at 2.54.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431109/ca625716-e02e-1167-9f3c-de67759e0217.png)


これを`tripData`という名前でimportします。

```jsx:App.js(一部)
import React from "react";
import DeckGL from "@deck.gl/react";
import { PathLayer } from "@deck.gl/layers";
import MapGL from "react-map-gl";
import "mapbox-gl/dist/mapbox-gl.css";
import tripData from "./data/locations.json";
```

## Viewportの設定修正
今まで設定していたViewportはサンフランシスコ辺りを指定していたので、シアトル中心部辺りの座標に書き換えます。

```jsx:App.js(一部)
// Viewport 初期設定
const viewState = {
  latitude: 47.60521,
  longitude: -122.33207,
  zoom: 12.3
};
```

## 描画データの削除
前回までは描画データを下記のように定義していましたが、もう必要ないので、こちらの記述は削除します。

```jsx:削除データ
// 描画する地理データ
const data = [
  {
    path: [
      [-122.45, 37.7],
      [-122.5, 37.8],
      [-122.6, 37.7]
    ]
  }
];
```


## レンダリング
最後にレンダリング部分を書いていきましょう。

### コンストラクタの設定
後ほどタイムラインデータを`state`に格納するので、`timelinePoints`という名前で初期値(空の配列)を設定します。

`state`で設定したデータはコンポーネント内で使用でき、値が変更されると変更部分のみを更新します。

```jsx:App.js(一部)
constructor(props) {
  super(props);
  this.state = {
    timelinePoints: []
  };
}
```

### タイムラインデータの整形
先ほどダウンロードしたタイムラインの緯度・経度は通常の値に`10 * 7` を掛けたものが設定されているので、表示する前に割り戻す必要があります。
`formatLocations`という関数を作成し、整形処理を行いましょう。整形後の配列データは`state`にセットします。

この関数がコンポーネントのマウントが行われた時に1度だけ実行してほしいので、`componentDidMount()`の中で呼び出しましょう。


```jsx:App.js(一部)
componentDidMount() {
  this.formatLocations();
}

formatLocations = () => {
  if (tripData) {
    const timelinePoints = tripData.locations.reduce((accu, curr) => {
      // lat/longのデータを 10000000 で割る
      accu.push([curr.longitudeE7 / 10000000, curr.latitudeE7 / 10000000]);
      return accu;
    }, []);
    this.setState({ timelinePoints });
  }
};
```

### レンダリング
最後に、`PathLayer`にデータ整形後のタイムラインデータを渡してあげましょう。

`trips`という名前で、pathオブジェクトに`state`に格納されている整形後の[緯度,経度]のデータを代入します。

そしたら、`PathLayer`のインスタンス生成部分の`data`に`trips`の変数を渡します。

```jsx:App.js(一部)
render() {
  const trips = [{
    path: this.state.timelinePoints
  }];
  const layer = [
    new PathLayer({
      id: "path-layer",
      data: trips,
      getPath: d => d.path,
      getWidth: 30
    })
  ];
  ...

}
```

# ブラウザで表示
それでは最後にブラウザで表示してみましょう！
yarn startコマンドで起動させると・・・

:point_down_tone2::point_down_tone2::point_down_tone2:
![Screen Shot 2019-12-20 at 0.27.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431109/27fe3eb5-d668-7c1b-aa7a-78d7d9680b4b.png)

無事シアトルの地図の上に、私のGoogleMapのタイムラインが表示されました〜！！:clap::clap:


# 最後に
DECK.GLにはもっといろいろなレイヤーがあります。
今回はシンプルなものでビジュアライズを行いましたが、今後はもっといろんなレイヤーを使っていろんなデータをビジュアライズさせたいと思っています！！

### おまけ :coffee:
`Trips Layer`と`Icon Layer`を使って、このタイムラインデータを時系列データを使ってアニメーションさせつつ、スターバックスの店舗データを表示させたものを下記のGitHubにあげていますので、ご興味ある方は是非こちらもご覧ください :grinning:
https://github.com/nouvelle/starbucks-journey

ここまでご覧いただきありがとうございました！！:blush:


# App.jsxの全体像

```jsx:App.js
import React from "react";
import DeckGL from "@deck.gl/react";
import { PathLayer } from "@deck.gl/layers";
import MapGL from "react-map-gl";
import "mapbox-gl/dist/mapbox-gl.css";
import tripData from "./data/locations.json";

// mapbox access token
const MAPBOX_ACCESS_TOKEN = "pk.eyJ1IjoiZ.......";

// Viewport 初期設定
const viewState = {
  latitude: 47.60521,
  longitude: -122.33207,
  zoom: 12.3
};

export default class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      timelinePoints: []
    };
  }

  componentDidMount() {
    this.formatLocations();
  }

  formatLocations = () => {
    if (tripData) {
      const timelinePoints = tripData.locations.reduce((accu, curr) => {
        // lat/longのデータを 10000000 で割る
        accu.push([curr.longitudeE7 / 10000000, curr.latitudeE7 / 10000000]);
        return accu;
      }, []);
      this.setState({ timelinePoints });
    }
  };

  render() {
    // 描画する地理データ
    const trips = [{
      path: this.state.timelinePoints
    }];
    const layer = [
      new PathLayer({
        id: "path-layer",
        data: trips,
        getPath: d => d.path,
        getWidth: 30
      })
    ];
    return (
      <DeckGL viewState={viewState} layers={layer}>
        <MapGL mapboxApiAccessToken={MAPBOX_ACCESS_TOKEN} />
      </DeckGL>
    );
  }
}
```