0

我希望点跟随鼠标光标,例如点击。代码看起来很简单,但每次单击时,点都会运行更短的距离并且不会到达目标。

问题是为什么?

代码在这里:

https://jsfiddle.net/thiefunny/ny0chx3q/3/

HTML

<circle r="10" cx="300" cy="300" />

JavaScript

const circle = document.querySelector("circle")

window.addEventListener("click", mouse => {

    const animation = _ => {

        let getCx = Number(circle.getAttribute('cx'))
        let getCy = Number(circle.getAttribute('cy'))

        circle.setAttribute("cx", `${getCx + (mouse.clientX - getCx)/10}`);
        circle.setAttribute("cy", `${getCy + (mouse.clientY - getCy)/10}`);

        requestAnimationFrame(animation)

    }

    requestAnimationFrame(animation)

});

编辑:对于这个任务,我需要 requestAnimationFrame(),而不是 CSS,因为这只是最简单的例子,但我想稍后为运动添加更多复杂性,包括多个点、随机参数等,就像我在这里所做的那样:https ://walanus.pl

我花了很多时间进行实验,但我唯一的结论是,在单击事件之后,我应该以某种方式取消当前动画并开始新的动画,以便为下一个动画重新开始。

4

2 回答 2

2

你不需要requestAnimationFrame这个:

const circle = document.querySelector("circle")

window.addEventListener("click", e => {

  let targetCircleX = e.clientX;
  let targetCircleY = e.clientY;
  let getCx = Number(circle.getAttribute('cx'))
  let getCy = Number(circle.getAttribute('cy'))
  let cx = targetCircleX - getCx;
  let cy = targetCircleY - getCy;
  
  circle.style.transform = `translate3d(${cx}px, ${cy}px, 0)`;
  
});
circle {
  transition-duration: .2s;
}
<svg version="1.1" baseProfile="full" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="500" height="500">
  <circle r="10" cx="100" cy="100" />
</svg>
    

编辑:CSS animations是一种简单而强大的方法来为网络中的事物设置动画,但是手动控制动画,正确完成,总是需要更多的工作,即高性能循环,正确的时间等(顺便说一下,提到的网站不会打扰用这些)。因此,为了完整的答案,requestAnimationFrame下面是一个变体

const circle = document.querySelector("circle");

const fps = 60;
const delay = 1000 / fps;
let rafId;

window.addEventListener("click", e => {

    cancelAnimationFrame(rafId);

    let [time, cx, cy, xf, yf] = [0];
    let r = +circle.getAttribute('r');
    let [X, x] = [e.clientX - r, +circle.getAttribute('cx')];
    let [Y, y] = [e.clientY - r, +circle.getAttribute('cy')];
    const decel = 10;
    
    const anim = now => {
        const delta = now - time;
        if (delta > delay) {
            time = now - (delta % delay);
            [x, y] = [x + (X - x) / decel, y + (Y - y) / decel];
            [xf, yf] = [x.toFixed(1), y.toFixed(1)];
            if (cx === xf && cy === yf)
                return;
            circle.setAttribute("cx", cx = xf);
            circle.setAttribute("cy", cy = yf);
        }
        rafId = requestAnimationFrame(anim);
    }

    anim(time);
});
<svg version="1.1" baseProfile="full" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="500" height="500" style="background: black">
  <circle r="10" cx="100" cy="100" fill="red"/>
</svg>

于 2021-03-12T16:16:55.037 回答
1

问题是为什么

好吧,您似乎知道原因:您永远不会停止动画循环,因此在每一帧它都会尝试转到mouse.clientN动画循环开始时的位置。然后在下一次单击时,将开始第二个动画循环,与第一个动画循环并行运行,两者将相互对抗以走向自己的mouse.clientN位置。


为避免这种情况,正如您所确定的,您可以使用简单地停止前一个循环cancelAnimationFrame。它所需要的只是动画范围和点击处理程序都可以访问的变量。
然而,让你的动画循环继续下去只会杀死树木。requestAnimationFrame因此,在再次从内部调用之前,让您的代码检查它是否已到达目标位置animation

const circle = document.querySelector("circle")
{

  let anim_id; // to be able to cancel the animation loop
  window.addEventListener("click", mouse => {
    const animation = _ => {

      const getCx = Number(circle.getAttribute('cx'))
      const getCy = Number(circle.getAttribute('cy'))
      const setCx = getCx + (mouse.clientX - getCx)/10;
      const setCy = getCy + (mouse.clientY - getCy)/10;

      circle.setAttribute("cx", setCx);
      circle.setAttribute("cy", setCy);
      // only if we didn't reach the target
      if(
        Math.floor( setCx ) !== mouse.x && 
        Math.floor( setCy ) !== mouse.y
      ) {
        // continue this loop
        anim_id = requestAnimationFrame(animation);
      }
    }
    // clear any previous animation loop
    cancelAnimationFrame( anim_id );
    anim_id = requestAnimationFrame(animation)
  });
  
}
svg { border: 1px solid }
<svg viewBox="0 0 500 500" width="500" height="500">
  <circle r="10" cx="100" cy="100" />
</svg>

此外,请注意,您的动画在具有 120Hz 显示器的设备上运行速度将比具有 60Hz 显示器的设备快两倍,在 240Hz 显示器上运行速度甚至更快。为避免这种情况,请使用增量时间。

于 2021-03-13T05:05:45.490 回答