canvas实现保存超出屏幕之外的内容

简述:先说一下,实现目标。
so,上图
在这里插入图片描述
因为,项目需求,需要把动态的课程表,实现点击保存按钮,实现将如上图一样的课程表保存到本地。
那么,实现的思路就是:

画布画出来,然后保存到本地

开发框架:uni,
开发工具:Hbulid-X,

既然有了思路,那么就好办了吧,我把课表分成了四个部分去画
1.左边的时间
2.顶部的场馆信息+底部的照片
3.底部的日期显示
4.课程表内容显示
把一张大图拆分四个部分画就很简单了。

但是,说一下,uni,编译成小程序的坑,首先,uni不支持es10的写法,亲测有效。

例如 :项目中用到了 es10的String.trimStart() //截取字符串前面的空格 ,然后换成了String.trim()使用

此处已班生成课程表照片,封装成组件。话不多说,上菜

index.vue

<template>
	<view>	
		<canvasCourse :courseList='courseList' :variableMonth='variableMonth' :venueInfo='venueInfo' ></canvasCourse>
	</view>

</template>

<script>
	
	import canvasCourse from '@/components/canvasCourse.vue';

	export default {
		components: {
			canvasCourse,
		},

		data() {
			return {
			
				weeks: ['一', '二', '三', '四', '五', '六', '日'],
				variableMonth: ["7-10", "10-10", "7-10", "10-10", "7-10", "10-10", "9-30", "10-10"],
				venueInfo: {
					title: '王府健身',
					codeImg: '/static/table.png',
					logoImg: '/static/login.png'
				},
				courseList: [{
						startTime: '13.00', //用来显示纵表头课程的开始时间
						list: [{
								timeSlot: "8:00-12:00", //课程时间段
								courseName: "塑形", //课程名称
								coash: "rechel", //教练
								courseStar: 5, //课程难度
								courseColor: 'background: red;'

							},
							{
								timeSlot: "8:00-12:00", //课程时间段
								courseName: "减肥", //课程名称
								coash: "rechel", //教练
								courseStar: 5, //课程难度
								courseColor: 'background: yellow;'
							},
							{
								timeSlot: "8:00-12:00", //课程时间段
								courseName: "减肥", //课程名称
								coash: "rechel", //教练
								courseStar: 5, //课程难度
								courseColor: 'background: green;'
							},
							{
								timeSlot: "8:00-12:00", //课程时间段
								courseName: "减肥", //课程名称
								coash: "rechel", //教练
								courseStar: 5, //课程难度
								courseColor: 'background: green;'
							},
							{
								timeSlot: "8:00-12:00", //课程时间段
								courseName: "减肥", //课程名称
								coash: "rechel", //教练
								courseStar: 5, //课程难度
								courseColor: 'background: green;'
							},
							{
								timeSlot: "8:00-12:00", //课程时间段
								courseName: "减肥", //课程名称
								coash: "rechel", //教练
								courseStar: 5, //课程难度
								courseColor: 'background: green;'
							},
							{
								timeSlot: "8:00-12:00", //课程时间段
								courseName: "减肥", //课程名称
								coash: "rechel", //教练
								courseStar: 5, //课程难度
								courseColor: 'background: green;'
							}
						],
					},
					{
						startTime: '20.00', //用来显示纵表头课程的开始时间
						list: [{
								timeSlot: "8:00-12:00", //课程时间段
								courseName: "塑形", //课程名称
								coash: "rechel", //教练
								courseStar: 5, //课程难度
								courseColor: 'background: red;'

							},
							{
								timeSlot: "8:00-12:00", //课程时间段
								courseName: "减肥", //课程名称
								coash: "rechel", //教练
								courseStar: 5, //课程难度
								courseColor: 'background: yellow;'
							},
							{
								timeSlot: "8:00-12:00", //课程时间段
								courseName: "减肥", //课程名称
								coash: "rechel", //教练
								courseStar: 5, //课程难度
								courseColor: 'background: green;'
							},
							{
								timeSlot: "8:00-12:00", //课程时间段
								courseName: "减肥", //课程名称
								coash: "rechel", //教练
								courseStar: 5, //课程难度
								courseColor: 'background: green;'
							},
							{
								timeSlot: "8:00-12:00", //课程时间段
								courseName: "减肥", //课程名称
								coash: "rechel", //教练
								courseStar: 5, //课程难度
								courseColor: 'background: green;'
							},
							{
								timeSlot: "8:00-12:00", //课程时间段
								courseName: "减肥", //课程名称
								coash: "rechel", //教练
								courseStar: 5, //课程难度
								courseColor: 'background: green;'
							},
							{
								timeSlot: "8:00-12:00", //课程时间段
								courseName: "减肥", //课程名称
								coash: "rechel", //教练
								courseStar: 5, //课程难度
								courseColor: 'background: green;'
							}
						],
					},

				],
				// ctxTotalH: null,

			}
		},
		onReady() {

			// this.draw()

		},
		onLoad() {
		
		},

		methods: {

		}
	}
