uniapp 使用canvas画海报(微信小程序)

效果展示:

 项目要求:点击分享绘制海报,并实现分享到好友,朋友圈,并保存

先实现绘制海报
 

<view class="data_item" v-for="(item,index) in dataList" :key="index"
			@click="goDetail(item,index)">
			<view class="data_bot">
				<view class="share" @click.stop="goShare(item,index)">
					<image :src="getimg('share_gray.png')" style="width: 36rpx;height: 36rpx;"></image>
					<view class="share_tt">分享</view>
				</view>
			</view>
		</view>

<view class="post_box" :class="isShare?' ':'post_box2'">
			<view class="post">
				<canvas style="width: 327px; height:482px;margin: 0 auto;" canvas-id="firstCanvas1"></canvas>
			</view>
		</view>
// 生成海报
			goShare(item, index) {
				let _this = this;
				this.shareId = item.id
				this.isShare = true
				// uni.hideTabBar()
				let userInfo = uni.getStorageSync('userInfo')
				uni.getImageInfo({
					src: userInfo.avatar,
					success: function(res) {
						if (res.path) {
							_this.canvasr(item, index, res.path, userInfo.nickname);
						}
					},
				});
			},
// 画海报
			canvasr(item, index, avatar, username) {
				let ctx = uni.createCanvasContext('firstCanvas1');
				// 背景图
				let postImage = '../../static/images/poster_bg.png'; //背景图
				ctx.globalAlpha = 0; // 设置图像透明度为0  为了让背景透明
				ctx.setFillStyle('#ffffff'); // 默认白色
				ctx.fillRect(0, 0, 327, 482);
				ctx.globalAlpha = 1; // 设置图像透明度为1
				ctx.drawImage(postImage, 0, 0, 327, 482); // (图片,x,y,宽,高)背景图
				ctx.save();
				// 头像
				ctx.restore();
				// let avatar = userInfo.avatar + "?timestamp=" + Date.now(); //地址栏加入新参数  解决canvas图片跨域问题
				this.drawAvatar(ctx, avatar, 30, 20, 15)
				// 昵称 +
				ctx.setFontSize(12); //设置字体字号
				ctx.setFillStyle('#000000'); //设置字体颜色
				// ctx.fillText(username, 65, 39); // (文字,x,y)
				let _strlineW = 0;
				let nickname = '';
				let actI = 0;
				for (let i = 0; i < username.length; i++) {
					_strlineW += ctx.measureText(username[i]).width;
					if(_strlineW <= 60){
						ctx.fillText(username, 65, 39); // (文字,x,y)
					}else if (_strlineW > 60 && _strlineW <= 70) {
						actI = i
						nickname = username.substring(0, i) + '…'
						ctx.fillText(nickname, 65, 39); // (文字,x,y)
					}else{
						nickname = username.substring(0, actI-1) + '…'
						ctx.fillText(nickname, 65, 39); // (文字,x,y)
					}
				}
				// 分享了一个点子
				let txt = '我发现了一个不错的点子';
				ctx.setFontSize(12); //设置字体字号
				ctx.setFillStyle('#999999'); //设置字体颜色
				ctx.fillText(txt, 135, 39); // (文字,x,y)
				// 内容开始引号图
				let startImage = '../../static/images/poster_quote_up.png'; //背景图
				ctx.drawImage(startImage, 30, 70, 32, 32); // (图片,x,y,宽,高)背景图
				ctx.save();
				ctx.restore();
				// 内容
				let content = item.idea_name;
				this.drawtext(ctx, content, 30, 130, 32, 267)
				// 内容结束引号图
				let endImage = '../../static/images/poster_quote_down.png'; //背景图
				ctx.drawImage(endImage, 265, 310, 32, 32); // (图片,x,y,宽,高)背景图
				ctx.save();
				ctx.restore();
				// 一条直线
				ctx.setFillStyle('#D8D8D8'); // 默认白色
				ctx.fillRect(30, 362, 267, 0.5); //x y 宽 高
				ctx.restore();
				// logo图
				let logoImage = '../../static/images/aiyop_logo.png'
				this.drawAvatar(ctx, logoImage, 30, 402, 15)
				ctx.save();
				ctx.restore();
				// AI有谱
				let title = 'AI有谱';
				ctx.setFontSize(13); //设置字体字号
				ctx.setFillStyle('#000000'); //设置字体颜色
				ctx.fillText(title, 70, 415); // (文字,x,y)
				// 心中有谱,奇思妙想也靠谱
				let intro = '心中有谱,奇思妙想也靠谱';
				ctx.setFontSize(10); //设置字体字号
				ctx.setFillStyle('#666666'); //设置字体颜色
				ctx.fillText(intro, 70, 430); // (文字,x,y)
				// 二维码
				let qrImage = '../../static/images/logo_program.jpg';
				this.drawAvatar(ctx, qrImage, 225, 381, 36)
				// 绘制
				ctx.draw();
			},
			// 绘制头像
			drawAvatar(ctx, img, x, y, r) {
				ctx.save();
				let d = r * 2;
				let cx = x + r;
				let cy = y + r;
				ctx.beginPath()
				ctx.arc(cx, cy, r, 0, 2 * Math.PI);
				ctx.strokeStyle = '#FFFFFF'; // 设置绘制圆形边框的颜色
				ctx.stroke(); // 绘制出圆形,默认为黑色,可通过 ctx.strokeStyle = '#FFFFFF', 设置想要的颜色
				ctx.clip();
				ctx.drawImage(img, x, y, d, d);
				ctx.restore();
			},
			// 文本n行换行与显示省略号
			// 1、canvas对象 2、文本 3、X轴 4、Y轴 5、单行行高 6、文本的宽度
			drawtext(ctx, str, axisX, axisY, titleHeight, maxWidth) {
				ctx.setFontSize(22); //设置字体字号
				ctx.setFillStyle('#000000'); //设置字体颜色
				// 文本处理
				let strArr = str.split("");
				let row = [];
				let temp = "";
				for (let i = 0; i < strArr.length; i++) {
					if (ctx.measureText(temp).width < maxWidth) {
						temp += strArr[i];
					} else {
						i--; //这里添加了i-- 是为了防止字符丢失,效果图中有对比
						row.push(temp);
						temp = "";
					}
				}
				row.push(temp); // row有多少项则就有多少行

				//如果数组长度大于6,现在只需要显示6行则只截取前两项,把第6行结尾设置成'...'
				if (row.length > 6) {
					let rowCut = row.slice(0, 6);
					let rowPart = rowCut[5];
					let test = "";
					let empty = [];
					for (let i = 0; i < rowPart.length; i++) {
						if (ctx.measureText(test).width < maxWidth) {
							test += rowPart[i];
						} else {
							break;
						}
					}
					empty.push(test);
					// let group = empty[0] //这里只显示两行,超出的用...表示
					let group = empty[0] + "..." //这里只显示两行,超出的用...表示
					rowCut.splice(5, 1, group);
					row = rowCut;
				}
				// 把文本绘制到画布中
				for (let i = 0; i < row.length; i++) {
					// 一次渲染一行
					ctx.fillText(row[i], axisX, axisY + i * titleHeight, maxWidth);
				}
				// 保存当前画布状态
				ctx.save()
				// 将之前在绘图上下文中的描述(路径、变形、样式)画到 canvas 中。
				// ctx.draw()
			},

