【问题标题】:How to avoid clearing canvas element on changing it's container's innerHtml如何避免在更改容器的 innerHtml 时清除画布元素
【发布时间】:2012-08-23 19:04:44
【问题描述】:

我正在使用 javascript 绘制到包含在包装器中的 div 内的画布元素。 画布及其 div 是通过添加到包装器的 innerHTML 来动态生成的。 目标是允许生成无限数量的画布

<div id="wrapper">
     <div id="container"><canvas id="previous"></canvas></div>
     <!-- infinite # of container divs & canvases -->
</div>

但是,当我将新的 div 和画布添加到包装器的 innerHTML 时,绘制到前一个画布的任何内容都会丢失。

如果我在页面的其他地方添加新的画布,添加到容器外的 div 或容器的子级:

<div id="wrapper">
     <div id="container"><canvas id="previous"></canvas></div>
</div>
<div id="wrapper2">
     <!-- newly inserted canvas: -->
     <div id="container"><canvas></canvas></div>
</div>

或:

<div id="wrapper">
     <div id="container"><canvas id="previous"></canvas></div>
     <div id="wrapperChild">
          <!-- newly inserted canvas: -->
          <div id="container"><canvas></canvas></div>
     </div>
</div>

然后保留之前的画布。

据我所知,更改包装器的 innerHTML 或其父级会导致清除画布。关于如何避免清除画布的任何建议?我可以保留在其他地方绘制到画布上的内容并恢复它吗?

【问题讨论】:

  • 是否使用 DOM 代替 innerHTML 清除画布?我的意思是,您可以将当前画布绘制到临时画布上,然后将其绘制回来,但这对于许多画布来说几乎是不可行的。 innerHTML 需要重组当前节点,这可能是清除画布的原因。如果可以,请使用 DOM 并避免使用innerHTML
  • 另一种可能的方法是 insertAdjacentHtml

标签: javascript html canvas innerhtml


【解决方案1】:

不管您的 javascript 方法(jQuery、其他方法或什么都没有),您都可以通过不使用 innerHTML 来做到这一点。基本上,当您附加到 innerHTML 属性时,您是在说“获取 innerHTML 的值,将其添加到这个新值(可能是画布元素),然后将 innerHTML 设置为所有这些。换句话说,您是” t 真的附加“就地”。您基本上是在添加您拥有的所有内容的新版本,并且由于画布没有使用子元素绘制其内容,因此不会使用此方法将它们带入。

您应该使用 DOM,而不是使用 innerHTML,将子节点作为节点而不是字符串附加到父节点。

【讨论】:

  • 非常感谢。我没有很多使用 DOM 的经验,但是当你这样解释时,我可以看到使用 innerHTML 的缺陷。我将尝试在我的项目中实现,但快速测试表明附加孩子是可行的方法。
  • 没问题,很高兴为您提供帮助。正是这些增量经验帮助我们学习。感谢您接受答案。
【解决方案2】:

听起来这是jQuery 的一个很好的用例。使用 jquery,您可以将 &lt;canvas&gt; 元素附加到任意容器中,而不必与“innerHtml”交互。

例如:

var myCanvas = $("<canvas>").appendTo("#container");

这样做是将一个新的&lt;canvas&gt; 元素添加到 id 为“容器”的元素(您的 div)。 “#”是 ids 的 css 选择器。谷歌“css 选择器”,因为这是一个相当广泛的话题。

myCanvas 变量现在是一个 jQuery 数组,其中包含对您刚刚添加的画布的引用。 myCanvas[0] 将是您可以与之交互的实际 DOM 元素。

使用这种方法,您将永远不需要更改 div 的“innerHtml”,因此现有的画布将永远不会被触摸/清除。

【讨论】:

    【解决方案3】:

    不要使用innerHtml,而是使用appendChild:

    document.getElementById('wrapper').appendChild(NewNodeHere);
    

    【讨论】:

      【解决方案4】:

      查看 Simon 关于绘制形状的教程。 http://simonsarris.com/project/canvasdemo/shapes.html

      形状的所有属性和位置都存储在对象数组中。 当像(单击形状)这样的事件发生时,画布的状态会发生变化(在这种情况下,形状正在被拖动),并且对于鼠标位置的每次更改,画布都会使用新的坐标和属性重新绘制。

      现在,如果您还使用形状、图像、文本对象,您也可以将它们的属性存储在对象数组中。这样,您只需多次遍历数组,就可以以相同的方式在多个画布上绘制相同的形状。

      因此,当您动态添加新画布时,您可以简单地重绘之前的上下文。

      这是西蒙教程中的相关代码:

      你定义一个矩形形状(构造函数)

      function Shape(x, y, w, h, fill) {
        this.x = x || 0;
        this.y = y || 0;
        this.w = w || 1;
        this.h = h || 1;
        this.fill = fill || '#AAAAAA';
      }
      

      将此形状绘制到给定的上下文中 Shape.prototype.draw = 函数(ctx){ ctx.fillStyle = this.fill; ctx.fillRect(this.x, this.y, this.w, this.h); }

      向数组添加新形状

      CanvasState.prototype.addShape = function(shape) {
        this.shapes.push(shape);
        this.valid = false;
      }
      

      遍历数组并对应绘制所有形状

      var l = shapes.length;
      for (var i = 0; i < l; i++) {
        var shape = shapes[i];
        // We can skip the drawing of elements that have moved off the screen:
        if (shape.x > this.width || shape.y > this.height ||
            shape.x + shape.w < 0 || shape.y + shape.h < 0) continue;
        shapes[i].draw(ctx);
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-04-14
        • 2013-03-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-01-16
        相关资源
        最近更新 更多