【问题标题】:html5 - canvas element - Multiple layershtml5 - 画布元素 - 多层
【发布时间】:2011-03-01 19:40:46
【问题描述】:

如果没有任何扩展库,是否可以在同一个画布元素中拥有多个图层?

所以如果我在顶层做一个clearRect,它不会擦除底层?

谢谢。

【问题讨论】:

标签: html canvas layer


【解决方案1】:

不,但是,您可以将多个 <canvas> 元素叠加在一起并完成类似的操作。

<div style="position: relative;">
 <canvas id="layer1" width="100" height="100" 
   style="position: absolute; left: 0; top: 0; z-index: 0;"></canvas>
 <canvas id="layer2" width="100" height="100" 
   style="position: absolute; left: 0; top: 0; z-index: 1;"></canvas>
</div>

layer1 画布上绘制第一层,在layer2 画布上绘制第二层。然后当你在顶层clearRect时,下层画布上的任何东西都会显示出来。

【讨论】:

  • 有没有办法隐藏/取消隐藏图层.. 这样我可以隐藏 layer1 并显示 layer2 并在需要时反之亦然..??
  • 你可以用 CSS 隐藏它 - 即display: none;。或者只是清除画布,如果在应该显示图层时重新绘制它不是超级昂贵的话。
  • 分配给'left'和'top'的值需要是'0px',而不是'0'。
  • @BryanGreen 不正确。 “但是,对于零长度,单位标识符是可选的(即可以在语法上表示为 0)。” w3.org/TR/css3-values/#lengths
  • 我可以控制多个画布的合成类型吗?
【解决方案2】:

与此相关:

如果你的画布上有一些东西,并且你想在它的背面画一些东西 - 你可以通过将 context.globalCompositeOperation 设置更改为“destination-over”来实现 - 然后将其返回到“source-over”完成后。

   var context = document.getElementById('cvs').getContext('2d');

    // Draw a red square
    context.fillStyle = 'red';
    context.fillRect(50,50,100,100);



    // Change the globalCompositeOperation to destination-over so that anything
    // that is drawn on to the canvas from this point on is drawn at the back
    // of what's already on the canvas
    context.globalCompositeOperation = 'destination-over';



    // Draw a big yellow rectangle
    context.fillStyle = 'yellow';
    context.fillRect(0,0,600,250);


    // Now return the globalCompositeOperation to source-over and draw a
    // blue rectangle
    context.globalCompositeOperation = 'source-over';

    // Draw a blue rectangle
    context.fillStyle = 'blue';
    context.fillRect(75,75,100,100);
&lt;canvas id="cvs" /&gt;

【讨论】:

  • 是的,这很好,但在擦除的情况下,如问题所述。这将同时擦除两层。这又是不正确的。
  • 那么这本质上只是一种仅在画布的透明/空白部分上绘制的方法吗?
  • 这是令人难以置信的惊人答案。非常感谢@Richard !!!!!!
  • 关于此评论:>>> 那么这本质上只是一种仅在画布的透明/空白部分上绘制的方法吗?
【解决方案3】:

您可以创建多个canvas 元素,而无需将它们附加到文档中。这些将是您的

然后对它们做任何你想做的事情,最后只需在目标画布上使用drawImage context 以正确的顺序呈现它们的内容。

例子:

/* using canvas from DOM */
var domCanvas = document.getElementById('some-canvas');
var domContext = domCanvas.getContext('2d');
domContext.fillRect(50,50,150,50);

/* virtual canvase 1 - not appended to the DOM */
var canvas = document.createElement('canvas');
var ctx = canvas.getContext('2d');
ctx.fillStyle = 'blue';
ctx.fillRect(50,50,150,150);

/* virtual canvase 2 - not appended to the DOM */    
var canvas2 = document.createElement('canvas')
var ctx2 = canvas2.getContext('2d');
ctx2.fillStyle = 'yellow';
ctx2.fillRect(50,50,100,50)

/* render virtual canvases on DOM canvas */
domContext.drawImage(canvas, 0, 0, 200, 200);
domContext.drawImage(canvas2, 0, 0, 200, 200);

这里有一些代码笔:https://codepen.io/anon/pen/mQWMMW

