score:23
Chart.js 2.7.2: https://jsfiddle.net/EmmaLouise/eb1aqpx8/3/
This approach handles different DPR settings and will scale the axis to match the scaling that Chart.js applies to its charts. It also calls .clearRect() on the original Y axis that Chart.js draws, clearing the pixels in the defined area which means that there is no duplication of axes or overlaps.
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">
<div class="chartAreaWrapper2">
<canvas id="chart-Test" height="300" width="1200"></canvas>
</div>
</div>
<canvas id="axis-Test" height="300" width="0"></canvas>
</div>
JS:
$(function () {
var rectangleSet = false;
var canvasTest = $('#chart-Test');
var chartTest = new Chart(canvasTest, {
type: 'bar',
data: chartData,
maintainAspectRatio: false,
responsive: true,
options: {
tooltips: {
titleFontSize: 0,
titleMarginBottom: 0,
bodyFontSize: 12
},
legend: {
display: false
},
scales: {
xAxes: [{
ticks: {
fontSize: 12,
display: false
}
}],
yAxes: [{
ticks: {
fontSize: 12,
beginAtZero: true
}
}]
},
animation: {
onComplete: function () {
if (!rectangleSet) {
var scale = window.devicePixelRatio;
var sourceCanvas = chartTest.chart.canvas;
var copyWidth = chartTest.scales['y-axis-0'].width - 10;
var copyHeight = chartTest.scales['y-axis-0'].height + chartTest.scales['y-axis-0'].top + 10;
var targetCtx = document.getElementById("axis-Test").getContext("2d");
targetCtx.scale(scale, scale);
targetCtx.canvas.width = copyWidth * scale;
targetCtx.canvas.height = copyHeight * scale;
targetCtx.canvas.style.width = `${copyWidth}px`;
targetCtx.canvas.style.height = `${copyHeight}px`;
targetCtx.drawImage(sourceCanvas, 0, 0, copyWidth * scale, copyHeight * scale, 0, 0, copyWidth * scale, copyHeight * scale);
var sourceCtx = sourceCanvas.getContext('2d');
// Normalize coordinate system to use css pixels.
sourceCtx.clearRect(0, 0, copyWidth * scale, copyHeight * scale);
rectangleSet = true;
}
},
onProgress: function () {
if (rectangleSet === true) {
var copyWidth = chartTest.scales['y-axis-0'].width;
var copyHeight = chartTest.scales['y-axis-0'].height + chartTest.scales['y-axis-0'].top + 10;
var sourceCtx = chartTest.chart.canvas.getContext('2d');
sourceCtx.clearRect(0, 0, copyWidth, copyHeight);
}
}
}
}
});
score:0
<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.
score:0
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`;
score:1
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);
score:2
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';
}
score:4
Here is the Complete working example with 5000 data points and add as much data as you want. the scrollbar code is taken from the internet so you can modify it as you want. this Example also contains a scrollbar with multiple series. (code is commented)
<!DOCTYPE html>
<html lang="en">
<head> </head>
<body>
<div style="width: 500pt;">
<canvas id="myChart" style="display: block;width: 1333px;height: 369px;"></canvas>
<section class="range-slider">
<span class="rangeValues"></span>
<input value="1" min="1" max="" type="range" />
<input value="10" min="1" max="" type="range" />
</section>
</div>
</body>
<style>
section.range-slider {
position: relative;
width: 700px;
height: 300px;
float: left;
text-align: center;
}
section.range-slider input[type="range"] {
pointer-events: none;
position: absolute;
-webkit-appearance: none;
-webkit-tap-highlight-color: rgba(255, 255, 255, 0);
border: none;
border-radius: 14px;
background: #f1efef;
box-shadow: inset 0 1px 0 0 #cdc6c6, inset 0 -1px 0 0 #d9d4d4;
-webkit-box-shadow: inset 0 1px 0 0 #cdc6c6, inset 0 -1px 0 0 #d9d4d4;
overflow: hidden;
left: 0;
top: 50px;
width: 700px;
outline: none;
height: 20px;
margin: 0;
padding: 0;
}
section.range-slider input[type="range"]::-webkit-slider-thumb {
pointer-events: all;
position: relative;
z-index: 1;
outline: 0;
-webkit-appearance: none;
width: 20px;
height: 20px;
border: none;
border-radius: 14px;
background-image: -webkit-gradient(
linear,
left top,
left bottom,
color-stop(0%, #dad8da),
color-stop(100%, #413f41)
);
/* android <= 2.2 */
background-image: -webkit-linear-gradient(top, #dad8da 0, #413f41 100%);
/* older mobile safari and android > 2.2 */
background-image: linear-gradient(to bottom, #dad8da 0, #413f41 100%);
/* W3C */
}
section.range-slider input[type="range"]::-moz-range-thumb {
pointer-events: all;
position: relative;
z-index: 10;
-moz-appearance: none;
width: 20px;
height: 20px;
border: none;
border-radius: 14px;
background-image: linear-gradient(to bottom, #dad8da 0, #413f41 100%);
/* W3C */
}
section.range-slider input[type="range"]::-ms-thumb {
pointer-events: all;
position: relative;
z-index: 10;
-ms-appearance: none;
width: 20px;
height: 20px;
border-radius: 14px;
border: 0;
background-image: linear-gradient(to bottom, #dad8da 0, #413f41 100%);
/* W3C */
}
section.range-slider input[type="range"]::-moz-range-track {
position: relative;
z-index: -1;
background-color: black;
border: 0;
}
section.range-slider input[type="range"]:last-of-type::-moz-range-track {
-moz-appearance: none;
background: none transparent;
border: 0;
}
section.range-slider input[type="range"]::-moz-focus-outer {
border: 0;
}
</style>
</html>
<script src="https://cdn.jsdelivr.net/npm/chart.js@2.8.0"></script>
<script>
var ctx = document.getElementById("myChart").getContext("2d");
// create dummt data
var labels = [];
var values = [];
for(var i=0;i<5000;i++){
labels.push("Label"+i)
values.push(Math.random()*30)
}
var chart = new Chart(ctx, {
// The type of chart we want to create
type: "bar",
// The data for our dataset
data: {
labels: labels,
datasets: [
{
label: "My First dataset",
backgroundColor: "rgb(255, 99, 132)",
borderColor: "rgb(255, 99, 132)",
data: values,
},
],
},
// Configuration options go here
options: {},
});
function getVals() {
// Get slider values
var parent = this.parentNode;
var slides = parent.getElementsByTagName("input");
var min = parseFloat(slides[0].value);
var max = parseFloat(slides[1].value);
// Neither slider will clip the other, so make sure we determine which is larger
if (min > max) {
var tmp = max;
max = min;
min = tmp;}
var label = [];
var value = [];
label = JSON.parse(JSON.stringify(labels)).slice(min, max);
//var datasets = Data.datasets;
// IF YOU HAVE MULTIPLE SERIESES
// ChartObj.data.labels = label;
// for (var i = 0; i < datasets.length; i++) {
// values = datasets[i].data.slice(min, max);
// ChartObj.data.datasets[i].data = values;
// }
// ChartObj.update();
value = JSON.parse(JSON.stringify(values)).slice(min, max);
chart.data.labels = label;
chart.data.datasets[0].data = value;
chart.update();
var displayElement = parent.getElementsByClassName("rangeValues")[0];
displayElement.innerHTML = "Min : " + min + " Max : " + max;
}
// Initialize Sliders
var sliderSections = document.getElementsByClassName("range-slider");
for (var x = 0; x < sliderSections.length; x++) {
var sliders = sliderSections[x].getElementsByTagName("input");
for (var y = 0; y < sliders.length; y++) {
if (sliders[y].type === "range") {
sliders[y].oninput = getVals;
sliders[y].max=JSON.parse(JSON.stringify(labels)).length;
// Manually trigger event first time to display values
sliders[y].oninput();
}
}
}
</script>
score:17
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>
score:36
Scrollable Chart
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/
Source: stackoverflow.com
Related Query
- How can I create a horizontal scrolling Chart.js line chart with a locked y axis?
- How do I draw a vertical line on a horizontal bar chart with ChartJS?
- Chartjs 3.x - How to duplicate X axis on both sides of horizontal bar chart with only 1 dataset?
- how can i use chart.js to create a chart that has one time series line and one linear line on it at the same time?
- How can I create a horizontal scroll effect with angular-chart.js and chart.js
- How do I create a stacked horizontal bar chart with Chart.js in React?
- How to use chart.js to plot line chart with x axis as time stamp in seconds
- How can I create a stacked bar chart with Charts.JS that displays relative rather than absolute values?
- How can I create a vertical scrolling in Chart.js for line chart?
- How can I create a long tail chart with chart.js
- Chartjs 2 - Stacked bar and unstacked line on same chart with same y axis
- How to display Line Chart dataset point labels with Chart.js?
- Show X axis on top and bottom in line chart rendered with Chart.js 2.4.0
- Obtain max value of y axis of line chart rendered with Chart.js
- Line chart with large number of labels on X axis
- How to hide the y axis and x axis line and label in my bar chart for chart.js
- How can I remove extra whitespace from the bottom of a line chart in chart.js?
- How to create a gradient fill line chart in latest Chart JS version (3.3.2)?
- How can I create a time series line graph in chart.js?
- How to draw Horizontal line on Bar Chart Chartjs
- Can we draw a Line Chart with both solid and dotted line in it?
- How can I trigger the hover mode from outside the chart with charts.js 2?
- How to start the line graph from the left Y axis in a line/bar mixed chart (Chart.js)?
- How can I make line on chart thinner?
- ChartJS - how to display line chart with single element as a line? (not as a dot)
- Chart.JS Vertical Line with Moment.JS Horizontal Axis
- ChartJS (React) Line Chart - How to show single tooltip with data and labels from 3 (multiple) dataset?
- In Stacked horizontal bar chart how to remove the vertical line in Chart.js?
- How to create chartjs chart with data from database C#
- How to add area with break on line chart with fill color
More Query from same tag
- How to sort color segments by value within the 100% stacked bars rather than by value across all the stacked bars in Highcharts or ChartJs
- Charts.js - onComplete javascript function coming from JSON
- Is it possible to reverse the display order of segments in polar chart?
- Chart.js padding not working for ScaleLabel
- ChartJS - Injecting data from the server-side
- How to remove percentage calculation on top of bar in ng2-chart bar chart
- Display a limited number of labels only on X-Axis of Line Chart using Chart.js
- How to loop tooptip additional data in chart.js
- How to use Real time chart in react?
- Get Dataset Values from Chart JS onHover in Version 3
- HTML in Chart.js labels
- How can I automatically rescale the y axis of my log chart using ChartJS?
- How to use Chart.js in Angular4?
- Chart.js Increase font size for higher resolution (i.e. monitor-agnostic chart configuration )
- ChartJS Label Names Not Showing, Just ID
- Can I specify a different font size for each row of text in Chart Title?
- each section of a pie chart to a random color in chartsjs
- How to display axis borders only (no grid lines) in chartjs?
- add editable textbox to specific datapoint in a chart
- Rails dual axis using Chartkick and chart js
- How can I add padding between tick labels?
- is there a way to change the dispaly of a date
- Artefacts when showing compact vertical bar chart in chart.js
- Chart.js: colouring tooltip labels
- How to edit the ID of each button in a class if a condition is true in JavaScript?
- Create Line Chart and populate with database information
- Dataset._meta[0].dataset is null in ChartJS
- How can I change color of only one column in Barchart using Chart.js
- Horizontal line syncing across multiple charts when hovering with Chart.js in Typescript-react
- Chart js - Line chart cuts border for lines in boundaries