Skip to content
javascript
/**
 * 业务场景:
 * 微信小程序利用canvas生成海报分享图片
 * 唯一一个不同点在于,要根据返回list算canvas的高度(也就是高度是不确定的,图片可以无限长)
 * */

// 页面结构
;<block>
  <view class='dire-content' wx:if='{{postersShow}}' catchtouchmove='donMove'>
    <scroll-view scroll-y class='dire-scroll'>
      <canvas
        class='inviteCanvas'
        canvas-id='inviteCanvas'
        style='width:{{canvasWidth}}rpx;height:{{canvasHeight}}rpx;'
      >
        {' '}
      </canvas>
      <image
        class='canvasimg'
        src='{{canvasImg}}'
        style='width:630rpx;height:{{canvasHeight}}rpx'
      ></image>
    </scroll-view>
  </view>
  <view class='create-poster-wbtn' bindtap='saveInviteCard' wx:if='{{postersShow}}'>
    保存到手机
  </view>
</block>

const app = getApp()

var that
var articleApps = require('../../banyan/logics/articleApps')
var promise = require('../../vendor/lib/promise.min.js')

Page({
  data: {
    resultList: [],
    img: '',
    showModal: false, // 遮罩层
    showWeekly: false, // 分享
    postersShow: false, // 生成海报
    canWidth: Number,
    canHeight: Number,
  },

  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {
    that = this
    let wkid = options.wkid
    // let wkid = 8;
    // let title = "生命周期函数--监听页面加载生命周期函数--监听页面加载"
    that.setData({
      wkid: wkid,
      title: options.title,
      // title: title
    })
    that.getWeeklyList(wkid)

    // 扫码场景处理
    var scene = options.scene ? decodeURIComponent(options.scene) : false
    console.log(options)
    if (scene) {
      let param = scene.split(',')
      let wkidKey = param[0]
      // let wkidValue = param[1];
      if (param.length > 1 && wkidValue !== null) {
        that.getWeeklyList(wkidKey)
      } else {
        wx.switchTab({
          url: '/pages/index/index',
        })
      }
    }
  },

  /**
   * 生命周期函数--监听页面显示
   */
  onShow: function () {
    that.setData({
      resultList: [],
      img: '',
      showModal: false,
      showWeekly: false,
      postersShow: false,
    })
    if (!app.globalData.userInfo) {
      app.getCurrentUser((res) => {
        that.getWeeklyList(that.data.wkid)
      }, 2)
    } else {
      that.getWeeklyList(that.data.wkid)
    }
  },

  // 加载页面数据
  getWeeklyList(id) {
    let reqData = {
      wkid: id,
    }
    articleApps.weeklyList(
      {
        data: reqData,
      },
      that,
      (data) => {
        that.setData({
          resultList: data.list,
          img: data.qrcode,
        })
        that.dowloadImgFiles(that.data.img)
      }
    )
  },

  // 显示分享弹框
  share() {
    that.setData({
      showModal: true,
      showWeekly: true,
    })
  },

  // 显示canvas海报
  posters() {
    that.setData({
      showModal: true,
      showWeekly: false,
      postersShow: true,
    })
    that.getCanvasSize()
    that.drawInviteCard()
  },

  // 关闭分享弹框
  unShow() {
    that.setData({
      showModal: false,
      showWeekly: false,
      postersShow: false,
    })
  },

  // 下载图片
  downloadImage: function (url) {
    var ulpromise = new promise(function (resolve, reject) {
      wx.downloadFile({
        url: url,
        success: function (res) {
          resolve(res)
        },
        fail: function (e) {
          reject(e)
          console.log('download image failed')
        },
      })
    })
    return ulpromise
  },

  // 下载图片到缓存
  dowloadImgFiles(img) {
    try {
      var imgArr = []
      that
        .downloadImage(img)
        .then(
          function (res) {
            imgArr.push(res.tempFilePath)
            that.data.imgArr = imgArr
            return that.downloadImage(img)
          }.bind(this)
        )
        .then(function (res) {
          that.getCanvasSize()
          that.drawInviteCard()
        })
    } catch (err) {
      console.log(err)
      that.setData({
        loaded: true,
      })
      app.ulToast('加载失败', 0)
    }
  },

  // 获取画布宽高
  getCanvasSize() {
    wx.getSystemInfo({
      success(res) {
        that.setData({
          canWidth: res.windowWidth,
          canHeight: res.windowHeight,
        })
      },
    })
  },

  // 绘制邀请卡画布
  drawInviteCard(callback) {
    let imgArr = that.data.imgArr
    let con = that.data.resultList
    // 文本list添加序号
    for (let j = 0; j < con.length; j++) {
      con[j].index = j
    }
    let ctx = wx.createCanvasContext('inviteCanvas')

    // 设置单个主体内容高度
    let _height = 190

    // 绘制白色背景
    ctx.setFillStyle('#fff')
    ctx.fillRect(
      0,
      0,
      that.changeRpx(630),
      that.changeRpx(_height) * con.length + that.changeRpx(600)
    )
    // ctx.clip(); //剪切矩形后 开始画画
    ctx.fill()
    that.setData({
      canvasWidth: that.changeRpx(630) * 2,
      // canvasHeight: Math.round((that.changeRpx(_height) * con.length + that.changeRpx(680)) * 2)
      canvasHeight: (95 * con.length + 300) * 2,
    })

    // 文本标题
    // let title = "本周报告更新目录";
    let title = that.data.title
    ctx.beginPath()
    ctx.setFillStyle('#000')
    ctx.font = 'bold 16px Arial'
    // ctx.fillText(title, that.changeRpx(60), that.changeRpx(104));
    that.drawText(
      ctx,
      title,
      that.changeRpx(60),
      that.changeRpx(104),
      that.changeRpx(530),
      that.changeRpx(32),
      1
    )

    // 以下为研究中心本期更新内容
    let title_two = '以下为研究中心本期更新内容'
    ctx.beginPath()
    ctx.setFontSize(that.changeRpx(28))
    ctx.setFillStyle('#747474')
    ctx.font = 'nobold 14px Arial'
    ctx.fillText(title_two, that.changeRpx(60), that.changeRpx(150))

    // canvas主体内容
    for (let i = 0; i < con.length; i++) {
      // 标题
      let con_title = con[i].index + 1 + '.' + con[i].Title
      ctx.beginPath()
      ctx.setFillStyle('#000')
      ctx.font = 'bold 16px Arial'
      that.drawText(
        ctx,
        con_title,
        that.changeRpx(60),
        that.changeRpx(_height) * i + that.changeRpx(260),
        that.changeRpx(530),
        that.changeRpx(40),
        2
      )

      // 内容
      let con_content = con[i].Summary
      ctx.beginPath()
      ctx.setFillStyle('#747474')
      ctx.font = 'nobold 14px Arial'
      // 判断10的用意是因为第二行是摘要,要缩略与标题保持一致
      if (i < 10) {
        that.drawText(
          ctx,
          con_content,
          that.changeRpx(90),
          that.changeRpx(_height) * i + that.changeRpx(340),
          that.changeRpx(470),
          that.changeRpx(32),
          3
        )
      } else {
        that.drawText(
          ctx,
          con_content,
          that.changeRpx(110),
          that.changeRpx(_height) * i + that.changeRpx(340),
          that.changeRpx(470),
          that.changeRpx(32),
          3
        )
      }

      // // 设置文本之间距离
      // let distance = that.changeRpx(160);
      // // 线框
      // ctx.moveTo(that.changeRpx(40), that.changeRpx(200) + i * distance);
      // ctx.lineTo(that.changeRpx(600), that.changeRpx(200) + i * distance);
      // ctx.lineTo(that.changeRpx(600), that.changeRpx(340) + i * distance);
      // ctx.lineTo(that.changeRpx(40), that.changeRpx(340) + i * distance);
      // ctx.lineTo(that.changeRpx(40), that.changeRpx(340) + i * distance);
      // ctx.closePath(); //闭合路径
      // ctx.lineWidth = 1;
      // ctx.strokeStyle = '#F6F6F6';
      // ctx.stroke();
    }

    // 小程序二维码
    ctx.beginPath()
    ctx.drawImage(
      imgArr[0],
      that.changeRpx(230),
      that.changeRpx(_height) * con.length + that.changeRpx(260),
      that.changeRpx(172),
      that.changeRpx(172)
    )
    ctx.draw()

    setTimeout(() => {
      that.downloadCanvasImg(
        0,
        0,
        that.changeRpx(630),
        that.changeRpx(_height) * con.length + that.changeRpx(600),
        that.changeRpx(630) * 2,
        (that.changeRpx(_height) * con.length + that.changeRpx(630)) * 2
      )
    }, 500)
  },

  /**
   *
   * @method downloadCanvasImg 把当前画布指定区域的内容导出生成指定大小的图片,并返回文件路径
   * @param { Number } x 画布区域的左上角横坐标
   * @param { Number } y 画布区域的左上角纵坐标
   * @param { Number } width 画布区域的宽度
   * @param { Number } height 画布区域的高度
   * @param { Number } destWidth 图片的宽度
   * @param { Number } destHeight 图片的高度
   */
  downloadCanvasImg(x, y, width, height, destWidth, destHeight) {
    wx.canvasToTempFilePath({
      x: x,
      y: y,
      width: width,
      height: height,
      destWidth: destWidth,
      destHeight: destHeight,
      canvasId: 'inviteCanvas',
      fileType: 'jpg',
      quality: 2,
      success(res) {
        console.log(res)
        let filePath = res.tempFilePath
        that.setData({
          canvasImg: filePath,
        })
      },
      fail(err) {
        console.log(err)
      },
    })
  },

  /**
   *
   * @method centerText canvas文本居中
   * @param {*} ctx canvas对象
   * @param {*} text 文字
   * @param {*} fontSzie 字体
   * @param {*} color 颜色
   * @param {*} height 绘制高度
   */
  centerText(ctx, text, fontSzie, color, height) {
    ctx.font = fontSzie
    ctx.fillStyle = color
    ctx.textAlign = 'center'
    ctx.textBaseline = 'middle'
    ctx.fillText(text, ctx.width / 2, height)
  },

  /**
   *
   * @method drawText canvas文本超过隐藏
   * @param {*} ctx canvas对象
   * @param {*} text 文字
   * @param {*} x X轴
   * @param {*} y Y轴
   * @param {*} maxWidth 文本宽度
   * @param {*} lineHeight 行高
   * @param {*} maxLine 显示行数
   */
  drawText(ctx, text, x, y, maxWidth, lineHeight, maxLine) {
    let arrText = text.split('')
    let line = ''
    let num = 1
    for (let n = 0; n < arrText.length; n++) {
      let testLine = line + arrText[n]
      let metrics = ctx.measureText(testLine)
      let testWidth = metrics.width
      if (testWidth > maxWidth && n > 0) {
        if (maxLine != undefined && num >= maxLine) {
          ctx.fillText(line.substr(0, line.length - 1) + '...', x, y)
          return num
        }
        num++
        ctx.fillText(line, x, y)
        line = arrText[n]
        y += lineHeight
      } else {
        line = testLine
      }
    }
    ctx.fillText(line, x, y)
    return num
  },

  // canvas圆角
  // drawRoundRect()
  drawRoundRect(ctx, x, y, width, height, radius) {
    ctx.beginPath()
    ctx.arc(x + radius, y + radius, radius, Math.PI, (Math.PI * 3) / 2)
    ctx.lineTo(width - radius + x, y)
    ctx.arc(width - radius + x, radius + y, radius, (Math.PI * 3) / 2, Math.PI * 2)
    ctx.lineTo(width + x, height + y - radius)
    ctx.arc(width - radius + x, height - radius + y, radius, 0, (Math.PI * 1) / 2)
    ctx.lineTo(radius + x, height + y)
    ctx.arc(radius + x, height - radius + y, radius, (Math.PI * 1) / 2, Math.PI)
    ctx.closePath()
  },

  // 转换rpx单位为px
  changeRpx(rpx) {
    return (rpx * that.data.canWidth) / 750
  },

  // 保存图片
  saveInviteCard(e) {
    app.saveCanvasToAlbum(e, that, (res) => {
      app.ulToast('保存成功', 1)
      that.setData({
        showModal: false,
        showWeekly: false,
        postersShow: false,
      })
    })
  },
})
//