html5 - elemento de lienzo - Múltiples capas


176

Sin ninguna biblioteca de extensión, ¿es posible tener varias capas en el mismo elemento de lienzo?

Entonces, si hago un clearRect en la capa superior, ¿no borrará la capa inferior?

Gracias.


puede echarle un vistazo a radikalfx.com/2009/10/16/canvas-collage . él usa una especie de técnica de "capas".
Mateo

2
mira esto ... html5.litten.com/using-multiple-html5-canvases-as-layers esto te ayudará a resolver tu problema de la manera adecuada
Dakshika

@Dakshika Gracias por ese enlace, explicaba un problema que tuve al usar el lienzo hace unos años y que una biblioteca se encargó de mí.
Fering

Respuestas:


267

No, sin embargo, podría superponer varios <canvas>elementos uno encima del otro y lograr algo similar.

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

Dibuja tu primera capa en el layer1lienzo y la segunda capa en el layer2lienzo. Luego, cuando esté clearRecten la capa superior, se mostrará lo que esté en el lienzo inferior.


¿Hay alguna forma de ocultar / mostrar una capa ... de modo que pueda ocultar layer1 y mostrar layer2 y viceversa cuando sea necesario?
Zaraki

44
Puede ocultarlo con CSS, es decir display: none;. O simplemente limpie el lienzo, si no es muy costoso volver a dibujarlo nuevamente cuando se muestre la capa.
jimr

Los valores asignados a 'left' y 'top' deben ser '0px', no '0'.
Bryan Green

66
@BryanGreen No es cierto. "Sin embargo, para longitudes cero, el identificador de la unidad es opcional (es decir, se puede representar sintácticamente como el <número> 0)". w3.org/TR/css3-values/#lengths
xehpuk

¿Puedo controlar el tipo de composición para varios lienzos?
ziyuang

40

Relacionado con esto:

Si tiene algo en su lienzo y desea dibujar algo en la parte posterior, puede hacerlo cambiando la configuración context.globalCompositeOperation a 'destination-over' y luego vuelva a 'source-over' cuando usted ' re hecho.

   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" />


Sí, eso está bien, pero en caso de borrado, como se hizo en la pregunta. Esto borrará ambas capas paralelamente. lo cual de nuevo no es correcto.
Pardeep Jain el

27

Puede crear varios canvaselementos sin agregarlos al documento. Estas serán tus capas :

Luego, haga lo que quiera con ellos y, al final, simplemente presente su contenido en el orden correcto en el lienzo de destino usando drawImageon context.

Ejemplo:

