前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【译】模拟鼠标移动

【译】模拟鼠标移动

作者头像
腾讯IVWEB团队
发布2020-06-28 10:52:03
3.2K0
发布2020-06-28 10:52:03
举报

本文采用意译,可能会与原文的表达有所不同,如果想看原文,请点击这里,或者复制链接 https://css-tricks.com/simulating-mouse-movement/ 自行前往。

如果你曾经需要在一场演讲或者一堂课上演示一个交互动画,那么你会发现边看着大屏幕演讲边操作电脑并不是那么容易。

这样的事情就发生在我身上,当我需要向学生演示粒子动效时,我其实挺不想去边移动我电脑的鼠标的。

<iframe name="cp_embed_1" src="https://codepen.io/Mamboleoo/embed/c208f44cd08c23e548ff088c1647ab0e?height=300&amp;theme-id=1&amp;default-tab=result&amp;user=Mamboleoo&amp;slug-hash=c208f44cd08c23e548ff088c1647ab0e&amp;pen-title=Particles%20(on%20move)&amp;name=cp_embed_1" scrolling="no" frameborder="0" height="300" allowtransparency="true" allowfullscreen="true" allowpaymentrequest="true" title="Particles (on move)" class="cp_embed_iframe " style="width: 100%; overflow: hidden; display: block; height: 100%;" id="cp_embed_c208f44cd08c23e548ff088c1647ab0e"></iframe>

如果不和页面进行交互,将只会看到一片空白。一旦移动鼠标,就可以看到动画。

由于不想去移动鼠标就能完成这个演示,所以创建了另一个一模一样的演示,但这个演示使用了一些额外的代码来模拟鼠标移动。

<iframe name="cp_embed_2" src="https://codepen.io/Mamboleoo/embed/aa35539e563fa36d2a6d00f23b0d1b7e?height=300&amp;theme-id=1&amp;default-tab=result&amp;user=Mamboleoo&amp;slug-hash=aa35539e563fa36d2a6d00f23b0d1b7e&amp;pen-title=Particles%20(fake)&amp;name=cp_embed_2" scrolling="no" frameborder="0" height="300" allowtransparency="true" allowfullscreen="true" allowpaymentrequest="true" title="Particles (fake)" class="cp_embed_iframe " style="width: 100%; overflow: hidden; display: block; height: 100%;" id="cp_embed_aa35539e563fa36d2a6d00f23b0d1b7e"></iframe>

单形噪音

这里的技巧是使用一种算法,生成连续的随机位置。如果我们使用经典的随机函数,假鼠标将在每个帧上处于纯粹的随机位置。我们想要的是每一帧的位置与前一帧的位置有直接的关系。值得庆幸的是,有一种技术可以完全满足我们的需求:单形噪音(或者更常见的称为 Perlin 噪声)。

让我们看看下面的图像,其中每列的高度是每次算法产生的值的大小。上图是经典的随机函数生成的图像,下图则是单形噪音算法生成的图像。

算法

你能十分明显地注意到底部图形看起来更平滑,因为每列的高度都与前一列有关联。这些图表仅显示一个维度(x轴,从左到右),但使用单形噪音算法,你可以获得多个维度的值。在我们的例子中,我们将需要两个维度的值,对应着假鼠标的X和Y坐标。

如果你想知道单形噪声是如何工作的,请查看 Daniel Shiffman 的视频 “I.5: Perlin Noise - The Nature of Code”

获取噪音坐标

The first thing we need to make our demo work is to implement a script that generates noise. In my case, I'm using this script by Seph.

我们需要做的第一件事就是实现一个生成噪音的脚本。就我而言,我正在使用 Seph 的这个脚本

Once the noise script is loaded, we can start using it on every frame to make our mouse move.

加载噪声脚本后,我们可以开始在每一帧上使用它来使鼠标移动。

我将使用鼠标图像放置在演示中,并且通过一个 mouse 类来使得它的 position 是 fixed,当然你可以为自己的项目设置其他任何动画。

接下来,让我们来看看代码:

代码语言:javascript
复制
// 从 DOM 中获取图像
const el = document.querySelector('.mouse');

// 每一帧都会调用一次 render 函数
function render (a) {
  // a 变量是执行脚本以来经过的毫秒数
  
  // 根据经过的时间获取噪声值,以获得每帧的新值
  // 这个噪声算法返回 [-1,1] 之间的值,所以我们需要将返回的值加 1 再除以 2 来将它们映射到 [0,1] 区间中
  const noiseX = (noise.simplex2(0, a*0.0005) + 1) / 2;
  // We get another noise value for the y axis but because we don't want the same value than x, we need to use another value for the first parameter
  // 为了使 y 轴的噪声值与 x 轴的不同,需要将第一个参数设为另一个值
  const noiseY = (noise.simplex2(1, a*0.0005) + 1) / 2;
  
  // 将噪声值从 [0,1] 区间转换为窗口区间的值
  const x = noiseX * window.innerWidth;
  const y = noiseY * window.innerHeight;
  
  // 将 x 和 y 坐标应用在元素上
  el.style.transform = `translate(${x}px, ${y}px)`;

  // 无限循环地调用 render 函数
  requestAnimationFrame(render);
}

// 开始执行动画
requestAnimationFrame(render);

以下是使用上述脚本得到的结果:

<iframe name="cp_embed_3" src="https://codepen.io/Mamboleoo/embed/79bd69e58f751fbb03ca7be25db6527c?height=300&amp;theme-id=1&amp;default-tab=result&amp;user=Mamboleoo&amp;slug-hash=79bd69e58f751fbb03ca7be25db6527c&amp;pen-title=Virtual%20user%201&amp;name=cp_embed_3" scrolling="no" frameborder="0" height="300" allowtransparency="true" allowfullscreen="true" allowpaymentrequest="true" title="Virtual user 1" class="cp_embed_iframe " style="width: 100%; overflow: hidden; display: block; height: 100%;" id="cp_embed_79bd69e58f751fbb03ca7be25db6527c"></iframe>

