因为网络图片不能直接使用ctx.drawImage()插入。得使用uni.getImageInfo()方法下载后插入。
但是当画布中存在多张网络图片时,必须等待uni.getImageInfo()下载完成后才行。这样得下载套下载。太过于繁琐。所以定义了一个递归下载方法。同时避免下载图片异步,画布不显示的结果。
- /**
- * canvas文本自动换行,注意调用前要设置字体,例如: ctx.font = '12px Arial'
- * @param {*} ctx CanvasRenderingContext2D
- * @param {*} text 文本
- * @param {*} x
- * @param {*} y
- * @param {*} lw 所占宽度
- * @param {*} lh 行高
- * return 绘制文本所需的高度
- */
- const fillTextLineBreak = (ctx, text, x, y, lw, lh, color = '#000', font = '14') => {
- var i = 0;
- var n = 0;
- var r = -1;
- var initHeight = 0;
- ctx.font = "" + font + "px Arial"; //字体大小
- ctx.fillStyle = color; //字体颜色
- while (i < text.length) {
- while (ctx.measureText(text.substring(n, i)).width < lw && i < text.length) {
- i++
- }
- r++
- ctx.fillText(text.substring(n, i), x, y + lh * r)
- n = i
- }
- initHeight = lh * r;
- wx.setStorageSync('initHeight', initHeight);
- }
-
-
- /**
- * 自定义函数roundRect
- * 画圆弧
- * ctx >> 画布
- *bg_x 图片的x坐标
- *bg_y 图片的y坐标
- *bg_w 图片宽度
- *bg_h 图片高度
- *bg_r 图片圆角
- *
- */
- function roundRect(ctx, img, bg_x, bg_y, bg_w, bg_h, bg_r) {
- // 开始绘制
- ctx.save();
- ctx.beginPath();
- ctx.arc(bg_x + bg_r, bg_y + bg_r, bg_r, Math.PI, Math.PI * 1.5);
- ctx.arc(bg_x + bg_w - bg_r, bg_y + bg_r, bg_r, Math.PI * 1.5, Math.PI * 2);
- ctx.arc(bg_x + bg_w - bg_r, bg_y + bg_h - bg_r, bg_r, 0, Math.PI * 0.5);
- ctx.arc(bg_x + bg_r, bg_y + bg_h - bg_r, bg_r, Math.PI * 0.5, Math.PI);
- ctx.clip();
- ctx.drawImage(img, bg_x, bg_y, bg_w, bg_h);
- // 恢复之前保存的绘图上下文
- ctx.restore();
- }
-
-
- /*
- * 画布网络图片预处理
- */
- function canvasImage(that, Datas = {}, callback = null) {
- var i = Datas.i ? Datas.i : 0;
- var callback_Datas = Datas.callback_Datas ? Datas.callback_Datas : [];
- var data = Datas.data ? Datas.data : [];
- uni.getImageInfo({
- src: data[i],
- success(res) {
- i++;
- callback_Datas.push(res.path)
- if (i == data.length) {
- //回调函数
- if (callback) {
- callback(that, callback_Datas);
- return;
- }
- } else {
- //递归执行下一个上传
- canvasImage(that, {
- i,
- callback_Datas,
- data,
- }, callback);
- }
- },
- fail(e) {
- wx.hideLoading();
- //关闭画布弹窗
- that.posterHideCanvas();
- setTimeout(function() {
- wx.showToast({
- title: '生成失败,稍后再试',
- icon: 'none',
- })
- }, 0)
- }
- });
- }
-
- /**
- * 自定义函数roundRect
- * 画圆弧背景
- * ctx >> 画布
- *bg_x 背景的x坐标
- *bg_y 背景的y坐标
- *bg_w 背景宽度
- *bg_h 背景高度
- *bg_r 背景圆角
- *
- */
- function roundRectKuang(ctx, bg_x, bg_y, bg_w, bg_h, bg_r, color = '#fff') {
- // 开始绘制
- ctx.save();
- ctx.beginPath();
- ctx.arc(bg_x + bg_r, bg_y + bg_r, bg_r, Math.PI, Math.PI * 1.5);
- ctx.arc(bg_x + bg_w - bg_r, bg_y + bg_r, bg_r, Math.PI * 1.5, Math.PI * 2);
- ctx.arc(bg_x + bg_w - bg_r, bg_y + bg_h - bg_r, bg_r, 0, Math.PI * 0.5);
- ctx.arc(bg_x + bg_r, bg_y + bg_h - bg_r, bg_r, Math.PI * 0.5, Math.PI);
- ctx.clip();
- ctx.fillStyle = color;
- ctx.fillRect(bg_x, bg_y, bg_w, bg_h);
- // 恢复之前保存的绘图上下文
- ctx.restore();
- }
- <view v-show="posterDatas.hidden" @touchmove="posterTouchMove" class="canvasMain flex center">
- <view class="box flex center column">
- <canvas :canvas-id="canvasId" :style="canvasStyle" class="canvas">canvas>
- <button v-if="posterDatas.buttonType==1" class="btn" @click="posterDownImage">点击保存图片到相册button>
- <button v-else-if="posterDatas.buttonType==2" class="btn">已保存到相册,快去分享吧button>
- <button v-else-if="posterDatas.buttonType==3" class="btn" open-type="openSetting"
- bindopensetting="posterOpenSetting">进入设置页,开启“保存到相册”button>
- <text class="iconfont icon-x" @click="posterHideCanvas">text>
- view>
- view>
-
- <style>
- /* 海报 */
- .canvasMain {
- position: fixed;
- left: 0;
- top: 0;
- width: 100%;
- height: 100%;
- background-color: rgba(0, 0, 0, 0.6);
- z-index: 9999;
- }
-
- .canvasMain.hidden {
- top: 100%;
- left: 100%;
- }
-
- .canvasMain .box {
- position: relative;
- }
-
- .canvasMain .box .canvas {
- margin: 0;
- }
-
- .canvasMain .box .btn {
- height: 40px;
- width: 280px;
- background-color: rgba(0, 0, 0, 0.3);
- border-radius: 40px;
- color: #fff;
- font-size: 15px;
- }
-
- .canvasMain .box .btn {
- margin: 10px 0;
- padding-left: 0;
- padding-right: 0;
- }
-
- .canvasMain .box .iconfont {
- font-size: 46rpx;
- color: #fff;
- }
- style>
- data() {
- return {
- posterDatas: {
- width: 285, //画布宽度
- height: 406, //画布高度
- buttonType: 1,
- hidden: false, // 是否隐藏海报弹窗
- success: false, // 是否成功生成过海报
- },
- canvasId: 'firstCanvas',
- canvasStyle: 'width: 285px; height: 406px;', // 根据实际需要设置 canvas 的宽高
- };
- },
-
- //海报生成配置
- posterSetCanvas() {
- var that = this
- var posterDatas = that.posterDatas;
- var tempConfig = that.tempConfig;
- //展示海报弹窗
- that.posterDatas.hidden = true;
- util.showLoading('生成中');
- var userInfo = wx.getStorageSync('userInfo') || {};
-
- var Datas = {};
- Datas.i = 0;
- Datas.callback_Datas = [];
- Datas.data = [];
- Datas.data[0] = userInfo.touimg; //头像
- Datas.data[1] = app.globalData.swtCircle + "/mp_ewm_v2.php?act=getwxacode&tjrhao=" + (userInfo
- .tjrhao || '') + "&url=pages/home/home"; //小程序码
- util.canvasImage(that, Datas, function(that, canvasImage_arr) {
- //要延时执行的代码
- setTimeout(function() {
- //预处理画布网络地址图片
- var ctx = uni.createCanvasContext(that.canvasId, that);
- // 清除背景
- //ctx.clearRect(0, 0, posterDatas.width, posterDatas.height);
- // 绘制背景
- // ctx.fillStyle = "#fff";
- // ctx.fillRect(0, 0, posterDatas.width, posterDatas.height);
- var bgImg = '/static/images/yao_bj.png';
- // 绘制背景图
- ctx.drawImage(bgImg, 0, 0, posterDatas.width, posterDatas.height);
-
- //简介
- util.fillTextLineBreak(ctx, "邀请您使用" + tempConfig.appMain.name + "小程序", 100, 81, 150,
- 20, '#fff',
- 13);
- //标题文字
- ctx.font = "bold 18px PingFang SC";
- ctx.fillStyle = "#fff";
- ctx.textAlign = "start";
- ctx.fillText(userInfo.nickName_hai, 100, 60);
-
- util.roundRect(ctx, canvasImage_arr[0], 30, 35, 56, 56, 28);
-
- ctx.font = "bold 18px PingFang SC";
- ctx.fillStyle = "#0D7239";
- ctx.textAlign = "start";
- ctx.fillText('分享有礼 荐者有份', 70, 170);
-
- ctx.drawImage(canvasImage_arr[1], 65, 200, 160, 160);
- ctx.draw();
- wx.hideLoading();
-
- }, 200)
- });
- },
-
- //海报下载图片
- posterDownImage: function() {
- var that = this
- util.showLoading('保存中');
- var posterDatas = that.posterDatas
- uni.canvasToTempFilePath({
- canvasId: "firstCanvas",
- success(res) {
- console.log(res)
- wx.showToast({
- icon: 'none',
- title: '已保存到相册,快去分享吧',
- })
- posterDatas["buttonType"] = 2;
- that.posterDatas = posterDatas;
-
- // 在 h5 中,res.tempFilePath 返回的是 base64 类型要处理,通过 a 标签的形式下载
- var arr = res.tempFilePath.split(',');
- var bytes = atob(arr[1]);
- let ab = new ArrayBuffer(bytes.length);
- let ia = new Uint8Array(ab);
- for (let i = 0; i < bytes.length; i++) {
- ia[i] = bytes.charCodeAt(i);
- }
- var blob = new Blob([ab], {
- type: 'application/octet-stream'
- });
- var url = URL.createObjectURL(blob);
- var a = document.createElement('a');
- a.href = url;
- a.download = new Date().valueOf() + ".png";
- var e = document.createEvent('MouseEvents');
- e.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false,
- false, 0, null);
- a.dispatchEvent(e);
- URL.revokeObjectURL(url);
- },
- fail(e) {
- console.log(e, "fail");
- util.showToast('保存失败,稍后再试”', 'none');
- that.posterHideCanvas();
- }
- })
- },
-
- //海报隐藏弹窗
- posterHideCanvas: function() {
- var that = this;
- that.posterDatas.buttonType = 1;
- that.posterDatas.hidden = false;
- },
-
- //海报弹窗禁止屏幕滚动
- posterTouchMove: function() {
- //在蒙层加上 catchtouchmove 事件
- //这里什么都不要放
- },