JavaScript利用canvas實(shí)現(xiàn)炫酷的碎片切圖效果
前言
今天分享一個(gè)炫酷的碎片式切圖效果,這個(gè)其實(shí)在自己的之前的博客上有實(shí)現(xiàn)過,本人覺得這個(gè)效果還是挺炫酷的,這次還是用我們的canvas來實(shí)現(xiàn),代碼量不多,但有些地方還是需要花點(diǎn)時(shí)間去理解的,需要點(diǎn)數(shù)學(xué)幾何理解能力,老規(guī)矩,我們還是先看效果再來看實(shí)現(xiàn)步驟。

需求分析
從上面我們看到圖片在切換的時(shí)候其實(shí)是一個(gè)一個(gè)的小碎片慢慢從點(diǎn)擊位置往外擴(kuò)散開來,這一個(gè)個(gè)小碎片,在頁(yè)面中其實(shí)就是一個(gè)個(gè)的小方塊。這里的難點(diǎn)在于如何將一張完整的圖片切割成一個(gè)一個(gè)的小方塊分別進(jìn)行渲染,還有就是這個(gè)棱形圖案的位置確定。
- 切割:這里我們可以以坐標(biāo)系的形式來進(jìn)行切割,每一個(gè)方塊都對(duì)應(yīng)著它們自己在坐標(biāo)系中的位置(x, y)
- 繪制:這里的重點(diǎn)在于drawImage方法
- 棱形擴(kuò)散:這里需要點(diǎn)數(shù)學(xué)幾何理解能力,后面作圖理解
實(shí)現(xiàn)過程
坐標(biāo)系
在實(shí)現(xiàn)之前,我們先來理解一個(gè)概念:「坐標(biāo)系」
注意:這里所說的坐標(biāo)系不是我們數(shù)學(xué)中的坐標(biāo)系,但兩者又有些類似,不同點(diǎn)在于兩者的原點(diǎn)位置以及y軸的方向不同。

