다시 그리기 위해 캔버스를 지우는 방법


1012

합성 작업을 실험하고 캔버스에 이미지를 그린 후 이미지를 제거하고 합성하려고합니다. 어떻게해야합니까?

다른 이미지를 다시 그리려면 캔버스를 지워야합니다. 이것은 한동안 계속 될 수 있으므로 매번 새로운 사각형을 그리는 것이 가장 효율적인 옵션이라고 생각하지 않습니다.

답변:


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

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

42
에 대한주의 clearRect는 필요 어느 쪽 변형되지 않은 상황을, 또는 실제의 경계를 추적.
Phrogz

7
캔버스 너비를 설정하면 a) 다른 값으로 설정 한 다음 다시 웹킷 호환성을 위해 다시 설정해야 하며 b) 컨텍스트 변환재설정 됩니다 .
Phrogz

45
폭 트릭을 사용하지 마십시오. 더러운 해킹입니다. JavaScript와 같은 고급 언어에서 원하는 것은 의도를 가장 잘 표현한 다음 하위 수준의 코드가이를 달성하도록하는 것입니다. 너비를 자체로 설정해도 캔버스를 지우는 진정한 의도 는 아닙니다 .
andrewrk

22
완전히 사소한 제안이지만 제안 context.clearRect(0, 0, context.canvas.width, context.canvas.height)합니다. 그것은 사실상 같은 것이지만 하나의 의존성이 적습니다 (2 대신 1 변수)
gman

6
이 답변의 최근 독자 : 이 답변이 수정되었으며 위의 설명 중 일부가 더 이상 적용되지 않는다는 점에 유의하십시오 .
daveslab

719

사용하다: context.clearRect(0, 0, canvas.width, canvas.height);

전체 캔버스를 지우는 가장 빠르고 설명적인 방법입니다.

사용하지 마세요: canvas.width = canvas.width;

재설정 canvas.width하면 모든 캔버스 상태 (예 : 변환, 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에서는) 변환을 재설정하지 않고 300x150 (기본 크기) 캔버스를 지우는 것이 약 10 % 빠릅니다. 캔버스 크기가 커질수록이 차이는 줄어 듭니다.

그것은 이미 상대적으로 중요하지 않지만 대부분의 경우 당신이 지우는 것보다 훨씬 더 많은 그림을 그릴 것입니다.이 성능 차이는 관련이 없다고 생각합니다.

100000 iterations averaged 10 times:
1885ms to clear
2112ms to reset and clear

4
@YumYumYum : clear ()가 표준 함수입니까? 아닌 것 같습니다.
nobar

7
대신 canvas사용하여 지역 변수 의 필요성을 제거 할 수 있습니다 ctx.canvas.
Drew Noakes

1
@DrewNoakes, 좋은 지적이지만, 거의 항상 속도 목적을 위해 별도의 변수를 선택합니다. 극도로 작지만 자주 사용하는 속성 (특히 애니메이션 루프 내부)의 별칭을 지정하여 역 참조 시간을 피하려고합니다.
Prestaul


변환 행렬 수정의 경우에 전체 캔버스를 취소하는 또 다른 방법은 단순히 변환을 추적하고 그들에게 자신을 적용하는 것입니다 canvas.widthcanvas.height청소 때. 변환 재설정과 비교하여 런타임 차이에 대한 수치 분석을 수행하지 않았지만 약간 더 나은 성능을 낼 것으로 생각됩니다.
NanoWizard

226

선을 그리는 경우 다음을 잊지 마십시오.

context.beginPath();

그렇지 않으면 줄이 지워지지 않습니다.


10
나는 이것이 한동안 여기에 있었음을 알고 있으며,이 모든 시간 후에 주석을 달리는 것은 아마도 어리석은 일이지만, 이것은 1 년 동안 나를 괴롭 혔습니다 ... 당신이 새로운 길을 시작할 때 전화beginPath 하십시오. 기존 경로를 지우려는 캔버스를 지우고 있습니다! 이것은 끔찍한 관행이며 그림을 거꾸로 보는 방법입니다.
Prestaul

