I’m trying to make a very simple paint in JS but I have a problem when I increase the line width it create weird shape at the end of shape but not when I use a lineWidth = 1 and I don’t know where the problem come from furthermore it create space between lines while with a lineWidth=1 I don’t have that problem
this is my code :
class Board{
constructor(canvas) {
this.canvas = canvas;
this.ctx = this.canvas.getContext("2d");
this.isDrawing = false;
this.mousePosition = {
x: 0,
y: 0
};
this.color = "black";
this.rect = this.canvas.getBoundingClientRect();
this.lineWidth = 15;
this.height = 0;
this.width = 0;
this.initBoard();
// this.test();
// this.checkIfFill = this.checkIfFill.bind(this)
}
initBoard() {
this.renderCanvas();
window.addEventListener("resize", () => {
this.renderCanvas();
});
this.canvas.addEventListener("mousedown", (e) => {
this.mousePosition = {
x: e.clientX - this.rect.left,
y: e.clientY - this.rect.top
};
this.isDrawing = true;
});
this.canvas.addEventListener("mousemove", (e) => {
if (this.isDrawing) {
this.draw((e.clientX - this.rect.left), (e.clientY - this.rect.top));
this.mousePosition = {
x: e.clientX - this.rect.left,
y: e.clientY - this.rect.top
};
}
});
this.canvas.addEventListener("mouseup", () => {
this.isDrawing = false;
});
}
renderCanvas() {
const drawingTools = document.querySelector(".drawing-tools");
const dpr = window.devicePixelRatio;
this.height = document.body.offsetHeight - drawingTools.offsetHeight;
this.width = document.body.offsetWidth;
this.canvas.style.height = this.height + "px";
this.canvas.style.width = this.width + "px";
this.canvas.setAttribute("width", (this.width*dpr) + "px");
this.canvas.setAttribute("height", (this.height*dpr) + "px");
this.ctx.scale(dpr, dpr);
}
draw(x, y) {
this.ctx.strokeStyle = this.color;
this.ctx.lineWidth = this.lineWidth;
this.ctx.beginPath();
this.ctx.moveTo(this.mousePosition.x, this.mousePosition.y);
this.ctx.lineTo(x, y);
this.ctx.stroke()
// this.ctx.closePath();
}
setColor(color) {
this.color = color;
}
setLineWidth(width) {
this.lineWidth = width;
}
reset() {
this.ctx.clearRect(0,0, this.canvas.width, this.canvas.height)
}
test() {
this.ctx.strokeStyle = this.color;
this.ctx.lineWidth = this.lineWidth;
this.ctx.beginPath();
this.ctx.moveTo(100, 100);
this.ctx.lineTo(150, 100);
this.ctx.stroke()
}
checkIfFill() {
this.canvas.addEventListener("mousemove", (e) => {
const x = e.clientX - this.rect.left;
const y = e.clientY - this.rect.top;
console.log(this.ctx.getImageData(x, y, 1, 1).data)
})
}
}
Advertisement
Answer
This happens because of two things:
- Inside your
draw()function you’re setting the starting point and the end point with every call. Usually you determine the start as soon as the user pushes the mousebutton – once. - even with #1 fixed, the line end might still look a bit ‘fuzzy’. This can be fixed by setting the context’s lineCap style to
roundinstead of it’s defaultbutt– which squares of line endpoints.
Here’s an example based on your code (just click ‘Run code snippet’):
class Board {
constructor(canvas) {
this.canvas = canvas;
this.ctx = this.canvas.getContext("2d");
this.isDrawing = false;
this.mousePosition = {
x: 0,
y: 0
};
this.color = "black";
this.rect = this.canvas.getBoundingClientRect();
this.lineWidth = 16;
this.height = 0;
this.width = 0;
this.initBoard();
// this.test();
// this.checkIfFill = this.checkIfFill.bind(this)
}
initBoard() {
this.renderCanvas();
window.addEventListener("resize", () => {
this.renderCanvas();
});
this.canvas.addEventListener("mousedown", (e) => {
this.mousePosition = {
x: e.clientX - this.rect.left,
y: e.clientY - this.rect.top
};
this.ctx.beginPath();
this.ctx.moveTo(this.mousePosition.x, this.mousePosition.y);
this.isDrawing = true;
});
this.canvas.addEventListener("mousemove", (e) => {
if (this.isDrawing) {
this.draw((e.clientX - this.rect.left), (e.clientY - this.rect.top));
this.mousePosition = {
x: e.clientX - this.rect.left,
y: e.clientY - this.rect.top
};
}
});
this.canvas.addEventListener("mouseup", () => {
this.isDrawing = false;
});
}
renderCanvas() {
// const drawingTools = document.querySelector(".drawing-tools");
const dpr = window.devicePixelRatio;
this.height = document.body.offsetHeight;
this.width = document.body.offsetWidth;
this.canvas.style.height = this.height + "px";
this.canvas.style.width = this.width + "px";
this.canvas.setAttribute("width", (this.width * dpr) + "px");
this.canvas.setAttribute("height", (this.height * dpr) + "px");
this.ctx.scale(dpr, dpr);
}
draw(x, y) {
this.ctx.strokeStyle = this.color;
this.ctx.lineWidth = this.lineWidth;
this.ctx.lineCap = 'round';
this.ctx.lineTo(x, y);
this.ctx.stroke()
}
setColor(color) {
this.color = color;
}
setLineWidth(width) {
this.lineWidth = width;
}
reset() {
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height)
}
test() {
this.ctx.strokeStyle = this.color;
this.ctx.lineWidth = this.lineWidth;
this.ctx.beginPath();
this.ctx.moveTo(100, 100);
this.ctx.lineTo(150, 100);
this.ctx.stroke()
}
checkIfFill() {
this.canvas.addEventListener("mousemove", (e) => {
const x = e.clientX - this.rect.left;
const y = e.clientY - this.rect.top;
});
}
}
var b = new Board(document.getElementById("canvas"));<canvas id="canvas" width=400 height=300></canvas>

