JavaScript requestAnimationFrame ускоряет анимацию с течением времени. Как этого избежать?Javascript

Форум по Javascript
Ответить
Anonymous
 JavaScript requestAnimationFrame ускоряет анимацию с течением времени. Как этого избежать?

Сообщение Anonymous »

У меня есть анимация Three.js, которая изменяет сферу с помощью requestAnimationFrame(). Однако после отправки нескольких сообщений в окно чата анимация начинает быстро ускоряться. Я подозреваю, что создается несколько циклов анимации, но не могу понять, где именно.
Что я пробовал:
  • пробовал сбросить переменную currentProcessing
  • пробовал отменить анимацию после каждого сообщения, отправленного пользователем
Что я ожидаю, что анимация будет поддерживать постоянную скорость независимо от количества сообщений отправлено.
Как правильно предотвратить ускорение анимации с течением времени?
Вот код JavaScript:
const apiKey = '';
const apiUrl = `https://generativelanguage.googleapis.c ... y=${apiKey}`;

let boostedSpeed = 1.0;
let update;
let currentProcessing = 1;

$(document).ready(function() {

let $canvas = $('#blob canvas'),
canvas = $canvas[0],
renderer = new THREE.WebGLRenderer({
canvas: canvas,
context: canvas.getContext('webgl2'),
antialias: true,
alpha: true
}),
simplex = new SimplexNoise();

renderer.setSize($canvas.width(), $canvas.height());
renderer.setPixelRatio(window.devicePixelRatio || 1);

let scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(45, $canvas.width() / $canvas.height(), 0.1, 1000);

camera.position.z = 5;

let geometry = new THREE.SphereGeometry(.8, 128, 128);

let material = new THREE.MeshPhongMaterial({
color: 0xE4ECFA,
shininess: 100
});

let lightTop = new THREE.DirectionalLight(0xFFFFFF, .7);
lightTop.position.set(0, 500, 200);
lightTop.castShadow = true;
scene.add(lightTop);

let lightBottom = new THREE.DirectionalLight(0xFFFFFF, .25);
lightBottom.position.set(0, -500, 400);
lightBottom.castShadow = true;
scene.add(lightBottom);

let ambientLight = new THREE.AmbientLight(0x798296);
scene.add(ambientLight);

let sphere = new THREE.Mesh(geometry, material);

scene.add(sphere);

update = () => {
let currentSpeed = 13;
let currentSpikes = 0.6;

let time = performance.now() * 0.00001 * currentSpeed * Math.pow(currentProcessing, 3);
let spikes = currentSpikes * currentProcessing;

for (let i = 0; i < sphere.geometry.vertices.length; i++) {
let p = sphere.geometry.vertices;
p.normalize().multiplyScalar(1 + 0.3 * simplex.noise3D(p.x * spikes, p.y * spikes, p.z * spikes + time));
}

sphere.geometry.computeVertexNormals();
sphere.geometry.normalsNeedUpdate = true;
sphere.geometry.verticesNeedUpdate = true;
};
function animate() {
update();
renderer.render(scene, camera);
requestAnimationFrame(animate);
}

requestAnimationFrame(animate);

});

document.addEventListener('DOMContentLoaded', function () {
const inputField = document.getElementById("user-input");

inputField.addEventListener('keypress', function (e) {
if (e.key === 'Enter') {
sendMessage();
}
});
});

function sendMessage() {
const userInput = document.getElementById("user-input").value;
if (!userInput.trim()) return;

// Display user message
const userMessage = document.createElement("div");
userMessage.classList.add("message", "user");
userMessage.textContent = userInput;
document.getElementById("chat-box").appendChild(userMessage);
document.getElementById("user-input").value = "";

animateProcessingEffect(1.8);
fetchGeminiResponse(userInput);
}

function animateProcessingEffect(targetProcessing = 1.8) {
if (animationFrameId) {
cancelAnimationFrame(animationFrameId);
}

const steps = 0.005;
const revertSteps = 0.001;
const revertDelay = 100;
let isReverting = false;

function animateStep() {
if (!isReverting) {
if (currentProcessing < targetProcessing) {
currentProcessing = Math.min(currentProcessing + steps, targetProcessing);
} else {
isReverting = true;
setTimeout(() => {
animationFrameId = requestAnimationFrame(animateStep);
}, revertDelay);
return;
}
} else {
if (currentProcessing > 1) {
currentProcessing = Math.max(currentProcessing - revertSteps, 1);
} else {
return;
}
}
update();
animationFrameId = requestAnimationFrame(animateStep);
}

animationFrameId = requestAnimationFrame(animateStep);
}

async function fetchGeminiResponse(input) {
const botMessage = document.createElement("div");
botMessage.classList.add("message", "bot");

try {
const response = await fetch(apiUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
contents: [{
parts: [{"text": input }]
}]
})
});

const data = await response.json();
console.log('API Response:', data);

