Chartjs动画x轴

15

我想使用chartjs折线图来可视化我的数据点。Chartjs似乎默认情况下会为图形添加动画效果,但它不会对x轴上的值进行动画处理。 x轴只会以离散步长移动。

是否有办法在轴上也启用动画效果?

谢谢!


不清楚你是否像ctg所做的那样在X维度上对图形数据进行动画处理,还是你指的是对x轴标签进行动画处理(这是我理解你问题的意思,并且也是我创建悬赏时寻找的内容),而这里没有任何答案涉及到。你能否澄清一下? - temporary_user_name
2个回答

9
据我所知,ChartJS默认情况下不支持X轴动画。因此,您需要对其进行修改。可能有几种方式来实现此目的,但以下方法似乎很有效。
如果您想要在X轴上动画数据:
当更新图表时,会执行以下步骤:1)绘制坐标轴,然后2)调用一个draw()函数来绘制数据。不同类型的图表有不同的draw()函数,线性图表的函数为Chart.controllers.line.prototype.drawdraw()函数接受一个参数(我将其称为animationFraction),该参数表示动画完成的百分比。例如,如果动画完成了5%,animationFraction将为0.05,如果动画完成了100%(即图表处于最终形式),则animationFraction=1。每个动画步骤都会调用draw()函数以更新数据显示。
那么,要在x轴上进行动画处理,可以通过monkey-patching线性图表draw()函数实现水平方向上的画布平移。
var hShift = (1-animationFraction)*ctx.canvas.width;

hShift是图表的水平像素偏移量。如上所述,数据将从右侧滑入;如果要从左侧滑入,则可以将上述值设为负。然后保存画布上下文状态,使用hShift转换画布,绘制图表数据,然后将画布恢复到其原始状态,以便在下一个动画帧中轴线将在正确位置绘制:

ctx.save();
ctx.setTransform(1, 0, 0, 1, hShift, 0);
ctx.oldDraw.call(this, animationFraction);
ctx.restore();

在上述代码中,this 指的是图表对象,oldDraw 是之前保存的原始线图绘制函数。
var oldDraw = Chart.controllers.line.prototype.draw;

您可以进一步设置新的draw()函数,以读取新的动画选项,从而设置x轴和y轴是否进行动画处理:

var oldDraw = Chart.controllers.line.prototype.draw;
Chart.controllers.line.prototype.draw = function(animationFraction) {
    var animationConfig = this.chart.options.animation;
    if (animationConfig.xAxis === true) {
        var ctx = this.chart.chart.ctx;
        var hShift = (1-animationFraction)*ctx.canvas.width;
        ctx.save();
        ctx.setTransform(1, 0, 0, 1, hShift,0);
        if (animationConfig.yAxis === true) {
            oldDraw.call(this, animationFraction);
        } else {
            oldDraw.call(this, 1);
        }
        ctx.restore();
    } else if (animationConfig.yAxis === true) {
        oldDraw.call(this, animationFraction);
    } else {
        oldDraw.call(this, 1);
    }
}

您可以使用以下代码创建同时拥有动画效果的两个轴线的折线图:

var lineChart = new Chart(ctx, {
    type: 'line',
    data: data,
    options: { 
        animation: { 
            duration: 5000,
            xAxis: true,
            yAxis: true,
        }
    }
});

请查看https://jsfiddle.net/16L8sk2p/获取演示。 如果您想要动画化X轴限制 如果您想要动画化x轴限制,即移动数据、轴刻度和刻度标签,则可以使用以下策略。它有点古怪,因此可能需要花费一些精力来解决任何给定用例的问题,但我相信它通常应该有效。首先,您需要将线图转换为散点图。线图具有分类x轴,以步骤移动,因此无法将轴限制设置为在刻度之间,这是您需要执行以获得动画效果的操作。因此,您需要改用线散点图,因为散点图可以具有任意轴限制。您可以通过对每个数据点进行编号,并将该数字分配给该数据点的x值来实现这一点。例如,要生成随机数据集,您可以执行以下操作:
var DATA_POINT_NUM = 58;
var data = {
    labels: [],
    datasets: [
        {
            data: [],
        },
    ]
}
for (var i=0; i<DATA_POINT_NUM; i++) {
    data.datasets[0].data.push({    x: i,
                                    y: Math.random()*10
                                });
    data.labels.push(String.fromCharCode(65+i));
}

