Diese Variante des letzten Punkt-Beispiels stellt jeden gemalten Punkt als Objekt dar, sodass jeder Punkt einzeln animiert werden kann.
HTML<canvas id="myCanvas" width="400" height="400"></canvas>
CSS#myCanvas {
border: 1px solid;
}
JavaScriptconst canvas = document.getElementById('myCanvas');
const ctx = canvas.getContext('2d');
// physics animation parameters
const dotAcceleration = -2000; // pixel per second^2
const bouncingLossFactor = 0.9; // speed loss factor when rebouncing at the bottom
const minBouncingSpeed = 25; // minimum speed stopping
const animatedDots = new Set(); // list of animated dots
let animationTime = null; // current animation time
canvas.addEventListener('click', onClick);
function onClick(evt) {
const canvasClientRect = canvas.getBoundingClientRect();
const x = evt.clientX - canvasClientRect.x;
const y = evt.clientY - canvasClientRect.y;
// create dot
const dot = {
x: x,
height: canvas.height - y,
speed: 0,
};
// add dot to set of animated dots
animatedDots.add(dot);
// start animation on first dot
if (animatedDots.size === 1) {
animationTime = 0.001 * performance.now();
requestAnimationFrame(onAnimationFrame);
}
}
function onAnimationFrame() {
const now = 0.001 * performance.now();
const deltaTime = now - animationTime;
// clear canvas
ctx.clearRect(0, 0, canvas.width, canvas.height);
for (let dot of animatedDots) {
if (animateDot(dot, deltaTime)) {
drawDot(dot);
} else {
animatedDots.delete(dot);
}
}
// advance animation time
animationTime = now;
// continue animation
if (animatedDots.size > 0) {
requestAnimationFrame(onAnimationFrame);
}
}
function animateDot(dot, deltaTime) {
// update height from speed
dot.height += deltaTime * dot.speed;
// bounce at bottom
if (dot.height <= 0) {
dot.height = -dot.height; // correct of negative y-positions
dot.speed *= -bouncingLossFactor; // invert speed and apply loss
// stop animation when rebouncing too slowly
if (dot.speed < minBouncingSpeed) {
return false;
}
}
// update speed from acceleration
dot.speed += deltaTime * dotAcceleration;
// continue animation
return true;
}
function drawDot(dot) {
let dotRadius = 10;
ctx.beginPath();
ctx.arc(dot.x, canvas.height - dot.height - dotRadius, dotRadius, 0, 2.0*Math.PI);
ctx.fill();
}
Auch wenn das Beispiel mit einfachen Objekten schon recht gut funktioniert, wäre es noch eleganter, wenn eine Punkt-Klasse verwendet wird.