JSFiddle - React, Tailwind, and code Playground

by Ben Gillbanks

HTML

<canvas id="myCanvas"></canvas>

JavaScript

const canvas = document.getElementById('myCanvas');
const ctx = canvas.getContext('2d');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;

let prevCursorPos = { x: 0, y: 0 };
let prevTimestamp = performance.now();
let scaledRadius = 10; // Initial radius

function getCursorPosition(event) {
  const rect = canvas.getBoundingClientRect();
  const x = event.clientX - rect.left;
  const y = event.clientY - rect.top;
  return { x, y };
}

function lerp(a, b, t) {
  return (1 - t) * a + t * b;
}

function updateCursor(event) {
  const cursorPos = getCursorPosition(event);
  const timestamp = performance.now();
  const deltaTime = timestamp - prevTimestamp;

  // Calculate velocity
  const velocity = {
    x: (cursorPos.x - prevCursorPos.x) / deltaTime,
    y: (cursorPos.y - prevCursorPos.y) / deltaTime,
  };
  
  if ( velocity < 2 ) {
      return;
  }

  // Calculate scaled radius based on velocity
  const targetRadius = Math.sqrt(velocity.x ** 2 + velocity.y ** 2) * 10;
    const numSteps = Math.ceil(targetRadius); // Adjust as needed
    
    console.log(numSteps);
for (let i = 0; i <= numSteps; i++) {

    const stepRadius = lerp(scaledRadius, targetRadius, 0.1);

    // Draw a circle at the cursor position with scaled radius
    ctx.beginPath();
    ctx.arc(
      lerp(prevCursorPos.x, cursorPos.x, 0.1),
      lerp(prevCursorPos.y, cursorPos.y, 0.1),
      stepRadius,
      0,
      2 * Math.PI
    );
    ctx.fillStyle = 'blue';
    ctx.fill();
  }

  // Update previous cursor position and timestamp
  prevCursorPos = cursorPos;
  prevTimestamp = timestamp;
}

canvas.addEventListener('mousemove', updateCursor);