JavaScript利用canvas實(shí)現(xiàn)炫酷的碎片切圖效果
前言
今天分享一個(gè)炫酷的碎片式切圖效果,這個(gè)其實(shí)在自己的之前的博客上有實(shí)現(xiàn)過(guò),本人覺(jué)得這個(gè)效果還是挺炫酷的,這次還是用我們的canvas來(lái)實(shí)現(xiàn),代碼量不多,但有些地方還是需要花點(diǎn)時(shí)間去理解的,需要點(diǎn)數(shù)學(xué)幾何理解能力,老規(guī)矩,我們還是先看效果再來(lái)看實(shí)現(xiàn)步驟。
需求分析
從上面我們看到圖片在切換的時(shí)候其實(shí)是一個(gè)一個(gè)的小碎片慢慢從點(diǎn)擊位置往外擴(kuò)散開(kāi)來(lái),這一個(gè)個(gè)小碎片,在頁(yè)面中其實(shí)就是一個(gè)個(gè)的小方塊。這里的難點(diǎn)在于如何將一張完整的圖片切割成一個(gè)一個(gè)的小方塊分別進(jìn)行渲染,還有就是這個(gè)棱形圖案的位置確定。
- 切割:這里我們可以以坐標(biāo)系的形式來(lái)進(jìn)行切割,每一個(gè)方塊都對(duì)應(yīng)著它們自己在坐標(biāo)系中的位置(x, y)
- 繪制:這里的重點(diǎn)在于drawImage方法
- 棱形擴(kuò)散:這里需要點(diǎn)數(shù)學(xué)幾何理解能力,后面作圖理解
實(shí)現(xiàn)過(guò)程
坐標(biāo)系
在實(shí)現(xiàn)之前,我們先來(lái)理解一個(gè)概念:「坐標(biāo)系」
注意:這里所說(shuō)的坐標(biāo)系不是我們數(shù)學(xué)中的坐標(biāo)系,但兩者又有些類似,不同點(diǎn)在于兩者的原點(diǎn)位置以及y軸的方向不同。
切割
這一步主要是為了確定每一個(gè)單元格的大小,單元格的長(zhǎng)寬最好不要是最大公約數(shù)或最小公約數(shù),因?yàn)檫^(guò)大效果不夠炫,過(guò)小性能會(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è)方法,我們可以先來(lái)了解一下這個(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ǔ)法來(lái)省略這個(gè)參數(shù)。 - 「s y」:(可選)需要繪制到目標(biāo)上下文中的,
image
的矩形(裁剪)選擇框的左上角 Y 軸坐標(biāo)??梢允褂?3 參數(shù)或 5 參數(shù)語(yǔ)法來(lái)省略這個(gè)參數(shù)。 - 「sWidth」:(可選)需要繪制到目標(biāo)上下文中的,
image
的矩形(裁剪)選擇框的寬度。如果不說(shuō)明,整個(gè)矩形(裁剪)從坐標(biāo)的sx
和sy
開(kāi)始,到image
的右下角結(jié)束??梢允褂?3 參數(shù)或 5 參數(shù)語(yǔ)法來(lái)省略這個(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)行縮放。如果不說(shuō)明,在繪制時(shí)image
寬度不會(huì)縮放。注意,這個(gè)參數(shù)不包含在 3 參數(shù)語(yǔ)法中。 - 「dHeight」:
image
在目標(biāo)畫布上繪制的高度。允許對(duì)繪制的image
進(jìn)行縮放。如果不說(shuō)明,在繪制時(shí)image
高度不會(huì)縮放。注意,這個(gè)參數(shù)不包含在 3 參數(shù)語(yǔ)法中。
這9個(gè)參數(shù)我們可以這樣來(lái)記憶,第一個(gè)參數(shù)是圖像源,接下來(lái)的四個(gè)參數(shù)指的是原圖,最后四個(gè)參數(shù)指的是畫布
切割&渲染
這里我們主要是將一張圖片切割成一個(gè)個(gè)的小碎片,是這些碎片拼起來(lái)就是一張完整的圖片。
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 ????); ??} }
這里正確拼出來(lái)看到的和正常圖片沒(méi)有任何區(qū)別
再來(lái)看一張拼錯(cuò)的圖
剛開(kāi)始幾何坐標(biāo)那里沒(méi)寫對(duì),拼出來(lái)就成這樣了,哈哈,看著就像動(dòng)畫幀卡住的樣子。
動(dòng)畫
這里主要是要找出某個(gè)點(diǎn)周圍棱形范圍內(nèi)的所有點(diǎn)的坐標(biāo),然后在清除這些坐標(biāo)圖案的同時(shí),開(kāi)始繪制下一張圖片。
「菱形線上的點(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)文章
每天一篇javascript學(xué)習(xí)小結(jié)(Date對(duì)象)
這篇文章主要介紹了javascript中的Date對(duì)象知識(shí)點(diǎn),對(duì)Date對(duì)象的基本使用方法,以及各種方法進(jìn)行整理,感興趣的小伙伴們可以參考一下2015-11-11Bootstrap基本樣式學(xué)習(xí)筆記之表單(3)
這篇文章主要介紹了Bootstrap學(xué)習(xí)筆記之表單基本樣式的相關(guān)資料,為大家分享了三種表單樣式,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-12-12IE中鼠標(biāo)經(jīng)過(guò)option觸發(fā)mouseout的解決方法
這篇文章主要介紹了IE中鼠標(biāo)經(jīng)過(guò)option觸發(fā)mouseout的解決方法,分析了IE中鼠標(biāo)移到option時(shí)window.event.toElement返回值為null的原因及解決方法,需要的朋友可以參考下2015-01-01JavaScript中的字符串與數(shù)字轉(zhuǎn)換的示例
在JavaScript編程中,掌握字符串與數(shù)字的轉(zhuǎn)換技巧對(duì)處理用戶輸入、數(shù)據(jù)計(jì)算及格式化輸出至關(guān)重要,本文詳細(xì)介紹了多種轉(zhuǎn)換方法,下面就一起來(lái)介紹一下2024-09-09