как удалить точки в холсте html?

Sep 11 2020

Во-первых, я перепробовал все вопросы и ответы по этой теме. Кроме того, я попробовал связанные вопросы и попытался решить их, но безуспешно. Поэтому внимательно прочтите мой вопрос.

Проблема: удалите только красную точку без прозрачного холста.

Я хочу удалить только красные точки, а не полностью удалить или перезагрузить холст.

const canvas = document.getElementById('canvas');
const context = canvas.getContext('2d');
    
context.beginPath();
context.arc(100, 100, 3, 0, Math.PI * 2, true); // Outer circle
context.lineWidth = 0;
context.fillStyle = "red";
context.fill();

context.beginPath();
context.arc(36, 100, 3, 0, Math.PI * 2, true); // Outer circle
context.lineWidth = 0;
context.fillStyle = "Orange";
context.fill();

context.beginPath();
context.arc(123, 100, 3, 0, Math.PI * 2, true); // Outer circle
context.lineWidth = 0;
context.fillStyle = "Green";
context.fill();

function removeRedDot(){
 // remove code
 alert('Remove Red Dot');
}
#canvas{
border:1px solid black;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<h4>Approach the circle with the mouse</h4> <button onclick="removeRedDot()"> Red Remove Dot</button>
<canvas id="canvas" width=300 height=200></canvas>

Ответы

3 Mr.Polywhirl Sep 11 2020 at 18:37

Так как вы нарисовали красный круг в точке ( x, y) положения ( 100px, 100px) с диаметром 6px, площадь он занимает это:

x      : 100 - (6 / 2)
y      : 100 - (6 / 2)
width  : 6
height : 6

Вы можете очистить часть холста с помощью clearRectметода.

context.clearRect(97, 97, 6, 6);

Если у вашего холста есть фон, вам нужно будет либо очистить весь холст и перерисовать все, кроме красной точки, либо вы можете вызвать fillRect… при условии, что для context.fillStyleнего установлен цвет фона.

context.fillRect(97, 97, 6, 6);

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

Изменить: см. Мой пример ООП после демонстрации ниже!


Демо

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

context.beginPath();
context.arc(100, 100, 3, 0, Math.PI * 2, true); // Outer circle
context.lineWidth = 0;
context.fillStyle = "red";
context.fill();

context.beginPath();
context.arc(36, 100, 3, 0, Math.PI * 2, true); // Outer circle
context.lineWidth = 0;
context.fillStyle = "Orange";
context.fill();

context.beginPath();
context.arc(123, 100, 3, 0, Math.PI * 2, true); // Outer circle
context.lineWidth = 0;
context.fillStyle = "Green";
context.fill();

function removeRedDot() {
  context.clearRect(97, 97, 6, 6);
  alert('Removed Red Dot');
}
#canvas {
  border: 1px solid black;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<h4>Approach the circle with the mouse</h4> <button onclick="removeRedDot()"> Red Remove Dot</button>
<canvas id="canvas" width=300 height=200></canvas>


ООП на помощь!

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

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

const main = () => {
  const canvas = new Canvas(ctx);
  const layer = canvas.addLayer();
  const circles = [
    new Circle({ x: 50, y: 50 }, 3, 'red'),
    new Circle({ x: 100, y: 100 }, 6, 'green'),
    new Circle({ x: 150, y: 150 }, 12, 'blue')
  ];
  layer.add(...circles);
  canvas.render();
  
  // After 2 second, remove the red dot and re-render.
  setTimeout(() => {
    alert('Removing "red" circle, and adding a "cyan" circle...');
    layer.remove(circles[0]);
    layer.add(new Circle({ x: 150, y: 50 }, 8, 'cyan'));
    canvas.render();
  }, 2000);
};

class Drawable {
  constructor(origin) {
    this.origin = origin;
  }
  draw(ctx) { }
}

