緯度経度情報を元に走行履歴を地図上に表示 ‐ Yellowfin と Leaflet / OpenStreetMapの連携 その2

[Yellowfin](https://yellowfin.co.jp/) [BI](https://yellowfin.co.jp/blog/2019/11/21-blog2-summary-of-bi-tools) と Leaflet / OpenStreetMap を連携して、緯度経度情報から車の走行履歴を地図上に描く内容の第 2 弾です。[前回]( https://qiita.com/ExtremeCarvFJ/items/ee60a9fd2860d177b702)もほぼ同じ内容の記事を投稿したのですが、その処理は細かなドットを使って走行履歴を地図に描画したものでした。今回は、線を使って走行履歴を描き、走行履歴全体が表示されるように自動で地図の中心点と拡大率が選択されるようにしたいと思います。

## 1. 事前準備

#### 1-1. ビューの作成まで
前回同様、会津若松市の[公用車・公共交通車両走行情報](https://data.data4citizen.jp/dataset/10060158)を走行履歴データとして参考にさせていただきました。お手元に緯度経度の移動情報があれば、もちろんそちらを活用いただくことが可能です。
[以前の記事](https://qiita.com/ExtremeCarvFJ/items/ad453a6110cec093bdb9)  を参考に、『1-2. ビューの作成』 までの作業を実施します。

## 2. グラフの作成
準備が整ったら、グラフの作成に手順を進めます。新規でレポートを作成し、以下の手順に従ってグラフを作成します。

#### 2-1. [データ] ステップ
1 つ以上の軸と、緯度経度の情報を使って以下のようなテーブルを作成します。下記例では軸に id を選択していますが、一般的には時系列の軸を選択する形になります。この軸を昇順で並び変えておくことで、走行履歴としてのデータの並び順になります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2128512/bd2056a5-be2a-2d00-8a34-a962592d1cb8.png)

#### 2-2. [グラフ] ステップ
[グラフ] ステップに進み、画面右側 [グラフの選択] から [JavaScriptグラフ] を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2128512/c875fce9-935b-ab5c-a697-91271e51cdca.png)

##### JavaScriptタブ
雛形を全て削除し、以下のコードに置き換えます。コードの処理の内容は後ほど説明します。
```javascript:JS
generateChart = function(options) {
    var $chartDiv = $(options.divSelector);
    var processedData = processData(options.dataset.data);
    doDrawing(processedData, $chartDiv);
},

processData = function(dataset) {
    var ds = [];
    for (i=0;i<dataset.id.length;i++){
        ds.push([
            dataset.latitude[i].raw_data,
            dataset.longitude[i].raw_data
        ])
    }
    return ds;
},

doDrawing = function(ds, $chartDiv) {
    console.log(JSON.stringify(ds));
    require(['https://unpkg.com/leaflet@1.7.1/dist/leaflet.js'], function() {
        $chartDiv.append('<div id="driving_record" style="height: 550px; width: 400px;"></div>');
        var driving = L.map('driving_record');
        L.tileLayer('https://{s}.tile.osm.org/{z}/{x}/{y}.png', {
            attribution: '&copy<a href="http://openstreetmap.org">OpenStreetMap</a>contributors'
        }).addTo(driving);
        var group = L.featureGroup();
        group.addLayer(L.polyline([ds],{color: 'red', weight: 3}));
        group.addTo(driving);
        driving.fitBounds(group.getBounds());
    });
};
```

##### CSS タブ
先の手順でダウンロードしたライブラリー群から、leaflet.css の内容を全て [CSS] タブにコピーして貼り付けます。CSS の内容を処理の先頭で読み込まないと、グラフが適切に描画されません。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2128512/b69854f1-efae-4b72-f870-96468245a6c4.png)

##### プレビュー
[プレビュー] に移り、どのようなチャートが作成されるか確認します。前回の記事よりも地図上の走行距離が長いのは、今回は 100,000 行のデータ全てを取り込んでみたからです。多少長めの処理時間を要するようにはなりましたが、十分に実用に耐えられる範囲です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2128512/5c958f70-e2a2-ed9a-15d5-fe20fa453bfc.png)