切割
這一步主要是為了確定每一個(gè)單元格的大小,單元格的長(zhǎng)寬最好不要是最大公約數(shù)或最小公約數(shù),因?yàn)檫^大效果不夠炫,過小性能會(huì)有壓力。
我這里畫板長(zhǎng)寬為 800 * 530 ,選取 16 * 15 為單元尺寸,即整個(gè)畫布由 50 * 35 共 1750 個(gè)單元格組成。切割分完單元格之后我們需要先計(jì)算一些基本的參數(shù)備用。
this.imgW?=?800;?//?圖片原始寬 this.imgH?=?530;?//?圖片原始高 this.conW?=?800;?//?畫布寬 this.conH?=?530;?//??畫布高 this.dw?=?16;?//?單元格寬 this.dh?=?15;?//?單元格高 this.I?=?this.conH?/?this.dh;?//單元行數(shù) this.J?=?this.conW?/?this.dw;?//?單元列數(shù) this.DW?=?this.imgW?/?this.J;?//?原圖單元寬 this.DH?=?this.imgH?/?this.I;?//?原圖單元高
「行數(shù) = 畫布高度 / 單元格高度;列數(shù) = 畫面寬度 / 單元格寬度」
繪制
本次繪制的重點(diǎn)在于drawImage這個(gè)方法,我們可以先來了解一下這個(gè)方法的參數(shù)及功能
drawImage
drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight)
這個(gè)方法一共有9個(gè)參數(shù),作用是在畫布上繪制圖像??吹竭@么多參數(shù)是不是已經(jīng)被勸退了,哈哈
- 「image」:繪制到上下文的元素。允許任何的畫布圖像源,例如:
HTMLImageElement、SVGImageElement、HTMLVideoElement、HTMLCanvasElement、ImageBitmap、OffscreenCanvas或VideoFrame。 - 「sx」:(可選)需要繪制到目標(biāo)上下文中的,
image的矩形(裁剪)選擇框的左上角 X 軸坐標(biāo)??梢允褂?3 參數(shù)或 5 參數(shù)語(yǔ)法來省略這個(gè)參數(shù)。 - 「s y」:(可選)需要繪制到目標(biāo)上下文中的,
image的矩形(裁剪)選擇框的左上角 Y 軸坐標(biāo)??梢允褂?3 參數(shù)或 5 參數(shù)語(yǔ)法來省略這個(gè)參數(shù)。 - 「sWidth」:(可選)需要繪制到目標(biāo)上下文中的,
image的矩形(裁剪)選擇框的寬度。如果不說明,整個(gè)矩形(裁剪)從坐標(biāo)的sx和sy開始,到image的右下角結(jié)束??梢允褂?3 參數(shù)或 5 參數(shù)語(yǔ)法來省略這個(gè)參數(shù)。使用負(fù)值將翻轉(zhuǎn)這個(gè)圖像。 - 「sHeight」:(可選)需要繪制到目標(biāo)上下文中的,
image的矩形(裁剪)選擇框的高度。使用負(fù)值將翻轉(zhuǎn)這個(gè)圖像。 - 「dx」:
image的左上角在目標(biāo)畫布上 X 軸坐標(biāo)。 - 「dy」:
image的左上角在目標(biāo)畫布上 Y 軸坐標(biāo)。 - 「dWidth」:
image在目標(biāo)畫布上繪制的寬度。允許對(duì)繪制的image進(jìn)行縮放。如果不說明,在繪制時(shí)image寬度不會(huì)縮放。注意,這個(gè)參數(shù)不包含在 3 參數(shù)語(yǔ)法中。 - 「dHeight」:
image在目標(biāo)畫布上繪制的高度。允許對(duì)繪制的image進(jìn)行縮放。如果不說明,在繪制時(shí)image高度不會(huì)縮放。注意,這個(gè)參數(shù)不包含在 3 參數(shù)語(yǔ)法中。
這9個(gè)參數(shù)我們可以這樣來記憶,第一個(gè)參數(shù)是圖像源,接下來的四個(gè)參數(shù)指的是原圖,最后四個(gè)參數(shù)指的是畫布
切割&渲染
這里我們主要是將一張圖片切割成一個(gè)個(gè)的小碎片,是這些碎片拼起來就是一張完整的圖片。
class?ChipBanner?{
??constructor()?{
????this.cvs?=?document.querySelector("#chip");
????this.ctx?=?this.cvs.getContext("2d");
????this.imgList?=?document.querySelectorAll(".bg");
????this.imgIndex?=?0;
????this.isAnimating?=?false;
????this.imgW?=?800;?//圖片原始寬/高
????this.imgH?=?530;
????this.conW?=?800;?//畫布寬/高
????this.conH?=?530;
????this.dw?=?16;?//畫布單元寬/高
????this.dh?=?15;
????this.I?=?this.conH?/?this.dh;?//單元行/列數(shù)
????this.J?=?this.conW?/?this.dw;
????this.DW?=?this.imgW?/?this.J;?//原圖單元寬/高
????this.DH?=?this.imgH?/?this.I;
??}
??init()?{
????this.ctx.beginPath();
????for?(let?i?=?0;?i?<?this.I;?i++)?{
??????for?(let?j?=?0;?j?<?this.J;?j++)?{
????????this.chipDraw(this.imgList[this.imgIndex],?i,?j);
??????}
????}
????this.ctx.closePath();
????this.ctx.stroke();
??}
??drawText()?{
????this.ctx.font?=?"150px?serif";
????this.ctx.strokeStyle?=?"white";
????this.ctx.strokeText("1024",?500,?500);
??}
??chipDraw(img,?i,?j)?{
????this.drawText();
????//負(fù)責(zé)繪制,i:?單元行號(hào);j:?單元列號(hào)
????this.ctx.drawImage(
??????img,
??????this.DW?*?j,
??????this.DH?*?i,
??????this.DW,
??????this.DH,
??????this.dw?*?j,
??????this.dh?*?i,
??????this.dw,
??????this.dh
????);
??}
}
這里正確拼出來看到的和正常圖片沒有任何區(qū)別

