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

[Yellowfin](https://yellowfin.co.jp/) [(BI)](https://yellowfin.co.jp/blog/2019/11/21-blog2-summary-of-bi-tools) と Leaflet / OpenStreetMap を連携して、緯度経度情報から車の走行履歴を地図上に描いてみたいと思います。[Yellowfin と FusionCharts の連携]( https://qiita.com/ExtremeCarvFJ/items/84e499a59e70dd5320e2)で、市町村レベルのポリゴン地図を描くことは可能です。一方で、走行履歴のようなものを描くためには、Leaflet / OpenStreetMap などとの連携が必要なんですね、これが。

## 1. 事前準備

#### 1-1. ビューの作成まで
今回、会津若松市の[公用車・公共交通車両走行情報](https://data.data4citizen.jp/dataset/10060158)を走行履歴データとして参考にさせていただきました。お手元に緯度経度の移動情報があれば、もちろんそちらを活用いただくことが可能です。数値情報としては、緯度と経度の情報さえあれば、走行履歴を描画することができます。
Leaflet のライブラリーを[ダウンロード]( https://leafletjs.com/SlavaUkraini/download.html)しておきます。後の手順で CSS ファイルの内容を利用する必要があるからです。
[前回記事](https://qiita.com/ExtremeCarvFJ/items/ad453a6110cec093bdb9)  を参考に、『1-2. ビューの作成』 までの作業を実施します。

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

#### 2-1. [データ] ステップ
1 つ以上の軸と、緯度経度の情報を使って以下のようなテーブルを作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2128512/ae79c052-8697-bfd6-34a0-f5e33d059adb.png)

#### 2-2. [グラフ] ステップ
[グラフ] ステップに進み、画面右側 [グラフの選択] から [JavaScriptグラフ] を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2128512/75b496fc-8640-1449-cae3-d201a3967896.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({
            id: dataset.id[i].raw_data,
            latitude: dataset.latitude[i].raw_data,
            longitude: 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: 600px; width: 500px;"></div>');
        var driving = L.map('driving_record').setView([ds[5000].latitude, ds[5000].longitude], 13);
        L.tileLayer('https://{s}.tile.osm.org/{z}/{x}/{y}.png', {
            attribution: '&copy<a href="http://openstreetmap.org">OpenStreetMap</a>contributors'
        }).addTo(driving);
        
        for(var ii in ds){
            var latitude = ds[ii].latitude;
            var longitude = ds[ii].longitude;
            L.circleMarker([latitude, longitude],{radius: 1, color: 'red'}).addTo(driving);
        }
    });
};
```

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

##### プレビュー
[プレビュー] に移り、どのようなチャートが作成されるか確認します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2128512/3ac7e1fb-8941-5bdf-03e8-feba068cfc7e.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({
            id: dataset.id[i].raw_data,
            latitude: dataset.latitude[i].raw_data,
            longitude: 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/fb312dfa-766f-b9e3-b414-0b67bceec0b6.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: 600px; width: 500px;"></div>');
        var driving = L.map('driving_record').setView([ds[5000].latitude, ds[5000].longitude], 13);
        L.tileLayer('https://{s}.tile.osm.org/{z}/{x}/{y}.png', {
            attribution: '&copy<a href="http://openstreetmap.org">OpenStreetMap</a>contributors'
        }).addTo(driving);
        
        for(var ii in ds){
            var latitude = ds[ii].latitude;
            var longitude = ds[ii].longitude;
            L.circleMarker([latitude, longitude],{radius: 1, color: 'red'}).addTo(driving);
        }
    });
};
```
OpenStreetMap の地図上に、移動経度情報から移動履歴を描画する処理を施しています。
`require([])`の中で、ライブラリーが公開されている URL を指定しています。
`$chartDiv.append()`でタグを付加し、`var driving = L.map('driving_record').setView([ds[5000].latitude, ds[5000].longitude], 13);` で、地図を描画するタグを指定するとともに、地図の中心点と拡大率を設定しています。今回は走行履歴の中間地点を地図の中心としています。
`L.tilelayer` の中で、OpenStreetMap の地図を読み込む処理を行っています。[Leaflet]( https://leafletjs.com/SlavaUkraini/) のサンプルコードを参考にしました。
`for(var ii in ds){}`の処理で、データセット内の移動経度情報をつかって、地図上に移動履歴を描画しています。今回の例では、10,000 行のデータ (全体で100,000 行のうち) を PostgreSQL に取り込んでいますが、待ち時間なく速攻で描画されます。

## 4. 最後に
[Leaflet](https://leafletjs.com/) のサイトにアクセスしていただくと分かりますが、Leaflet は 11 年前にウクライナ人の Volodymyr Agafonkin さんが開発されたものです。2022 年 4 月 14 日現在、彼はキーフを離れ避難している様子です。ウクライナは東欧のシリコンバレーと呼ばれるほど、IT 産業が盛んな国です。ロシアの一部政治家による非人道的な行動により、エンジニアなどの有能な人間や、将来ある子供たちも悲惨な目に合っている実情を認識しながら、Leaflet を活用させていただこうと思います。
See you then, peace!!