I want to access the current point in a progressive line chart in Chart JS using javascript, e.g log the current value of the line on the console every one second where the total duration of the animation is 20 seconds.
Is it possible to do it with setInterval? Or is there easier method which isn't as clumsy?
In fact you can set the interval same way ChartJS do the animation. So sneak into the animation delay definition you have and add some code. Please note that we may not set exact seconds to delay the output, but we may use delay interval for each dot, because:
// Animation-----
const totalDuration = 10000; /* 10 seconds */
const delayBetweenPoints = totalDuration / data.length;
/* This delayBetweenPoints may be 100ms, or 33ms...
depending on data.length */
Anyway you can do some calculations by yourserlf, or just expose one value for example every 100 points of chart data this way, look at bottom of the code:
// Animation-----
const totalDuration = 10000;
const delayBetweenPoints = totalDuration / data.length;
const previousY = (ctx) => ctx.index === 0 ? ctx.chart.scales.y.getPixelForValue(100) : ctx.chart.getDatasetMeta(ctx.datasetIndex).data[ctx.index - 1].getProps(['y'], true).y;
const animation = {
x: {
type: 'number',
easing: 'linear',
duration: delayBetweenPoints,
from: NaN, // the point is initially skipped
delay(ctx) {
if (ctx.type !== 'data' || ctx.xStarted) {
return 0;
}
ctx.xStarted = true;
return ctx.index * delayBetweenPoints;
}
},
y: {
type: 'number',
easing: 'linear',
duration: delayBetweenPoints,
from: previousY,
delay(ctx) {
if (ctx.type !== 'data' || ctx.yStarted) {
return 0;
}
ctx.yStarted = true;
/* HERE we output the value of each data row and
we use same delay between drawing the points: */
if( ctx.index%100==0 ) setTimeout(()=>{
console.log( ctx.raw.y );
}, ctx.index * delayBetweenPoints);
return ctx.index * delayBetweenPoints;
}
}
};
// Animation-----
You can check it on this Fiddle, or below:
// Data-----
const data = [];
const data2 = [];
let prev = 100;
let prev2 = 80;
for (let i = 0; i < 1000; i++) {
prev += 5 - Math.random() * 10;
data.push({x: i, y: prev});
prev2 += 5 - Math.random() * 10;
data2.push({x: i, y: prev2});
}
// Data-----
// Animation-----
const totalDuration = 10000;
const delayBetweenPoints = totalDuration / data.length;
const previousY = (ctx) => ctx.index === 0 ? ctx.chart.scales.y.getPixelForValue(100) : ctx.chart.getDatasetMeta(ctx.datasetIndex).data[ctx.index - 1].getProps(['y'], true).y;
const animation = {
x: {
type: 'number',
easing: 'linear',
duration: delayBetweenPoints,
from: NaN, // the point is initially skipped
delay(ctx) {
if (ctx.type !== 'data' || ctx.xStarted) {
return 0;
}
ctx.xStarted = true;
return ctx.index * delayBetweenPoints;
}
},
y: {
type: 'number',
easing: 'linear',
duration: delayBetweenPoints,
from: previousY,
delay(ctx) {
if (ctx.type !== 'data' || ctx.yStarted) {
return 0;
}
ctx.yStarted = true;
/* HERE we output the value of each data row and
we use same delay between drawing the points: */
if( ctx.index%100==0 ) setTimeout(()=>{
console.log( ctx.raw.y );
}, ctx.index * delayBetweenPoints);
return ctx.index * delayBetweenPoints;
}
}
};
// Animation-----
// Config-----
const config = {
type: 'line',
data: {
datasets: [{
borderColor: "#ff0000",
borderWidth: 1,
radius: 0,
data: data,
},
{
borderColor: "#00FFFF",
borderWidth: 1,
radius: 0,
data: data2,
}]
},
options: {
animation,
interaction: {
intersect: false
},
plugins: {
legend: false
},
scales: {
x: {
type: 'linear'
}
}
}
};
// Config-----
var myChart = new Chart(
document.getElementById('myChart'),
config
);
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<div>
<canvas id="myChart"></canvas>
</div>