前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >如何用原生 JS 复刻 Bilibili 首页头图的视差交互效果

如何用原生 JS 复刻 Bilibili 首页头图的视差交互效果

原创
作者头像
茶无味的一天
发布于 2023-09-06 02:54:59
发布于 2023-09-06 02:54:59
47900
代码可运行
举报
文章被收录于专栏:品味前端品味前端
运行总次数:0
代码可运行

本文首发于公众号:品味前端,作者:茶无味de一天,转载请注明出处。

最近网上冲浪的时候,发现了 B 站这个首页头图的交互效果非常有趣,如下图所示,当鼠标在画面中左右滑动时,海洋生物会栩栩如生地动起来:

这是通过给图层设置不同的移动速度来实现的视差效果,在佩服 UI 与前端对网页交互效果方面的努力和探索之外,我也沉浸在这片“海洋”中疯狂摸鱼:尝试只使用原生 JS 来复刻它,最终实现了非常还原的效果:

可点击图片进入 码上掘金 中体验完整效果。

本文将一步步介绍整个制作思路,讲解涉及的相关知识点,干货非常多,搬好你的小板凳,咱们话不多说直接开摸吧。

准备工作

打开浏览器控制台,查看B站头图的 HTML 结构:

不难看出,我们接下来的思路就是把 banner 中所有的图片用一个 .layer 的 div 包住堆叠起来,然后编写鼠标事件对每张图片应用相应的变换(transform)操作,由于接下来的操作我们都用 JS 来完成,所以布局很简单,只需要一个 div 来充当容器

代码语言:html
AI代码解释
复制
<div id="app">loading...</div>

把图片素材通过 JS 添加进容器中,我们创建一个数组来描述这些图片,数据的结构暂时如下所示:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
const barnerImagesData = [
  {
    url: 'https://xxxx/abcdegfsa.webp',
  },
  {
    url: 'https://xxxx/dsaasdsaasdds.webp',
  }, ...........
]

注:完整数据在 https://code.juejin.cn/api/raw/7267103634863702050?id=7267103634863751202 ,这里包含了后续全部代码所需的内容

然后我们把 barnerImagesData 循环并添加到容器中:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
const body = document.getElementById('app')
let layers = []

function initItems() {
    body.style.display = 'none'
    for (let i = 0; i < barnerImagesData.length; i++) {
      const item = barnerImagesData[i]
      // 创建 layer
      const layer = document.createElement('div')
      layer.classList.add('layer')
      // 创建 imgage
      const img = document.createElement('img')
      img.src = item.url
      // 将 layer 添加到容器中
      layer.appendChild(img)
      body.appendChild(layer)
    }
    body.style.display = ''
    // 把创建好的 layers 缓存起来,方便后续操作
    layers = document.querySelectorAll(".layer")
}

initItems()

这里先给容器设置 display: 'none' 的作用是,无论添加多少图片都只会回流重绘两次。

接着我们稍微完善一下样式,给容器设定一个高度,把每个图层都绝对定位堆在一起:

代码语言:css
AI代码解释
复制
#app {
  position: relative;
  overflow: hidden;
  min-width: 1000px;
  min-height: 155px;
  height: 10vw;
  max-height: 240px;
}

.layer {
    position: absolute;
    left: 0;
    top: 0;
    height: 100%;
    width: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
}

准备工作就完成了,你会看到如下的界面,所有元素我们都添加了进来:

现在层次已经有了,图片位置还很乱,需要给它们设置上初始偏移值来调整位置,但先不急,让我们先看看贯穿整个交互方式的鼠标事件。

鼠标事件 & 执行动画

我们这里主要会用到三个鼠标事件,分别是 mouseovermousemovemouseleave,分别代表鼠标的进入事件移动事件以及离开事件,我们将在容器上绑定这三个事件监听,在鼠标进入时记录初始化位置,鼠标移动时减去初始值就得到偏移值,这个偏移值将是接下来所有变换的核心系数,这里我们取 clientXPageX 来计算偏移量,相关代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
const body = document.getElementById('app')
let initX = 0 // 初始值
let moveX = 0 // 偏移值