캔버스의 모든 것을 지우려면 어떻게해야합니까? 게임을 만들고 있으며 수백 분의 1 초마다 화면을 다시 그려야한다고 가정 해 보겠습니다.

1
@JoseQuinones beginPath는 캔버스에서 아무것도 지우지 않고 경로를 재설정하여 이전 경로 항목을 그리기 전에 제거합니다. 아마도 필요할 수도 있지만 그리기 작업으로, 지우기 작업이 아닙니다. clear, beginPath 및 draw, clear 및 beginPath, draw하지 마십시오. 차이가 의미가 있습니까? 예를 보려면 여기를보십시오 : w3schools.com/tags/canvas_beginpath.asp
Prestaul

1
이것은 시간이 지남에 따라 경험 한 애니메이션의 속도 저하를 해결했습니다. 모든 단계에서 그리드 선을 다시 그렸지만 이전 단계에서 선을 지우지 않았습니다.
Georg Patscheider

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

6
이것은 훌륭한 구현입니다. 네이티브 프로토 타입 향상을 완벽하게 지원하지만, 할당하기 전에 "클리어"가 정의되지 않았는지 확인하고 싶을 수도 있습니다. 언젠가 네이티브 구현을 기대하고 있습니다. :) 브라우저가 CanvasRenderingContext2D를 얼마나 광범위하게 지원하고 "쓰기 가능"상태로 두는지 알고 있습니까?
Prestaul

피드백 @Prestaul에 감사드립니다-또한 브라우저 가이 방식으로 자바 스크립트 객체를 확장하지 못하게해서는 안됩니다.
JonathanK

@JonathanK, 나는 변환을 재설정하지 않고 지우는 것 사이의 성능 차이에 대한 프로파일 링을보고 싶습니다. 나는 당신이 작은 그림을하고 있다면 차이가 분명 할 것이라고 생각하지만 당신이 그리는 것이 사소한 것이 아니라면 명확한 단계는 무시할 수 있습니다 ... 나중에 더 많은 시간이있을 때 테스트해야 할 수도 있습니다 :)
Prestaul

좋아, 나는 프로파일 링을했고 내 게시물에 세부 사항을 추가 할 것입니다.
Prestaul

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를 사용하는 것이 가장 빠르며 캔버스를 구현하는 모든 브라우저에서 작동해야합니다.
Prestaul

1
나는 IE가 여전히 경로 버퍼에 있기 때문에 라인을 다시 그리는 것으로 생각합니다. 나는이 형식을 사용하고 완벽하게 작동합니다. function clearCanvas(ctx) { ctx.beginPath(); ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height); }
DarrenMB

나는이 전에 각각의 모든 방법을 시도했지만 ...이 유일한 방법이었습니다. 선, 사각형 및 텍스트와 함께 Chrome을 사용하고 있습니다 ... 내장해야 할 일을 너무 어렵게 생각하지 않았을 것입니다! 감사!
Anthony Griggs

26

이것은 2018이지만 여전히 다시 그리기 위해 캔버스를 완전히 지우는 기본 방법은 없습니다. 캔버스를 완전히 지우지 clearRect() 않습니다 . 비 채우기 형식의 도면은 밖으로 삭제되지 않습니다 (예. rect())

1. 그리는 방법에 관계없이 캔버스를 완전히 지우려면 :

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

장점 : strokeStyle, fillStyle 등을 유지합니다. 지연이 없습니다.

단점 : 무언가를 그리기 전에 이미 beginPath를 사용하는 경우 불필요

2. 너비 / 높이 핵 사용 :

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

또는

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

장점 : IE와 함께 작동 단점 : strokeStyle, fillStyle을 검은 색으로 재설정합니다. 게으른;

네이티브 솔루션이 존재하지 않는 이유가 궁금합니다. 실제로 clearRect()대부분의 사용자는 beginPath()새로운 경로를 그리기 전에 수행 하기 때문에 단일 회선 솔루션으로 간주됩니다 . beginPath는 선을 그릴 때만 사용되며 닫힌 경로는 아닙니다.rect().