允许交互

上述代码无法让用户和页面进行交互。接下来让我们增加一些代码,使得用户移动鼠标时,显示真正的鼠标位置,停止移动时切换回假鼠标。

代码语言:javascript
复制
const el = document.querySelector('.mouse');
let lastMove = 0;

// 当鼠标开始移动时
function onMouseMove (e) {
  // 获得鼠标的 x, y 坐标
  x = e.clientX;
  y = e.clientY;
  
  // 保存最后一次移动的时间
  lastMove = Date.now();
}

// 用鼠标的 x, y 坐标更新假鼠标的位置
function updateMouse (x, y) {
  el.style.transform = `translate(${x}px, ${y}px)`;
}

function render (a) {
  // 判断距离最后一次移动是否超过 500ms
  if (Date.now() - lastMove > 500) {
    // 生成假鼠标的位置
    ...
    updateMouse(x, y);
  }
}

// 监听鼠标移动的事件
window.addEventListener('mousemove', onMouseMove);

现在,如果移动鼠标,假鼠标将跟随真实的鼠标移动。如果停止移动时长超过 500 毫秒,假的鼠标将再次开始自动移动。

<iframe id="result-iframe" class="result-iframe " sandbox="allow-forms allow-modals allow-pointer-lock allow-popups allow-presentation allow-same-origin allow-scripts" allow="geolocation; microphone; camera; midi; vr; accelerometer; gyroscope; payment; ambient-light-sensor; encrypted-media" tabindex="-1" data-src="https://s.codepen.io/Mamboleoo/fullembedgrid/7363fad2aa95810e8e586248a785cc2d?type=embed&amp;animations=run" src="https://s.codepen.io/Mamboleoo/fullembedgrid/7363fad2aa95810e8e586248a785cc2d?type=embed&amp;animations=run" allowtransparency="true" frameborder="0" scrolling="yes" allowpaymentrequest="true" allowfullscreen="true" name="CodePen Preview for Virtual user 3" title="CodePen Preview for Virtual user 3">

</iframe>

控制移动

在上述代码中,我们可以通过更改第三个参数的值来更新鼠标的速度。目前,我们是用经过的时间乘以0.0005(a/2000)来设置这个值的。

代码语言:javascript
复制
// 定义一个速度比率
const speed = a * 0.0005;
// 控制鼠标速度
const noiseX = (noise.simplex3(1, 0, speed) + 1) / 2;

我们还可以通过从其位置添加更多噪声来增加方向变化的随机性。

代码语言:javascript
复制
let random = 0;
function render (a) {
  ...
  // 更新随机值
  random += 0.1;
  // 基于视口宽度计算一个 x 轴的随机强度
  const randX = noise.simplex3(1, 0, random) * window.innerWidth * 0.1;
  // 基于视口高度计算一个 y 轴的随机强度
  const randY = noise.simplex3(3, 0, random) * window.innerHeight * 0.1;

  // 基于 (noise * screen) + randomness 这个公式计算 x & y 轴的值
  const x = noiseX * innerWidth + randX;
  const y = noiseY * innerHeight + randY;
  ...
}

这里使用 input 控件来控制移动的参数,以查看速度和随机计算的值如何影响假鼠标移动。

<iframe id="result-iframe" class="result-iframe " sandbox="allow-forms allow-modals allow-pointer-lock allow-popups allow-presentation allow-same-origin allow-scripts" allow="geolocation; microphone; camera; midi; vr; accelerometer; gyroscope; payment; ambient-light-sensor; encrypted-media" tabindex="-1" data-src="https://s.codepen.io/Mamboleoo/fullembedgrid/8dddd6728db7770a7c7680e9a5503cfa?type=embed&amp;animations=run" src="https://s.codepen.io/Mamboleoo/fullembedgrid/8dddd6728db7770a7c7680e9a5503cfa?type=embed&amp;animations=run" allowtransparency="true" frameborder="0" scrolling="yes" allowpaymentrequest="true" allowfullscreen="true" name="CodePen Preview for Virtual user 4" title="CodePen Preview for Virtual user 4">

代码语言:javascript
复制
  </iframe>

更多鼠标

现在已经有一个假鼠标了,何不再创建 500 个呢?

<iframe id="result-iframe" class="result-iframe " sandbox="allow-forms allow-modals allow-pointer-lock allow-popups allow-presentation allow-same-origin allow-scripts" allow="geolocation; microphone; camera; midi; vr; accelerometer; gyroscope; payment; ambient-light-sensor; encrypted-media" tabindex="-1" data-src="https://s.codepen.io/Mamboleoo/fullembedgrid/8fe0544443b1ddae0e0258fb91d6b5ff?type=embed&amp;animations=run" src="https://s.codepen.io/Mamboleoo/fullembedgrid/8fe0544443b1ddae0e0258fb91d6b5ff?type=embed&amp;animations=run" allowtransparency="true" frameborder="0" scrolling="yes" allowpaymentrequest="true" allowfullscreen="true" name="CodePen Preview for Virtual user 5" title="CodePen Preview for Virtual user 5">

代码语言:javascript
复制
  </iframe>

我现在几乎所有的演示都使用这个技巧,我认为能够在不使用视频的情况下显示项目或者演示时自动移动鼠标真的很酷。

如果你有任何疑问或想法,请在下面发表评论或在 Twitter 上发帖。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 单形噪音
  • 获取噪音坐标
  • 允许交互
  • 控制移动
  • 更多鼠标
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档