【讨论】:

  • @SCLeo 你说“性能杀手。大约慢 10 倍”是完全错误的。根据使用情况,使用单个 DOM 画布并将屏幕外画布渲染到该画布比在 DOM 中堆叠画布更快。常见的错误是对渲染调用进行基准测试,画布绘制调用可以定时,DOM 渲染在 Javascripts 上下文之外并且无法定时。结果是,被 DOM 堆叠的画布没有获得基准中包含的合成渲染(由 DOM 完成)..
  • @Blindman67 我知道你的意思。只需查看此基准:jsfiddle.net/9a9L8k7k/1。万一你误会了,这里有三个画布,画布 1 (ctx1) 是一个真正的画布。画布 2 (ctx2) 和画布 3 (ctx) 不在屏幕上。该图像之前已渲染到 ctx3 上。在这个基准的测试 1 中,我直接将 ctx3 渲染到 ctx1 上。在测试 2 中,我将 ctx3 渲染到 ctx2,然后将 ctx2 渲染到 ctx1。测试 2 在我的计算机上比测试 1 慢 30 倍。这就是为什么我说使用中间画布要慢得多。
  • @Blindman67 离屏画布的技巧只有在离屏画布是静态的时候才有效。使用动态画布会极大地损害性能。 (再次,我想说的是动态离屏画布非常慢,所以大概这种技术(由多个离屏画布模拟层)是不可取的)
  • @Blindman67 重要提示:基准地址是 https://jsfiddle.net/9a9L8k7k/3 ,我在编辑后忘记保存,Stack Overflow 不允许我再更改之前的评论...
  • @Blindman67 对不起,这是我的错误。我测试并发现使用多个屏幕外画布运行非常流畅。我仍然不确定为什么该基准显示使用屏幕外画布会那么慢。
【解决方案4】:

我也遇到了同样的问题,我在使用 position:absolute 的多个画布元素时完成了这项工作,如果你想将输出保存到图像中,那是行不通的。

所以我继续做了一个简单的分层“系统”来编码,好像每一层都有自己的代码,但它们都被渲染到同一个元素中。

https://github.com/federicojacobi/layeredCanvas

我打算添加额外的功能,但现在可以了。

您可以执行多个函数并调用它们以“伪造”图层。

【讨论】:

  • 这个很完美。
【解决方案5】:

您还可以查看http://www.concretejs.com,它是一个现代的、轻量级的 Html5 画布框架,它支持命中检测、分层和许多其他外围功能。你可以这样做:

var wrapper = new Concrete.Wrapper({
  width: 500,
  height: 300,
  container: el
});

var layer1 = new Concrete.Layer();
var layer2 = new Concrete.Layer();

wrapper.add(layer1).add(layer2);

// draw stuff
layer1.sceneCanvas.context.fillStyle = 'red';
layer1.sceneCanvas.context.fillRect(0, 0, 100, 100);

// reorder layers
layer1.moveUp();

// destroy a layer
layer1.destroy();

【讨论】:

  • 这些层最终会以何种方式出现在 DOM 中?每一个都可以通过 CSS 访问?
【解决方案6】:

我了解 Q 不想使用库,但我会为来自 Google 搜索的其他人提供此库。 @EricRowell 提到了一个不错的插件,但是,您还可以尝试另一个插件,html2canvas

在我们的例子中,我们使用带有z-index 的分层透明PNG 作为“产品构建器”小部件。 Html2canvas 在不推送图像、不使用复杂性、变通方法和“无响应”画布本身的情况下出色地简化了堆栈。我们无法使用 vanilla canvas+JS 顺利/理智地做到这一点。

首先在绝对 div 上使用 z-index 在相对定位的包装器中生成分层内容。然后通过 html2canvas 管道包装器以获取渲染的画布,您可以保持原样,或者作为图像输出,以便客户端可以保存它。

【讨论】:

  • 如果您有较重的图像,这将需要一些时间来将 HTML 转换为画布,我们不得不放弃这一点,因为渲染需要很长时间。
  • @Vilius 是的,很好地呼吁重/大图像。我们试图坚持使用不超过 4 层的 300K 或更少的图像,否则资源匮乏的客户在下载最终的 composted 图像时会感到烧毁。很好奇,你在缩短的时间里做了什么?
  • 好吧,我们犯了一个大错误,一开始就使用 html 元素来绘制一些东西。因为我们的 api 返回了 x、y、width 和 height,所以我们使用 jscanavs 来绘制图像,而不是使用 html 元素。请注意,我们确实在旋转方面遇到了一些问题(起点有点尴尬和不可预测)并使用特定尺寸将图像应用到它,但最终都解决了。我们还发现我们的图像处理应用程序消耗了大量资源,因此我们也放弃了这一点。
【解决方案7】:

但是图层 02 将覆盖图层 01 中的所有绘图。我用它来显示两个图层中的绘图。在样式中使用 (background-color: transparent;)。

    <div style="position: relative;"> 
      <canvas id="lay01" width="500" height="500" style="position: absolute; left: 0; top: 0; z-index: 0; background-color: transparent;">
      </canvas> 
      <canvas id="lay02" width="500" height="500" style="position: absolute; left: 0; top: 0; z-index: 1; background-color: transparent;">
      </canvas>
</div>

【讨论】:

    猜你喜欢
    • 2013-11-15
    • 2012-06-30
    • 2012-06-13
    • 1970-01-01
    • 2020-01-08
    • 2017-06-02
    • 2015-11-11
    • 2013-07-24
    • 2015-02-10
    相关资源
    最近更新 更多