html5 - элемент canvas - несколько слоев

176

Без какой-либо библиотеки расширений возможно ли иметь несколько слоев в одном элементе canvas?

Так что, если я сделаю clearRect на верхнем слое, он не сотрет нижний?

Спасибо.

Gregoire
источник
Вы можете взглянуть на radikalfx.com/2009/10/16/canvas-collage . он использует своего рода технику "слоев".
Мэтью
2
проверьте это .. html5.litten.com/using-multiple-html5-canvases-as-layers это поможет вам решить проблему надлежащим образом
Дакшика,
@Dakshika Спасибо за эту ссылку, она объяснила проблему, с которой я столкнулся несколько лет назад, когда за меня позаботилась библиотека.
Fering

Ответы:

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на верхнем слое, все, что находится на нижнем холсте, будет просвечивать.

jimr
источник
Есть ли способ скрыть / показать слой .. так, что я могу скрыть layer1 и показать layer2 и делать наоборот, когда это необходимо .. ??
Зараки
4
Вы можете скрыть это с помощью CSS - то есть display: none;. Или просто очистите холст, если не слишком дорого перерисовать его снова, когда слой должен быть показан.
Jimr
Значения, присвоенные «left» и «top», должны быть «0px», а не «0».
Брайан Грин
6
@BryanGreen Не правда. «Однако для нулевой длины идентификатор единицы является необязательным (то есть может быть синтаксически представлен как <число> 0)». w3.org/TR/css3-values/#lengths
xehpuk
Могу ли я контролировать тип композиции для нескольких холстов?
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" />

Ричард
источник
да, это хорошо, но в случае стирания, как задано вопросом. это сотрет оба слоя параллельно. что опять не правильно.
Пардип Джайн
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

Juszczak
источник
4
@SCLeo Вы сказали, что «Убийство производительности. Примерно в 10 раз медленнее» совершенно неправильно. В зависимости от сценариев использования использование одного холста DOM и рендеринг закадрового полотна выполняется быстрее, чем укладка холста в DOM. Распространенной ошибкой является сравнение вызовов рендеринга, вызовы отрисовки холста могут быть синхронизированы, рендеринг DOM находится вне контекста Javascripts и не может быть рассчитан по времени. В результате холст со
Blindman67
@ Blindman67 Я знаю, что ты имеешь в виду. Просто проверьте этот тест: jsfiddle.net/9a9L8k7k/1 . Если вы не правильно поняли, есть три холста, холст 1 (ctx1) - это настоящий холст. Холст 2 (ctx2) и холст 3 (ctx) отключены от экрана. Изображение было ранее отрендерено на ctx3. В тесте 1 этого теста я напрямую рендерил ctx3 на ctx1. В тесте 2 я рендерил ctx3 на ctx2, а затем ctx2 на ctx1. Тест 2 в 30 раз медленнее, чем тест 1 на моем компьютере. Вот почему я говорю, что использование промежуточного холста намного медленнее.
SCLeo
@ Blindman67 Уловка закадрового холста работает только тогда, когда закадровый холст статичен. Использование динамических холстов сильно повредит производительности. (Опять же, я пытаюсь сказать, что динамический холст вне экрана чрезвычайно медленный, поэтому, вероятно, этот метод (имитация слоев несколькими
холстами
@ Blindman67 ВАЖНО: Адрес бенчмарка: https://jsfiddle.net/9a9L8k7k/3 , я забываю сохранить после редактирования, а переполнение стека не позволяет мне изменять предыдущий комментарий ...
SCLeo
4
@ Blindman67 Извините, это моя ошибка. Я проверил и обнаружил, что использование нескольких закадровых холст работает очень гладко. Я до сих пор не уверен, почему этот тест показывает, что использование закадрового холста так медленно.
SCLeo
6

У меня тоже была такая же проблема, я в то время как несколько элементов canvas с position: absolute делает работу, если вы хотите сохранить вывод в изображение, это не сработает.

Поэтому я пошел дальше и создал простую многоуровневую «систему» ​​для кодирования, как если бы каждый слой имел свой собственный код, но все это отображается в одном элементе.

https://github.com/federicojacobi/layeredCanvas

Я намерен добавить дополнительные возможности, но пока это будет сделано.

Вы можете выполнять несколько функций и вызывать их, чтобы «подделать» слои.

Федерико Якоби
источник
Этот идеален.
Надир
4

Вы также можете зайти на 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?
Гаравани,
0

Я понимаю, что Q не хочет использовать библиотеку, но я предложу это для других, поступающих из поисков Google. @EricRowell упомянул хороший плагин, но есть и другой плагин, который вы можете попробовать, html2canvas .

В нашем случае мы используем многоуровневые прозрачные PNG с z-indexвиджетом «Построитель продукта». Html2canvas блестяще работал для того, чтобы свести стек, не выдвигая изображения, не используя сложности, обходные пути и сам «неотвечающий» холст. Мы не смогли сделать это гладко / вменяемым с vanilla canvas + JS.

Сначала используйте z-indexабсолютные элементы div для создания многоуровневого содержимого в относительной позиционированной оболочке. Затем направьте оболочку через html2canvas, чтобы получить визуализированный холст, который вы можете оставить как есть, или вывести как изображение, чтобы клиент мог его сохранить.

dhaupin
источник
Если у вас более тяжелые изображения, для преобразования HTML в canvas потребуется некоторое время, нам пришлось отойти от этого только потому, что рендеринг занял много времени.
Вилюс
@Vilius, да, хорошо обращайтесь к большим / большим изображениям. Мы старались придерживаться изображений размером 300 КБ или менее, используя не более 4 слоев, иначе клиенты, пораженные ресурсами, чувствовали бы ожог при загрузке окончательного компостированного изображения. Любопытно, что вы перешли к этому сокращенному времени?
Дхаупин
Что ж, мы сделали большую ошибку, используя HTML-элементы, чтобы нарисовать что-то в первую очередь. Поскольку наш API вернул x, y, ширину и высоту, мы перешли к jscanavs, чтобы нарисовать изображение вместо использования HTML-элементов. Напомним, у нас было несколько проблем с вращением (начальные точки были немного неуклюжими и непредсказуемыми) и применением к ним изображений с использованием определенных размеров, но все было в конечном итоге решено. Мы также обнаружили, что наше приложение для обработки изображений истощает много ресурсов, поэтому мы также отошли от этого.
Вилюс
0

но слой 02 будет охватывать все рисунки в слое 01. Я использовал это, чтобы показать рисунок в обоих слоях. использовать (background-color: прозрачный;) в стиле.

    <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
источник