Scrollable chart with fixed Y axis by Chart.js
Sorry, comments are described in Japanese. This page owes much to the following page: https://jsfiddle.net/EmmaLouise/eb1aqpx8/3/
by oktopus1959
HTML
<!-- スクロール可能グラフ領域のラッパーブロック -->
<div class="scrollableChartWrapper">
<!-- スクロールされる canvas を持つ div:
- style.width を省略すると div の幅がページ幅に合わせられる;
- style.width を指定すると div の幅(≒スクロールバーの長さ)が固定される -->
<div>
<!-- グラフ描画用 canvas:
- style.height は必須;
- style.width は JS によって設定する;
- width,height は Chart により設定される -->
<canvas id="chart" style="height: 250px"></canvas>
</div>
<!-- Y軸イメージコピー用 canvas: {style.,}{height,width} は JS によって設定する -->
<canvas id="yAxis" width="0"></canvas>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.js"></script>
CSS
/* 配置の基準となるラッパーブロック; 背景色も設定する */
.scrollableChartWrapper {
position: relative;
background-color: ghostwhite;
}
/* スクロール可能グラフを囲む div */
.scrollableChartWrapper > div {
position: relative;
overflow-x: scroll;
}
/* Y軸イメージコピー用 canvas */
.scrollableChartWrapper > canvas {
position: absolute; /* これにより、上の div と重なる位置に canvas が配置される */
left: 0;
top: 0;
background-color: ghostwhite; /* ここをコメントアウトすると、背景色が透明になるので、Y軸を透かしてグラフ部分が見えるようになる */
}
JavaScript
// Y軸コピー用 canvas
var cvsYAxis = document.getElementById('yAxis');
var ctxYAxis = cvsYAxis.getContext('2d');
// テスト用データ
var data = [];
var labels = [];
var colors = [];
for (i = 0; i < 15; i += 1) {
[12, 19, 3, 5, 2, 3].forEach(x => { data.push(x); });
['Red', 'Blue', 'Yellow', 'Green', 'Purple', 'Orange'].forEach(x => { labels.push(x); });
[ 'rgb(255, 99, 132)',
'rgb(54, 162, 235)',
'rgb(255, 206, 86)',
'rgb(75, 192, 192)',
'rgb(153, 102, 255)',
'rgb(255, 159, 64)'].forEach(x => { colors.push(x); });
}
// X軸の1データ当たりの幅
var xAxisStepSize = 30;
// グラフ全体の幅を計算
var chartWidth = data.length * xAxisStepSize;
// グラフ描画用 canvas
var cvsChart = document.getElementById('chart');
var ctxChart = cvsChart.getContext('2d');
// Chart用canvasのstyle.width(すなわち実際に描画されるべきサイズ)に上記の幅を設定
cvsChart.style.width = chartWidth + "px";
// canvas.width(height)はグラフ描画時に Chart により変更される(らしい)ので、下記はやる必要なし
//cvsChart.width = chartWidth;
//cvsChart.height = chartHeight;
// 二重実行防止用フラグ
var copyYAxisCalled = false;
// Y軸イメージのコピー関数
function copyYAxisImage(chart) {
//console.log("copyYAxisCalled="+copyYAxisCalled);
if (copyYAxisCalled) return;
copyYAxisCalled = true;
// グラフ描画後は、canvas.width(height):canvas.style.width(height) 比は、下記 scale の値になっている
var scale = window.devicePixelRatio;
// Y軸のスケール情報
var yAxScale = chart.scales['y-axis-0'];
// Y軸部分としてグラフからコピーすべき幅 (TODO: 良く分かっていない)
var yAxisStyleWidth0 = yAxScale.width - 10;
// canvas におけるコピー幅(yAxisStyleWidth0を直接使うと微妙にずれるので、整数値に切り上げる)
var copyWidth = Math.ceil(yAxisStyleWidth0 * scale);
// Y軸canvas の幅(右側に少し空白部を残す)
var yAxisCvsWidth = copyWidth + 4;
// 実際の描画幅(styleに設定する)
var yAxisStyleWidth = yAxisCvsWidth / scale;
// Y軸部分としてグラフからコピーすべき高さ (TODO: 良く分かっていない) ⇒これを実際の描画高とする(styleに設定)
var yAxisStyleHeight = yAxScale.height + yAxScale.top + 10;
// canvas におけるコピー高
var copyHeight = yAxisStyleHeight * scale;
// Y軸canvas の高さ
var yAxisCvsHeight = copyHeight;
console.log("After chart canvas...