先放圖,哈哈哈
整體思路:
頁面需要有一個canvas容器,用來放后面繪制的結果,canvas不熟練,底下沒有畫圓角,所以展現給用戶看的不是canvas畫的,當保存下來的時候才是canvas生成的圖片.

1 <canvas class="sharePoster" canvas-id="poster"></canvas> 2 <view class="show-img" wx:if="{{sharePoster}}"> 3 <!-- <view class="show-img"> --> 4 <view class="show-con"> 5 <image class="share-del" src="/images/unshare.png" alt="" catchtap="unshare" /> 6 <view class="canvas-img"> 7 <image class="share-bg" src="/images/share-bg.png" alt="" /> 8 <view class="canvas-user"> 9 <image class="user-img" src="{{shareInfo.avatar}}" alt=""></image> 10 <view class="canvas-info"> 11 <view class="user-name">{{shareInfo.nickname}}</view> 12 <view class="tip">正在參賽...</view> 13 </view> 14 </view> 15 <view class="canvas-works"> 16 <image src="{{shareInfo.opus_type==1? shareInfo.opus_url : shareInfo.opus_banner_image || '/images/vote-wei.png'}}" alt="" /> 17 </view> 18 <view class="canvas-info"> 19 <view class="canvas-name">{{shareInfo.opus_name}}</view> 20 <view class="canvas-content">{{shareInfo.opus_content}}</view> 21 </view> 22 <view class="canvas-footer"> 23 <image class="canvas-code" src="{{shareInfo.qrcode_url}}" alt="" /> 24 <view class="code-tip"> 25 <view>長按識別二維碼</view> 26 <view>為好友加油,一起參賽!</view> 27 </view> 28 </view> 29 </view> 30 </view> 31 <view class="sava-img" catchtap='savePoster'>保存到本地</view> 32 </view>
在用戶點擊生成海報的時候,獲取海報所需要的的信息,開始下載圖片資源,並繪制canvas,期間需要一些時間,可以先彈個'生成中...'的彈窗給用戶看.
1 getPosterInfo(ho_id) { 2 let params = { ho_id: ho_id }; 3 let that = this; 4 //獲取海報所需信息 5 wx.hideLoading(); 6 this.setData({ 7 shareInfo: res.data, 8 shareFlag: false, 9 sharePoster: true 10 }); 11 //這里需要下載對應的網絡圖片資源並且開始繪畫canvas 12 this.downloadImg(this.data.shareInfo.avatar, "userImg"); 13 if (this.data.item.type == 1) { 14 this.downloadImg(this.data.shareInfo.opus_url, "showImg"); //圖片下載 15 } else { 16 this.downloadImg(this.data.shareInfo.opus_banner_image, "showImg"); //視頻封面下載 17 } 18 this.downloadImg(this.data.shareInfo.qrcode_url, "code"); //二維碼下載 19 setTimeout(() => { 20 wx.getSystemInfo({ 21 success: function(res) { 22 var v = 750 / res.windowWidth; //獲取手機比例 23 that.drawPoster(v); 24 } 25 }); 26 }, 500); 29 }); 30 }
因為我要下載的圖片比較多,所以這邊把微信的下載圖片接口封裝了一下,直接使用 'wx.downloadFile({})' 下載圖片即可.
這是第一次做海報分享,而且canvas很菜,比例抓不住,后來才知道用比例直接計算,基本上就比較好了

1 drawPoster(v) { 2 let that = this; 3 let ratio = 0.5; 4 let ctx = wx.createCanvasContext("poster", this); 5 ctx.drawImage(this.data.imgs, 0, 0, 630 / v, 812 / v); 6 ctx.save(); 7 ctx.beginPath(); 8 //頭部 9 // ctx.rect(30 / v, 31 / v, 570 / v, 96 / v) 10 11 ctx.save(); 12 // 圓的圓心的 x 坐標和 y 坐標,25 是半徑,后面的兩個參數就是起始和結束,這樣就能畫好一個圓了 13 ctx.arc(78 / v, 78 / v, 48 / v, 0, 2 * Math.PI); 14 ctx.clip(); 15 ctx.drawImage(this.data.userImg, 30 / v, 31 / v, 96 / v, 96 / v); 16 ctx.restore(); 17 ctx.setFontSize(30 / v); 18 ctx.setFillStyle("white"); 19 ctx.fillText(this.data.shareInfo.nickname, 150 / v, 65 / v); 20 ctx.setFontSize(28 / v); 21 ctx.setFillStyle("white"); 22 ctx.fillText("正在參賽......", 150 / v, 115 / v); 23 ctx.restore(); //恢復限制 24 //分享圖片 25 ctx.rect(30 / v, 157 / v, 570 / v, 380 / v); 26 ctx.lineJoin = "round"; 27 ctx.lineWidth = 20 / v; 28 //作品圖片 29 let worksImg = this.data.showImg || "/images/vote-wei.png"; 30 ctx.drawImage(worksImg, 30 / v, 157 / v, 570 / v, 380 / v); 31 32 //作品名稱 33 ctx.setFontSize(40 / v); 34 ctx.setFillStyle("white"); 35 ctx.fillText(this.data.shareInfo.opus_name, 30 / v, 598 / v, 560 / v); 36 ctx.save(); 37 //作品內容 38 // ctx.rect(30 * ratio, 616 * ratio, 570 * ratio, 172 * ratio) 39 40 ctx.setFontSize(36 * ratio); 41 ctx.setFillStyle("white"); 42 //可以嘗試切割字符串,循環數組,達到換行的效果 43 let info = this.data.shareInfo.opus_content; 44 let len = 0; 45 if (info.length > 15 && info.length < 30) { 46 //兩行以內 47 for (var a = 0; a < 2; a++) { 48 let content = info.substr(len, 15); 49 len += 15; 50 ctx.fillText(content, 30 * ratio, (658 + a * 48) / v); 51 } 52 } else if (info.length > 30) { 53 //超過三行 54 let con1 = info.substr(len, 15); 55 let con2 = info.substr(15, 14) + "..."; 56 ctx.fillText(con1, 30 * ratio, 658 / v); 57 ctx.fillText(con2, 30 * ratio, (658 + 48) / v); 58 } else { 59 //就一行 60 ctx.fillText(info, 30 * ratio, 658 / v); 61 } 62 63 ctx.restore(); 64 65 //二維碼 66 ctx.save(); 67 ctx.setFillStyle("white"); 68 // ctx.lineJoin = "round"; 69 // ctx.lineWidth = 20 / v; 70 71 ctx.fillRect(0 / v, 740 / v, 630 / v, 235 / v); 72 ctx.drawImage(this.data.code, 30 / v, 761 / v, 153 / v, 153 / v); 73 ctx.setFontSize(36 / v); 74 ctx.setFillStyle("#666666"); 75 ctx.fillText("長按識別二維碼", 210 / v, 826 / v); 76 ctx.fillText("為好友加油,一起參賽!", 210 / v, 877 / v); 77 // ctx.setFillStyle('white'); 78 // ctx.fill(); 79 // ctx.draw(); 80 ctx.restore(); 81 let windowWidth = wx.getSystemInfoSync().windowWidth; 82 ctx.draw(true, () => { 83 let timer = setTimeout(() => { 84 wx.canvasToTempFilePath( 85 { 86 x: 0, 87 y: 0, 88 width: 315, 89 height: 470, 90 destWidth: (315 * 750) / windowWidth, 91 destHeight: (470 * 750) / windowWidth, 92 canvasId: "poster", 93 // fileType: 'jpg', //如果png的話,圖片存到手機可能有黑色背景部分 94 success(res) { 95 //生成成功 96 that.setData({ 97 tempImg: res.tempFilePath 98 }); 99 clearTimeout(timer); 100 }, 101 fail: res => { 102 //生成失敗 103 clearTimeout(timer); 104 } 105 }, 106 this 107 ); 108 }, 100); 109 }); 110 }
直接用所需像素除以上面得到的比例,就OK了.我是在外面又建了一個項目畫完之后直接移進來,canvas畫了很久,邊看文檔邊畫
關於多行字符串可以手動計算字符串長度,然后給他切割出來,分段繪制.主要是我也不懂怎么用canvas繪制多行省略???完全沒有找到相關方法,如果有更好的方法,求教,謝謝!!
wx.canvasToTempFilePath(obj,this) 官方文檔: https://developers.weixin.qq.com/miniprogram/dev/api/canvas/wx.canvasToTempFilePath.html
把當前畫布指定區域的內容導出生成指定大小的圖片. 在draw()回調里調用該方法才能保證圖片保存成功, 輸出的圖片寬度和高度需要按比例,不能寫死.這樣不同手機生成的圖片就不一樣了.
接下來就是要保存圖片到本地了,仍然使用小程序接口,將上面生成圖片后的臨時路徑放進來就可以了,本來以為這邊分分鍾,后面差點忘了做授權處理.不要粗心大意!!!
1 wx.saveImageToPhotosAlbum({ 2 filePath: that.data.tempImg, 3 success(res) { 4 wx.showToast( 5 { 6 title: "保存成功", 7 icon: "success" 8 }, 9 1000 10 ); 11 that.unshare(); 12 that.shareOff(); //關閉窗口 13 }, 14 fail(err) { 15 //授權問題報錯 16 if ( 17 err.errMsg === "saveImageToPhotosAlbum:fail:auth denied" || 18 err.errMsg === "saveImageToPhotosAlbum:fail auth deny" || 19 err.errMsg === "saveImageToPhotosAlbum:fail authorize no response" 20 ) { 21 wx.showModal({ 22 title: "提示", 23 content: "需要您授權保存相冊", 24 showCancel: false, 25 success: modal=> { 26 wx.openSetting({ 27 success(settingdata) { 28 //授權狀態 29 if (settingdata.authSetting["scope.writePhotosAlbum"]) { 30 wx.showToast( 31 { 32 title: "獲取權限成功,再次點擊即可保存", 33 icon: "none" 34 }, 35 500 36 ); 37 } else { 38 wx.showToast( 39 { 40 title: "獲取權限失敗,將無法保存到相冊哦~", 41 icon: "none" 42 }, 43 500 44 ); 45 } 46 }, 47 fail(failData) { 48 console.log("failData", failData); 49 } 50 }); 51 } 52 }); 53 } 54 } 55 });
做完之后竟然對討厭的canvas產生了一點點好感,嗯,只要不畫貝塞爾曲線,一切都好商量,代碼感覺還有冗余,需要進一步的改進,不過這是第一次做,就不想刪了,看優化后的和看第一次做出來的,感覺總是有點不同的.我應該是個戀舊的人吧,哈哈哈,開個玩笑.