#javascript #css #animation #canvas #draw
Вопрос:
Я пытаюсь создать анимацию внутри холста: здесь необходимо нарисовать пронумерованный круг и один раз переместить его слева направо, исчезнув, как только он достигнет конца анимации.
На данный момент мне удалось анимировать его в цикле, но мне нужно анимировать одновременно (или с заданной задержкой) несколько пронумерованных кругов, расположенных в разных строках (меняя положение y), чтобы они не перекрывались.
Есть идеи, как я могу с этим справиться? мой JS-код выглядит следующим образом:
// 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 amp;amp; randomNumber <= 10) {
ctx.strokeStyle = "#0b0bf1";
} else if (randomNumber > 10 amp;amp; randomNumber <= 20) {
ctx.strokeStyle = "#f10b0b";
} else if (randomNumber > 20 amp;amp; randomNumber <= 30) {
ctx.strokeStyle = "#0bf163";
} else if (randomNumber > 30 amp;amp; randomNumber <= 40) {
ctx.strokeStyle = "#f1da0b";
} else if (randomNumber > 40 amp;amp; randomNumber <= 50) {
ctx.strokeStyle = "#950bf1";
} else if (randomNumber > 50 amp;amp; 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>
Комментарии:
1. Есть ли причина для использования canvas вместо анимации HTML-элементов?
2. Ну, задание требует, чтобы анимация была внутри холста
3. Отличное задание. 1) вам нужно понять область применения. Посмотрите на X, Y и радиус? Видите, где они определены глобально? Вы собираетесь создать функцию, в которой они будут определены внутри этой функции. 2)На самом деле вы создадите эти три значения с помощью генератора случайных чисел 3) наконец, вы вызовете эту новую функцию несколько раз. 4) совершенно нечестно просить людей в stackoverflow делать за вас домашнее задание.
Ответ №1:
Вот решение, которое не использует классы как таковые и отделяет логику анимации от обновления, что может быть полезно, если вам нужен более точный контроль над временем.
// 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>
Комментарии:
1. Большое вам спасибо. В вашем коде очень интересный подход. Я изучу его и адаптирую ваши идеи к тому, что я делаю (я ничего не выиграю, просто скопировав и вставив его). И еще раз спасибо вам
Ответ №2:
Здесь я преобразовал ваш пример кода в класс …
Мы передаем все данные в качестве параметра, вы можете видеть, что в конструкторе я упростил большую часть вашего кода, чтобы он был действительно коротким, но все тот же рисунок, который вы сделали, есть в функции рисования
Затем все, что нам нужно сделать, это создать экземпляры этого класса и вызвать функцию draw внутри того цикла animate3, который у вас уже есть.
У вас было жестко закодированное значение радиуса:
ctx.arc(x, y, 12, 0, Math.PI * 2, false)
Я предполагаю, что это была ошибка, и исправляю ее в своем коде
var canvas = document.getElementById("canvas");
canvas.width = canvas.height = 300;
var ctx = canvas.getContext("2d");
class Circle {
constructor(data) {
this.data = data
}
draw() {
if (this.data.x this.data.radius > 300 || this.data.x - this.data.radius < 0) {
this.data.x = this.data.radius;
}
this.data.x = this.data.dx;
ctx.beginPath();
ctx.arc(this.data.x, this.data.y, this.data.radius, 0, Math.PI * 2, false);
ctx.stroke();
ctx.fillText(this.data.number, this.data.x - 5, this.data.y 3);
}
}
circles = []
circles.push(new Circle({radius:13, x: 10, y: 15, dx: 1, dy: 0, number: "1"}))
circles.push(new Circle({radius:10, x: 10, y: 50, dx: 2, dy: 0, number: "2"}))
function animate3() {
requestAnimationFrame(animate3);
ctx.clearRect(0, 0, canvas.width, canvas.height);
circles.forEach(item => item.draw());
}
animate3();
<canvas id="canvas"></canvas>
Код должен быть простым в использовании, дайте мне знать, если у вас есть какие-либо вопросы
Комментарии:
1. Большое вам спасибо! Я не думал о создании массива с несколькими кругами.
2. @PedroFernandes Я рад, что это то, что вам нужно, этот код должен быть чище, чем у вас, и тот же шаблон, который вы должны легко использовать на других объектах, просто сделайте другой класс для тех, кто вам нужен