Chartjs为x轴设置动画

时间:2016-07-03 17:34:20

标签: javascript animation graph charts

我想使用chartjs折线图来显示我的数据点。 Chartjs似乎默认为图形设置动画,但它不会为x轴上的值设置动画。 x轴仅以不连续的步骤移动。

有没有办法在轴上启用动画?

谢谢!

2 个答案:

答案 0 :(得分:4)

据我所知,ChartJS不支持开箱即用的x轴动画。所以你必须破解它。有几种方法可以做到这一点,但以下方法似乎有效。

如果您想在X轴上设置数据动画

更新图表时,会发生以下步骤:1)绘制轴,然后2)调用draw()函数绘制数据。不同的图表类型有不同的draw()函数,折线图的函数是Chart.controllers.line.prototype.drawdraw()函数接受一个参数,我将其称为animationFraction,它表示动画的完整程度。例如,如果动画完成5%,animationFraction将为0.05,如果动画100%完成(即图表是最终形式),animationFraction=1。在动画的每一步调用draw()函数来更新数据显示。

对X轴进行动画处理的一个方法就是对线图draw()函数进行修补,以便在每个绘制步骤中在水平维度上平移画布:

var hShift = (1-animationFraction)*ctx.canvas.width;

hShift是图表中像素的水平偏移。如上所述,数据将从右侧扫入;如果你想让它从左边扫入,你可以使上面的负面。然后保存画布上下文状态,使用hShift转换画布,绘制图表数据,然后将画布恢复到其原始状态,以便在下一个动画帧中将轴绘制在正确的位置:< / p>

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会略微不同地绘制图表,因此如果值==最小值,您需要编写此函数以返回空字符串的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=falsemaxRotation=0以确保轴标签以一致的方式绘制。

然后,您可以通过调整x轴ticks.minticks.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/

答案 1 :(得分:2)

我不是javascript的专家,但是我找到了一个Chartjs的例子,当插入一个新的数据点时,通过动画更新x轴,看起来可能它会帮助你:example

示例来源:sitepoint.com