スケジュール管理表：Yellowfin と FusionCharts の連携

## 1. はじめに
[以前の記事](https://qiita.com/ExtremeCarvFJ/items/e47d606b52f4c2e7e351)で、FusionCharts と連携してガントチャートを作成する方法をお伝えしました。今回は、ガントチャートを社員のスケジュール管理表に作り変えてみたいと思います。

## 1. 事前準備
#### 1-1. データの準備
以下の手順で取り扱うデータを[こちら](https://github.com/ChasingHH/ShareFiles/blob/Share/gantt_hourly.csv)に共有しています。ダウンロードしてデータベースのテーブルにインポートするなどしてご利用ください。

#### 1-2. ビューの作成
続いて、上記データを参照するための [ビュー](https://wiki.yellowfin.co.jp/pages/viewpage.action?pageId=2294284)を作成します。
一点、時間データに関しては、FusionCharts 側で設定する書式に合わせてください。今回の場合は hh：mm：dd (24h)の書式で取り扱うため、サンプルデータの [start] [end] は上記書式に設定する必要があります。ビューで書式を修正する手順に関しては[こちら](https://wiki.yellowfin.co.jp/pages/viewpage.action?pageId=2293966)をご確認ください。


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

#### 2-1. [データ] ステップ
ビューに設定した軸と集計値を全てテーブルに配置します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2128512/d8cb9bd0-f620-33c6-e1e9-1c3a5c6ee628.png)

#### 2-2. [グラフ] ステップ
[グラフ] ステップに進み、画面右側 [グラフの選択] から [JavaScriptグラフ] を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2128512/88f1134b-cf8b-c691-c6b3-018068a5e2c0.png)

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

processTask = function(dataset) {
    var ds_task = [];
    for (i=0;i<dataset.type.length;i++){
        if(dataset.type[i].formatted_data === "task"){
            ds_task.push({
                processid: dataset.id[i].formatted_data,
                start: dataset.start[i].formatted_data,
                end: dataset.end[i].formatted_data,
                label: dataset.label[i].formatted_data,
                color: dataset.color[i].raw_data
            });
        }
    }
    return ds_task;
},

processProcess = function(dataset) {
    var ds_process = [];
    for (j=0;j<dataset.type.length;j++){
        if(dataset.type[j].formatted_data === "process"){
            ds_process.push({
                label: dataset.label[j].formatted_data,
                id: dataset.id[j].formatted_data,
            });
        }
    }
    return ds_process;
},

processCategory = function(dataset) {
    var ds_category = [];
    for (k=0;k<dataset.type.length;k++){
        if(dataset.type[k].formatted_data === "category"){
            ds_category.push({
                start: dataset.start[k].formatted_data,
                end: dataset.end[k].formatted_data,
                label: dataset.label[k].formatted_data,
            });
        }
    }
    return ds_category;
},

doDrawing = function(ds_task, ds_process, ds_category, $chartDrawDiv) {
    console.log(JSON.stringify(ds_task));
    console.log(JSON.stringify(ds_process));
    console.log(JSON.stringify(ds_category));
    require(['js/chartingLibraries/fusioncharts-suite-xt/js/fusioncharts.js'], function(){
        const dataSource = {
            chart: {
                outputdateformat: "hh12:mn ampm",
                caption: "社員の予定管理",
            },
            tasks: {showlabels: "1", task: ds_task},
            processes: {
                fontsize: "11",
                isbold: "1",
                align: "Center",
                process: ds_process
            },
            categories: [{category: ds_category}]
        };
        FusionCharts.ready(function() {
            var myChart = new FusionCharts({
                type: "gantt",
                renderAt: $chartDrawDiv[0],
                width: 800,
                height: 400,
                dataFormat: "json",
                dataSource
            }).render();
        });
    });
};
```
##### プレビュー
[プレビュー] に移り、どのようなチャートが作成されるか確認します。マウスをホバーすると、ツールチップが表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2128512/096bfcd3-9587-d025-0f97-aead477051c0.png)

## 3. コードの内容
動作概要が分かったところで、コードの中身を見てみましょう。
##### generateChart
```JavaScript:generateChart
generateChart = function(options) {
    var $chartDrawDiv = $(options.divSelector);
    var processedTask = processTask(options.dataset.data);
    var processedProcess = processProcess(options.dataset.data);
    var processedCategory = processCategory(options.dataset.data);
    doDrawing(processedTask, processedProcess, processedCategory, $chartDrawDiv);
},
```

JavaScript グラフの処理において、最初に呼び出されるのが generateChart = function(options) です。
[データ] ステップでテーブルに追加した情報が options に格納されて、メソッドに受け渡されます。
`processTask(options.dataset.data)`、`processProcess(options.dataset.data)`、`processCategory(options.dataset.data)` でデータ処理を行う関数を、`doDrawing(processedTask, processedProcess, processedCategory, $chartDrawDiv)` で描画するメソッドをそれぞれ呼び出しています。各メソッドで実行する具体的な処理は後述します。

##### processTask
```JavaScript:processTask
processTask = function(dataset) {
    var ds_task = [];
    for (i=0;i<dataset.type.length;i++){
        if(dataset.type[i].formatted_data === "task"){
            ds_task.push({
                processid: dataset.id[i].formatted_data,
                start: dataset.start[i].formatted_data,
                end: dataset.end[i].formatted_data,
                label: dataset.label[i].formatted_data,
                color: dataset.color[i].raw_data
            });
        }
    }
    return ds_task;
},
```

Yellowfin のデータセットを JSON の配列に変換して ds_task にオブジェクトとして格納しています。
今回のサンプルデータであれば、以下のような JSON の書式になります。各社員の予定を水平バーで示すために必要な情報です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2128512/460505de-1925-9261-21ea-1bbe48f6cd1a.png)

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

同じ要領で、ガントチャートを描くために必要なデータを各関数の中で取り込んでいく流れになります。機能毎にどのようなデータが必要となるかは、[こちら](https://www.fusioncharts.com/dev/chart-guide/standard-charts/gantt-chart)で詳しく紹介しています。以降の説明と合わせてご確認ください。

##### processProcess
```JavaScript:processProcess
processProcess = function(dataset) {
    var ds_process = [];
    for (j=0;j<dataset.type.length;j++){
        if(dataset.type[j].formatted_data === "process"){
            ds_process.push({
                label: dataset.label[j].formatted_data,
                id: dataset.id[j].formatted_data,
            });
        }
    }
    return ds_process;
},
```
チャート左の社員名ラベルを描画するためのデータを、JSONの配列に変換して ds_process にオブジェクトとして格納しています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2128512/9559b4d3-1654-78e0-9633-6f80f06f6d8c.png)

##### processCategory
```JavaScript:processCategory
processCategory = function(dataset) {
    var ds_category = [];
    for (k=0;k<dataset.type.length;k++){
        if(dataset.type[k].formatted_data === "category"){
            ds_category.push({
                start: dataset.start[k].formatted_data,
                end: dataset.end[k].formatted_data,
                label: dataset.label[k].formatted_data,
            });
        }
    }
    return ds_category;
},
```
チャート上部の時間軸ラベルを描画するためのデータを、JSONの配列に変換して ds_category にオブジェクトとして格納しています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2128512/0cf83d4b-87bc-c710-499b-c45114d1283b.png)

##### doDrawing
```JavaScript:doDrawing
doDrawing = function(ds_task, ds_process, ds_category, $chartDrawDiv) {
    console.log(JSON.stringify(ds_task));
    console.log(JSON.stringify(ds_process));
    console.log(JSON.stringify(ds_category));
    require(['js/chartingLibraries/fusioncharts-suite-xt/js/fusioncharts.js'], function(){
        const dataSource = {
            chart: {
                outputdateformat: "hh12:mn ampm",
                caption: "社員の予定管理",
            },
            tasks: {showlabels: "1", task: ds_task},
            processes: {
                fontsize: "11",
                isbold: "1",
                align: "Center",
                process: ds_process
            },
            categories: [{category: ds_category}]
        };
        FusionCharts.ready(function() {
            var myChart = new FusionCharts({
                type: "gantt",
                renderAt: $chartDrawDiv[0],
                width: 800,
                height: 400,
                dataFormat: "json",
                dataSource
            }).render();
        });
    });
};

```

`require[]` の中で、JavaScriptライブラリーを格納したディレクトリーを相対パスで記述します。
`dataSource` > `chart` > `outputdateformat: "hh12:mn ampm"` で時間の書式を定義しています。マウスを各予定にホバーした際に表示されるツールチップの中身に関わってきます。
`task: ds_task`、` process: ds_process `、` category: ds_category` で先の手順でデータセットに取り込んだオブジェクトの中身を FushionCharts に受け渡しています。

`FusionCharts.ready` でチャートを描画します。
`type: "gantt”,` でチャートの種類を指定します。

`renderAt: $chartDrawDiv[0]` でチャートを描画する div を指定します。`$chartDrawDiv` はコードの先頭で宣言した変数です。
`width` と `height` はダッシュボードの大きさなどに合わせてピクセル単位で指定します。FusionCharts のサンプルを見ると、%で指定していますが、Yellowfin で扱う場合は、ピクセルで指定した方がきれいに表示されます。

## 4. 最後に
今回は、ガントチャートを応用して、スケジュール管理表を作成してみました。
ライブラリーとの連携で、Yellowfin の用途も広がりますね。
では皆様、良いデータ分析とスケジュール管理を! See you then!! Cheers!!