How to do automatic pan with Chart.js - javascript

I'm using chart.js to plot data in real time. Currently, as new data points come in and are drawn, the old ones remain which increases the amount of points chart.js has to plot every iteration. I'd like to have a maximum number of visible points, say 20 and after 20 points are on the graph, to pan every iteration. I'm using the zoom and pan plugin. Here's my code right now
if (ticks > 20) {
flukeChart.pan({x: 1, y: 0}, 'active');
flukeChart.update();
}
ticks is an integer that get's incremented every time new data comes in.
Another thing to note, the X axis is timestamps. I'm using the timestamp from the incoming data source and not calculating the current time in JS. I have a feeling the delta in the .pan method shouldn't be 1 because the x axis isn't integers but timestamps.

You can get the pixel for the values of the timestamps. If you then subtract the first and second visable ones you can pan the chart with that amount of pixels.
const options = {
type: 'line',
data: {
datasets: [{
label: '# of Votes',
data: [],
borderColor: 'pink'
}]
},
options: {
scales: {
x: {
type: 'time'
}
},
}
}
const ctx = document.getElementById('chartJSContainer').getContext('2d');
const chart = new Chart(ctx, options);
let dataPointsCounter = -1;
const interVal = setInterval(() => {
chart.data.datasets[0].data.push({
x: new Date(),
y: Math.random()
});
dataPointsCounter++;
if (dataPointsCounter > 20) {
const diff = chart.scales.x.getPixelForValue(chart.data.datasets[0].data[dataPointsCounter - 21].x) - chart.scales.x.getPixelForValue(chart.data.datasets[0].data[dataPointsCounter - 20].x)
chart.pan({
x: diff
}, undefined, 'default');
}
chart.update();
}, 500)
<body>
<canvas id="chartJSContainer" width="600" height="400"></canvas>
<script src="https://cdn.jsdelivr.net/npm/hammerjs#2.0.8"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.6.0/chart.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/chartjs-plugin-zoom/1.1.1/chartjs-plugin-zoom.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-adapter-date-fns/dist/chartjs-adapter-date-fns.bundle.min.js"></script>
</body>
Edit:
It is not exactly what you want but you can also use the streaming plugin that handles scolling and updating for you:
const options = {
type: 'line',
data: {
datasets: [{
label: '# of Votes',
data: [],
borderColor: 'pink'
}]
},
options: {
scales: {
x: {
type: 'realtime',
realtime: {
duration: 7500,
refresh: 1000,
delay: 2000,
onRefresh: (chart) => {
chart.data.datasets[0].data.push({
x: new Date(),
y: Math.random()
})
}
}
}
},
}
}
const ctx = document.getElementById('chartJSContainer').getContext('2d');
const chart = new Chart(ctx, options);
<body>
<canvas id="chartJSContainer" width="600" height="400"></canvas>
<script src="https://cdn.jsdelivr.net/npm/hammerjs#2.0.8"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.6.0/chart.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/chartjs-plugin-zoom/1.1.1/chartjs-plugin-zoom.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-adapter-date-fns/dist/chartjs-adapter-date-fns.bundle.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-plugin-streaming#2.0.0"></script>
</body>

Related

chart.js 3 and time axis displays wrong date data

I have a very hard time to get chart.js running with time axis.
I have following simplified code:
<html>
<head>
<!--
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.bundle.js"></script>
-->
<script src="https://cdn.jsdelivr.net/npm/moment"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.4.0/chart.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-adapter-moment"></script>
</head>
<body>
<canvas id="chart" width="800" height="400"></canvas>
<script type="text/javascript">
window.onload = function () {
var ctx = document.getElementById('chart').getContext('2d');
var myChart = new Chart(ctx,{
type: 'line',
data: {
datasets:[ {
data: [
{ x: '2017-01-06', y: 50 },
{ x: '2017-01-15', y: 45 },
{ x: '2017-03-07', y: 35 },
]
} ]
},
options: {
scales: {
xAxes: [ { type: 'time', } ]
}
}
});
};
</script>
</body>
</html>
When including the latest 3.4.0 chart.js the time axis is not correctly formatted (the datapoints are evenly distributed on the x-axis). However when using the 2.9.3 version, it is displayed correctly (datapoints are not evenly distributed).
Fiddle not working (using 3.4.0): https://jsfiddle.net/ungoq8j6/1/
Fiddle working (using 2.9.3): https://jsfiddle.net/ungoq8j6/2/
According to the docs (which are completly vague about that topic) you have to include a date library and an adapter (here moment.js + chartjs-adapter-moment).
The script is used only on the client side, so no node.js/npm is available.
Your config is wrong, in v3 the way you have to define scales have changed, please read the migration guide: https://www.chartjs.org/docs/master/getting-started/v3-migration.html#scales
Working example:
<html>
<head>
<script src="https://cdn.jsdelivr.net/npm/moment"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.4.0/chart.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-adapter-moment"></script>
</head>
<body>
<canvas id="chart" width="800" height="400"></canvas>
<script type="text/javascript">
window.onload = function() {
var ctx = document.getElementById('chart').getContext('2d');
var myChart = new Chart(ctx, {
type: 'line',
data: {
datasets: [{
data: [{
x: '2017-01-06',
y: 50
},
{
x: '2017-01-15',
y: 45
},
{
x: '2017-03-07',
y: 35
},
]
}]
},
options: {
scales: {
x: {
type: 'time',
}
}
}
});
};
</script>
</body>
</html>

