Search code examples
javascriptcanvashtml5-canvas

Click on an object using canvas and javascript


I created a canvas with a circle inside it and I'm trying to detect the mouse click.

I am calculating the distance between the mouse click and the radius of the circle. The output should be 0 when the click is next to the center of the circle however I'm getting more than 400!

Here is the code that I have tried. I couldn't understand what I'm doing wrong!?

let canvas = document.querySelector('canvas');
let ctx = canvas.getContext('2d');
let mousePos = {
  x: undefined,
  y: undefined
};

function Circle(x, y, r) {
  this.x = x;
  this.y = y;
  this.r = r;

  this.draw = function() {
    ctx.beginPath();
    ctx.arc(this.x, this.y, this.r, 0, Math.PI * 2, false);
    ctx.stroke();
    ctx.fill();
    ctx.closePath();
  };

  this.clickCircle = function(xmouse, ymouse) {
    let distance = Math.sqrt(
      (xmouse - this.x) * (xmouse - this.x) +
      (ymouse - this.y) * (ymouse - this.y)
    );
    console.log(distance);
  };
}

let myCircle = new Circle(100, 100, 20);
myCircle.draw();

canvas.addEventListener('click', e => {
  const rect = canvas.getBoundingClientRect();
  mousePos.x = e.clientX - rect.left;
  mousePos.y = e.clientY - rect.top;

  myCircle.clickCircle(mousePos.x, mousePos.y);
});
canvas {
  border: 1px solid black;
  background-color: wheat;
  width: 100%;
}
<div class="container">
  <canvas id="app"></canvas>
</div>


Solution

  • In general, your code is correct except one detail. Unfortunately, canvas doesn't work with relative sizes (such as %). Actually he does, but that is a style which is applied to the result picture not the canvas itself.

    So the only thing you need to change is to remove width: 100%; from the CSS code for canvas element and at the same time set the concrete values for canvas width and height via html attributes or by javascript code.

    For example:

    let canvas = document.querySelector('canvas');
    canvas.width = 500;
    canvas.height = 300;
    ...
    

    let canvas = document.querySelector('canvas');
    // add size. btw, you may calculate those based on the parent element or window
    // or just use the values you like
    canvas.width = 500;
    canvas.height = 300;
    
    let ctx = canvas.getContext('2d');
    let mousePos = {
      x: undefined,
      y: undefined
    };
    
    function Circle(x, y, r) {
      this.x = x;
      this.y = y;
      this.r = r;
    
      this.draw = function() {
        ctx.beginPath();
        ctx.arc(this.x, this.y, this.r, 0, Math.PI * 2, false);
        ctx.stroke();
        ctx.fill();
        ctx.closePath();
      };
    
      this.clickCircle = function(xmouse, ymouse) {
        let distance = Math.sqrt(
          (xmouse - this.x) * (xmouse - this.x) +
          (ymouse - this.y) * (ymouse - this.y)
        );
        console.log(distance);
      };
    }
    
    let myCircle = new Circle(100, 100, 20);
    myCircle.draw();
    
    canvas.addEventListener('click', e => {
      const rect = canvas.getBoundingClientRect();
      mousePos.x = e.clientX - rect.left;
      mousePos.y = e.clientY - rect.top;
    
      myCircle.clickCircle(mousePos.x, mousePos.y);
    });
    canvas {
      border: 1px solid black;
      background-color: wheat;
      /* width: 100%; REMOVED THIS */
    }
    <div class="container">
      <canvas id="app"></canvas>
    </div>