UI 甩过来了这样的一张图,让我实现,作为一位面向Google百度编程的程序媛,立马打开了搜索引擎,找遍了都没有找到合适的插件。
怎么办呢?只能自己来了呀!首先我们简单来列一下这张图重要的几个点:
- 实现圆环进度效果
- 实现大指针(那根针一样的东西 哈哈哈)的进度指向效果
- 实现圆环上的图标指针随着进度移动效果
- 实现背景渐变
接下来我们就从这几个点逐步击破,实现效果,哈哈哈哈哈哈哈哈哈哈哈 开始吧!!!
实现圆环进度效果
这里我们可以用到css的锥形渐变,我们可以通过计算值所占的比例来计算进度,再用伪元素把中间部分盖掉,这样我们就得到了一个圆环啦。但是呢我们需要的是半圆环,所以可以用clip-path 来进行 矩形裁剪,只留上半部分。
<div class="dashboard_content">
<div class="box">
<span class="progressBar"></span>
</div>
</div>
.dashboard_content {
position: relative;
z-index: 2;
width: 300px;
height: 300px;
margin-top: 10px;
.box {
position: absolute;
width: 300px;
height: 300px;
// 矩形裁剪
clip-path: inset(0% 0% 50% 0%);
.progressBar {
--gauge-percentage: calc(90 / 200 * 100%);
--gauge-circle-color: #60e8fc;
--gauge-circle-color-lighter: #072d5b;
display: flex;
justify-content: center;
align-items: center;
width: 300px;
height: 300px;
color: #000;
transform: rotate(-90deg);
background: conic-gradient(
var(--gauge-circle-color) var(--gauge-percentage),
var(--gauge-circle-color-lighter) 0
);
transition: all 0.5s cubic-bezier(0.14, 1.24, 0.96, 0.77);
border-radius: 50%;
&::before {
content: '';
position: absolute;
display: flex;
justify-content: center;
align-items: center;
width: calc(100% - 16px);
height: calc(100% - 16px);
background: #072d5b;
border-radius: inherit;
}
}
}
}
实现大指针
绘制指针
指针就相当于一个半圆和三角形拼起来
计算指针旋转角
大圆环的直径是300,小圆环(假设有圆)把指针也看做一个圆,指针的长度就是圆的半径,圆心为针头,直径是160。小圆环可旋转的范围大概是黄色位置到绿色位置。
大圆和小圆的相对位置如下图所示:
如何计算绿色指针指向大圆的180°时候,小圆大概是多少度,也就是计算小圆环可旋转的范围是多少度。所以我们要计算 ∠EAC 只要计算 ∠BAC 就行啦。
已知 边长BC是【大圆半径】:150,边长AB是【大圆半径 减 向上偏移量(加上指针宽度指针宽度14)】:64。
根据正切定理:
tan∠BAC = BC / AB = 150 / 64 ≈ 2.3;哈哈哈哈哈然后又开始面向百度编程了。
所以我们就知道了∠BAC 是67°,即是 ∠EAC 是23°。那么小圆环可旋转的范围:-23° ~ 203°,总共 226°。
<div class="dashboard_content">
<div class="conic_pointer">
<div class="conic_pointer_circle"></div>
<div class="conic_pointer_rect"></div>
</div>
<div class="box">
<span class="progressBar"></span>
</div>
</div>
.conic_pointer {
position: absolute;
width: 160px;
height: 14px;
background: red;
z-index: 2;
margin-left: calc((300px - 160px) / 2);
margin-top: calc(120px - 20px);
transform: rotate((0.9 * 226deg) - 23deg);
&_circle {
left: calc(50% - 7px);
position: absolute;
width: 14px;
height: 14px;
background: #fff;
border-radius: 50%;
}
&_rect {
position: absolute;
left: 0;
width: 80px;
height: 14px;
background-color: #fff;
clip-path: polygon(100% 0px, 100% 100%, 0px 50%);
}
}
实现圆环上的图标
图标是根据进度进行移动的,并且进行了相应的角度旋转。
以下偏移都以扇形0°位置作为参照,我们把图标的位置分成五种情况:
1. 在扇形最左侧
宽度:0
高度:0
2. 在扇形最左侧到中间
已知 边长b 为150,根据三角函数 sin(∠C) = c / b;cos(∠C) = a / b;180° 等于 π,夹角 = 夹角比 * π。
我们假设总占比为1,进度占比为0.7。
// 指针占比
let a = 0.7;
// 扇形占比
let b = 1;
// 与底边的夹角比
let angle = a;
宽度:扇形半径 - Math.cos(Math.PI * 夹角比) * 扇形半径
高度:Math.sin(Math.PI * 夹角比) * 扇形半径
3. 在扇形最中间
宽度:大圆半径
高度:大圆半径
4. 在扇形中间到最右侧
已知 边长b 为150,根据三角函数 sin(∠C) = c / b;cos(∠C) = a / b;180° 等于 π,夹角 = 夹角比 * π。
我们假设总占比为1,进度占比为0.7。
// 指针占比
let a = 0.7;
// 扇形占比
let b = 1;
// 与底边的夹角比
let angle = b - a;
宽度:Math.cos(Math.PI * 夹角比) * 扇形半径 + 扇形半径
高度:Math.sin(Math.PI * 夹角比) * 扇形半径
5. 在扇形最右侧
宽度:大圆半径 * 2
高度:0
下面是具体的计算方法,拿参数存是为了在css中使用变量
// 小指针偏移
let testW = ref<any>();
let testH = ref<any>();
// 小指针旋转角
let ringRotate = ref<any>();
// 大指针旋转角
let pointerRotate = ref<any>();
let ringPercentage = ref<any>();
// 左侧颜色
let ringLeftColor = ref<any>();
// 右侧颜色
let ringRightColor = ref<any>();
/**
*
* @param r 占比
*/
function calculationPosition(percent = 0) {
// 指针占比
let a = percent;
// 扇形占比
let b = 1;
// 小指针的总旋转角是180°
ringRotate.value = a * 180 + 'deg';
// 大指针的总旋转角是226°
pointerRotate.value = (a * 226 - 23).toFixed(2) + 'deg';
ringPercentage.value = (a / 2) * 100 + '%';
ringLeftColor.value = a > 0 ? '#60e8fc' : '#072d5b';
ringRightColor.value = a == b ? '#60e8fc' : '#072d5b';
// 与底边的夹角比
let sectorRatio;
// 扇形半径
let sectorRadius = 150;
// 横向偏移
let lateralOffset = -11;
// 在扇形左侧
if (a < b / 2) {
sectorRatio = a;
testH.value = (Math.sin(Math.PI * sectorRatio) * Number(sectorRadius))?.toFixed(2) || 0;
testW.value =
(
Number(sectorRadius) -
Math.cos(Math.PI * sectorRatio) * Number(sectorRadius)
)?.toFixed(2) || 0;
}
// 在扇形右侧
else if (a > b / 2) {
sectorRatio = b - a;
lateralOffset = -19;
testH.value = (Math.sin(Math.PI * sectorRatio) * Number(sectorRadius))?.toFixed(2) || 0;
testW.value =
(
Math.cos(Math.PI * sectorRatio) * Number(sectorRadius) +
Number(sectorRadius)
)?.toFixed(2) || 0;
}
// 扇形最左边
if (a == 0) {
testH.value = 0;
testW.value = 0;
} else if (a == b) {
lateralOffset = -19;
testH.value = 0;
testW.value = Number(sectorRadius) * 2;
} else if (a == b / 2) {
testH.value = Number(sectorRadius);
testW.value = Number(sectorRadius);
}
testH.value =
floatObj.add(-15, floatObj.subtract(Number(sectorRadius), testH.value)) + 'px';
testW.value = floatObj.add(Number(lateralOffset), testW.value) + 'px';
}
这个可以用伪元素
.dashboard_content {
&::before {
content: '';
position: absolute;
top: 149px;
width: 8px;
height: 8px;
//background: #60e8fc;
background: v-bind(ringLeftColor);
clip-path: circle(50% at 50% 0%);
border-radius: inherit;
z-index: 3;
}
&::after {
content: '';
position: absolute;
top: 149px;
left: 292px;
width: 8px;
height: 8px;
//background: #60e8fc;
background: v-bind(ringRightColor);
clip-path: circle(50% at 50% 0%);
border-radius: inherit;
z-index: 3;
}
}
实现背景渐变
走到了这一步差不多已经做完啦!!!长吐了一口气…嘿嘿嘿
画一个带渐变色的圆形层级放最上面。
<div class="box_bg"> </div>
.box_bg {
position: absolute;
width: calc(300px - 16px);
height: calc(300px - 16px);
top: 8px;
left: 8px;
&::before {
content: '';
position: absolute;
display: flex;
justify-content: center;
align-items: center;
width: 100%;
height: 100%;
background: #00061c;
border-radius: 50%;
}
&::after {
content: '';
position: absolute;
display: block;
width: 100%;
height: 100%;
border-radius: 50%;
background: linear-gradient(180deg, #072d5b 0%, transparent 60%);
}
}