Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/html/81.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript HTML5/Canvas支持双缓冲吗?_Javascript_Html_Canvas_Double Buffering - Fatal编程技术网

Javascript HTML5/Canvas支持双缓冲吗?

Javascript HTML5/Canvas支持双缓冲吗?,javascript,html,canvas,double-buffering,Javascript,Html,Canvas,Double Buffering,我想做的是在缓冲区上绘制图形,然后能够将其复制到画布上,这样我就可以制作动画并避免闪烁。但我找不到这个选项。有人知道我该怎么做吗?与其自己动手,不如使用现有的库来创建干净且无闪烁的JavaScript动画,这样您可能会获得最佳的效果: 这里有一个流行的方法:一个非常简单的方法是在同一屏幕位置有两个画布元素,并为需要显示的缓冲区设置可见性。完成后,在隐藏面上绘制并翻转 一些代码: CSS: 在JS中翻转: Buffers[1-DrawingBuffer].style.visibility='hid

我想做的是在缓冲区上绘制图形,然后能够将其复制到画布上,这样我就可以制作动画并避免闪烁。但我找不到这个选项。有人知道我该怎么做吗?

与其自己动手,不如使用现有的库来创建干净且无闪烁的JavaScript动画,这样您可能会获得最佳的效果:


这里有一个流行的方法:

一个非常简单的方法是在同一屏幕位置有两个画布元素,并为需要显示的缓冲区设置可见性。完成后,在隐藏面上绘制并翻转

一些代码:

CSS:

在JS中翻转:

Buffers[1-DrawingBuffer].style.visibility='hidden';
Buffers[DrawingBuffer].style.visibility='visible';

DrawingBuffer=1-DrawingBuffer;
在此代码中,数组“Buffers[]”包含两个画布对象。因此,当您要开始绘制时,仍然需要获取上下文:

var context = Buffers[DrawingBuffer].getContext('2d');

我测试过的所有浏览器都会通过在绘制帧的代码完成之前不重新绘制画布来为您处理这种缓冲。另请参见WHATWG邮件列表:

网络浏览器中没有闪烁!他们已经使用dbl缓冲进行渲染。Js引擎将在显示之前进行所有渲染。此外,上下文仅保存和恢复堆栈转换矩阵数据等,而不是画布内容本身。
因此,您不需要或不想要dbl缓冲

Opera 9.10速度非常慢,显示了绘图过程。如果希望看到浏览器不使用双缓冲,请尝试Opera 9.10

有些人建议浏览器以某种方式决定绘图过程何时结束,但你能解释一下这是如何工作的吗?我没有注意到Firefox、Chrome或IE9中有任何明显的闪烁,即使绘图速度很慢,所以看起来他们就是这么做的,但这是如何实现的对我来说是个谜。浏览器如何知道在执行更多图形指令之前正在刷新显示?你认为他们只是计时吗?如果间隔超过5毫秒左右而不执行画布绘制指令,它会假定它可以安全地交换缓冲区吗?

你需要2个画布:(注意css z索引和位置:绝对)


您的浏览器不支持画布元素。
您的浏览器不支持画布元素。
你可以注意到,第一块画布是可见的,第二块是隐藏的,在隐藏的画布上画图,然后我们将隐藏可见的画布,使隐藏的画布可见。隐藏时“清除隐藏画布”

<script type="text/javascript">
var buff=new Array(2);
buff[0]=document.getElementById("layer1");
buff[1]=document.getElementById("layer2");

ctx[0]=buff[0].getContext("2d");
ctx[1]=buff[1].getContext("2d");
var current=0;
// draw the canvas (ctx[ current ]);
buff[1- current ].style.visibility='hidden';
buff[ current ].style.visibility='visible';
ctx[1-current].clearRect(0,0,760,600);
current =1-current;

var buff=新数组(2);
buff[0]=document.getElementById(“layer1”);
buff[1]=document.getElementById(“layer2”);
ctx[0]=buff[0].getContext(“2d”);
ctx[1]=buff[1].getContext(“2d”);
无功电流=0;
//绘制画布(ctx[current]);
buff[1-当前].style.visibility='hidden';
buff[current].style.visibility='visible';
ctx[1-当前].clearRect(0,0760600);
电流=1-电流;

