实现的效果如图所示:

 1、使用canvas实现

 canvas写的比较简单,就是两个圆环叠加。

import React, { useEffect } from 'react';

// 将canvas变量定义在组件外,否则组件更新,会将ctx重置,后面执行方法会报错
let ctx = null;
export default function index(props) {
  const { percent } = props;
  let id = `circle-${Math.random()}`;   //每次使用组件都会赋不同的id

  useEffect(() => {
    initCanvas();
    draw();
  }, []);

  useEffect(() => {
    draw();
  }, [percent]);

  // 初始化canvas
  const initCanvas = () => {
    let canvas = document.getElementById(id);
    if (canvas.getContext) {
      ctx = canvas.getContext('2d');
    }
  };
  const draw = () => {
    // 每次画图之前先清除画布
    ctx.clearRect(0, 0, 570, 570);
    ctx.beginPath();
    // 背景圆圈,ctx.arc(圆心x座标,圆心y座标,半径,开始的角度,结束的角度,顺/逆时针)
    ctx.arc(570 / 2, 570 / 2, 570 / 2 - 30, 0, 360);
    ctx.strokeStyle = 'rgba(158, 215, 255, 0.2)';
    ctx.lineWidth = 30;
    ctx.stroke();
    ctx.save();
    ctx.beginPath();
    // 为了后面的角度方便计算,将画布旋转,使0度在12点方向
    ctx.translate(570 / 2, 570 / 2);
    ctx.rotate(-Math.PI / 2);
    ctx.arc(0, 0, 570 / 2 - 30, 0, percent * 2 * Math.PI, false);
    ctx.strokeStyle = '#00FFC2';
    ctx.stroke();
    ctx.restore();
    // 中间显示的文字部分
    ctx.beginPath();
    ctx.fillStyle = '#9ED7FF';
    ctx.font = '80px Source Han Sans CN';
    // 百分号
    ctx.fillText(`%`, 570 / 2 + 150, 570 / 2 + 70);
    ctx.fillStyle = '#FFF';
    // 百分比值
    ctx.font = '140px Geograph Test';
    ctx.fillText(
      `${(percent * 100)?.toFixed(2)}`,
      570 / 2 - 220,
      570 / 2 + 70,
    );

  };

  return (
    <canvas id={id} width={570} height={570}></canvas>
  );
}

2、css实现

 html与css实现的原理是将整体分为右半圆与左半圆,右半圆显示颜色,当百分比>0.5时,将左半圆的颜色设置为与右侧相同,旋转一定角度,弥补>0.5的部分;当百分比<0.5时,将左半圆的颜色设置为与背景色相同,旋转一定角度,遮住<0.5的部分。

 html部分

import React from "react";
import styles from "./index.less";

export default function index(props) {
  const { name, value, percent, index, unit, clickCard } = props;
  return (
    <div className={styles["circle-content"]}>
      //右半圆
      <div className={styles["right-arch"]}></div>
      //左半圆
      <div
        className={styles["left-arch"]}
        style={
          percent >= 0.5
            ? { borderColor: "#5178FF", transform: `rotate(-${360 - 360 * percent}deg)` }
            : { borderColor: "#DCE4FF", transform: `rotate(-${360 * (0.5 - percent)}deg)` }
        }
      ></div>
      // 最上层圆,将以上两个半圆遮住一部分,达到看起来是圆弧的目的
      <div className={styles["center"]}>
        <div>{(percent * 100).toFixed(2)}%</div>
      </div>
    </div>   
  );
}

css部分

  .circle-content {
    position: relative;
    width: 120px;
    height: 120px;
    border-radius: 120px;
    background: #dce4ff;
    .right-arch {
      position: absolute;
      left: 60px;
      width: 60px;
      height: 120px;
      border-left: 0;
      border-radius: 0 60px 60px 0;
      border: 20px solid #5178ff;
    }
    .left-arch {
      position: absolute;
      width: 60px;
      height: 120px;
      border: 20px solid;
      border-right: 0;
      border-radius: 60px 0 0 60px;
      transform-origin: right center;
      transform: rotate(0deg);
    }
    .center {
      position: absolute;
      top: 10px;
      left: 10px;
      width: 100px;
      height: 100px;
      padding-top: 23px;
      border-radius: 100px;
      background: #fff;
      text-align: center;
      div {
        &:nth-of-type(1) {
          .mixins-font(Microsoft YaHei; 24px; #1b9869; 700);
        }
      }
    }
  }

Logo

技术共进,成长同行——讯飞AI开发者社区

更多推荐