class Layer {
  constructor(name) {
    this.name = name;
    this.drawables = [];
  }
  add(...drawables) {
    drawables.forEach(drawable => this.drawables.push(drawable));
  }
  remove(drawableOrIndex) {
    if (isNaN(drawableOrIndex)) {
      drawableOrIndex = this.drawables.indexOf(drawableOrIndex);
    }
    if (drawableOrIndex > -1) {
      this.drawables.splice(drawableOrIndex, 1);
    }
  }
  render(ctx) {
    this.drawables.forEach(drawable => drawable.render(ctx));
  }
}

class Canvas {
  constructor(ctx) {
    this.ctx = ctx;
    this.layers = [];
  }
  addLayer(name) {
    const newLayer = new Layer(name || 'layer-' + this.layers.length);
    this.layers.push(newLayer);
    return newLayer;
  }
  getLayer(nameOrIndex) {
    return isNaN(nameOrIndex)
      ? this.layers.find(layer => layer.name === nameOrIndex)
      : this.layers[nameOrIndex];
  }
  render() {
    const { width, height } = this.ctx.canvas;
    this.ctx.clearRect(0, 0, width, height);
    this.layers.forEach(layer => layer.render(this.ctx));
  }
}

class Circle extends Drawable {
  constructor(origin, radius, color) {
    super(origin);
    this.radius = radius;
    this.color = color;
  }
  render(ctx) {
    const { x, y } = this.origin;
    const diameter = this.radius * 2;
    ctx.save();
    ctx.beginPath();
    ctx.arc(x, y, this.radius, 0, Math.PI * 2, true);
    ctx.lineWidth = 0;
    ctx.fillStyle = this.color;
    ctx.fill();
    ctx.restore();
  }
}

main();
#canvas {
  border: 1px solid black;
}
<canvas id="canvas" width=300 height=200></canvas>

Blindman67 Sep 11 2020 at 22:13

Как показал существующий ответ, пословица OO ...

  • «Я попросил банан, но нашел в джунглях гориллу, держащую банан». ,

Я добавил этот ответ, чтобы продемонстрировать более сжатый уникальный объектно-ориентированный подход JavaScript.

Причина: борьба со сложностью.

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

Думал, что это может не иметь значения, если имеется менее 100 строк, для больших проектов дополнительный код складывается быстро, и каждая строка является дополнительным источником ошибок.

JavaScript предоставляет простую и очень гибкую объектно-ориентированную модель с упором на полиморфизм через создание и расширение специальных объектов. Он также имеет значительный набор ярлыков кодирования, которые имеют большое значение для уменьшения количества строк, необходимых для реализации поведения.

Результат - вдвое меньше кода с почти такой же функциональностью,

пример

  • Использует Arrayпрототип для реализации слоев
  • circleНаследует drawable, передавая тип конструктору.
  • Удаляет по color, а не по индексу или ссылке

const ctx = canvas.getContext("2d");
const P2 = (x = 0, y = 0) => ({x,y});
const Drawable = (pos, color, size = 10, type = Circle) => ({pos, size, color, ...type});
const Circle = {
    draw(ctx) {
        ctx.fillStyle = this.color;
        ctx.beginPath();
        ctx.arc(this.pos.x, this.pos.y, this.size, 0, Math.PI * 2);
        ctx.fill();
    }
};
const drawables = Object.assign([], {
       draw(ctx) { for (const d of this) { d.draw(ctx) } },
       remove(color) {
           const idx = this.findIndex(d => d.color === color);
           return (idx > -1 && (this.splice(idx, 1)[0])) || undefined;
       },
    }
);
drawables.push(...[...document.querySelectorAll("#buttons button")].map((but, idx)=>
    Drawable(P2(100 + idx * 100, 50), but.dataset.color)
));
drawables.draw(ctx);   
buttons.addEventListener("click", e => {
    if (drawables.remove(e.target.dataset.color)) {
       ctx.clearRect(0,0,ctx.canvas.width,ctx.canvas.height);
       drawables.draw(ctx);
    }
});
<canvas id="canvas" width="400" height="100"></canvas>
<div id="buttons">
    <button data-color="red">Remove Red</button>
    <button data-color="green">Remove Green</button>
    <button data-color="blue">Remove Blue</button>
</div>

(И я добавлю, что в коде мистера Поливерла нет ничего плохого )