下面是海报下面的分享弹窗

<!-- 分享海报的遮罩层 -->
		<view v-if="isShare" class="over_box" @touchmove.stop.prevent="moveHandle"></view>
		<!-- 分享海报 -->
		<u-popup :show="isShare" @close="closeShare" @open="openShare" mode="bottom" :round="10" :overlay="false">
			<view class="trans_box">
				<view class="per_box">
					<button open-type="share" class="per_but" @click="shareWeixin('WXSceneSession')">
						<image :src="getimg('wehcat.png')" style="width:86rpx;height: 86rpx;"></image>
						<view class="per_txt">微信好友</view>
					</button>
					<button class="per_but" @click="shareWeixin('WXSceneTimeline')">
						<image :src="getimg('wechat-moments.png')" style="width:86rpx;height: 86rpx;"></image>
						<view class="per_txt">朋友圈</view>
					</button>
					<button @click="saveLocal" class="per_but">
						<image :src="getimg('save-poster.png')" style="width:86rpx;height: 86rpx;"></image>
						<view class="per_txt">保存图片</view>
					</button>
				</view>
				<view class="share_line"></view>
				<view class="close_tran" @click="closeShare">取消</view>
			</view>
		</u-popup>

因为分享到朋友圈实在没找到有使用自定义按钮的可能,所以还是需要点击右上角胶囊
 

onLoad(){
    //分享功能
			wx.showShareMenu({
				withShareTicket: true,
				//设置下方的Menus菜单,才能够让发送给朋友与分享到朋友圈两个按钮可以点击
				menus: ["shareAppMessage", "shareTimeline"]
			})

}
//点击分享朋友,朋友圈事件
shareWeixin(scene) {
				if (scene == 'WXSceneTimeline') {
					uni.showToast({
						title: '点击右上角胶囊分享朋友圈',
						icon: 'none',
						duration: 2000
					})
				} else {
					uni.share({
						provider: "weixin",
						scene: scene,
						type: 0,
						href: '/subPackage/index/like_details?id=' + this.shareId + '&type=1',
						title: '点子分享',
						success(res) {
							console.log(res);
						},
						fail(err) {
							console.log(err);
						}
					})
				}
			},
