html5 - elemento canvas - Várias camadas

176

Sem nenhuma biblioteca de extensão, é possível ter várias camadas no mesmo elemento da tela?

Então, se eu fizer um clearRect na camada superior, ela não apagará a inferior?

Obrigado.

Gregoire
fonte
você pode dar uma olhada no radikalfx.com/2009/10/16/canvas-collage . ele usa uma espécie de técnica de "camadas".
Mateus
2
verificar isso .. html5.litten.com/using-multiple-html5-canvases-as-layers isso irá ajudá-lo a resolver o problema de forma adequada
Dakshika
@ Dakshika Obrigado por esse link, ele explicou um problema que eu tinha usando a tela há alguns anos atrás, que uma biblioteca cuidava de mim.
Fering 16/04/19

Respostas:

267

Não, no entanto, você pode colocar vários <canvas>elementos em camadas uns sobre os outros e realizar algo semelhante.

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

Desenhe sua primeira camada na layer1tela e a segunda camada na layer2tela. Então, quando você estiver clearRectna camada superior, o que estiver na tela inferior será exibido.

jimr
fonte
existe uma maneira de ocultar / mostrar uma camada .. de modo que eu possa ocultar a camada1 e mostrar a camada2 e vice-versa quando necessário .. ??
Zaraki
4
Você pode escondê-lo com CSS - ie display: none;. Ou simplesmente limpe a tela, se não for muito caro redesenhá-la novamente quando a camada for exibida.
jimr
Os valores atribuídos a 'left' e 'top' precisam ser '0px', não '0'.
Bryan Green
6
@BryanGreen Não é verdade. "No entanto, para comprimentos zero, o identificador da unidade é opcional (ou seja, pode ser representado sintaticamente como o <número> 0)." w3.org/TR/css3-values/#lengths
xehpuk
Posso controlar o tipo de composição para várias telas?
ziyuang
40

Relacionado a isso:

Se você tem algo na tela e deseja desenhar algo na parte de trás, altere a configuração context.globalCompositeOperation para 'destination-over' - e retorne-a para 'source-over' quando você ' re feito.

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

Richard
fonte
sim, isso é bom, mas em caso de apagamento, conforme solicitado. isso apagará as duas camadas paralelamente. o que novamente não está correto.
Pardeep Jain
27

Você pode criar vários canvaselementos sem anexá-los ao documento. Estas serão as suas camadas :

Em seguida, fazer o que quiser com eles e no final apenas tornar o seu conteúdo na ordem correta na tela de destino usando drawImageon context.

Exemplo:

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

E aqui está um código de código: https://codepen.io/anon/pen/mQWMMW

juszczak
fonte
4
@SCLeo você disse "Assassino de desempenho. Cerca de 10 vezes mais lento" está completamente errado. Dependendo dos casos de uso, usar uma única tela do DOM e renderizar telas fora da tela é mais rápido que empilhar a tela no DOM. O erro comum é fazer comparações de chamadas de renderização, chamadas de desenho de tela podem ser cronometradas, a renderização DOM está fora do contexto de Javascripts e não pode ser cronometrada. O resultado é que o ser DOM empilhados tela não obter a composição render (feito por DOM) incluída no benchmark ..
Blindman67
@ Blindman67 Eu sei o que você quer dizer. Basta fazer o checkout deste benchmark: jsfiddle.net/9a9L8k7k/1 . Caso você entenda mal, existem três telas, a tela 1 (ctx1) é uma tela real. A tela 2 (ctx2) e a tela 3 (ctx) estão fora da tela. A imagem foi renderizada anteriormente no ctx3. No teste 1 deste benchmark, eu renderizo diretamente ctx3 para ctx1. No teste 2, renderizo ctx3 em ctx2 e depois ctx2 em ctx1. O teste 2 é 30 vezes mais lento que o teste 1 no meu computador. É por isso que digo que usar uma tela intermediária é muito mais lento.
SCLeo
@ Blindman67 O truque da tela fora da tela só funciona quando a tela fora da tela é estática. O uso de telas dinâmicas prejudicará bastante o desempenho. (Mais uma vez, o que eu estou tentando dizer é que dinâmica off-screen tela é extremamente lento então, presumivelmente, esta técnica (camadas simulados por tela fora da tela múltipla) não será desejável)
SCLeo
@ Blindman67 IMPORTANTE: O endereço do benchmark é https://jsfiddle.net/9a9L8k7k/3 , eu esqueça de salvar após a edição e não de estouro de pilha não deixe-me para mudar o comentário anterior mais ...
SCLeo
4
@ Blindman67 Sinto muito, é meu erro. Eu testei e acho que o uso de várias telas fora da tela é muito suave. Ainda não sei ao certo por que essa referência mostra que o uso de telas fora da tela é tão lento.
SCLeo
6

