我在 Chart.js 中创建了一个折线图,它每秒更新一次新值。但是,有一个小问题:当添加新值时,动画从底部开始并向上移动到正确的行位置。如何防止行尾在达到新值之前掉落?
您可以通过设置
animations.x.from
和 animations.y.from
回调来做到这一点;图表的每个点都会调用它们
因此必须采取案例来识别刚刚添加的最后一个数据点。
const fromX = function(context){
if(!context.element){
return;
}
if(context.dataIndex === context.dataset.data.length -1){
const [prevValue] = context.chart.data.labels.slice(-2); // penultimate element
return context.chart.getDatasetMeta(context.datasetIndex)['xScale'].getPixelForValue(prevValue);
}
return context.element.x;
};
const fromY = function(context){
if(!context.element){
return;
}
if(context.dataIndex === context.dataset.data.length -1){
const [prevValue] = context.dataset.data.slice(-2); // penultimate element
return context.chart.getDatasetMeta(context.datasetIndex)['yScale'].getPixelForValue(prevValue);
}
return context.element.y;
};
以及配置:
options: {
....... other options
animations: {
x: {
from: fromX
},
y: {
from: fromY
}
}
}
只要新数据位于现有图表区域内,这种方法就可以正常工作;如果不是,则图表 将随着新点重新调整,事情会变得更加复杂。我们必须把初始位置 使用初始轴比例的新点,其最终位置将使用 最终尺度。这是一种简单的方法,可以在当前点和上一个点之间的中间位置开始新点 职位:
let labels = [1, 2, 3, 4, 5, 6, 7];
let data = [65, 59, 80, 81, 56, 55, 40];
const chartData = {
labels: labels,
datasets: [
{
label: "My First dataset",
backgroundColor: "rgba(75,192,192,0.4)",
borderColor: "rgba(75,192,192,1)",
data: data,
},
],
};
const fromX = function(context){
if(!context.element){
return;
}
if(context.dataIndex === context.dataset.data.length -1){
const [prevValue, lastValue] = context.chart.data.labels.slice(-2);
const scale = context.chart.getDatasetMeta(context.datasetIndex)['xScale'];
return (scale.getPixelForValue(prevValue) + scale.getPixelForValue(lastValue))/2;
}
return context.element.x;
}
const fromY = function(context){
if(!context.element){
return;
}
if(context.dataIndex === context.dataset.data.length -1){
const [prevValue, lastValue] = context.dataset.data.slice(-2); // penultimate element
const scale = context.chart.getDatasetMeta(context.datasetIndex)['yScale'];
return (scale.getPixelForValue(prevValue) + scale.getPixelForValue(lastValue))/2;
}
return context.element.y;
};
const options = {
responsive: true,
scales: {
x: {
display: true,
title: {
display: true,
text: "Time",
},
},
y: {
display: true,
title: {
display: true,
text: "Value",
},
},
},
animations: {
x: {
duration: 800,
from: fromX
},
y: {
duration: 800,
from: fromY
}
},
};
const chart = new Chart("canvas", {
type: "line",
data: chartData,
options: options,
});
let interval;
function startInterval(){
interval = setInterval(() => {
data.push(Math.random() * data.length + 1);
labels.push(labels.length + 1);
chart.update();
}, 2000);
}
addEventListener("DOMContentLoaded", () => {startInterval();});
document.querySelector('#reset').onclick = () => {
chart.data.datasets[0].data = [1];
chart.data.labels = [1];
data = chart.data.datasets[0].data;
labels = chart.data.labels;
chart.update()
};
document.querySelector('#stop').onclick = () => {
clearInterval(interval);
};
<div>
<button id="reset">reset</button> <button id="stop">stop</button>
<canvas id="canvas"></canvas>
</div>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
注意此代码基于我认为之前一定是类似答案的代码,但由于某种原因我在SO上找不到它;根据我原始代码的日期,它一定是针对这篇文章, 我也投了赞成票,但由于某种原因我一定没有发布它。如果这是错误的,并且我之前已经发布过类似的内容,请告诉我。