小程序畫布canvas

/**
需要繪制的內(nèi)容有:
> 圖片
  1枝缔、背景圖
  2瞬雹、頭像
  3粗蔚、邀請(qǐng)語(yǔ)
  4靡菇、商品圖
  5昌讲、二維碼
  6国夜、指紋

>文字
  1、0
  2短绸、元搶購(gòu)
  3车吹、原價(jià)¥999.00
  4、商品標(biāo)題
  5醋闭、長(zhǎng)按識(shí)別二維碼 進(jìn)入活動(dòng)
  6窄驹、此二維碼已安全認(rèn)證,可以放心掃描*/

// 繪制圓形頭像
function circleImg(ctx, img, x, y, r) {
  ctx.save();
  var d = 2 * r;
  var cx = x + r;
  var cy = y + r;
  ctx.arc(cx, cy, r, 0, 2 * Math.PI);
  ctx.clip();
  ctx.drawImage(img, x, y, d, d);
  ctx.restore();
}

// 文字換行
function textWrap(ctx, str, initX, initY, lineHeight, cavWithd) {
  let lineWidth = 0;
  let canvasWidth = cavWithd ? cavWithd : 240;
  let lastSubStrIndex = 0;
  if (!lineHeight) {
    lineHeight = 20;
  }
  let _addLineHeight = 0;
  for (let i = 0; i < str.length; i++) {
    lineWidth += ctx.measureText(str[i]).width;
    if (lineWidth > canvasWidth - initX) {  //減去initX,防止邊界出現(xiàn)的問(wèn)題
      ctx.fillText(str.substring(lastSubStrIndex, i), initX, initY);
      initY += lineHeight;
      lineWidth = 0;
      lastSubStrIndex = i;
      _addLineHeight += lineHeight;
      //++lineNum
    }
    if (i == str.length - 1) {
      ctx.fillText(str.substring(lastSubStrIndex, i + 1), initX, initY);
    }
  }
  return _addLineHeight;
}

