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 = 逆时针
相关推荐
limuyang24 小时前
PDF Viewer KMP(基于 chrome 的 PDFium 内核)
android·kotlin
心平气和量大福大7 小时前
android-控件-搜索框SearchView
android·gitee
2601_962177137 小时前
【MySQL篇】聚合查询,联合查询
android·java·mysql
壮哥_icon8 小时前
【Android】批量 VectorDrawable 动态分别修改 fillColor 和 strokeColor 的踩坑与终极解决方案
android
齐天qaq9 小时前
Android 系统 APK 分区与权限
android
心平气和量大福大9 小时前
android-控件-多选框CheckBox
android·gitee
pengyu11 小时前
【Kotlin 协程修仙录 · 大乘境 · 初阶】 | 跳出三界:协程在 KMP 与后端开发中的跨平台之道
android·kotlin
XiaoLeisj11 小时前
Android Memory Profiler:堆内存指标、内存抖动与泄漏定位
android·性能优化·内存抖动·内存泄露·memory profiler
未来猫咪花11 小时前
Everything is ViewModel:让状态管理回到对象世界
android·flutter·ios