import regeneratorRuntime from "../../../lib/regenerator-runtime/runtime";
let ctx = false, crown = 0, widFit = 0 // ctx canvas对象, crown生成图的宽高比, widFit当然布局下与需生成图寛比, heiFit高度比
Component({
/**
* 组件的属性列表
*/
properties: {
canvasList: {
type: Array,
value: [
{
type: 'backImage',
url: 'https://portal.lanrenyun.cn/activity/50/activity_50-background-poster.jpg',
},
{
type: 'text',
text: '一二三四五六七八九十十一十二十三十四十五',
drawText:{
x: 100,
y: 100,
maxWidth: 200,
fontSize: 14,
lineHeight:60,
color: '#000'
}
},
{
type: 'image',
clip: true,
url: 'https://portal.lanrenyun.cn/Fs8toIXayCVeQAfLZDhsdlG-kcWX',
drawArguments:{
dwX: 153,
dwY: 660,
dWidth: 106,
dHeight: 106
},
drawArc:{
x: 206,
y: 713,
radius: 53,
}
},
{
type: 'image',
clip: true,
url: 'https://portal.lanrenyun.cn/Fs8toIXayCVeQAfLZDhsdlG-kcWX',
drawArguments:{
dwX: 435,
dwY: 1497,
dWidth: 210,
dHeight: 210
},
drawArc:{
x: 540,
y: 1602,
radius: 105,
}
}, ]
},
getShareWidth:{ //想得到的分享图宽度
type: Number,
value: 1080
}, getShareHeight:{ //想得到的分享图高度
type: Number,
value: 1900
} }, /**
* 组件的初始数据
*/
data: {
canvasWidth: 375, //屏幕宽度
canvasHeight: 375, //屏幕高度
isShow: true, //canvas组件默认显示
}, /**
* 组件的方法列表
*/
methods: {
async canvasStart() {
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{
this.drawText(v.text,v.drawText)
}
}) ctx.draw()
this.saveImage()
}, // 画背景图
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){
debugger
const { x, y, maxWidth, fontSize, lineHeight = 0, color = 'white' } = drawText // text文字内容, x画布X坐标, y画布y坐标, max最大宽度, fontSize字体大小, color文字颜色
if(!text || (!x && x !== 0) || (!y && y !== 0) || !maxWidth || !fontSize){
wx.showToast({
title: '文字传入参数有误',
icon: 'none'
})
return
}
ctx.save()
ctx.setFontSize(fontSize) //设置文字字体 const measure = ctx.measureText(text).width //测量文本宽度
const scale = Math.ceil(measure / maxWidth) //scale<1则 maxWidth>measure,1 <= scale < 2 则 maxWidth >= measure/2,scale >= 2 则 maxWidth <= measure / 2
let arr = [] if(scale >= 2){
const fontNum = Math.floor(maxWidth / fontSize) //每行最多字体个数
let patchVal = 0, patchY = y
for(var i = 0; i < scale; i++){
arr[i] = text.substr(patchVal,fontNum)
if(i < scale - 1){
ctx.fillText(text.substr(patchVal,fontNum), x * widFit, patchY * widFit)
patchVal += fontNum
patchY += (fontSize + lineHeight * widFit)
}else{
arr[i] = text.substr(patchVal)
ctx.fillText(text.substr(patchVal), x * widFit, patchY * widFit) //画最后剩下的内容
console.log('arr:',arr)
}
}
}else if(scale == 1 && maxWidth != measure ){
const fontNum = Math.floor(maxWidth / fontSize) //每行最多字体个数
ctx.fillText(text.substr(0,fontNum), x * widFit, y * widFit)
ctx.fillText(text.substr(fontNum), x * widFit, (y+fontSize) * widFit)
// console.log(text,arr,measure)
}else{
ctx.fillText(text, x * widFit, y * widFit);
} ctx.setFillStyle(color)
ctx.restore()
}, // 保存图片
saveImage(){
const { getShareWidth, getShareHeight } = this.data
wx.canvasToTempFilePath({
destWidth: getShareWidth,
destHeight: getShareHeight,
canvasId: 'firstCanvas',
quality: 1,
complete(fin){
console.log('finish',fin)
if(fin.tempFilePath){
wx.hideLoading();
wx.saveImageToPhotosAlbum({
filePath: fin.tempFilePath,
success: (result)=>{
wx.hideLoading()
wx.showToast({
title: '保存图片成功',
icon: 'none'
})
}
})
}else{
wx.showToast({
title: '生成图片失败',
icon: 'none'
})
} }
},this)
}, //转成本地图片
getImages(url){
return new Promise( (sovle,reject)=>{
wx.getImageInfo({
src: url,
success: (res)=>{
sovle(res.path)
},
fail: (err)=>{
reject(err)
}
});
}) }
}, lifetimes: {
async attached() {
wx.showLoading({
title: '生成图片中...',
mask: true
})
// 获取屏幕宽高
const { windowWidth } = wx.getSystemInfoSync(); let { getShareWidth, getShareHeight, canvasList} = this.data
crown = getShareWidth / getShareHeight //分享图的宽高比 const canvasHeight = windowWidth / crown
this.setData({
canvasWidth: windowWidth,
canvasHeight
}) 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)
}
} const self = this
console.log(4,this.data.canvasList)
// await this.getImageInfo() //网络图片转成本地图片或临时图片
this.setData({
canvasList
},function(){
self.canvasStart()
}) },
}
})

  最重要的是要注意换算比例以及自定义组件this参数,draw(true,this), 生存图片的时候也要带上this参数

  wx.canvasToTempFilePath(Object object, Object this)

