這是一個微信小程序,用來生成九宮格心形的圖片。html
連接: https://pan.baidu.com/s/1sPx6FJlqzlFZ0Md6xy9jzw 提取碼: 88v8git
掃碼體驗github
微信小程序須要的代碼,在 src 文件夾中。canvas
前幾天在朋友圈看到好幾回這種圖片。小程序
這種圖片,是用九張圖片拼成的一個心形。微信小程序
感受頗有趣,就上網查了查怎麼作,大部分的說法就是用美圖秀秀的拼圖功能來作, 在微信小程序中也有專門作心形拼圖的小程序,我都試了試以後,感受還能夠更加簡單一些,因而我就本身作了個小程序。api
一、有兩個 canvas,一個小的 canvas 顯示最後會是什麼樣子,一個大的 canvas 用來最後進行截圖,生成圖片,保存到相冊。
經過CSS的定位,把大的 canvas 移到屏幕外面不讓用戶看到就能夠了。
而若是用小的canvas 保存圖片的話,最後的圖片有些模糊。數組
二、canvas 能夠當作一個 9 * 9 的網格,微信
用一個叫 heart 的數組來表示就是這樣的。優化
用其中的小格子,來拼出心形,根據數組的內容在 canvas 上進行渲染。
這個小程序有 選擇單張圖片,選擇多張圖片,補充圖片,保存圖片,重置,推薦,意見反饋,這幾個功能。
當用戶點擊心形區域的時候,就能夠選擇單張圖片,調用 wx.chooseImage 就能夠從本地相冊選擇圖片,而後就把這張圖,畫在 canvas上,具體畫的位置就是用戶點擊的位置。
在小的 canvas上綁定 touchend 事件,觸發事件後,事件中有一個 changedTouches 屬性,這是一個保存了,當前變化的觸摸點信息的數組,這個數組中的元素有 x 和 y 屬性,也就是觸摸點距離 canvas 左上角的距離。
// 觸摸點在 x 軸的值 var x = e.changedTouches[0].x; // 觸摸點在 y 軸的值 var y = e.changedTouches[0].y;
有 x 軸 和 y 軸的距離後,算出具體應該畫在哪一個格子上。
//grid 表示一個格子的寬度 // 肯定 x 軸是在第幾個格子 x = Math.floor(x / grid); // 肯定 y 軸是在第幾個格子 y = Math.floor(y / grid);
知道在哪一個格子畫以後,就要肯定畫圖片的哪部分了,由於全部的格子都是正方形的,可是用戶選擇的圖片不必定是正方形,若是壓縮成正方形會很難看,因此我畫的時候,選擇了正中間的部分來畫,
經過 wx.getImageInfo 來獲取圖片信息,以短邊爲正方形的寬,而後從(長邊 - 短邊)/2
的地方來畫。
// 獲取圖片的寬和高 var width = res.width; var height = res.height; // 若是圖片不是正方形,只畫中間的部分 // sWidth 表示正方形的寬 var sWidth = width > height ? height : width; // sx 是源圖像的矩形選擇框的左上角 X 座標 var sx = 0; // sy 是源圖像的矩形選擇框的左上角 y 座標 var sy = 0; if (width > height) { sx = (width - height) / 2; } if (width < height) { sy = (height - width) / 2; }
知道畫什麼,在哪裏畫以後,調用 canvasContext.drawImage 來畫就能夠了。
選擇多張圖片,一樣是調用 wx.chooseImage 方法,成功選擇多張圖片後,返回的對象中有一個 tempFilePaths 屬性,這個屬性保存了,圖片的本地文件路徑列表。
而後遍歷 heart 數組,也就是保存心形數據的數組,若是數組中某個元素的值是1,也就是說在心形範圍內,就按順序從 tempFilePaths 中取一張圖片畫上去,畫的時候一樣的,若是不是正方形就只畫中間的部分。
在 image 的文件中,有保存幾張圖片,用來補充心形,他們的路徑保存在一個數組中。
// 用來補充心形的圖片 images: [ '../../images/1.jpg', '../../images/2.jpg', '../../images/3.jpg', '../../images/4.jpg', '../../images/5.jpg', '../../images/6.jpg', '../../images/7.jpg', '../../images/8.jpg', '../../images/9.jpg', '../../images/10.jpg', ]
而後就是遍歷 heart 數組,若是數組的某個元素的值是1,就隨機從這組圖片中選擇一張畫上去。
畫一張圖片,畫多張圖片,補充圖片,他們都是在 canvas 上畫圖片,爲了不已經畫了圖片的位置被覆蓋,他們所畫的圖片的等級是不一樣的。
補充圖片:1 畫多張圖片:2 畫一張圖片:3
等級高的能夠覆蓋等級低的,等級低的不能覆蓋等級高的,同等級的,除了畫多張圖片的不能覆蓋,其他的兩種狀況,均可以覆蓋。
簡單意思就是: 補充圖片,補充完了以後,再補充會把原來補充的覆蓋掉,可是用戶選擇的圖片不會被覆蓋掉。
畫多張圖片,能夠覆蓋掉補充的圖片,但用戶選擇的圖片也不會覆蓋掉。
畫一張圖片,無論這個位置有沒有圖片,都會再畫一張。
保存圖片的時候,就是按順序對大的 canvas 進行截取,而後保存成圖片,主要靠 wx.canvasToTempFilePath 這個API來實現,這個 API ,能夠把當前畫布指定區域的內容導出生成指定大小的圖片,並返回文件路徑。
這裏要注意幾個細節
一、爲了不最後保存的圖片有黑色背景,最好開始的時候就在 canvas 上畫一個 和 canvas 大小同樣的矩形,矩形填充上顏色。
二、爲了保存的圖片,在用戶的相冊中也能保持心形。須要按下面這個順序來保存圖片
三、wx.canvasToTempFilePath 中有兩個選填的參數 destWidth 和 destHeight,這個兩個參數決定 輸出圖片寬度和高度,若是不是準確的知道是多少,用默認值就能夠。
destWidth
和 destHeight
單位是物理像素(pixel),canvas 繪製的時候用的是邏輯像素(物理像素=邏輯像素 * density),因此這裏若是隻是使用 canvas 中的 width 和 height(邏輯像素)做爲輸出圖片的長寬的話,生成的圖片 width 和 height 其實是縮放了到 canvas 的 1 / density
大小了,因此就顯得比較模糊了。
而默認值是 width * 屏幕像素密度
文檔中提到的屏幕像素密度,應該不是指每英寸屏幕所擁有的像素數,而是指設備像素比(pixelRatio),也就是用多少個物理像素去顯示 1px 的 CSS 像素。 用API wx.getSystemInfo 能夠查看設備像素比
wx.getSystemInfo({ success: function(res) { console.log(res.pixelRatio) } })
這裏若是個人理解有誤,還請知道的小夥伴指出。
說了這麼多,主要就是想說用默認的值其實就已經很清晰了。
四、由於要保存9張圖片,因此須要一些時間,這個時候就須要一個進度條了,保存圖片的時候,顯示進度條,禁用保存按鈕,畢竟點擊一下按鈕就是9張圖片,因此這個時候仍是禁用了好,每保存一張圖片進度條的值就 +12 ,超過100的時候,就表示 9張圖片都保存好了。
而微信小程序中也恰好有進度條(progress)這個組件。
這個功能就是遍歷 heart 數組,用一種顏色,根據數組內容,把心形畫出來。而後再在 x 軸 和 y 軸上畫兩條線,行成九宮格的樣子。
<button open-type='share'>推薦給朋友</button> <button open-type='feedback'>意見反饋
這個兩個功能就是用了,微信小程序的 button 組件,這裏須要注意的就是,在清除 button 的默認樣式時,須要把 button 的 after
僞元素的邊框也去掉。
button::after{ border: 0; }
有一些地方是小程序在替用戶作選擇,好比,若是所選擇的圖片不是正方形,就畫中間的部分,可是中間的部分不必定是用戶想要的,而若是每張圖片都要用戶本身來選擇畫哪部分,顯然是有些麻煩了,這裏還能夠繼續優化下。
還有在補充圖片的時候,補充的圖片也不必定是用戶喜歡的,因此這部分再考慮是否是能夠加一些標籤,用戶選擇不一樣的標籤,來補充符合標籤的圖片,相似 QQ音樂的歌詞海報這樣。
此次作的這個九宮格心形拼圖的小程序,初版已經上線了。
這個小程序無論在代碼,仍是功能上都還有許多地方能夠繼續優化,若是有須要的朋友能夠直接拿去改。
若是你喜歡這個小程序的話,能夠 star 支持一下。
目前,這個小程序有進行一些優化,具體能夠點這裏。
若是須要最開始的版本,請到這裏