body.addEventListener('mouseover', (e) => initX = e.pageX)
body.addEventListener('mousemove', (e) => {
  moveX = e.pageX - initX
})

获取到偏移值后,我想你已经迫不及待地想要让画面跟随鼠标动起来了,我们先来尝试一下吧,CSS 变换属性为 transform,它可以接收多个值,其中 translate() 可以让元素发生偏移,从而改变显示位置,接下来我们即是要将偏移值应用到其中,我们定义一个 animate 方法用于执行动画,该方法中循环取出所有元素并应用变换:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 动画执行
function animate() {
  for (let i = 0; i < layers.length; i++) {
    const layer = layers[i];
    layer.style.transform = `translate(${moveX}px, 0)`
  }
}

接着在前面的 mousemove 回调事件中加入 animate(),此时画面里移动鼠标,所有图片应该都会紧紧跟随鼠标的位置而变化了,但在浏览器中,我们通常不会这么执行动画,而是采用 requestAnimationFrame 来辅助执行,它会通过浏览器的刷新频率来调度动画帧,自动以最佳的性能进行渲染,修改代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
body.addEventListener('mousemove', (e) => {
  moveX = e.pageX - initX
  requestAnimationFrame(mouseMove)
})

function mouseMove() { // 滑动操作
  animate()
}

滑动就会看到如下效果:

到这里都还没什么难度,虽然离最终效果相距甚远,但基本就只剩下对细节的亿点处理了,我们来具体看看B站是怎么做的。

视差效果原理

在视差效果中,通常会使用多张具有不同视角的图片或分层的图像,通过透视、位移等处理方式,让观察者感受到物体的前后关系和深度差异。

我们打开控制台观察B站首页头图对应的 DOM 结构,会看到处理的对应变换包括了:平移(translate)、旋转(rotate)、缩放(scale)等,此外还有透明度可能也会随之改变。

通过鼠标移动产生的偏移值,我们可以按一定比例设置对应的变换属性来达到最终效果,不过这里我并不打算使用跟B站一样的实现方式,让我们来上点强度,只使用矩阵变换 matrix 来实现 transform 中的三种变换。

二维矩阵变换

很多人可能对 matrix 感到陌生,实际上平时我们常使用的 translaterotate 等变换操作都是语法糖,是为了更加符合开发直觉而设计出来的,最终它们都会被转化成矩阵进行二维变换,它的基本形式是这样的:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
matrix(a, b, c, d, e, f)

这里的 abcdef 共6个参数,默认值是 1,0,0,1,0,0,按顺序拆开来分别是:

  • x 轴系数:(1,0)
  • y 轴系数:(0,1)
  • 偏移绝对值:(0,0)

我们把第一个坐标点表示在如下的坐标轴上:

第二个点是在 y 轴上:

通过这两个点与原点我们可以确定一个图形:(注意这里是倍数,1就是保持原样的意思)

如果我要把图形拉宽 2 倍那就是改变第一个坐标为 (2,0),同理,如果将图形变高 1.5 倍就是改变第二个坐标点为 (0,1.5),如下所示:

如此变换过程编写为 CSS 就是:

代码语言:css
AI代码解释
复制
transform: matrix(2,0,0,1.5,0,0);

即等价于:

代码语言:css
AI代码解释
复制
transform: scale(2, 1.5)

学会了如上这一基础变换,后面我们实现等比缩放的操作就非常简单了,往这两个系数乘上一个缩放倍数(假设为 s)即可,公式表示如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
matrix(s * x, 0, 0, s * y, 0, 0)

而平移就更简单了,第三个坐标点即代表平移的 x y 值,例如我们将图形向右平移 100 个像素:

只需在 x 上增加 100 即可,前面两个点不需要动,CSS 编写为:

代码语言:css
AI代码解释
复制
transform: matrix(1,0,0,1,100,0);

等价于:

代码语言:css
AI代码解释
复制
transform: translateX(100px);

如果图形向左偏移,那么 x 就加上负的 100,如何上下平移相信也不用我多说了吧。

