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
round
instead 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>