前一陣有完成在小程式內動態生成圖片再進行分享的需求,是很常見的場景,因此我抽出了一個小工具CanvasPainter.js,囊括在小程式內canvas畫圖基本需求:
- 用配置形式繪圖(暫支援單行及多行文字,矩形,圓形,圖片及圓形圖片型別),以及支援後續預覽及儲存成圖片,且皆為Promise格式。
- canvas尺寸以一般設計稿的750px為準(可配),在不同螢幕機型下等比縮放。
- 生成圖片時,支援圖片預下載,及在一個小程式週期內快取圖片下載的tmp路徑。
用法
使用也很簡單~無需染指到wx.各種api
,直接配置初始化+呼叫對應方法即可,一條龍服務美滋滋~
import CanvasPainter from `./CanvasPainter`;
const config = [
{type:`rect, width: 640, height: 560, x: 0, y: 0, color: `#fff`},
{type: `text`, text: `測試文字`, color: `#1499f8`,size: 50, x: 30,y: 100}
]
// 初始化
const painter = new CanvasPainter({
canvasId: `canvasId`,
context: this, // 元件內使用需傳this
config //畫圖路徑
});
painter.loadImgInAdvance(); //預下載圖片到本地;如不主動呼叫,則draw的時候會再下載。
// 更新畫圖路徑
painter.resetConfig(newConfig);
// 畫圖
painter.draw().then(() => {
console.log(`畫圖完成`);
}).catch(e => {
console.log(`生成圖片失敗`, e);
});
// 預覽
painter.preview();
// 儲存
painter.save().then(() => {
console.log(`儲存完成`);
}).catch(e => {
console.log(`儲存失敗`, e);
});
複製程式碼
開發過程中遇到的要點記錄如下:
-
如何等比縮放
因為canvas繪圖時的長度單位為px,所以可以利用小程式的canvas.scale()來解決。
const scale = wx.getSystemInfoSync().windowWidth / 750; this.ctx.scale(scale, scale); // 這樣可以實現以750px尺寸的ui圖等比縮放 複製程式碼
-
繪製圖片預下載及快取
呼叫
ctx.drawImage()
時,圖片需要先下載到本地臨時路徑,這一步耗時較長,所以建議前置進行。臨時路徑的有效期為一個小程式週期,所以完全可以快取本地臨時路徑。這樣重複生成canvas時只會下載動態圖片,複用固定圖片路徑,避免重複下載~另外圖片域名需配置在小程式後臺,為避免意外,下載圖片前應先對圖片url做一次校驗,校驗失敗直接跳過下載或換用兜底圖。
-
下載圖片到本地
在save圖片前,需要先呼叫
wx.getSetting()
來獲取使用者是否已允許下載圖片到本地許可權,或是喚起請求許可權彈窗。如果許可權被拒絕,則最好給出toast提示,同時把下載按鈕重置為open-type="openSetting"
,使用者再次點選時,引導跳轉至授權頁面。
另外使用時也有兩點不溫馨提示:
-
canvas元件顯隱控制
不建議將canvas元件用wx:if控制顯隱,因為將canvas元件掛載至頁面後,要經過200ms左右的延遲才能draw()成功。建議直接用display:none/block來控制,這樣也方便實現圖片預下載。
-
結合業務抽離元件
建議結合當前業務將生成分享圖功能進一步抽離成元件,包括內嵌點選canvas預覽圖片,儲存canvas為圖片按鈕(相容未授權下載圖片跳轉授權頁情況)等。亦可更靈活的自由控制畫圖及更新畫圖的時機。
注意到這兩點後,就可以分分鐘擼出一個動態生成圖啦~
附:完整API
初始化
new CanvasPainter(options)
options
-
canvsId
: canvas-id。 -
context
: canvas使用時上下文,在元件內使用時傳入this即可。 -
config
: Array[]。繪圖路徑。支援型別如下:-
rect 矩形
完整配置:{ type: `rect`, width: 640, height: 560, x:0, y:0, color: `#fff`, // fill下為填充顏色,storke下為筆跡顏色 stroke(可選): true, // 代表模式為fill還是stroke。預設false,即fill狀態。 round(可選): true, // 代表是否為圓形。預設false。 } 複製程式碼
-
text 文字
完整配置:{ type: `text`, x:0, y:30, color: `#fff`, // 字色 font: `xx`, // 字型 size: 20, //字號 align: `center`, //對齊。預設left。 decoration(可選): `line-through`, // 暫時只有中劃線模式哈哈哈 } 複製程式碼
-
multiline_text 多行文字
完整配置:{ type: `multiline_text`, line_limit: 30, //每行字數 line_height: 20, //行高 ... //其餘都與text一致 } 複製程式碼
-
image 圖片
完整配置:{ type: `image`, url: ``, //圖片路徑 x: ``, y: ``, width: ``, height:``, round(可選): true, // 圓形。預設false。 } 複製程式碼
-
-
saleBase(可選)
: 按設計稿尺寸來,預設750。
預下載圖片:
canvasPainter.loadImgInAdvance()
。可在例項化CanvasPainter後立即呼叫。
繪圖:
canvasPainter.draw()
預覽大圖:
canvasPainter.preview()
儲存成圖片:
canvasPainter.save()
更改config:
canvasPainter.resetConfig(newConfig)