如何从鼠标移动中获取值并将其插入动画

2020-07-02 19:35:59

到目前为止,这是我最喜欢的片段之一。对光标位置做出反应的小动画。

在这篇文章中,我们将介绍如何从鼠标移动中获取值,并将其插入动画中。

这是我最喜欢的SVG动画。不是特别的鼠标移动,而是交互性。将动画导出为MP4很酷。但是你不能玩它。

如果你是那种通过钻研代码学得最好的人,那么就去拿起那支笔,玩得开心!

我所有的SVG动画都使用Greensock。这有几个原因。首先,它给了你更多的操控力,并且使用起来非常有趣。但更重要的是,由于浏览器实现SVG规范的方式不同,动画可能会变得有点混乱。Greensock的团队花了很多精力来协调浏览器之间的行为。

然而,在引擎盖下,格林索克只是一个真正表现出色的财产操纵者。它将操纵(几乎)您想要更改的任何值。在这种情况下,它更新矩阵变换中的值。看看这个。

很酷,对吧!格林索克在这方面很在行,但这支笔里有很多东西,所以让我们把它分成几块,一次专注于一小块。首先,我们来看一下鼠标的互动。我们稍后再回到格林索克!

因此,还有另一种方法可以用Javascript修改CSS中的值。CSS自定义属性!

让我们一步一步走完这个过程。目标是在我们移动鼠标时获得光标的x和y位置,然后我们可以使用这些值来更新一些自定义属性。

在前面的gif中,Greensock使用了性能更好的矩阵变换。但是我们将对此使用Transform:Translate(x,y),因为它的可读性更好一些,而且我们可以使用百分比值。

首先,我们为x和y值声明一些自定义属性,然后在我们的转换中使用这些自定义属性来代替常规属性值。

然后我们需要得到我们的鼠标坐标。我们可以通过监听鼠标移动并获取鼠标与clientX和clientY的坐标来做到这一点。

我们将把这些值赋给一些全局变量,这样我们以后就可以在另一个函数中访问它们。

let xPosition;let yPosition;//更新鼠标坐标函数updateMouseCoods(Event){xPosition=event.clientX;yPosition=event.clientY;}窗口。addEventListener(';Mousemove';,updateMouseCo);

现在我们已经得到了我们的坐标,让我们使用它们来更新我们的自定义属性,并移动我们的指针!

😇在网页上制作动画时,注意性能是很重要的。我们不能确切地知道用户的鼠标事件会触发多少次,因为它的实现是特定的。如果它每秒触发超过60次(这是大多数浏览器的平均刷新率),我们最终将进行不必要的计算。因此,为了避免烧毁每个人的笔记本电脑风扇并融化他们的CPU,我们可以使用requestAnimationFrame

请求动画帧使我们可以制作更流畅、浏览器优化的动画。如果用户更改选项卡,动画将停止并让CPU休息一下。您只需调用该函数一次即可启动,然后它会循环调用自身。

⚠️如果您有一些代码错误,这是一个使浏览器崩溃的好方法!

现在,我们从event.clientX和event.clientY返回的x和y位置都是像素值,这对我们来说并不是很有用。如果我们将它们直接插入到我们的自定义属性中,我们最终可能会在一个方向上将指针转换成几百个像素的距离。

我们需要将这些像素值转换为窗口高度和宽度的百分比。

让我们为窗口宽度和高度定义一些全局变量,并计算出百分比值。

let windowHeight=window.innerHeight;let windowWidth=window.innerWidth;函数Percent(artialValue,totalValue){return(100*artialValue)/totalValue;}函数movePointer(){x=Percent(xPosition,windowWidth);y=Percent(yPosition,windowHeight);Window。requestAnimationFrame(MovePointer);}requestAnimationFrame(MovePointer);

这将给出一个从0到100的范围,这只会将指针向下和向右移动,所以我们可以通过减去50来移动范围。

一旦我们获得了很好的集中范围,我们就可以使用setProperty()将其插入到我们的自定义属性中

