Как очистить холст для перерисовки

1013

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

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

Ричард
источник

Ответы:

1293
const context = canvas.getContext('2d');

context.clearRect(0, 0, canvas.width, canvas.height);
Pentium10
источник
42
Обратите внимание, что clearRectвам нужно либо иметь нетрансформированный контекст, либо отслеживать ваши фактические границы.
Phrogz
7
Также обратите внимание, что установка ширины холста a) должна установить другое значение, а затем снова вернуться для совместимости с Webkit , и b) это сбросит преобразование контекста .
Phrogz
45
Не используйте трюк с шириной. Это грязный хак. На языке высокого уровня, таком как JavaScript, вам нужно наилучшим образом заявить о своих намерениях, а затем позволить коду нижнего уровня выполнить их. Установка ширины для себя не указывает на ваше истинное намерение - очистить холст.
andrewrk
22
Абсолютно незначительное предложение, но я бы предложил context.clearRect(0, 0, context.canvas.width, context.canvas.height). Это фактически то же самое, но на одну зависимость меньше (1 переменная вместо 2)
gman
6
Для более поздних читателей этого ответа: имейте в виду, что этот ответ был изменен и что некоторые из приведенных выше комментариев больше не применяются .
daveslab
719

Использование: context.clearRect(0, 0, canvas.width, canvas.height);

Это самый быстрый и описательный способ очистить весь холст.

Не используйте: canvas.width = canvas.width;

Сброс canvas.widthсбрасывает все состояние холста (например, transformation, lineWidth, strokeStyle и т. Д.), Он очень медленный (по сравнению с clearRect), он работает не во всех браузерах и не описывает, что вы на самом деле пытаетесь сделать.

Работа с преобразованными координатами

Если вы изменили матрицу преобразования (например, используя scale, rotateили translate), то context.clearRect(0,0,canvas.width,canvas.height), скорее всего, не очистите всю видимую часть холста.

Решение? Сброс матрицы преобразования до очистки холста:

// Store the current transformation matrix
context.save();

// Use the identity matrix while clearing the canvas
context.setTransform(1, 0, 0, 1, 0, 0);
context.clearRect(0, 0, canvas.width, canvas.height);

// Restore the transform
context.restore();

Редактировать: я только что провел некоторое профилирование и (в Chrome) примерно на 10% быстрее очистить холст 300x150 (размер по умолчанию) без сброса преобразования. По мере увеличения размера вашего холста эта разница уменьшается.

Это уже относительно незначительно, но в большинстве случаев вы будете рисовать значительно больше, чем очищаете, и я считаю, что эта разница в производительности не имеет значения.

100000 iterations averaged 10 times:
1885ms to clear
2112ms to reset and clear
Prestaul
источник
4
@YumYumYum: clear () - стандартная функция? Кажется, это не так.
Нобар
7
Обратите внимание, что вы можете устранить необходимость в локальной canvasпеременной, используя ctx.canvasвместо этого.
Дрю Ноакс
1
@DrewNoakes, хорошая мысль, но я почти всегда выбираю отдельные переменные для целей скорости. Это крайне незначительно, но я стараюсь избегать разыменования, используя псевдонимы часто используемых свойств (особенно внутри цикла анимации).
Prestaul
Демо AlexanderN больше не работает из-за неработающей ссылки на изображение, исправлено: jsfiddle.net/Ktqfs/50
Domino
Другой способ очистить весь холст в случае изменения матрицы преобразования - просто отслеживать преобразования и применять их самостоятельно canvas.widthи canvas.heightпри очистке. Я не проводил никакого числового анализа разницы во времени выполнения по сравнению со сбросом преобразования, но я подозреваю, что это принесет чуть лучшую производительность.
NanoWizard
226

Если вы рисуете линии, убедитесь, что вы не забыли:

context.beginPath();

В противном случае линии не будут очищены.

TrEMBL
источник
10
Я знаю, что это было здесь некоторое время, и, наверное, глупо комментировать все это время, но это беспокоило меня в течение года ... Позвоните, beginPathкогда начнете новый путь , не думайте, что только потому, что вы очищаем холст, который вы хотите очистить существующий путь! Это было бы ужасной практикой и обратным взглядом на рисование.
Prestaul
Что делать, если вы просто хотите очистить холст от всего. Допустим, вы создаете игру, и вам нужно перерисовывать экран каждую сотую доли секунды.
1
@JoseQuinones, beginPathничего не удаляет с вашего холста, он сбрасывает путь, так что предыдущие записи пути удаляются перед рисованием. Возможно, вам это нужно, но это не операция очистки, а операция рисования. очистить, затем beginPath и рисовать, не очистить и beginPath, затем нарисовать. Имеет ли смысл разница? Посмотрите здесь для примера: w3schools.com/tags/canvas_beginpath.asp
Prestaul
1
Это решило замедление моей анимации, которое я испытал со временем. Я перерисовывал линии сетки на каждом шаге, но без очистки линий из предыдущего шага.
Георг Патшайдер
118

