0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

ガントチャートの作成 : Yellowfin と FusionCharts の活用でプロジェクト管理

Posted at

以前、Google チャートと連携してガントチャートを作成する手順を紹介しました。
今回は、FusionChart との連携でガントチャートを作成してみようと思います。

1. 事前準備

1-1. ビューの作成まで

前回記事 を参考に、『1-2. ビューの作成』 までの作業を実施します。

以下の手順で取り扱うデータをこちらに共有しています。ダウンロードしてご利用ください。

上記から取得したデータを全てビューで参照できるようにします。
1 点、日付データに関しては、FusionCharts 側で設定する書式に合わせてください。今回の場合は yyyy/MM/dd の書式で取り扱うため、サンプルデータの [start] [end] は上記書式に設定する必要があります。ビューで書式を修正する手順に関してはこちらをご確認ください。

2. グラフの作成

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

2-1. [データ] ステップ

ビューに設定した軸と集計値を全てテーブルに配置します。
image.png

2-2. [グラフ] ステップ

[グラフ] ステップに進み、画面右側 [グラフの選択] から [JavaScriptグラフ] を選択します。
image.png

JavaScriptタブ

雛形を全て削除し、以下のコードに置き換えます。コードの処理の内容は後ほど説明します。

JS
generateChart = function(options) {
    var $chartDrawDiv = $(options.divSelector);
    var processedTask = processTask(options.dataset.data);
    var processedConnector = processConnector(options.dataset.data);
    var processedMilestone = processMilestone(options.dataset.data);
    var processedProcess = processProcess(options.dataset.data);
    var processedCategory = processCategory(options.dataset.data);
    doDrawing(processedTask, processedConnector, processedMilestone, processedProcess, processedCategory, $chartDrawDiv);
},

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

processConnector = function(dataset) {
    var ds_connector = [];
    for (k=0;k<dataset.type.length;k++){
        if(dataset.type[k].formatted_data === "connector"){
            ds_connector.push({
                fromtaskid: dataset.fromtaskid[k].formatted_data,
                totaskid: dataset.totaskid[k].formatted_data,
                color: dataset.color[k].formatted_data,
                thickness: dataset.thickness[k].formatted_data,
            });
        }
    }
    return ds_connector;
},

processMilestone = function(dataset) {
    var ds_milestone = [];
    for (n=0;n<dataset.type.length;n++){
        if(dataset.type[n].formatted_data === "milestone"){
            ds_milestone.push({
                date: dataset.start[n].formatted_data,
                taskid: dataset.id[n].formatted_data,
                tooltext: dataset.label[n].formatted_data,
                color: dataset.color[n].formatted_data,
                shape: dataset.shape[n].formatted_data,
            });
        }
    }
    return ds_milestone;
},

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

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

