輕松生成小程序分享海報

小程序海報組件

https://github.com/jasondu/wx...

需求

小程序分享到朋友圈只能使用小程序碼海報來實現,生成小程序碼的方式有兩種,一種是使用后端方式,一種是使用小程序自帶的canvas生成;后端的方式開發難度大,由于生成圖片耗用內存比較大對服務端也是不小的壓力;所以使用小程序的canvas是一個不錯的選擇,但由于canvas水比較深,坑比較多,還有不同海報需要重現寫渲染流程,導致代碼冗余難以維護,加上不同設備版本的情況不一樣,因此小程序海報生成組件的需求十分迫切。

在實際開發中,我發現海報中的元素無非一下幾種,只要實現這幾種,就可以通過一份配置文件生成各種各樣的海報了。

海報中的元素分類

要解決的問題

  • 單位問題
  • canvas隱藏問題
  • 圓角矩形、圓角圖片
  • 多段文字
  • 超長文字和多行文字縮略問題
  • 矩形包含文字
  • 多個元素間的層級問題
  • 圖片尺寸和渲染尺寸不一致問題
  • canvas轉圖片
  • IOS 6.6.7 clip問題
  • 關于獲取canvas實例

單位問題

canvas繪制使用的是px單位,但不同設備的px是需要換算的,所以在組件中統一使用rpx單位,這里就涉及到單位怎么換算問題。

通過wx.getSystemInfoSync獲取設備屏幕尺寸,從而得到比例,進而做轉換,代碼如下:

const sysInfo = wx.getSystemInfoSync();
const screenWidth = sysInfo.screenWidth;
this.factor = screenWidth / 750;    // 獲取比例
function toPx(rpx) {    // rpx轉px
    return rpx * this.factor;
}
function toRpx(px) {    // px轉rpx
    return px / this.factor;
},

canvas隱藏問題

在繪制海報過程時,我們不想讓用戶看到canvas,所以我們必須把canvas隱藏起來,一開始想到的是使用display:none; 但這樣在轉化成圖片時會空白,所以這個是行不通的,所以只能控制canvas的絕對定位,將其移出可視界面,代碼如下:

.canvas.pro {
    position: absolute;
    bottom: 0;
    left: -9999rpx;
}

圓角矩形、圓角圖片

由于canvas沒有提供現成的圓角api,所以我們只能手工畫啦,實際上圓角矩形就是由4條線(黃色)和4個圓弧(紅色)組成的,如下:

圓弧可以使用canvasContext.arcTo這個api實現,這個api的入參由兩個控制點一個半徑組成,對應上圖的示例

canvasContext.arcTo(x1, y1, x2, y2, r)

接下來我們就可以非常輕松的寫出生成圓角矩形的函數啦

/**
 * 畫圓角矩形
 */
_drawRadiusRect(x, y, w, h, r) {
    const br = r / 2;
    this.ctx.beginPath();
    this.ctx.moveTo(this.toPx(x + br), this.toPx(y));            // 移動到左上角的點
    this.ctx.lineTo(this.toPx(x + w - br), this.toPx(y));        // 畫上邊的線
    this.ctx.arcTo(this.toPx(x + w), this.toPx(y), this.toPx(x + w), this.toPx(y + br), this.toPx(br));                                                    // 畫右上角的弧        
    this.ctx.lineTo(this.toPx(x + w), this.toPx(y + h - br));    // 畫右邊的線
    this.ctx.arcTo(this.toPx(x + w), this.toPx(y + h), this.toPx(x + w - br), this.toPx(y + h), this.toPx(br));                                              // 畫右下角的弧
    this.ctx.lineTo(this.toPx(x + br), this.toPx(y + h));        // 畫下邊的線
    this.ctx.arcTo(this.toPx(x), this.toPx(y + h), this.toPx(x), this.toPx(y + h - br), this.toPx(br));                                                    // 畫左下角的弧
    this.ctx.lineTo(this.toPx(x), this.toPx(y + br));            // 畫左邊的線
    this.ctx.arcTo(this.toPx(x), this.toPx(y), this.toPx(x + br), this.toPx(y), this.toPx(br));                                                    // 畫左上角的弧
}

如果是 畫線框 就使用 this.ctx.stroke();

如果是 畫色塊 就使用 this.ctx.fill();

如果是 圓角圖片 就使用

this.ctx.clip();
this.ctx.drawImage(***);

clip() 方法從原始畫布中剪切任意形狀和尺寸。一旦剪切了某個區域,則所有之后的繪圖都會被限制在被剪切的區域內(不能訪問畫布上的其他區域)。可以在使用 clip() 方法前通過使用 save() 方法對當前畫布區域進行保存,并在以后的任意時間對其進行恢復(通過 restore() 方法)。

