完善版封装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上搜了一下都没有找到最新版本绑定好的项目,就自己动手来绑定 ...
随机推荐
- leetcode406
public class Solution { public int[,] ReconstructQueue(int[,] people) { ) { return new int[,] { }; } ...
- python练习题_02
#1.有两个列表 l1=[11,22,33] l2=[22,33,44] #a.获取内容相同的元素列表 l3=[] for i in l1: if i in l2: l3.append(i) prin ...
- laravel PHPExcel 使用小结
最近需求要用到PHPExcel,laravel框架中有相应的组件https://github.com/Maatwebsite/Laravel-Excel,我用的是2.1的(3.0文档不详细而且坑似乎也 ...
- [C语言]进阶|指针与字符串
------------------------------------------------------------------------------------ 回顾:[C语言]指针与字符串 ...
- tensorflow-serving-gpu 本地编译并使用
因为要部署,模型比较大,所以通常官网的pip install 和bazel 教程编译的都是cpu版本的代码, 所以为了感受下gpu就尝试自己编译了,首先,下载源码: git clone --recur ...
- html 提取 公用部分
在写HTML时,总会遇到一些公用部分,如果每个页面都写那就很麻烦,并且代码量大大增加. 网上查询了几种方法: 1.es6 的 embed 标签. <embed src="header. ...
- Django之Form、ModelForm 组件
Django之Form.ModelForm 组件 一.Form组件: django框架提供了一个form类,来处理web开发中的表单相关事项.众所周知,form最常做的是对用户输入的内容进行验证,为此 ...
- centos7 smplayer 安装 安装视频播放器
# yum -y install http://li.nux.ro/download/nux/dextop/el7/x86_64/nux-dextop-release-0-5.el7.nux.noar ...
- struts2遇到的一个问题。
2018-09-12 好几年没配过struts2了,今天想用最新版的配一下,一直不成功,后来才知道,一堆红色输出里面有这样一句 ERROR StatusLogger No log4j2 configu ...
- centos 网卡自动连接
/etc/sysconfig/network-scripts/目录下ifcfg-eth0这个文件,把ONBOOT="no"改为yes,