添加新值时如何避免chartjs线路下降?

问题描述 投票:0回答:1

我在 Chart.js 中创建了一个折线图,它每秒更新一次新值。但是,有一个小问题:当添加新值时,动画从底部开始并向上移动到正确的行位置。如何防止行尾在达到新值之前掉落?

视频演示:https://jam.dev/c/a928a2f1-d467-4ed5-b7ec-339b480eabc9

Edit chart=line

javascript reactjs charts chart.js react-chartjs-2
1个回答
0
投票

您可以通过设置

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>

codesandbox 叉子


注意此代码基于我认为之前一定是类似答案的代码,但由于某种原因我在SO上找不到它;根据我原始代码的日期,它一定是针对这篇文章, 我也投了赞成票,但由于某种原因我一定没有发布它。如果这是错误的,并且我之前已经发布过类似的内容,请告诉我。

© www.soinside.com 2019 - 2024. All rights reserved.