uniapp中canvas绘制圆弧滑动条

前言

 开始时用vue实现了一个圆弧滑动条,因为uniapp自己封装了canvas方法,移植到uniapp时并不能适用。于是进行了修改。

实现

<canvas style="height: 300px; width: 300px;" ref="myCanvas" canvas-id="myCanvas" @touchstart="canvasDown" @touchmove="canvasMove" @touchend="canvasUp"></canvas>
<script>
import {
	hideTabBar
} from "@/common/util.js"
import slideableImg from "@/static/settings/slideable.png"
export default {
	data() {
		return {
			pageUrl: {
				info: 'device/loadDevice', // 设备信息
				edit: 'appDevice/singleSetting' // 保存设备信息
			},
			// 画布
			canvas: '',
			// 画笔
			ctx: '',
			// 是否可以拖动
			canvasMoveUse: false,
			// 可滑动提醒图片
			slideableImg,
			// 显示的电量百分比
			showCharge: 50,
			// 设备信息
			deviceInfo: {},
			// 设备id
			deviceId: '',
			// 用户id
			userId: ''
		}
	},
	
	created() {
		hideTabBar()
	},
	computed: {
		// 显示百分比
		showChargePercent(){
			return this.showCharge + '%'
		}
	},
	onLoad() {
		this.deviceId = uni.getStorageSync('deviceId')
		this.userId = uni.getStorageSync('consumer').id
		this.$nextTick(() => {
			this.initCanvas()
		})
	},
	onShow() {
		uni.setNavigationBarTitle({
			title: this.$t('function.deviceDischarge')
		});
		// 获取设备信息
		// this.getDischargeInfo()
	},
	// 监听返回事件
	onBackPress() {
	},
	methods: {
		// 初始化
		async initCanvas() {
			await this.getDischargeInfo()
			let realAngel = (0.01 * (Math.PI * 5 / 3) * this.showCharge) + ((Math.PI * 2) / 3)
			let x = this.getInitX(150, 150, 100, this.showCharge)
			let y = this.getInitY(150, 150, 100, this.showCharge)
			this.ctx = uni.createCanvasContext("myCanvas")
			this.drawDefaultRing()
			// this.drawRingByTouch(Math.PI * 9 / 6)
			this.drawRingByTouch(realAngel)
			this.drawPoint(x, y)
			this.drawText(this.showChargePercent)
			this.ctx.draw()
		},

		// 画默认的圆弧	
		drawDefaultRing() {
			this.ctx.beginPath()
			this.ctx.setLineWidth(20)
			this.ctx.setStrokeStyle('#fff')
			this.ctx.arc(
				150, 150,
				100,
				0, Math.PI * 2 / 6,
				false
			);
			this.ctx.stroke();
			this.ctx.beginPath()
			this.ctx.arc(
				150, 150,
				100,
				Math.PI * 4 / 6, Math.PI * 14 / 6,
				false
			);
			this.ctx.stroke();
		},

		// 画圆点
		drawPoint(x, y) {
			this.ctx.beginPath()
			this.ctx.setFillStyle('#009f8a')
			this.ctx.arc(
				x, y,
				9,
				0, Math.PI * 2
			)
			this.ctx.fill();

			this.ctx.beginPath()
			this.ctx.setFillStyle('#ffffff')
			this.ctx.arc(
				x, y,
				4,
				0, Math.PI * 2
			)
			this.ctx.fill();
		},

		// 画圆弧
		drawRingByTouch(angle) {
			this.ctx.beginPath()
			this.ctx.setLineWidth(8)
			var gr = this.ctx.createLinearGradient(80, 150, 220, 150);
			//添加颜色端点
			gr.addColorStop(0, 'rgba(12, 194, 194, 1)');
			gr.addColorStop(.24, 'rgba(46, 163, 255, 1)');
			gr.addColorStop(.58, 'rgba(74, 115, 247, 1)');
			gr.addColorStop(.78, 'rgba(74, 115, 247, 1)');
			gr.addColorStop(1, 'rgba(139, 71, 222, 1)');
			//应用fillStyle生成渐变
			this.ctx.setStrokeStyle(gr);
			this.ctx.arc(
				150, 150,
				100,
				(Math.PI * 4 / 6), angle,
				false
			);
			this.ctx.stroke();
		},

		// 写文字
		drawText(text) {
			// 文字下方底色
			this.ctx.beginPath()
			this.ctx.setFillStyle('#ffffff')
			this.ctx.arc(
				150, 150,
				70,
				0, Math.PI * 2
			)
			this.ctx.fill();

			this.ctx.beginPath()
			// text = '75%';
			//字体颜色
			this.ctx.font = '30px arial';
			this.ctx.fillStyle = '#000000';
			// 位置
			this.ctx.textAlign = 'center';
			this.ctx.textBaseline = 'middle';
			//描边宽度
			this.ctx.lineWidth = 3;
			//填充文字
			this.ctx.fillText(text, 150, 150);
		},

		canvasDown(e) {
			this.canvasMoveUse = true;
		},
		canvasMove(e) {
			if (this.canvasMoveUse) {
				let canvasX = e.touches[0].x
				let canvasY = e.touches[0].y

				// console.log(canvasX + ',' + canvasY);
				let angle = Math.atan((canvasY - 150) / (canvasX - 150))

				let x = this.getX(150, 150, 100, canvasX, canvasY)
				let y = this.getY(150, 150, 100, canvasX, canvasY)

				let realAngle = this.getRealAngle(canvasX, canvasY, angle)
				// 半圆的滑动范围判断
				if (realAngle <= (Math.PI * 14 / 6) && realAngle >= (Math.PI * 9 / 6)) {
					let percent = ((realAngle - (2 * Math.PI / 3)) / (Math.PI * 5 / 3)).toFixed(2)
					let showPercent = (percent * 100).toFixed(0)
					this.showCharge = showPercent
					// console.log(realAngle);
					this.$nextTick(() => {
						this.ctx.clearRect(0, 0, 300, 300)
						this.drawDefaultRing()
						this.drawRingByTouch(realAngle)
						this.drawPoint(x, y)
						this.drawText(this.showChargePercent)
						this.ctx.draw()
					})
				}
			}
		},

		/**
		 * 获取角度
		 * @param canvasX 鼠标x坐标
		 * @param canvasY 鼠标y坐标
		 * @param angle 根据反正切函数算出的角度
		 */
		getRealAngle(canvasX, canvasY, angle) {
			let realAngle = 0
			if (canvasX < 150 && canvasY > 150) {
				realAngle = (Math.PI / 2) - Math.abs(angle) + Math.PI / 2
			}
			if (canvasX < 150 && canvasY < 150) {
				realAngle = Math.abs(angle) + (Math.PI / 2) + Math.PI / 2
			}
			if (canvasX > 150 && canvasY < 150) {
				realAngle = (Math.PI / 2) - Math.abs(angle) + Math.PI + Math.PI / 2
			}
			if (canvasX > 150 && canvasY > 150) {
				realAngle = Math.abs(angle) + Math.PI * (3 / 2) + Math.PI / 2
			}
			return realAngle
		},

		/**
		 * 获取在圆上x轴坐标
		 * @param ox 原点x坐标
		 * @param oy 原点y坐标
		 * @param r 圆的半径
		 * @param x 鼠标x轴坐标
		 * @param y 鼠标y轴坐标
		 */
		getX(ox, oy, r, x, y) {
			// 角度
			let angle = Math.atan((oy - y) / (x - ox))
			// x轴长度
			let realX = Math.abs(r * Math.cos(angle))
			if (x < ox) {
				return (-realX) + ox
			} else {
				return realX + ox
			}
		},

		/**
		 * 根据初始值获取初始的x
		 * @param ox 原点x坐标
		 * @param oy 原点y坐标
		 * @param r 半径 
		 * @param angle
		 */
		getInitX(ox, oy, r, angle) {
			let tempAngle = (angle * (Math.PI * 5 / 3 * 0.01) + Math.PI / 6)
			if (tempAngle <= Math.PI) {
				return (-Math.abs(r * Math.sin(tempAngle))) + ox
			} else if (tempAngle > Math.PI) {
				return Math.abs(r * Math.sin(tempAngle)) + ox
			}
		},

		/**
		 * 根据初始值获取初始y
		 * @param ox 原点x坐标
		 * @param oy 原点y坐标
		 * @param {Object} r 半径
		 * @param {Object} angle 角度
		 */
		getInitY(ox, oy, r, angle) {
			let tempAngle = (angle * (Math.PI * 5 / 3) * 0.01 + Math.PI / 6)
			if ((tempAngle <= Math.PI / 2) || (tempAngle >= Math.PI * 3 / 2)) {
				return oy + Math.abs(r * Math.cos(tempAngle))
			} else if ((tempAngle > Math.PI / 2) && (tempAngle < Math.PI * 3 / 2)) {
				return oy - Math.abs(r * Math.cos(tempAngle))
			}
		},

		/**
		 * 获取在圆上y轴坐标
		 * @param ox 原点x坐标
		 * @param oy 原点y坐标
		 * @param r 圆的半径
		 * @param x 鼠标x轴坐标
		 * @param y 鼠标y轴坐标
		 */
		getY(ox, oy, r, x, y) {
			// 角度
			let angle = Math.atan((oy - y) / (x - ox))
			// y轴长度
			let realY = Math.abs(r * Math.sin(angle))
			if (y < oy) {
				return (-realY + oy)
			} else {
				return realY + oy
			}
		},

		canvasUp(e) {
			this.canvasMoveUse = false
		},
		canvasLeave(e) {
			this.canvasMoveUse = false
		},

		/**
		 * 获取设备放电信息
		 */
		getDischargeInfo() {
			let params = {
				id: this.deviceId
			}
			return this.$http('GET', this.pageUrl.info, params)
				.then(res => {
					if (res.success) {
						if(this.showCharge){
							this.deviceInfo = res.result // 保存设备信息
							this.showCharge = Number(res.result.battery_low_discharge)
						}
					} else {
						this.$showToast(res.message)
					}
				})
				.catch(err => {
					this.$showToast(err.message)
				})
		},

		// 保存
		save() {
			let params = {
				id: this.deviceId,
				battery_low_discharge: Number(this.showCharge) ,
				user_id: this.userId
			}
			this.$http('POST', this.pageUrl.edit, params)
			.then(res => {
				if(res.success){
					this.$showToast(res.message)
				}else{
					this.$showToast(res.message)
				}
			})
			.catch(err => {
				this.$showToast(err.message)
			})
		}
	}
}
</script>

