以前、Google チャートと連携してガントチャートを作成する手順を紹介しました。
今回は、FusionChart との連携でガントチャートを作成してみようと思います。
1. 事前準備
1-1. ビューの作成まで
前回記事 を参考に、『1-2. ビューの作成』 までの作業を実施します。
以下の手順で取り扱うデータをこちらに共有しています。ダウンロードしてご利用ください。
上記から取得したデータを全てビューで参照できるようにします。
1 点、日付データに関しては、FusionCharts 側で設定する書式に合わせてください。今回の場合は yyyy/MM/dd の書式で取り扱うため、サンプルデータの [start] [end] は上記書式に設定する必要があります。ビューで書式を修正する手順に関してはこちらをご確認ください。
2. グラフの作成
準備が整ったら、グラフの作成に手順を進めます。新規でレポートを作成し、以下の手順に従ってグラフを作成します。
2-1. [データ] ステップ
2-2. [グラフ] ステップ
[グラフ] ステップに進み、画面右側 [グラフの選択] から [JavaScriptグラフ] を選択します。
JavaScriptタブ
雛形を全て削除し、以下のコードに置き換えます。コードの処理の内容は後ほど説明します。
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();
});
});
};
プレビュー
[プレビュー] に移り、どのようなチャートが作成されるか確認します。マウスをホバーすると、ツールチップが表示されます。ところでこのプロジェクト、開発実装フェーズの遅延が原因で、もう少しで検収が来期に先送りされるところでしたね。やばいやばい。
3. コードの内容
動作概要が分かったところで、コードの中身を見てみましょう。
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 = 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 の書式になります。各タスクの予定、実績、遅延の状況を水平バーで示すために必要な情報です。
画面は [グラフ] ステップでディベロッパーツールのコンソールから確認したものです。コードの中に console.log(JSON.stringify(ds_task))
を記述しておくと、データオブジェクトの中身をコンソールで確認することができます。今回の場合は、doDrawing の先頭に記述しています。デバッグに便利なので、活用してみてください。
以下の手順では、上記と同じ要領で、ガントチャートを描くために必要なデータを各関数の中データセットで取り込んでいく流れになります。機能毎にどのようなデータが必要となるかは、こちらで詳しく紹介しています。これ以降の説明と合わせてご確認ください。
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 = 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 = 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 = 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 = 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
はコードの先頭で宣言した変数です。
width
と height
はダッシュボードの大きさなどに合わせてピクセル単位で指定します。FusionCharts のサンプルを見ると、%で指定していますが、Yellowfin で扱う場合は、ピクセルで指定した方がきれいに表示されます。
4. 最後に
今回は、極めてシンプルなガントチャートの作成手順を紹介いたしました。ガントチャートの作成に当たっては、プロジェクトごとにタスク種類や期間など、条件に応じて描画する内容を柔軟に変更する必要があります。Yellowfin が参照するデータの設計が重要になってくると考えます。
Anyway, ライブラリーとの連携で、Yellowfin の用途も広がりますね。
では皆様、良いデータ分析とプロジェクト管理を! Cheers!!