はじめに
Yellowfin(BIツール)でIoTデータを表示する際にグラフを作成するにあたって、リアルタイムで表現できるものがないか探していたら、chartjs-plugin-streamingで実現できることがわかり、早速手を付けたのですが、なかなかうまく実装できなかったので記事にしてみました。・・・sampleのPlainJSはすごく簡単なのに
アノテーションプラグインでは、limitとしてvalue90の値のところにオレンジの横線をいれ、90以上に赤の薄いboxと-90以下に青の薄いboxを置いています。
Yellowfinでは前からレポートにJSChartを組み込むことで自分でライブラリを読み込んでグラフを描画できたのですが、v9からダッシュボード上にドラッグアンドドロップでレポートを配置したり、より柔軟にデザインできるようになったので、せっかくなのでダッシュボードにHTMLウィジェットを置いて実装していきます。
※データはchartjs-plugin-streamingのサンプル通り、時間はDate.now()、値は-100〜100までの値をとる関数を使用しています。
準備
各ライブラリは下記に配置していきます。YellowfinではROOTフォルダがwebserver上の/になるので適宜実装したい環境によって読み替えてください。
Yellowfin9.2/appserver/webapps/ROOT/js/chartingLibraries
moment.js 使用したバージョン(2.24.0)
Chart.js 使用したバージョン(2.8.0)
chartjs-plugin-annotation.js 使用したバージョン(0.5.7)
chartjs-plugin-streaming.js 使用したバージョン(1.8.0)
今回はこの4つのライブラリとそのプラグインを使っていきます。
HTMLタブ
基本的にはdivとcanvasタグを入れるだけです。YellowfinではHTMLウィジェットを置いて、コードモードにすることで、canvas-areaタグの中に配置します。
<canvas-area xmlns="http://www.w3.org/1999/xhtml" canvas-uuid="22a3ee56-fc20-4c23-82d5-ea659a0c2835">
<custom-html widget-uuid="8bc6dfd7-6b0c-4023-9792-6fe0fa11a066" width="1001" height="785" top="0" left="0" rotation="0" name="カスタムHTML" on-click="none" style="z-index: 1">
<div>
<canvas id="myChart" width="1000" height="600"></canvas>
</div>
</custom-html>
</canvas-area>
JSタブ
ここが一番しんどかったです・・。require.jsの仕様やjavascriptの勉強不足ですね。。まだまだ理解できてないです。。
大事なrequire.configの部分はこんな感じです。
shimのdepsを指定することで、jsの依存性を解決し、読み込む順番をコントロールできます。これを使う方法以外ではrequire関数のネストしかないのかな。
後は、mapで各chart.jsプラグイン中で使われるchart.jsを紐つけます。
全体としてはこんな感じになります。
require.config({
paths: {
moment: "js/chartingLibraries/moment",
chart: "js/chartingLibraries/Chart",
annotation: "js/chartingLibraries/chartjs-plugin-annotation",
streaming: "js/chartingLibraries/chartjs-plugin-streaming"
},
shim: {
chart: {
exports: "C",
deps: ["moment"]
},
annotation: {
exports: "C",
deps: ["chart"]
},
streaming: {
exports: "C",
}
},
map: {
annotation: {
"chart.js": "chart"
},
streaming: {
"chart.js": "chart"
}
}
});
require(["moment", "chart","annotation","streaming"], function(moment, chart) {
var chartColors = {
red: 'rgb(255, 99, 132)',
orange: 'rgb(255, 159, 64)',
yellow: 'rgb(255, 205, 86)',
green: 'rgb(75, 192, 192)',
blue: 'rgb(54, 162, 235)',
purple: 'rgb(153, 102, 255)',
grey: 'rgb(201, 203, 207)'
};
function randomScalingFactor() {
return (Math.random() > 0.5 ? 1.0 : -1.0) * Math.round(Math.random() * 100);
}
function onRefresh(chart) {
chart.config.data.datasets.forEach(function(dataset) {
dataset.data.push({
x: Date.now(),
y: randomScalingFactor()
});
});
}
var color = chart.helpers.color;
var config = {
type: 'line',
data: {
datasets: [{
label: 'データセット1',
backgroundColor: chartColors.red,
borderColor: chartColors.red,
fill: false,
lineTension: 0,
borderDash: [8, 4],
data: []
}, {
label: 'データセット2',
backgroundColor: chartColors.blue,
borderColor: chartColors.blue,
fill: false,
cubicInterpolationMode: 'monotone',
data: []
}]
},
options: {
title: {
display: true,
text: 'annotation and realtime plugin sample'
},
scales: {
xAxes: [{
type: 'realtime',
realtime: {
duration: 20000,
refresh: 1000,
delay: 2000,
onRefresh: onRefresh
}
}],
yAxes: [{
type: 'linear',
display: true,
scaleLabel: {
display: true,
labelString: 'value'
}
}]
},
tooltips: {
mode: 'nearest',
intersect: false
},
hover: {
mode: 'nearest',
intersect: false
},
annotation: {
events: ['click'],
annotations: [
{
drawTime: 'afterDatasetsDraw',
id: 'hline',
type: 'line',
mode: 'horizontal',
scaleID: 'y-axis-0',
value: 90,//randomScalingFactor(),
borderColor: 'rgb(255, 159, 64)',//'black',
borderWidth: 5,
label: {
backgroundColor: 'red',
content: 'limit',
enabled: true
},
onClick: function(e) {
console.log('Annotation', e.type, this);
}
},
{
drawTime: 'beforeDatasetsDraw',
type: 'box',
yScaleID: 'y-axis-0',
yMin: 90,//randomScalingFactor(),
yMax: 100,//randomScalingFactor(),
backgroundColor: color(chartColors.red).alpha(0.25).rgbString(),
borderColor: color(chartColors.purple),
borderWidth: 1,
onClick: function(e) {
console.log('Box', e.type, this);
}
},
{
drawTime: 'beforeDatasetsDraw',
type: 'box',
yScaleID: 'y-axis-0',
yMin: -90,//randomScalingFactor(),
yMax: -100,//randomScalingFactor(),
backgroundColor: color(chartColors.blue).alpha(0.25).rgbString(),
borderColor: color(chartColors.purple),
borderWidth: 1,
onClick: function(e) {
console.log('Box', e.type, this);
}
}
]
}
}
};
var ctx = document.getElementById('myChart').getContext('2d');
window.myChart = new Chart(ctx, config);
});
おわりに
実際のデータで使用するには、データを取得するAPIやプログラムにアクセスして、それをparseしてdataにpushすることになるのでもう少し手をかけないといけないですね。
そして、もっといい方法があれば知りたいです。。プラグインをたくさん入れようとするとさらにconfigの設定が難しくて・・
他の環境で動かない場合は、require.configのpathsかmapのフォルダパスを調整すればいい気がします。1
参考にさせて頂いたところ
https://www.chartjs.org/
https://nagix.github.io/chartjs-plugin-streaming/ja/
Chart.js でリアルタイムストリーミングデータをグラフ化