android 自定义半圆指针开关效果_css


UI 甩过来了这样的一张图,让我实现,作为一位面向Google百度编程的程序媛,立马打开了搜索引擎,找遍了都没有找到合适的插件。

怎么办呢?只能自己来了呀!首先我们简单来列一下这张图重要的几个点:

  • 实现圆环进度效果
  • 实现大指针(那根针一样的东西 哈哈哈)的进度指向效果
  • 实现圆环上的图标指针随着进度移动效果
  • 实现背景渐变

接下来我们就从这几个点逐步击破,实现效果,哈哈哈哈哈哈哈哈哈哈哈 开始吧!!!

实现圆环进度效果

这里我们可以用到css的锥形渐变,我们可以通过计算值所占的比例来计算进度,再用伪元素把中间部分盖掉,这样我们就得到了一个圆环啦。但是呢我们需要的是半圆环,所以可以用clip-path 来进行 矩形裁剪,只留上半部分。

android 自定义半圆指针开关效果_css3_02

android 自定义半圆指针开关效果_android 自定义半圆指针开关效果_03

android 自定义半圆指针开关效果_android 自定义半圆指针开关效果_04

<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;
       }
     }
   }
}

实现大指针

绘制指针

指针就相当于一个半圆和三角形拼起来

android 自定义半圆指针开关效果_android 自定义半圆指针开关效果_05

android 自定义半圆指针开关效果_css3_06

计算指针旋转角

大圆环的直径是300,小圆环(假设有圆)把指针也看做一个圆,指针的长度就是圆的半径,圆心为针头,直径是160。小圆环可旋转的范围大概是黄色位置到绿色位置。

android 自定义半圆指针开关效果_css_07


大圆和小圆的相对位置如下图所示:

android 自定义半圆指针开关效果_android 自定义半圆指针开关效果_08

如何计算绿色指针指向大圆的180°时候,小圆大概是多少度,也就是计算小圆环可旋转的范围是多少度。所以我们要计算 ∠EAC 只要计算 ∠BAC 就行啦。

已知 边长BC是【大圆半径】:150,边长AB是【大圆半径 减 向上偏移量(加上指针宽度指针宽度14)】:64。

根据正切定理:

android 自定义半圆指针开关效果_android 自定义半圆指针开关效果_09


tan∠BAC = BC / AB = 150 / 64 ≈ 2.3;哈哈哈哈哈然后又开始面向百度编程了。

android 自定义半圆指针开关效果_Math_10


所以我们就知道了∠BAC 是67°,即是 ∠EAC 是23°。那么小圆环可旋转的范围:-23° ~ 203°,总共 226°。

android 自定义半圆指针开关效果_android 自定义半圆指针开关效果_11

android 自定义半圆指针开关效果_Math_12

android 自定义半圆指针开关效果_css_13

<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%);
   }
 }

实现圆环上的图标

android 自定义半圆指针开关效果_javascript_14


图标是根据进度进行移动的,并且进行了相应的角度旋转。

以下偏移都以扇形0°位置作为参照,我们把图标的位置分成五种情况:

1. 在扇形最左侧

android 自定义半圆指针开关效果_Math_15

宽度:0
高度:0

2. 在扇形最左侧到中间

android 自定义半圆指针开关效果_css_16

android 自定义半圆指针开关效果_css_17

已知 边长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. 在扇形最中间

android 自定义半圆指针开关效果_css_18

宽度:大圆半径
高度:大圆半径

4. 在扇形中间到最右侧

android 自定义半圆指针开关效果_javascript_19


android 自定义半圆指针开关效果_javascript_20


已知 边长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. 在扇形最右侧

android 自定义半圆指针开关效果_android 自定义半圆指针开关效果_21

宽度:大圆半径 * 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';
}

这个可以用伪元素

android 自定义半圆指针开关效果_android 自定义半圆指针开关效果_22

.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;
  }
}

实现背景渐变

走到了这一步差不多已经做完啦!!!长吐了一口气…嘿嘿嘿

画一个带渐变色的圆形层级放最上面。

android 自定义半圆指针开关效果_Math_23

<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%);
  }
}

android 自定义半圆指针开关效果_css_24