Javascript 如何在不中断动画的情况下清除画布?
我正在用D3和画布可视化飞行路径。简而言之,我有每个航班的始发地和目的地的数据 还有机场坐标。理想的结束状态是有一个单独的圆代表一个移动的平面 沿着从起点到目的地的每条飞行路线。当前状态是每个圆沿路径可视化, 然而,由于Javascript 如何在不中断动画的情况下清除画布?,javascript,html,d3.js,canvas,Javascript,Html,D3.js,Canvas,我正在用D3和画布可视化飞行路径。简而言之,我有每个航班的始发地和目的地的数据 还有机场坐标。理想的结束状态是有一个单独的圆代表一个移动的平面 沿着从起点到目的地的每条飞行路线。当前状态是每个圆沿路径可视化, 然而,由于clearRect几乎经常被调用,因此沿着该行删除上一个圆并不起作用 当前状态: 理想状态(通过SVG实现): 概念 从概念上讲,每个航班的SVG路径都是在内存中使用D3的自定义插值生成的,其中包含path.getTotalLength()和path.getPointAtLe
clearRect
几乎经常被调用,因此沿着该行删除上一个圆并不起作用
当前状态:
理想状态(通过SVG实现):
概念
从概念上讲,每个航班的SVG路径都是在内存中使用D3的自定义插值生成的,其中包含path.getTotalLength()
和path.getPointAtLength()
,以沿路径移动圆
插值器在变换的任何给定时间返回沿路径的点。一个简单的绘图函数获取这些点并绘制圆
关键功能
可视化开始于:
od_pairs.forEach(function(el, i) {
fly(el[0], el[1]); // for example: fly('LHR', 'JFK')
});
fly()
函数在内存中创建SVG路径,并在D3中选择一个圆(“平面”)——也在内存中
function fly(origin, destination) {
var pathElement = document.createElementNS(d3.namespaces.svg, 'path');
var routeInMemory = d3.select(pathElement)
.datum({
type: 'LineString',
coordinates: [airportMap[origin], airportMap[destination]]
})
.attr('d', path);
var plane = custom.append('plane');
transition(plane, routeInMemory.node());
}
通过delta()
函数中的自定义插值器沿路径转换平面:
function transition(plane, route) {
var l = route.getTotalLength();
plane.transition()
.duration(l * 50)
.attrTween('pointCoordinates', delta(plane, route))
// .on('end', function() { transition(plane, route); });
}
function delta(plane, path) {
var l = path.getTotalLength();
return function(i) {
return function(t) {
var p = path.getPointAtLength(t * l);
draw([p.x, p.y]);
};
};
}
。。。它调用简单的draw()
函数
function draw(coords) {
// contextPlane.clearRect(0, 0, width, height); << how to tame this?
contextPlane.beginPath();
contextPlane.arc(coords[0], coords[1], 1, 0, 2*Math.PI);
contextPlane.fillStyle = 'tomato';
contextPlane.fill();
}
函数图(坐标){
//clearRect(0,0,宽度,高度);处理小脏区域,特别是当对象之间有重叠时,计算量会很快变得非常大
一般来说,如果计算位置的计算很简单,一台普通笔记本电脑/台式机可以轻松处理800个动画对象
这意味着制作动画的简单方法是清除画布并重画每一帧。节省了大量复杂的代码,与简单的清除和重画相比没有任何优势
constdofor=(count,callback)=>{vari=0;而(i{planes.add(Math.random()*canvas.width,Math.random()*canvas.height)})
}
setTransform(1,0,0,1,0,0);
//清除或渲染背景贴图
clearRect(0,0,canvas.width,canvas.height);
planes.update();
平面图();
requestAnimationFrame(主循环)
}
requestAnimationFrame(主循环)
画布{
位置:绝对位置;
顶部:0px;
左:0px;
}
800个动画点
@Blindman67是正确的,清除并重新绘制每一帧的所有内容
我在这里只是想说,当处理像arc
这样没有太多颜色变化的基本形状时,实际上使用arc
方法比drawImage()
更好
其思想是使用
ctx.beginPath(); // start path declaration
for(i; i<shapes.length; i++){ // loop through our points
ctx.moveTo(pt.x + pt.radius, pt.y); // default is lineTo and we don't want it
// Note the '+ radius', arc starts at 3 o'clock
ctx.arc(pt.x, pt.y, pt.radius, 0, Math.PI*2);
}
ctx.fill(); // a single fill()
画布{
位置:绝对位置;
顶部:0px;
左:0px;
z指数:-1;
}
8000个动画点
处理此类动画的标准方法是清除整个画布并重新绘制每一帧的所有动画。如果这是一个很大的负载,您可以将画布与地图和其他细节分层,在一个画布和另一个画布上进行飞行,并为每一帧组合。例如,沿路径的点(移动点)在这里,我认为应该只创建初始点,然后将其移动到整个区域route@PiLHA该示例使用SVG,而问题明确要求使用画布…谢谢@Blindman67。飞行路径确实位于地图/机场层顶部的自己的画布上。我的问题是何时清除最后一帧并绘制新的fram因为大约150次飞行的x和y位置在稍微不同的时间出现。@我已经添加了一个答案,可以设置800个点的动画。刷新率取决于机器,但大多数情况下会以60FPS的速度刷新。如果在不同的时间有不同的位置,则