关注前端 | 前端博客
当前位置: 微信小程序 > 微信小程序(canvas绘制海报)

微信小程序(canvas绘制海报)

2019-09-04 分类:微信小程序 作者:管理员 阅读(151)

小程序中有时需要生成一个海报,以供用户保存后分享到群里.需要哪些步骤已经应该注意哪些呢?

上一张效果图:

第一步:配置合法域名

微信小程序绑定的微信号登录微信公众号,配置好uploadFile 域名,否则会报错说配置的uploadFile域名列表里没有你的域名.

第二步:把网络图片下载到微信本地

图片要提前下载完之后再绘图,不然图片显示不出来,用到的方法是:

1
2
3
4
5
6
7
8
wx.downloadFile({
      url: imgUrl,
      success:res=>{
        if (res.statusCode === 200) {
          this.data.tempSrc= res.tempFilePath; //下载成功返回结果
        }
      }
 })

第三步:绘制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
//开始用canvas绘制分享海报
  drawCanvas(fn) {
    const ctx = wx.createCanvasContext('myCanvas'); //创建画布
    wx.createSelectorQuery().select('#canvas-container').boundingClientRect(rect=>{
   
      let width = rect.width;
      let height = rect.height;
      let right = rect.right;
      let left = 20;

      ctx.setFillStyle('#fff');               // 填充画布为白色
      ctx.fillRect(0, 0, rect.width, height); // 画一个矩形 两个坐标
      let posterHeight = 400;                 // 海报高度 总共600
      let avatarWidth = width/7;              // 头像宽度
      let avatarHeight = avatarWidth;         // 头像宽度

      //海报
      if (this.data.posterSrc) {
        ctx.drawImage(this.data.posterSrc, 0, 0, width, posterHeight);
      }

      //姓名
      if (this.data.Name) {
        var name = this.data.Name
        let maxNameWidth = width - avatarHeight
        let maxNameLength = parseInt(maxNameWidth / 16) - 1
        if (maxNameLength < name.length) {
          name = name.substring(0, maxNameLength) + '...'
        }
        ctx.font = 'normal bold 16px sans-serif';
        ctx.setFontSize(16);
        ctx.setFillStyle('#000');
        ctx.setTextAlign('left');
        ctx.fillText(name, left + avatarWidth + 15, posterHeight + 38, width - avatarHeight - 40 - 15);
      }

      // 头像
      if (this.data.avatarSrc) {
        ctx.drawImage(this.data.avatarSrc, left, posterHeight + 20, avatarHeight, avatarHeight)
        ctx.setFontSize(10);
        ctx.setFillStyle('#000');
      }

      //职位
      if (this.data.Position) {
        var position = this.data.Position
        let maxPositionWidth = width - 70
        let maxPositionLength = parseInt(maxPositionWidth / 12) - 2
        if (maxPositionLength < position.length) {
          position = position.substring(0, maxPositionLength) + '...'
        }
        ctx.setFontSize(12);
        ctx.setFillStyle('#676b6d');
        ctx.setTextAlign('left');
        ctx.fillText(position, left + avatarWidth + 15, posterHeight + 58);
      }

      //电话
      if (this.data.Mobile) {
        ctx.drawImage(this.data.phoneIconSrc, left, posterHeight + avatarHeight + 60, 15, 15);
        ctx.setFontSize(12);
        ctx.setFillStyle('#666');
        ctx.setTextAlign('left');
        ctx.fillText(this.data.Mobile, left + 20, posterHeight + avatarHeight + 73);
      }

      // 公司名称
      if (this.data.Company) {
        var companyName = this.data.Company
        let maxCompanyNameWidth = width - 120
        // console.log(maxCompanyNameWidth)
        let maxCompanyNameLength = parseInt(maxCompanyNameWidth / 12) - 1
        // console.log(maxCompanyNameLength)
        const CONTENT_ROW_LENGTH = maxCompanyNameLength * 2; // 正文 单行显示字符长度
        ctx.drawImage(this.data.addressIconSrc, left, posterHeight + avatarHeight + 85, 15, 15);
        let [contentLeng, contentArray, contentRows] = this.textByteLength(this.data.Company, CONTENT_ROW_LENGTH);
        ctx.setFontSize(12);
        ctx.setFillStyle('#666');
        ctx.setTextAlign('left');
        let contentHh = 22 * 1;
        for (let m = 0; m < contentArray.length; m++) {
          ctx.fillText(contentArray[m], left + 20, posterHeight + avatarHeight + 100 + contentHh * m);
        }
      }

      //  绘制二维码
      if (this.data.qrSrc) {
        ctx.drawImage(this.data.qrSrc, width - 90, posterHeight + avatarHeight + 30, 70, 70)
        ctx.setFontSize(8);
        ctx.setFillStyle('#6f7475');
        ctx.fillText("扫一扫或长按识别", width - 88, posterHeight + avatarHeight + 115);
      }
      ctx.draw();
      wx.hideLoading();
      fn && fn()
    }).exec()
  },
  /**
   * 多行文字处理,每行显示数量
   * @param text 为传入的文本
   * @param num  为单行显示的字节长度
   */

  textByteLength(text, num) {
    let strLength = 0; // text byte length
    let rows = 1;
    let str = 0;
    let arr = [];
    for (let j = 0; j < text.length; j++) {
      if (text.charCodeAt(j) > 255) {
        strLength += 2;
        if (strLength > rows * num) {
          strLength++;
          arr.push(text.slice(str, j));
          str = j;
          rows++;
        }
      } else {
        strLength++;
        if (strLength > rows * num) {
          arr.push(text.slice(str, j));
          str = j;
          rows++;
        }
      }
    }
    arr.push(text.slice(str, text.length));
    // console.log([strLength, arr, rows])
    return [strLength, arr, rows] //  [处理文字的总字节长度,每行显示内容的数组,行数]
  }