Другие уже проделали отличную работу, отвечая на вопрос, но если простой clear()метод на объекте контекста был бы полезен для вас (это было для меня), я использую эту реализацию, основываясь на ответах здесь:

CanvasRenderingContext2D.prototype.clear = 
  CanvasRenderingContext2D.prototype.clear || function (preserveTransform) {
    if (preserveTransform) {
      this.save();
      this.setTransform(1, 0, 0, 1, 0, 0);
    }

    this.clearRect(0, 0, this.canvas.width, this.canvas.height);

    if (preserveTransform) {
      this.restore();
    }           
};

Применение:

window.onload = function () {
  var canvas = document.getElementById('canvasId');
  var context = canvas.getContext('2d');

  // do some drawing
  context.clear();

  // do some more drawing
  context.setTransform(-1, 0, 0, 1, 200, 200);
  // do some drawing with the new transform
  context.clear(true);
  // draw more, still using the preserved transform
};
JonathanK
источник
6
Это отличная реализация. Я полностью поддерживаю расширение собственных прототипов, но вы можете убедиться, что «clear» не определено перед его назначением - я все еще надеюсь на нативную реализацию когда-нибудь. :) Знаете ли вы, насколько широко браузеры поддерживают CanvasRenderingContext2D и оставляют его «доступным для записи»?
Prestaul
Спасибо за отзыв @Prestaul - также ни один браузер не должен мешать вам расширять объекты javascript таким образом.
JonathanK
@JonathanK, я бы хотел увидеть некоторые различия в производительности между очисткой с преобразованием и без него. Я предполагаю, что разница будет очевидна, если вы будете мало рисовать, но если то, что вы рисуете, не тривиально, то четкий шаг незначителен ... Возможно, мне придется проверить это позже, когда у меня будет больше времени :)
Престол
Хорошо, я сделал профилирование, и я собираюсь добавить детали в свой пост.
Престол
35
  • Chrome хорошо реагирует на: context.clearRect ( x , y , w , h );как предлагает @ Pentium10, но IE9, похоже, полностью игнорирует эту инструкцию.
  • IE9, кажется, отвечает: canvas.width = canvas.width;но он не очищает линии, только фигуры, рисунки и другие объекты, если только вы не используете решение @John Allsopp о первом изменении ширины.

Так что если у вас есть холст и контекст, созданный так:

var canvas = document.getElementById('my-canvas');
var context = canvas.getContext('2d');

Вы можете использовать такой метод:

function clearCanvas(context, canvas) {
  context.clearRect(0, 0, canvas.width, canvas.height);
  var w = canvas.width;
  canvas.width = 1;
  canvas.width = w;
}
граната
источник
13
Обратите внимание, что метод может быть упрощен путем передачи только контекста и использования context.clearRect(0,0,context.canvas.width,context.canvas.height).
Phrogz
5
IE 9 должен абсолютно отвечать на вызов clearRect ... (См .: msdn.microsoft.com/en-us/library/ff975407(v=vs.85).aspx ). Медленно, как изменение canvas.width, единственный способ Вы можете сделать медленнее, изменив его дважды и вызвав clearRect.
Prestaul
1
Извините, я должен быть более ясным ... Этот метод будет работать (если вы не применили преобразование), но это метод [медленной] грубой силы, где он не нужен. Просто используйте clearRect, поскольку он самый быстрый и должен работать во всех браузерах с реализацией canvas.
Prestaul
1
Я считаю, что IE перерисовывает строки из-за того, что они все еще находятся в буфере пути. Я использую этот формат, и он отлично работает. function clearCanvas(ctx) { ctx.beginPath(); ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height); }
DarrenMB
Я пробовал каждый метод до этого ... и это был единственный, который работал. Я использую Chrome со строками, прямоугольниками и текстом ... я бы не подумал, что будет так сложно сделать что-то, что должно быть встроено! Спасибо!
Энтони Григгс
27

