¿Cómo eliminar puntos en lienzo html?
En primer lugar, probé todas las preguntas y respuestas relacionadas con este tema. Además, probé preguntas relacionadas e intenté resolverlo pero no tuve éxito. Entonces, lea mi pregunta detenidamente.
Problema: elimine solo el punto rojo sin un lienzo transparente.
Quiero quitar solo los puntos rojos, no quitar o recargar el lienzo completo.
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>
Respuestas
Dado que dibujó el círculo rojo al ( x, y) posición ( 100px, 100px) con un diámetro de 6px, el área que ocupa es:
x : 100 - (6 / 2)
y : 100 - (6 / 2)
width : 6
height : 6
Puede borrar una sección del lienzo con el clearRectmétodo.
context.clearRect(97, 97, 6, 6);
Si su lienzo tiene un fondo, deberá borrar todo el lienzo y volver a dibujar todo excepto el punto rojo, o puede llamar fillRect... asumiendo que context.fillStyleestá configurado en el color de fondo.
context.fillRect(97, 97, 6, 6);
De alguna manera, tendría que saber dónde se pintó el punto rojo (y qué tamaño tenía), antes de pintarlo.
Editar: ¡ Vea mi ejemplo de OOP siguiendo la demostración a continuación!
Manifestación
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>
¡OOP al rescate!
Un mejor enfoque sería conocer el punto rojo fuera de la representación del lienzo. Puede envolver el contexto del lienzo dentro de una clase que administra capas y elementos de diseño.
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>
Como la respuesta existente ha demostrado el adagio OO ...
- "Pedí un plátano, pero encontré un gorila en la jungla sosteniendo un plátano". ,
He agregado esta respuesta para demostrar un enfoque OO único de JavaScript más conciso.
El motivo: la batalla contra la complejidad.
La complejidad es el enemigo número uno de los codificadores, agregando capas innecesarias de abstracción, duplicando comportamientos existentes, anticipando necesidades indefinidas, todo agrega complejidad.
Aunque puede que no importe si solo hay menos de 100 líneas, para proyectos grandes el código adicional se suma rápidamente y cada línea es una fuente adicional de errores.
JavaScript proporciona un modelo OO simple y muy flexible, con énfasis en el polimorfismo mediante la construcción y extensión de objetos ad hoc. También tiene un conjunto sustancial de atajos de codificación que contribuyen en gran medida a reducir la cantidad de líneas necesarias para implementar comportamientos.
El resultado es la mitad de código con casi la misma funcionalidad,
Ejemplo
- Utiliza el
Arrayprototipo para implementar capas circleSe heredadrawablepasando un tipo al constructor.- Elimina por
color, en lugar de índice o referencia
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>
(Y agregaré que no hay nada de malo en el código del Sr. Polywhirl )