Joa*_*son 14 javascript charts animation graph
我想使用chartjs线图来可视化我的数据点.Chartjs似乎默认为图形设置动画,但它不会为x轴上的值设置动画.x轴仅以不连续的步骤移动.
有没有办法在轴上启用动画?
谢谢!
据我所知,ChartJS不支持现成的x轴动画。因此,您必须对其进行破解。有几种方法可以执行此操作,但是以下方法似乎可行。
如果要对X轴上的数据进行动画处理
更新图表时,将执行以下步骤:1)绘制轴,然后2)draw()调用一个函数绘制数据。draw()不同的图表类型有不同的功能,折线图的功能是Chart.controllers.line.prototype.draw。这些draw()函数采用一个参数,我将其称为animationFraction,它指示动画的完整程度。例如,如果动画完成了5%,animationFraction将是0.05;如果动画完成了100%(即,图表采用其最终形式),则animationFraction=1。draw()在动画的每个步骤都调用该函数以更新数据显示。
为X轴设置动画的一种方法是draw()在每个绘制步骤中猴子修补折线图函数以在水平尺寸上平移画布:
var hShift = (1-animationFraction)*ctx.canvas.width;
Run Code Online (Sandbox Code Playgroud)
hShift是图表像素的水平移动。如上所定义,数据将从右边扫入;如果您希望它从左侧扫入,则可以将上述值设为负数。然后,您保存画布的上下文状态,使用转换画布hShift,绘制图表数据,然后将画布还原为其原始状态,以便在下一个动画帧上将在正确的位置绘制轴:
ctx.save();
ctx.setTransform(1, 0, 0, 1, hShift, 0);
ctx.oldDraw.call(this, animationFraction);
ctx.restore();
Run Code Online (Sandbox Code Playgroud)
在上面,this指的是图表对象,并且oldDraw指的是先前保存的原始折线图绘制函数:
var oldDraw = Chart.controllers.line.prototype.draw;
Run Code Online (Sandbox Code Playgroud)
您还可以设置新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);
}
}
Run Code Online (Sandbox Code Playgroud)
然后,您可以创建一个折线图,使两个轴都具有以下动画:
var lineChart = new Chart(ctx, {
type: 'line',
data: data,
options: {
animation: {
duration: 5000,
xAxis: true,
yAxis: true,
}
}
});
Run Code Online (Sandbox Code Playgroud)
有关演示,请参见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));
}
Run Code Online (Sandbox Code Playgroud)
然后,您需要编写一个函数,以在分配的数据点的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];
}
}
Run Code Online (Sandbox Code Playgroud)
其中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,
},
}]
}
}
});
Run Code Online (Sandbox Code Playgroud)
ticks.callback设置为getXAxisLabel上面的函数。当ChartJS绘制x轴时,它将把数据点的x值传递给回调函数,然后将结果字符串用作x轴上的值。这样,我们可以像线形图一样绘制散点图。我还设置autoSkip=false并maxRotation=0确保以一致的方式绘制轴标签。
然后,可以通过调整x轴ticks.min和ticks.max值并调用图表的.update()方法来为图表设置动画。为了说明这一点,下面的代码沿图表x轴扫描,一次显示10个数据点。
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();
Run Code Online (Sandbox Code Playgroud)
全部放在一起:https://jsfiddle.net/qLhojncy/
| 归档时间: |
|
| 查看次数: |
4064 次 |
| 最近记录: |