多段文字

如果是連續多段不同格式的文字,如果讓用戶每段文字都指定坐標是不現實的,因為上一段文字的長度是不固定的,這里的解決方案是使用 ctx.measureText (基礎庫 1.9.90 開始支持)Api來計算一段文字的寬度,記住這里返回寬度的單位是px( ),從而知道下一段文字的坐標。

超長文字和多行文字縮略問題

設置文字的寬度,通過 ctx.measureText 知道文字的寬度,如果超出設定的寬度,超出部分使用“...”代替;對于多行文字,經測試發現字體的高度大約等于字體大小,并提供lineHeight參數讓用戶可以自定義行高,這樣我們就可以知道下一行的y軸坐標了。

矩形包含文字

這個同樣使用 ctx.measureText 接口,從而控制矩形的寬度,當然這里用戶還可以設置paddingLeft和paddingRight字段;

文字的垂直居中問題可以設置文字的基線對齊方式為middle( this.ctx.setTextBaseline('middle'); ),設置文字的坐標為矩形的中線就可以了;水平居中 this.ctx.setTextAlign('center'); ;

多個元素間的層級問題

由于canvas沒有Api可以設置繪制元素的層級,只能是根據后繪制層級高于前面繪制的方式,所以需要用戶傳入zIndex字段,利用數組排序(Array.prototype.sort)后再根據順序繪制。

圖片尺寸和渲染尺寸不一致問題

繪制圖片我們使用 ctx.drawImage() API;

如果使用 drawImage(dx, dy, dWidth, dHeight) ,圖片會壓縮尺寸以適應繪制的尺寸,圖片會變形,如下圖:

在基礎庫1.9.0起支持 drawImage(sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight),sx和sy是源圖像的矩形選擇框左上角的坐標,sWidth和sHeight是源圖像的矩形選擇框的寬度和高度,如下圖:

如果繪制尺寸比源圖尺寸寬,那么繪制尺寸的寬度就等于源圖寬度;反之,繪制尺寸比源圖尺寸高,那么繪制尺寸的高度等于源圖高度;

我們可以通過 wx.getImageInfo Api獲取源圖的尺寸;

canvas轉圖片

在canvas繪制完成后調用 wx.canvasToTempFilePath Api將canvas轉為圖片輸出,這樣需要注意, wx.canvasToTempFilePath 需要寫在 this.ctx.draw 的回調中,并且在組件中使用這個接口需要在第二個入參傳入this( ),如下

this.ctx.draw(false, () => {
    wx.canvasToTempFilePath({
        canvasId: 'canvasid',
        success: (res) => {
            wx.hideLoading();
            this.triggerEvent('success', res.tempFilePath);
        },
        fail: (err) => {
            wx.hideLoading();
            this.triggerEvent('fail', err);
        }
    }, this);
});

IOS 6.6.7 clip問題

在IOS 6.6.7版本中clip方法連續裁剪圖片時,只有第一張有效,這是微信的bug,官方也證實了( https://developers.weixin.qq....

關于獲取canvas實例

我們可以使用 wx.createCanvasContext 獲取小程序實例,但在組件中使用切記第二個參數需要帶上this,如下

this.ctx = wx.createCanvasContext('canvasid', this);

如何使用組件

https://github.com/jasondu/wx...

專欄作家

weizaidu。小程序社區博主,堅持原創分享技術博文。

本文原創發布于小程序社區。未經許可,禁止轉載

原文地址:輕松生成小程序分享海報-小程序社區/博主專區-微信小程序開發社區-微信小程序聯盟

相關文章:

小程序生成海報保存分享圖片完全指南

微信小程序朋友圈分享圖片生成方案實現

微信小程序中的分享事件

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 第一章 HTML5 (2014年10月29日發布)新特性: 10個 (1)新的語義標簽 (2)增強型表單 (3)視...
    fastwe閱讀 974評論 0 1
  • 啥是canvas? HTML5 標簽用于繪制圖像(通過腳本,通常是 JavaScript)。不過, 元素本身...
    kiaizi閱讀 787評論 0 4
  • 線條樣式 繪制直線,第五章知識簡單回顧 lineWidth 設置或返回當前的線條寬度,單位為像素 lineCap ...
    Zd_silent閱讀 499評論 0 0
  • 最怕一生碌碌無為,還說平凡可貴 站酷網看到一篇這樣的文章,寫的是愛情,感觸頗深! 今天又刷屏的“逃離北上廣” 引發...
    啡常識閱讀 267評論 2 1
  • 2015-09-08周二 晴 真正關注股市是去年12月份,某天看新聞說牛市要來了,于是持續關注了好一段時間。到今年...
    韓日記閱讀 626評論 0 3