完善版封装canvas分享组件
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分享组件的更多相关文章
- 自己封装的一个JS分享组件
因为工作的需求之前也封装过一个JS分享插件,集成了我们公司常用的几个分享平台. 但是总感觉之前的结构上很不理想,样式,行为揉成一起,心里想的做的完美,实际上总是很多的偏差,所以这次我对其进行了改版. ...
- 基于Bootstrap的DropDownList的JQuery组件的完善版
在前文 创建基于Bootstrap的下拉菜单的DropDownList的JQuery插件 中,实现了DropDownList的JQuery组件,但是留有遗憾.就是当下拉菜单出现滚动条的时候,滚动条会覆 ...
- WPF 自定义 MessageBox (相对完善版)
WPF 自定义 MessageBox (相对完善版) 基于WPF的自定义 MessageBox. 众所周知WPF界面美观.大多数WPF元素都可以简单的修改其样式,从而达到程序的风格统一.可是当 ...
- AngularJS指令封装高德地图组件
1 概述 公司移动门户原来是基于AngularJS指令封装的百度地图组件,用于签到.签退.定位等功能,在使用过程中发现百度地图频繁的弹出广告,所以打算重新引用其它地图组件,最后决定基于AngularJ ...
- WPF 自定义 MessageBox (相对完善版 v1.0.0.6)
基于WPF的自定义 MessageBox. 众所周知WPF界面美观.大多数WPF元素都可以简单的修改其样式,从而达到程序的风格统一.可是当你不得不弹出一个消息框通知用户消息时(虽然很不建议在程序中频繁 ...
- 【小程序】---- 封装Echarts公共组件,遍历图表实现多个饼图
一.问题描述: 在小程序的项目中,封装公共的饼图组件,并在需要的页面引入使用.要求一个页面中有多个饼图,动态渲染不同的数据. 二.效果实现: 1. 查看——小程序使用Echarts的方式 2. 封装饼 ...
- vue3 vite2 封装 SVG 图标组件 - 基于 vite 创建 vue3 全家桶项目续篇
在<基于 vite 创建 vue3 全家桶>一文整合了 Element Plus,并将 Element Plus 中提供的图标进行全局注册,这样可以很方便的延续 Element UI 的风 ...
- iOS开发---集成百度地图完善版
一.成为百度的开发者.创建应用 http://developer.baidu.com/map/index.php?title=首页 (鼠标移向 然后选择你的项目需要的功能 你可以在里面了解到你想要使用 ...
- Xamarin.Android 绑定友盟社会化分享组件
Xamarin.Android 绑定友盟社会化分享组件 最近在开发博客园Android App的时候需要用到友盟社会化分享组件,在github上搜了一下都没有找到最新版本绑定好的项目,就自己动手来绑定 ...
随机推荐
- English-英语日常交流语句
- HTML-全局属性 / 事件属性(转)
拷贝自:< http://www.runoob.com > HTML 全局属性 New : HTML5 新属性. 属性 描述 accesskey 设置访问元素的键盘快捷键. class 规 ...
- java 8 日期函数
1.Timestamp(long)转成日期 Timestamp timestamp = new Timestamp(System.currentTimeMillis()); LocalDate ...
- 微商城项目 请求接口封装中出现 callback && callback() 原理
http://www.imooc.com/wenda/detail/522579 因为逻辑运算符&& ||通常具有短路求值的特性即,如果只求部分值就可以得到整个表达式的值,那么剩下的部 ...
- lvs+nginx负载均衡
1 学习目标 掌握什么是负载均衡及负载均衡的作用和意义. 了解lvs负载均衡的三种模式. 了解lvs-DR负载均衡部署方法. 掌握nginx实现负载均衡的方法. 掌握lvs+nginx负载 ...
- Spark 基础之SQL 快速上手
知识点 SQL 基本概念 SQL Context 的生成和使用 1.6 版本新API:Datasets 常用 Spark SQL 数学和统计函数 SQL 语句 Spark DataFrame 文件保存 ...
- 字符串的排列(python)
题目描述 输入一个字符串,按字典序打印出该字符串中字符的所有排列.例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba. 输入描述: 输 ...
- Eclipse Android 模拟器启动过慢
打开AVD Manager窗口,在模拟器配置页面,选择Intel Atom (x86)选项.笔记本的CPU处理器是Intel 酷睿. 可以发现模拟器的启动速度明显变快.
- 365. Water and Jug Problem量杯灌水问题
[抄题]: 简而言之:只能对 杯子中全部的水/容量-杯子中全部的水进行操作 You are given two jugs with capacities x and y litres. There i ...
- thinkphp 视图(一)
视图 View <?php namespace app\index\controller; class Index{ public function index(){ return view() ...