I\'d like to create a line chart with Chart.Js
but have the Y-Axis
not move when I scroll.
I\'m assuming I can use a fixed width, and put i
Chart.js 2.x:
CSS:
.graph {
padding: 10px;
position: relative;
overflow-x: scroll;
width: 100%;
.graph-container {
height: 500px;
width: 100%;
min-width: 100%
}
}
HTML : Ignore the angular ngFor
<div *ngFor="let graph of graphs; let i = index" class="graph">
<div class="graph-container">
<canvas #graphCanvas></canvas>
</div>
</div>
JS
Set these options:
options: {
responsive: true,
maintainAspectRatio: false
}
Set the width of the "graph-container"
I'm setting the width based on the number of elements I have X a zoom that the user chooses
graphCanvasElement.nativeElement.parentElement
.setAttribute('style', `width: ${chartData.data.labels.length*graph.zoom}px;min-width: 100%`);
graph.chartObj = new Chart(graphCanvasElement.nativeElement.getContext('2d'), chartData);
To add to Emma Louise's solution above (I don't have the reputation to comment), I found that if I filled the rectangle with a color before drawing the image, the overlay canvas is opaque. Then you don't need to worry about clearing the rectangle, either onProgress or onComplete.
targetCtx.fillStyle = 'white'
targetCtx.fillRect(0, 0, copyWidth * scale, copyHeight * scale);
Also, maybe it's because my devicePixelRatio is one, but these two lines caused the text in my chart to be all fuzzy. It looks fine when I remove them.
targetCtx.canvas.style.width = `${copyWidth}px`;
targetCtx.canvas.style.height = `${copyHeight}px`;
You're pretty much on the right track. If you add another wrapper and the y axis you are done.
Preview
CSS
.chartWrapper {
position: relative;
}
.chartWrapper > canvas {
position: absolute;
left: 0;
top: 0;
pointer-events:none;
}
.chartAreaWrapper {
width: 600px;
overflow-x: scroll;
}
HTML
<div class="chartWrapper">
<div class="chartAreaWrapper">
<canvas id="myChart" height="300" width="1200"></canvas>
</div>
<canvas id="myChartAxis" height="300" width="0"></canvas>
</div>
Script
...
new Chart(ctx).Line(data, {
onAnimationComplete: function () {
var sourceCanvas = this.chart.ctx.canvas;
// the -5 is so that we don't copy the edges of the line
var copyWidth = this.scale.xScalePaddingLeft - 5;
// the +5 is so that the bottommost y axis label is not clipped off
// we could factor this in using measureText if we wanted to be generic
var copyHeight = this.scale.endPoint + 5;
var targetCtx = document.getElementById("myChartAxis").getContext("2d");
targetCtx.canvas.width = copyWidth;
targetCtx.drawImage(sourceCanvas, 0, 0, copyWidth, copyHeight, 0, 0, copyWidth, copyHeight);
}
});
Fiddle - http://jsfiddle.net/mbhavfwm/
with the latest version (2.4.0) this worked for me:
HTML
<div style="width: 100%; overflow-x: auto; overflow-y: hidden">
<div style="width: 3000px; height: 300px">
<canvas id="chart1" height="300" width="0"></canvas>
</div>
</div>
You can also calculate the width
dynamically based on the length of data. For example in VueJS you can do it as follow (considering 30px
for each entry):
VueJS
<div style="width: 100%; overflow-x: auto;">
<div :style="{width: (data.length * 30) + 'px', height: '300px'}">
<canvas id="chart1" height="300" width="0"></canvas>
</div>
</div>
All these answers are rather muddy and complex.. Heres what I went with for my project. I just call fitChart() whenever the dataset changes or the container size changes.
HTML:
<div class="chartWrapper">
<div class="chartContainer">
<canvas id="chart"></canvas>
</div>
</div>
CSS: (Set the width and height to whatever you want)
div.chartWrapper {
position: relative;
overflow: auto;
width: 100%;
}
div.chartContainer {
position: relative;
height: 300px;
}
JS:
var xAxisLabelMinWidth = 15; // Replace this with whatever value you like
var myChart = new Chart(document.getElementById('chart').getContext('2d'), {
type: 'line',
data: {},
options: {
responsive: true,
maintainAspectRatio: false
}
});
function fitChart(){
var chartCanvas = document.getElementById('chart');
var maxWidth = chartCanvas.parentElement.parentElement.clientWidth;
var width = Math.max(mayChart.data.labels.length * xAxisLabelMinWidth, maxWidth);
chartCanvas.parentElement.style.width = width +'px';
}
<ion-content >
<div scrollX="true" scrollY="true" style="overflow:scroll; position:fixed; display:inline; top:0; right:0; bottom:0; left:0; white-space: nowrap;">
<canvas baseChart
[data]="barChartData"
[labels]="barChartLabels"
[options]="barChartOptions"
[colors]="lineChartColors"
[legend]="barChartLegend"
[chartType]="barChartType"
(chartHover)="chartHovered($event)"
(chartClick)="chartClicked($event)">
</canvas>
</div>
<button (click)="randomize()">Update</button>
</ion-content>
It works for me as I set canvas width 700 px and scroll works smoothly.