JavaScript利用canvas實現炫酷的碎片切圖效果
前言
今天分享一個炫酷的碎片式切圖效果,這個其實在自己的之前的博客上有實現過,本人覺得這個效果還是挺炫酷的,這次還是用我們的canvas來實現,代碼量不多,但有些地方還是需要花點時間去理解的,需要點數學幾何理解能力,老規(guī)矩,我們還是先看效果再來看實現步驟。
需求分析
從上面我們看到圖片在切換的時候其實是一個一個的小碎片慢慢從點擊位置往外擴散開來,這一個個小碎片,在頁面中其實就是一個個的小方塊。這里的難點在于如何將一張完整的圖片切割成一個一個的小方塊分別進行渲染,還有就是這個棱形圖案的位置確定。
- 切割:這里我們可以以坐標系的形式來進行切割,每一個方塊都對應著它們自己在坐標系中的位置(x, y)
- 繪制:這里的重點在于drawImage方法
- 棱形擴散:這里需要點數學幾何理解能力,后面作圖理解
實現過程
坐標系
在實現之前,我們先來理解一個概念:「坐標系」
注意:這里所說的坐標系不是我們數學中的坐標系,但兩者又有些類似,不同點在于兩者的原點位置以及y軸的方向不同。
切割
這一步主要是為了確定每一個單元格的大小,單元格的長寬最好不要是最大公約數或最小公約數,因為過大效果不夠炫,過小性能會有壓力。
我這里畫板長寬為 800 * 530 ,選取 16 * 15 為單元尺寸,即整個畫布由 50 * 35 共 1750 個單元格組成。切割分完單元格之后我們需要先計算一些基本的參數備用。
this.imgW?=?800;?//?圖片原始寬 this.imgH?=?530;?//?圖片原始高 this.conW?=?800;?//?畫布寬 this.conH?=?530;?//??畫布高 this.dw?=?16;?//?單元格寬 this.dh?=?15;?//?單元格高 this.I?=?this.conH?/?this.dh;?//單元行數 this.J?=?this.conW?/?this.dw;?//?單元列數 this.DW?=?this.imgW?/?this.J;?//?原圖單元寬 this.DH?=?this.imgH?/?this.I;?//?原圖單元高
「行數 = 畫布高度 / 單元格高度;列數 = 畫面寬度 / 單元格寬度」
繪制
本次繪制的重點在于drawImage這個方法,我們可以先來了解一下這個方法的參數及功能
drawImage
drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight)
這個方法一共有9個參數,作用是在畫布上繪制圖像。看到這么多參數是不是已經被勸退了,哈哈
- 「image」:繪制到上下文的元素。允許任何的畫布圖像源,例如:
HTMLImageElement
、SVGImageElement
、HTMLVideoElement
、HTMLCanvasElement
、ImageBitmap
、OffscreenCanvas
或VideoFrame
。 - 「sx」:(可選)需要繪制到目標上下文中的,
image
的矩形(裁剪)選擇框的左上角 X 軸坐標??梢允褂?3 參數或 5 參數語法來省略這個參數。 - 「s y」:(可選)需要繪制到目標上下文中的,
image
的矩形(裁剪)選擇框的左上角 Y 軸坐標。可以使用 3 參數或 5 參數語法來省略這個參數。 - 「sWidth」:(可選)需要繪制到目標上下文中的,
image
的矩形(裁剪)選擇框的寬度。如果不說明,整個矩形(裁剪)從坐標的sx
和sy
開始,到image
的右下角結束。可以使用 3 參數或 5 參數語法來省略這個參數。使用負值將翻轉這個圖像。 - 「sHeight」:(可選)需要繪制到目標上下文中的,
image
的矩形(裁剪)選擇框的高度。使用負值將翻轉這個圖像。 - 「dx」:
image
的左上角在目標畫布上 X 軸坐標。 - 「dy」:
image
的左上角在目標畫布上 Y 軸坐標。 - 「dWidth」:
image
在目標畫布上繪制的寬度。允許對繪制的image
進行縮放。如果不說明,在繪制時image
寬度不會縮放。注意,這個參數不包含在 3 參數語法中。 - 「dHeight」:
image
在目標畫布上繪制的高度。允許對繪制的image
進行縮放。如果不說明,在繪制時image
高度不會縮放。注意,這個參數不包含在 3 參數語法中。
這9個參數我們可以這樣來記憶,第一個參數是圖像源,接下來的四個參數指的是原圖,最后四個參數指的是畫布
切割&渲染
這里我們主要是將一張圖片切割成一個個的小碎片,是這些碎片拼起來就是一張完整的圖片。
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;?//單元行/列數 ????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(); ????//負責繪制,i:?單元行號;j:?單元列號 ????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ū)別
再來看一張拼錯的圖
剛開始幾何坐標那里沒寫對,拼出來就成這樣了,哈哈,看著就像動畫幀卡住的樣子。
動畫
這里主要是要找出某個點周圍棱形范圍內的所有點的坐標,然后在清除這些坐標圖案的同時,開始繪制下一張圖片。
「菱形線上的點與坐標的 行號差值的絕對值 + 列號差值的絕對值 = 距離」
找出坐標棱形范圍內所有的點
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); }
合并&動畫
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); ??}
大功告成,這樣就實現了一個炫酷的碎片式切圖效果了~
到此這篇關于JavaScript利用canvas實現炫酷的碎片切圖效果的文章就介紹到這了,更多相關JavaScript canvas碎片切圖效果內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
IE中鼠標經過option觸發(fā)mouseout的解決方法
這篇文章主要介紹了IE中鼠標經過option觸發(fā)mouseout的解決方法,分析了IE中鼠標移到option時window.event.toElement返回值為null的原因及解決方法,需要的朋友可以參考下2015-01-01