JSFiddle - React, Tailwind, and code Playground
HTML
<canvas id="myCanvas" width="600" height="600"></canvas>
<button id="clear">Clear</button>
CSS
body {
background: gray;
margin: 0;
}
canvas {
border: 1px solid black;
}
JavaScript
const canvas = document.getElementById('myCanvas');
const clear = document.getElementById('clear');
const ctx = canvas.getContext('2d');
let lastCanvas;
clear.addEventListener('click', () => {
ctx.clearRect(0, 0, canvas.width, canvas.height);
});
let down = false;
let lastPoints = [];
ctx.lineCap = 'round';
canvas.addEventListener('mousedown', ({offsetX: x, offsetY: y}) => {
lastPoints.push({x, y});
ctx.lineWidth = 5;
ctx.shadowColor = 'transparent';
lastCanvas = ctx.getImageData(0, 0, canvas.width, canvas.height);
down = true;
ctx.beginPath();
ctx.moveTo(x, y);
});
canvas.addEventListener('mouseup', (event) => {
ctx.putImageData(lastCanvas, 0, 0);
redraw();
lastPoints = [];
down = false;
});
let count = 0;
canvas.addEventListener('mousemove', ({offsetX: x, offsetY: y}) => {
count++;
if (!down) return;
lastPoints.push({x, y});
ctx.lineTo(x, y);
ctx.stroke();
});
function redraw() {
if (lastPoints.length === 0) return;
const length = lastPoints.length;
const {x, y} = lastPoints[0];
ctx.beginPath();
ctx.moveTo(x, y);
let oldX = x, oldY = y;
for (let i = 0; i < length-1; i++) {
const {x, y} = lastPoints[i];
const {x: nX, y: nY} = lastPoints[i+1];
if (oldX && (x !== oldX || y !== oldY)) {
ctx.beginPath();
let dis = Math.sqrt((x-oldX)*(x-oldX) + (y-oldY)*(y-oldY));
let nDis = Math.sqrt((nX-x)*(nX-x) + (nY-y)*(nY-y));
ctx.shadowColor = 'rgba(0, 0, 0, 0.07)';
ctx.shadowBlur = dis;
ctx.lineWidth = 1;
const normX = (x - oldX)/dis;
const normY = (y - oldY)/dis;
const xP = -normY;
const yP = normX;
dis *= 0.5;
nDis *= 0.5;
const x1 = dis*xP + oldX;
const y1 = dis*yP + oldY;
const x2 = -dis*xP + oldX;
const y2 = -dis*yP + oldY;
const x3 = nDis*xP + x;
const y3 = nDis*yP + y;
const x4 = -nDis*xP + x;
const y4 = -nDis*yP + y;
...