接下来,您需要编写一个函数,将数据点的分配x值和数据点标签(即图表x轴上的类别)之间进行转换:

function getXAxisLabel(value) {
    try {
        var xMin = lineChart.options.scales.xAxes[0].ticks.min;
    } catch(e) {
        var xMin = undefined;
    }
    if (xMin === value) {
        return '';
    } else {
        return data.labels[value];
    }
}

其中 lineChart 是我们的 Chart 对象,稍后会进行定义。请注意,如果 x 轴最小值处有标签,ChartJS 会稍微不同地绘制图表,因此您需要编写此函数以在 value==x 轴最小值时返回空字符串。然后,您可以定义 Chart 对象:

var lineChart = new Chart(ctx, {
    type: 'line',
    data: data,
    options: { 
        animation: false,
        scales: {
            xAxes: [{
                type: 'linear',
                position: 'bottom',
                ticks: {
                    min: 0,
                    max: 10,
                    callback: getXAxisLabel, // function(value) { return data.labels[value]; },
                    autoSkip: false,
                    maxRotation: 0,

                },
            }]
        }
    }
});

ticks.callback被设置为我们上面的getXAxisLabel函数。当ChartJS绘制x轴时,它将向回调函数传递数据点的x值,然后使用生成的字符串作为x轴上的值。通过这种方式,我们可以像线形图一样绘制散点图。我还设置了autoSkip=false和maxRotation=0来确保轴标签以一致的方式绘制。
您可以通过调整x轴ticks.min和ticks.max值,并调用图表的.update()方法来对图表进行动画处理。为了说明这一点,下面的代码沿着图表的x轴扫描,每次显示十个数据点。
var xMin = 0;                   // Starting minimum value for the x-axis
var xLength = 10;               // Length of the x-axis
var animationDuration = 5000;   // Duration of animation in ms

// Calculate animation properties
var framesPerSec = 100;
var frameTime = 1000/framesPerSec;
var xStep = (DATA_POINT_NUM-xMin+xLength)/(animationDuration/1000*framesPerSec);

function nextFrame() {
    var xMax = xMin+xLength;
    if (xMax < DATA_POINT_NUM-1) {

        if (xMax+xStep > DATA_POINT_NUM-1) {
            xMax = DATA_POINT_NUM-1;
            xMin = xMax-xLength;
        }
        lineChart.options.scales.xAxes[0].ticks.min = xMin;
        lineChart.options.scales.xAxes[0].ticks.max = xMax;
        lineChart.update();
        setTimeout(nextFrame, frameTime);
        xMin += 0.1;
    }
}

nextFrame();

将所有内容整合起来:https://jsfiddle.net/qLhojncy/

现在我重新阅读了问题,它似乎不太清楚,但当我创建赏金时,我要寻找的是能够对x轴上的标签进行动画处理的功能,而不是对x维度中的图形数据进行处理。我不确定原始提问者是指这些中的哪一个。您可以通过单击此处的“更新”在d3中查看我所说的示例~http://bl.ocks.org/d3noob/7030f35b72de721622b8 - temporary_user_name
@Aerovistae,我明白了。我已经修改了我的回答,包括一种可能的标签动画方法。希望对您有所帮助。 - cjg
谢谢,这太完美了! - Joakim Ericsson
@cjg请在https://stackoverflow.com/questions/57315554/chartjs-how-to-apply-after-animation上给我一个提示。 - Seabizkit

4

我不是javascript的专家,但我找到了一个Chartjs的例子,当插入一个新的数据点时,它通过动画更新x轴,也许可以帮助你:示例

示例来源:sitepoint.com


2
正如问题所述,问题是在折线图上对x轴进行动画处理。 - Joakim Ericsson
这个答案现在已经过时了。Chart.js不再具有removeData()addData()函数。 - Dakkaron

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接