附上此效果图的全部代码:

wxml

ps:本人用的是colorUI,当然样式不重要,都是可以自己写出来的

1
2
3
4
5
6
7
8
9
10
<view class='poste_box' id='canvas-container'>
  <canvas canvas-id="myCanvas">
  </canvas>
</view>
<view class="btn-container">
  <button class="cu-btn block bg-mauve lg shadow-blur" catchtap="drawLasted">最新海报</button>
  <button class="cu-btn block bg-orange lg shadow-blur" catchtap="drawRandom">随机海报</button>
  <button class="cu-btn block bg-blue lg shadow-blur" catchtap="drawDefault">自定义海报</button>
  <button class="cu-btn block bg-green lg shadow-blur" catchtap="saveShareImg" >保存海报</button>
</view>

wxss

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
page {
  display: flex;
  flex-direction: column;
}
.btn-container{
  padding: 20rpx 30rpx 40rpx 30rpx;
  display: flex;
  justify-content: space-between;
}
.btn-container button{
  width: 160rpx;
  height: 60rpx!important;
  line-height: 60rpx;
  font-size: 24rpx!important;
  padding: 0!important;
  text-align: center;
  border-radius: 32rpx;
}
canvas{
  width:calc(100% - 30rpx);
  height:1200rpx;
  margin: 20rpx auto;
}

