我正在做一个Web项目,我有一个用户可以点击的元素列表。当一个元素被点击时,它应该成为活动的,触发一个持续200毫秒的CSS转换(例如,转换)。同时,我想更新HTML5画布上该元素的坐标。
目前,我有JavaScript代码将“active”类添加到单击的元素中,触发CSS转换,然后它调用updateItemCoordinates()函数来更新坐标。但是,坐标更新发生在CSS转换完成之后,导致转换和坐标更新之间存在滞后。或者它会保留先前的坐标。
我希望坐标更新与CSS转换同时发生。
下面是我在codepen上的例子:https://codepen.io/kilian-m/pen/QWzXmEr
下面是我目前使用的JavaScript代码:
// Lines animation
const canvas = document.getElementById('line-canvas');
const ctx = canvas.getContext('2d');
const list = document.querySelector('.ressource-search__parent-terms');
const items = Array.from(list.querySelectorAll('.ressource-search__parent-term'));
const parent = document.querySelector('.ressource-search');
canvas.width = list.offsetWidth;
canvas.height = parent.offsetHeight;
const animationDuration = 200;
function getCanvasCoordinates(element) {
const rect = element.getBoundingClientRect();
const canvasRect = canvas.getBoundingClientRect();
return {
x: rect.left + rect.width / 2 - canvasRect.left,
y: rect.top + rect.height / 2 - canvasRect.top
};
}
let itemCoordinates = items.map(getCanvasCoordinates);
// Click sur l'element
items.forEach((item, key) => {
item.addEventListener('click', () => {
items.forEach(otherItem => {
otherItem.classList.remove('active');
otherItem.classList.add('not-active');
});
item.classList.remove('not-active');
item.classList.add('active');
updateItemCoordinates();
});
})
function updateItemCoordinates() {
const newCoordinates = items.map(getCanvasCoordinates);
const startTime = performance.now();
function animateTransition(timestamp) {
const elapsed = timestamp - startTime;
const progress = Math.min(1, elapsed / animationDuration);
ctx.clearRect(0, 0, canvas.width, canvas.height);
for (let i = 0; i < items.length - 1; i++) {
const x1 = itemCoordinates[i].x;
const y1 = itemCoordinates[i].y;
const x2 = itemCoordinates[i + 1].x;
const y2 = itemCoordinates[i + 1].y;
const newX1 = x1 + (newCoordinates[i].x - x1) * progress;
const newY1 = y1 + (newCoordinates[i].y - y1) * progress;
const newX2 = x2 + (newCoordinates[i + 1].x - x2) * progress;
const newY2 = y2 + (newCoordinates[i + 1].y - y2) * progress;
drawLine(newX1, newY1, newX2, newY2, 1);
}
if (progress < 1) {
requestAnimationFrame(animateTransition);
} else {
itemCoordinates = newCoordinates;
cancelAnimationFrame(animateTransition);
}
}
requestAnimationFrame(animateTransition);
}
function animateLine(index, startTime) {
const x1 = itemCoordinates[index].x;
const y1 = itemCoordinates[index].y;
const x2 = itemCoordinates[index + 1].x;
const y2 = itemCoordinates[index + 1].y;
return function(timestamp) {
const elapsed = timestamp - startTime;
const progress = Math.min(1, elapsed / animationDuration);
ctx.clearRect(0, 0, canvas.width, canvas.height);
for (let i = 0; i < index; i++) {
const prevX1 = itemCoordinates[i].x;
const prevY1 = itemCoordinates[i].y;
const prevX2 = itemCoordinates[i + 1].x;
const prevY2 = itemCoordinates[i + 1].y;
drawLine(prevX1, prevY1, prevX2, prevY2, 1);
}
drawLine(x1, y1, x2, y2, progress);
if (progress < 1) {
requestAnimationFrame(animateLine(index, startTime));
} else {
if (index + 2 < items.length) {
animateLine(index + 1, performance.now())(performance.now());
}
}
};
}
function drawLine(x1, y1, x2, y2, progress) {
ctx.beginPath();
ctx.moveTo(x1, y1);
ctx.lineTo(x1 + (x2 - x1) * progress, y1 + (y2 - y1) * progress);
ctx.lineWidth = 1;
ctx.strokeStyle = "#707070";
ctx.stroke();
}
function startAnimation() {
if (items.length > 1) {
animateLine(0, performance.now())(performance.now());
}
}
window.addEventListener('resize', () => {
itemCoordinates = items.map(getCanvasCoordinates);
startAnimation();
});
setTimeout(() => {
startAnimation();
}, 50);
我尝试使用transitionend事件,但它引入了延迟。我还尝试使用requestAnimationFrame在转换过程中更新坐标,但我很难正确地同步两者。
1条答案
按热度按时间a0x5cqrl1#
为了解决这个问题,我添加了不带转换的复制品