I came across an interesting interaction that reminded me of the older web the other day. As a user
moved their mouse cursor around, there would be a trail of something that followed it. I was intrigued
and wanted to see how/what it worked, so I opened up the dev console for the website
(Synchronized Digital Studio) and after poking around a bit, I realized that it wasn't
just a plain old <div>
that had some special handling. It was <canvas>
, which I had never worked
with before.
Using a combination of <canvas>
and requestAnimationFrame()
, I was able to recreate the interaction.
The idea is to attach an event listener for mouse movement to add a new Point
to an array that
holds the position of the user's movement.
const canvas = document.querySelector('canvas')
const ctx = canvas.getContext('2d')
class Point {
constructor(x, y) {
this.x = x
this.y = y
this.timestamp = 0
}
}
const points = []
const addPoint = (x, y) => {
const point = new Point(x, y)
points.push(point)
}
document.addEventListener('mousemove', ({ clientX, clientY }) => {
addPoint(clientX - canvas.offsetLeft, clientY - canvas.offsetTop)
})
Next, using requestAnimationFrame
, on each frame, clear the canvas, loop over each
point
and either
- Remove the point if enough time has passed (
maxAgeMS
) - Draw the point and connect it to the previous
point
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height)
const maxAgeMS = 160
for (let i = 0; i < points.length; i++) {
const currentPoint = points[i]
let previousPoint
if (points[i - 1] !== undefined) {
previousPoint = points[i - 1]
} else {
previousPoint = currentPoint
}
if (!currentPoint.timestamp) {
currentPoint.timestamp = timestamp
}
const elapsed = timestamp - currentPoint.timestamp
if (elapsed > maxAgeMS) {
points.shift()
} else {
ctx.lineJoin = 'round'
ctx.lineWidth = 4
ctx.strokeStyle = `rgb(152,236,60)`
ctx.beginPath()
ctx.moveTo(previousPoint.x, previousPoint.y)
ctx.lineTo(currentPoint.x, currentPoint.y)
ctx.stroke()
ctx.closePath()
}
}
Rinse and repeat for each frame, and this is what I ended up with: