Chart.jsで作る「kintoneのダッシュボード」
※当記事の内容はサポート対象外です
こんにちは。武井です。
ダッシュボードの季節ですね。
目次
kintoneのグラフ解析
kintoneの標準グラフにはHigh Chartsが採用されているようです。
High Chartsの特徴としては、
- 見た目が綺麗
- 使用に便利
- カスタムに融通が利く
と最強らしいのですが、有料です。
一方、今回使用するChart.jsは無料チャートライブラリの中では一強の様相を呈しています。
ただし、Chart.jsはやや融通の利かない部分があります。
ダッシュボード作ってみた
こんなん作ってみました。
詳しくは下記記事に譲りますが、
kintoneの標準機能にないグラフを厳選してChart.jsで実現したところが売りとなっております。
■Chart.jsを使ってダッシュボードを作ってみよう!
https://cybozudev.zendesk.com/hc/ja/articles/214479043
上記記事と参考画像では説明不足だったのですが、
下図のようなインタフェースも導入しているので、非常に使い勝手はよいです。
右下部分が空白地帯でちょっと寂しいのは作業時間の関係上となります(゚゚;)
ダッシュボードをポータルに表示する
さて、kintone公式ではめったなことでDOMを操作してはいけないことになっていますので、
上記記事ではアプリ内にダッシュボードを表示していますが、
こちらでは例によってDOMをいじりまくることでポータルにダッシュボードを表示してしまう魔改造を披露していきたいと思います。
完成イメージ
ぶっちゃけ使いやすさは圧倒的にこちらですね!
コードを一応すべて載せますが、アプリ版との違いは、ほぼほぼ「// URLが変更される場合のチャート書き直し処理」からcreateSlider関数までの部分のみです。
(function() {
"use strict";
// 販売実績アプリID
var SALES_APPID = 70;
// 試用申し込み管理アプリID
var TRIAL_APPID = 71;
var oneTimeFlg = true;
var chart1, chart2, chart3;
var onceFlg = true;
/* 【参考】ドーナツグラフの各項目を常に表示
Chart.pluginService.register({
beforeRender: function (chart) {
if (chart.config.options.showAllTooltips) {
chart.pluginTooltips = [];
chart.config.data.datasets.forEach(function (dataset, i) {
chart.getDatasetMeta(i).data.forEach(function (sector, j) {
chart.pluginTooltips.push(new Chart.Tooltip({
_chart: chart.chart,
_chartInstance: chart,
_data: chart.data,
_options: chart.options.tooltips,
_active: [sector]
}, chart));
});
});
chart.options.tooltips.enabled = false;
}
},
afterDraw: function (chart, easing) {
if (chart.config.options.showAllTooltips) {
if (!chart.allTooltipsOnce) {
if (easing !== 1)
return;
chart.allTooltipsOnce = true;
}
chart.options.tooltips.enabled = true;
Chart.helpers.each(chart.pluginTooltips, function (tooltip) {
tooltip.initialize();
tooltip.update();
tooltip.pivot();
tooltip.transition(easing).draw();
});
chart.options.tooltips.enabled = false;
}
}
});*/
// URLが変更される場合のチャート書き直し処理
window.onhashchange = firstFunc;
// ポータルを最初に読み込んだ時のチャート表示処理
window.onload = firstFunc;
function firstFunc() {
if (onceFlg) {
if (location.href.indexOf("/#/portal") > 0) {
onceFlg = false;
var portalInterval = setInterval(function () {
if ($(".ocean-portal-announcement .gaia-argoui-widget-menu").length > 0) {
clearInterval(portalInterval);
$(".ocean-portal-announcement .gaia-argoui-widget-menu").css("display", "block");
$(".ocean-portal-announcement .gaia-argoui-widget-menu").append('<div id="slider" style="margin-left:30px"></div><br /><p id="p1" style="margin-left:30px;">■売上高(前年同月比)</p><div id="canvas1Div" style="margin-left:30px;"><canvas id="canvas1"></canvas></div><br /><p id="p2" style="margin-left:30px;">■売上高・試用申込数</p><div id="canvas2Div" style="margin-left:30px;"><canvas id="canvas2"></canvas></div><br /><p id="p3" style="margin-left:30px;">■製品別売上高</p><div id="canvas3Div" style="margin-left:30px"><canvas id="canvas3"></canvas></div>');
createCompareGraph();
// お知らせを更新した場合等、URLが変わらずに画面が更新されるパターンでアプリ一覧を表示し直す処理
var rePortalInterval = setInterval(function () {
if ($("#slider").length === 0) {
clearInterval(rePortalInterval);
oneTimeFlg = true;
firstFunc();
}
}, 500);
}
}, 100);
}
}
}
function createSlider() {
$("#slider").dateRangeSlider();
$("#slider").dateRangeSlider(
"option",
{
bounds: {
min: moment().add(-5, 'years').startOf("month").toDate(),
max: moment().startOf("month").toDate()
},
step: {
months: 1
},
range: {
min: {months: 11},
max: {months: 11}
},
formatter: function(val) {
return moment(val).format("YYYY年M月");
}
}
).bind("userValuesChanged", function(e, data) {
// スライダーを動かした場合
createCompareGraph(data.values.min, data.values.max);
});
reset();
oneTimeFlg = false;
}
function reset() {
// スライダーの初期位置
$("#slider").dateRangeSlider("values", moment().add(-1, 'years').startOf("month").toDate(), moment().startOf("month").toDate());
// スライダーの位置を微調整
$("#slider").css("margin-bottom", "20px");
}
function createCompareGraph(min, max) {
//setLoading();
var maxMonth, maxMonth2, minMonth, minMonth2, elevenMonthsBefore, tenMonthsBefore, nineMonthsBefore, eightMonthsBefore, sevenMonthsBefore, sixMonthsBefore, fiveMonthsBefore, fourMonthsBefore, threeMonthsBefore, twoMonthsBefore, oneMonthBefore, thisMonth;
if (max) {
maxMonth = '"' + moment(max).endOf("month").format('YYYY-MM-DD') + '"';
maxMonth2 = moment(max).add(-12, "months").endOf("month").format('YYYY-MM-DD');
elevenMonthsBefore = moment(max).add(-11, 'months').format("M月");
tenMonthsBefore = moment(max).add(-10, 'months').format("M月");
nineMonthsBefore = moment(max).add(-9, 'months').format("M月");
eightMonthsBefore = moment(max).add(-8, 'months').format("M月");
sevenMonthsBefore = moment(max).add(-7, 'months').format("M月");
sixMonthsBefore = moment(max).add(-6, 'months').format("M月");
fiveMonthsBefore = moment(max).add(-5, 'months').format("M月");
fourMonthsBefore = moment(max).add(-4, 'months').format("M月");
threeMonthsBefore = moment(max).add(-3, 'months').format("M月");
twoMonthsBefore = moment(max).add(-2, 'months').format("M月");
oneMonthBefore = moment(max).add(-1, 'months').format("M月");
thisMonth = moment(max).format("M月");
} else {
maxMonth = "THIS_MONTH()";
maxMonth2 = moment().add(-12, "months").endOf("month").format('YYYY-MM-DD');
elevenMonthsBefore = moment().add(-11, 'months').format("M月");
tenMonthsBefore = moment().add(-10, 'months').format("M月");
nineMonthsBefore = moment().add(-9, 'months').format("M月");
eightMonthsBefore = moment().add(-8, 'months').format("M月");
sevenMonthsBefore = moment().add(-7, 'months').format("M月");
sixMonthsBefore = moment().add(-6, 'months').format("M月");
fiveMonthsBefore = moment().add(-5, 'months').format("M月");
fourMonthsBefore = moment().add(-4, 'months').format("M月");
threeMonthsBefore = moment().add(-3, 'months').format("M月");
twoMonthsBefore = moment().add(-2, 'months').format("M月");
oneMonthBefore = moment().add(-1, 'months').format("M月");
thisMonth = moment().format("M月");
}
if (min) {
minMonth = moment(min).format('YYYY-MM-DD');
minMonth2 = moment(min).add(-12, "months").startOf("month").format('YYYY-MM-DD');
} else {
minMonth = moment().add(-11, "months").startOf("month").format('YYYY-MM-DD');
minMonth2 = moment().add(-23, "months").startOf("month").format('YYYY-MM-DD');
}
// 今月から一年前までのレコード取得
fetchRecords(SALES_APPID, '日付 <= ' + maxMonth + ' and 日付 >= "' + minMonth + '" order by 日付 asc').then(function(canvas1Rec) {
var data = [];
data[elevenMonthsBefore] = 0;
data[tenMonthsBefore] = 0;
data[nineMonthsBefore] = 0;
data[eightMonthsBefore] = 0;
data[sevenMonthsBefore] = 0;
data[sixMonthsBefore] = 0;
data[fiveMonthsBefore] = 0;
data[fourMonthsBefore] = 0;
data[threeMonthsBefore] = 0;
data[twoMonthsBefore] = 0;
data[oneMonthBefore] = 0;
data[thisMonth] = 0;
for (var i = 0; i < canvas1Rec.length; i++) {
var month;
var date = canvas1Rec[i].日付.value.split("-");
if (date[1].charAt(0) === "0") {
month = date[1].charAt(1) + "月";
} else {
month = date[1] + "月";
}
data[month] += parseInt(canvas1Rec[i].販売額.value, 10);
}
var eventuallyThisYearData = [data[elevenMonthsBefore], data[tenMonthsBefore], data[nineMonthsBefore], data[eightMonthsBefore], data[sevenMonthsBefore], data[sixMonthsBefore], data[fiveMonthsBefore], data[fourMonthsBefore], data[threeMonthsBefore], data[twoMonthsBefore], data[oneMonthBefore], data[thisMonth]];
fetchRecords(SALES_APPID, '日付 <= "' + maxMonth2 + '" and 日付 >= "' + minMonth2 + '" order by 日付 asc').then(function(canvas1Rec2) {
fetchRecords(TRIAL_APPID, '日付 <= ' + maxMonth + ' and 日付 >= "' + minMonth + '" order by 日付 asc').then(function(canvas2Rec) {
data = refreshData(data);
// 前年同月比グラフのデータ作成
for (var j = 0; j < canvas1Rec2.length; j++) {
var month2;
var date2 = canvas1Rec2[j].日付.value.split("-");
if (date2[1].charAt(0) === "0") {
month2 = date2[1].charAt(1) + "月";
} else {
month2 = date2[1] + "月";
}
data[month2] += parseInt(canvas1Rec2[j].販売額.value, 10);
}
var eventuallyLastYearData = [data[elevenMonthsBefore], data[tenMonthsBefore], data[nineMonthsBefore], data[eightMonthsBefore], data[sevenMonthsBefore], data[sixMonthsBefore], data[fiveMonthsBefore], data[fourMonthsBefore], data[threeMonthsBefore], data[twoMonthsBefore], data[oneMonthBefore], data[thisMonth]];
data = refreshData(data);
// ミックスドグラフのデータ作成
for (var k = 0; k < canvas2Rec.length; k++) {
var month3;
var date3 = canvas2Rec[k].日付.value.split("-");
if (date3[1].charAt(0) === "0") {
month3 = date3[1].charAt(1) + "月";
} else {
month3 = date3[1] + "月";
}
data[month3] += 1;
}
var eventuallyTrialData = [data[elevenMonthsBefore], data[tenMonthsBefore], data[nineMonthsBefore], data[eightMonthsBefore], data[sevenMonthsBefore], data[sixMonthsBefore], data[fiveMonthsBefore], data[fourMonthsBefore], data[threeMonthsBefore], data[twoMonthsBefore], data[oneMonthBefore], data[thisMonth]];
// ドーナツグラフのデータ作成
var prodData = [];
var prodLabels = [];
for (var l = 0; l < canvas1Rec.length; l++) {
var prod = canvas1Rec[l].製品名.value;
if (typeof (prodData[prod]) === "undefined") {
prodData[prod] = 0;
prodLabels.push(prod);
}
prodData[prod] += parseInt(canvas1Rec[l].販売額.value, 10);
}
var eventuallyByProductData = [];
// 製品背景色
var prodBGColorMST = {
プリントクリエイター: "rgba(54, 162, 235, 0.4)",
フォームクリエイター: "rgba(255, 99, 132, 0.4)",
kBackup: "rgba(0, 100, 0, 0.4)",
kViewer: "rgba(255, 60, 255, 0.4)",
タイムスタンプ: "rgba(255, 255, 0, 0.4)",
メールワイズ: "rgba(255, 112, 0, 0.4)",
ガルーン: "rgba(60, 60, 120, 0.4)",
kintone: "rgba(255, 0, 0, 0.4)",
安否確認: "rgba(0, 255, 255, 0.4)"
};
// 【参考】製品縁取り色
/*var prodBDColorMST = {
プリントクリエイター:"rgba(54, 162, 235, 1)",
フォームクリエイター:"rgba(255,99,132,1)",
kBackup:"rgba(0, 170, 0, 1)",
kViewer:"rgba(255, 170, 255, 1)",
タイムスタンプ:"rgba(255, 255, 0, 1)",
メールワイズ:"rgba(255, 112, 0, 1)",
ガルーン:"rgba(100, 0, 0, 1)",
kintone:"rgba(255, 184, 184, 1)",
安否確認:"rgba(0, 255, 255, 1)"
};*/
var prodBGColor = [];
//var prodBDColor = [];
// 降順にソート
prodLabels.sort(function(a, b) {
if (prodData[a] > prodData[b]) {
return -1;
}
if (prodData[a] < prodData[b]) {
return 1;
}
return 0;
});
for (var m = 0; m < prodLabels.length; m++) {
eventuallyByProductData.push(prodData[prodLabels[m]]);
prodBGColor.push(prodBGColorMST[prodLabels[m]]);
// 【参考】縁取り色をつける場合
//prodBDColor.push(prodBDColorMST[prodLabels[m]]);
// 【参考】ランダムで配色する場合の処理
//prodBGColor.push(dynamicColors());
//prodBDColor.push(dynamicColors());
}
// 前年同月比グラフを描画
var ctx = document.getElementById("canvas1");
if (chart1) {
chart1.destroy();
}
chart1 = new Chart(ctx, {
type: 'bar',
data: {
labels: [elevenMonthsBefore, tenMonthsBefore, nineMonthsBefore, eightMonthsBefore, sevenMonthsBefore, sixMonthsBefore, fiveMonthsBefore, fourMonthsBefore, threeMonthsBefore, twoMonthsBefore, oneMonthBefore, thisMonth],
datasets: [
{
label: '前年同月売上',
data: eventuallyLastYearData,
backgroundColor: "rgba(54, 162, 235, 0.2)",
borderColor: 'rgba(54, 162, 235, 1)',
borderWidth: 1
},
{
label: min ? moment(min).format('YYYY年M月~') + moment(max).format('YYYY年M月売上') : moment().add(-11, "months").format('YYYY年M月~') + moment().format('YYYY年M月売上'),
data: eventuallyThisYearData,
backgroundColor: 'rgba(255, 99, 132, 0.2)',
borderColor: 'rgba(255,99,132,1)',
borderWidth: 1
}
]
},
options: {
scales: {
yAxes: [{
display: true,
scaleLabel: {
display: true,
labelString: '売上',
fontFamily: 'monospace'
},
ticks: {
beginAtZero: true,
maxTicksLimit: 8,
callback: function(value) {
return value + '万円';
}
}
}]
},
tooltips: {
enabled: true,
mode: 'single',
callbacks: {
title: function(tooltipItems, titleData) {
var val = $("#slider").dateRangeSlider("values");
var min2 = moment(val.min);
var tmp = tooltipItems[0].xLabel.split("月");
var first = moment(min2.format("YYYY-") + tmp[0] + '-1', 'YYYY-M-D');
if (first.isBetween(min2, moment(val.max), null, '[]')) {
if (tooltipItems[0].datasetIndex === 0) {
return min2.add(-1, 'years').format("YYYY年") + tmp[0] + '月';
}
return min2.format("YYYY年") + tmp[0] + '月';
}
if (tooltipItems[0].datasetIndex === 0) {
return min2.format("YYYY年") + tmp[0] + '月';
}
return min2.add(1, 'years').format("YYYY年") + tmp[0] + '月';
},
label: function(tooltipItems, data3) {
return tooltipItems.yLabel + '万円';
}
}
}
}
});
// mixedグラフを描画
var ctx2 = document.getElementById("canvas2");
if (chart2) {
chart2.destroy();
}
chart2 = new Chart(ctx2, {
type: 'bar',
data: {
labels: [elevenMonthsBefore, tenMonthsBefore, nineMonthsBefore, eightMonthsBefore, sevenMonthsBefore, sixMonthsBefore, fiveMonthsBefore, fourMonthsBefore, threeMonthsBefore, twoMonthsBefore, oneMonthBefore, thisMonth],
datasets: [
{
yAxisID: "y-axis-1",
type: 'line',
label: '試用申込数',
data: eventuallyTrialData,
backgroundColor: "rgba(54, 162, 235, 0.2)",
borderColor: 'rgba(54, 162, 235, 1)',
borderWidth: 1
},
{
yAxisID: "y-axis-0",
type: 'bar',
label: min ? moment(min).format('YYYY年M月~') + moment(max).format('YYYY年M月売上') : moment().add(-11, "months").format('YYYY年M月~') + moment().format('YYYY年M月売上'),
data: eventuallyThisYearData,
backgroundColor: 'rgba(255, 99, 132, 0.2)',
borderColor: 'rgba(255,99,132,1)',
borderWidth: 1
}
]
},
options: {
scales: {
yAxes: [{
position: "left",
id: "y-axis-0",
display: true,
scaleLabel: {
display: true,
labelString: '売上',
fontFamily: 'monospace'
},
ticks: {
beginAtZero: true,
maxTicksLimit: 8,
callback: function(value) {
return value + '万円';
}
}
}, {
position: "right",
id: "y-axis-1",
display: true,
scaleLabel: {
display: true,
labelString: '試用申込数',
fontFamily: 'monospace'
},
ticks: {
beginAtZero: true,
maxTicksLimit: 6
}
}]
},
tooltips: {
enabled: true,
mode: 'single',
callbacks: {
title: function(tooltipItems, data4) {
var val = $("#slider").dateRangeSlider("values");
var min3 = moment(val.min);
var tmp = tooltipItems[0].xLabel.split("月");
var first = moment(min3.format("YYYY-") + tmp[0] + '-1', 'YYYY-M-D');
if (first.isBetween(min3, moment(val.max), null, '[]')) {
return min3.format("YYYY年") + tmp[0] + '月';
}
return min3.add(1, 'years').format("YYYY年") + tmp[0] + '月';
},
label: function(tooltipItems, data5) {
if (tooltipItems.datasetIndex === 0) {
return '試用申込数:' + tooltipItems.yLabel;
}
return '売上:' + tooltipItems.yLabel + '万円';
}
}
}
}
});
// ドーナツグラフを描画
var ctx3 = document.getElementById("canvas3");
if (chart3) {
chart3.destroy();
}
chart3 = new Chart(ctx3, {
type: 'doughnut',
data: {
labels: prodLabels,
datasets: [
{
label: min ? moment(min).format('YYYY年M月~') + moment(max).format('YYYY年M月売上') : moment().add(-11, "months").format('YYYY年M月~') + moment().format('YYYY年M月売上'),
data: eventuallyByProductData,
backgroundColor: prodBGColor,
//borderColor: prodBDColor,
borderWidth: 1
}
]
},
options: {
showAllTooltips: true,
animation: {
animateScale: true
},
tooltips: {
callbacks: {
title: function(tooltipItems, data6) {
return data6.labels[tooltipItems[0].index];
},
label: function(tooltipItems, data7) {
var sum = 0;
for (var n = 0; n < data7.datasets[0].data.length; n++) {
sum += data7.datasets[0].data[n];
}
var per = Math.round((data7.datasets[0].data[tooltipItems.index] / sum * 100));
return per + '% ' + data7.datasets[0].data[tooltipItems.index] + '万円';
}
}
}
}
});
// グラフのデフォルトフォントサイズ
Chart.defaults.global.defaultFontSize = 14;
// 期間指定スライダーの横幅調整
$("#slider").css("width", "90%");
// スライダーの作成は画面読み込み時のみ
if (oneTimeFlg) {
createSlider();
}
onceFlg = true;
//removeLoading();
});
});
});
}
// data配列の中身を消す関数
function refreshData(data) {
for (var key in data) {
data[key] = 0;
}
return data;
}
// 全レコード取得関数
function fetchRecords(appId, query, opt_offset, opt_limit, opt_records) {
var offset = opt_offset || 0;
var limit = opt_limit || 100;
var allRecords = opt_records || [];
var params = {
app: appId,
query: query + ' limit ' + limit + ' offset ' + offset
};
return kintone.api('/k/v1/records', 'GET', params).then(function(resp) {
allRecords = allRecords.concat(resp.records);
if (resp.records.length === limit) {
return fetchRecords(appId, query, offset + limit, limit, allRecords);
}
return allRecords;
});
}
// ローディング画面を出す関数
// function setLoading() {
// var $body = $('body');
// $body.css('width', '100%');
//
// var $loading = $('<div>').attr('id', 'loading').attr('class', 'loading')
// .attr('style', 'width: 100%; height: 100%; position:absolute;' +
// ' top:0; left:0; text-align:center; background-color:#666666; opacity:0.6; z-index: 9;');
// var $div = $('<div>').attr('id', 'imgBox').attr('style', 'width: 100%; height: 100%;');
// var $img = $('<img>').attr('src', 'data:image/gif;base64,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');
// $loading.append($div.append($img));
// $body.append($loading);
//
// $('#imgBox').attr('style', 'margin-top: ' + Math.floor($('#loading').height() / 2) + 'px;');
//
// $body.css('position', 'fixed');
//
// var autoRemoveCnt = 0;
// var autoRemoveInterval = setInterval(function() {
// autoRemoveCnt++;
// if (autoRemoveCnt > 9) {
// clearInterval(autoRemoveInterval);
// removeLoading();
// }
// }, 1000);
// }
// ローディング画面を消す関数
// function removeLoading() {
// var $loading = $('.loading');
// $loading.remove();
//
// var $body = $('body');
// $body.css('position', '');
// }
// 【参考】ドーナツグラフの各製品色をランダムに決定する関数
// function dynamicColors() {
// var r = Math.floor(Math.random() * 255);
// var g = Math.floor(Math.random() * 255);
// var b = Math.floor(Math.random() * 255);
// return "rgb(" + r + "," + g + "," + b + ")";
// }
})();
感想
他のデベロッパーサイト記事と比して私の記事のコード量に圧倒されますね(゜o ゜;)
Chart.jsではできないことが割と多いので、「いかにChart.jsを要件に寄せるか」ではなく「いかに要件をChart.jsに寄せるか」が問われます(SIer的に考えて)。


