I'm trying to make an svg's eye pupil follow the cursor using this tutorial:
https://dev.to/anomaly3108/make-svg-follow-cursor-using-css-and-js-2okp
We have 4 divs:
Looks like the JS is working, but the angles aren't quite right. The student is positioned too high and cannot stay in the correct position.
let eyeball_left = document.querySelector("#eyeball_left"), pupil_left = document.querySelector("#pupil_left"), eyeArea_left = eyeball_left.getBoundingClientRect(), pupil_leftArea = pupil_left.getBoundingClientRect(), R_left = eyeArea_left.width / 2, r_left = pupil_leftArea.width / 2, centerX_left = eyeArea_left.left + R_left, centerY_left = eyeArea_left.top + R_left; console.log(centerX_left) console.log(centerY_left) let eyeball_right = document.querySelector("#eyeball_right"), pupil_right = document.querySelector("#pupil_right"), eyeArea_right = eyeball_right.getBoundingClientRect(), pupil_rightArea = pupil_right.getBoundingClientRect(), R_right = eyeArea_right.width / 2, r_right = pupil_rightArea.width / 2, centerX_right = eyeArea_right.left + R_right, centerY_right = eyeArea_right.top + R_right; console.log(centerX_right) console.log(centerY_right) document.addEventListener("mousemove", (e) => { let x_left = e.clientX - centerX_left, y_left = e.clientY - centerY_left, theta_left = Math.atan2(y_left, x_left), angle_left = (theta_left * 180) / Math.PI + 360; let x_right = e.clientX - centerX_right, y_right = e.clientY - centerY_right, theta_right = Math.atan2(y_right, x_right), angle_right = (theta_right * 180) / Math.PI + 360; pupil_left.style.transform = `translateX(${ R_left - r_left + "px" }) rotate(${angle_left + "deg"})`; pupil_left.style.transformOrigin = `${r_left + "px"} center`; pupil_right.style.transform = `translateX(${ R_right - r_right + "px" }) rotate(${angle_right + "deg"})`; pupil_right.style.transformOrigin = `${r_right + "px"} center`; });
#monster { height: 100px; width: 400px; }
<div id="monster"> <svg xmlns="http://www.w3.org/2000/svg" data-name="Layer 1" viewBox="168.88 0 290.9 400.77"> <g> <title>Layer 1</title> <path id="svg_1" fill="#6c63ff" d="m296.30999,388.65991l0,-67.88825l-22,0l0,67.88825a13.98286,13.98286 0 0 0 -7,12.11175l36,0a13.98286,13.98286 0 0 0 -7,-12.11175z" /> <path id="svg_2" fill="#6c63ff" d="m355.30999,388.65991l0,-67.88825l-22,0l0,67.88825a13.98286,13.98286 0 0 0 -7,12.11175l36,0a13.98286,13.98286 0 0 0 -7,-12.11175z" /> <circle id="svg_3" fill="#6c63ff" r="145.45113" cy="238.54887" cx="314.33362" /> <ellipse id="svg_4" fill="#fff" ry="19.21053" rx="57.63158" cy="311.43609" cx="314.33362" /> <circle id="svg_5" fill="#fff" r="24.69925" cy="205.61654" cx="262.19076" /> <circle id="svg_6" fill="#fff" r="24.69925" cy="205.61654" cx="366.47648" /> {/* eyebol */} <circle id="eyeball_left" fill="#3f3d56" r="19.21053" cy="205.31579" cx="262.67948" /> <circle id="eyeball_right" fill="#3f3d56" r="19.21053" cy="205.31579" cx="366.73212" /> {/* eyebol */} <ellipse id="svg_9" fill="#3f3d56" ry="74.09774" rx="96.05263" cy="87.09774" cx="314.33362" /> <ellipse id="svg_10" fill="#3f3d56" ry="18" rx="38" cy="18" cx="314.33362" /> <path id="svg_11" fill="#3f3d56" d="m315.39428,259.75517c6.323,-6.40629 16.04713,-6.53419 24.2561,-4.42458c9.786,2.51489 18.116,8.57423 27.17791,12.79851a49.55555,49.55555 0 0 0 14.58024,4.54776a38.27945,38.27945 0 0 0 36.63871,-17.0858a38.7584,38.7584 0 0 0 4.54212,-30.91717a1.50128,1.50128 0 0 0 -2.89283,0.79752a35.70693,35.70693 0 0 1 -3.34417,27.11259a35.29669,35.29669 0 0 1 -35.30417,17.03843a49.62651,49.62651 0 0 1 -14.22886,-4.81212c-8.76148,-4.28973 -16.98465,-10.00419 -26.54935,-12.41745c-9.21411,-2.32481 -19.9481,-1.90083 -26.997,5.241c-1.35753,1.37543 0.76245,3.4981 2.12132,2.12132l-0.00002,-0.00001z" /> <path id="svg_12" fill="#3f3d56" d="m315.39428,257.63384c-6.22928,-6.31139 -15.3898,-7.36984 -23.77027,-5.92682c-9.6154,1.65567 -17.88675,6.88869 -26.379,11.36988c-8.6772,4.57879 -17.92825,8.08187 -27.8912,6.48578a35.20905,35.20905 0 0 1 -23.1751,-14.039a35.77653,35.77653 0 0 1 -5.208,-30.05228a1.50128,1.50128 0 0 0 -2.89283,-0.79752a38.80889,38.80889 0 0 0 2.82291,27.89016a37.47231,37.47231 0 0 0 20.97865,18.1838c9.41409,3.348 19.35061,2.63 28.52089,-1.11613c9.42621,-3.85066 17.77515,-10.13661 27.45644,-13.36827c8.93708,-2.98324 20.2603,-3.75844 27.41619,3.49176c1.3583,1.37619 3.47944,-0.7453 2.12132,-2.12132l0,-0.00004z" /> <circle id="svg_13" fill="#3f3d56" r="11" cy="258.5" cx="314.36371" /> {/* PUPIL */} <circle id="pupil_left" fill="#fff" r="4" cy="198.77165" cx="254.31" /> <circle id="pupil_right" fill="#fff" r="4" cy="198.77165" cx="376.31" /> {/* PUPIL */} </g> </svg>
P粉4638111002024-03-28 22:37:29
The basic idea here is that I use line elements to determine the rotation/direction of the eye. A line can have a mark at both ends and in the middle. In this example the eyeball is a marker and then I update the end of the line based on the mouse position.
First a simple example with outline, then the full example:
let l1 = document.querySelector("#l1"); let l2 = document.querySelector("#l2"); let svg1 = document.querySelector("#svg1"); const toSVGPoint = (svg, x, y) => { let p = new DOMPoint(x, y); return p.matrixTransform(svg.getScreenCTM().inverse()); }; document.addEventListener('mousemove', e => { let p = toSVGPoint(svg1, e.clientX, e.clientY); l1.setAttribute('x2', p.x); l1.setAttribute('y2', p.y); l2.setAttribute('x2', p.x); l2.setAttribute('y2', p.y); });
let l1 = document.querySelector("#l1"); let l2 = document.querySelector("#l2"); let svg1 = document.querySelector("#svg1"); const toSVGPoint = (svg, x, y) => { let p = new DOMPoint(x, y); return p.matrixTransform(svg.getScreenCTM().inverse()); }; document.addEventListener('mousemove', e => { let p = toSVGPoint(svg1, e.clientX, e.clientY); l1.setAttribute('x2', p.x); l1.setAttribute('y2', p.y); l2.setAttribute('x2', p.x); l2.setAttribute('y2', p.y); });
#monster { height: 100px; width: 400px; }