I've been working on a JavaScript drawing app, but I'm facing an issue where the drawn elements are not aligned with my cursor. The positioning seems off, especially when moving to the right or up on the canvas. As I move towards the furthest left or bottom side of the canvas, the alignment improves and matches the cursor position accurately. Can someone help me troubleshoot this?
const canvas = document.getElementById("canvas");
const increaseBtn = document.getElementById("increase");
const decreaseBtn = document.getElementById("decrease");
const sizeEl = document.getElementById("size");
const colorEl = document.getElementById("color");
const clearEl = document.getElementById("clear");
//Core Drawing Functionality (with some research)
const ctx = canvas.getContext("2d");
let size = 5;
let isPressed = false;
let color = "black";
let x;
let y;
let fakeSize = 1;
canvas.addEventListener("mousedown", (e) => {
isPressed = true;
x = e.offsetX;
y = e.offsetY;
});
canvas.addEventListener("mouseup", (e) => {
isPressed = false;
x = undefined;
y = undefined;
});
canvas.addEventListener("mousemove", (e) => {
if (isPressed) {
const x2 = e.offsetX;
const y2 = e.offsetY;
drawCircle(x2, y2);
drawLine(x, y, x2, y2);
x = x2;
y = y2;
}
});
function drawCircle(x, y) {
ctx.beginPath();
ctx.arc(x, y, size, 0, Math.PI * 2);
ctx.fillStyle = color;
ctx.fill();
}
function drawLine(x1, y1, x2, y2) {
ctx.beginPath();
ctx.moveTo(x1, y1);
ctx.lineTo(x2, y2);
ctx.strokeStyle = color;
ctx.lineWidth = size * 2;
ctx.stroke();
}
function updateSizeOnScreen() {
sizeEl.innerHTML = fakeSize;
}
increaseBtn.addEventListener("click", () => {
size += 5;
fakeSize++;
if (fakeSize > 10) {
fakeSize = 10;
}
if (size > 50) {
size = 50;
}
updateSizeOnScreen();
});
decreaseBtn.addEventListener("click", () => {
size -= 5;
fakeSize--;
if (fakeSize < 1) {
fakeSize = 1;
}
if (size < 5) {
size = 5;
}
updateSizeOnScreen();
});
colorEl.addEventListener("change", (e) => {
color = e.target.value;
});
clearEl.addEventListener("click", () => {
ctx.clearRect(0, 0, canvas.width, canvas.height);
});
//Eraser and Pencil Actions (my own algorithm)
const eraser = document.getElementById("eraser");
const pencil = document.getElementById("pencil");
eraser.addEventListener("click", () => {
localStorage.setItem("colorEl", JSON.stringify(color));
color = "#fff";
colorEl.disabled = true;
canvas.classList.add("eraseractive");
eraser.classList.add("eraseractive");
colorEl.classList.add("eraseractive");
canvas.classList.remove("pencilactive");
eraser.classList.remove("pencilactive");
colorEl.classList.remove("pencilactive");
});
pencil.addEventListener("click", () => {
JSON.parse(localStorage.getItem("colorEl"));
color = colorEl.value;
colorEl.disabled = false;
canvas.classList.remove("eraseractive");
eraser.classList.remove("eraseractive");
colorEl.classList.remove("eraseractive");
canvas.classList.add("pencilactive");
eraser.classList.add("pencilactive");
colorEl.classList.add("pencilactive");
});
// Dark/Light Mode
const darkMode = document.getElementById("darkMode");
const lightMode = document.getElementById("lightMode");
const toolbox = document.getElementById("toolbox");
darkMode.addEventListener("click", () => {
darkMode.classList.add("mode-active");
lightMode.classList.remove("mode-active");
lightMode.classList.add("rotate");
darkMode.classList.remove("rotate");
toolbox.style.backgroundColor = "#293462";
document.body.style.backgroundImage =
"url('/assets/images/darkModeBackground.svg')";
document.body.style.backgroundSize = "1920px 1080px";
canvas.style.borderColor = "#293462";
toolbox.style.borderColor = "#293462";
});
lightMode.addEventListener("click", () => {
lightMode.classList.add("mode-active");
darkMode.classList.remove("mode-active");
darkMode.classList.add("rotate");
lightMode.classList.remove("rotate");
toolbox.style.backgroundColor = "#293462";
document.body.style.backgroundImage =
"url('/assets/images/lightModeBackground.svg')";
document.body.style.backgroundSize = "1920px 1080px";
canvas.style.borderColor = "#293462";
toolbox.style.borderColor = "#293462";
});
* {
box-sizing: border-box;
font-size: 20px !important;
}
body {
background: url("https://drawing-app-green.vercel.app/assets/images/lightModeBackground.svg");
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100%;
margin: 0;
position: relative;
max-height: 100vh;
overflow: hidden;
}
::selection {
background: transparent;
}
::-moz-selection {
background: transparent;
}
.mode {
display: flex;
position: absolute;
top: 10px;
right: 25px;
cursor: pointer;
}
.light-mode {
color: yellow;
}
.dark-mode {
color: #16213e;
}
.container {
display: flex;
flex-direction: column;
max-width: 1200px;
width: 100%;
max-height: 600px;
height: 100%;
}
canvas {
display: flex;
border: 2px solid #293462;
cursor: url("https://drawing-app-green.vercel.app/assets/images/pencilCursor.png") 2 48, pointer;
background-color: #fff;
margin-top: 3rem;
width: 100%;
height: 600px;
}
.toolbox {
background-color: #293462;
border: 1px solid #293462;
display: flex;
width: 100%;
align-items: center;
justify-content: center;
padding: 0.2rem;
}
.toolbox > * {
background-color: #fff;
border: none;
display: inline-flex;
align-items: center;
justify-content: center;
font-size: 2rem;
height: 30px;
width: 30px;
margin: 0.25rem;
padding: 0.25rem;
cursor: pointer;
}
.toolbox > *:last-child {
margin-left: auto;
}
canvas.eraseractive {
cursor: url("https://drawing-app-green.vercel.app/assets/images/eraserCursor.png") 2 48, pointer;
}
#color.eraseractive {
cursor: not-allowed;
}
canvas.pencilactive {
cursor: url("https://drawing-app-green.vercel.app/assets/images/pencilCursor.png") 2 48, pointer;
}
.mode-active {
visibility: hidden;
}
.rotate {
transform: rotate(360deg);
transition: transform 1s linear;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Drawing App</title>
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.2.0/css/all.min.css"
integrity="sha512-xh6O/CkQoPOWDdYTDqeRdPCVd1SpvCA9XXcUnZS2FmJNp1coAFzvtCN9BmamE+4aHK8yyUHUSCcJHgXloTyT2A=="
crossorigin="anonymous"
referrerpolicy="no-referrer"
/>
</head>
<body>
<i class="fa-solid fa-moon dark-mode fa-2x mode" id="darkMode"></i>
<i
class="fa-solid fa-sun light-mode fa-2x mode mode-active"
id="lightMode"
></i>
<div class="container">
<canvas id="canvas" width="1024" height="600"></canvas>
<div class="toolbox" id="toolbox">
<button id="decrease">-</button>
<span id="size">1</span>
<button id="increase">+</button>
<input type="color" id="color" />
<button id="pencil">
<img src="assets/images/pencilCursor.png" alt="" />
</button>
<button id="eraser">
<img src="assets/images/eraserCursor.png" alt="" />
</button>
<button id="clear">X</button>
</div>
</div>
<script src="assets/js/script.js"></script>
</body>
</html>