关于矩阵变换先搞懂这些就行,旋转后面会讲到,我们接着回到正题中。

调整初始位置

修改第一步的数组结构,添加一些初始值,大致结构如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
const barnerImagesData = [
  {
    url: 'https://xxxx/xxxxxxx.webp',
    transform: [1, 0, 0, 1, 0, 0],
    width: 1950,
    blur: 0
  }, ...........
]

注:之后我也会像这样增加一些“参数”,将不再赘述,完整数据在这里 https://code.juejin.cn/api/raw/7267103634863702050?id=7267103634863751202

其中 transform 值就是为这些海洋生物所提供的初始位置了,我们在前面的 initItems 方法中编写相应代码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function initItems() {
    .........
      layer.classList.add('layer')
      layer.style = 'transform:' + new DOMMatrix(item.transform)
      // 创建 imgage
      const img = document.createElement('img')
      img.src = item.url
      img.style.filter = `blur(${item.blur}px)`
      img.style.width = `${item.width}px`
    ...........
}

我们用 new DOMMatrix 方法将数组实例化为 matrix,赋值给 CSS 的 transform 属性,同时我们也定义了一些图片的宽度和模糊值,这里使用 CSS filter: blur() 来实现高斯模糊,给靠前面的水草等几个图层添加模糊值,使场景更真实,更符合人眼聚焦画面主体时的环境感受。

代码编写完毕,对数据进行亿番调整后,画面已经基本和B站一致了:

平移与缩放

我们继续完善鼠标交互效果,让原本紧贴鼠标移动的图层按不同速度进行移动,以此实现最基本的视差效果,为此我添加了一个参数 a 用来代表加速度,不同图层有不同的加速度,加速度越快代表移动幅度越大,我们修改 animate 函数:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function animate() {
  for (let i = 0; i < layers.length; i++) {
    const layer = layers[i];
    const item = barnerImagesData[i]
    let m = new DOMMatrix(item.transform)
    let move = moveX * item.a // 移动X translateX
    m = m.multiply(new DOMMatrix([1, 0, 0, 1, move, 0]))
    layer.style.transform = m // 应用所有变换效果
  }
}

注意到了吗,矩阵变换的一个重要特性就是,它可以通过乘积进行多次变换

以往使用常规手段进行变换时,例如我先写了一个:transform: rotate(45deg); 进行旋转,之后想再进行平移就必须这么写:transform: rotate(45deg) translate(100, 0);,而不是直接写 translate 就行,不然前面的旋转角就丢失了。但是使用矩阵则不同,你可以把多次变换乘起来得到最终的变换结果。

前面的左右平移比较单一,接下来我继续添加参数 g 来表示重力,参数 f 表示每一帧的缩放幅度,以此来为画面增加一些动态细节,继续修改代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function animate() {
    .........
    let s = item.f ? item.f * moveX + 1 : 1 // 放大比例 Scale
    let g = moveX * (item.g || 0) // 移动Y translateY
    m = m.multiply(new DOMMatrix([m.a * s, m.b, m.c, m.d * s, move, g]))
    .........
}

如此根据重力不同,就可以控制鱼往上浮还是往下游:

而根据缩放系数不同,就可以模拟远近大小的变化,例如画面中的乌龟是往靠近镜头的方向游动的,那么它在视野中就会越来越大,反之则缩小:

透明度处理

我们看到画面中央的那撮气泡一开始就出现有点不太合理,我们需要在移动过程中改变透明度,在数据中添加参数 opacity 来表示透明度变化,它应该是一个区间比较合理,表示一个变化过程。例如 [0,1] 表示一开始是不可见的,随着移动过后逐渐显现,反之 [1,0] 则表示逐渐透明消失的过程,相关代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function initItems() {
  .......
  // 初始化时设置起始透明度
    item.opacity && (layer.style.opacity = item.opacity[0])
    ......
}
// 动画执行
function animate(progress) {
  ........
    if (item.opacity) { // 有透明度变化
      layer.style.opacity = isHoming && moveX > 0 ? lerp(item.opacity[1], item.opacity[0], progress) : lerp(item.opacity[0], item.opacity[1], moveX / window.innerWidth * 2)
    }
    ........
}

