Step to mouse
Smooth out abrupt changes in mouse input or finger taps by taking gradual steps toward the mouse pointer. We do this by creating and tracking an input target, which is moved closer to the mouse position on each frame.
p5.js includes a function called
lerp(), or "linear
interpolation" which can be used for a similar purpose. While lerp()
provides consistent spacing in a single frame, when used frame-by-frame,
lerp() "slows" as it approaches the target point, while StepToMouse
maintains a constant velocity.
Source Code for this Sketch
let input
class StepToMouse{
x = 0
y = 0
static def(input, defaultValue) {
if (typeof input === "number") {
return input
}
return defaultValue
}
constructor(step, minX, minY, maxX, maxY) {
// step determines how quickly we orient towards
// the mouse position. Each frame, we move at
// most this many units in any direction.
this.step = StepToMouse.def(step, 3)
// Set the bounds for valid input values
this.minX = StepToMouse.def(minX, 0)
this.minY = StepToMouse.def(minY, 0)
this.maxX = StepToMouse.def(maxX, width)
this.maxY = StepToMouse.def(maxY, height)
}
update() {
let deltaX = mouseX-this.x
let deltaY = mouseY-this.y
// Calculate the hypotenuse of our delta triangle
// so we can limit angular movement by this.step
let c = sqrt(pow(deltaX, 2)+pow(deltaY, 2))
// Multiply our x & y movement by a ratio of their
// length to the hypotenuse. For lateral or
// horizonal movement we'll have 1:0 or 0:1.
let ratioX = abs(deltaX) / c || 0
let ratioY = abs(deltaY) / c || 0
this.x += max(min(deltaX, this.step), -this.step)*ratioX
this.y += max(min(deltaY, this.step), -this.step)*ratioY
// Constrain x and y to valid area
this.x = min(this.x, this.maxX)
this.x = max(this.x, this.minX)
this.y = min(this.y, this.maxY)
this.y = max(this.y, this.minY)
}
}
function setup() {
createCanvas(400, 400, P2D, canvas)
input = new StepToMouse(3)
ellipseMode(CENTER)
colorMode(HSL)
noStroke()
}
function draw() {
input.update()
fill(0, 0, 100, .05)
rect(0, 0, width, height)
fill(30)
circle(input.x, input.y, 10)
}
document.addEventListener("DOMContentLoaded", (e) => {
let p5ui = document.getElementById("p5ui")
p5ui.innerHTML = `
<div style="text-align: center;">
<input id="p5step" type="range" min=".5" max="20"
step=".5" default="2" value="2">
<label for="p5step">Current step value:</label>
<span id="p5stepvalue" style="font-family: monospace;">3.0</span>
</div>
`
let p5step = document.getElementById("p5step")
let p5stepvalue = document.getElementById("p5stepvalue")
p5step.addEventListener("input", (e) => {
p5stepvalue.innerText = Number(e.target.value).toFixed(1)
input.step = e.target.value
})
})
You may use all or part of the p5 code seen on this page for your own creations, without restriction. Attribution is appreciated but not required.
This sketch also includes the following sources: p5common.js . Sources are available under their respective licenses.