const apiResponse = data.candidates[0].content.parts[0].text || "Sorry, I couldn't process that.";
botMessage.textContent = apiResponse;

} catch (error) {
console.error('Error fetching from Gemini API:', error);
botMessage.textContent = "Oops! Something went wrong while connecting to the server.";
}

document.getElementById("chat-box").appendChild(botMessage);

const chatBox = document.getElementById("chat-box");
chatBox.scrollTop = chatBox.scrollHeight;
}

document.addEventListener("DOMContentLoaded", function () {
var width, height, largeHeader, canvas, ctx, points, target, animateHeader = true;

initHeader();
initAnimation();
addListeners();

function initHeader() {
width = window.innerWidth;
height = window.innerHeight;
target = {x: width / 2, y: height / 2};

largeHeader = document.getElementById('large-header');
if (!largeHeader) {
console.error('large-header element not found');
return;
}
largeHeader.style.height = height + 'px';

canvas = document.getElementById('demo-canvas');
canvas.width = width;
canvas.height = height;
ctx = canvas.getContext('2d');

points = [];
for (var x = 0; x < width; x = x + width / 20) {
for (var y = 0; y < height; y = y + height / 20) {
var px = x + Math.random() * width / 20;
var py = y + Math.random() * height / 20;
var p = {x: px, originX: px, y: py, originY: py};
points.push(p);
}
}

for (var i = 0; i < points.length; i++) {
var closest = [];
var p1 = points;
for (var j = 0; j < points.length; j++) {
var p2 = points[j];
if (!(p1 == p2)) {
var placed = false;
for (var k = 0; k < 5; k++) {
if (!placed) {
if (closest[k] == undefined) {
closest[k] = p2;
placed = true;
}
}
}
for (var k = 0; k < 5; k++) {
if (!placed) {
if (getDistance(p1, p2) < getDistance(p1, closest[k])) {
closest[k] = p2;
placed = true;
}
}
}
}
}
p1.closest = closest;
}

for (var i in points) {
var c = new Circle(points, 2 + Math.random() * 2, 'rgba(255,255,255,1)');
points.circle = c;
}
}

function addListeners() {
if (!('ontouchstart' in window)) {
window.addEventListener('mousemove', mouseMove);
}
window.addEventListener('scroll', scrollCheck);
window.addEventListener('resize', resize);
}

function mouseMove(e) {
var posx = posy = 0;
if (e.pageX || e.pageY) {
posx = e.pageX;
posy = e.pageY;
} else if (e.clientX || e.clientY) {
posx = e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;
posy = e.clientY + document.body.scrollTop + document.documentElement.scrollTop;
}
target.x = posx;
target.y = posy;
}

function scrollCheck() {
if (document.body.scrollTop > height) animateHeader = false;
else animateHeader = true;
}

function resize() {
width = window.innerWidth;
height = window.innerHeight;
largeHeader.style.height = height + 'px';
canvas.width = width;
canvas.height = height;
}

function initAnimation() {
animate();
for (var i in points) {
shiftPoint(points);
}
}

function animate() {
if (animateHeader) {
ctx.clearRect(0, 0, width, height);
for (var i in points) {
if (Math.abs(getDistance(target, points)) < 4000) {
points.active = 0.3;
points.circle.active = 0.6;
} else if (Math.abs(getDistance(target, points)) < 20000) {
points.active = 0.1;
points[i].circle.active = 0.3;
} else if (Math.abs(getDistance(target, points[i])) < 40000) {
points[i].active = 0.02;
points[i].circle.active = 0.1;
} else {
points[i].active = 0;
points[i].circle.active = 0;
}
drawLines(points[i]);
points[i].circle.draw();
}
}
requestAnimationFrame(animate);
}

function shiftPoint(p) {
gsap.to(p, {
duration: 1 + 1 * Math.random(),
x: p.originX - 50 + Math.random() * 100,
y: p.originY - 50 + Math.random() * 100,
ease: "circ.inOut",
onComplete: function () {
shiftPoint(p);
}
});
}

function drawLines(p) {
if (!p.active) return;
for (var i in p.closest) {
ctx.beginPath();
ctx.moveTo(p.x, p.y);
ctx.lineTo(p.closest[i].x, p.closest[i].y);
ctx.strokeStyle = 'rgba(156,217,249,' + p.active + ')';
ctx.stroke();
}
}
function Circle(pos, rad, color) {
var _this = this;

(function () {
_this.pos = pos || null;
_this.radius = rad || null;
_this.color = color || null;
})();

this.draw = function () {
if (!_this.active) return;
ctx.beginPath();
ctx.arc(_this.pos.x, _this.pos.y, _this.radius, 0, 2 * Math.PI, false);
ctx.fillStyle = 'rgba(156,217,249,' + _this.active + ')';
ctx.fill();
};
}

function getDistance(p1, p2) {
return Math.pow(p1.x - p2.x, 2) + Math.pow(p1.y - p2.y, 2);
}
});



Подробнее здесь: https://stackoverflow.com/questions/793 ... to-prevent
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «Javascript»