how remove dots in canvas html?

Viewed 544

Firstly, I tried all the questions & answers related to this topic. Additionally and I tried related questions and try to solve it but no success. So please read my question thoroughly.

Problem: Remove Only Red Dot without a clear canvas.

I want to Remove only Red Dotes not Full Canvas Remove or Reload .

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>

2 Answers

Since you drew the red circle at (x, y) position (100px, 100px) with a diameter of 6px, the area it takes up is:

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

You can clear a section of the canvas with the clearRect method.

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

If your canvas has a background, you will either need to clear the entire canvas and redraw everything except for the red dot, or you could call fillRect… assuming that context.fillStyle is set to the background color.

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

You would somehow have to know where the red dot was painted (and what size it was), prior to painting it.

Edit: See my OOP example following the demo below!


Demo

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 to the rescue!

A better approach would be knowing about the red dot outside the canvas rendering. You could wrap the canvas context inside a class that manages layers and drawables.

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>

As the existing answer has demonstrated the OO adage...

  • "I asked for a banana, but got a gorilla in the jungle holding a banana.",

I have added this answer to demonstrate a more concise JavaScript unique OO approach.

The reason: The battle against complexity.

Complexity is a coders number one enemy, adding unneeded layers of abstraction, duplicating existing behaviours, anticipating undefined needs, all add complexity.

Thought it may not matter if there is only less than 100 lines, for large projects the additional code adds up quickly, and every line is an additional source of bugs.

JavaScript provides a simple and very flexible OO model, with an emphasis on polymorphism via ad hoc object construction and extension. It also has a substantial set of coding shortcuts that go a long way in reducing the number of lines need to implement behaviours

The result is half as much code with almost the same functionality,

Example

  • Uses the Array prototype to implement layers
  • circle Inherits drawable by passing a type to constructor.
  • Removes by color, rather than index or reference

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>

(And I will add that there is nothing wrong with Mr. Polywhirl's code)

Related