矩阵旋转

上面其实我们已经完成了 90% 的效果了,但和B站的效果相比还是有点差距,通过观察我发现乌龟在前进的过程中还带有一点旋转的角度。

再次为数据添加参数 deg 来表示每一帧的旋转角度,当存在角度时乘以新矩阵 [Math.cos(deg), Math.sin(deg), -Math.sin(deg), Math.cos(deg),0,0](旋转时不发生位移,所以第三个坐标应为 0,0),我们为 animate 函数增加如下代码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function animate() {
  .........
    if (item.deg) { // 有旋转角度
      const deg = item.deg * moveX
      m = m.multiply(new DOMMatrix([Math.cos(deg), Math.sin(deg), -Math.sin(deg), Math.cos(deg), 0, 0]))
    }
    .........
}

来感受下加入一定的旋转角度后是什么效果:

画面更加灵动自然了,基本和B站的效果无差,感觉海洋生物们都栩栩如生起来了捏~

矩阵旋转推导过程

这里补充一下旋转的四个值是如何推导而来的,首先帮大家回忆一下中学时的三角函数,在如图所示的直角三角形中,我们有 A、B、C 三个角,每个角的对边我们记作小写 a、b、c:

然后我们会有边长比值的公式:

  • 正弦(sin):sin(A) = a / c,对边比斜边。
  • 余弦(cos):cos(A) = b / c,邻边比斜边。
  • 正切(tan):tan(A) = a / b,对边比领边。

当旋转一定角度 θ 时,我们画出图形的变化,如下图,矩阵的第一个点 ( x , y ) 变为 ( x‘ , y‘ ),要求得变化后的 x’y‘,我们先把它与 θ 角围成的三角形画出来,并标记其三条边:

代入参数可得:

正弦

余弦

接着我们根据上面两条公式分别得出坐标点:

x' = x * cos(θ)

y' = x * sin(θ)

前面我们讲矩阵的时候已经知道了,这个( x , y )点其实就是 ( 1 , 0 ),代入 x = 1 我们得到 ( x‘ , y‘ ) 点坐标值为: ( cos(θ) , sin(θ) )

我们继续看另一个点,还是把变化与夹角的三角形画出来:

同样地,得到下面的正余弦:

正弦

余弦

然后得出坐标点:

x' = y * sin(θ)

y' = y * cos(θ)

矩阵第二个坐标为 ( 0 , 1 ),将 y = 1 代入得到这个点的坐标为: ( -sin(θ) , cos(θ) ),注意这个点的 x 是在负半轴上,所以要加上负号。

以上,我们就推导出了二维矩阵的旋转变换为:

matrix(cosθ, sinθ, -sinθ, cosθ, 0, 0)

位置回正

到这里整个交互还没有结束,当前在鼠标离开时,画面会停滞住,这样鼠标下次进入画面时也会闪动,所以需在离开时自动回正到初始位置上才行,我们先注册相关事件:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 鼠标已经离开了视窗或者切出浏览器,执行回正动画
body.addEventListener("mouseleave", leave)
window.onblur = leave

leave 函数里将初始的 matrix 逐一取出并应用到图像上的话,画面会瞬间闪动,这并不优雅,所以我们需要让它们平滑恢复到初始位置,通常我们可能会这么做:先设置一个样式比如 transition: all .3s; 这表示变换效果将会缓动并在 300ms 后完成,但是这个样式不能在一开始就写上,不然前面的画面移动效果也会受到影响,所以得在执行回正时才设置,其它情况下则移除。

这种方式虽然没什么问题,但需要额外利用 CSS 才能实现,能不能只用 JS 来做呢,我们先分析下 transition 中两个主要的参数:

  1. 持续时间
  2. 动画函数

其实只要搞懂这两个参数,我们就可以用 JS 来实现 CSS 中的平滑缓动效果。

动画进度

先看持续时间,这个参数表明动画在经过一个明确的时间后结束,虽然持续时间是个变量,但无论动画持续多久,都是一个从 0% 变化到 100% 的过程,所以我们要把时间转化为能被确定的进度

