I looked up a tutorial on how to make a simple drawing app, see here: https://www.youtube.com/watch?v=mRDo-QXVUv8
However, there is one flaw: it doesn't draw dots, because it only draws when the "mousemove" event listener is activated. I tried to solve this by always drawing a pixel where the mouse is whenever the mouse is pressed down. This allowed me to draw dots, but didn't work very well because whenever I tried to draw lines quickly, the line would be separated from that pixel, since the "mousemove" event listener reaction isn't very fast: see uploaded image. Basically, It only starts drawing a line a short while after I click my mouse, which means the line doesn't actually start where I clicked my mouse down.
Does anyone have a solution for this? How do the commercial drawing apps make it so seamless?
This is my 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">
<link rel="stylesheet" href="notexcss.css">
<title>PaperBrain</title>
</head>
<body>
<section class="container">
<div id="toolbar" style="z-index: 2">
<div id="toolbarheader">Logo here</div>
<label for="stroke">Stroke</label>
<input id="stroke" name='stroke' type="color">
<button id="clear">Clear</button>
</div>
<div class="drawing-board">
<div>
<canvas id="canv"
style="position: absolute; left: 0; top: 0; z-index: 1;"></canvas>
<canvas id="background"
style="position: absolute; left: 0; top: 0; z-index: 0;"></canvas>
</div>
</div>
</section>
<script src="./notexjs.jsx"></script>
</body>
</html>
My Javascript code (scroll down to the event listener for 'mousedown'):
const canvas = document.getElementById('canv');
const background = document.getElementById('background');
const toolbar = document.getElementById('toolbar');
const ctx = canvas.getContext('2d');
const bctx = background.getContext('2d');
const canvasOffsetX = canvas.offsetLeft;
const canvasOffsetY = canvas.offsetTop;
canvas.width = window.innerWidth - canvasOffsetX;
canvas.height = window.innerHeight - canvasOffsetY;
background.width = window.innerWidth - canvasOffsetX;
background.height = window.innerHeight - canvasOffsetY;
let isPainting = false;
let lineWidth = 1;
let startX;
let startY;
let yes;
bctx.beginPath()
bctx.setLineDash([]);
for (let i = 45.5; i < canvas.height; i+=46) {
bctx.moveTo(0, i+canvasOffsetY);
bctx.lineTo(canvas.width, i+canvasOffsetY);
bctx.stroke()
}
bctx.setLineDash([5,10]);
for (let l = 22.5; l < canvas.height; l+=46) {
bctx.moveTo(0, l+canvasOffsetY);
bctx.lineTo(canvas.width, l+canvasOffsetY);
bctx.stroke()
}
dragElement(document.getElementById("toolbarheader"));
function dragElement(drag) {
elmnt=document.getElementById("toolbar");
var pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;
//if (document.getElementById(drag)) {
// if present, the header is where you move the DIV from:
drag.onmousedown = dragMouseDown;
//} else {
// otherwise, move the DIV from anywhere inside the DIV:
//elmnt.onmousedown = dragMouseDown;
//}
function dragMouseDown(e) {
e = e || window.event;
e.preventDefault();
// get the mouse cursor position at startup:
pos3 = e.clientX;
pos4 = e.clientY;
document.onmouseup = closeDragElement;
// call a function whenever the cursor moves:
document.onmousemove = elementDrag;
}
function elementDrag(e) {
e = e || window.event;
e.preventDefault();
// calculate the new cursor position:
pos1 = pos3 - e.clientX;
pos2 = pos4 - e.clientY;
pos3 = e.clientX;
pos4 = e.clientY;
// set the element's new position:
elmnt.style.top = (elmnt.offsetTop - pos2) + "px";
elmnt.style.left = (elmnt.offsetLeft - pos1) + "px";
}
function closeDragElement() {
// stop moving when mouse button is released:
document.onmouseup = null;
document.onmousemove = null;
}
}
toolbar.addEventListener('click', e => {
if (e.target.id === 'clear') {
ctx.clearRect(0, 0, canvas.width, canvas.height);
}
});
toolbar.addEventListener('change', e => {
if(e.target.id === 'stroke') {
ctx.strokeStyle = e.target.value;
}
/* if(e.target.id === 'lineWidth') {
lineWidth = e.target.value;
}
*/
});
window.addEventListener('resize', e => {
canvas.width=window.innerWidth;
canvas.height=window.innerHeight;
background.width=window.innerWidth;
background.height=window.innerHeight;
ctx.clearRect(0, 0, canvas.width, canvas.height);
bctx.setLineDash([]);
for (let i = 45.5; i < canvas.height; i+=46) {
bctx.moveTo(0, i);
bctx.lineTo(canvas.width, i);
bctx.stroke()
}
bctx.setLineDash([5,10]);
for (let i = 22.5; i < canvas.height; i+=46) {
bctx.moveTo(0, i);
bctx.lineTo(canvas.width, i);
bctx.stroke()
}
});
const draw = (e) => {
if(!isPainting) {
return;
}
ctx.lineWidth = lineWidth;
//ctx.lineCap = 'round';
ctx.lineTo(e.clientX - canvasOffsetX, e.clientY);
ctx.stroke();
}
canvas.addEventListener('mousedown', (e) => {
startX = e.clientX;
startY = e.clientY;
isPainting = true;
//below is what I tried to do
ctx.fillRect(e.clientX,e.clientY,2,2);
});
canvas.addEventListener('mouseup', e => {
isPainting = false;
ctx.stroke();
ctx.beginPath();
});
//UNDO REVISIT LATER
/*document.addEventListener("keydown", e => {
if (e.ctrlKey && e.key === "z") {
;
}
});*/
canvas.addEventListener('mousemove', draw);