Это 2018 год, и до сих пор нет собственного способа полностью очистить холст для перерисовки. clearRect() не очищает холст полностью Чертежи типа Non-штриховки не убрались (например. rect())

1. Чтобы полностью очистить холст, независимо от того, как вы рисуете:

context.clearRect(0, 0, context.canvas.width, context.canvas.height);
context.beginPath();

Плюсы: сохраняет инсульты, fillStyle и т.д .; Нет лагов;

Минусы: не нужны, если вы уже используете beginPath перед рисованием чего-либо

2. Используя хак ширины / высоты:

context.canvas.width = context.canvas.width;

ИЛИ

context.canvas.height = context.canvas.height;

Плюсы: Работает с IE. Минусы: Сбрасывает strokeStyle, fillStyle в черный; лаг;

Мне было интересно, почему родного решения не существует. На самом деле, clearRect()рассматривается как однолинейное решение, потому что большинство пользователей делают, beginPath()прежде чем рисовать любой новый путь. Хотя beginPath должен использоваться только при рисовании линий, а не при закрытом пути, какrect().

Это причина, по которой принятый ответ не решил мою проблему, и я потратил часы, пытаясь использовать различные способы взлома. Проклинаю тебя мозилла

sziraqui
источник
Я думаю, что это правильный ответ, особенно для рисования холста. Я страдал от оставшегося context.stroke независимо от того, как я вызываю clearRect, в то время как beginPath помогло!
Шао-Куй,
20

Используйте метод clearRect, передавая координаты x, y, а также высоту и ширину холста. ClearRect очистит весь холст как:

canvas = document.getElementById("canvas");
ctx = canvas.getContext("2d");
ctx.clearRect(0, 0, canvas.width, canvas.height);
Vishwas
источник
Вы можете просто поместить это в метод и вызывать его каждый раз, когда хотите обновить экран, правильно.
@ XXX.xxx плз, проверьте id холста в вашем html и используйте его для первой строки (чтобы получить элемент по id)
Vishwas
14

Здесь есть множество хороших ответов. Еще одно замечание: иногда бывает весело только частично очистить холст. то есть «затухает» предыдущее изображение, а не стирает его полностью. это может дать хорошие следы эффектов.

это просто. Предположим, ваш цвет фона белый:

// assuming background color = white and "eraseAlpha" is a value from 0 to 1.
myContext.fillStyle = "rgba(255, 255, 255, " + eraseAlpha + ")";
myContext.fillRect(0, 0, w, h);
Орион Элензил
источник
Я знаю, что это возможно, и у меня нет проблем с вашим ответом, мне просто интересно, если у вас есть 2 движущихся объекта, и вы хотите отследить только один из них, как бы вы поступили так?
супер
это намного сложнее. в этом случае вы должны создать закадровый холст, и каждый кадр рисует объекты, которые вы хотите отследить на этом холсте, используя метод частичного стирания, описанный здесь, а также каждый кадр очищает основной холст на 100%, рисует нетранслируемый объекты, а затем скомпоновать закадровый холст на основной, используя drawImage (). Вам также необходимо установить для globalCompositeOperation что-то подходящее для изображений. например, «умножение» будет хорошо работать для темных объектов на светлом фоне.
Орион Элензил
12

Быстрый способ сделать

canvas.width = canvas.width

ИДК, как это работает, но это делает!

Джейкоб Моррис
источник
Ух ты. Это действительно работает, как вы когда-нибудь нашли это?
Зипзит
@zipit Быстрый трюк, который я обнаружил на medium.com после того, как обычная очистка не
Джейкоб Моррис
1
Я дергаю себя за волосы, пытаясь понять, почему это работает! Спасибо, что поделился!
aabbccsmith
Кто-нибудь может объяснить, почему это работает, и даже canvas.width + = 0 тоже делает свою работу, что за чёртова наука стоит за этим?
PYK
8

Это то, что я использую, независимо от границ и матричных преобразований:

function clearCanvas(canvas) {
  const ctx = canvas.getContext('2d');
  ctx.save();
  ctx.globalCompositeOperation = 'copy';
  ctx.strokeStyle = 'transparent';
  ctx.beginPath();
  ctx.lineTo(0, 0);
  ctx.stroke();
  ctx.restore();
}

По сути, он сохраняет текущее состояние контекста и рисует прозрачный пиксель с copyas globalCompositeOperation. Затем восстанавливает предыдущее состояние контекста.

superruzafa
источник
меня устраивает...! Спасибо.
NomanJaved
6

Это сработало для моего pieChart в chart.js

