JavaScript前端實(shí)現(xiàn)拼圖分割效果
第一步
找到一張模板圖,如下:
這是一張通過(guò)RGBA的B通道區(qū)分的模板圖,每個(gè)碎片的B通道,對(duì)應(yīng)序號(hào)分別是0,10,20,30,40,……
即序號(hào)的10倍等于B通道的值。
第二步
找到一張需要切分的圖,如下:
確保兩張圖的尺寸一致,不一致會(huì)導(dǎo)致壓縮變形既。
第三步
上代碼,微信小程序: ts代碼:
// components/cut-img/index.ts Component({ /** * 組件的屬性列表 */ properties: { temp: { type: String, value: getApp().imgPrefix('/model/test/temp5-3.png') }, img: { type: String, value: getApp().imgPrefix('/model/test/test.jpg') }, size: { type: Number, value: 15 }, }, /** * 組件的初始數(shù)據(jù) */ data: { }, lifetimes: { ready() { // 通過(guò) SelectorQuery 獲取 Canvas 節(jié)點(diǎn) setTimeout(() => { const query = wx.createSelectorQuery().in(this) query.select('#canvas') .fields({ node: true, size: true, }) .exec(this.init.bind(this)) }, 1000); }, }, /** * 組件的方法列表 */ methods: { /** * 初始化 */ init(res: any) { const canvas = this.canvas = res[0]?.node if (!canvas) { return false } this.ctx = canvas.getContext('2d') this.setTemp() return false }, /** * 設(shè)置temp 圖片上圖 */ setTemp() { const ctx = this.ctx const canvas = this.canvas const img = canvas.createImage() ctx.clearRect(0, 0, canvas.width, canvas.height) img.onload = () => { this.width = canvas.width = img.width this.height = canvas.height = img.height ctx.drawImage(img, 0, 0, canvas.width, canvas.height) this.tempData = ctx.getImageData(0, 0, canvas.width, canvas.height); this.setImg() } img.src = this.data.temp }, /** * 設(shè)置img 圖片上圖 */ setImg() { const ctx = this.ctx const canvas = this.canvas const img = canvas.createImage() ctx.clearRect(0, 0, canvas.width, canvas.height) img.onload = () => { ctx.drawImage(img, 0, 0, canvas.width, canvas.height) this.imgData = ctx.getImageData(0, 0, canvas.width, canvas.height); const size = this.data.size const list: any[] = [] for(let i = 0; i < size; i++) { this.cut(i, list) } console.log('>>> list', list) // this.triggerEvent('success', list) } img.src = this.data.img }, /** * 裁剪 * @param index 序號(hào) * @param list 存儲(chǔ)列表 */ cut(index: number, list: any[]) { const ctx = this.ctx const canvas = this.canvas const newData = ctx.createImageData(this.width, this.height); for (let i = 0; i < newData.data.length; i += 4) { const temp = this.tempData.data.slice(i, i + 4) if (Math.abs(temp[2] - index * 10) < 2 && temp[3] > 10) { newData.data[i + 0] = this.imgData.data[i + 0] newData.data[i + 1] = this.imgData.data[i + 1] newData.data[i + 2] = this.imgData.data[i + 2] newData.data[i + 3] = this.imgData.data[i + 3] } else { newData.data[i + 0] = 0 newData.data[i + 1] = 0 newData.data[i + 2] = 0 newData.data[i + 3] = 0 } } // ctx.putImageData(newData, 0, 0) let minX = newData.width; let minY = newData.height; let maxX = -1; let maxY = -1; // 遍歷所有像素,查找非透明像素的位置 for (let y = 0; y < newData.height; y++) { for (let x = 0; x < newData.width; x++) { const pixelIndex = (y * newData.width + x) * 4; if (newData.data[pixelIndex + 3] > 0) { // Alpha通道大于0表示非透明 minX = Math.min(minX, x); maxX = Math.max(maxX, x); minY = Math.min(minY, y); maxY = Math.max(maxY, y); } } } const width = maxX - minX + 1 const height = maxY - minY + 1 canvas.width = width canvas.height = height // 創(chuàng)建新的圖像數(shù)據(jù)對(duì)象用于裁剪后的圖像 const croppedImage = ctx.createImageData(width, height); // 復(fù)制非透明像素到新的圖像數(shù)據(jù)中 for (let y = minY; y <= maxY; y++) { for (let x = minX; x <= maxX; x++) { const srcIndex = ((y * newData.width) + x) * 4; const destIndex = ((y - minY) * (maxX - minX + 1) + (x - minX)) * 4; croppedImage.data.set(newData.data.subarray(srcIndex, srcIndex + 4), destIndex); } } // 清除畫(huà)布并繪制裁剪后的圖像 ctx.clearRect(0, 0, width, height); ctx.putImageData(croppedImage, 0, 0); const dataUrl = canvas.toDataURL('image/png'); list.push({ x: minX, y: minY, width, height, dataUrl }) }, } })
wxml代碼:
<!--components/cut-img/index.wxml--> <view style="display: none;"> <canvas type="2d" id="canvas"></canvas> </view>
步驟總結(jié)
1、獲取canvas
2、先渲染模板,拿到模板圖的imgdata
3、再渲染需要切換的目標(biāo)圖,拿到目標(biāo)圖的imgdata
4、根據(jù)切分的數(shù)量,循環(huán)切分
4.1、創(chuàng)建一個(gè)空的imgdata,根據(jù)序號(hào)對(duì)應(yīng)的B通道,把對(duì)應(yīng)的切片數(shù)據(jù)存入imgdata
4.2、計(jì)算非空白區(qū)域的位置和尺寸,裁剪圖片數(shù)據(jù)
4.3、裁剪后的數(shù)據(jù)放回canvas,導(dǎo)出dataURL
4.4、保存對(duì)應(yīng)的x、y、width、height、dataURL
5、返回list
到此這篇關(guān)于JavaScript前端實(shí)現(xiàn)拼圖分割效果的文章就介紹到這了,更多相關(guān)JavaScript拼圖分割內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
70+漂亮且極具親和力的導(dǎo)航菜單設(shè)計(jì)國(guó)外網(wǎng)站推薦
網(wǎng)站可用性是任何網(wǎng)站的基本要素,而可用的導(dǎo)航更是網(wǎng)站所必需的要素之一。導(dǎo)航?jīng)Q定了用戶如何與網(wǎng)站進(jìn)行交互。如果沒(méi)有了可用的導(dǎo)航,那么網(wǎng)站內(nèi)容就會(huì)變得毫無(wú)用處。2011-09-09bootstrap datetimepicker 日期插件在火狐下出現(xiàn)一條報(bào)錯(cuò)信息的原因分析及解決辦法
日期插件 bootstrap-datetimepicker 在火狐下出現(xiàn)一條報(bào)錯(cuò)信息:TypeError: (intermediate value).toString(…).split(…)[1] is undefined.什么原因?qū)е碌哪兀旅嫘【幗o大家分享解決思路,需要的朋友參考下2017-03-03javascript結(jié)合Canvas 實(shí)現(xiàn)簡(jiǎn)易的圓形時(shí)鐘
本文給大家分享的是javascript結(jié)合Canvas 實(shí)現(xiàn)簡(jiǎn)易的圓形時(shí)鐘,主要是對(duì)自己前段時(shí)間學(xué)習(xí)html5的canvas的一次小檢驗(yàn),這里推薦給小伙伴們,有需要的可以參考下。2015-03-03Bootstrap項(xiàng)目實(shí)戰(zhàn)之子欄目資訊內(nèi)容
Bootstrap項(xiàng)目實(shí)戰(zhàn)之資訊內(nèi)容,本文主要學(xué)習(xí)制作一下子欄目資訊內(nèi)容,感興趣的小伙伴們可以參考一下2016-04-04javascript window.confirm確認(rèn) 取消對(duì)話框?qū)崿F(xiàn)代碼小結(jié)
本文章講述的三種都是基于了javascript confirm提示確認(rèn)框的做法了,只是在不同的地方寫(xiě)哦,有需要的同學(xué)可參考一下2012-10-10JavaScript之IE的fireEvent方法詳細(xì)解析
剛開(kāi)始我以為是會(huì)跟平時(shí)使用onclick()一樣,沒(méi)想到最近在寫(xiě)javascript入門(mén)ppt的時(shí)候發(fā)現(xiàn)了,原來(lái)自己太自以為是了!看來(lái)還有很多javascript的細(xì)節(jié)沒(méi)有掌握好啊2013-11-11獲取元素距離瀏覽器周邊的位置的方法getBoundingClientRect
本文為大家介紹下如何使用getBoundingClientRect()方法獲取元素距離瀏覽器周邊的位置,有類(lèi)似問(wèn)題的朋友可以參考下哈,希望對(duì)你學(xué)習(xí)js有所幫助2013-04-04