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

SVG实现眼球随光标移动并保持瞳孔高光固定的问题

解决SVG瞳孔高光随旋转偏移的问题

问题说明

基于已有实现完成SVG眼球跟踪光标效果后,尝试给瞳孔添加径向渐变高光时,高光会随瞳孔旋转,无法固定在瞳孔右上侧。尝试通过反向旋转瞳孔元素抵消旋转,却导致元素移出marker的viewbox,设置transform origin也未生效。

解决方案

放弃用marker实现瞳孔的方式(marker的旋转会带动内部渐变/元素一起旋转),改为直接控制瞳孔和高光的位置,让高光始终相对于瞳孔保持固定偏移:

修改后的HTML代码

<svg id="svg1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 50">
    <!-- 眼睛轮廓 -->
    <circle cx="75" cy="25" r="20" fill="none" stroke="black" />
    <circle cx="125" cy="25" r="20" fill="none" stroke="black" />
    <!-- 瞳孔 -->
    <circle class="pupil" id="pupil1" cx="75" cy="25" r="4" fill="#030507" stroke="green"/>
    <circle class="pupil" id="pupil2" cx="125" cy="25" r="4" fill="#030507" stroke="green"/>
    <!-- 高光(固定在瞳孔右上侧) -->
    <circle class="highlight" id="highlight1" cx="77" cy="23" r="1" fill="#fff"/>
    <circle class="highlight" id="highlight2" cx="127" cy="23" r="1" fill="#fff"/>
</svg>

修改后的JS代码

let svg1 = document.querySelector("#svg1");
// 存储每只眼睛的中心坐标、半径、瞳孔和高光元素
const eyeConfig = [
  { 
    centerX: 75, 
    centerY: 25, 
    eyeRadius: 20,
    pupil: document.querySelector('#pupil1'),
    highlight: document.querySelector('#highlight1')
  },
  { 
    centerX: 125, 
    centerY: 25, 
    eyeRadius: 20,
    pupil: document.querySelector('#pupil2'),
    highlight: document.querySelector('#highlight2')
  }
];

// 将屏幕坐标转换为SVG内部坐标
const toSVGPoint = (svg, x, y) => {
    let p = new DOMPoint(x, y);
    return p.matrixTransform(svg.getScreenCTM().inverse());
};

document.addEventListener('mousemove', e => {
    const mousePos = toSVGPoint(svg1, e.clientX, e.clientY);
    
    eyeConfig.forEach(eye => {
        // 计算鼠标与眼睛中心的向量
        const dx = mousePos.x - eye.centerX;
        const dy = mousePos.y - eye.centerY;
        const distance = Math.sqrt(dx * dx + dy * dy);
        // 瞳孔最大移动范围:眼睛半径减去瞳孔半径
        const maxPupilMove = eye.eyeRadius - 4;

        let pupilX, pupilY;
        if (distance <= maxPupilMove) {
            // 鼠标在眼睛范围内,瞳孔直接跟随鼠标
            pupilX = mousePos.x;
            pupilY = mousePos.y;
        } else {
            // 鼠标在眼睛外,瞳孔移动到眼睛边缘
            const ratio = maxPupilMove / distance;
            pupilX = eye.centerX + dx * ratio;
            pupilY = eye.centerY + dy * ratio;
        }

        // 更新瞳孔位置
        eye.pupil.setAttribute('cx', pupilX);
        eye.pupil.setAttribute('cy', pupilY);
        // 更新高光位置:相对于瞳孔右上偏移(+2,-2)
        eye.highlight.setAttribute('cx', pupilX + 2);
        eye.highlight.setAttribute('cy', pupilY - 2);
    });
});

原理说明

  1. 直接控制瞳孔的坐标位置,避免marker旋转带来的渐变跟随问题
  2. 高光作为独立元素,始终以瞳孔坐标为基准加上固定偏移量,确保始终处于右上侧
  3. 限制瞳孔移动范围,保证不会超出眼睛轮廓

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 10:45:31