实际效果:
代码实现:
HTML部分:
xml
<svg width="500" height="500" viewBox="0 0 100 100">
<!-- 各参数详解 -->
<!-- stroke:圆环(轮廓)填充色 -->
<!-- stroke-width: 圆环(圆的轮廓)的宽度 -->
<!-- stroke-dasharray: 设置轮廓的间隙,会按照轮廓颜色-空白-轮廓颜色-空白...这样的规律去无限渲染 -->
<!-- r:圆环的半径,该半径的计算为两个圆的中心点。例如:圆环的宽度为10 组成圆环的两个圆半径分别为10,20,则r应该设为15 -->
<!-- fill:圆的内部填充色,我们想实现圆环效果,就需要设置其为transparent让其显示背景色,这样圆只显示轮廓,即圆环 -->
<!-- cx,cy:圆心点的坐标 -->
<!-- transform:平移、旋转、缩放圆环 -->
<!-- 最下层的圆 蓝色区域 -->
<circle
id="circle1"
cx="50"
cy="50"
r="31"
stroke="blue"
stroke-width="5"
fill="transparent"
stroke-dasharray="100,0"
transform="rotate(-94 50 50)"
/>
<!-- 中间的圆 灰色区域 -->
<circle
id="circle2"
cx="50"
cy="50"
r="31"
stroke="gray"
stroke-width="5"
fill="transparent"
stroke-dasharray="0,100"
transform="rotate(-94 50 50)"
/>
<!-- 顶部圆环 设置间隙 颜色设为白色(背景色) -->
<!-- stroke-width属性设置的比前两个圆稍微大一些,否则圆的轮廓会出现两条圆环的线 -->
<circle
id="circle3"
cx="50"
cy="50"
r="31"
stroke="white"
stroke-width="6"
fill="transparent"
stroke-dasharray="0,100"
transform="rotate(-94 50 50)"
/>
</svg>
JS部分
typescript
// 在线数量
onlineCount = 3;
// 离线数量
offlineCount = 4;
typescript
const circle1 = document.getElementById('circle1');
const circle2 = document.getElementById('circle2');
const circle3 = document.getElementById('circle3');
circle1?.setAttribute('stroke-dasharray', this.getCircle(1));
circle2?.setAttribute('stroke-dasharray', this.getCircle(2));
circle3?.setAttribute('stroke-dasharray', this.getCircle(3));
typescript
// 此函数主要为计算三个圆环的占比
// 需要先计算出圆环的周长,再根据周长分配各部分的长度,例如:此处三个圆环半径为31,则周长为31*3.14*2=194.68,约等于195
// 第一个圆环渲染蓝色区域,计算出蓝色区域与空白区域
// 第二个圆环渲染灰色区域,由于渲染的起始位置相同,所以计算时先渲染一段0长度的实际区域,再渲染一段蓝色区域长度的空白区域,显示第一个圆环的蓝色区域,然后再渲染灰色区域
// 第三个圆环则添加圆环中的间隙(此函数设置为2,可根据实际需求更改)
getCircle(index: any) {
switch (index) {
case 1:
if (this.onlineCount === 0) {
if (this.offlineCount === 0) {
return '195,0';
} else {
return '0,195';
}
} else if (this.offlineCount === 0) {
return `195,0`;
} else {
const length =
(195 / (this.onlineCount + this.offlineCount)) * this.onlineCount;
return `${length},${195 - length}`;
}
case 2:
if (this.onlineCount === 0) {
if (this.offlineCount === 0) {
return '0,195';
} else {
return '195,0';
}
} else if (this.offlineCount === 0) {
return '0,195';
} else {
const length =
(195 / (this.onlineCount + this.offlineCount)) * this.offlineCount;
// 先绘制0长度的实际灰色区域,再绘制空白区域(用于显示第一个圆环的蓝色),再绘制灰色区域
return `0,${195 - length},${length}`;
}
case 3:
if (this.onlineCount === 0) {
if (this.offlineCount === 0) {
return '0,195';
} else {
const length = 195 / this.offlineCount - 2;
return `2,${length}`;
}
} else if (this.offlineCount === 0) {
const length = 195 / this.onlineCount - 2;
return `2,${length}`;
} else {
const length = 195 / (this.onlineCount + this.offlineCount) - 2;
return `2,${length}`;
}
default:
return '';
}
}