let drawCanvas = function (that, shareInfo) {
  if(that.data.resultimg){
    return
  }
  let userInfoData = wx.getStorageSync('userInfoData') || {}
  // 圖片
  let img = {
    bg: 'https://dahoutai.side.vip/project/activity/theme/poster/wx-share-bg2.jpg',
    avatar: shareInfo.avatar || 'https://dahoutai.side.vip/project/app/memberCard/default-avatar.png',
    text: 'https://dahoutai.side.vip/project/activity/theme/poster/text.png',
    goods: shareInfo.goods,
    logo: userInfoData.brandlogo,
    gou: 'https://dahoutai.side.vip/project/activity/theme/poster/gou.png',
    qrcode: shareInfo.qrcode,
    fingerprint: 'https://dahoutai.side.vip/project/activity/theme/poster/two-code.png'
  }

  // 文字內(nèi)容
  let content = {
    zero: shareInfo.price,
    mTitle: '元搶購(gòu)',
    oPrice: `原價(jià)¥${shareInfo.cprice}`,
    pTitle: shareInfo.prize,
    tip: '長(zhǎng)按識(shí)別二維碼 進(jìn)入活動(dòng)',
    scan: '此二維碼已安全認(rèn)證证逻,可以放心掃描',
  }

  // 將圖片地址轉(zhuǎn)為臨時(shí)圖片
  let num = 0
  let goodsRate = 1 // 商品圖寬高比例
  let logoRate = 1 // logo比例
  for (let i in img) {
    wx.getImageInfo({
      src: img[i],
      success: function (res) {
        if(i == 'goods'){
          goodsRate = res.height/res.width
        }
        if(i == 'logoRate'){
          logoRate = res.height/res.width
        }
        img[i] = res.path
        ++ num

        if(num == 8){ // 這里有個(gè)異步問(wèn)題
          console.log('開始繪圖')
          // 繪制canvas
          let rate = .5 // 縮小比例
          let ctx = wx.createCanvasContext('myCanvas',that)
          /**圖片繪制*/
          ctx.drawImage(img.bg,0,0,750*rate,1334*rate) // 背景
          circleImg(ctx,img.avatar,30*rate,139*rate,33*rate) // 繪制頭像
          ctx.drawImage(img.text,86*rate,139*rate,632*rate,68*rate) // 推薦語(yǔ)

          // 商品圖需要做寬高自適應(yīng)居中
          // 圖片以高度為自適應(yīng)
          // 如果自適應(yīng)高度之后的圖片乐埠,超出ui的最大寬度,則再次進(jìn)行寬度自適應(yīng)調(diào)整和高度自適應(yīng)調(diào)整
          let goodsMaxWidth = 560*rate, // 商品ui最大寬度
            goodsMaxHeight = 372*rate, // 商品ui最大高度
            goodsWidth = 372/goodsRate*rate,
            goodsHeight = 372*rate,
            goodsDeviationX = 0,  // X軸偏移
            goodsDeviationY = 0   // Y軸偏移
          if( goodsWidth > goodsMaxWidth){
            goodsHeight = goodsHeight * (goodsMaxWidth/goodsWidth)
            goodsWidth = goodsMaxWidth
            goodsDeviationY = (goodsMaxHeight - goodsHeight)/2
          }else {
            goodsDeviationX = (goodsMaxWidth - goodsWidth)/2
          }

          ctx.drawImage(img.goods,95*rate+goodsDeviationX,436*rate+goodsDeviationY,goodsWidth,goodsHeight) // 商品圖
          ctx.drawImage(img.qrcode,243*rate,937*rate,100*rate,100*rate) // 二維碼
          ctx.drawImage(img.fingerprint,426*rate,937*rate,100*rate,100*rate) // 指紋
          ctx.drawImage(img.gou,190*rate, 1097*rate,24*rate,24*rate) // 勾
          ctx.drawImage(img.logo,275*rate,0*rate,200*rate,114*rate) // logo

          /**文字繪制*/
          // 商品標(biāo)題
          ctx.setFillStyle('#333333')//文字顏色:默認(rèn)黑色
          ctx.setFontSize(30*rate)  // 文字大小
          ctx.setTextAlign('left') // 文字居中
          textWrap(ctx,content.pTitle,103*rate, 858*rate,50*rate,660*rate)

          // 長(zhǎng)按識(shí)別二維碼 進(jìn)入活動(dòng)
          ctx.setFontSize(24*rate)
          ctx.setTextAlign('center') // 文字居中
          ctx.fillText(content.tip, 375*rate, 1084*rate)

          // 此二維碼已安全認(rèn)證囚企,可以放心掃描
          ctx.setTextAlign('left') // 文字居中
          ctx.setFontSize(20*rate)
          ctx.setFillStyle('#88AE5C')//文字顏色:默認(rèn)黑色
          ctx.fillText(content.scan, 220*rate, 1118*rate)

          // 活動(dòng)標(biāo)題
          // 活動(dòng)標(biāo)題由三部分組成:( 紅色0 元搶購(gòu) 原價(jià) )這邊需要根據(jù)原價(jià)進(jìn)行偏移控制
          // 原價(jià)

          // 紅色0
          let zeroDeviation = 0 // 紅色字體偏移
          let zero = '0'
          let oirginDeviation = 0 // 原價(jià)偏移
          let oirgin = '原價(jià)¥0'
          // content.zero = 65650
          content.zero = content.zero.toString()  // 蘋果手機(jī)必須字符串!!!!!!
          ctx.setFontSize(54*rate)
          let _zeroDeviation = parseFloat(ctx.measureText(zero).width)
          zeroDeviation = parseFloat(ctx.measureText(content.zero).width)
          zeroDeviation = (zeroDeviation-_zeroDeviation)/2
          if(shareInfo.cprice){ // 兼容舊數(shù)據(jù)沒(méi)有cprice字段
            // content.oPrice = '原價(jià)¥043434'
            ctx.setFontSize(34*rate)
            ctx.setFillStyle('#666666')//文字顏色:默認(rèn)黑色
            let _oirginDeviation = parseFloat(ctx.measureText(oirgin).width)
            oirginDeviation = parseFloat(ctx.measureText(content.oPrice).width)
            oirginDeviation = (oirginDeviation - _oirginDeviation)/2
            ctx.fillText(content.oPrice, 400*rate+zeroDeviation-oirginDeviation, 406*rate)
            // 繪制刪除線
            ctx.beginPath();
            ctx.setStrokeStyle('#666666')
            ctx.setLineWidth(1)
            ctx.moveTo(506*rate+zeroDeviation-oirginDeviation, 392*rate)
            ctx.lineTo(506*rate+zeroDeviation+oirginDeviation, 392*rate)
            ctx.closePath();
            ctx.stroke()

            // 紅色0
            ctx.setTextAlign('left')
            ctx.setFontSize(54*rate)
            ctx.setFillStyle('#FF0237')
            ctx.fillText(content.zero, 196*rate-zeroDeviation-oirginDeviation, 416*rate)


            // 元搶購(gòu)
            ctx.setFontSize(44*rate)
            ctx.setFillStyle('#333333')
            ctx.fillText(content.mTitle, 248*rate+zeroDeviation-oirginDeviation, 410*rate)
            ctx.draw()
          }else {
            // 紅色0
            ctx.setTextAlign('left')
            ctx.setFontSize(54*rate)
            ctx.setFillStyle('#FF0237')
            ctx.fillText(content.zero, 196*rate-zeroDeviation+50, 416*rate)
            // 元搶購(gòu)
            ctx.setFontSize(44*rate)
            ctx.setFillStyle('#333333')
            ctx.fillText(content.mTitle, 248*rate+zeroDeviation+50, 410*rate)
            ctx.draw()
          }


          setTimeout(()=>{
            if(that.data.shareImgFlag){ // 如果彈窗了丈咐,但是畫布還沒(méi)生成,這提醒下
              wx.showToast({
                title: '生成海報(bào)中...',
                mask: true,
                icon: 'loading'
              })
            }
            let rate = 2
            wx.canvasToTempFilePath({
              x: 0,
              y: 0,
              width: 375,
              height: 667,
              destWidth: 375*rate,
              destHeight: 667*rate,
              canvasId: 'myCanvas',
              success: function (res) {
                that.setData({
                  resultimg: res.tempFilePath
                })
                wx.hideLoading()
                console.log('繪圖成功')
              },
              fail: function () {
                // 導(dǎo)出圖片錯(cuò)誤
                /*wx.showModal({
                  title: '導(dǎo)出圖片時(shí)出錯(cuò)',
                  content: '請(qǐng)重新嘗試龙宏!',
                })*/
              },
              complete: function () {
                wx.hideLoading()
              }
            },that)
          },1000)
        }
      }
    })
  }

}