<div class="pie_nut" id="pieChartContainer">
    <canvas id="pieChart" height="5" width="6"></canvas> 
</div>

$('#pieChartContainer').html(''); //remove canvas from container
$('#pieChartContainer').html('<canvas id="pieChart" height="5" width="6"></canvas>'); //add it back to the container
Санал С
источник
5

Я обнаружил, что во всех браузерах, которые я тестирую, самый быстрый способ - заполнить Rect белым или любым другим цветом, который вы хотите. У меня очень большой монитор, и в полноэкранном режиме clearRect мучительно медленный, но fillRect оправдан.

context.fillStyle = "#ffffff";
context.fillRect(0,0,canvas.width, canvas.height);

Недостатком является то, что холст больше не является прозрачным.

Джон Пейдж
источник
4

в webkit вам нужно установить ширину на другое значение, затем вы можете вернуть его к первоначальному значению

Джон Аллсопп
источник
4
function clear(context, color)
{
    var tmp = context.fillStyle;
    context.fillStyle = color;
    context.fillRect(0, 0, context.canvas.width, context.canvas.height);
    context.fillStyle = tmp;
}
Представьте себе брейкер
источник
Это медленнее, чем clearRect (0,0, canvas.width, canvas.height)
sEver
4

Простой, но не очень читаемый способ - написать так:

var canvas = document.getElementId('canvas');

// after doing some rendering

canvas.width = canvas.width;  // clear the whole canvas
Чанг
источник
2

Я всегда использую

cxt.fillStyle = "rgb(255, 255, 255)";
cxt.fillRect(0, 0, canvas.width, canvas.height);
GameMaster1928
источник
это самый простой способ! Ну, по крайней мере для меня.
Жак Оливье
1
context.clearRect(0,0,w,h)   

заполните данный прямоугольник значениями RGBA:
0 0 0 0: с Chrome
0 0 0 255: с FF & Safari

Но

context.clearRect(0,0,w,h);    
context.fillStyle = 'rgba(0,0,0,1)';  
context.fillRect(0,0,w,h);  

пусть прямоугольник заполнен
0 0 0 255
независимо от браузера!

Филипп Осеангерманик
источник
1
Context.clearRect(starting width, starting height, ending width, ending height);

Пример: context.clearRect(0, 0, canvas.width, canvas.height);

Гэвин Т
источник
1

кратчайший путь:

canvas.width += 0
Yukulélé
источник
0

самый быстрый способ:

canvas = document.getElementById("canvas");
c = canvas.getContext("2d");

//... some drawing here

i = c.createImageData(canvas.width, canvas.height);
c.putImageData(i, 0, 0); // clear context by putting empty image data
Элзер
источник
12
вау ... в каком браузере? В моем (Chrome 22 и Firefox 14 на OS X) ваш метод, безусловно, самый медленный вариант. jsperf.com/canvas-clear-speed/9
Prestaul
1
> 5 лет в будущем, это все еще самый медленный метод, очень большой, в 700 раз медленнее, чем clearRect.
mgthomas99
0

Если вы используете только clearRect, если у вас есть его в форме для отправки чертежа, вы получите отправку вместо очистки, или, возможно, сначала ее можно очистить, а затем загрузить недействительный чертеж, поэтому вам нужно будет добавить protectDefault в начале функции:

   function clearCanvas(canvas,ctx) {
        event.preventDefault();
        ctx.clearRect(0, 0, canvas.width, canvas.height);
    }


<input type="button" value="Clear Sketchpad" id="clearbutton" onclick="clearCanvas(canvas,ctx);">

Надеюсь, это кому-нибудь поможет.

JoelBonetR
источник
0

Я всегда этим пользуюсь

ctx.clearRect(0, 0, canvas.width, canvas.height)
window.requestAnimationFrame(functionToBeCalled)

НОТА

объединение clearRect и requestAnimationFrame позволяет более плавную анимацию, если это то, что вы собираетесь

Энтони Гедеон
источник
-2

Все это отличные примеры того, как вы очищаете стандартный холст, но если вы используете paperjs, то это будет работать:

Определите глобальную переменную в JavaScript:

var clearCanvas = false;

Из вашего PaperScript определите:

function onFrame(event){
    if(clearCanvas && project.activeLayer.hasChildren()){
        project.activeLayer.removeChildren();
        clearCanvas = false;
    }
}

Теперь, где бы вы ни установили clearCanvas в true, он удалит все элементы с экрана.

Роберт Огл
источник