以下有用的链接除了显示使用双缓冲的示例和优点外,还显示了使用html5画布元素的其他几个性能提示。它包括指向jsPerf测试的链接,jsPerf测试将跨浏览器的测试结果聚合到Browserscope数据库中。这可以确保性能提示得到验证

为方便起见,我提供了一个文章中描述的有效双缓冲的最小示例

// canvas element in DOM
var canvas1 = document.getElementById('canvas1');
var context1 = canvas1.getContext('2d');

// buffer canvas
var canvas2 = document.createElement('canvas');
canvas2.width = 150;
canvas2.height = 150;
var context2 = canvas2.getContext('2d');

// create something on the canvas
context2.beginPath();
context2.moveTo(10,10);
context2.lineTo(10,30);
context2.stroke();

//render the buffered canvas onto the original canvas element
context1.drawImage(canvas2, 0, 0);

对于不信者,这里有一些闪烁的代码。请注意,我正在明确清除前一个圆圈

var c=document.getElementById(“myCanvas”);
var ctx=c.getContext(“2d”);
函数绘制球(球){
ctx.clearRect(0,040400);
ctx.fillStyle=“#FF0000”;
ctx.beginPath();
弧(ball.x,ball.y,30,0,Math.PI*2,真);
ctx.closePath();
ctx.fill();
}
var-deltat=1;
var-ball={};
ball.y=0;
球x=200;
ball.vy=0;
ball.vx=10;
ball.ay=9.8;
ball.ax=0.1;
函数compute_position(){
如果(ball.y>370&&ball.vy>0){
ball.vy=-ball.vy*84/86;
}
如果(球x<30){
ball.vx=-ball.vx;
ball.ax=-ball.ax;
}否则,如果(ball.x>370){
ball.vx=-ball.vx;
ball.ax=-ball.ax;
}
ball.ax=ball.ax/2;
ball.vx=ball.vx*185/186;
ball.y=ball.y+ball.vy*deltat+ball.ay*deltat*deltat/2
ball.x=ball.x+ball.vx*deltat+ball.ax*deltat*deltat/2
ball.vy=ball.vy+ball.ay*deltat
ball.vx=ball.vx+ball.ax*deltat
抽球;
}
设置间隔(计算位置,40)

篮球
您的浏览器不支持画布元素。
Josh(不久前)询问浏览器如何知道“绘图过程何时结束”,以避免闪烁。我会直接对他的帖子发表评论,但我的代表级别不够高。这也是我的看法。我没有事实来支持它,但我对它有相当的信心,它可能会对其他人在未来阅读这篇文章有所帮助

我猜浏览器不知道你什么时候画完。但就像大多数javascript一样,只要代码运行时不将控制权交给浏览器,浏览器就基本上处于锁定状态,不会/无法更新/响应其UI。我猜,如果你清除画布并绘制整个框架,而不将控制权交给浏览器,那么在你完成之前,它实际上不会绘制画布

如果设置渲染跨越多个setTimeout/setInterval/requestAnimationFrame调用的情况,即在一个调用中清除画布,并在接下来的几个调用中在画布上绘制元素,每5个调用重复一次循环(例如),我敢打赌你会看到闪烁,因为画布会在每次调用后更新

也就是说,我不确定我会相信这一点。我们已经到了javascript在执行之前被编译成本地机器代码的地步(据我所知,至少Chrome的V8引擎就是这样做的)。如果是这样,我也不会感到惊讶
<script type="text/javascript">
var buff=new Array(2);
buff[0]=document.getElementById("layer1");
buff[1]=document.getElementById("layer2");

ctx[0]=buff[0].getContext("2d");
ctx[1]=buff[1].getContext("2d");
var current=0;
// draw the canvas (ctx[ current ]);
buff[1- current ].style.visibility='hidden';
buff[ current ].style.visibility='visible';
ctx[1-current].clearRect(0,0,760,600);
current =1-current;
// canvas element in DOM
var canvas1 = document.getElementById('canvas1');
var context1 = canvas1.getContext('2d');

// buffer canvas
var canvas2 = document.createElement('canvas');
canvas2.width = 150;
canvas2.height = 150;
var context2 = canvas2.getContext('2d');

// create something on the canvas
context2.beginPath();
context2.moveTo(10,10);
context2.lineTo(10,30);
context2.stroke();

//render the buffered canvas onto the original canvas element
context1.drawImage(canvas2, 0, 0);