完善版封装canvas分享组件的更多相关文章

  1. 自己封装的一个JS分享组件

    因为工作的需求之前也封装过一个JS分享插件,集成了我们公司常用的几个分享平台. 但是总感觉之前的结构上很不理想,样式,行为揉成一起,心里想的做的完美,实际上总是很多的偏差,所以这次我对其进行了改版. ...

  2. 基于Bootstrap的DropDownList的JQuery组件的完善版

    在前文 创建基于Bootstrap的下拉菜单的DropDownList的JQuery插件 中,实现了DropDownList的JQuery组件,但是留有遗憾.就是当下拉菜单出现滚动条的时候,滚动条会覆 ...

  3. WPF 自定义 MessageBox (相对完善版)

    WPF 自定义 MessageBox (相对完善版)     基于WPF的自定义 MessageBox. 众所周知WPF界面美观.大多数WPF元素都可以简单的修改其样式,从而达到程序的风格统一.可是当 ...

  4. AngularJS指令封装高德地图组件

    1 概述 公司移动门户原来是基于AngularJS指令封装的百度地图组件,用于签到.签退.定位等功能,在使用过程中发现百度地图频繁的弹出广告,所以打算重新引用其它地图组件,最后决定基于AngularJ ...

  5. WPF 自定义 MessageBox (相对完善版 v1.0.0.6)

    基于WPF的自定义 MessageBox. 众所周知WPF界面美观.大多数WPF元素都可以简单的修改其样式,从而达到程序的风格统一.可是当你不得不弹出一个消息框通知用户消息时(虽然很不建议在程序中频繁 ...

  6. 【小程序】---- 封装Echarts公共组件,遍历图表实现多个饼图

    一.问题描述: 在小程序的项目中,封装公共的饼图组件,并在需要的页面引入使用.要求一个页面中有多个饼图,动态渲染不同的数据. 二.效果实现: 1. 查看——小程序使用Echarts的方式 2. 封装饼 ...

  7. vue3 vite2 封装 SVG 图标组件 - 基于 vite 创建 vue3 全家桶项目续篇

    在<基于 vite 创建 vue3 全家桶>一文整合了 Element Plus,并将 Element Plus 中提供的图标进行全局注册,这样可以很方便的延续 Element UI 的风 ...

  8. iOS开发---集成百度地图完善版

    一.成为百度的开发者.创建应用 http://developer.baidu.com/map/index.php?title=首页 (鼠标移向 然后选择你的项目需要的功能 你可以在里面了解到你想要使用 ...

  9. Xamarin.Android 绑定友盟社会化分享组件

    Xamarin.Android 绑定友盟社会化分享组件 最近在开发博客园Android App的时候需要用到友盟社会化分享组件,在github上搜了一下都没有找到最新版本绑定好的项目,就自己动手来绑定 ...

随机推荐

  1. PHP和Redis实现在高并发下的抢购及秒杀功能示例详解

    抢购.秒杀是平常很常见的场景,面试的时候面试官也经常会问到,比如问你淘宝中的抢购秒杀是怎么实现的等等. 抢购.秒杀实现很简单,但是有些问题需要解决,主要针对两个问题: 一.高并发对数据库产生的压力二. ...

  2. ReactNative项目结构目录详解

    在使用 react-native init TestProject 在新建项目时,会看到如下目录 React Native结构目录 名称 描述 android目录 Android项目目录,包含了使用A ...

  3. java 自动补全

    int youNumber = 1; // 0 代表前面补充0 // 4 代表长度为4 // d 代表参数为正数型 String str = String.format("%04d" ...

  4. Hibernate 再接触 悲观锁和乐观锁

    为什么取1248 二进制 CRUD 移位效率高 在并发和效率选择一个平衡点 一般不会考虑幻读 因为我们不会再一个事务里查询两次,(只能设置为seralizable) 悲观锁和乐观锁的前提是read-u ...

  5. python获取文件夹的大小(即取出所有文件计算大小)

    import os path = r'/Users/authurchen/PycharmProjects/Demo' # print(os.listdir(path)) ls = os.listdir ...

  6. C++11 constexpr常量表达式

    常量表达式函数 要求: 函数体内只有单一的return返回语句 例如: constexpr int data() { const int i=1; //含有除了return以外的语句 return i ...

  7. django 请求与响应

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  8. Teemo's tree problem

    题目链接 : https://nanti.jisuanke.com/t/29228 There is an apple tree in Teemo's yard. It contains n node ...

  9. FortiGate防火墙500D下PC至外网丢包

    1.现状: 如图,防火墙堆叠,500D共4个出口方向,联通.电信.FQ.运维专线 2.现象: 到网关和防火墙上.下联口不丢包,到网联通和运维专线方向丢包4%左右,电信和FQ方向不丢包 3.分析 采用从 ...

  10. application/json和application/x-www-form-urlencoded使用选择

    一.参考资料 选application/x-www-form-urlencoded还是application/json? @RequestBody应用 二.理解 1.@RequestBody的作用 注 ...