Canvas: восстановить изображение после удаления объекта на нем

#javascript #html #html5-canvas

#javascript #HTML #html5-canvas

Вопрос:

У меня есть следующий код:

 const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');

const image = new Image(60, 45); // Using optional size for image
image.onload = drawImageActualSize; // Draw when image has loaded

// Load an image of intrinsic size 300x227 in CSS pixels
image.src = 'https://mdn.mozillademos.org/files/5397/rhino.jpg';

function drawImageActualSize() {
  // Use the intrinsic size of image in CSS pixels for the canvas element
  canvas.width = this.naturalWidth;
  canvas.height = this.naturalHeight;

  // Will draw the image as 300x227, ignoring the custom size of 60x45
  // given in the constructor
  ctx.drawImage(this, 0, 0);

  // To use the custom size we'll have to specify the scale parameters 
  // using the element's width and height properties - lets draw one 
  // on top in the corner:
  ctx.drawImage(this, 0, 0, this.width, this.height);
  ctx.save();
  ctx.fillStyle = 'green';
ctx.fillRect(10, 10, 150, 100);

ctx.restore();
ctx.clearRect(10, 10, 150, 100);
}  
 <canvas id="canvas" width=300 height=200></canvas>  

Здесь метод ctx.clearRect (10, 10, 150, 100) удаляет зеленую часть, а также изображение и показывает белый холст.

Я хочу удалить только зеленую часть и восстановить предыдущее изображение.

Как я могу этого добиться?

Ответ №1:

Перерисовать

Стандартный способ добавления и удаления динамического содержимого — повторно отображать холст каждый раз, когда происходит изменение. Вот как это делают HTML-игры canvas, работающие со скоростью 60 кадров в секунду, и в них может меняться 100 элементов за кадр.

Существуют другие методы, которые требуют создания копии того, что находится под прямоугольником каждый раз, когда он рисуется, а затем рисования копии поверх прямоугольника, когда вы хотите его удалить.

Это сложно и требует по крайней мере одного дополнительного холста для каждого отрисовываемого динамического объекта и, таким образом, занимает много памяти. Или используйте getImageData и putImageData, которые также загружают память, работают очень медленно, приведут к большому количеству действий GC и недоступны для незащищенного содержимого (изображения в разных доменах или из локального хранилища файлов).

Перерисовка — безусловно, самый простой способ. Вы бы рассматривали другие методы, только если для рендеринга всего содержимого (для не анимированного содержимого) потребовалось более нескольких 100 мс

Пример

В примере переменная rectOn , если true, добавляет зеленый прямоугольник на холст (рисует как изображение, так и прямоугольник). Если не верно, то прямоугольник удаляется (рисуется только изображение).

Функция draw отображает холст в соответствии с состоянием переменной rectOn

Нажмите кнопку, чтобы добавить / удалить прямоугольник.

 const ctx = canvas.getContext('2d');
var rectOn = false; 
const image = new Image();
image.src = 'https://mdn.mozillademos.org/files/5397/rhino.jpg';
image.addEventListener("load", ready, {once:true});
function ready() {
    canvas.width = this.naturalWidth;
    canvas.height = this.naturalHeight;
    loading.classList.add("hide");
    addRemove.classList.remove("hide");
    addRemove.addEventListener("click", toggle);
    draw();
}
function draw() {
    ctx.drawImage(image, 0, 0);
    if (rectOn) {
        ctx.fillStyle = "#0F0";
        ctx.fillRect(10, 50, 150, 100);    
    }
}
function toggle() {
    rectOn = !rectOn;     
    addRemove.textContent = (rectOn ? "Remove": "Add" )   " rect";
    draw();
}  
 button { cursor: pointer; width: 120px }
.hide {display:none}
canvas { position: absolute; top: 0px; left: 0px; z-index:-1; }  
 <span id="loading">Loading image</span><button id="addRemove" class="hide">Add green rect</button><br>
<canvas id="canvas"></canvas>