Why does putting two data sets with a Time Cartesian axis in Chart.js cause two Y axis tick sets?

var canvas = document.getElementById('chart');
function genMockData() {
return {
x: moment().add(moment.duration(Math.random() * 10, 'hours')).format('YYYY-MM-DD HH:mm:ss'),
y: Math.random() * 100
}
}
new Chart(canvas, {
type: 'line',
data: {
labels: [],
datasets: [{
data: [genMockData(), genMockData(), genMockData()]
}, {
data: [genMockData(), genMockData(), genMockData()]
}]
},
options: {
scales: {
axis: {
x: {
type: 'time'
}
}
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<canvas id="chart"></canvas>
While it seems that both datasets are scaled based on the same Y axis, adding 'time' as a type settings for the x axis causes two sets of ticks (one being 0-1, in decimal intervals) on the Y axis. How do I get rid of the 0-1 ticks on the Y axis?
Because in your config you specify a new axis and since you dont specify a placement it makes it a y axis, removing the axis part will solve your issue
var canvas = document.getElementById('chart');
function genMockData() {
return {
x: moment().add(moment.duration(Math.random() * 10, 'hours')).format('YYYY-MM-DD HH:mm:ss'),
y: Math.random() * 100
}
}
new Chart(canvas, {
type: 'line',
data: {
labels: [],
datasets: [{
data: [genMockData(), genMockData(), genMockData()]
}, {
data: [genMockData(), genMockData(), genMockData()]
}]
},
options: {
scales: {
x: {
type: 'time'
}
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-adapter-moment#0.1.1"></script>
<canvas id="chart"></canvas>

Chartsjs only showing two data points

I am using charts.js to visualise some data, but unfortunately, I only see two data points, while the scale is like to highest value.
This is my code.
<canvas id="myChart" width="400" height="80"></canvas>
<script>
window.onload=function() {
var ctx = document.getElementById('myChart').getContext('2d');
var chart = new Chart(ctx, {
// The type of chart we want to create
type: 'line',
// The data for our dataset
data: {
labels: '',
datasets: [{
label: 'Tests',
backgroundColor: 'rgb(252, 160, 12)',
borderColor: 'rgb(8, 19, 42)',
data: [
{x:'2016-12-23', y:200}, {x:'2016-12-24', y:300}, {x:'2016-12-25', y:400}, {x:'2016-12-26', y:100}
]
}]
},
// Configuration options go here
options: {
legend: {
display: false
},
}
});
};
</script>
I don't see, why this is limited. Suggestions are more than welcome.
Try like this, please.
<canvas id="myChart" width="400" height="80"></canvas>
<script>
window.onload=function() {
var ctx = document.getElementById('myChart').getContext('2d');
var chart = new Chart(ctx, {
// The type of chart we want to create
type: 'line',
// The data for our dataset
data: {
labels: ['2016-12-23','2016-12-24','2016-12-25','2016-12-26']
datasets: [{
label: 'Tests',
backgroundColor: 'rgb(252, 160, 12)',
borderColor: 'rgb(8, 19, 42)',
data: [200, 300, 400 100]
}]
},
// Configuration options go here
options: {
legend: {
display: false
},
}
});
};
</script>

Chart.js - Timeline

I am trying to display dates on xAxes with Chart.js
I tried this with 2 dates but it shows nothing.
Probably something I did wrong with the labels or date format.
<canvas id="graph"></canvas>
<script>
var ctx = document.getElementById('graph').getContext('2d');
var myChart = new Chart(ctx, {
type: 'line',
data: {
labels: ["2013-02-08", "2013-02-10"],
datasets: [{
label: "Something",
data: [{
x: "2013-02-08",
y: 1
}, {
x: "2013-02-10",
y: 10
}]
}]
},
options: {
scales: {
xAxes: [{
type: 'time',
time: {
unit: 'day'
}
}]
}
}
});
</script>
Need help :)
Your code looks fine except that you don't need to define data.labels since the data in your dataset is defined as individual points through objects containing x and y properties.
Chart.js internally uses Moment.js for the functionality of the time axis. Therefore you should use the bundled version of Chart.js that includes Moment.js in a single file.
var ctx = document.getElementById('graph').getContext('2d');
var myChart = new Chart(ctx, {
type: 'line',
data: {
datasets: [{
label: "Something",
data: [
{ x: "2013-02-08", y: 1 },
{ x: "2013-02-10", y: 10 }
]
}]
},
options: {
scales: {
xAxes: [{
type: 'time',
time: {
unit: 'day'
}
}]
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.bundle.min.js"></script>
<canvas id="graph"></canvas>

Add zoom event handler to charts for chartjs with chartjs-plugin-zoom

chartjs-plugin-zoom is a zoom and pan plugin for Chart.js
You can call chart.resetZoom() to programmatically resets the zoom to the default state. See this example on jsfiddle.
HTML:
<div class="myChartDiv">
<canvas id="myChart" width="600" height="400"></canvas>
</div>
<button id="reset_zoom">
Reset zoom
</button>
JavaScript:
var ctx = document.getElementById("myChart");
var myChart = new Chart(ctx, {
type: 'bar',
data: {
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
datasets: [{
label: '# of Votes',
data: [12, 19, 3, 5, 2, 3]
}]
},
options: {
pan: {
enabled: true,
mode: 'x',
},
zoom: {
enabled: true,
mode: 'x',
}
}
});
$('#reset_zoom').click(function(){
myChart.resetZoom();
});
And it looks like:
However, I don't want to show the Reset zoom button in the first place. Instead, I would like to hide it first, and then listen for a zoom event (In chartjs-plugin-zoom the event is mouse wheel and pinch for touch screens) to show it.
So the question is, is there a way in chartjs with chartjs-plugin-zoom to add a zoom event handler (wheel and pinch events) to a chart? Thanks.
Unfortunately, you can not add mouse scroll event to the chart, as the chartjs-plugin-zoom will prevent that by default.
However, you can use the following chart plugin, which will get the job done for you ...
plugins: [{
beforeDraw: function(c) {
var reset_zoom = document.getElementById("reset_zoom"); //reset button
var ticks = c.scales['x-axis-0'].ticks.length; //x-axis ticks array
var labels = c.data.labels.length; //labels array
if (ticks < labels) reset_zoom.hidden = false;
else reset_zoom.hidden = true;
}
}]
add this plugin followed by your chart options.
Basically, the way chartjs-plugin-zoom works is, it removes/adds elements from/to the ticks array on mouse scroll, and the above plugin will check for that, henceforth show / hide the rest zoom button accordingly.
ᴡᴏʀᴋɪɴɢ ᴇxᴀᴍᴘʟᴇ ⧩
var ctx = document.getElementById("myChart");
var myChart = new Chart(ctx, {
type: 'bar',
data: {
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
datasets: [{
label: '# of Votes',
data: [12, 19, 3, 5, 2, 3]
}]
},
options: {
pan: {
enabled: true,
mode: 'x',
},
zoom: {
enabled: true,
mode: 'x',
}
},
plugins: [{
beforeDraw: function(c) {
var reset_zoom = document.getElementById("reset_zoom"); //reset button
var ticks = c.scales['x-axis-0'].ticks.length; //x-axis ticks array
var labels = c.data.labels.length; //labels array
if (ticks < labels) reset_zoom.hidden = false;
else reset_zoom.hidden = true;
}
}]
});
$('#reset_zoom').click(function() {
myChart.resetZoom();
});
.myChartDiv {
max-width: 600px;
max-height: 400px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.6.0/Chart.min.js"></script>
<script src="https://npmcdn.com/Chart.Zoom.js#0.3.0/Chart.Zoom.min.js"></script>
<div class="myChartDiv">
<canvas id="myChart" width="600" height="400"></canvas>
</div>
<button id="reset_zoom" hidden>
Reset zoom
</button>
Another approach to this is to use the zoom plugin onZoomComplete event.
First, you should apply a style to the zoom button that will have it hidden by default.
.reset-zoom {
display: none;
}
and the button
<button id="reset_zoom" class="reset-zoom">
Reset zoom
</button>
Then on the chart's zoom options you should add
zoom: {
enabled: true,
mode: 'x',
onZoomComplete: function(myChart) {
$('#reset_zoom').show();
}
}
And in order to hide the zoom button again once a resetZoom is called you could add
$('#reset_zoom').click(function(){
myChart.resetZoom();
$('#reset_zoom').hide();
});
So each time you zoom in the reset zoom button is displayed and once you reset the zoom it is hidden again.

Categories

Resources