I am trying to make the eye pupil of the svg to follow cursor using this tutorial:
https://dev.to/anomaly3108/make-svg-follow-cursor-using-css-and-js-2okp
We have 4 divs:
- eyeball_left
- eyeball_right
- pupil_left
- pupil_right
looks like the JS is working, but the angle is not really accurate. the pupils are going too high and they do not 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>
2
Answers
The basic idea here, is that I use a line element to decide the rotation/direction of the eye. A line can have a marker in both ends and in the middle. In this example the eye ball is a marker and then I update the end of the line based on the position of the mouse.
First a simple example with outlines and then the full example:
Alternative: update
<circle>
cx
andcy
attributesThis approach requires to calculate
Demo example
The above script can be applied by wrapping all eyeballs and pupils in a group with a class "eye" like so :
Like in @chrwahl’s example we need to convert HTML DOM coordinates to SVG user units.
Calculate angles
Fine tune pupil positioning within eyeball area
Calculating the distance between cursor and eyeball center, allows us to further adjust the pupil movement: If the cursor is within the eyeball, the pupil will be centered around the current mouse coordinates.
Point on circle
Sinc we want the circle to be placed within the eyball’s boundaries we need to use a decreased radius for this calculation (according to the pupil’s radius).