根据鼠标位置旋转 SVG 渐变

Rotate SVG gradient based on mouse position

我想根据鼠标位置旋转 svg 的渐变。 机制应该如下,其中[0,0]是鼠标在[=31=左上角],[100%,0]应该是鼠标在[=31=右上角=]等

到目前为止,我所知道的是角度随鼠标位置而变化(仅 mouseX),但不是基于我想要的机制: https://codepen.io/magglomag/pen/YzKYLaa

svg渐变是这样定义的:

<defs>
    <linearGradient gradientTransform="rotate( X, 0.5, 0.5 )" id="gradient" gradientUnits="objectBoundingBox">
      <stop offset="0.4" style="stop-color:#33FF8F"/>
      <stop offset="0.6" style="stop-color:#5A33FF"/>
    </linearGradient>
</defs>

角度的操作是通过用JS改变gradientTransform属性中的X来实现的:

$( 'body' ).mousemove( function( e ) {

    mouseX = e.pageX - this.offsetLeft;
    mouseY = e.pageY - this.offsetTop;

    xy = mouseX;

    $( 'svg defs' ).html( '<linearGradient gradientTransform="rotate(' + xy + ', 0.5, 0.5 )"  id="gradient" gradientUnits="objectBoundingBox"><stop offset="0.4" stop-color="#33FF8F"/><stop offset="0.6" stop-color="#5A33FF"/></linearGradient>' );

});

此外,我想添加一些缓和,这样改变就不那么难了。这是我发现的一个使用缓动的例子。不与梯度角度变化结合,而是与运动结合,但底层代码可能会有所帮助:https://www.kirupa.com/canvas/mouse_follow_ease.htm

非常感谢任何帮助。

您只需要一点数学知识。您需要 SVG 图像的中心点以及鼠标与该点之间的角度:

相对于<svg>

  // position of mouse
  mouseX = e.pageX - this.offsetLeft;
  mouseY = e.pageY - this.offsetTop;
  // client rect of the gear
  const svgRoot = document.querySelector("#mysvg");
  const rect = svgRoot.getBoundingClientRect();
  // center point is x+width/2 and y+height/2
  const midx = rect.left + (rect.right - rect.left)/2;
  const midy = rect.top + (rect.bottom - rect.top)/2;
  // angle
  const angle = Math.atan2(midy - mouseY, midx - mouseX);
  // The transform uses degrees (0-365), not radians (0 - 2PI)
  const angleDeg = angle* 180 / Math.PI

演示:https://codepen.io/MXXIV/pen/OJLzEOV

相对于window

  // position of mouse
  mouseX = e.pageX - this.offsetLeft;
  mouseY = e.pageY - this.offsetTop;
  // center point is x+width/2 and y+height/2
  const midx = window.innerWidth/2;
  const midy = window.innerHeight/2;
  // angle
  const angle = Math.atan2(midy - mouseY, midx - mouseX);
  const angleDeg = angle* 180 / Math.PI

演示:https://codepen.io/MXXIV/pen/eYOyjdP

您可以按如下方式使用 atan2 来获取以弧度为单位的角度,并通过乘以 180 / Math.PI:

将其转换为度数

$('body').mousemove(function(e) {
  var {
    left: offsetX,
    top: offsetY
  } = $('svg').offset();
  centerX = $('svg').width() / 2 + offsetX;
  centerY = $('svg').height() / 2 + offsetY;
  mouseX = e.pageX - centerX;
  mouseY = e.pageY - centerY;

  xy = Math.atan2(mouseY, mouseX) * (180 / Math.PI);
  $('svg defs').html('<linearGradient gradientTransform="rotate(' + xy + ', 0.5, 0.5)"  id="gradient" gradientUnits="objectBoundingBox"><stop offset="0.4" stop-color="#33FF8F"/><stop offset="0.6" stop-color="#5A33FF"/></linearGradient>');

});
svg {
  width: 150px;
  height: 150px;
}

body {
  height: 100vw;
  width: 100vw;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<svg x="0px" y="0px" viewBox="0 0 150 150">
  
  <style>
   .st0 { fill:url( #gradient ); }
  </style>

  <defs>
    <linearGradient gradientTransform="rotate( 0, 0.5, 0.5 )" id="gradient" gradientUnits="objectBoundingBox">
   <stop  offset="0.4" style="stop-color:#33FF8F"/>
   <stop  offset="0.6" style="stop-color:#5A33FF"/>
    </linearGradient>
  </defs>
  
  <path class="st0" d="M149.3,89.5l0.7-24.6l-15.7-0.5c-1-5.4-2.8-10.8-5.3-16l12.4-9.7l-15.4-19.3l-12.4,9.7 c-4.4-3.6-9.3-6.6-14.5-8.8L102.2,5L77.9,0l-3.2,15.3c-5.6,0-11.3,0.8-16.8,2.4L50.4,4L28.5,15.6L36,29.4 c-4.4,3.7-8.2,7.9-11.3,12.6L10,36.2L0.8,59.1l14.7,5.8c-1,5.5-1.2,11.2-0.5,16.8L0,86.5l7.8,23.4l15-4.9c2.9,5,6.5,9.4,10.5,13.2 L25,131.5l21.2,12.9l8.3-13.3c5.3,1.9,10.9,3.1,16.6,3.4l2.3,15.4l24.6-3.6L95.7,131c2.6-1,5.2-2.1,7.8-3.5c2.5-1.4,4.9-2.9,7.2-4.5 l11.8,10.4L139,115l-11.8-10.4c2.8-4.9,4.9-10.2,6.3-15.6L149.3,89.5z M90,102.7c-15.4,8.2-34.7,2.5-43.1-12.8 c-8.3-15.3-2.5-34.4,12.9-42.6c15.4-8.2,34.7-2.5,43,12.8C111.2,75.3,105.4,94.4,90,102.7z"/>
</svg>