Подтвердить что ты не робот

Стирание ранее нарисованных линий на холсте HTML5

Чтобы поиграть с холстом HTML5, я решил сделать приложение, которое рисует аналоговую синхронизацию. Все отлично, за исключением того, что старые строки не стираются так, как я ожидал. Я включил часть кода ниже - DrawHands() вызывается один раз в секунду:

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, угол, длина)

Проблема в том, что, хотя все руки нарисованы, как ожидалось, в черном, они никогда не стираются. Я ожидал бы, что, поскольку одна и та же линия рисуется белым цветом (фоновым цветом), она эффективно стирает то, что было ранее нарисовано в этой точке. Но, похоже, это не так.

Что-нибудь мне не хватает?

4b9b3361

Ответ 1

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

Вы хотите clearRect, что-то вроде этого:

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

//redraw your clock here
/* ... */

Ответ 2

Вместо того, чтобы стирать ненужные вещи, вы можете:

  1. сохранить состояние холста
  2. рисовать вещи, которые вы не хотите
  3. восстановить холст в сохраненное состояние, чтобы "стереть" их

Это можно сделать довольно легко с помощью ImageData:

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

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

// 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.fillStyle = 'red';
context.fillRect(50,50,100,100);

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

Ответ 3

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

Когда вы делаете белые линии "стирания", попробуйте рисовать их с большим lineWidth примерно на 3 или 4. Это должно работать для вашего дела.

Вы также должны нарисовать все белые линии сначала, а затем все черные линии, если они пересекаются.

Ответ 4

Быстрый и простой способ очистки холста - установить ширину:

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

Ответ 5

Мое решение - двойная буферизация:

var shapes = 
  [{type:"circle", x:50, y:50, radious:40, lineWidth:2, strokeStyle:"#FF0000", fillStyle:"#800000"}
  ,{type:"rectangle", x:50, y:50, width:100, height: 100, lineWidth:2, strokeStyle:"#00FF00", fillStyle:"#008000"}
  ,{type:"line", x1:75, y1:100, x2:170, y2:75, lineWidth:3, strokeStyle:"#0000FF"}
  ];

step1();
setTimeout(function () {
  step2();
  setTimeout(function () {
    step3();
  }, 1000);
}, 1000);

function step1() {
  clearCanvas('myCanvas1');
  shapes.forEach((sh) => { drawShape('myCanvas1', sh); });
};

function step2() {
  clearCanvas('myCanvas2');
  shapes.pop();
  shapes.forEach((sh) => { drawShape('myCanvas2', sh); });
  showOtherCanvas('myCanvas2', 'myCanvas1');
};

function step3() {
  clearCanvas('myCanvas1');
  shapes.pop();
  shapes.forEach((sh) => { drawShape('myCanvas1', sh); });
  showOtherCanvas('myCanvas1', 'myCanvas2');
};

function showOtherCanvas(cnv1, cnv2) {
  var c1 = document.getElementById(cnv1);
  var c2 = document.getElementById(cnv2);
  
  c1.style['z-index'] = 3;
  c2.style['z-index'] = 1;
  c1.style['z-index'] = 2;
}

function clearCanvas(canvasID) {
  var canvas = document.getElementById(canvasID);
  var ctx = canvas.getContext('2d');
  
  ctx.fillStyle="#FFFFFF";
  ctx.fillRect(0,0,480,320);
} 

function drawShape (canvasID, info) {
  switch (info.type) {
    case "line"      : drawLine(canvasID, info);
    case "rectangle" : drawRectangle(canvasID, info);
    case "circle"    : drawCircle(canvasID, info);
  }
}

function drawLine (canvasID, info) {
  var canvas = document.getElementById(canvasID);
  var ctx = canvas.getContext('2d');
  
  ctx.strokeStyle = info.strokeStyle;
  ctx.lineWidth = info.lineWidth

  ctx.beginPath();
  ctx.moveTo(info.x1, info.y1);
  ctx.lineTo(info.x2, info.y2);
  ctx.stroke();
}

function drawRectangle (canvasID, info) {
  var canvas = document.getElementById(canvasID);
  var ctx = canvas.getContext('2d');
  
  ctx.fillStyle = info.fillStyle;
  ctx.strokeStyle = info.strokeStyle;
  ctx.lineWidth = info.lineWidth

  ctx.fillRect(info.x, info.y, info.width, info.height);
  ctx.strokeRect(info.x, info.y, info.width, info.height);
}

function drawCircle (canvasID, info) {
  var canvas = document.getElementById(canvasID);
  var ctx = canvas.getContext('2d');
  
  ctx.fillStyle = info.fillStyle;
  ctx.strokeStyle = info.strokeStyle;
  ctx.lineWidth = info.lineWidth

  ctx.beginPath();
  ctx.arc(info.x, info.y, info.radious, 0, 2 * Math.PI);
  ctx.fill();

  ctx.beginPath();
  ctx.arc(info.x, info.y, info.radious, 0, 2 * Math.PI);
  ctx.stroke();
}
<canvas id="myCanvas2" width="480" height="320"
	style="border: 1px solid #000000; position: absolute; top: 10; left: 10; z-index:1">
</canvas>
<canvas id="myCanvas1" width="480" height="320"
	style="border: 1px solid #000000; position: absolute; top: 10; left: 10; z-index:2">
</canvas>