需求:点击分享,弹出遮罩层,可分享给好友,可保存图片分享,canvas中的图片自适应(缩放、裁剪)
技术:canvas 2,vant-weapp-ui
思路:计划将整个分享都写成一个自定义组件,由于一些bug,没能实现,部分还是需要写在页面中。
share组件:
share.wxml
保存图片
share.js 含有canvas绘制白色背景,canvas文本换行,绘制图片,图片原比例缩小裁剪,图片自适应,保存图片等方法
import {request} from "../../common/httpService";
const app = getApp()
Component({
/**
* 组件的属性列表
*/
properties: {
type: {
type: String,
value: ''
},
shareWords: {
type: String,
value: ''
},
imgSrc: {
type: String,
value: ''
},
title: {
type: String,
value: ''
},
userName: {
type: String,
value: ''
},
product: {
type: Object,
value: {}
},
dec: {
type: String,
value: ''
},
link: {
type: String,
value: ''
},
sceneStr: {
type: String,
value: ''
},
articleName: {
type: String,
value: ''
}
},
/**
* 组件的初始数据
*/
data: {
showShare: false,
referrer: wx.getStorageSync('userId'),
canvas: null
},
ready: function () {
if (this.properties.type === 'article') {
this.createArticlePic()
} else if (this.properties.type === 'invited') {
this.createInvitePic()
} else if (this.properties.type === 'product') {
this.createProductPic()
}
// this.getCodeImg()
},
/**
* 组件的方法列表
*/
methods: {
initCanvas() {
return new Promise((resolve, reject) => {
const query = wx.createSelectorQuery()
query.select('#myCanvas')
.fields({
node: true,
size: true,
id: true
})
.exec((res) => {
const canvas = res[0].node
const ctx = canvas.getContext('2d')
this.setData({
canvas: canvas
})
const dpr = wx.getSystemInfoSync().pixelRatio
canvas.width = res[0].width * dpr
canvas.height = res[0].height * dpr
ctx.scale(dpr, dpr)
let imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
console.log('imageData', imageData)
for (let i = 0; i < imageData.data.length; i += 4) {
if (imageData.data[i + 3] === 0) {
imageData.data[i] = 255;
imageData.data[i + 1] = 255;
imageData.data[i + 2] = 255;
imageData.data[i + 3] = 255;
}
}
ctx.putImageData(imageData, 0, 0);
let data = {
ctx,
canvas: res[0]
}
return resolve(data)
})
})
},
createArticlePic() {
let that = this
that.initCanvas().then((data) => {
const ctx = data.ctx
const canvasInfo = data.canvas
const canvas = that.data.canvas
let pic = that.properties.imgSrc
if (!that.properties.imgSrc) {
pic = '../../images/share-article-bg.png'
}
let cW = canvasInfo.width * 0.91
let cH = canvasInfo.height * 0.56
console.log('cW', cW)
console.log('cH', cH)
that.drawArticlePic(ctx, canvas, cW, cH, pic).then(res => {
console.log('画入成功')
ctx.fillStyle = 'rgba(0,0,0,0.5)'
ctx.fillRect(15, 95, cW, cH)
ctx.fillStyle = '#333333'
ctx.font = '18px PingFang'
let title = that.properties.articleName
console.log('文章title', title)
if (!title) {
if (that.properties.dec.length < 10) {
title = that.properties.dec
} else {
title = that.properties.dec.slice(0, 10) + '...'
}
}
ctx.fillText(title, 15, 50)
ctx.fillStyle = '#aaa'
ctx.font = '14px PingFang'
ctx.fillText(`来自${that.properties.userName}的邀请`, 15, 80)
ctx.fillStyle = '#ffffff'
ctx.font = '14px PingFang'
ctx.fillText(`123人已浏览`, 30, 288)
wx.canvasToTempFilePath({
canvasId: 'myCanvas',
canvas: canvas,
fileType: 'png',
success: function (res) {
console.log('canvas生成图片')
console.log(res.tempFilePath)
that.setData({
canvasPicPath: res.tempFilePath
})
},
fail: function (res) {
console.log('canvas生成图片失败')
console.log(res);
}
}, that)
})
})
},
createProductPic() {
let that = this
that.initCanvas().then(data => {
const ctx = data.ctx
const canvasInfo = data.canvas
const canvas = that.data.canvas
let borderW = canvasInfo.width * 0.89
let borderH = canvasInfo.height * 0.77
let textW = canvasInfo.width * 0.81
this.initCanvasBg(canvas, ctx, "../../images/logo.png", 25, 25, 15, 28)
ctx.fillStyle = '#333333'
ctx.font = '12px PingFang'
ctx.fillText('绿植物', 49, 46)
ctx.fillStyle = '#8E8E8E'
ctx.font = '14px PingFang'
ctx.fillText(`${this.properties.userName}给你推荐了一个好东西`, 20, 79)
ctx.strokeStyle = '#EEEEEE'
ctx.strokeRect(20, 89, borderW, borderH)
that.initCanvasBg(canvas, ctx, this.properties.imgSrc, 163, 163, 84, 98)
ctx.fillStyle = '#CF1322'
ctx.font = '24px PingFang'
ctx.fillText('¥' + this.properties.product.vipPrice, 27, 288)
ctx.fillStyle = '#AAAAAA'
ctx.font = '14px PingFang'
ctx.fillText('¥' + this.properties.product.originPrice, 105, 288)
//原价删除线
ctx.beginPath()
ctx.lineWidth = 1;
ctx.strokeStyle = "#AAAAAA";
ctx.moveTo(103, 283)
ctx.lineTo(149, 283)
ctx.stroke()
ctx.fillStyle = '#333333'
ctx.font = '14px PingFang'
// ctx.fillText(that.properties.product.name, 27, 318)
that.drawText(ctx, that.properties.product.name, 29, 293, textW);
ctx.fillStyle = '#AAAAAA'
ctx.font = '12px PingFang'
// ctx.fillText(that.properties.product.fullDescription, 27, 340)
that.drawText(ctx, that.properties.product.fullDescription, 29, 340, textW);
// TODO 二维码
wx.canvasToTempFilePath({
canvasId: 'myCanvas',
canvas: canvas,
fileType: 'png',
success: function (res) {
console.log('canvas生成图片')
console.log(res.tempFilePath)
that.setData({
canvasPicPath: res.tempFilePath
})
},
fail: function (res) {
console.log('canvas生成图片失败')
console.log(res);
}
}, that)
})
},
createInvitePic() {
let that = this
that.initCanvas().then(data => {
const ctx = data.ctx
const canvasInfo = data.canvas
const canvas = that.data.canvas
let systemWidth = app.globalData.systemWidth
let picWidth = systemWidth * 0.8
let picHeight = picWidth * 0.97
this.initCanvasBg(canvas, ctx, "../../images/logo.png", 25, 25, 15, 36).then((logoSuc) => {
console.log('logoSuc', logoSuc)
this.initCanvasBg(canvas, ctx, "../../images/share-img.png", picWidth, picHeight).then((res1) => {
console.log('res1', res1)
ctx.textAlign = 'left'
ctx.fillStyle = '#333333'
ctx.font = '14px PingFang' // 文字字号:22px
ctx.fillText('绿植物', 49, 56)
ctx.textAlign = 'center'
ctx.fillStyle = '#E2A02B'
ctx.font = '20px PingFang' // 文字字号:22px
ctx.fillText('邀您成为VIP会员', canvasInfo.width / 2, 137)
ctx.textAlign = 'center'
ctx.fillStyle = '#ffffff'
ctx.font = '14px PingFang' // 文字字号:22px
ctx.fillText(`来自${this.properties.userName}的邀请`, canvasInfo.width / 2, 160)
this.roundRectColor(ctx, 119, 250, 92, 22, 16, canvasInfo.width)
ctx.textAlign = 'center'
ctx.fillStyle = '#E2A02B'
ctx.font = '20px PingFang' // 文字字号:22px
ctx.fillText('最高可享3折优惠', canvasInfo.width / 2, 325)
wx.canvasToTempFilePath({
canvasId: 'myCanvas',
canvas: canvas,
fileType: 'png',
success: function (res) {
console.log('canvas生成图片')
console.log(res.tempFilePath)
that.setData({
canvasPicPath: res.tempFilePath
})
},
fail: function (res) {
console.log('canvas生成图片失败')
console.log(res);
}
}, that)
})
})
})
},
initCanvasBg(canvas, ctx, imgPath, w, h, x, y) {
return new Promise((resolve, reject) => {
let bgPicturePath = imgPath;//图片路径不要出错
const img = canvas.createImage()
img.src = bgPicturePath
let oX = 15
let oY = 76
if (x) {
oX = x
}
if (y) {
oY = y
}
img.onload = () => {
ctx.drawImage(img, oX, oY, w, h);
return resolve()
}
})
},
drawArticlePic(ctx, canvas, canvas_width, canvas_height, imgPath) {
return new Promise((resolve, reject) => {
wx.getImageInfo({
src: imgPath,
success: function (res) {
let img_width = res.width, //图片宽
img_height = res.height; //图片高
let clip_left, clip_top, //左偏移值,上偏移值,
clip_width, clip_height, //截取宽度,截取高度
dWidth, dHeight,
dx, dy;
// ----------------裁剪图片----------------
if (img_width > canvas_width && img_height > canvas_height) { //图片宽高都大于框框
if (img_width / img_height > 1 || img_width / img_height === 1) { //宽图 或正方形
//将图高度自适应
let factor = img_height / canvas_height
clip_width = factor * canvas_width
clip_height = img_height
clip_top = 0
clip_left = (img_width - clip_width) / 2 //clip_left 取中间值
} else if (img_width / img_height < 1) { //长图
let factor = img_width / canvas_width // 图片宽/框宽= 裁剪长度/框长
// img_width = canvas_width
clip_width = img_width
clip_height = factor * canvas_height
clip_top = (img_height - clip_height) / 2
clip_left = 0 //clip_left 取中间值
}
dWidth = canvas_width
dHeight = canvas_height
dx = 15
dy = 95
} else if (img_width <= canvas_width) { //宽度小于等于框
dWidth = img_width
if (img_height >= canvas_height) {
dHeight = canvas_height
clip_top = (img_height - canvas_height) / 2 //裁掉多余的高
dy = 0 //起始位置
} else {
dHeight = img_height
dy = (canvas_height - img_height) / 2
clip_top = 0
}
dx = 0
clip_left = 0
} else if (img_height <= canvas_height) { //高度小于等于框
dHeight = img_height
if (img_width >= canvas_width) {
dWidth = canvas_width
dx = 0
clip_left = (img_width - canvas_width) / 2
} else {
dWidth = img_width
dx = (canvas_width - img_width) / 2
clip_left = 0
}
dy = 0
clip_top = 0
}
const img = canvas.createImage()
img.src = imgPath
img.onload = (res) => {
console.log('img_load', res)
ctx.drawImage(img, clip_left, clip_top, clip_width, clip_height, dx, dy, dWidth, dHeight);
return resolve()
}
}
})
})
},
roundRectColor(context, x, y, w, h, r, canvasWidth) { //绘制圆角矩形(纯色填充)
context.save();
context.fillStyle = '#3B3B3B';
context.strokeStyle = '#3B3B3B'
context.lineJoin = 'round'; //交点设置成圆角
context.lineWidth = r;
context.strokeRect(x + r / 2, y + r / 2, w - r, h - r);
context.fillRect(x + r, y + r, w - r * 2, h - r * 2);
context.stroke();
context.closePath();
context.textAlign = 'center'
context.fillStyle = '#ffffff'
context.font = '10px PingFang' // 文字字号:22px
context.fillText('长按扫码加入', canvasWidth / 2, 265)
},
savePic() {
let canvasPicPath = this.data.canvasPicPath
console.log('canvasPicPath', canvasPicPath)
wx.saveImageToPhotosAlbum({
filePath: canvasPicPath,
success(res) {
console.log('保存成功', res)
wx.showToast({
title: '保存成功'
})
}
})
},
closeWindow: function () {
console.log('ad')
wx.switchTab({
url: 'pages/user/user'
})
},
getCodeImg() {
let link = this.properties.link
let sceneStr = this.properties.sceneStr
console.log('link', link)
console.log('sceneStr', sceneStr)
let randomStr = this.randomString(32)
console.log('randomStr', randomStr)
// return
request(`/item/share/getVxQRCode?sceneStr=${sceneStr}&url=${link}`, {}).then(res => {
console.log('res', res)
})
},
randomString(len) {
//默认去掉了容易混淆的字符oOLl,9gq,Vv,Uu,I1
let chars = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678';
let tempLen = chars.length, tempStr = '';
for (let i = 0; i < len; ++i) {
tempStr += chars.charAt(Math.floor(Math.random() * tempLen));
}
return tempStr;
},
drawText(context, t, x, y, w) { //canvas中文本换行
let chr = t.split("");
let temp = "";
let row = [];
console.log('chr', chr)
for (let a = 0; a < chr.length; a++) {
if (context.measureText(temp).width < w) {
;
} else {
row.push(temp);
temp = "";
}
temp += chr[a];
}
row.push(temp);
for (let b = 0; b < row.length; b++) {
context.fillText(row[b], x, y + (b + 1) * 20);
}
}
}
})