uniapp小程序封装圆环显示比例数据

如下是组件信息
1.顺时针旋转

2.逆时针旋转

bash 复制代码
<template>
	<!-- 圆环组件 -->
	<view class="circle-box" :style="{width: size + 'px', height: size + 'px'}">
		<canvas type="2d" id="ringCanvas" class="canvas" :style="{width: size + 'px', height: size + 'px'}"></canvas>
		<!-- 中间文字:显示原始值 -->
		<view class="num-text" v-if="showText">{{ percent }}%</view>
	</view>
</template>

<script>
	export default {
		props: {
			// 百分比数值
			percent: {
				type: Number,
				default: 50
			},
			// 圆环背景色
			bgColor: {
				type: String,
				default: '#ECECEC'
			},
			// 圆环填充色
			activeColor: {
				type: String,
				default: '#409EFF'
			},
			// 线条宽度
			lineWidth: {
				type: Number,
				default: 6
			},
			// 宽高大小
			size: {
				type: Number,
				default: 150
			},
			// 是否现在中间文字
			showText: {
				type: Boolean,
				default: false
			}
		},
		data() {
			return {
				drawTimer: null
			}
		},
		watch: {
			percent: {
				handler() {
					this.debounceDraw()
				},
				immediate: true
			},
			activeColor() {
				this.debounceDraw()
			},
			lineWidth() {
				this.debounceDraw()
			},
			size() {
				this.debounceDraw()
			},
			bgColor() {
				this.debounceDraw()
			}
		},
		onReady() {
			// 确保 Canvas 节点真实渲染后再绘制
			setTimeout(() => {
				this.drawRing()
			}, 30)
		},
		beforeDestroy() {
			if (this.drawTimer) clearTimeout(this.drawTimer)
		},
		methods: {
			debounceDraw() {
				if (this.drawTimer) clearTimeout(this.drawTimer)
				this.drawTimer = setTimeout(() => {
					this.drawRing()
				}, 10)
			},
			drawRing() {
				const query = uni.createSelectorQuery().in(this)
				query.select('#ringCanvas')
					.fields({
						node: true,
						size: true
					})
					.exec(res => {
						if (!res || !res[0] || !res[0].node) return

						const canvas = res[0].node
						const ctx = canvas.getContext('2d')
						const dpr = uni.getSystemInfoSync().pixelRatio || 2

						canvas.width = this.size * dpr
						canvas.height = this.size * dpr
						ctx.scale(dpr, dpr)

						const cx = this.size / 2
						const cy = this.size / 2
						const r = cx - this.lineWidth / 2

						ctx.clearRect(0, 0, this.size, this.size)

						// 1. 绘制背景圆环
						ctx.beginPath()
						ctx.arc(cx, cy, r, 0, 2 * Math.PI)
						ctx.lineWidth = this.lineWidth
						ctx.strokeStyle = this.bgColor
						ctx.stroke()

						// 真实绘制百分比
						let realPercent = Math.max(0, Math.min(100, this.percent))
						let drawPercent = realPercent

						// 只有100%才闭合,非满圈保留缺口
						const isFull = realPercent >= 100
						if (!isFull) {
							drawPercent = Math.min(realPercent, 95)
						}

						// ==============================================
						// 顺时针绘制(从顶部开始)
						// ==============================================
						const startRad = -Math.PI / 2 // 顶部起点
						// const endRad = startRad + (drawPercent / 100) * 2 * Math.PI  //顺时针
						const endRad = startRad - (drawPercent / 100) * 2 * Math.PI //逆时针

						ctx.beginPath()
						ctx.arc(cx, cy, r, startRad, endRad, true) // false = 顺时针  true = 逆时针
						ctx.strokeStyle = this.activeColor
						ctx.lineWidth = this.lineWidth
						ctx.lineCap = 'round'
						ctx.stroke()
					})
			}
		}
	}
</script>

<style scoped>
	.circle-box {
		position: relative;
		margin: 0 auto;
	}

	.canvas {
		display: block;
		width: 100%;
		height: 100%;
	}

	.num-text {
		position: absolute;
		top: 50%;
		left: 50%;
		transform: translate(-50%, -50%);
		font-size: 28rpx;
		color: #333;
		font-weight: bold;
		pointer-events: none;
	}
</style>

顺时针/逆时针的代码差别

bash 复制代码
const endRad = startRad + (drawPercent / 100) * 2 * Math.PI  //顺时针
const endRad = startRad - (drawPercent / 100) * 2 * Math.PI   //逆时针


ctx.arc(cx, cy, r, startRad, endRad, true) // false = 顺时针  true = 逆时针
相关推荐
__zRainy__1 小时前
uni-app 全局容器实战系列(三):全局 NavBar 和 TabBar 组件设计
uni-app
万岳软件开发小城1 小时前
外卖系统源码如何选择?校园外卖APP+小程序平台搭建指南
小程序·同城外卖系统源码·校园外卖小程序·外卖app开发·外卖软件开发·外卖平台搭建
三少爷的鞋1 小时前
Android 面试系列:runBlocking 到底该在哪用?
android
DogDaoDao9 小时前
Android 硬件编码器参数完全指南:MediaCodec 深度解析
android·音视频·视频编解码·h264·硬编码·视频直播·mediacodec
JohnnyDeng9410 小时前
Android 自定义 View:Canvas 绘图与事件分发深度解析
android
Android小码家13 小时前
Framework之Launcher小窗开发
android·framework·虚拟屏·小窗
赏金术士13 小时前
第七章:状态管理实战与架构总结
android·ui·kotlin·compose
程序鉴定师14 小时前
西安小程序制作的可靠选择与发展前景
大数据·小程序
一颗小青松14 小时前
uniapp输入框fixed定位,导致页面顶起解决方案
前端·uni-app