看過復仇者聯盟的都知道,滅霸做爲計劃生育政策的堅決支持者和執行者,一個響指清除了宇宙中二分之一的生命。電影中被清除的生命灰飛煙滅的鏡頭非常酷炫,因此在復聯4上映後,那個不存在的網站google,推出了一個彩蛋,若是在搜索框搜索滅霸,會出現一個手套的按鈕,點擊後會讓網頁搜索結果消失一半。 javascript
咱們這裏只用一個圖片元素,HTML結構以下html
<body>
<div class="content">
<div id="image">
<!-- 圖片爲網絡地址纔可在本地經過直接打開html調試 -->
<img src="https://i.loli.net/2019/05/06/5ccffa469ec52.jpg" width="400" />
</div>
</div>
</body>
複製代碼
const imageBox = document.querySelector('#image')
html2canvas(imageBox, {
backgroundColor: 'transparent' //背景設置爲透明
}).then(canvas=>{
//處理canvas的代碼(注意.then這種寫法只有在新版本的html2canvas可用)
});
複製代碼
//處理canvas的代碼
const ctx = canvas.getContext('2d');
const imageData = ctx.getImageData(
0,
0,
canvas.width,
canvas.height
);
const pixelArr = imageData.data; //像素信息
複製代碼
圖像信息被存儲在一個Uint8ClampedArray(8位無符號整型固定數組)中,這個數組中的值爲0到255的整數,按圖片中像素從左到右從上到下的順序,每4個數字表示一個像素信息,這4個數字分別表示rgba(r-紅色,g-綠,b-藍色,a-透明度)的四個值。 好比這樣一個圖片java
[0,0,0,255,255,255,255,255,255,0,0,255,0,255,0,255]
複製代碼
//建立一個和圖像信息數組長度相同的數組並填充0(至關於一個和原圖像尺寸相同的透明圖像)
const data = pixelArr.slice(0).fill(0);
//建立透明圖像數組的個數,不能過小也不能太大。
const canvasCount = 30;
//將透明圖像數組複製多個
const imageDataArray = Array.from({ length: canvasCount }, () =>
data.slice(0)
);
//將原圖像上的像素信息隨機分配進不一樣的透明圖象上,位置保持不變
for (let i = 0; i < pixelArr.length; i += 4) {
const p = Math.floor((i / pixelArr.length) * canvasCount);
//a爲隨機選出要放入像素信息的數組
const a = imageDataArray[Math.floor(Math.random() * canvasCount];
//將像素信息放入隨機到的透明圖像數組中覆蓋
a[i] = pixelArr[i];
a[i + 1] = pixelArr[i + 1];
a[i + 2] = pixelArr[i + 2];
a[i + 3] = pixelArr[i + 3];
}
複製代碼
當canvasCount爲3時效果以下:
原始圖片canvas
生成的包含原圖部分像素的3個canvas
canvasCount越大,生成的canvas越多,分配到每一個canvas上面的像素就越少,飄的就越散。
4. 接下來就很是簡單了,隱藏掉原始圖像,爲生成的canvas添加飄散動畫就能夠了,飄散動畫主要組成就是高斯模糊,位移,旋轉,透明度變化,具體代碼這裏就不寫了,能夠在demo源代碼中看到,最終效果以下。canvas
灰飛煙滅的動畫已經完成,接下來是如何觸發這段動畫,文章開始就說過谷歌搜索上的原始效果是經過點擊按鈕觸發,而咱們經過麥克風實時檢測輸入音量,當打響指時(音量達到必定大小)觸發動畫。數組
if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
// 獲取用戶的 media 信息
navigator.mediaDevices
.getUserMedia({ audio: true })
.then(stream => {
//音頻處理代碼
})
.catch(error => {
mystatus.innerHTML = '獲取音頻時好像出了點問題。' + error;
});
} else {
mystatus.innerHTML = '不支持獲取媒體接口';
}
複製代碼
// 當輸入音量超過此值時,表示檢測大音量輸入(響指聲)
const TRIGGER_VALUE = 0.9;
// 將麥克風的聲音輸入這個對象
mediaStreamSource = audioContext.createMediaStreamSource(
stream
);
// 建立一個音頻分析對象,採樣的緩衝區大小爲4096,輸入和輸出都是單聲道
scriptProcessor = audioContext.createScriptProcessor(
4096,
1,
1
);
// 將該分析對象與麥克風音頻進行鏈接
mediaStreamSource.connect(scriptProcessor);
// 此舉無甚效果,僅僅是由於解決 Chrome 自身的 bug
scriptProcessor.connect(audioContext.destination);
// 開始處理音頻
scriptProcessor.onaudioprocess = function(e) {
// 得到緩衝區的輸入音頻,轉換爲包含了PCM通道數據的32位浮點數組
let buffer = e.inputBuffer.getChannelData(0);
// 獲取緩衝區中最大的音量值
let maxVal = Math.max.apply(Math, buffer);
// 顯示音量值
if (maxVal > TRIGGER_VALUE) {
//灰飛煙滅動畫
start();
}
};
複製代碼
一切搞定,就這麼簡單能夠拿去裝逼了,不過我同事問我,只能監測音量大小嗎,這樣的話不論是咳嗽聲,大喊一聲,啪啪啪聲均可以觸發,能不能真的只檢測響指的聲音。 嗯~這是個好問題,你們一塊兒想一想吧。網絡