wxml

<view class="shareBox" style="backgound:{{isShow ? '#000' : '#fff'}}" wx:if="{{isShow && canvasList}}">
<canvas canvas-id="firstCanvas" class="canvas myCanvas" style="width:{{canvasWidth}}px;height:{{canvasHeight}}px;margin-top:calc((100vh - 54px - {{canvasHeight}}px) / 2)"></canvas>
<button class="saveImg {{iphoneX ? 'iphonex' : ''}}" bindtap="saveImage" disabled="{{btnShow}}">保存图片</button>
</view>
<view wx:else class="refresh">
<button size="default" type="primary" bindtap="readyCanvas">重新加载</button>
</view>

  

js

import regeneratorRuntime from "../../../lib/regenerator-runtime/runtime";
let ctx = false, crown = 0, widFit = 0 // ctx canvas对象, crown生成图的宽高比, widFit当然布局下与需生成图寛比, heiFit高度比
Component({
externalClasses:['myCanvas'],
properties: {
canvasList: {
type: Array,
value: []
},
getShareWidth: { //想得到的分享图宽度
type: Number,
value: 1080
}, getShareHeight: { //想得到的分享图高度
type: Number,
value: 1900
} }, /**
* 组件的初始数据
*/
data: {
canvasWidth: 375, //屏幕宽度
canvasHeight: 375, //屏幕高度
isShow: true, //canvas组件默认显示
iphoneX: false, //适配机型
btnShow: false, //阻止事件多次触发
}, /**
* 组件的方法列表
*/
methods: {
async canvasStart() {
this.drawbackColor()
const canvasList = this.data.canvasList
await canvasList.map( (v,k)=>{
if(v.type === 'backImage'){
this.drawBackImg(v.url)
}else if(v.type === 'image'){
this.drawContentImg(v)
}else if(v.type === 'line'){
this.drawLine(v.drawLine)
}else{
this.drawText(v.text,v.drawText)
}
}) ctx.draw()
wx.hideLoading()
// this.saveImage()
}, //画默认白底色
drawbackColor(){
const { canvasWidth, canvasHeight } = this.data
ctx.save()
ctx.rect(0, 0, canvasWidth, canvasHeight)
ctx.setFillStyle('white')
ctx.fill()
}, // 画背景图
drawBackImg(url) {
// console.log('drawBackImg',url)
const {
canvasWidth,
canvasHeight
} = this.data
ctx.save()
ctx.drawImage(url, 0, 0, canvasWidth, canvasHeight)
}, // 画图不用裁剪(查看小程序canvas api 文档 https://developers.weixin.qq.com/miniprogram/dev/api/CanvasContext.drawImage.html)
drawImg(url, drawArguments) {
const arg = Object.keys(drawArguments)
if (arg.length == 8) { const { sx, sy, sWidth, sHeight, dwX, dwY, dWidth, dHeight } = drawArguments
ctx.drawImage(url, sx * widFit, sy * widFit, sWidth * widFit, sHeight * widFit, dwX * widFit, dwY * widFit, dWidth * widFit, dHeight * widFit) } else if (arg.length == 4) { const { dwX, dwY, dWidth, dHeight } = drawArguments
ctx.drawImage(url, dwX * widFit, dwY * widFit, dWidth * widFit, dHeight * widFit) } else if (arg.length == 2) { const { dwX, dwY } = drawArguments
ctx.drawImage(url, dwX * widFit, dwY * widFit) } else { wx.showToast({
title: '背景图传入参数有误,请确认无误后再进行操作',
icon: 'none'
}) } }, // 画内容图 clip裁剪
drawContentImg(val){
const { url, clip, drawArguments, drawArc} = val if(clip){ //裁剪流图片
if(!url || !drawArguments || !drawArc){
wx.showToast({
title: '请确认drawContentImg参数无误',
icon: 'none'
})
return;
} const {
x,
y,
radius
} = drawArc
if ((x || x === 0) && (y || y === 0) && (radius || radius === 0)) {
const {
x,
y,
radius,
startRadian = 0,
endRadian = 2 * Math.PI
} = drawArc
ctx.save()
ctx.beginPath();
ctx.arc(x * widFit, y * widFit, radius * widFit, startRadian, endRadian) // arc(x坐标,y坐标,radius半径,startRadian起始弧度/单位弧度(默认在3点钟方向),endRadian终止弧度)
ctx.clip()
this.drawImg(url, drawArguments)
ctx.restore()
} else {
wx.showToast({
title: '画圆参数有误',
icon: 'none'
})
}
} else {
ctx.save()
this.drawImg(url, drawArguments)
ctx.restore()
} }, // 画文字
drawText(text,drawText){
const canvasWidth = this.data.canvasWidth
const exg = /[a-zA-Z0-9]/g
const { x, y, bold, maxWidth = canvasWidth, fontSize = 14, lineHeight = 0, color = 'white', textAlign = 'left' } = drawText // text文字内容, x画布X坐标, y画布y坐标, maxWidth最大宽度, fontSize字体大小, color文字颜色 const patchTextHeight = fontSize ? fontSize : lineHeight
if(!text || (!x && x !== 0) || (!y && y !== 0)){
wx.showToast({
title: '文字传入参数有误',
icon: 'none'
})
return
}
ctx.save()
ctx.setFillStyle(color) //设置文字颜色
ctx.setTextAlign(textAlign)
if(bold){
ctx.font = `${fontSize}px bold PingFangSC-Medium` //设置文字样式
}else{
ctx.setFontSize(fontSize) //设置文字字体
} const measure = ctx.measureText(text).width //测量文本宽度
const scale = Math.ceil(measure / (maxWidth * widFit)) //scale<1则 maxWidth>measure,1 <= scale < 2 则 maxWidth >= measure/2,scale >= 2 则 maxWidth <= measure / 2
let arr = [], count = 0 if(scale >= 2){
let fontNum = Math.floor((maxWidth / fontSize) * widFit) //每行最多字体个数
let patchVal = 0, patchY = y + patchTextHeight
for(var i = 0; i < scale; i++){
arr[i] = text.substr(patchVal,fontNum)
count = arr[i].match(exg) ? arr[i].match(exg).length / 2 - 1 : 0
// console.log('正则匹配:',ctx.measureText('和').width,ctx.measureText('B').width,ctx.measureText('a').width,ctx.measureText(1).width)
fontNum += count
if(i < scale - 1){
ctx.fillText(text.substr(patchVal,fontNum), x * widFit, patchY * widFit)
patchVal += fontNum
patchY += patchTextHeight
}else{
arr[i] = text.substr(patchVal)
ctx.fillText(text.substr(patchVal), x * widFit, patchY * widFit) //画最后剩下的内容
console.log('arr:',arr)
}
}
}else{
ctx.fillText(text, x * widFit, (y + patchTextHeight)* widFit);
console.log('felltext:',text,x*widFit,y*widFit)
} ctx.restore()
}, // 画线
drawLine(drwaLine){
const { sx, sy, ex, ey, lineWidth = 1, color = '#EBEBEB' } = drwaLine
if(!sx || !sy || !ex || !ey){
wx.showToast({
title: '画线参数有误',
icon: 'none'
})
return
}else{
ctx.save()
ctx.moveTo(sx, sy) //线起点
ctx.lineTo(ex, ey) //线终点
ctx.setLineWidth(lineWidth) //线宽度
ctx.setStrokeStyle(color) //线颜色
ctx.stroke()
ctx.restore()
}
}, // 保存图片
saveImage(){
wx.showLoading({
title: '生成图片中...',
mask: true
})
this.setData({
btnShow: true
})
const { getShareWidth, getShareHeight } = this.data
wx.canvasToTempFilePath({
destWidth: getShareWidth * 5,
destHeight: getShareHeight * 5,
canvasId: 'firstCanvas',
quality: 1,
complete: fin=>{
// console.log('finish',fin)
if(fin.tempFilePath){
wx.saveImageToPhotosAlbum({
filePath: fin.tempFilePath,
success: (res)=>{
wx.showToast({
title: '保存图片成功',
icon: 'none',
duration: 2000
})
this.setData({
btnShow: false
})
}
})
}else{
wx.showToast({
title: '生成图片失败',
icon: 'none'
})
this.setData({
btnShow: false,
})
} }
},this)
}, //转成本地图片
getImages(url){
return new Promise( (sovle,reject)=>{
wx.getImageInfo({
src: url,
success: (res)=>{
sovle(res.path)
},
fail: (err)=>{
wx.showToast({
title: '网络不好,请稍后再试',
icon: 'none'
})
this.setData({
isShow: false
})
}
});
}) }, // 画图前准备工作
async readyCanvas(){
const { windowWidth, model } = wx.getSystemInfoSync(); // 获取屏幕宽高 let { getShareWidth, getShareHeight, canvasList} = this.data
crown = getShareWidth / getShareHeight //分享图的宽高比
const canvasHeight = windowWidth / crown if(model === 'iPhone X'){
this.setData({
canvasWidth: windowWidth,
canvasHeight,
iphoneX: true
})
}else{
this.setData({
canvasWidth: windowWidth,
canvasHeight,
iphoneX: false
})
} ctx = wx.createCanvasContext('firstCanvas',this) //把ctx赋值给全局变量
widFit = windowWidth / getShareWidth //宽比 (以px为单位) for(let i = 0; i < canvasList.length; i++){
if(canvasList[i].url){
canvasList[i].url = await this.getImages(canvasList[i].url) // console.log(i,canvasList[i].url)
}
} this.setData({
canvasList,
isShow: true
},()=>{
console.log(getShareWidth,getShareHeight,canvasList)
this.canvasStart()
})
} }, lifetimes: { }, pageLifetimes: {
show(){
wx.showLoading({
title: '加载中...',
mask: true
})
this.readyCanvas()
}
}
})
// let shareList = { //传参例子
// canvasList: [
// {
// type: 'image',
// clip: false,
// url: courseInfo.bgImage, //顶部背景
// drawArguments:{
// dwX: 0,
// dwY: 0,
// dWidth: 375,
// dHeight: 209
// },
// },
// {
// type: 'text',
// text: courseInfo.courseTitle,
// drawText:{
// x: 20,
// y: 227,
// fontSize: 18,
// color: '#303030',
// bold: true
// }
// },
// {
// type: 'image',
// clip: true,
// url: courseInfo.coachesInfo[0].avatar, //教练头像
// drawArguments:{
// dwX: 20,
// dwY: 304,
// dWidth: 32,
// dHeight: 32
// },
// drawArc:{
// x: 36,
// y: 320,
// radius: 16,
// }
// },
// {
// type:'line',
// drawLine:{
// sx: 20, //开始x坐标
// sy: 348, //开始y坐标
// ex: 355, //结束x坐标
// ey: 348, //结束y坐标
// lineWidth: 0.5, //线宽度
// color: '#ebebeb' //线颜色
// }
// },
// ],
// getShareWidth: 375,
// getShareHeight: 463,
// pageTitle: courseInfo.courseTitle
// }

 wxss

