Home  >  Q&A  >  body text

Why is my drawing canvas offset within the page?

It's hard to explain. But I'll try, the whole canvas is offset. I'm not sure how this happened or how to fix it. Like when your mouse is in the top left corner of the page and you start from the center, it matches the top left corner of the canvas element itself. Use code snippets to understand what I'm talking about.

let currentColor = null;

let inputs = document.getElementsByClassName("style2");

for (const input of inputs) {
  input.addEventListener("click", (e) => {
    if (e.detail !== 2) e.preventDefault();
  });
}


let arr = [];

for (let i = 0; i < inputs.length + 1; i++) {
  arr.push(i.toString());
}
arr.shift();

for (const input of inputs) {
  input.addEventListener("input", (e) => {
    const { value } = document.getElementById(e.target.id);
    currentColor = value;
    $("#selectedColor").css("background-color", value);
  })
    input.addEventListener("click", (e) => {
    const { value }  = document.getElementById(e.target.id);
    currentColor = value;
    $("#selectedColor").css("background-color", value);
  })
}

var rangeslider = document.getElementById("sliderRange");
const setSize = document.getElementById("setSize")
const submit = document.getElementById("submit")

submit.addEventListener("click", (e) => {
  rangeslider.value = setSize.value 
})

const button = document.getElementById("clear")
// create canvas element and append it to document body
var canvas = document.getElementById('canvas');
// some hotfixes... ( ≖_≖)
// get canvas 2D context and set him correct size
var ctx = canvas.getContext('2d');
resize();

// last known position
var pos = { x: 0, y: 0 };

window.addEventListener('resize', resize);
button.addEventListener('click', clear)
document.addEventListener('mousemove', draw);
document.addEventListener('mousedown', setPosition);
document.addEventListener('mousemove', setPosition);


// new position from mouse event
function setPosition(e) {
  let canvas = document.getElementById("canvas")
  pos.x = e.clientX
  pos.y = e.clientY
}

// resize canvas
function resize() {
  ctx.canvas.width = 650;
  ctx.canvas.height = 375;
}

function draw(e) {
  // mouse left button must be pressed
  if (e.buttons !== 1) return;
  let canvas = document.getElementById('canvas');

  console.log(pos)
  ctx.beginPath(); // begin

  ctx.lineWidth = rangeslider.value;
  ctx.lineCap = 'round';
  ctx.strokeStyle = currentColor;

  ctx.moveTo(pos.x, pos.y); // from
  setPosition(e);
  ctx.lineTo(pos.x, pos.y); // to

  ctx.stroke(); // draw it!
}

function clear() {
  ctx.clearRect(0, 0, canvas.width, canvas.height);
}
html, body {
  height: 100%;
  width: 100%;
  font-family: sans-serif;
  background-color: #B3B7B5;
/*   overflow: hidden; */
}

.style2 {
  -webkit-appearance: none;
  -moz-appearance: none;
  appearance: none;
  background-color: transparent;
  width: 35px;
  height: 35px;
  border: none;
  cursor: pointer;
}


.style2::-webkit-color-swatch {
  border-radius: 50%;
  border: 3px solid #000000;
}
.style2::-moz-color-swatch {
  border-radius: 50%;
  border: 3px solid #000000;
}

.box {
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
  gap: 5px;
  max-width: 320px;
  margin: 0 auto;
  padding: 7.5px 10px;
}

.box1 {
    display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
  gap: 5px;
  max-width: 9999px;
  margin: 0 auto;
  padding: 10px 10px;
}

.box5 {
    display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
  gap: 5px;
  max-width: 650px;
  margin: 0 auto;
  padding: 10px 10px;
}

.box2 {
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
  gap: 5px;
  max-width: 9999px;
  margin: 0 auto;
  padding: 10px 10px;
}

#selectedColor {
  width: 100px;
  height: 30px;
  border: 3px solid black;
  border-radius: 5px;
  background-color: black;
}

