画一个圆形进度条 - Canvas

大致思路

不断绘制半圆弧(因为要形成间隔式透明线条效果),绘制两层,一层用作背景,一层用作进度条展示

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
<script setup>
import { onMounted, ref, onUpdated } from 'vue'

const props = defineProps({
value: {
type: Number,
default: 0.3
},
color: {
type: String,
default: '#46ebb7'
// default: '#ffe699'
},
width: {
type: Number,
default: 200
},
height: {
type: Number,
default: 200
}
})

const canvasRef = ref(null)

const draw = () => {
const canvas = canvasRef.value
const context = canvas.getContext('2d')
const x = 0
const y = 0
const lineWidth = 20
const radius = Math.min(canvas.width / 2, canvas.height / 2) - lineWidth / 2
const segmentCount = 12 // 分割线数量
const segmentAngle = (2 * Math.PI) / segmentCount // 每个分割线的角度
const offsetAngle = Math.PI / 7 // 每个圆环偏移较多
const halfWidth = canvas.width / 2
const halfHeight = canvas.height / 2

context.clearRect(0, 0, canvas.width, canvas.height)

// 偏移画布起点到中心
context.translate(halfWidth, halfHeight)
context.rotate((-90 * Math.PI) / 180)

// 绘制分割线
for (let i = 0; i < segmentCount; i++) {
const angle = i * segmentAngle
const angleEnd = angle + offsetAngle

// 绘制底部圆环
context.beginPath()
context.arc(x, y, radius, angle, angleEnd)
context.lineWidth = lineWidth
context.strokeStyle = 'rgba(55,76,121,0.5)'
context.stroke()

// 绘制进度圆环
const maxAngle = Math.PI * 2 * props.value
if (angle <= maxAngle) {
context.beginPath()
context.arc(x, y, radius, angle, Math.min(angleEnd, maxAngle))
context.lineWidth = lineWidth
context.strokeStyle = props.color
context.stroke()
}
}

// 绘制中间文本
context.rotate((90 * Math.PI) / 180)
context.font = 'bold 32px serif'
context.textAlign = 'center'
context.textBaseline = 'middle'
context.fillStyle = props.color
context.fillText('92%', 0, 0)
}

onMounted(() => {
draw()
})

onUpdated(() => {
draw()
})
</script>

<template>
<div class="circle-process-container">
<canvas :width="width" :height="height" ref="canvasRef"></canvas>
<div class="bottom-bg"></div>
</div>
</template>

<style>
.circle-process-container {
display: inline-block;
}
.bottom-bg {
height: 200px;
background: url('./bottom-bg.png');
background-size: cover;
background-position: center;
background-repeat: no-repeat;
height: 48px;
}
canvas {
border: solid 4px v-bind(color);
border-radius: 50%;
padding: 8px;
box-shadow: v-bind(color) 0px 0px 26px;
width: v-bind(width);
height: v-bind(height);
margin: 0 auto;
display: block;
}
</style>

画一个圆形进度条 - Canvas
https://wanmeishijie.xyz/notes/canvas/画一个圆形进度条/
作者
发布于
2023年9月4日
许可协议