从灭霸的无限手套提及

本文不是技术文章,只是单纯记录下

最近妇联4在热映,先剧透两个精彩片断。
图片描述图片描述php

前两天看到Google搜索有个彩蛋,搜索灭霸或者thanos,点击右边的无限手套触发彩蛋,打个响指,消灭一半的搜索结果条目,消失特效相似电影里的。
图片描述html

首先分析下这个彩蛋主要包括前端

  1. 点击手套动画效果
  2. 消失的搜索条目的粒子效果

接下来是从如下方面着手node

  1. html页面
  2. DOMcanvas
  3. 粒子效果
  4. 其余包括音效、页面平滑滚动等

html页面(扒网页)

首先排除扒Google搜索页面,由于服务器用的是国内阿里云访问不了。git

而后就打算扒百度的搜索页,用的是PHP程序,我知道的可以获取页面代码的有file_get_contentcURL函数,虽然拿到了页面代码,可是只要搜索结果那些DOM的话用正则比较麻烦,搜了下找到phpQuery库,它能像jQuery操做那样拿到指定DOM,和Node.js的cheerio包相似。可是百度的这个页面样式类是动态的,还要把整个style内容也输出,并且不少图片大概是通过了什么处理,没权限显示不了,遂放弃。github

接着扒斗鱼的直播列表页,返回一堆乱码,实力告退了。最后选择了类似的企鹅电竞直播列表页,页面算是搞定了。canvas

DOM转canvas

前端有html2canvasdom-to-image两个库能够把页面指定元素转化为画布或图片,html2canvas比较有名些,早期我也是用这个库作前端截图功能(https://imusic.github.io/clip/),可是它对CSS3的处理并很差,后来我发现了dom-to-image这个库,它对CSS3的处理就比较好了,并且体积更小,因此又用这个库替换了(https://demo.vczhan.com/clip/)。
图片描述跨域

不过由于要转化的内容里有跨域的图片,canvas对此作了限制,咱们须要对图片作代理处理。dom-to-image这个库并无提供相关的代理插件,最后仍是用html2canvas这个库。页面没有复杂的元素,而且这个库近来作了更新,对CSS3支持好了些,做者还提供了两种语言的代理,分别是Python版本的和Node.js版本的,不过我选择了其余人写的PHP版本。前端只要配置相关参数就能够。服务器端则会在文件目录下新建cache目录存放图片并返回给前端渲染到画布上。(不知可否改为不存储图片文件而是改为输出base64或者blob数据)服务器

html2canvas(node, {
  proxy: 'html2canvasproxy.php'
}).then(canvas => {
  // do stuff
})

粒子效果

粒子效果比较难的部分是怎么调整各个参数到合适的值还要保证动画不卡。其实js计算过程并不会让动画卡顿,主要瓶颈在渲染阶段。dom

渲染部分原来用遍历粒子直接绘制,但由于粒子较多,动画看起来有点卡。

render() {
  context.clearRect(0, 0, sw, sh)

  let particles = this.particles

  for (let i = 0, particle; particle = particles[i++];) {
    if (particle.state === 'dead') continue

    context.save()
    context.translate(particle.x, particle.y)

    context.fillStyle = particle.color
    context.globalAlpha = particle.alpha
    context.beginPath()
    context.fillRect(0, 0, 1, 1)
    context.restore()
  }
}

后来改为每次渲染时,先获得空白画布的图像数据,而后遍历粒子,给图像数据对应的位置加上rgba,最后将图像数据放回画布。

render() {
  // context.clearRect(0, 0, sw, sh)
  let particles = this.particles

  const imageData = context.createImageData(sw, sh)
  const buffer32 = new Uint32Array(imageData.data.buffer)

  for (let i = 0, particle; particle = particles[i++];) {
    if (particle.state === 'dead') continue

    const {x, y, color: {r, g, b}, alpha: a} = particle
    const pos = y * sw + x

    buffer32[pos] = r | (g << 8) | (b << 16) | (a << 24)
  }

  context.putImageData(imageData, 0, 0)
}

Google那个页面是用了多个canvas,能够参考下面的粒子
https://codepen.io/birjolaxew...

其余

其余就是些细节调整,好比点击手套的过渡动画并加上音效,过渡时间和延迟要慢慢调到合适的使动画与音效对应。当某个DOM要消失也要加上音效,而且页面平滑滚动,使其位于屏幕中心,能够直接用scrollIntoView这个方法。

node.scrollIntoView({behavior: 'smooth', block: 'center'})

素材均可以从Google彩蛋页里提取,还有其余一些细节就不逐一赘述了。

最后放上本次的demo

相关文章
相关标签/搜索