</script>

<style scoped=''>

</style>

课程表组件
course.vue

<template>
	<view>

		<canvas canvas-id="myCanvas" :style="{height:canvasH}" />
		<!-- <canvas canvas-id="myCanvas" :style="{width:canvasW,height:canvasH,border: '1px solid black',background:'#FFFFFF',}" /> -->
		<button @tap="save"> 保存 </button>

	</view>

</template>

<script>
	export default {
		props: {
			courseList: {
				type: Array,
				// default: [{
				// 	startTime: '8.00', //课程开始时间
				// 	list: [{
				// 		timeSlot: "8:00-12:00", //课程时间段
				// 		courseName: "塑形", //课程名称
				// 		coash: "rechel", //教练
				// 		courseStar: 5, //课程难度
				// 		courseColor: 'background: red;'
				// 	}]
				// }]
			},
			variableMonth: {
				type: Array,

			},
			venueInfo: {
				type: Object,

			},

		},

		data() {
			return {
				canvasW: 1800 + 'upx',
				canvasH: '0vh', //100 + 'vh',
				ctxTotalH: 860,
				weeks: ['一', '二', '三', '四', '五', '六', '日'],
						}
		},
		mounted() {

			// console.log(canvasH,canvasW,'canvasH');
			// this.draw()//绘制课表
		},
		created() {

		},

		methods: {

			drawVenueInfo(ctx, centerX, centerY) {
				let height = (parseInt(this.canvasH)) * (this.courseList.length + 4)  //初始化高度*行数

				this.ctxTotalH = height
				console.log(this.ctxTotalH, height, this.canvasH, "height")
				let logoHeight = 200 + 100 * this.courseList.length //画布总高度

				//顶部瑜伽场馆信息
				let img = "/static/time.png"
				ctx.drawImage(img, 30, 20, 50, 50) //x y W H
				ctx.drawImage(this.venueInfo.logoImg, centerX, 10, 80, 80)
				ctx.setFontSize(20)
				let logoX = centerX + 120
				ctx.fillText(this.venueInfo.title, logoX, centerY - 5);
				ctx.fillText(this.variableMonth[0], logoX + 150, centerY - 5); //所在周周一
				ctx.fillText('——', logoX + 150 + 60, centerY - 5); //所在周周一
				ctx.fillText(this.variableMonth[6] + '课程表', logoX + 150 + 60 + 70, centerY - 5); //所在周周日
				//左下角固定照片
				ctx.drawImage('/static/leftLogo.png', 30, logoHeight, 150, 150)

				//右下角瑜伽场馆二维码信息
				ctx.drawImage(this.venueInfo.codeImg, 580, logoHeight - 10, 130, 130)
				ctx.setFontSize(12)
				ctx.fillText('长按识别二维码立即约课', 600 + 130, logoHeight + 50); //所在周周日
				ctx.fillText('翼速网络有限公司技术支持', 600 + 130, logoHeight + 50 + 20); //所在周周日

			},
			drawTime(ctx, row, centerY) {

				let oneWordX = 30 //距离左边30
				let oneWordY = oneWordY = row * 100 + 90 + centerY
				ctx.setFillStyle('white') //矩形背景色
				ctx.fillRect(oneWordX, oneWordY, 70, 100) //画矩形
				ctx.stroke(); //对当前路径进行描边
				ctx.setFillStyle('black')
				ctx.fillText(this.courseList[row].startTime, oneWordX + 15, oneWordY + 50);

			},
			drawDateTitle(ctx, centerY) {
				let allRight = 100
				for (let i = 0; i < 7; i++) {
					let oneX = i * 110
					let oneWordX = i * 110 + 30 + allRight
					if (oneWordX == 0) {
						oneWordX = 10
					}
					ctx.setFontSize(14)
					ctx.setFillStyle('green')
					ctx.fillText(this.variableMonth[i], oneWordX, 50 + centerY);
					ctx.fillText("周" + this.weeks[i], oneWordX, 50 + 20 + centerY);
				}
			},

			drawCourse(ctx, row, centerY) {
				//画日期
				// let 整体右移
				let allRight = 100
				let startHeight = row * 100 + 90 + centerY

				//画一行课程表

				for (let i = 0; i < 7; i++) {
					let oneX = i * 110
					let oneWordX = i * 110 + 10 + allRight

					if (oneWordX == 0) {
						oneWordX = 10
					}

					//文字要居中,等于矩形的一半高度
					if (this.courseList[row] != null) {
						let one = this.courseList[row].list[i]
						let abc = this.courseList[row].list[i].courseColor
						let b = abc.substring(abc.indexOf(':') + 1, abc.length);
						//.replace(/^\s+|\s+$/g,"") 清楚两端空格
						let color = b.substring(1, b.length - 1).replace(/^\s+|\s+$/g, "")

						// let color = b.split(';')[0].trimStart() //trimStart()去掉空格	转化课程背景色					

						ctx.setStrokeStyle('#f2f2f2')
						ctx.strokeRect(oneX + allRight, startHeight, 100, 100) //绘制无填充矩形边框
						ctx.setFillStyle(color)
						ctx.fillRect(oneX + allRight, startHeight, 99, 99) //绘制填充矩形  给矩形背景色 内容宽高小于有边框矩形宽高
						ctx.setFontSize(14)
						ctx.setFillStyle('white') //字体颜色
						ctx.fillText(one.courseName, oneWordX, startHeight + 30); //渲染字体
						ctx.fillText(one.coash, oneWordX, startHeight + 30 + 20);
						ctx.fillText(one.timeSlot, oneWordX, startHeight + 30 + 40);
						//画难度系数星星
				    	let img;
						if (!one.courseStar) {
							one.courseStar = 0
						} else {
							for (let i = 0; i < 5; i++) {
								if (i < parseInt(one.courseStar)) {
									img = "/static/xing.png"
									ctx.drawImage(img, oneWordX + 10 * i + 2, startHeight + 50 + 30, 10, 10)
								} else {
									img = "/static/xing1.png"
									ctx.drawImage(img, oneWordX + 10 * i + 2, startHeight + 50 + 30, 10, 10)
								}
							}
						}

					}

				}
			},

			draw() {
				//画布顶部标题中心点
				let centerX = 250 //300
				let centerY = 50 //
				const ctx = uni.createCanvasContext('myCanvas', this) //编译成小程序需要给canvas上下文绑定this指向
				// const ctx = uni.createCanvasContext('myCanvas').bind(this)
				ctx.fillStyle = "#FFFFFF"; //画布默认颜色色
				let courseListCount = this.courseList.length
				this.drawDateTitle(ctx, centerY) //画日期
				this.drawVenueInfo(ctx, centerX, centerY) //画获取场馆信息
				for (let i = 0; i < courseListCount; i++) {
					//画一行 this.courseList[i]
					this.drawTime(ctx, i, centerY)
					this.drawCourse(ctx, i, centerY)
					if (i > 0) {
						this.canvasH = (i * centerY + 100) + 'vh' //动态获取画布高度 总高度是每一行之和 多余的100是展示logo和二维码

						console.log(this.canvasH, '9999999999999');
					}
				}

				ctx.draw()
			},



			save() {
				console.log('保存');
				this.draw()
				console.log('画完了');

				this.packSave()
				console.log('保存到手机相册');



			},

			packSave() {
				wx.showToast({
					title: '分享图片生成中...',
					icon: 'loading',
					duration: 1000
				});
				let ctxTotalH = this.ctxTotalH
				console.log(ctxTotalH, 'save 画布高度');
				uni.showModal({
					title: '是否保存为照片到本地',
					success: (res) => {
						console.log("eeeeeeeeee")
						if (res.confirm) {
							console.log("eeeeeeeeee2")
							uni.canvasToTempFilePath({
								x: 0,
								y: 0,
								width: 1800,
								height: 1800,
								destWidth: 900,
								destHeight: 900,
								canvasId: 'myCanvas',
								fileType: 'jpg',
								success: (res) => {
									this.canvasImg = res.tempFilePath
									console.log(this.canvasImg, '生成的照片')
									this.saveImg()
								}
							}, this)
						}
					}
				})

			},


			saveImg() {
				uni.saveImageToPhotosAlbum({
					filePath: this.canvasImg,
					success: () => {

						console.log('save success');
						uni.showToast({
							title: '保存成功',
							success: () => {
								setTimeout(() => {
									uni.navigateBack({
										delta: 2
									})
								}, 200)
							}
						})
					}
				})


			},

		}
	}
</script>

<style scoped=''>
	canvas {
		background: white;		
		width: 2200upx;
		border: 1px solid black;
		background: #fff;
	}

	button {
		font-size: 30upx;
		height: 100upx;
		line-height: 100upx;

		background: #1ECFA7;
		position: fixed;
		left: 10upx;
		bottom: 100upx;
		color: white;
		border-radius: 50%;
	}
</style>

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值