.canvas {
  height: 350px;
  width: 650px;
  border: 3px solid black;
  border-radius: 5px;
  background-color: white;
  cursor: crosshair;
  position: relative;
/*   left: 50%; */
}

#clear {
  width: 50px;
  height: 35px;
  font-size: 15px;
  border-radius: 5px;
}

#submit {
  width: 59px;
  height: 23px;
  margin: auto;
  left: 35%;
  border-radius: 5px;
  position: relative;
}

.rangeslider {
    width: 50%;
}
  
.myslider {
    -webkit-appearance: none;
    background: #FCF3CF  ;
    width: 50%;
    height: 20px;
    opacity: 2;
   }
  
  
.myslider::-webkit-slider-thumb {
    -webkit-appearance: none;
    cursor: pointer;
    background: #34495E  ;
    width: 5%;
    height: 20px;
}
  
  
.myslider:hover {
    opacity: 1;
}

.rangeslider {
  left: 38%;
  position: absolute;
}
<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>replit</title>
  <link href="style.css" rel="stylesheet" type="text/css" />
</head>

<body>
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

  <div class="box5">
    <canvas class="canvas" id="canvas"></canvas>
  </div>
  
  <div class="box1">
    <button id="clear">Clear</button><br>
  </div>

  <div class="box1">
    <div class="rangeslider">
          <input type="range" min="1" max="100" value="5" class="myslider" id="sliderRange">
    </div>
  </div>
  <div class=box1>
    <div>
      <input id="setSize" type="text" placeholder="Set Brush Size... (Max 100)">
      <br>
      <button type="submit" id="submit" for="setSize">Submit</button>
    </div>
  </div>
  
  <div class="box">
      <div class="container">
        <input type="color" value="#000000" class="style2" id="1" />
      </div>
      <div class="container">
        <input type="color" value="#ffffff" class="style2" id="2" />
      </div>
      <div class="container">
        <input type="color" value="#ffffff" class="style2" id="3" />
      </div>
      <div class="container">
        <input type="color" value="#ffffff" class="style2" id="4" />
      </div>
      <div class="container">
        <input type="color" value="#ffffff" class="style2" id="5" />
      </div>
  </div>

  <div class="box">
    <label for="selectedColor">Current Color:</label>
    <div id="selectedColor"></div>
  </div>

  <script src="script.js"></script>
</body>

</html>
 

I know this code is a bit weird, but please tell me.

P粉475126941P粉475126941204 days ago286

reply all(2)I'll reply

  • P粉905144514

    P粉9051445142024-03-29 14:08:37

    The way to calculate the mouse position is not appropriate, and the deviation of the canvas relative to the viewport needs to be taken into account. You cannot use getBoundingClientRect() to do this:

    function setPosition(e) {
      const canvas = document.getElementById("canvas");
      const bounds = canvas.getBoundingClientRect();
      pos.x = e.clientX - bounds.left;
      pos.y = e.clientY - bounds.top;
    }

    But you must also fix the .canvas css class by removing the width and height or setting the same height as in the resize function.

    https://codepen.io/Joulss/pen/BaPYgpZ?editors=1111

    reply
    0
  • P粉481815897

    P粉4818158972024-03-29 11:28:25

    This is actually an easy problem to solve. You just forgot about the offsets clientX and clientY. You see, these coordinates are in window space, so (0,0) will be in the upper left corner of the window. If your canvas was also in the top left corner then everything would look fine, but in your case the canvas is in the center so the coordinates don't line up. This can be fixed by subtracting the coordinates from the screen position of the canvas.

    This is an example:

    function setPosition(e) {
      let canvas = document.getElementById("canvas")
      let bounds = canvas.getBoundingClientRect()
      pos.x = e.clientX - bounds.x
      pos.y = e.clientY - bounds.y
    }
    

    You can find it at https://developer.mozilla.org/en-US/docs/Web/API/Element/getBoundingClientRect" rel="nofollow noreferrer">https:// /developer.mozilla.org /en-US/docs/Web/API/Element/getBoundingClientRect

    reply
    0
  • Cancelreply