html5-画布元素-多层


176

没有任何扩展库,同一个canvas元素中可以有多个图层吗?

因此,如果我在顶层上执行clearRect,它将不会擦除底层?

谢谢。


您可能需要看一下radikalfx.com/2009/10/16/canvas-collage。他使用了一种“分层”技术。
马修(Matthew)2010年


@Dakshika感谢您的链接,它解释了我几年前使用画布时图书馆为我照顾的一个问题。
Fering

Answers:


267

不,但是,您可以将多个<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和show layer2,并在需要时反之亦然。
Zaraki 2012年

4
您可以使用CSS将其隐藏-即display: none;。或者只是清除画布,如果在显示图层时重新绘制它并不昂贵。
jimr 2012年

分配给“ left”和“ top”的值必须是“ 0px”,而不是“ 0”。
布莱恩·格林

6
@BryanGreen不是真的。“但是,对于零长度,单位标识符是可选的(即可以在语法上表示为<number> 0)。” w3.org/TR/css3-values/#lengths
xehpuk '16

我可以控制多个画布的构图类型吗?
ziyuang,

40

与此相关:

如果您在画布上有东西,并且想在它的背面绘制东西,可以通过将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);
<canvas id="cvs" />


是的,这很好,但是如所要求的那样在擦除的情况下。这将并行擦除两层。这又是不正确的。
Pardeep Jain

27

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

然后对它们进行任何操作,最后使用drawImageon 在目标画布上按适当顺序呈现其内容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


4
@SCLeo,您说“性能杀手。大约慢10倍”是完全错误的。根据使用情况,使用单个DOM画布并将屏幕外的画布渲染到该场景要比在DOM中堆叠画布更快。常见的错误是基准化渲染调用,画布绘制调用可以计时,DOM渲染不在Javascript上下文之外并且不能计时。结果是be DOM堆叠的画布未包含基准中包含的合成渲染(由DOM完成)
。– Blindman67

@ Blindman67我知道你的意思。只需检查此基准测试:jsfiddle.net/9a9L8k7k/1。如果您误解了,共有三个画布,画布1(ctx1)是真实的画布。画布2(ctx2)和画布3(ctx)不在屏幕上。该图像先前已渲染到ctx3上。在此基准测试的测试1中,我将ctx3直接渲染到ctx1上。在测试2中,我将ctx3渲染到ctx2上,然后将ctx2渲染到ctx1。测试2比计算机上的测试1慢30倍。这就是为什么我说使用中间画布要慢得多。
SCLeo

@ Blindman67屏幕外画布的技巧仅在屏幕外画布为静态时才有效。使用动态画布会极大地损害性能。(再次,我要说的是动态屏幕外画布非常慢,因此可能不希望使用此技术(通过多个屏幕外画布模拟图层))
SCLeo

@ Blindman67重要提示:基准测试的地址为https://jsfiddle.net/9a9L8k7k/3,我在编辑后忘记保存,并且Stack Overflow不允许我更改以前的注释了……
SCLeo

4
@ Blindman67对不起,这是我的错误。我进行了测试,发现使用多个屏幕外画布运行非常顺畅。我仍然不确定为什么该基准测试表明使用屏幕外画布这么慢。
SCLeo

6

我也遇到了同样的问题,当我将多个具有position:absolute的画布元素同时使用时,如果您要将输出保存到图像中,那将是行不通的。

因此,我继续进行了一个简单的分层“系统”来进行编码,就好像每个层都有自己的代码一样,但是所有这些都被渲染到同一元素中。

https://github.com/federicojacobi/layeredCanvas

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

您可以执行多种功能并调用它们以“伪造”图层。


这是完美的。
Nadir

4

您可能还需要检出http://www.concretejs.com,这是一个现代的,轻量级的Html5 canvas框架,它可以进行点击检测,分层和许多其他外围功能。您可以执行以下操作:

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访问吗?
Garavani

0

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

在我们的案例中,我们将分层透明PNG z-index用作“产品构建器”小部件。Html2canvas出色地工作,可以在不压入图像的情况下使堆栈沸腾,也无需使用复杂性,变通办法和“无响应”画布本身。我们无法使用香草canvas + JS顺利/理智地执行此操作。

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


如果图像较重,则将HTML转换为画布将需要一些时间,我们不得不放弃这一点,因为渲染花费了很长时间。
Vilius

@Vilius是的,在大图/大图上不错。我们尝试保留不超过4层的300K或更少的图像,否则资源匮乏的客户端在下载最终的堆肥图像时会感到烧焦。很好奇,您在减少时间上做了什么?
dhaupin

好吧,我们通过使用html元素首先绘制东西犯了一个大错误。因为我们的api返回了x,y,宽度和高度,所以我们移到jscanavs来绘制图像,而不是使用html元素。请注意,旋转确实存在一些问题(起点有些笨拙且不可预测),并使用特定尺寸将图像应用于其旋转,但最终所有问题都得到解决。我们还发现我们的图像处理应用程序正在消耗大量资源,因此我们也放弃了这一点。
Vilius

0

但第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>

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.