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