You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SVG瞳孔跟随光标功能角度偏差问题求助

解决SVG瞳孔跟随光标时角度偏移、位置异常的问题

问题分析

你的代码存在几个核心问题导致瞳孔位置不准:

  • 眼球中心坐标仅在页面加载时计算一次,未考虑窗口缩放、滚动带来的位置变化,后续计算的偏移量会持续出错。
  • 瞳孔初始位置未与眼球中心对齐,固定的cx/cy导致基准位置偏差,视觉上出现"偏高"的情况。
  • 使用rotate + translateX的组合方式适配SVG元素时,坐标系转换容易出现偏移,不如直接计算瞳孔目标位置可靠。

解决方案

1. 调整SVG结构:重置瞳孔初始位置

将瞳孔的初始cx/cy改为对应眼球的中心坐标,确保默认状态下瞳孔在眼球正中央:

<div id="monster">
  <svg xmlns="http://www.w3.org/2000/svg" data-name="Layer 1" viewBox="168.88 0 290.9 400.77">
    <!-- 其他SVG元素保持不变 -->
    <!-- PUPIL -->
    <circle
      id="pupil_left"
      fill="#fff"
      r="4"
      cy="205.31579"
      cx="262.67948"
    />
    <circle
      id="pupil_right"
      fill="#fff"
      r="4"
      cy="205.31579"
      cx="366.73212"
    />
    <!-- PUPIL -->
  </svg>
</div>

2. 重构JS逻辑:实时计算位置+直接偏移瞳孔

封装单眼处理逻辑,鼠标移动时实时获取眼球位置,通过三角函数计算瞳孔的目标偏移量,确保始终在眼球范围内:

// 处理单只眼的逻辑函数
function handleEyeCursor(eyeballEl, pupilEl) {
  return function(e) {
    const eyeRect = eyeballEl.getBoundingClientRect();
    const eyeRadius = eyeRect.width / 2;
    const pupilRadius = pupilEl.getBoundingClientRect().width / 2;
    const maxOffset = eyeRadius - pupilRadius; // 瞳孔可移动的最大距离

    // 计算眼球中心的实时坐标
    const eyeCenterX = eyeRect.left + eyeRadius;
    const eyeCenterY = eyeRect.top + eyeRadius;

    // 鼠标相对于眼球中心的坐标差
    const dx = e.clientX - eyeCenterX;
    const dy = e.clientY - eyeCenterY;

    // 计算鼠标到眼球中心的距离
    const distance = Math.sqrt(dx * dx + dy * dy);

    // 限制瞳孔在眼球范围内移动
    let offsetX = dx;
    let offsetY = dy;
    if (distance > maxOffset) {
      const ratio = maxOffset / distance;
      offsetX = dx * ratio;
      offsetY = dy * ratio;
    }

    // 应用偏移到瞳孔
    pupilEl.style.transform = `translate(${offsetX}px, ${offsetY}px)`;
  };
}

// 初始化左右眼的鼠标监听函数
const leftEyeHandler = handleEyeCursor(
  document.querySelector("#eyeball_left"),
  document.querySelector("#pupil_left")
);
const rightEyeHandler = handleEyeCursor(
  document.querySelector("#eyeball_right"),
  document.querySelector("#pupil_right")
);

// 绑定鼠标移动事件
document.addEventListener("mousemove", (e) => {
  leftEyeHandler(e);
  rightEyeHandler(e);
});

// 监听窗口缩放,确保位置计算始终准确
window.addEventListener("resize", () => {
  // 重新初始化处理函数,更新眼球位置参数
  leftEyeHandler = handleEyeCursor(
    document.querySelector("#eyeball_left"),
    document.querySelector("#pupil_left")
  );
  rightEyeHandler = handleEyeCursor(
    document.querySelector("#eyeball_right"),
    document.querySelector("#pupil_right")
  );
});

3. 保留原有CSS

#monster {
  height: 100px;
  width: 400px;
}

关键改进点

  • 实时坐标计算:每次鼠标移动时重新获取眼球位置,避免窗口缩放、滚动导致的坐标偏差。
  • 直接偏移替代旋转:通过translate直接设置瞳孔偏移量,适配SVG元素的坐标系,避免旋转带来的角度误差。
  • 边界限制:确保瞳孔不会移出眼球范围,始终保持在眼球边缘内。

内容的提问来源于stack exchange,提问作者Ofir Cohen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 09:40:47