requestAnimationFrame 每一帧执行时回调函数会接收一个参数 timestamp,我们可以以此来计算出进度:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
let startTime;
const duration = 300; // 动画持续时间(毫秒)

function leave() {
  startTime = 0; // 离开时初始值归零
  requestAnimationFrame(homing); // 开始回弹动画
}

function homing(timestamp) {
  !startTime &&( startTime = timestamp)
  const elapsed = timestamp - startTime // 计算经过时间
  const progress = Math.min(elapsed / duration, 1)
  progress < 1 && requestAnimationFrame(homing) // 继续下一帧
  console.log(progress)
}

elapsed 是经过的时间,duration 是过渡的总持续时间。通过将这两个值相除,可以得到一个 01 之间的进度比例,另外别忘了使用 Math.min 函数将进度值与 1 比较,取最小值,确保进度不会超过 1

我们依旧使用 animate 函数进行动画操作,为它传入 progress 参数,后面判断当 isHomingtrue 时即执行回正动画:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function homing(timestamp) {
  .........
  animate(progress) // 传递动画进度
}
function animate(progress) {
  // 若传入进度则判断为执行回正
  const isHoming = typeof progress === 'number'
  ............
}

线性差值

在 CSS 中,transition 属性包含多种动画函数,而我们当前场景没有那么复杂的动画需求,只需要在过渡期间保持匀速平滑运动即可。

线性插值是一种简单的插值方法,它使用线性函数来计算过渡过程中的值。简单来说,它是一种通过直线来连接两个点,在两个点之间按比例计算中间的数值。线性插值可以用于各种场景,比如在图形学中计算两个点之间的中间点,或者在动画中实现平滑的过渡效果。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 计算线性插值
const lerp = (start, end, amt) => (1 - amt) * start + amt * end;

