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. 活用RPM获取包的信息

    rpm -q 功效大 如果你想要在系统上安装.卸载或是升级软件,需要对系统软件进行查询:或是有如下的场景: 安装了一个软件,需要知道这个软件的版本. 遇到一个文件,不认识它,需要知道它是什么软件,有什 ...

  2. 用ActiveX 创建自己的comboBox 控件(一)

    新建ActiveX工程ActiveXcomboBox        Ok->next->next->next, create control based on 选择combobox, ...

  3. ssh 报错Host key verification failed 或Ubuntu connect to serve 失败

    ssh 报错Host key verification failed  或Ubuntu connect to serve 失败  通常是因为没有装ssh sudo apt-get install  o ...

  4. CheckBox获取一组及全选

    获取一组CheckBox: jQuery: $(function () { $("input[name=names]").click(function () { //获得所有的na ...

  5. python 删除非空文件夹

    import os import shutil os.remove(path) #删除文件 os.removedirs(path) #删除空文件夹 shutil.rmtree(path) #递归删除文 ...

  6. ExecuteReader()获得数据

    ExecuteReader用于实现只进只读的高效数据查询.ExecuteReader:返回一个SqlDataReader对象,可以通过这个对象来检查查询结果,它提供了只进只读的执行方式,即从结果中读取 ...

  7. jsp中<c:if>标签的用法

    <c:if test="${(tbl.column1 eq '值') and (tbl.column2 eq 'str')}"> <table>...< ...

  8. 2017-2018-2 20165315 实验四《Android程序设计》实验报告

    2017-2018-2 20165315 实验四<Android程序设计>实验报告 第24章:初识Android Android Studio项目的目录树 1 build:该目录包含了自动 ...

  9. ES6自我总结笔记(阮一峰ES6入门)

    [let和const命令] 1.var的作用域是函数体内,不是块级作用域 2.let是更完美的var,let的变量的作用是块级作用域 3.let声明的全局变量不是全局对象属性,不可以通过window. ...

  10. windows下webstorm调试react native

    安装请参考:http://www.cnblogs.com/wjx0912/p/5662457.html webstorm在2016.10.20的版本才正式增加react native的调试支持,所以w ...