이것이 받아 들여진 대답이 내 문제를 해결하지 못한 이유이며 다른 해킹을 시도하는 데 몇 시간을 낭비했습니다. 모질라 저주


나는 이것이 캔버스 그리기에 대한 정답이라고 생각합니다. beginPath가 도움이되는 동안 clearRect를 호출하는 방법에 관계없이 context.stroke가 남아 있습니다.
Shao-Kui

20

x, y 좌표와 캔버스의 높이와 너비를 전달하여 clearRect 메소드를 사용하십시오. ClearRect는 전체 캔버스를 다음과 같이 지 웁니다.

canvas = document.getElementById("canvas");
ctx = canvas.getContext("2d");
ctx.clearRect(0, 0, canvas.width, canvas.height);

이것을 메소드에 넣고 화면을 새로 고칠 때마다 호출하면됩니다.

에 @ XXX.xxx PLZ 캔버스의 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 개의 물체가 있고 그중 하나만 트레일하고 싶다면 어떻게 할 것입니까?
super

그것은 훨씬 더 복잡한 거래입니다. 이 경우 오프 스크린 캔버스를 작성해야하며 각 프레임은 여기에 설명 된 부분 지우기 방법을 사용하여 해당 캔버스에 추적 할 오브젝트를 그리고 각 프레임은 기본 캔버스를 100 % 지우고 비트 레일 드를 그립니다. 그런 다음 drawImage ()를 사용하여 오프 스크린 캔버스를 기본 캔버스에 합성합니다. 또한 globalCompositeOperation을 이미지에 적합한 것으로 설정해야합니다. 예를 들어 "곱하기"는 밝은 배경의 어두운 물체에 적합합니다.
오리온 엘렌 질

12

빠른 방법은

canvas.width = canvas.width

작동 방식은 Idk이지만 작동합니다!


와. 이것은 실제로 작동합니다. 어떻게 이것을 찾았습니까?
zipzit

@zipit 일반적인 비운 후에도 medium.com에서 찾은 빠른 트릭은 렌더링되지 않았습니다 :)
Jacob Morris

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. 그런 다음 이전 컨텍스트 상태를 복원합니다.


그것은 나를 위해 작동합니다 ...! 감사.
NomanJaved

6

이것은 chart.js의 pieChart에서 작동했습니다.

<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

테스트 한 모든 브라우저에서 가장 빠른 방법은 실제로 흰색 또는 원하는 색상으로 채우는 것입니다. 나는 매우 큰 모니터를 가지고 있으며 전체 화면 모드에서 clearRect는 느리게 느리지 만 fillRect는 합리적입니다.

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

단점은 캔버스가 더 이상 투명하지 않다는 것입니다.


4

웹킷에서 너비를 다른 값으로 설정 한 다음 다시 초기 값으로 설정할 수 있습니다


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

이것이 가장 쉬운 방법입니다! 글쎄, 적어도 나를 위해.
Jacques Olivier

1
context.clearRect(0,0,w,h)   

주어진 사각형을 RGBA 값으로 채 웁니다 : 000
0 : Chrome으로
0 255 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);



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
와우 ... 어떤 브라우저에서? 내 경우 (OS X의 Chrome 22 및 Firefox 14) 귀하의 방법은 훨씬 느린 옵션입니다. jsperf.com/canvas-clear-speed/9
Prestaul

1
> 5 년이 지난 후에도이 방법은 ~ 700 배 더 느린 매우 큰 방법으로 여전히 가장 느린 방법 clearRect입니다.
mgthomas99

0

clearRect 만 사용하는 경우 도면을 제출하기위한 양식이있는 경우 지우기 대신 제출을 받거나 먼저 지운 후 빈 도면을 업로드 할 수 있으므로 추가해야합니다. 함수 시작시 preventDefault :

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

그것이 누군가를 돕기를 바랍니다.


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로 설정하면 화면에서 모든 항목이 지워집니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.