我正在嘗試在 JS 中創建一個繪圖應用程式,但是,無論何時繪制任何東西,它都會遠離我的游標,具體取決于它在畫布上的位置,當我在畫布的最左側/底部時,你可以畫出游標所在的位置,但我移動得越向右/向上,畫筆就越開始“漂移”并且比游標所在的位置更遠。
顯示代碼片段
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>
uj5u.com熱心網友回復:
您的問題是您的畫布尺寸與包含它的 HTML 元素的尺寸不匹配。你看:你的畫布有一個固定的 width="" 和 height="" 屬性集。但是在您的 HTML 中,您的 canvas 元素的寬度為 100%。所以這意味著容器的尺寸不同,但里面的畫布沒有。這導致畫布試圖調整大小以顯示在容器內,從而給您計算精確單擊的像素的問題。
你有兩個選擇:
選項 1:計算您的點擊位置并考慮畫布變形
如果您希望畫布調整大小,請使用簡單的比率公式計算實際位置。例如,如果您的畫布的寬度為 100,但現在它的容器寬度為 10px,那么如果您單擊像素 5,您希望在 50 像素處繪制一個點。換句話說,如果您的畫布小 10 倍那么你需要將你的位置乘以 10 倍。
在您的代碼中,它看起來像這樣:
// this is your same code in lines 33 ana34 but see that I added a multiplication by the ratio between the canvas size and the canvas container
const x2 = e.offsetX * (canvas.width / ctx.canvas.getBoundingClientRect().width);
const y2 = e.offsetY * (canvas.height / ctx.canvas.getBoundingClientRect().height);
選項#2:不要讓你的畫布變形
洗掉容器類,并從畫布 css 中洗掉 width:100%。您的畫布將溢位并導致滾動條,但位置將使用您的代碼正確計算。
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/527399.html
