Clear Canvas Rect(但保留背景)

时间:2011-04-08 14:17:18

标签: html canvas drawing

我试图为圆圈设置动画并将其水平移动,但效果很好。然而,当圆圈移动时,我必须对该圆圈执行clearRect,以便在水平方向上重新绘制它。当我做一个clearRect时,它也会使背景周围有白框,这样它就会在圆圈移动的方向上成为一条白色的水平线。

  1. 有没有办法在没有clearRect的情况下清除圆圈?
  2. 如果我必须在clearRect之后继续重新绘制背景,那么当theres说10个圆圈在那个区域移动时,画布会闪烁。
  3. 解决此问题的其他任何方法?

        function drawcircle() {
            clear();    
    
            context.beginPath();
            context.arc(X, Y, R, 0, 2*Math.PI, false);                  
            context.moveTo(X,Y);            
            context.lineWidth = 0.3;
            context.strokeStyle = "#999999"; 
            context.stroke();
    
            if (X > 200)
            {
                clearTimeout(t); //stop
            }
            else
            {
                //move in x dir
                X += dX;
                t = setTimeout(drawcircle, 50);
            }
        }
    
        function clear() {
            context.clearRect(X-R, Y-R, 2*R, 2*R);
        }
    

3 个答案:

答案 0 :(得分:25)

基础知识:HTML5 Canvas作为非保留的绘图模式图形API

首先,让我们讨论HTML5 Canvas的工作方式。就像带有快干油画颜料的真实帆布一样,当你在画布上stroke()fill()drawImage()时,油漆就会成为画布的一部分。尽管您画了一个“圆圈”并且看到它,但圆圈的像素完全取代了背景(或者在圆形边缘处消除锯齿,混合并永远改变它们)。如果你让他把一幅画中的一个人“移动”到右边,Monet会怎么说?你无法移动圆圈,你无法擦除圆圈,你无法检测圆圈的鼠标悬停...因为没有圆圈 ,只有单个2D像素阵列。

一些选项

  1. 如果您的背景是完全静态的,请通过CSS将其设置为canvas元素的背景图像。这将显示并覆盖您绘制的内容,但在清除画布时不会被清除。

  2. 如果你不能做到这一点,那么你也可以清除整个画布并在每一帧重新绘制它。在我的测试中,除非重绘画布非常昂贵,否则清除和重绘画布的一部分所需的工作是不值得的。

    例如,请参阅此测试:http://phrogz.net/tmp/image_move_sprites_canvas.html
    在Safari v5.0.4中,如果我每帧清除并重新绘制整个画布一次,则会看到59.4fps,如果我使用20个clearRect()调用和20个drawImage()调用重新绘制,则会看到56.8fps每帧的背景弄脏了一部分。在这种情况下,较慢要聪明并跟踪小脏区。

  3. 作为另一种选择,使用保留绘图图形系统,如SVG或HTML。有了这些,每个元素都是独立维护。你可以改变物品的位置,它会神奇地移动;浏览器可以以最有效的方式智能地绘制更新。

    您可以通过在同一HTML页面中创建和分层多个画布(使用CSS绝对定位和z-index)来保留自定义画布绘制的强大功能。如this performance test所示,移动20 sprites via CSS要比在单个画布上自己完成所有操作要快得多。

  4. 闪烁?

    您写道:

      

    如果我必须在clearRect之后继续重新绘制背景,那么当有10个圆圈在那个区域移动时,画布会闪烁。

    这从来就不是我的经历。您能否提供一个小例子来说明您声称会出现这种“闪烁”问题(请指明您遇到的操作系统,浏览器和版本)?以下是two comments by prominent browser developers,注意到Firefox和Safari都不应该显示任何闪烁。

答案 1 :(得分:1)

通过简单地将多个画布放在彼此的顶部,实际上很容易实现。您可以在背景中的画布上绘制背景(等待它......),并在前景中的第二个画布上绘制圆圈。 (即堆放在背景画布前面)

多个画布实际上是提高任何动画效果的最佳方法之一,其中最终图像的元素独立移动而不一定在每一帧中移动。这样可以避免重绘每个帧中没有移动的项目。但是,要记住的一件事是,改变在不同画布上绘制的项目的相对深度(想想z-index)现在要求在dom中重新排序实际的<canvas>元素。在实践中,这对于2D游戏和动画来说很少是一个问题。

答案 2 :(得分:0)

有两种方法可以减少闪烁,尤其是如果你有很多圈子的话。

一个是双缓冲,对于一个简短的问题你可以看看: Does HTML5/Canvas Support Double Buffering?

基本上,你在两幅画布上画画,并根据需要交换它们。

这将是更好的选择,尤其是每帧有很多变化,但是,我这样做的另一种方法是使用背景颜色绘制我想要擦除的圆圈,然后使用正确的颜色绘制新圈子。

唯一的问题是,您可能会留下一些尝试擦除的证据,因为对于某些形状来说,很难将其精确地绘制在顶部。

<强>更新

根据评论,您可以在画布上查看有关双缓冲的讨论:

HTML canvas double buffering frame-rate issues

基本的想法是跟踪你绘制的所有内容,使用当前位置,然后在单独的画布上,重新绘制所有内容,然后将它们翻转出来,然后我将再次重新绘制,在新的位置,确保图像看起来完全像它应该的样子。将它们交换进去是一个快速操作,唯一的问题是如果你在画布上放置事件处理程序,在这种情况下,将它们放在画布周围的div或span上,这样这些信息就不会丢失。