## 3. コードの内容
動作概要が分かったところで、コードの中身を見てみましょう。
##### generateChart
```JavaScript:generateChart
generateChart = function(options) {
    var $chartDiv = $(options.divSelector);
    var processedData = processData(options.dataset.data);
    doDrawing(processedData, $chartDiv);
},
```
JavaScript グラフの処理において、最初に呼び出されるのが generateChart = function(options) です。
[データ] ステップでテーブルに追加した情報が、options に格納されて、メソッドに受け渡されます。
`var $chartDiv = $(options.divSelector);`
`var processedData = processData(options.dataset.data);`
`doDrawing(processedData, $chartDiv);`
上記 3 行で、チャートを描画するタグを定義し、データ処理とグラフ描画処理を行う関数を呼び出しています。呼び出し先の関数での処理内容は後続の個所で説明をします。

##### processData
```JavaScript:processData
processData = function(dataset) {
    var ds = [];
    for (i=0;i<dataset.id.length;i++){
        ds.push([
            dataset.latitude[i].raw_data,
            dataset.longitude[i].raw_data
        ])
    }
    return ds;
},
```

Yellowfin のデータセットを JSON の配列に変換して ds にオブジェクトとして格納しています。
今回のサンプルデータであれば、以下のような JSON の書式になります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2128512/523e6840-9d79-2b9c-201c-3210c0f932ec.png)

画面は [グラフ] ステップでディベロッパーツールのコンソールから確認したものです。コードの中に `console.log(JSON.stringify(ds))` を記述しておくと、データオブジェクトの中身をコンソールで確認することができます。今回の場合は、doDrawing の先頭に記述しています。デバッグに便利なので、活用してみてください。

##### doDrawing
```JavaScript:doDrawing
doDrawing = function(ds, $chartDiv) {
    console.log(JSON.stringify(ds));
    require(['https://unpkg.com/leaflet@1.7.1/dist/leaflet.js'], function() {
        $chartDiv.append('<div id="driving_record" style="height: 550px; width: 400px;"></div>');
        var driving = L.map('driving_record');
        L.tileLayer('https://{s}.tile.osm.org/{z}/{x}/{y}.png', {
            attribution: '&copy<a href="http://openstreetmap.org">OpenStreetMap</a>contributors'
        }).addTo(driving);
        var group = L.featureGroup();
        group.addLayer(L.polyline([ds],{color: 'red', weight: 3}));
        group.addTo(driving);
        driving.fitBounds(group.getBounds());
    });
};
```
OpenStreetMap の地図上に、移動経度情報から移動履歴を描画する処理を施しています。
`require([])`の中で、ライブラリーが公開されている URL を指定しています。同ライブラリーは[ダウンロード]( https://leafletjs.com/SlavaUkraini/download.html)して利用することも可能です。
`$chartDiv.append(…)`でタグを付加し、`var driving = L.map('driving_record’)` で描画するタグを指定しています。
`var driving`から`addTo(driving);`で、OpenStreetMap の地図を読み込むとともに出所を示しています。[Leaflet]( https://leafletjs.com/SlavaUkraini/) のサンプルコードを参考にしました。

###### 座標と拡大率の自動選択
これ以降が座標と拡大率の自動選択に関わる処理を含むものです。下記処理に関しては、[こちら](https://www.achiachi.net/blog/leaflet/autocenter)の情報を参考にさせていただきました。
`var group = L.featureGroup();` でポリラインをグループ化する変数を準備します。
`group.addLayer(L.polyline([ds],{color: 'red', weight: 3}));` で group グループに全てのポリラインを追加します。`ds` データセットで描くことのできるポリラインをまとめて登録しています。
`group.addTo(driving);` でポリラインを地図上に描画します。
`driving.fitBounds(group.getBounds());` ポリラインが全て収まる座標と拡大率を選択します。


## 4. 最後に
[Leaflet](https://leafletjs.com/) を開発したウクライナ人の Volodymyr Agafonkin さんは、2022 年 5 月 2 日現在、いまだキーフを離れ避難している様子です。いまだ戦闘が続くウクライナに平和な日常が戻るのにはもうしばらく先になりそうです。
そんな事実を頭に置きながら、皆様良いデータ分析を！See you then, peace!!