search

Home  >  Q&A  >  body text

Make the eye follow the cursor in this SVG

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:

  1. Left eyeball
  2. eyeball_right
  3. Student left
  4. pupil_right

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粉969253139P粉969253139247 days ago376

reply all(1)I'll reply

  • P粉463811100

    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;
    }
    Layer 1 {/* eyebol */} {/* eyebol */} {/* PUPIL */} {/* PUPIL */}

    reply
    0
  • Cancelreply