# 圆环百分比三种实现方式汇总

# 前言

如下图所示,圆环百分比的效果在平常业务中还是有时候需要用到的(比如抢优惠券),借此总结一个几种实现圆环百分比做法

1559222101896

# 实现方式

# 1. canvas实现

  • html部分代码
<canvas id="circle" height="132px" width="132px">
</canvas>
  • js部分代码
// 1.canvas实现
  circle()
  function circle() {
      var canvas = document.getElementById('circle');
      var ctx = canvas.getContext("2d");

      /*填充文字*/

      ctx.font = "12px Microsoft YaHei";
      /*文字颜色*/
      ctx.fillStyle = '#FF4437';
      /*文字内容*/
      var insertContent = '已抢';
      var text = ctx.measureText(insertContent);
      /*插入文字,后面两个参数为文字的位置*/
      /*此处注意:text.width获得文字的宽度,然后就能计算出文字居中需要的x值*/
      ctx.fillText(insertContent, (132 - text.width) / 2, 68);

      /*填充百分比*/
      var ratioStr = percent + '%';
      var text = ctx.measureText(ratioStr);
      ctx.fillText(ratioStr, (132 - text.width) / 2, 85);

      /*开始圆环*/
      var circleObj = {
          ctx: ctx,
          /*圆心*/
          x: 66,
          y: 66,
          /*半径*/
          radius: 55,
          /*环的宽度*/
          lineWidth: 10
      }
      /*有色的圆环*/
      /*从-90度的地方开始画*/
      circleObj.startAngle = - Math.PI * 2 * 90 / 360;
      /*从当前度数减去-90度*/
      circleObj.endAngle = Math.PI * 2 * (percent / 100 - 0.25);
      circleObj.color = '#FF4437';
      drawCircle(circleObj);
      /*灰色的圆环*/
      /*开始的度数-从上一个结束的位置开始*/
      circleObj.startAngle = circleObj.endAngle;
      /*结束的度数*/
      circleObj.endAngle = Math.PI * 2;
      circleObj.color = '#ff453833';
      drawCircle(circleObj);

  }
  /*画曲线*/
  function drawCircle(circleObj) {
      var ctx = circleObj.ctx;
      ctx.beginPath();
      ctx.arc(circleObj.x, circleObj.y, circleObj.radius, circleObj.startAngle, circleObj.endAngle, false);
      //设定曲线粗细度
      ctx.lineWidth = circleObj.lineWidth;
      //给曲线着色
      ctx.strokeStyle = circleObj.color;
      //连接处样式
      ctx.lineCap = 'round';
      //给环着色
      ctx.stroke();
      ctx.closePath();
  }

# 2.svg实现

  • HTML部分代码
<div class="circle-wrapper">
      <svg xmlns="http://www.w3.org/200/svg" height="100%" width="100%">
          <circle class="circle-full" cx="66" cy="66" r="55" fill="none" stroke="#FF4437" stroke-width="10" stroke-linecap="round"></circle>
          <circle class="circle-detail" cx="66" cy="66" r="55" fill="none" stroke-width="10" stroke-linecap="round" stroke="#FF4437" stroke-dasharray="0,10000"></circle>
      </svg>
      <p class="coupon-num had-percent">
        已抢
        <span class="percent">45%</span>
      </p>
  </div>
  • css部分代码
.circle-wrapper {
      display: inline-block;
      position: relative;
      width: 132px;
      height: 132px;
      margin-bottom: 8px;
}
 .circle-wrapper .coupon-num {
    width: 36px;
    position: absolute;
    top: 50%;
    left: 50%;
    margin-left: -18px;
    color: #FF4437;
    font-size: 12px;
    margin-top: -15px;
   }
   .circle-full {
    opacity: .2;
   }
   .circle-detail {
    -webkit-transform-origin: 66px 66px;
    transform-origin: 66px 66px;
    -webkit-transform: rotate(-90deg);
    transform: rotate(-90deg);
    stroke: #FF4437;
  }
  • js部分代码
  //2.svg实现
  var cricleEl = document.querySelector('.circle-detail')
  var percentEl = document.querySelector('.percent')
  var circleLength = Math.floor(2 * Math.PI * 55);
  rotateCircle(cricleEl,percent)
  percentEl.innerHTML =percent + '%'
  function rotateCircle (el,percent) {
    var val = parseFloat(percent).toFixed(0);
    val = Math.max(0,val);
    val = Math.min(100,val);
    el.setAttribute("stroke-dasharray","" + circleLength * val / 100 + ",10000");
  }

# 3.css-clip实现

  • html部分代码
<div class="box">
    <div class="clip">
        <div class="left"></div>
        <div class="right width-none"></div>
    </div>
    <div class="num">
    </div>
</div>
  • css部分代码
 .box{
      display: inline-block;
      width: 132px;
      height: 132px;
      position: relative;
      background-color: #ffdad7;
      border-radius: 50%;
  }
  .num{
      position: absolute;
      top: 50%;
      left: 50%;
      background: #fff;
      border-radius: 50%;
      width: 112px; 
      height: 112px;
      transform: translate(-50%, -50%);
      text-align: center;
      line-height: 112px;
      font-size: 12px;
  }
  .clip{
      width: 132px;
      height: 132px;
      position: absolute;
      border: 10px solid #ffdad7;
      border-radius: 50%;
      clip: rect(0, 132px, 132px, 66px);
  }
  .left{
      width: 132px;
      height: 132px;
      position: absolute;
      border: 10px solid #FF4437;
      border-radius: 50%;
      clip: rect(0 66px 132px 0);
      top: -10px;
      left: -10px;
  }
  .right{
      width: 132px;
      height: 132px;
      position: absolute;
      border: 10px solid #FF4437;
      border-radius: 50%;
      clip: rect(0 132px 132px 66px);
      top: -10px;
      left: -10px;
  }
  .width-none{
      width: 0;
  }
  .auto{
      clip: auto;
  }
  • js部分代码

// 3.css-clip实现方式
  let clip = document.querySelector('.clip'),
  left = document.querySelector('.left'),
  right = document.querySelector('.right'),
  num = document.querySelector('.num');
// 
  let loop = setTimeout(() => {
      if(percent >= 100){
          percent = 0;
          right.classList.add('width-none');
          clip.classList.remove('auto');
      } else if(percent > 50){
          right.classList.remove('width-none');
          clip.classList.add('auto');
      }
      // rotate++;
      left.style.transform = 'rotate('+ 3.6*percent + 'deg)';
      num.innerHTML = `${percent}%`
  },100)
  

# 小结

结合兼容性,代码简洁性,三种方式各有优势。结合兼容性,我青睐使用svg实现

原文地址 (opens new window)

不如自己动手试试

See the Pen 圆环百分比的实现(三种方法比较) by lumoumou (@jackluson) on CodePen.


# REFERENCE