/* 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);

Y aquí hay algunos codepen: https://codepen.io/anon/pen/mQWMMW


44
@SCLeo dijiste "Asesino de rendimiento. Aproximadamente 10 veces más lento" está completamente equivocado. Dependiendo de los casos de uso, usar un solo lienzo DOM y renderizar lienzos fuera de pantalla es más rápido que apilar lienzos en DOM. El error común es la evaluación comparativa de las llamadas de representación, las llamadas de extracción de lienzo se pueden cronometrar, la representación DOM está fuera del contexto de Javascripts y no se puede cronometrar. El resultado es que el lienzo apilado DOM no obtiene el renderizado de composición (hecho por DOM) incluido en el punto de referencia ..
Blindman67

@ Blindman67 Sé lo que quieres decir. Simplemente revise este punto de referencia: jsfiddle.net/9a9L8k7k/1 . En caso de que malinterpretes, hay tres lienzos, el lienzo 1 (ctx1) es un lienzo real. El lienzo 2 (ctx2) y el lienzo 3 (ctx) están fuera de la pantalla. La imagen se ha renderizado previamente en ctx3. En la prueba 1 de este punto de referencia, renderizo directamente ctx3 en ctx1. En la prueba 2, renderizo ctx3 en ctx2 y luego ctx2 a ctx1. La prueba 2 es 30 veces más lenta que la prueba 1 en mi computadora. Por eso digo que usar un lienzo intermedio es mucho más lento.
SCLeo

@ Blindman67 El truco del lienzo fuera de la pantalla solo funciona cuando el lienzo fuera de la pantalla es estático. El uso de lienzos dinámicos dañará en gran medida el rendimiento. (Una vez más, lo que estoy tratando de decir es que el lienzo dinámico fuera de pantalla es extremadamente lento, por lo que presumiblemente esta técnica (simulando capas por lienzo fuera de pantalla múltiple) no será deseable)
SCLeo

@ Blindman67 IMPORTANTE: La dirección del punto de referencia es https://jsfiddle.net/9a9L8k7k/3 , me olvido de guardar después de editar y Stack Overflow ya no me permite cambiar el comentario anterior ...
SCLeo

44
@ Blindman67 Lo siento, es mi error. Probé y descubrí que el uso de múltiples lienzos fuera de la pantalla funciona muy bien. Todavía no estoy seguro de por qué ese punto de referencia muestra que usar el lienzo fuera de la pantalla es tan lento.
SCLeo

6

También tenía este mismo problema, mientras que múltiples elementos de lienzo con posición: absoluto hacen el trabajo, si desea guardar la salida en una imagen, eso no va a funcionar.

Así que seguí adelante e hice un "sistema" de capas simple para codificar como si cada capa tuviera su propio código, pero todo se representa en el mismo elemento.

https://github.com/federicojacobi/layeredCanvas

Tengo la intención de agregar capacidades adicionales, pero por ahora lo hará.

Puede realizar múltiples funciones y llamarlas para "simular" capas.


Este es perfecto
Nadir

4

También puede consultar http://www.concretejs.com, que es un marco de lienzo Html5 moderno y liviano que permite la detección de golpes, la estratificación y muchas otras cosas periféricas. Puedes hacer cosas como esta:

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();

¿De qué manera esas capas terminarán en el DOM? ¿Cada uno accesible a través de CSS?
Garavani

0

Entiendo que el Q no quiere usar una biblioteca, pero lo ofreceré a otros que provengan de búsquedas de Google. @EricRowell mencionó un buen complemento, pero también hay otro complemento que puedes probar, html2canvas .

En nuestro caso, estamos usando PNG transparentes en capas con z-indexun widget de "creador de productos". Html2canvas funcionó de manera brillante para reducir la pila sin presionar imágenes, ni utilizar complejidades, soluciones alternativas y el lienzo "no sensible". No pudimos hacer esto sin problemas con el lienzo de vainilla + JS.

Primer uso z-indexen divs absolutos para generar contenido en capas dentro de un contenedor posicionado relativo. Luego canalice el contenedor a través de html2canvas para obtener un lienzo renderizado, que puede dejar tal cual, o generar como una imagen para que un cliente pueda guardarlo.


Si tiene imágenes más pesadas, esto llevará algún tiempo convertir HTML a lienzo, tuvimos que alejarnos de esto solo porque el renderizado tomó mucho tiempo.
Vilius

@Vilius, sí, buena llamada en las imágenes pesadas / grandes. Intentamos mantener imágenes de 300K o menos con no más de 4 capas, de lo contrario, los clientes afectados por los recursos sentirían la quemadura al descargar la imagen compostada final. Curioso, ¿qué pasaste a ese tiempo reducido?
dhaupin

Bueno, cometimos un gran error al usar elementos html para dibujar algo en primer lugar. Debido a que nuestra API devolvió x, y, ancho y alto, nos mudamos a jscanavs para dibujar la imagen en lugar de usar elementos html. Tenga en cuenta que teníamos un par de problemas con la rotación (los puntos de partida eran un poco incómodos e impredecibles) y la aplicación de imágenes con dimensiones específicas, pero finalmente todo se resolvió. También descubrimos que nuestra aplicación de procesamiento de imágenes estaba agotando muchos recursos, por lo que también nos alejamos de eso.
Vilius

0

pero la capa 02 cubrirá todos los dibujos de la capa 01. Utilicé esto para mostrar el dibujo en ambas capas. use (background-color: transparent;) en estilo.

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

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.