.shareBox{
width: 100vw;
height: 100vh;
background: #000;
position: fixed;
left: 0;
top: 0;
}
.canvas{
background: #fff;
}
.saveImg{
width: 100%;
height: 108rpx;
line-height: 108rpx;
background: #00C3AA;
text-align: center;
font-size: 30rpx;
color: #FFFFFF;
border-radius: 0;
border: 0;
position: absolute;
left: 0;
bottom: 0;
}
.refresh{
width: 350rpx;
height: 92rpx;
position: fixed;
left: 0;
top: 0;
right: 0;
bottom: 0;
margin: auto;
}
.iphonex{
height: 172rpx;
}

  

最新文章

  1. SQL Server ---(CDC)监控表数据(转译)
  2. [转]asp.net c# 网上搜集面试题目(附答案)
  3. Node.js学习
  4. jdk6提供的加密算法
  5. 树莓派版的家用NAS服务器
  6. Ubuntu 下安装 Oracle JDK
  7. The Socket API, Part 3: Concurrent Servers
  8. Java Web 前端高性能优化(二)
  9. IE兼容HTML5
  10. 第八届河南省赛B.最大岛屿(dfs)
  11. Java菜鸟学习笔记--面向对象篇(十八):对象转型&amp;多态
  12. jenkins gradle 编译遇到tomcat异常
  13. 在ConcurrentModificationException异常上的联想
  14. 开源ERP-成功案例分析(3)
  15. jar 包启动脚本
  16. docker安装及配置
  17. sci-hub免费下载论文
  18. .Net混淆工具和反混淆工具
  19. Excel技巧--分隔工资条
  20. ext2文件系统学习(一)

热门文章

  1. mvn多环境下的配置
  2. synchronized 和reentrantlock的优缺点
  3. 使用idea生成maven项目的jar包(转)
  4. django 环境配置.
  5. 判断JS的数据类型
  6. c#: 任务栏进度显示(TaskbarManager)
  7. hbase总结~hbase配置和使用
  8. rpo攻击
  9. mysql启动错误,提示crash 错误
  10. playframework链接MySQL数据库的问题