该函数接收一个起始值 start目标值 end,插值系数:amt是在 01 之间的值,表示过渡的进度比例。我们在回正动画处理中,通过每一帧的这三个入参,返回对应的计算结果应用到矩阵变换中:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function animate(progress) {
  ............
  if (isHoming) { // 回正时处理
      m.e = lerp(moveX * item.a + item.transform[4], item.transform[4], progress)
      move = 0
      s = lerp(item.f ? item.f * moveX + 1 : 1, 1, progress)
      g = lerp(item.g ? item.g * moveX : 0, 0, progress)
    }
  .........
  if (item.deg) { // 有旋转角度
      const deg = isHoming ? lerp(item.deg * moveX, 0, progress) : item.deg * moveX
  ...........
}

进度控制了动画过程,线性函数描述了动画曲线,缓动效果就这样实现了,至此,整个交互效果就和开头演示时一样了。

加餐

本来到这里就该结束了,但正好在文章写完那天,我登录B站时发现首页头图更新了。。那敢情好啊,我就把新出的效果也复刻一下吧!不过上面的代码是一行也不用改动的,只需要换一套数据就行了。

打开B站,把以下代码粘贴在控制台(可能需要滑动一下头图),回车。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
const layersEl = document.getElementsByClassName('animated-banner')[0].getElementsByClassName('layer');
let layers = [];
const pattern = /translate\(([-.\d]+px), ([-.\d]+px)\)/;
for (let i = 0; i < layersEl.length; i++) {
    const {width, height, src, style} = layersEl[i].firstElementChild;
    const matches = style.transform.match(pattern);
    const transform = [1,0,0,1,...matches.slice(1).map(x => +x.replace('px', ''))]
    layers.push({width, height, url:src, transform, a: 0.01})
}
JSON.stringify(layers)

把打印的数据拷贝出来,图片链接自行保存后替换,接下来就是对着B站的效果微调变换参数啦,这次的更新整体比之前的还简单些,不一会就调校完毕了,鳄鱼那部分实现逻辑较有出入,但无伤大雅,看看效果:

完整代码

前往码上掘金查看完整代码及体验效果:https://code.juejin.cn/pen/7267433230263910460

核心代码只有几十行,你可以通过改变数据中的各项值来调整画面元素的交互变化程度及效果,大家觉得这波原生 JS 整活如何?欢迎在评论区说说你的想法~

最后让我们来回顾下,虽然整体效果看上去似乎也不算难,但本文知识点还是蛮多的,首先是如何利用鼠标事件计算以及执行动画;知道了什么是矩阵变换以及如何使用它实现平移旋转缩放等操作;利用三角函数推导了矩阵旋转的原理;使用线性差值函数实现了缓动回弹动画等。

以上就是文章的全部内容了,感谢看到这里!如果觉得写得还不错,对你有所帮助或启发,别忘了点赞收藏关注“一键三连”哦~ 我是茶无味,一名平凡的前端 Developer,希望与你共同成长~

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

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

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

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

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
不用3d引擎实现炫酷“真”裸眼3d效果!
第一种对性能要求比较大,毕竟需要页面进行3d渲染;第二种属于一种伪3d效果,图片都是平面的,并不会因为视角的切换看到另一面的东西。
治电小白菜
2025/01/02
2750
不用3d引擎实现炫酷“真”裸眼3d效果!
SVG 动画精髓(上)
本文作者:ivweb villainthr TL;DR 本文主要是讲解关于 SVG 的一些高级动画特效,比如 SVG 动画标签,图形渐变,路径动画,线条动画,SVG 裁剪等。 例如:路径动画 图形
腾讯IVWEB团队
2017/07/06
3.8K0
SVG 动画精髓(上)
前端游戏巨制! CSS居然可以做3D游戏了
了解过css3D属性的同学应该都了解过perspective、perspective-origin、transform-style: preserve-3d这个三个属性值, 它们构成了CSS的3d世界.
Nealyang
2021/09/27
2.4K0
前端游戏巨制! CSS居然可以做3D游戏了
SVG 动画精髓
TL;DR 本文主要是讲解关于 SVG 的一些高级动画特效,比如 SVG 动画标签,图形渐变,路径动画,线条动画,SVG 裁剪等。 例如:路径动画 图形渐变: 线条动画: 以及,相关的动画的矩阵知识,
villainhr
2018/07/03
3.5K0
【愚公系列】2023年12月 WEBGL专题-图形旋转矩阵
这些操作常常用于计算机图形学、图像处理等领域中的图像变换。图形平移、缩放、旋转是计算机图形学中常用的操作,用来改变图像的位置、大小和方向。
愚公搬代码
2025/05/28
840
【愚公系列】2023年12月 WEBGL专题-图形旋转矩阵
吕布的回城特效有了,貂蝉的也要有,用css3制作一款貂蝉的简易回城特效
前两天用css3写了一个吕布的回城特效,感觉还行,不过吕布有了,作为吕布对象的貂蝉怎么能没有呢?今天就来用css3再给貂蝉也来一套,写的不好不要喷我哦
十里青山
2022/08/22
5880
吕布的回城特效有了,貂蝉的也要有,用css3制作一款貂蝉的简易回城特效
【Flutter 专题】45 图解矩阵变换 Transform 类 (二)
和尚刚学习了 Transform 类,其核心部分在于矩阵变换,而矩阵变换是由 Matrix4 处理的,且无论是如何的平移旋转等操作,根本上还是一个四阶矩阵操作的;接下来和尚学习一下 Matrix4 的基本用法;
阿策小和尚
2019/08/12
1.6K0
【Flutter 专题】45 图解矩阵变换 Transform 类 (二)
65.Harmonyos NEXT 图片预览组件之手势处理实现(三)
在前两篇文章中,我们介绍了图片预览组件的单指拖动、双指缩放和双指旋转手势实现。本文将继续介绍双击缩放手势的实现细节,以及手势之间的协同工作机制。
全栈若城
2025/03/14
1510
实现3D环绕效果的图片展示技术探索
本文将介绍如何使用现代前端技术实现3D环绕效果的图片展示。我们将通过详细的步骤和代码示例,探索如何实现这种富有创意和吸引力的视觉效果,从而提升用户体验和网站互动性。
大盘鸡拌面
2024/04/25
5600
Canvas系列(7):形变
CSS3中有一个很重要的点,就是形变。他分为移动,缩放、旋转和倾斜。在Canvas中,形变都是基于坐标做的,所以,并没有直接的API支持倾斜,其它几种都是有独立的API来支持,命名和CSS是一样的。今天我们就看一下这几种吧。
kai666666
2020/10/17
5890
第4章代码-图形几何变换
目录 4.4 编程实例——三角形与矩形变换及动画 4.4.1 自定义矩阵变换实例——三角形变换 4.4.2 OpenGL几何变换实例——矩形变换 4.4.3 变换应用实例——正方形旋转动画 4.4
步行者08
2020/09/19
7340
用初中数学知识撸一个canvas环形进度条
周末好,今天给大家带来一款接地气的环形进度条组件vue-awesome-progress。近日被设计小姐姐要求实现这么一个环形进度条效果,大体由四部分组成,分别是底色圆环,进度弧,环内文字,进度圆点。设计稿截图如下:
程序员白彬
2020/07/10
1K0
用初中数学知识撸一个canvas环形进度条
【CSS】398- 原生JS实现DOM爆炸效果
此次分享是一次自我组件开发的总结,还是有很多不足之处,望各位大大多提宝贵意见,互相学习交流。
pingan8787
2019/11/05
3.6K0
学到了!Figma 原来是这样表示矩形的
对一些简单的图形编辑操作,这些属性基本上是够用的,比如白板工具,如果你不考虑或者不希望图形可以翻转(flip) 的话。
前端西瓜哥
2023/12/20
2770
学到了!Figma 原来是这样表示矩形的
Flutter 绘制探索 | 绘制中的动画变换
这篇文章来通过一个有趣的案例,介绍一下 绘制中的动画变换 ,以及如何在当前的变换基础上,叠加变换。如下所示,小车在界面上呈现的任何变动,都是变换矩阵作用的效果: 注: gif 图片为 15fps ,有些卡顿,非实际动画运行效果
张风捷特烈
2023/04/23
1.3K0
Flutter 绘制探索 | 绘制中的动画变换
iOS动画系列之一:带时分秒指针的时钟动画(上)1. 最终实现的效果以及思维导图2. CALayer3. 隐式动画
1. 最终实现的效果以及思维导图 实现的效果。不小心暴露了写文章的时间。-_-+++ 实现效果 实现的步骤思维导图: 思维导图.png 2. CALayer 其实今天分享的主角是CALayer。因为所
stanbai
2018/06/28
2.2K0
视差特效的原理和实现方法
本文的 『推荐』 部分也别错过喔~ 因为日常开发很少使用原生的方式去做视差效果。
德育处主任
2022/04/17
2.1K0
视差特效的原理和实现方法
用初中数学知识撸一个canvas环形进度条
周一好,今天给大家带来一款接地气的环形进度条组件vue-awesome-progress。近日被设计小姐姐要求实现这么一个环形进度条效果,大体由四部分组成,分别是底色圆环,进度弧,环内文字,进度圆点。设计稿截图如下:
Sneaker-前端公虾米
2021/06/21
6360
用初中数学知识撸一个canvas环形进度条
CSS3 transform 和 canvas 背后不为人知的秘密
身为一个合格切图仔,CSS3 的 transfrom 那是熟的不能再熟,什么平移、缩放、旋转更是信手捏来,完全没有难度。不过碰到 transform: matrix() 这个样式,立刻脑袋一片空白,这个 matrix() CSS 函数接收高达 6 个参数!完全不知道它是用来干啥的,去看官方文档也完全没说,一条下面这个简单的样式。
羽月
2022/10/08
1.2K0
CSS3 transform 和 canvas 背后不为人知的秘密
音视频开发之旅(63) -Lottie 源码分析之动画与绘制
上一篇我们学习分析了Lottie的json解析部分. 这篇我们分析的动画和渲染部分。
音视频开发之旅
2022/01/16
9730
音视频开发之旅(63) -Lottie 源码分析之动画与绘制
相关推荐
不用3d引擎实现炫酷“真”裸眼3d效果!
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验