admin管理员组

文章数量:1336289

I'm trying to create an animation in a webpage where an element's box-shadow responds to the mouse's position, i.e. (red X = mouse):

I already found a function that tracks the mouse movement, but I don't know how to apply this to the object. This is my code:

$(document).ready(function() {
  function shadowAnimation() {
    var objectToAnimate = $("#shadow-test");
    document.onmousemove = handleMouseMove;

    function handleMouseMove(event) {
      var eventDoc, doc, body;

      event = event || window.event;

      if (event.pageX == null && event.clientX != null) {
        eventDoc = (event.target && event.target.ownerDocument) || document;
        doc = eventDoc.documentElement;
        body = eventDoc.body;

        event.pageX = event.clientX +
          (doc && doc.scrollLeft || body && body.scrollLeft || 0) -
          (doc && doc.clientLeft || body && body.clientLeft || 0);
        event.pageY = event.clientY +
          (doc && doc.scrollTop || body && body.scrollTop || 0) -
          (doc && doc.clientTop || body && body.clientTop || 0);
      }

      console.log(event.pageX + " " + event.pageY);

    }
  }
});
#shadow-test {
  box-shadow: -10px -10px red;
  border: 1px solid white;
}
<script src=".3.1/jquery.min.js"></script>
<p id="shadow-test">This is a shadow test</p>

I'm trying to create an animation in a webpage where an element's box-shadow responds to the mouse's position, i.e. (red X = mouse):

I already found a function that tracks the mouse movement, but I don't know how to apply this to the object. This is my code:

$(document).ready(function() {
  function shadowAnimation() {
    var objectToAnimate = $("#shadow-test");
    document.onmousemove = handleMouseMove;

    function handleMouseMove(event) {
      var eventDoc, doc, body;

      event = event || window.event;

      if (event.pageX == null && event.clientX != null) {
        eventDoc = (event.target && event.target.ownerDocument) || document;
        doc = eventDoc.documentElement;
        body = eventDoc.body;

        event.pageX = event.clientX +
          (doc && doc.scrollLeft || body && body.scrollLeft || 0) -
          (doc && doc.clientLeft || body && body.clientLeft || 0);
        event.pageY = event.clientY +
          (doc && doc.scrollTop || body && body.scrollTop || 0) -
          (doc && doc.clientTop || body && body.clientTop || 0);
      }

      console.log(event.pageX + " " + event.pageY);

    }
  }
});
#shadow-test {
  box-shadow: -10px -10px red;
  border: 1px solid white;
}
<script src="https://cdnjs.cloudflare./ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<p id="shadow-test">This is a shadow test</p>

Share Improve this question asked Nov 13, 2020 at 18:44 Miguel AndradeMiguel Andrade 671 silver badge6 bronze badges 1
  • 3 Maybe look to tilt.js and tobiasahlin./blog/how-to-animate-box-shadow for some inspiration. – Jason Kleban Commented Nov 13, 2020 at 18:54
Add a ment  | 

3 Answers 3

Reset to default 4

Please take a look at the following examples(sans jquery).

const p = document.querySelector('#shadow-test');

const clamp = (a, m, n) => {
  const max = Math.max(m, n);
  const min = Math.min(m, n);

  return Math.max(min, Math.min(max, a));
};

const MAX_SHADOW_OFFSET = 30;

const paint = (x, y) => {
  const r = p.getBoundingClientRect();
  const o = Math.min(r.width, r.height, MAX_SHADOW_OFFSET); // pute max shadow offset
  
  const mx = clamp(x, r.left - o, r.right + o); // clamp mouse coordinates within the shadow projection bounding box.
  const my = clamp(y, r.top - o, r.bottom + o);
  const px = r.right - r.width / 2; // pute element bb midpoints.
  const py = r.bottom - r.height / 2;
  const nx = (mx - px) / (r.right - r.left + 2 * o); // project mouse position relative to the bounding box to [-.5, .5];
  const ny = (my - py) / (r.bottom - r.top + 2 * o); 
  
  requestAnimationFrame(() => {
    p.style.boxShadow = `${-1 * nx * o}px ${-1 * ny * o}px var(--shadow-color)`;
  });
};

