'Why does my mousefollow method not work on different browsers

Here is a link to the code pen https://codepen.io/shahman28/pen/mdXraRE

This is a part of a larger project that I am working on. I am attempting to place circles when the mouse is clicked. As you can see in the codepen above the mouse follows well and places the circles at the correct locations, but when I try to do it in browser the cursor has an offset from the mouse and the circles are placed incorrectly. In firefox it is completely arbitrary, but in chrome it places them in the location of the cursor(which is in the incorrect location). I am recycling some code from previous projects so that is why there is the border in the html and css.

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

points = [];
class Mouse {
  constructor(c) {
    this.x = 0;
    this.y = 0;
    this.easing = 0.05;

    let rect = canvas.getBoundingClientRect();

    canvas.onmousemove = e => {
      this.x = e.clientX - rect.left;
      this.y = e.clientY - rect.top;
    }
  }

}

class Point {
  constructor(x, y, color) {
    this.x = x;
    this.y = y;
    this.color = color;
  }

  draw() {
    ctx.fillStyle = this.color;
    ctx.beginPath();
    ctx.arc(this.x, this.y, 5, 0, 2 * Math.PI);
    ctx.stroke();
    ctx.fill();
  }
}

function random_hex_color_code() {
  let n = (Math.random() * 0xfffff * 1000000).toString(16);
  return '#' + n.slice(0, 6);
};

canvas.addEventListener('click', function(e) {

  let rect = canvas.getBoundingClientRect();
  x = e.clientX - rect.left
  y = e.clientY - rect.top;
  point = new Point(x, y, '#FF0000');
  points.push(point);
})
w = canvas.width = window.innerWidth,
  h = canvas.height = window.innerHeight,
  mousePosition = new Mouse(canvas);


function animate() {

  ctx.fillStyle = '#4A7DB9';
  ctx.beginPath();
  ctx.arc(mousePosition.x, mousePosition.y, 5, 0, Math.PI * 2);
  ctx.closePath();
  ctx.fill();
}

function handlePoints() {
  for (let i = 0; i < points.length; i++) {
    points[i].draw();
  }
}

function render() {
  ctx.clearRect(0, 0, w, h);
  handlePoints();
  animate();
  window.requestAnimationFrame(render);
}

render();
body {
  background: black;
}

#canvas1 {
  border: 1px solid black;
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 900px;
  height: 600px;
  background: white;
}
<!DOCTYPE html>
<html lang="en">
<!--[if lt IE 7]>      <html class="no-js lt-ie9 lt-ie8 lt-ie7"> <![endif]-->
<!--[if IE 7]>         <html class="no-js lt-ie9 lt-ie8"> <![endif]-->
<!--[if IE 8]>         <html class="no-js lt-ie9"> <![endif]-->
<!--[if gt IE 8]>      <html class="no-js"> <!--<![endif]-->
<html>

<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device.width, initial-scale=1.0">
  <title>Tower Defense</title>
  <link rel="stylesheet" href="style.css">
</head>

<body>
  <button onClick="start()">Start Combat</button>
  <canvas id="canvas1"></canvas>
  <script src="script.js"></script>
</body>

</html>

Does anyone know how to make it so that the the cursor and placed arcs are consistent?



Solution 1:[1]

The problem is that at one point the canvas is set to have fixed px dimensions and at another point it is set to have the dimensions of the viewport.

This snippet removes the settings in the stylesheet and just uses viewport dimensions. It seems to work fine (tested on Windows10 Edge/Chrome and Firefox).

You need to decide which setting you want and to stick with that rather than try to use both which leads to the inconsistency.

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

points = [];
class Mouse {
  constructor(c) {
    this.x = 0;
    this.y = 0;
    this.easing = 0.05;

    let rect = canvas.getBoundingClientRect();

    canvas.onmousemove = e => {
      this.x = e.clientX - rect.left;
      this.y = e.clientY - rect.top;
    }
  }

}

class Point {
  constructor(x, y, color) {
    this.x = x;
    this.y = y;
    this.color = color;
  }

  draw() {
    ctx.fillStyle = this.color;
    ctx.beginPath();
    ctx.arc(this.x, this.y, 5, 0, 2 * Math.PI);
    ctx.stroke();
    ctx.fill();
  }
}

function random_hex_color_code() {
  let n = (Math.random() * 0xfffff * 1000000).toString(16);
  return '#' + n.slice(0, 6);
};

canvas.addEventListener('click', function(e) {

  let rect = canvas.getBoundingClientRect();
  x = e.clientX - rect.left
  y = e.clientY - rect.top;
  point = new Point(x, y, '#FF0000');
  points.push(point);
})
w = canvas.width = window.innerWidth,
  h = canvas.height = window.innerHeight,
  mousePosition = new Mouse(canvas);


function animate() {

  ctx.fillStyle = '#4A7DB9';
  ctx.beginPath();
  ctx.arc(mousePosition.x, mousePosition.y, 5, 0, Math.PI * 2);
  ctx.closePath();
  ctx.fill();
}

function handlePoints() {
  for (let i = 0; i < points.length; i++) {
    points[i].draw();
  }
}

function render() {
  ctx.clearRect(0, 0, w, h);
  handlePoints();
  animate();
  window.requestAnimationFrame(render);
}

render();
body {
  background: black;
}

#canvas1 {
  border: 1px solid black;
  position: absolute;
  left 0;
  top: 0;
  /* removed 
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 900px;
  height: 600px;
  */
  background: white;
}
<meta name="viewport" content="width=device.width, initial-scale=1.0">
<!--<button onClick = "start()">Start Combat</button>-->
<canvas id="canvas1"></canvas>

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 A Haworth