js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
const app = getApp()
Page({
  data:{
    avatar: '',                     //用户头像
    qrCode: "",                     //需要https图片路径
    Name: '',                       //姓名
    Position: "",                   //职位
    Mobile: "",                     //手机
    Company: "",                    //公司
    posterSrc: '',                  //海报图片
    avatarSrc: '',                  //用户头像
    phoneIconSrc: '',               //电话图标
    addressIconSrc: '',             //地址图标
    qrSrc: '',                      //二维码
    token: "",                      //七牛云token
    flag: true,                     //相机授权标识 默认授权 true
  },
  onLoad(options){
    this.data.card_id = options.card_id
    this.donwloadImg('https://pimg.llwangpu.com//1566886354972-8293', "phoneIconSrc")
    this.donwloadImg('https://pimg.llwangpu.com//1566886425694-8615', "addressIconSrc")
    app.apis.getQiniuToken().then(data => {this.data.token = data})
    this.init()
  },
  init(){
    wx.showLoading({ title: '生成中...', mask: true })
    //初始化海报
    this.initPosterInfo(1,()=>{
      //初始化名片信息
      this.initCardInfo(() => {
        //初始化二维码信息
        this.initQrInfo(() => {
          wx.hideLoading()
          //开始绘制海报
          this.drawCanvas()
        })
      })
    })
  },
  //初始化名片信息
  initCardInfo(fn){
    app.apis.getCardDetail(this.data.card_id).then(data => {
      this.donwloadImg(decodeURI(data.card_info.avatar), "avatarSrc",()=>{
        this.setData({
          avatar: data.card_info.avatar,
          Name: data.card_info.name,
          Position: data.card_info.position,
          Mobile: data.card_info.mobile_phone_number,
          Company: data.card_info.company_name
        })
        fn && fn()
      })
    })
  },
  //初始化二维码
  initQrInfo(fn){
    app.apis.getQr(1, this.data.card_id).then(res => {
      this.setData({ qrCode: res.url})
      this.donwloadImg(res.url, "qrSrc",()=>{
        fn && fn()
      })
    })
  },
  //初始化海报
  initPosterInfo(type,fn){
    app.apis.getPoster(type).then(res=>{
      this.donwloadImg(res.image_url, "posterSrc",()=>{
        fn && fn()
      })
    })
  },
  //初始化图片为本地图片
  donwloadImg(imgUrl,resultSrc,callback) {
    wx.downloadFile({
      url: imgUrl,
      success:res=>{
        if (res.statusCode === 200) {
          this.data[resultSrc] = res.tempFilePath; //下载成功返回结果
          callback && callback()
        }
      }
    })
  },
  //开始用canvas绘制分享海报
  drawCanvas(fn) {
    const ctx = wx.createCanvasContext('myCanvas'); //创建画布
    wx.createSelectorQuery().select('#canvas-container').boundingClientRect(rect=>{
   
      let width = rect.width;
      let height = rect.height;
      let right = rect.right;
      let left = 20;

      ctx.setFillStyle('#fff');               // 填充画布为白色
      ctx.fillRect(0, 0, rect.width, height); // 画一个矩形 两个坐标
      let posterHeight = 400;                 // 海报高度 总共600
      let avatarWidth = width/7;              // 头像宽度
      let avatarHeight = avatarWidth;         // 头像宽度

      //海报
      if (this.data.posterSrc) {
        ctx.drawImage(this.data.posterSrc, 0, 0, width, posterHeight);
      }

      //姓名
      if (this.data.Name) {
        var name = this.data.Name
        let maxNameWidth = width - avatarHeight
        let maxNameLength = parseInt(maxNameWidth / 16) - 1
        if (maxNameLength < name.length) {
          name = name.substring(0, maxNameLength) + '...'
        }
        ctx.font = 'normal bold 16px sans-serif';
        ctx.setFontSize(16);
        ctx.setFillStyle('#000');
        ctx.setTextAlign('left');
        ctx.fillText(name, left + avatarWidth + 15, posterHeight + 38, width - avatarHeight - 40 - 15);
      }

      // 头像
      if (this.data.avatarSrc) {
        ctx.drawImage(this.data.avatarSrc, left, posterHeight + 20, avatarHeight, avatarHeight)
        ctx.setFontSize(10);
        ctx.setFillStyle('#000');
      }

      //职位
      if (this.data.Position) {
        var position = this.data.Position
        let maxPositionWidth = width - 70
        let maxPositionLength = parseInt(maxPositionWidth / 12) - 2
        if (maxPositionLength < position.length) {
          position = position.substring(0, maxPositionLength) + '...'
        }
        ctx.setFontSize(12);
        ctx.setFillStyle('#676b6d');
        ctx.setTextAlign('left');
        ctx.fillText(position, left + avatarWidth + 15, posterHeight + 58);
      }

      //电话
      if (this.data.Mobile) {
        ctx.drawImage(this.data.phoneIconSrc, left, posterHeight + avatarHeight + 60, 15, 15);
        ctx.setFontSize(12);
        ctx.setFillStyle('#666');
        ctx.setTextAlign('left');
        ctx.fillText(this.data.Mobile, left + 20, posterHeight + avatarHeight + 73);
      }

      // 公司名称
      if (this.data.Company) {
        var companyName = this.data.Company
        let maxCompanyNameWidth = width - 120
        // console.log(maxCompanyNameWidth)
        let maxCompanyNameLength = parseInt(maxCompanyNameWidth / 12) - 1
        // console.log(maxCompanyNameLength)
        const CONTENT_ROW_LENGTH = maxCompanyNameLength * 2; // 正文 单行显示字符长度
        ctx.drawImage(this.data.addressIconSrc, left, posterHeight + avatarHeight + 85, 15, 15);
        let [contentLeng, contentArray, contentRows] = this.textByteLength(this.data.Company, CONTENT_ROW_LENGTH);
        ctx.setFontSize(12);
        ctx.setFillStyle('#666');
        ctx.setTextAlign('left');
        let contentHh = 22 * 1;
        for (let m = 0; m < contentArray.length; m++) {
          ctx.fillText(contentArray[m], left + 20, posterHeight + avatarHeight + 100 + contentHh * m);
        }
      }

      //  绘制二维码
      if (this.data.qrSrc) {
        ctx.drawImage(this.data.qrSrc, width - 90, posterHeight + avatarHeight + 30, 70, 70)
        ctx.setFontSize(8);
        ctx.setFillStyle('#6f7475');
        ctx.fillText("扫一扫或长按识别", width - 88, posterHeight + avatarHeight + 115);
      }
      ctx.draw();
      wx.hideLoading();
      fn && fn()
    }).exec()
  },
  /**
   * 多行文字处理,每行显示数量
   * @param text 为传入的文本
   * @param num  为单行显示的字节长度
   */

  textByteLength(text, num) {
    let strLength = 0; // text byte length
    let rows = 1;
    let str = 0;
    let arr = [];
    for (let j = 0; j < text.length; j++) {
      if (text.charCodeAt(j) > 255) {
        strLength += 2;
        if (strLength > rows * num) {
          strLength++;
          arr.push(text.slice(str, j));
          str = j;
          rows++;
        }
      } else {
        strLength++;
        if (strLength > rows * num) {
          arr.push(text.slice(str, j));
          str = j;
          rows++;
        }
      }
    }
    arr.push(text.slice(str, text.length));
    // console.log([strLength, arr, rows])
    return [strLength, arr, rows] //  [处理文字的总字节长度,每行显示内容的数组,行数]
  },
  //最新海报
  drawLasted(){
    wx.showLoading({ title: '生成中...', mask: true })
    app.apis.getPoster(1).then(res => {
      this.donwloadImg(decodeURI(res.image_url), "posterSrc",()=>{
        this.drawCanvas(()=>{
          wx.hideLoading()
        })
      })
    })
  },
  //随机海报
  drawRandom(){
    wx.showLoading({ title: '生成中...', mask: true })
    app.apis.getPoster(2).then(res => {
      this.donwloadImg(decodeURI(res.image_url), "posterSrc", ()=>{
        this.drawCanvas(()=>{
          wx.hideLoading()
        })
      })
    })
  },
  //自定义海报
  drawDefault(){
    app.tools.uploadImage(this.data.token).then(res => {
      this.donwloadImg(res.imageURL, "posterSrc",()=>{
        this.drawCanvas()
      })
    })
  },
  //保存海报
  saveShareImg(){
 
    if (this.data.flag){
      wx.showLoading({title: '正在保存',mask: true})
      wx.canvasToTempFilePath({
        canvasId: 'myCanvas',
        success: res => {
          wx.hideLoading();
          wx.saveImageToPhotosAlbum({
            filePath: res.tempFilePath,
            success:res => {
              wx.showModal({
                title:'提示',
                content: '图片已保存到相册,赶紧晒一下吧~',
                showCancel: false,
                confirmText: '好的',
                confirmColor: '#333',
                success: function (res) {
                  if (res.confirm) { }
                },
                fail: function (res) { }
              })
            },
            fail:res => {
              wx.showToast({
                title: '保存失败,再次点击授权',
                icon: 'none',
                duration: 2000
              })
              this.data.flag = false
            }
          })
        }
      });
    }else{
      wx.openSetting({
        success: settingdata => {
          // console.log(settingdata)
          if (settingdata.authSetting['scope.writePhotosAlbum']) {
            // console.log('获取权限成功,给出再次点击图片保存到相册的提示。')
            this.data.flag = true
          } else {
            // console.log('获取权限失败,给出不给权限就无法正常使用的提示')
            this.data.flag = false
          }
        }
      })
    }
  }
})
PS:

海报需要单个接口请求,头像、名字、职位、电话、公司需要一个接口初始化,二维码需要一个接口请求,由于个人项目实际情况,采用的是回调函数方式调用实现。
实现了最新海报、随机海报、自定义海报、保存海报(拒绝授权保存到相册的合理处理),app.tools.uploadImage 是封装的自定义上传海报,利用七牛云上传实现自定义上传

「两年博客,如果觉得我的文章对您有用,请帮助本站成长」

赞(0) 打赏

感谢您让我添加个鸡腿!

支付宝
微信
0

感谢您让我添加个鸡腿!

支付宝
微信
标签:

上一篇:

下一篇:

共有 0 条评论 - 微信小程序(canvas绘制海报)

博客简介

一位不知名的前端工程师,专注全栈技术,分享各种所遇问题与个人心得,梦想成为一位知名大神!

精彩评论

服务热线:
 177****6038

 QQ在线交流

 旺旺在线