Code

Canvas

Mouse Drawing App

Intermediate Interactive paint canvas — smooth drawing and erasing via mouse and touch events, with brush colour and size controls. MDN Reference

8px
// Smooth drawing with mousemove
let drawing = false, lastX = 0, lastY = 0;

canvas.addEventListener('mousedown', e => {
  drawing = true;
  ({ lastX, lastY } = getPos(e));
});

canvas.addEventListener('mousemove', e => {
  if (!drawing) return;
  const { x, y } = getPos(e);

  ctx.beginPath();
  ctx.moveTo(lastX, lastY);
  ctx.lineTo(x, y);
  ctx.lineCap  = 'round';
  ctx.lineJoin = 'round';
  ctx.lineWidth = brushSize;
  ctx.strokeStyle = brushColor;
  ctx.stroke();

  [lastX, lastY] = [x, y];
});

canvas.addEventListener('mouseup',    () => drawing = false);
canvas.addEventListener('mouseleave', () => drawing = false);

// Scale mouse coords for CSS-scaled canvas
const getPos = (e: MouseEvent) => {
  const rect = canvas.getBoundingClientRect();
  return {
    x: (e.clientX - rect.left) * (canvas.width / rect.width),
    y: (e.clientY - rect.top)  * (canvas.height / rect.height),
  };
};

// Eraser: draw white OR use destination-out
ctx.globalCompositeOperation = 'destination-out';
ctx.strokeStyle = 'rgba(0,0,0,1)';
// reset after:
ctx.globalCompositeOperation = 'source-over';

// Always remove listeners on destroy!
ngOnDestroy() {
  canvas.removeEventListener('mousedown', startDraw);
  canvas.removeEventListener('mousemove', draw);
}
Key Concepts
  • Track mousedown / mousemove / mouseup for draw state
  • Scale coordinates: (clientX - rect.left) × (canvas.width / rect.width)
  • lineCap = 'round' + lineJoin = 'round' for smooth strokes
  • Eraser with globalCompositeOperation = 'destination-out'
  • Support touch with touchstart / touchmove + e.preventDefault()
  • Always remove event listeners in ngOnDestroy to prevent memory leaks