Eu também estava tendo esse mesmo problema, enquanto vários elementos da tela com posição: absoluto faz o trabalho, se você deseja salvar a saída em uma imagem, isso não vai funcionar.

Então, fui adiante e criei um "sistema" de camadas simples para codificar como se cada camada tivesse seu próprio código, mas tudo é renderizado no mesmo elemento.

https://github.com/federicojacobi/layeredCanvas

Eu pretendo adicionar recursos extras, mas por enquanto isso fará.

Você pode executar várias funções e chamá-las para "falsificar" as camadas.

Federico Jacobi
fonte
Este é perfeito.
Nadir
4

Você também pode verificar o site http://www.concretejs.com, que é uma estrutura de tela Html5 moderna e leve, que permite a detecção de hits, camadas e muitas outras coisas periféricas. Você pode fazer coisas assim:

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();
Eric Rowell
fonte
De que maneira essas camadas vão acabar no DOM? Cada um acessível via CSS?
Garavani
0

Entendo que o Q não deseja usar uma biblioteca, mas vou oferecê-lo a outros provenientes de pesquisas no Google. O @EricRowell mencionou um bom plugin, mas também existe outro plugin que você pode tentar, o html2canvas .

No nosso caso, estamos usando PNG transparentes em camadas com z-indexum widget "construtor de produtos". O Html2canvas trabalhou brilhantemente para reduzir a pilha sem empurrar imagens, nem usar complexidades, soluções alternativas e a própria tela "não responsiva". Não conseguimos fazer isso sem problemas / com a tela de baunilha + JS.

Primeiro use z-indexem divs absolutas para gerar conteúdo em camadas dentro de um invólucro posicionado relativo. Em seguida, passe o wrapper pelo html2canvas para obter uma tela renderizada, que você pode deixar como está, ou como uma imagem para que um cliente possa salvá-la.

dhaupin
fonte
Se você tiver imagens mais pesadas, isso levará algum tempo para converter HTML em tela, tivemos que nos afastar disso apenas porque a renderização levou muito tempo.
Vilius
@Vilius sim, é bom chamar as imagens pesadas / grandes. Tentamos manter imagens de 300 mil ou menos, com não mais de 4 camadas, caso contrário, os clientes afetados por recursos sentiriam a queimadura ao baixar a imagem compostada final. Curioso, o que você mudou para esse tempo reduzido?
precisa saber é o seguinte
Bem, cometemos um grande erro usando elementos html para desenhar algo em primeiro lugar. Como nossa API retornou x, y, largura e altura, mudamos para jscanavs para desenhar a imagem em vez de usar elementos html. Lembre-se de que tivemos alguns problemas com a rotação (os pontos de partida eram um pouco estranhos e imprevisíveis) e aplicamos imagens a ela usando dimensões específicas, mas tudo foi resolvido eventualmente. Também descobrimos que nosso aplicativo de processamento de imagens estava consumindo muitos recursos, então também nos afastamos dele.
Vilius
0

mas a camada 02 cobrirá todos os desenhos da camada 01. Usei isso para mostrar o desenho nas duas camadas. use (cor de fundo: transparente;) em grande 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>

aymhenry
fonte