本文不是技術文章,只是單純記錄下
最近婦聯4在熱映,先劇透兩個精彩片段。
前兩天看到Google搜尋有個彩蛋,搜尋滅霸
或者thanos
,點選右邊的無限手套觸發彩蛋,打個響指,消滅一半的搜尋結果條目,消失特效類似電影裡的。
首先分析下這個彩蛋主要包括
- 點選手套動畫效果
- 消失的搜尋條目的粒子效果
接下來是從以下方面著手
- html頁面
-
DOM
轉canvas
- 粒子效果
- 其他包括音效、頁面平滑滾動等
html頁面(扒網頁)
首先排除扒Google搜尋頁面,因為伺服器用的是國內阿里雲訪問不了。
然後就打算扒百度的搜尋頁,用的是PHP
程式,我知道的能夠獲取頁面程式碼的有file_get_content
和cURL
函式,雖然拿到了頁面程式碼,但是隻要搜尋結果那些DOM的話用正則比較麻煩,搜了下找到phpQuery庫,它能像jQuery
操作那樣拿到指定DOM,和Node.js的cheerio
包類似。但是百度的這個頁面樣式類是動態的,還要把整個style內容也輸出,而且很多圖片大概是經過了什麼處理,沒許可權顯示不了,遂放棄。
接著扒鬥魚的直播列表頁,返回一堆亂碼,實力告退了。最後選擇了相似的企鵝電競直播列表頁,頁面算是搞定了。
DOM轉canvas
前端有html2canvas和dom-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計算過程並不會讓動畫卡頓,主要瓶頸在渲染階段。
渲染部分原來用遍歷粒子直接繪製,但因為粒子較多,動畫看起來有點卡。
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