從滅霸的無限手套提及

本文不是技術文章,只是單純記錄下

最近婦聯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

相關文章
相關標籤/搜索