Search code examples
javascripthtmlcsscanvasline

Line drawn below the center of the Mouse in JavaScript


I am working on a simple drawing tool using JavaScript. However I have a problem with my draw() function. The line is always drawn slightly below the center of the mouse. May I please know what is my mistake here? I want the line to always be drawn at the center of the mouse as it moves. In my setPosition() function, does e.pageX and e.pageY actually maps the center of the mouse as x and y coordinates?

<!doctype html>
<html>

<head>
  <style>
    canvas {
      border: 1px solid black;
    }
  </style>
</head>

<body>
  <div class="controls">
    <button class="clear">Clear</button> <span>Color
            <input type="color" value="#ffff00" id="penColor"></span>
    <span>Width
            <input type="range" min="1" max="20" value="10" id="penWidth"></span>
  </div>

  <canvas id="canvas"></canvas>
  <script>
    let penColor = document.getElementById("penColor");
    let penWidth = document.getElementById("penWidth");
    let canvas = document.getElementById("canvas");
    canvas.width = 700;
    canvas.height = 700;

    let context = canvas.getContext("2d");
    let clearButton = document.querySelector(".clear");

    let position = {
      x: null,
      y: null
    }

    let initialization = (e) => {
      canvas.addEventListener("mousemove", draw);
      canvas.addEventListener("mouseenter", setPosition)
      canvas.addEventListener("mousemove", setPosition)
    }

    window.onload = initialization;

    let setPosition = (e) => {
      position.x = e.pageX;
      position.y = e.pageY;
    }

    clearButton.addEventListener("click", (e) => {
      let confirmation = confirm("Are you sure you want to clear the canvas?");

      let result = confirmation ? true : false;
      if (result) {
        context.clearRect(0, 0, canvas.width, canvas.height);
      }
    })


    let draw = (e) => {
      if (e.buttons !== 1) return;
      context.beginPath();
      context.moveTo(position.x, position.y);

      setPosition(e);

      context.lineTo(position.x, position.y);
      context.lineWidth = penWidth.value;
      context.strokeStyle = penColor.value;
      context.lineCap = "round";
      context.stroke();
    }
  </script>
</body>

</html>


Solution

  • MouseEvent.pageX

    The pageX read-only property of the MouseEvent interface returns the X (horizontal) coordinate (in pixels) at which the mouse was clicked, relative to the left edge of the entire document.

    https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/pageX

    so that is not the X position on the canvas, you have to substract the canvas position.

    e.pageX - canvas.offsetLeft;
    e.pageY - canvas.offsetTop;
    

    let canvas = document.getElementById("canvas");
    canvas.width = canvas.height = 200;
    
    let context = canvas.getContext("2d");
    let position = { x: null, y: null }
    
    let setPosition = (e) => {
      position.x = e.pageX - canvas.offsetLeft;
      position.y = e.pageY - canvas.offsetTop;
    }
    
    let draw = (e) => {
      if (e.buttons !== 1) return;
      context.beginPath();
      context.moveTo(position.x, position.y);
    
      setPosition(e);
      context.lineTo(position.x, position.y);
      context.stroke();
    }
    
    canvas.addEventListener("mousemove", draw);
    canvas.addEventListener("mouseenter", setPosition)
    canvas.addEventListener("mousemove", setPosition)
    canvas {
      border: 1px solid black;
    }
    <canvas id="canvas"></canvas>