我正在开发一个网络项目,其中有用户可以单击的元素列表。单击某个元素时,它应该变为活动状态,从而触发持续 200 毫秒的 CSS 转换(例如,变换)。同时,我想更新该元素在 HTML5 画布上的坐标。
目前,我有 JavaScript 代码,将“active”类添加到单击的元素,触发 CSS 转换,然后调用 updateItemCooperatives() 函数来更新坐标。但是,坐标更新发生在 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 在过渡期间更新坐标,但我很难正确同步两者。
我添加了透明克隆而不进行过渡来解决我的问题