export default drawCanvas
總結(jié):中間涉及到比較坑的是標(biāo)題位移計(jì)算(發(fā)現(xiàn)數(shù)學(xué)能力現(xiàn)在倒退到小學(xué)水平了 lol)棵逊,還有一個(gè)兼容問(wèn)題:ctx.measureText(str)必須是字符串格式!R铩歹河!開發(fā)過(guò)程發(fā)現(xiàn)str為number類型,蘋果手機(jī)沒(méi)有反應(yīng)花吟,安卓可以秸歧,坑得一批,找了大半天~
效果
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末衅澈,一起剝皮案震驚了整個(gè)濱河市键菱,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖经备,帶你破解...
    沈念sama閱讀 219,490評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件拭抬,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡侵蒙,警方通過(guò)查閱死者的電腦和手機(jī)造虎,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,581評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)纷闺,“玉大人算凿,你說(shuō)我怎么就攤上這事±绻Γ” “怎么了氓轰?”我有些...
    開封第一講書人閱讀 165,830評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)浸卦。 經(jīng)常有香客問(wèn)我署鸡,道長(zhǎng),這世上最難降的妖魔是什么限嫌? 我笑而不...
    開封第一講書人閱讀 58,957評(píng)論 1 295
  • 正文 為了忘掉前任靴庆,我火速辦了婚禮,結(jié)果婚禮上怒医,老公的妹妹穿的比我還像新娘撒穷。我一直安慰自己,他們只是感情好裆熙,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,974評(píng)論 6 393
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著禽笑,像睡著了一般入录。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上佳镜,一...
    開封第一講書人閱讀 51,754評(píng)論 1 307
  • 那天僚稿,我揣著相機(jī)與錄音,去河邊找鬼蟀伸。 笑死蚀同,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的啊掏。 我是一名探鬼主播蠢络,決...
    沈念sama閱讀 40,464評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼迟蜜!你這毒婦竟也來(lái)了刹孔?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,357評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤娜睛,失蹤者是張志新(化名)和其女友劉穎髓霞,沒(méi)想到半個(gè)月后卦睹,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,847評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡方库,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,995評(píng)論 3 338
  • 正文 我和宋清朗相戀三年结序,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片纵潦。...
    茶點(diǎn)故事閱讀 40,137評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡徐鹤,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出酪穿,到底是詐尸還是另有隱情凳干,我是刑警寧澤,帶...
    沈念sama閱讀 35,819評(píng)論 5 346
  • 正文 年R本政府宣布被济,位于F島的核電站救赐,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏只磷。R本人自食惡果不足惜经磅,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,482評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望钮追。 院中可真熱鬧预厌,春花似錦、人聲如沸元媚。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,023評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)刊棕。三九已至炭晒,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間甥角,已是汗流浹背网严。 一陣腳步聲響...
    開封第一講書人閱讀 33,149評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留嗤无,地道東北人震束。 一個(gè)月前我還...
    沈念sama閱讀 48,409評(píng)論 3 373
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像当犯,于是被迫代替她去往敵國(guó)和親垢村。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,086評(píng)論 2 355