onShareAppMessage(res) {
			if (res.from === 'button') { // 来自页面内分享按钮
				return {
					title: 'xxxxxxx', //分享的名称
					path: '/subPackage/index/like_details?id=' + this.shareId + '&type=1',
					mpId: 'wx000000000', //此处配置微信小程序的AppId
					imageUrl: ''
				}
			}
			return {
				title: 'xxxxx', //分享的名称
				path: '/subPackage/index/like_details?id=' + this.shareId + '&type=1',
				mpId: 'wx0000000000', //此处配置微信小程序的AppId
				imageUrl: ''
			}
		},
		//分享到朋友圈
		onShareTimeline(res) {
			return {
				title: this.timeItem,
				path: '/pages/index/index',
				type: 0,
				summary: "",
				imageUrl: ''
			}
		},

 以上就是画海报以及分享的全部过程了,另有一个点:
就是分享朋友的地址path: '/subPackage/index/like_details?id=' + this.shareId + '&type=1'
这里这个加个type=1是因为点击分享进入小程序的是个详情页,可能会出现点击左上角返回不能返回首页,所以加上这个type可以在分享页加个判断
 

        onLoad(option) {
			if(option.type && option.type==1){ //分享来的页面
				this.shareType = 1
			}
			
		},
//左上角的点击返回事件加判断,当是分享进入的时候回到首页
        goBack(){
				if(this.shareType==1){
					uni.switchTab({
						url:'/pages/index/index'
					})
				}else{
					uni.navigateBack()
					this.shareType = 0
				}
			},

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/68702.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

CSDN到底要多少积分才有排名(图解)

2016年8月16日的截图&#xff1a; 2016年8月17日的截图&#xff1a; CSDN的排名是完全按照积分排的&#xff0c;只隔了22分而已&#xff0c;千里之外和2万名的差别就是卡在这个地方。 2016年10月18日的截图&#xff1a; 这是刚刚进入前7000名&#xff0c;刚好访问也是刚刚突破4…

持有PMP证书,可申请CSPM证书!

一&#xff0c;CSPM介绍 CSPM的全称是&#xff1a;项目管理专业人员能力评价&#xff0c;是我们国内的“PMP”&#xff0c;是我们中国人自己的项目管理专业人士评价指南&#xff0c;符合中国国情且符合中国未来发展的项目管理专业人员能力评价标准。 2022年10月12日发布实施了…

Word转PDF工具哪家安全?推荐好用的文件格式转换工具

Word文档是我们最常见也是最常用的办公软件&#xff0c;想必大家都知道了Word操作起来十分的简单&#xff0c;而且功能也是比较齐全的。随着科技的不断进步&#xff0c;如今也是有越来越多类型的办公文档&#xff0c;PDF就是其中之一&#xff0c;那么word转pdf怎么转?Word转PD…

企业权限管理(七)-权限操作

1. 数据库与表结构 1.1 用户表 1.1.1 用户表信息描述 users 1.1.2 sql语句 CREATE TABLE users( id varchar2(32) default SYS_GUID() PRIMARY KEY, email VARCHAR2(50) UNIQUE NOT NULL, username VARCHAR2(50), PASSWORD VARCHAR2(50), phoneNum VARCHAR2(20), STATUS INT )…

Godot 4 源码分析 - 文件读入编码处理

今天需要读入xml文件进行处理&#xff0c;结果读入一个带中文的文件时&#xff0c;出错了。当然程序还能运行&#xff0c;但编译器一直报错&#xff0c;而且XML解析也不正确 单步调试发现读入的内容出现乱码&#xff0c;具体逻辑&#xff1a; String FileAccess::get_as_text…

Android:自定义沿着曲线轨迹移动

前言 前几天&#xff0c;后台有老铁留言&#xff0c;说有个需求&#xff0c;画两条曲线&#xff0c;中间是一个小球&#xff0c;沿着两条线中间的轨迹从左往右移动&#xff0c;让提供个思路&#xff0c;做为一个极度宠粉的博主&#xff0c;思路不仅要提供&#xff0c;实现方案也…

修改Egohands公开数据集,用于YOLOv5训练通用手部检测模型

〇、背景&#xff1a; 项目需要&#xff0c;需要利用摄像头对人手进行实时监测&#xff0c;最先考虑到的就是简单易用且高效的YOLOv5&#xff0c;很快找到了公开数据集&#xff1a;Egohands EgoHands: A Dataset for Hands in Complex Egocentric Interactions | IU Computer…

机器学习模型的可解释性:增加对人工智能系统的信任和理解

为了以道德和值得信赖的方式使用人工智能&#xff0c;研究人员必须继续创建平衡模型复杂性和易于解释的方法。 机器学习模型在各个领域的使用都取得了重大进展&#xff0c;包括自然语言处理、生成式人工智能和自主系统等。另一方面&#xff0c;随着模型复杂性和规模的增加&…

