uniapp,自绘仪表盘组件(基础篇)
文章目录
- 一、为什么需要自绘仪表盘?
- 二、准备知识
- 三、实现基础仪表盘
- 1. 组件模板结构
- 2. 核心绘制逻辑
- 3. 样式优化
- 四、使用示例
- 五、核心实现原理
- 六、扩展方向
- 七、常见问题
一、为什么需要自绘仪表盘?
在物联网、数据监控等场景中,仪表盘是常见的数据可视化组件。uniapp的组件市场虽然有许多现成方案,但自绘组件具有以下优势:
- 完全掌控视觉效果
- 无依赖零冗余
- 高性能Canvas渲染
- 轻松适配多端
二、准备知识
- 基础Canvas绘图API
- uni-app的Canvas组件使用
- 三角函数基础
- Vue组件开发基础
三、实现基础仪表盘
1. 组件模板结构
<template>
<view class="gauge-container">
<canvas
canvas-id="gaugeCanvas"
:style="{ width: canvasSize + 'px', height: canvasSize + 'px' }"
></canvas>
<view class="value-text">{{ currentValue }}</view>
</view>
</template>
2. 核心绘制逻辑
export default {
props: {
value: { type: Number, default: 0 }, // 当前值
max: { type: Number, default: 100 }, // 最大值
min: { type: Number, default: 0 }, // 最小值
size: { type: Number, default: 300 } // 画布尺寸
},
mounted() {
this.initCanvas();
},
methods: {
initCanvas() {
this.ctx = uni.createCanvasContext('gaugeCanvas', this);
this.drawBase();
this.drawPointer();
},
// 绘制底盘
drawBase() {
const center = this.canvasSize / 2;
const radius = center * 0.8;
// 外圆环
this.ctx.beginPath();
this.ctx.arc(center, center, radius, 0.75 * Math.PI, 2.25 * Math.PI);
this.ctx.strokeStyle = '#eee';
this.ctx.lineWidth = 8;
this.ctx.stroke();
// 刻度线
const totalTicks = 20;
for (let i = 0; i <= totalTicks; i++) {
this.ctx.save();
this.ctx.translate(center, center);
const angle = 0.75 * Math.PI + (i / totalTicks) * 1.5 * Math.PI;
this.ctx.rotate(angle);
// 长刻度
this.ctx.beginPath();
this.ctx.moveTo(radius - 15, 0);
this.ctx.lineTo(radius, 0);
this.ctx.strokeStyle = i % 5 === 0 ? '#333' : '#999';
this.ctx.lineWidth = i % 5 === 0 ? 3 : 1;
this.ctx.stroke();
this.ctx.restore();
}
},
// 绘制指针
drawPointer() {
const center = this.canvasSize / 2;
const valueAngle = this.getCurrentAngle();
this.ctx.save();
this.ctx.translate(center, center);
this.ctx.rotate(valueAngle);
// 指针三角形
this.ctx.beginPath();
this.ctx.moveTo(-8, 0);
this.ctx.lineTo(0, -center * 0.7);
this.ctx.lineTo(8, 0);
this.ctx.fillStyle = '#e64340';
this.ctx.fill();
// 中心圆点
this.ctx.beginPath();
this.ctx.arc(0, 0, 5, 0, 2 * Math.PI);
this.ctx.fillStyle = '#333';
this.ctx.fill();
this.ctx.restore();
this.ctx.draw();
},
getCurrentAngle() {
const range = this.max - this.min;
const progress = (this.value - this.min) / range;
return 0.75 * Math.PI + progress * 1.5 * Math.PI;
}
}
}
3. 样式优化
.gauge-container {
position: relative;
display: flex;
justify-content: center;
align-items: center;
}
.value-text {
position: absolute;
font-size: 24px;
font-weight: bold;
color: #333;
}
四、使用示例
<template>
<view class="container">
<Gauge :value="75" :max="100" size="300" />
</view>
</template>
<script>
import Gauge from '@/components/gauge.vue'
export default {
components: {
Gauge
}
}
</script>
五、核心实现原理
角度计算:将数值映射到135°~315°的扇形角度(0.75π ~ 2.25π)
坐标系变换:通过translate和rotate实现指针旋转
分层绘制:先绘制静态元素(底盘),再绘制动态元素(指针)
性能优化:使用Canvas的save/restore管理绘图状态
六、扩展方向
添加动画效果(使用requestAnimationFrame)
绘制渐变颜色区间
添加触摸交互
实现双指针仪表
添加数字标签
七、常见问题
模糊问题:确保canvas尺寸与样式尺寸一致
层级问题:数值文本需要绝对定位覆盖在canvas上
单位转换:使用uni.upx2px处理不同屏幕适配
多次绘制:在修改数据后需要手动调用draw方法
通过这个基础实现,开发者可以快速掌握uniapp中Canvas组件的使用技巧,后续可根据具体需求进行样式定制和功能扩展。这种自绘方案在H5和小程序端均可获得良好的性能表现。