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); }); });
原理说明
- 直接控制瞳孔的坐标位置,避免marker旋转带来的渐变跟随问题
- 高光作为独立元素,始终以瞳孔坐标为基准加上固定偏移量,确保始终处于右上侧
- 限制瞳孔移动范围,保证不会超出眼睛轮廓
内容的提问来源于stack exchange,提问作者Kabel
相关产品推荐
相关产品推荐