元年方舟企业数字化PaaS平台入选《全国企业数字化转型十佳案例》|元年科技

7月4日&#xff0c;2023全球数字经济大会第二届全国企业数字化转型高峰论坛在京隆重举行。大会由全球数字经济大会组委会主办&#xff0c;中关村数字经济产业联盟承办&#xff0c;北京市科学技术协会鼎力支持。论坛期间元年科技凭借卓越案例《构建数字化转型引擎&#xff1a;元…

苏州OV泛域名RSA加密算法https

RSA加密算法是一种非对称加密算法&#xff0c;它被广泛应用于信息安全领域。与对称加密算法不同&#xff0c;RSA加密算法使用了两个密钥&#xff0c;一个公钥和一个私钥。公钥可以公开&#xff0c;任何人都可以使用它加密信息&#xff0c;但只有私钥的持有者才能解密信息。RSA加…

竞赛项目 深度学习的水果识别 opencv python

文章目录 0 前言2 开发简介3 识别原理3.1 传统图像识别原理3.2 深度学习水果识别 4 数据集5 部分关键代码5.1 处理训练集的数据结构5.2 模型网络结构5.3 训练模型 6 识别效果7 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 深度学习…

Mac unsupported architecture

&#xff08;瓜是长大在营养肥料里的最甜&#xff0c;天才是长在恶性土壤中的最好。——培根&#xff09; unsupported architecture 在mac的m系列芯片中容易出现此类问题&#xff0c;因为m系列是arm64的芯片架构&#xff0c;而有些nodejs版本或npm包的芯片架构是x86的&#x…

代码随想录算法训练营第十四天|对树的初步认识

二叉树种类 在我们解题过程中二叉树有两种主要的形式&#xff1a;满二叉树和完全二叉树。 满二叉树 满二叉树&#xff1a;如果一棵二叉树只有度为0的结点和度为2的结点&#xff0c;并且度为0的结点在同一层上&#xff0c;则这棵二叉树为满二叉树。 这棵二叉树为满二叉树&…

相关C语言易错点

四区 我们想来介绍一下内存四区 栈区 局部变量&#xff0c;局部常量 空间自动开辟和释放&#xff0c;只能作用于局部&#xff0c;函数不能返回局部变量的空间地址 堆区 malloc,realloc,free 手动开辟&#xff0c;手动释放&#xff0c;如果不手动释放&#xff0c;那么会在程…

python3.6 安装pillow失败

问题描述 python3 安装 pillow 失败 错误原因 python3.6 不支持 pillow9.0 以上的版本 解决方法&#xff1a; 指定版本安装 e.g., pillow8.0 pip3 install pillow8.0

【HarmonyOS】Java如何引用外部jar包

【关键字】 Java、引用jar包​ 【写在前面】 使用API6和API7开发HarmonyOS应用时&#xff0c;因为应用中只能引用SDK中开放的功能接口&#xff0c;但是部分jdk自带的接口功能在SDK中并未封装&#xff0c;要想在工程中使用jdk开放的接口功能&#xff0c;需要将jdk中的jar包通过…

一文讲述什么是数字孪生?

当前世界正处于百年未有之大变局&#xff0c;数字经济在各国已成为经济发展的重点。数字经济也是我国社会经济发展的必经之路。 近些年&#xff0c;大数据、人工智能、数字孪生等技术的发展促使技术与国内各产业进一步融合&#xff0c;从而推动了各产业在智能化、数字化等方面…

UEFI+win7+多系统安装

物理主机先安装的Windows10&#xff0c;同时需要安装Windows7的双系统 1.在https://next.itellyou.cn/下载Windows 7 ISO 2.使用Rufus制作U盘安装盘 注意一定要选择FAT32格式&#xff0c;否则安装过程会卡住 3.由于官方纯净的安装镜像默认不支持UEFI安装&#xff0c;有两种解决…

React - useEffect函数的理解和使用

文章目录 一&#xff0c;useEffect描述二&#xff0c;它的执行时机三&#xff0c;useEffect分情况使用1&#xff0c;不写第二个参数 说明监测所有state&#xff0c;其中一个变化就会触发此函数2&#xff0c;第二个参数如果是[]空数组&#xff0c;说明谁也不监测3&#xff0c;第…

RHCE使用RHEL系统角色题报错

题目&#xff1a; 使用 RHEL 系统角色 4. 安装 RHEL 系统角色软件包&#xff0c;并创建符合以下条件的 playbook/home/curtis/ansible/selinux.yml &#xff1a; 在所有受管节点上运行 使用 selinux 角色 配置该角色&#xff0c;以强制状态使用 selinux 报错一&#xff1a; [c…