let windowHeight=window.innerHeight;let windowWidth=window.innerWidth;函数Percent(artialValue,totalValue){return(100*artialValue)/totalValue;}函数movePointer(){//将范围从0到100转移到-50到50//这将使移动保持中心x=Percent(xPosition,windowWidth)-50;y=Percent(yPosition,windowHeight)-。setProperty(';--鼠标-x';,`${x}%`);document.DocumentElement.style。setProperty(';--鼠标-y';,`${y}%`);窗口。requestAnimationFrame(MovePointer);}requestAnimationFrame(MovePointer);

当鼠标位置没有改变时,我们还可以通过存储过去的x和y位置并将它们与新位置进行比较来避免不必要的计算。

让xPosition;let yPosition;let storedXPosition;let storedYPosition;函数movePointer(){Window.。requestAnimationFrame(MovePointer);//仅当(storedXPosition=xPosition&;&;storedYPosition=yPosition)返回时才重新计算值是否更改;//更新自定义属性//使用当前位置storedXPosition=xPosition;storedYPosition=yPosition;}更新存储的位置。

😇另一个非常重要的功能是检查用户是否在其操作系统中设置了减少运动的首选项。有些人有前庭功能障碍,在看动画时会变得大惊小怪。

我会在所有动画功能开始时弹出此检查,并在必要时返回。

让我们看看如何使用Greensock做同样的事情!首先,我们必须包含核心库,如果您正在使用codesen,您可以转到您的笔设置并搜索greensock。

现在我们已经有了GSAP库,我们可以利用gsap.ticker()。

greensock代码类似于GSAP引擎的心跳-在幕后它使用requestAnimationFrame,就像我们使用的一样,但是如果不支持,代码会自动后退到使用常规的setTimeout()循环。

除了让构建动画本身更直观之外,Greensock还提供了大量超酷的实用功能,让您的生活变得更轻松。还记得我们为得到一个好的可用射程所做的所有工作吗?把这些都扔进垃圾桶。看看我们现在能做什么!

//使用GSAP实用程序设置我们的坐标映射!让mapWidth;let mapHeight;function setMaps(){mapWidth=gsap.utils。mapRange(0,innerWidth,-50,50);mapHeight=gsap.utils。mapRange(0,innerHeight,-50,50);}窗口。addEventListener(';resize';,setMaps);setMaps();

现在我们可以监听鼠标的移动,将clientX和clientY提供给mapWidth,我们将得到一个在我们设置的范围内的值!

let xPosition;let yPosition;//更新鼠标坐标函数updateMouseCoods(Event){xPosition=mapWidth(event.clientX);yPosition=mapWidth(event.clientY);}窗口。addEventListener(';Mousemove';,updateMouseCo);

我们将使用Greensock补间,而不是更新CSS自定义属性。补间是做所有动画工作的东西,正如我在开始时所说的,它就像一个高性能的属性操纵器。

目标,即要为其属性设置动画的对象。Greensock在内部使用Document.querySelectorAll(),这样我们就可以使用在CSS中使用的任何CSS选择器,或者直接引用元素。

以及vars,这是一个包含要设置动画的所有属性/值的对象,以及任何特殊属性,如延迟、缓动或持续时间。

函数movePointer(){gsap.。到(指针,{xPercent:xPosition,yPercent:yPosition,Ease:';None';//Ease:';power4.out';,//Ease:';power4.in';});}//gsap';的RAF,回退到设置超时gsap.ticker。add(MovePointer);

我在这里多加了几个缓和方程式,这样你就可以把它们换掉,看看它能给运动带来什么不同。

在CodePen上查看Cassie Evans(@Cassie-codes)的钢笔鼠标运动演示-GSAP-Easing(@Cassie-code)。

如果您希望更多地关注性能而不是缓动,您可以使用gsa.ickSetter来更新转换。创建一个QuickSetter函数可以提高大约50%-250%的性能!

//使用.ickSetter可获得最佳性能,因为我们动态地重新更新了很多值。//将其应用于指针x/y属性,并附加一个";%";unit const xSet=gsap。QuickSetter(指针,';x';,';%';);const ySet=gsap。QuickSetter(POINTER,';y&39;,';%&39;);函数movePointer(){xSet(XPosition);ySet(YPosition);}//gsap&39;的raf,回退以设置超时gsap.ticker。add(MovePointer);

下一步-让我们将其应用于SVG,并伪造一些三维运动!