2011-09-09 90 views
12

爲了充分利用HTML5畫布,我決定製作一個繪製模擬錶盤的應用程序。一切都很好,除了舊的線條不會以我期望的方式擦除。我已經包含下面的代碼的一部分 - )DrawHands(被調用一次,第二:擦除HTML5畫布上的以前繪製的線

var hoursPoint = new Object(); 
var minutesPoint = new Object(); 
var secondsPoint = new Object(); 

function drawHands() 
{ 
    var now = new Date(); 

    drawLine(centerX, centerY, secondsPoint.X, secondsPoint.Y, "white", 1); 
    var seconds = now.getSeconds(); 
    secondsPoint = getOtherEndOfLine(centerX, centerY, 2 * Math.PI/60 * seconds, 0.75 * radius); 
    drawLine(centerX, centerY, secondsPoint.X, secondsPoint.Y, "black", 1); 

    drawLine(centerX, centerY, minutesPoint.X, minutesPoint.Y, "white", 3); 
    var minutes = now.getMinutes(); 
    minutesPoint = getOtherEndOfLine(centerX, centerY, 2 * Math.PI/60 * minutes, 0.75 * radius); 
    drawLine(centerX, centerY, minutesPoint.X, minutesPoint.Y, "black", 3); 

    drawLine(centerX, centerY, hoursPoint.X, hoursPoint.Y, "white", 3); 
    var hours = now.getHours(); 
    if (hours >= 12) { hours -= 12; } // Hours are 0-11 
    hoursPoint = getOtherEndOfLine(centerX, centerY, (2 * Math.PI/12 * hours) + (2 * Math.PI/12/60 * minutes), 0.6 * radius); 
    drawLine(centerX, centerY, hoursPoint.X, hoursPoint.Y, "black", 3); 
} 

作出上述感,還有兩個輔助功能:

  • 的drawLine(X1,Y1 ,X2,Y2,顏色,厚度)
  • getOtherEndOfLine(X,Y,角度,長度)

的問題是,雖然預期在黑色的所有手中拿得出,他們永遠不會抹去。我認爲,因爲同一條線以白色(背景色)繪製,它將有效地抹去以前繪製的那一點。但似乎並非如此。

我錯過了什麼?

回答

13

由於我可以擴展的原因,你應該考慮清理你的畫布並重新繪製它,除非有性能或合成原因。

你想clearRect,這樣的事情:

//clear the canvas so we can draw a fresh clock 
ctx.clearRect(0, 0, canvasWidth, canvasHeight); 

//redraw your clock here 
/* ... */ 
+3

如果一個人要清除特定行或形狀(像我一樣),而不是清除一個矩形區域,設置'ctx.globalCompositeOperation =「destination-out」' - 正如andrewmu的解決方案中提到的[類似問題](http://stackoverflow.com/questions/3328906/erasing-in-html5-canvas) - 會很漂亮使您的填充/中風操作更像橡皮擦工具。請記住在完成後更改合成模式。查看[Mozilla的合成和裁剪](https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Compositing)瞭解完整的細節。 – TheMadDeveloper

+0

沒有必要總是完全清除畫布。請參閱Simon Sarris的答案,使用getImageData/putImageData,它允許您將繪圖恢復到繪圖的任何先前階段。 – Allasso

+0

糾正上面的評論 - 應該讀mrmcgreg的答案。 – Allasso

4

的原因,你不能只重畫線在白色和希望,以清除舊線是因爲可能有一些抗鋸齒/流血的。您還會注意到,由於這個原因,在像素上繪製的水平直線與半像素看起來非常不同。

當你做你的白色「擦除」線,嘗試用更大的lineWidth大約3或4繪製它們。這應該適用於你的情況。

你也應該畫出所有的白線,然後所有的黑線,以防它們相交。

4

一個快速簡便的方法來清除畫布,設置寬度:

context.canvas.width = context.canvas.width; 
+1

聞起來像依賴於特定的瀏覽器,這是一種簡單的方法在其他瀏覽器不確定的行爲的一些具體的實施。 – BarbaraKwarc

10

相反,你畫了之前的擦除你不想讓你可以在時間保存畫布狀態的東西你不想要的東西,然後將畫布恢復到該狀態以「擦除」它們。

這可以很容易地使用ImageData來完成:

var canvas = document.querySelector('canvas'), 
 
    context = canvas.getContext('2d'); 
 

 
context.fillStyle = 'blue'; 
 
context.fillRect(0,0,10,10); 
 

 
// save the state of the canvas here 
 
var imageData = context.getImageData(0,0,canvas.width,canvas.height); 
 

 
// draw a red rectangle that we'll get rid of in a second 
 
context.strokeStyle = 'red'; 
 
context.strokeRect(70,70,20,20); 
 

 
setTimeout(function() { 
 
    // return the canvas to the state right after we drew the blue rect 
 
    context.putImageData(imageData, 0, 0); 
 
}, 1000);
<canvas width=100 height=100>

+1

該方法具有優於使用clearRectangle中,你可以getImageData在圖中的任何階段,恢復到這個水平,而clearRectangle總會把你帶回一張空白的畫布。出於這個原因我upvoted。 – Allasso

+1

...如果需要恢復,您甚至可以在繪圖過程中的幾個點上拍攝快照。 – Allasso

+0

如果您使用背景圖片,這也可以防止您重新加載圖片。 – Allasso