效果:
在这里插入图片描述

  • 5
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
uniapp使用canvas绘制水印,可以通过以下步骤实现: 1. 首先,在uniapp项目创建一个新的页面或组件,用于显示canvas画布。 2. 在该页面或组件,使用`<canvas>`标签创建一个画布元素,并设置其宽度和高度。 3. 使用`uni.createCanvasContext()`方法创建一个绘图上下文对象,用于操作画布。 4. 使用绘图上下文对象的相关方法,如`fillText()`、`fillRect()`等来绘制水印内容。 5. 通过调用绘图上下文对象的`draw()`方法将绘制的内容显示在画布上。 下面是一个简单的示例代码,演示了如何在uniapp使用canvas绘制水印: ``` <template> <view> <canvas id="canvas" style="width: 300px; height: 200px;"></canvas> </view> </template> <script> export default { onReady() { const ctx = uni.createCanvasContext('canvas', this); ctx.setFillStyle('rgba(0, 0, 0, 0.5)'); // 设置水印颜色和透明度 ctx.setFontSize(16); // 设置水印字体大小 ctx.fillText('水印内容', 10, 20); // 绘制水印文本 ctx.draw(); // 绘制到画布上 } } </script> ``` 在上述代码,我们使用了uniapp提供的`uni.createCanvasContext()`方法创建了一个绘图上下文对象,并通过该对象的`setFillStyle()`、`setFontSize()`以及`fillText()`方法来设置水印的样式和内容。最后,通过调用`draw()`方法将绘制的水印显示在画布上。 需要注意的是,在uniapp使用canvas绘制水印时,需要确保在`onReady()`生命周期函数进行绘制操作,以确保画布已经完全加载。另外,还需要注意设置画布的宽度和高度,以及调整水印的位置和样式,以满足具体需求。 希望以上内容对您有所帮助!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值