| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218 |
- <template>
- <view class="circle-container">
- <canvas :canvas-id="canvasId" :style="{ width: size + 'px', height: size + 'px' }"></canvas>
- <view class="circle-text">
- <view class="percent">{{ percent }}<text class="mini-text">%</text></view>
- <view class="tips">充电枪正在<text class="tips-text">充电中</text></view>
- </view>
- </view>
- </template>
- <script>
- export default {
- name: "qs-circle-percent",
- props: {
- canvasId: {
- type: String,
- default: "11", // 进度颜色
- },
- percent: {
- type: Number,
- default: 0, // 当前进度百分比
- },
- size: {
- type: Number,
- default: 200, // 圆尺寸
- },
- lineWidth: {
- type: Number,
- default: 5, // 线宽
- },
- color: {
- type: [String, Array, Object],
- default: () => "#ff7b00", // 进度颜色 - 支持单色、渐变色数组或渐变配置对象
- },
- backgroundColor: {
- type: String,
- default: "#f2f2f2", // 背景圆颜色
- },
- angle: {
- type: Number,
- default: 360, // 显示的圆弧角度(360=全圆, 180=半圆, 120=三分之一圆)
- },
- // 渐变配置参数
- gradientConfig: {
- type: Object,
- default: () => ({
- type: 'linear', // 'linear' 或 'radial'
- colorStops: [], // 渐变色停止点,如 [{offset: 0, color: '#ff7b00'}, {offset: 1, color: '#ffaa00'}]
- angle: 0 // 线性渐变角度(度)
- })
- },
- },
- data() {
- return {
- ctx: null,
- };
- },
- mounted() {
- this.$nextTick(() => {
- this.initCanvas();
- })
- },
- watch: {
- percent() {
- this.drawCircle();
- },
- angle() {
- this.drawCircle();
- },
- },
- methods: {
- initCanvas() {
- const ctx = uni.createCanvasContext(this.canvasId, this);
- this.ctx = ctx;
- this.drawCircle();
- },
- drawCircle() {
- const { ctx, percent, size, lineWidth, color, backgroundColor, angle } = this;
- const radius = (size - lineWidth) / 2;
- const center = size / 2;
- ctx.clearRect(0, 0, size, size);
- // 计算起始角度和结束角度
- const startAngle = (Math.PI / 2) + (Math.PI * (180 - angle) / 360);
- const endAngle = (Math.PI * 2 + Math.PI / 2) - (Math.PI * (180 - angle) / 360);
- // 背景弧
- ctx.beginPath();
- ctx.arc(center, center, radius, startAngle, endAngle, false);
- ctx.setStrokeStyle(backgroundColor);
- ctx.setLineWidth(lineWidth);
- ctx.setLineCap("round");
- ctx.stroke();
- // 进度弧
- const progressAngle = startAngle + ((endAngle - startAngle) * percent / 100);
- ctx.beginPath();
- ctx.arc(center, center, radius, startAngle, progressAngle, false);
- // 根据 color 类型设置颜色
- if (typeof color === 'string') {
- // 单色
- ctx.setStrokeStyle(color);
- } else if (Array.isArray(color)) {
- // 渐变色数组
- if (color.length >= 2) {
- const gradient = this.createGradient(ctx, center, radius, startAngle, progressAngle, color);
- ctx.setStrokeStyle(gradient);
- } else {
- ctx.setStrokeStyle(color[0] || "#ff7b00");
- }
- } else if (typeof color === 'object' && color.colorStops && color.colorStops.length > 0) {
- // 渐变配置对象
- const gradient = this.createGradientFromConfig(ctx, center, radius, startAngle, progressAngle, color);
- ctx.setStrokeStyle(gradient);
- } else {
- ctx.setStrokeStyle("#ff7b00");
- }
- ctx.setLineCap("round");
- ctx.setLineWidth(lineWidth);
- ctx.stroke();
- ctx.draw();
- },
- // 创建基于颜色数组的渐变
- createGradient(ctx, center, radius, startAngle, progressAngle, colorArray) {
- // 使用中心点创建径向渐变,更适合圆形
- const gradient = ctx.createLinearGradient(
- center - radius * Math.cos(startAngle),
- center - radius * Math.sin(startAngle),
- center + radius * Math.cos(progressAngle),
- center + radius * Math.sin(progressAngle)
- );
- const step = 1 / (colorArray.length - 1);
- colorArray.forEach((color, index) => {
- gradient.addColorStop(Math.min(step * index, 1), color);
- });
- return gradient;
- },
- // 根据配置对象创建渐变
- createGradientFromConfig(ctx, center, radius, startAngle, endAngle, config) {
- let gradient;
- if (config.type === 'radial') {
- // 径向渐变
- gradient = ctx.createRadialGradient(
- center,
- center,
- 0,
- center,
- center,
- radius
- );
- } else {
- // 线性渐变 - 根据角度计算起点和终点
- const angleInRadians = (config.angle || 0) * Math.PI / 180;
- const halfRadius = radius * 0.7; // 调整半径以适配弧形
- const startX = center - halfRadius * Math.cos(angleInRadians);
- const startY = center - halfRadius * Math.sin(angleInRadians);
- const endX = center + halfRadius * Math.cos(angleInRadians);
- const endY = center + halfRadius * Math.sin(angleInRadians);
- gradient = ctx.createLinearGradient(startX, startY, endX, endY);
- }
- // 添加颜色停止点
- config.colorStops.forEach(stop => {
- gradient.addColorStop(stop.offset, stop.color);
- });
- return gradient;
- }
- },
- };
- </script>
- <style lang="scss" scoped>
- .circle-container {
- display: flex;
- flex-direction: column;
- align-items: center;
- justify-content: center;
- position: relative;
- }
- .circle-text {
- position: absolute;
- text-align: center;
- font-size: 18rpx;
- font-weight: bold;
- color: #333;
- top: 50rpx;
- .percent {
- font-weight: 800;
- font-size: 80rpx;
- color: #2B303A;
- .mini-text {
- font-weight: normal;
- font-size: 28rpx;
- }
- }
- .tips {
- font-weight: 800;
- font-size: 24rpx;
- .tips-text {
- color: #3EB6F8;
- }
- }
- }
- </style>
|