uniapp实现简单的温度刻度表盘

一、简介

        使用canvas 实现简单的温度刻度表盘,可自定义显示信息和内容,可滑动控制显示。

二、效果图

三、示例代码

<template>
	<view class="page">
		<view class="progress_box" @touchmove="handleTouchMove">
			<canvas class="progress_bar" canvas-id="temperatureCanvas" style="width: 200px; height: 200px;" ></canvas>
		</view>
		<!-- <view class="progress_box">
			<canvas class="progress_bar" canvas-id="temperatureCanvas" style="width: 200px; height: 200px;"></canvas>
		</view> -->
		<button @click="testFun">test</button>
	</view>
</template>

<script>
export default {
	data() {
		return {
			temperature: 20, // 温度值
			colors: ['#25baff','#11fcff','#10ffd0', '#00ff7f', '#00ff00','#ff0000'], // 温度对应的颜色
			centerx:0,
			centery:0,
			touchAngle:0,
		};
	},
	mounted() {
		this.drawTemperatureScale(200,200,'temperatureCanvas',80,this.temperature);
		this.getCanvasPosition();
	},
	methods: {
		getCanvasPosition() {
		    uni.createSelectorQuery().in(this).select('.progress_bar').boundingClientRect((rect) => {
			const { left, top } = rect;
			
			// 计算圆心在整个页面坐标系的 x 和 y 轴坐标
			this.centerx = left + rect.width / 2;
			this.centery = top + rect.height / 2;
	
			console.log('圆心坐标:', this.centerx, this.centery);
		    }).exec();
		},
		//width heigth 圆的直径   scale 刻度表示视图上多少个刻度点  temp 温度数值 也可显示其他的数值
		drawTemperatureScale(width,height,canvasId,scale,temp) {
			const ctx = uni.createCanvasContext(canvasId, this);
			const radius = Math.min(width, height) / 2;
			const centerX = width / 2;
			const centerY = height / 2;
			// 绘制背景圆盘
			ctx.beginPath();
			ctx.arc(centerX, centerY, radius, 0, 2 * Math.PI);
			// ctx.setLineWidth(25);
			// ctx.setStrokeStyle('#ffffff');
			// ctx.stroke();
			ctx.setFillStyle('#ffffff');
			ctx.fill();
			// 绘制刻度线
			const temporaryTemp = Math.floor((temp-20)/50*scale)
			for (let i = 0; i <= scale; i++) {//外圈刻度
				const angle = (i / scale) * (1.6 * Math.PI)+1.2* Math.PI; // 刻度线对应的角度
				const startX = centerX + (radius - 10) * Math.sin(angle); //-10 到 -0 间隔5  这个是刻度线的长度 
				const startY = centerY - (radius - 10) * Math.cos(angle);
				const endX = centerX + radius * Math.sin(angle);
				const endY = centerY - radius * Math.cos(angle);
				ctx.beginPath();
				ctx.moveTo(startX, startY);
				ctx.lineTo(endX, endY);
				// 根据温度设置刻度线颜色
				const colorIndex = (i / scale)===1? this.colors.length-1:Math.floor(i / scale * this.colors.length);
				if(i <= temporaryTemp){
					ctx.setStrokeStyle(this.colors[colorIndex]);
				}else{
					ctx.setStrokeStyle('#f1f1f1');
				}
				ctx.setLineWidth(2);//刻度线宽度
				ctx.stroke();
			}
			for (let i = 0; i <= scale; i++) {//内圈刻度
				const angle = (i / scale) * (1.6 * Math.PI)+1.2* Math.PI; // 刻度线对应的角度 
				const startX = centerX + (radius - 23) * Math.sin(angle);//-23 到 -17 间隔5  这个是刻度线的长度
				const startY = centerY - (radius - 23) * Math.cos(angle);
				const endX = centerX + (radius - 17) * Math.sin(angle);
				const endY = centerY - (radius - 17) * Math.cos(angle);
				ctx.beginPath();
				ctx.moveTo(startX, startY);
				ctx.lineTo(endX, endY);
				// 根据温度设置刻度线颜色
				ctx.setStrokeStyle('#f1f1f1');
				ctx.setLineWidth(2);
				ctx.stroke();
			}
			// 绘制圆心位置的文字
			const text1 = temp;
			const text2 = '℃';
			ctx.setFontSize(28); // 设置第一个文字的大小
			ctx.setFillStyle('#000');
			ctx.setTextAlign('center'); 
			ctx.fillText(text1, centerX - 15, centerY+10);
			
			ctx.setFontSize(18); // 设置第二个文字的大小
			ctx.setTextAlign('left'); 
			ctx.fillText(text2, centerX + 5, centerY+10);
			//结尾处图标
			const iconWidth = 20;
			const iconHeight = 20;
			const endAngle = (temporaryTemp / scale) * (1.6 * Math.PI)+1.2* Math.PI;
			const iconX = (centerX-10) + (radius-10) * Math.sin(endAngle);// -10\-10 与图标位置相关 不同大小的视图需要适当的调整
			const iconY = (centerY-10) - (radius-10) * Math.cos(endAngle);// -10\-10 与图标位置相关
			ctx.drawImage('../../static/logo.png', iconX, iconY, iconWidth, iconHeight);
			
			ctx.draw();
		},
		testFun(){
			this.temperature+=1;
			this.drawTemperatureScale(200,200,'temperatureCanvas',80,this.temperature);
		},
		handleTouchMove(e) {//根据数值范围自行换算角度关系 
		    const touchX = e.touches[0].clientX;
		    const touchY = e.touches[0].clientY;
		    // 计算相对于圆心的角度
		    this.touchAngle = Math.atan2(  touchY-this.centery, touchX - this.centerx)-0.7* Math.PI;
			if(touchX < this.centerx && touchY > this.centery && this.touchAngle >= 0 ){
				const touchScale = Math.floor(this.touchAngle/(1.6* Math.PI)*50)+20;
				this.drawTemperatureScale(200,200,'temperatureCanvas',80,touchScale);
				console.log(touchScale)
			}else if(this.touchAngle <= -0.4* Math.PI){
				const touchScale1 = Math.floor((this.touchAngle+1.7* Math.PI)/(1.6* Math.PI)*50+10)+20;
				this.drawTemperatureScale(200,200,'temperatureCanvas',80,touchScale1);
				console.log(touchScale1)
			}
		    // console.log('相对圆心的角度:', this.touchAngle-0.7* Math.PI);
		}
	}
}
</script>

<style>
	.page{
		position: fixed;
		display: flex;
		flex-direction: column;
		align-items: center;
		width: 100%;
		height: 100vh;
		background-color: #f6f7fb;
	}
	.progress_box {
		position: relative;
		width: 100%;
		height: 300px;
		display: flex;
		align-items: center;
		justify-content: center;
		text-align: center;
		background-color: aqua;
	}
	.progress_bar{
		position: absolute;
		background-color: beige;
	}
</style>

代码中有部分注释可借助注释修改,代码逻辑相较简单。

四、优缺点

        优点:自定义、样式可多变、参数自调、简单移植、多平台可用

        缺点:未限制滑动范围(可自行通过计算移动位置到圆心的距离进行判定)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值