效果图
注释:图中红色圈以及黑色圈等区域涉及隐私,故此马赛克处理(理解( •̀ ω •́ )✧)
wxml 区域
<!-- S 页面海报按钮区域 -->
<view catchtap="showDrawCanvasImg" class="sys-flex acPhone">
<view>
<image mode="aspectFill" src="../images/share.png" style="height: 23px;width:24px"></image>
</view>
<view style="margin-left: 15rpx">
<text>海报分享</text>
</view>
</view>
<!-- E 页面海报按钮区域 -->
<!-- S 海报分享区域 -->
<view catchtap="modalhide" class="share-wrap modal" wx:if="{{canvasimg!=''}}">
<image class="content-wrap draw" src="{{canvasimg}}"></image><!-- 图片显示区域 -->
<view catchtap="getSetting" class="btn-wrap">
<view data-text='保存海报分享好友'>保存海报分享好友</view>
</view>
</view>
<!-- E 海报分享区域 -->
wxss 区域
.share-wrap {
position: fixed;
top: 0;
left: 0vw;
background:rgba(0,0,0,0.5);
width: 100vw;
height: 100vh;
z-index: 99999;
}
.content-wrap {
position: absolute;
top: 15vh;
left: 13vw;
overflow: hidden;
height: 62vh;
width: 74vw;
background-color: #2E7DE3;
color: #333333;
}
.btn-wrap {
position: absolute;
top: 78vh;
left: 20vw;
z-index: 99;
width: 58.6vw;
height: 4.7vh;
line-height: 4.7vh;
margin: 2.75vh auto 0;
text-align: center;
color: #2E7DE3;
font-size: 31rpx;
background-color: #fff;
border-radius: 3vh;
}
js 区域
//关闭海报弹窗
modalhide() {
var that = this;
that.setData({
canvasimg: ''
})
},
// 生成海报
showDrawCanvasImg: function() {
var that = this;
wx.showLoading({
title: '正在生成',
icon: 'loading'
})
wx.downloadFile({
url: 'https://www.******',//三方产品图片(需要是https开头的,且域名需要在小程序后台的downloadFile合法域名里配置)
success: function(res) {
if (res.statusCode === 200) {
that.setData({
'shareData.image':res.tempFilePath
})
wx.downloadFile({
url: 'https://www.******',//三方产品图片(需要是https开头的,且域名需要在小程序后台的downloadFile合法域名里配置)
success: function(res) {
console.log(res)
if (res.statusCode === 200) {
that.setData({
'shareData.wechatCode':res.tempFilePath
})
let path1 = '../images/headIcon.png';
let path2 = that.data.shareData.image;
let wechatCode = that.data.shareData.wechatCode;
let customerName = that.data.shareData.customerName + that.data.shareData.userName;
let lineName = that.data.shareData.lineName;
let startCity = '出发地:' + that.data.shareData.startCity;
let price = "¥" + that.data.shareData.price;
that.createNewImg(path1,customerName,path2,lineName,startCity,price,wechatCode);
} else {
wx.hideLoading();
wx.showToast({
title: '图片加载失败',
icon:'none'
})
}
},
fail:function() {
wx.hideLoading();
wx.showToast({
title: '图片加载失败',
icon:'none'
})
}
})
} else {
wx.hideLoading();
wx.showToast({
title: '图片加载失败',
icon:'none'
})
}
},
fail:function() {
wx.hideLoading();
wx.showToast({
title: '图片加载失败',
icon:'none'
})
}
})
},
/**
* 生成canvas区域
* @param {string} path1 logo左上角图标
* @param {string} customerName 供应商名称
* @param {string} path2 分享轮播图
* @param {string} lineName 产品名称
* @param {string} startCity 出发城市
* @param {string} price 价格
* @param {string} wechatCode 二维码图
*/
createNewImg(path1,customerName,path2,lineName,startCity,price,wechatCode,) {
var that = this;
var context = wx.createCanvasContext('customCanvas',this);
var rpx = that.data.canvasWidth;
context.setFillStyle("#2E7DE3")//背景颜色蓝色
context.fillRect(0, 0, rpx * 375, 576 * rpx);//背景颜色蓝色
context.setFillStyle("#ffffff")//背景颜色白色
that.roundRect(context,15 * rpx, 14 * rpx, 345 * rpx, 548 * rpx,6,'#fff')
// context.fillRect(28, 30, 325, 480);//背景颜色白色
context.drawImage(path1, 30 * rpx, 29 * rpx, 36 * rpx, 36 * rpx);//logo左上角
//绘制供应商名字
var name = customerName;//绘制供应商名字
context.setFontSize(15);
context.setTextBaseline('top');
context.setFillStyle('#333333');//绘制供应商名字
context.fillText(name.length < 15 ? name : name.substring(0,10) + '...', 74 * rpx, 30 * rpx);//绘制供应商名字
//绘制为您推荐
context.setFontSize(15);
context.setFillStyle('#999');
context.setTextBaseline('top');
context.fillText("为您推荐", 74 * rpx, 50 * rpx);
context.stroke();
// 分享轮播图
context.drawImage(path2, 30 * rpx, 80 * rpx, 315 * rpx, 188 * rpx);
// 分割线
var path3 = '../images/line.png';
// 背景图
var path4 = '../images/background.png';
//绘制产品名称
context.setFontSize(20);
context.setFillStyle('#333333');
if(lineName.length > 15) {
if(lineName.length > 30) {
context.fillText(`${lineName.slice(0, 15)}`, 30*rpx, 278 * rpx);
context.fillText(`${lineName.slice(15, 30)}`, 30*rpx, 298 * rpx);
context.fillText(`${lineName.slice(30, 45)}`, 30*rpx, 318 * rpx);
} else {
context.fillText(`${lineName.slice(0, 15)}`, 30*rpx, 278 * rpx);
context.fillText(`${lineName.slice(15, 30)}`, 30*rpx, 298 * rpx);
}
} else {
context.fillText(lineName, 30 * rpx, 278 * rpx);
}
context.stroke();
//绘制出发地
context.setFontSize(14);
context.setFillStyle('#999');
context.fillText(startCity, 30 * rpx, 353 * rpx);
context.stroke();
//绘制价格
context.setFontSize(20);
context.setFillStyle('#F43530');
context.setTextAlign('right');
context.fillText(price, 344 * rpx, 353 * rpx);
context.stroke();
//绘制分割线
context.drawImage(path3,30 * rpx, 391 * rpx, 315 * rpx, 2 * rpx);
// 绘制左侧半圆
context.beginPath()
context.arc(14 * rpx, 392 * rpx, 15 * rpx, 0,360,false)
context.fillStyle ='#2E7DE3';
context.fill();
context.closePath();
// 绘制右侧半圆
context.beginPath()
context.arc(359 * rpx, 392 * rpx, 15 * rpx, 0,360,false)
context.fillStyle ='#2E7DE3';
context.fill();
context.closePath();
// 绘制二维码
context.drawImage(wechatCode, 30 * rpx, 442 * rpx, 80 * rpx, 80 * rpx);//二维码
// 绘制 长按图片识别二维码,抢购此产品
context.setFontSize(15);
context.setFillStyle('#333');
context.setTextAlign('left');
context.fillText("长按图片识别二维码抢购", 122 * rpx, 461 * rpx);
context.stroke();
// 绘制 分享自***
context.setFontSize(15);
context.setFillStyle('#999');
context.setTextAlign('left');
context.fillText("分享自***", 122 * rpx, 486 * rpx);
context.stroke();
// 绘制背景图
context.drawImage(path4, 0, 480 * rpx, rpx * 375, 96 * rpx);// 背景图
context.draw(false,function() {
setTimeout(function () {
wx.canvasToTempFilePath({
x: 0,
y: 0 ,
width: rpx * 375,
height: rpx * 576,
canvasId: 'customCanvas',
fileType: 'jpg',
success: function (res) {
wx.hideLoading()
that.setData({
canvasimg: res.tempFilePath,
})
},
fail:function() {
wx.hideLoading();
}
})
}, 500)
});
},
//打开手机相册授权
getSetting() {
var that = this;
wx.getSetting({
success(res) {
if (!res.authSetting['scope.writePhotosAlbum']) {
wx.authorize({
scope: 'scope.writePhotosAlbum',
success() { //这里是用户同意授权后的回调
that.baocun();
that.setData({
setting: false,
})
},
fail() { //这里是用户拒绝授权后的回调
that.setData({
setting: true,
})
}
})
} else { //用户已经授权过了
that.baocun();
}
}
})
},
//海报保存相册
baocun() {
var that = this;
setTimeout(function() {
wx.saveImageToPhotosAlbum({
filePath: that.data.canvasimg,
success: function() {
wx.showToast({
title: '已保存图片,请到相册里查看哦!',
icon: 'none',
duration: 3000
})
setTimeout(function() {
that.modalhide()
}, 3000)
},
fail: function() {
}
})
}, 500)
},
/**
* 圆角框的画法
* @param {CanvasContext} ctx canvas上下文
* @param {number} x 圆角矩形选区的左上角 x坐标
* @param {number} y 圆角矩形选区的左上角 y坐标
* @param {number} w 圆角矩形选区的宽度
* @param {number} h 圆角矩形选区的高度
* @param {number} r 圆角的半径
* @param {number} c 圆圈的颜色
*/
roundRect(ctx, x, y, w, h, r,c) {
// 开始绘制
ctx.beginPath()
// 因为边缘描边存在锯齿,最好指定使用 transparent 填充
// 这里是使用 fill 还是 stroke都可以,二选一即可
// ctx.setFillStyle('transparent')
ctx.setStrokeStyle('transparent')
// 左上角
ctx.arc(x + r, y + r, r, Math.PI, Math.PI * 1.5)
// border-top
ctx.moveTo(x + r, y)
ctx.lineTo(x + w - r, y)
ctx.lineTo(x + w, y + r)
// 右上角
ctx.arc(x + w - r, y + r, r, Math.PI * 1.5, Math.PI * 2)
// border-right
ctx.lineTo(x + w, y + h - r)
ctx.lineTo(x + w - r, y + h)
// 右下角
ctx.arc(x + w - r, y + h - r, r, 0, Math.PI * 0.5)
// border-bottom
ctx.lineTo(x + r, y + h)
ctx.lineTo(x, y + h - r)
// 左下角
ctx.arc(x + r, y + h - r, r, Math.PI * 0.5, Math.PI)
// border-left
ctx.lineTo(x, y + r)
ctx.lineTo(x + r, y)
ctx.setFillStyle(c)
// 这里是使用 fill 还是 stroke都可以,二选一即可,但是需要与上面对应
ctx.fill()
// ctx.stroke()
ctx.closePath()
// 剪切
ctx.clip()
},
注释:以下为用到的本地图(自行下载,headIcon.png是logo,就不上传了哈)