再來看一張拼錯(cuò)的圖

剛開始幾何坐標(biāo)那里沒寫對(duì),拼出來就成這樣了,哈哈,看著就像動(dòng)畫幀卡住的樣子。
動(dòng)畫
這里主要是要找出某個(gè)點(diǎn)周圍棱形范圍內(nèi)的所有點(diǎn)的坐標(biāo),然后在清除這些坐標(biāo)圖案的同時(shí),開始繪制下一張圖片。
「菱形線上的點(diǎn)與坐標(biāo)的 行號(hào)差值的絕對(duì)值 + 列號(hào)差值的絕對(duì)值 = 距離」
找出坐標(biāo)棱形范圍內(nèi)所有的點(diǎn)
countAround(i,?j,?dst)?{
????let?arr?=?[];
????for?(let?m?=?i?-?dst;?m?<=?i?+?dst;?m++)?{
??????for?(let?n?=?j?-?dst;?n?<=?j?+?dst;?n++)?{
????????if?(
??????????Math.abs(m?-?i)?+?Math.abs(n?-?j)?==?dst?&&
??????????m?>=?0?&&
??????????n?>=?0?&&
??????????m?<=?this.I?-?1?&&
??????????n?<=?this.J?-?1
????????)?{
??????????arr.push({?x:?m,?y:?n?});
????????}
??????}
????}
????return?arr;
??}
清除單元格畫布
chipClear(i,?j)?{
????this.ctx.clearRect(this.dw?*?j,?this.dh?*?i,?this.dw,?this.dh);
}
合并&動(dòng)畫
start(i,?j)?{
????if?(this.isAnimating)?return;
????this.isAnimating?=?true;
????this.imgIndex++;
????if?(this.imgIndex?>?this.imgList.length?-?1)?this.imgIndex?=?0;
????let?_this?=?this,
??????dst?=?0,
??????timer?=?setInterval(()?=>?{
????????let?resArr?=?_this.countAround(i,?j,?dst);
????????resArr.forEach((item)?=>?{
??????????_this.chipClear(item.x,?item.y);??//?清除單元格
??????????_this.chipDraw(_this.imgList[_this.imgIndex],?item.x,?item.y);?//?繪制下一張圖片
????????});
????????if?(!resArr.length)?{
??????????clearInterval(timer);
??????????_this.isAnimating?=?false;
????????}
????????dst++;
??????},?30);
??}
大功告成,這樣就實(shí)現(xiàn)了一個(gè)炫酷的碎片式切圖效果了~

到此這篇關(guān)于JavaScript利用canvas實(shí)現(xiàn)炫酷的碎片切圖效果的文章就介紹到這了,更多相關(guān)JavaScript canvas碎片切圖效果內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
原生JS實(shí)現(xiàn)輪播效果+學(xué)前端的感受(防止走火入魔)
下面小編就為大家?guī)硪黄鶭S實(shí)現(xiàn)輪播效果+學(xué)前端的感受(防止走火入魔)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2016-08-08
解決layui的form里的元素進(jìn)行動(dòng)態(tài)生成,驗(yàn)證失效的問題
今天小編就為大家分享一篇解決layui的form里的元素進(jìn)行動(dòng)態(tài)生成,驗(yàn)證失效的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2019-09-09
兼容IE,firefox的獲取節(jié)點(diǎn)的文本值的javascript代碼
javascript獲取節(jié)點(diǎn)的文本值,已經(jīng)考慮了兼容性。大家可以放心使用。注意了這里的兼容沒有使用innerText,如果要使用兼容innerText,請(qǐng)參考腳本之家以前發(fā)布的文章。2009-12-12
JS中使用new Date(str)創(chuàng)建時(shí)間對(duì)象不兼容firefox和ie的解決方法(兩種)
這篇文章主要介紹了JS中使用new Date(str)創(chuàng)建時(shí)間對(duì)象不兼容firefox和ie的解決方法的相關(guān)資料,需要的朋友可以參考下2016-12-12

