ui的设计是这样的:
image.png
使用场景是在手机app里面加载某些模块时,显示加载进度。
思路比较简单直接见代码注释吧:

interface Params {
  /** canvas dom */
  dom: any,
  /** 颜色 */
  color: string,
  size?: number,
  callback?: Function
  /**表示进度的圆半径(比例) */
  opaqueRate?: number
  /** 挖空的圆半径(比例) */
  excavatedRate?: number
}

/**
 * 显示进度的饼图
 */
const appDownloadRate = (params: Params) => {
  const { dom, color, size, callback, opaqueRate = 0.35, excavatedRate = 0.40 } = params;
  const canvas = dom;

  const L = size || dom.offsetWidth;
  const l_moiety = L / 2;

  return {
    setRate(value: number) {
      canvas.width = L
      canvas.height = L
      const ctx = canvas.getContext("2d");
      ctx.fillStyle = color;
      // 设置坐标零点
      ctx.translate(l_moiety, l_moiety);
      // 先画一个剔除圆的矩形填充
      ctx.beginPath()
      ctx.arc(0, 0, L * excavatedRate, 90 * Math.PI / 180, 450 * Math.PI / 180);
      ctx.lineTo(0, l_moiety)
      ctx.lineTo(l_moiety, l_moiety)
      ctx.lineTo(l_moiety, -l_moiety)
      ctx.lineTo(-l_moiety, -l_moiety)
      ctx.lineTo(-l_moiety, l_moiety)
      ctx.lineTo(0, l_moiety)
      ctx.closePath()
      ctx.fill()

      // 再画一个饼图 表示进度(顺时针)
      ctx.beginPath()
      ctx.moveTo(0, 0);
      // 逆时针旋转90度
      ctx.rotate(-90 * Math.PI / 180)
      // 左右镜像
      ctx.scale(1, -1)
      ctx.arc(0, 0, L * opaqueRate, 0, ((100 - value) * 3.6) * Math.PI / 180);
      ctx.closePath()
      ctx.fill();

      if (value === 100) {
        this.done()
      }
    },

    done() {
      setTimeout(() => { canvas.style.display = 'none' }, 200)
      if (callback) callback()
    }
  }
}
<canvas id='appCanvas' style={{ width: '100%', borderRadius: '24%', overflow: 'hidden', zIndex: 9, position: 'absolute', top: 0, left: 0 }}></canvas>

显示效果:
image.png


电动风筝
1 声望0 粉丝