Chart.js を使うと、レスポンシブ対応した各種グラフを簡単に実現できて便利です。便利でよく使うのですが、それ故にカスタマイズしたくなることも少なからず発生します。
例えばこんな例です。Chart.js を使うと水平の積み上げ棒グラフもこんな感じで作れるのですが・・・

このグラフの特定部分に追加の描画を加えたくなることがあります。例えばある値やエリアを強調表示するために塗りつぶしたい、といったカスタマイズです。カスタマイズ後の例としてはこんな感じ:

↑横軸の 450 ~ 550 部分を薄くピンクで塗りつぶして強調
これを実現するには Chart.js のカスタマイズが必要になります。具体的にはヘルパー機能を使って水平棒グラフの draw() メソッドを拡張し、本来の draw() メソッド実行後に Canvas のグラフィックコンテキストを使って直線や矩形を追加で描画する、というカスタマイズを行います(変更箇所を赤で表記):
変に HTML5 Canvas に慣れていると、グラフィックコンテキストを取得して自由に描画して、・・・というカスタマイズを考えてしまうのですが、Chart.js でそのようにすると描画した部分を別のタイミングで Chart.js が上書きしてしまったりして、想定通りにカスタマイズできないことが多くあります。そのためか、上記のようなカスタマイズのためのヘルパーが用意されていて、その中でカスタマイズを行う、という手法を実装する必要があるようです。
例えばこんな例です。Chart.js を使うと水平の積み上げ棒グラフもこんな感じで作れるのですが・・・

:
:
<script src="//code.jquery.com/jquery-2.2.4.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.3/Chart.min.js"></script>
:
:
<script>
var data = {
labels: [ 'カレーライス', 'ラーメン', 'ハンバーグ', 'サラダ' ],
datasets: [{
label: '脂質',
data: [ 500, 300, 400, 100 ],
backgroundColor: 'rgba( 255, 100, 100, 1 )'
},
{
label: 'たんぱく質',
data: [ 300, 250, 400, 200 ],
backgroundColor: 'rgba( 100, 100, 255, 1 )'
},
{
label: '炭水化物',
data: [ 200, 300, 100, 50 ],
backgroundColor: 'rgba( 100, 255, 100, 1 )'
}],
};
var options = {
scales: {
title: {
display: true,
text: '三大栄養素別比較',
padding: 3
},
xAxes: [{
display: true,
scaleLabel: {
display: true,
labelString: 'mg'
},
ticks: {
min: 0
},
stacked: true //. 積み上げ棒グラフ
}],
yAxes: [{
display: true,
scaleLabel: {
display: true,
labelString: ''
},
stacked: true //. 積み上げ棒グラフ
}]
},
legend: {
labels: {
boxWidth: 30,
padding: 20
},
display: true
},
tooltips: {
titleFontSize: 20,
bodyFontSize: 20,
mode: 'label'
}
};
$(function(){
var ctx1 = document.getElementById( 'myChart1' );
var graph1 = {
type: 'horizontalBar',
data: data,
options: options
};
var myChart1 = new Chart( ctx1, graph1 );
});
</script>
:
:
<canvas id="myChart1" style="position:relative; width:900; height:300;"></canvas>
:
:
このグラフの特定部分に追加の描画を加えたくなることがあります。例えばある値やエリアを強調表示するために塗りつぶしたい、といったカスタマイズです。カスタマイズ後の例としてはこんな感じ:

↑横軸の 450 ~ 550 部分を薄くピンクで塗りつぶして強調
これを実現するには Chart.js のカスタマイズが必要になります。具体的にはヘルパー機能を使って水平棒グラフの draw() メソッドを拡張し、本来の draw() メソッド実行後に Canvas のグラフィックコンテキストを使って直線や矩形を追加で描画する、というカスタマイズを行います(変更箇所を赤で表記):
:
:
var options = {
scales: {
title: {
display: true,
text: '三大栄養素別比較',
padding: 3
},
xAxes: [{
display: true,
scaleLabel: {
display: true,
labelString: 'mg'
},
ticks: {
min: 0
},
stacked: true //. 積み上げ棒グラフ
}],
yAxes: [{
display: true,
scaleLabel: {
display: true,
labelString: ''
},
stacked: true //. 積み上げ棒グラフ
}]
},
lineAtX1: 450, //. この位置に矩形を描画
lineAtX2: 550, //. この位置に矩形を描画
legend: {
labels: {
boxWidth: 30,
padding: 20
},
display: true
},
tooltips: {
//enabled: false,
titleFontSize: 20,
bodyFontSize: 20,
mode: 'label'
}
};
//. hozirontalBar を拡張
var originalLineDraw = Chart.controllers.horizontalBar.prototype.draw;
Chart.helpers.extend(Chart.controllers.horizontalBar.prototype, {
draw: function () {
//. 本来の hozizontalBar を描画
originalLineDraw.apply(this, arguments);
var chart = this.chart;
var ctx = chart.chart.ctx; //. グラフィックコンテキスト
var lineAtX1 = chart.config.options.lineAtX1;
var lineAtX2 = chart.config.options.lineAtX2;
if( lineAtX1 && lineAtX2 ){
var xaxis = chart.scales['x-axis-0'];
var yaxis = chart.scales['y-axis-0'];
//. 軸の値をグラフィックコンテキストの座標に変換
var x1 = xaxis.getPixelForValue( lineAtX1 );
var y1 = yaxis.top;
var x2 = xaxis.getPixelForValue( lineAtX2 );
var y2 = yaxis.bottom;
ctx.save();
ctx.beginPath();
ctx.lineWidth = 5;
ctx.fillStyle = 'rgba(255,200,200,0.1)';
ctx.fillRect( x1, y1, x2 - x1, y2 - y1 );
ctx.restore();
}
}
});
:
:
変に HTML5 Canvas に慣れていると、グラフィックコンテキストを取得して自由に描画して、・・・というカスタマイズを考えてしまうのですが、Chart.js でそのようにすると描画した部分を別のタイミングで Chart.js が上書きしてしまったりして、想定通りにカスタマイズできないことが多くあります。そのためか、上記のようなカスタマイズのためのヘルパーが用意されていて、その中でカスタマイズを行う、という手法を実装する必要があるようです。

コメント