doDrawing = function(ds_task, ds_connector, ds_milestone, ds_process, ds_category,  $chartDrawDiv) {
    console.log(JSON.stringify(ds_task));
    console.log(JSON.stringify(ds_connector));
    console.log(JSON.stringify(ds_milestone));
    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: {
                caption: "プロジェクト計画",
                dateformat: "yyyy/mm/dd",
                ganttwidthpercent: "60",
                ganttpaneduration: "40",
                ganttpanedurationunit: "w",
                useverticalscrolling: "0",
                plottooltext: "<b>$label</b><br>開始: <b>$start</b><br>終了: <b>$end</b>",
                theme: "fusion"
            },
            tasks: [{task: ds_task}],
            connectors: [{connector: ds_connector}],
            milestones: [{milestone: ds_milestone}],
            processes: {
                headertext: "タスク",
                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

3. コードの内容

動作概要が分かったところで、コードの中身を見てみましょう。

generateChart
generateChart
generateChart = function(options) {
    var $chartDrawDiv = $(options.divSelector);
    var processedTask = processTask(options.dataset.data);
    var processedConnector = processConnector(options.dataset.data);
    var processedMilestone = processMilestone(options.dataset.data);
    var processedProcess = processProcess(options.dataset.data);
    var processedCategory = processCategory(options.dataset.data);
    doDrawing(processedTask, processedConnector, processedMilestone, processedProcess, processedCategory, $chartDrawDiv);
},

JavaScript グラフの処理において、最初に呼び出されるのが generateChart = function(options) です。
[データ] ステップでテーブルに追加した情報が、options に格納されて、メソッドに受け渡されます。
var $chartDrawDiv = $(options.divSelector) でグラフを出力する div を選択します。
var processedTask = processTask(options.dataset.data);
var processedProcess = processProcess(options.dataset.data);
var processedCategory = processCategory(options.dataset.data);
var processedConnector = processConnector(options.dataset.data);
var processedMilestone = processMilestone(options.dataset.data);
doDrawing(processedTask, processedProcess, processedCategory, processedConnector, processedMilestone, $chartDrawDiv);
上記 6 行で、別の関数を呼び出して、データ処理とグラフ描画処理を行っています。呼び出し先の関数での処理内容は後続の個所で説明をします。

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

Yellowfin のデータセットを JSON の配列に変換して ds_task にオブジェクトとして格納しています。
今回のサンプルデータであれば、以下のような JSON の書式になります。各タスクの予定、実績、遅延の状況を水平バーで示すために必要な情報です。
image.png

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

以下の手順では、上記と同じ要領で、ガントチャートを描くために必要なデータを各関数の中データセットで取り込んでいく流れになります。機能毎にどのようなデータが必要となるかは、こちらで詳しく紹介しています。これ以降の説明と合わせてご確認ください。

processConnector
processConnector
processConnector = function(dataset) {
    var ds_connector = [];
    for (k=0;k<dataset.type.length;k++){
        if(dataset.type[k].formatted_data === "connector"){
            ds_connector.push({
                fromtaskid: dataset.fromtaskid[k].formatted_data,
                totaskid: dataset.totaskid[k].formatted_data,
                color: dataset.color[k].formatted_data,
                thickness: dataset.thickness[k].formatted_data,
            });
        }
    }
    return ds_connector;
},

各タスクの依存関係を示すためのデータを、JSON の配列に変換して ds_connector にオブジェクトとして格納しています。

processMilestone
processMilestone
processMilestone = function(dataset) {
    var ds_milestone = [];
    for (n=0;n<dataset.type.length;n++){
        if(dataset.type[n].formatted_data === "milestone"){
            ds_milestone.push({
                date: dataset.start[n].formatted_data,
                taskid: dataset.id[n].formatted_data,
                tooltext: dataset.label[n].formatted_data,
                color: dataset.color[n].formatted_data,
                shape: dataset.shape[n].formatted_data,
            });
        }
    }
    return ds_milestone;
},

マイルストーン(キックオフと検収)を表示するためのデータを、JSON の配列に変換して ds_milestone にオブジェクトとして格納しています。

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

チャート左の「タスク」(キックオフから検収まで)欄の情報を描画するためのデータを、JSON の配列に変換して ds_process にオブジェクトとして格納しています。

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

時系列 (1月~3月) の情報を描画するためのデータを、JSON の配列に変換して ds_category にオブジェクトとして格納しています。

doDrawing
doDrawing
doDrawing = function(ds_task, ds_connector, ds_milestone, ds_process, ds_category,  $chartDrawDiv) {
    console.log(JSON.stringify(ds_task));
    console.log(JSON.stringify(ds_connector));
    console.log(JSON.stringify(ds_milestone));
    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: {
                caption: "プロジェクト計画",
                dateformat: "yyyy/mm/dd",
                ganttwidthpercent: "60",
                ganttpaneduration: "40",
                ganttpanedurationunit: "w",
                useverticalscrolling: "0",
                plottooltext: "<b>$label</b><br>開始: <b>$start</b><br>終了: <b>$end</b>",
                theme: "fusion"
            },
            tasks: [{task: ds_task}],
            connectors: [{connector: ds_connector}],
            milestones: [{milestone: ds_milestone}],
            processes: {
                headertext: "タスク",
                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 の中で、タイトルやフォントなどのチャートの見た目を定義しています。
dateformat: "yyyy/mm/dd" で、日付の書式を定義しています。ビューで日付を定義する場合は、この書式と合わせる必要があります。
tasks: [{task: ds_task}],
connectors: [{connector: ds_connector}],
milestones: [{milestone: ds_milestone}],
processes: {headertext: "タスク", align: "center", process: ds_process},
categories: [{category: ds_category}]
上記 5 行で、先の手順でデータセットに取り込んだオブジェクトの中身を FushionCharts に受け渡しています。

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

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

4. 最後に

今回は、極めてシンプルなガントチャートの作成手順を紹介いたしました。ガントチャートの作成に当たっては、プロジェクトごとにタスク種類や期間など、条件に応じて描画する内容を柔軟に変更する必要があります。Yellowfin が参照するデータの設計が重要になってくると考えます。

Anyway, ライブラリーとの連携で、Yellowfin の用途も広がりますね。
では皆様、良いデータ分析とプロジェクト管理を! Cheers!!

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?