I’m trying to make an animation inside a canvas: here, a numbered circle must be drawn and move from left to right one single time, disappearing as soon as it reaches the end of animation.
For now I managed to animate it in loop, but I need to animate at the same time (or with a set delay) multiple numbered circles, strating in different rows (changing y position) so they wont overlap.
Any idea how can I manage this? my JS code is the following:
// Single Animated Circle - Get Canvas element by Id var canvas = document.getElementById("canvas"); // Set Canvas dimensions canvas.width = 300; canvas.height = 900; // Get drawing context var ctx = canvas.getContext("2d"); // Radius var radius = 13; // Starting Position var x = radius; var y = radius; // Speed in x and y direction var dx = 1; var dy = 0; // Generate random number var randomNumber = Math.floor(Math.random() * 60) + 1; if (randomNumber > 0 && randomNumber <= 10) { ctx.strokeStyle = "#0b0bf1"; } else if (randomNumber > 10 && randomNumber <= 20) { ctx.strokeStyle = "#f10b0b"; } else if (randomNumber > 20 && randomNumber <= 30) { ctx.strokeStyle = "#0bf163"; } else if (randomNumber > 30 && randomNumber <= 40) { ctx.strokeStyle = "#f1da0b"; } else if (randomNumber > 40 && randomNumber <= 50) { ctx.strokeStyle = "#950bf1"; } else if (randomNumber > 50 && randomNumber <= 60) { ctx.strokeStyle = "#0bf1e5"; } function animate3() { requestAnimationFrame(animate3); ctx.clearRect(0, 0, 300, 900); if (x + radius > 300 || x - radius < 0) { x = radius; } x += dx; ctx.beginPath(); ctx.arc(x, y, 12, 0, Math.PI * 2, false); ctx.stroke(); ctx.fillText(randomNumber, x - 5, y + 3); } // Animate the Circle animate3();
<canvas id="canvas"></canvas>
Advertisement
Answer
Here is a solution which doesn’t use classes as such and separates the animation logic from the updating – which can be useful if you want more precise control over timing.
// Some helper functions const clamp = (number, min, max) => Math.min(Math.max(number, min), max); // Choose and remove random member of arr with equal probability const takeRandom = arr => arr.splice(parseInt(Math.random() * arr.length), 1)[0] // Call a function at an interval, passing the amount of time that has passed since the last call function update(callBack, interval) { let now = performance.now(); let last; setInterval(function() { last = now; now = performance.now(); callBack((now - last) / 1000); }) } const settings = { width: 300, height: 150, radius: 13, gap: 5, circles: 5, maxSpeed: 100, colors: ["#0b0bf1", "#f10b0b", "#0bf163", "#f1da0b", "#950bf1", "#0bf1e5"] }; const canvas = document.getElementById("canvas"); canvas.width = settings.width; canvas.height = settings.height; const ctx = canvas.getContext("2d"); // Set circle properties const circles = [...Array(settings.circles).keys()].map(i => ({ number: i + 1, x: settings.radius, y: settings.radius + (settings.radius * 2 + settings.gap) * i, radius: settings.radius, dx: settings.maxSpeed * Math.random(), // This is the speed in pixels per second dy: 0, color: takeRandom(settings.colors) })); function drawCircle(circle) { ctx.strokeStyle = circle.color; ctx.beginPath(); ctx.arc(circle.x, circle.y, circle.radius, 0, Math.PI * 2, false); ctx.stroke(); ctx.fillText(circle.number, circle.x - 5, circle.y + 3); } function updateCircle(circle, dt) { // Update a circle's position after dt seconds circle.x = clamp(circle.x + circle.dx * dt, circle.radius + 1, settings.width - circle.radius - 1); circle.y = clamp(circle.y + circle.dy * dt, circle.radius + 1, settings.height - circle.radius - 1); } function animate() { ctx.clearRect(0, 0, settings.width, settings.height); circles.forEach(drawCircle); requestAnimationFrame(animate); } update(dt => circles.forEach(circle => updateCircle(circle, dt)), 50); animate();
<canvas id="canvas" style="border: solid 1px black"></canvas>