document.addEventListener('mousemove', (e) => paint(e.clientX, e.clientY), {
  passive: true
});
:root {
  --primary-color: black;
  --secondary-color: white;
  --shadow-color: red;
  --button-color: blue;
  --color: white;
}

body {
  background-color: var(--primary-color);
  padding: 1rem;
}

.center {
  text-align: center;
}

button {
 background-color: var(--button-color);
 color: var(--color);
 border: 0;
 border-radius: .25rem;
 padding: .375rem 1rem;
}

#shadow-test {
  border: 1px solid var(--secondary-color);
  color: var(--secondary-color);
}
<div class="center">
  <button>
    More
  </button>
</div>

<p id="shadow-test">This is a shadow test</p>

Its definitely a mouthful pared to the other solutions but its not all that plex. The algorithm can be broken down into a couple of steps.

  1. We figure out the bounding box of the element. We need this to figure out the max offset for our box shadow as well as projections to our normalize coordinate space later on.

  2. We clamp the mouse coordinates to our new bounding box. This is used so that if you move your mouse far away from the element it doesn't continue moving. We also will need the mouse coordinates to project our to our normalized coordinate space.

  3. We find the midpoint of our element. Anything left of the midpoint will be negative, anything right will be positive and so on. We can use the sign values to figure what side the box shadow should be. A mouse on the left side of the midpoint will give use a negative value, on the right side it will be positive.

  4. Finally we project our mouse coordinates to our normalized coordinate space of [-0.5, .5]. The normalized coordinates makes it super easy to pute offsets by just simple multiplication. Think of (nx,ny) as just scale values. Given a max shadow offset value, how much should we apply to the style? and what direction?

Other notes

Im updating the style in an request animation frame. This is typically better for performance. You should also note the css variables. This is done so i don't have to hard code the color value of the box-shadow in code. The theme lives pletely in css.

Your logic to capture the mouse position is much more plicated than it needs to be. You only need to track pageX and pageY of the mousemove event.

To move the shadow you simply need to work out the distance from the mouse to the mid-point of each dimension of the target element. Then you can apply that distance, limited by the available height of the element, to the size of the box-shadow, something like this:

jQuery($ => {
  let $shadow = $('#shadow-test');
  let shadowMax = $shadow.height();
  let shadowMin = shadowMax * -1;
  let shadowMidPoints = [
    $shadow.offset().left + $shadow.width() / 2,
    $shadow.offset().top + $shadow.height() / 2
  ];

  $(document).on('mousemove', e => {
    let shadowX = Math.min(shadowMax, Math.max(shadowMin, shadowMidPoints[0] - e.pageX));
    let shadowY = Math.min(shadowMax, Math.max(shadowMin, shadowMidPoints[1] - e.pageY));
    $shadow.css('box-shadow', `${shadowX}px ${shadowY}px red`);
  });
});
body {
  height: 2000px;
}

#shadow-test {
  box-shadow: -10px -10px red;
  border: 1px solid white;
  margin: 100px;
  background-color: #CCC;
}
<script src="https://cdnjs.cloudflare./ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<p id="shadow-test">This is a shadow test</p>

As I understand you implemented tracking of mouse. In your screenshot and description its not clear when box-shadow property changes according to mouse position. Once you catch mouse position and can calculate position of where mouse pointer is then just use this js code to update box-shadow property of your text input. three case

$("#shadow-test").css('box-shadow', '-10px -10px red');
$("#shadow-test").css('box-shadow', '10px 10px red');
$("#shadow-test").css('box-shadow', '0px 10px red');

本文标签: javascriptBoxshadow responds to mouse positionStack Overflow