react中使用canvas画一个半圆弧进度条

效果:

圆弧进度条最终效果

代码:

import React, { useEffect, useRef } from 'react';
interface Props {
  /** 设置进度 0 ~ 1 */
  progress: number;
  /** 设置 标签ID  */
  sid: number;
}
/** 圆弧半径 */
const radius = 110;
const width = radius * 2;
export default function ArcProgressBar({ progress, sid }: Props) {
  /** 定义一个对象 保存上下文和中心点 */
  const ref = useRef<{
    ctx?: CanvasRenderingContext2D | null;
    center: number;
  }>({
    center: 0,
  });
  /** 每次进度有更新时进行重绘 */
  useEffect(() => {
    init();
  }, [progress]); //eslint-disable-line

  function init() {
    /** 重绘之前先找到标签 */
    let el: HTMLElement | null = document.getElementById('aceProgress' + sid);
    if (!el) return;
    draw(el);
  }

  function draw(el: HTMLElement) {
    // 清除标签内的所有内容
    el.replaceChildren();
    // 创建画板
    let canvas = document.createElement('canvas');
    // 把画板添加到标签内
    el.appendChild(canvas);
    // 保存上下文
    ref.current.ctx = canvas.getContext('2d');
    // 设置组件的宽高  rpx() 方法用于手机端的自适应 见代码最底部
    el.style.width = `${rpx(width)}px`;
    el.style.height = `${rpx(radius)}px`;
    canvas.style.width = `${rpx(width)}px`;
    canvas.style.height = `${rpx(radius)}px`;
    canvas.width = rpx(width);
    canvas.height = rpx(radius);
    // 设置中心点
    ref.current.center = rpx(radius);
    // 因为想要从3点钟方向逆时针画线,所以下面对画板进行翻转和移动
    // 对画板进行垂直翻转 弧线的绘制默认是从钟表的3点钟位置顺时针画线
    ref.current.ctx!.scale(1, -1);
    // 移动画板的起始点到负的高度,因为我们要逆时针往上画
    ref.current.ctx!.translate(0, -width);
    // 画背景的细弧线
    drawBg();
    // 画进度的粗弧线
    drawProgress();
  }
  function drawBg() {
    let ctx = ref.current.ctx!;

    // 开始画笔路径
    ctx.beginPath();
    // 设置线条宽度
    ctx.lineWidth = rpx(8);
    // 设置线条终端形状
    ctx.lineCap = 'round';
    // 设置线条样式
    ctx.strokeStyle = 'rgba(255,255,255,0.3)';
    // 开始弧度
    const _start = 0;
    // 结束弧度 弧度和角度是有区别的 注意区分
    const _end = (Math.PI / 180) * 180;
    ctx.arc(
      ref.current.center, // 坐标 X
      ref.current.center + rpx(10) * 2, // 坐标Y  rpx(10) * 2 是把位置稍微扩展一点
      ref.current.center - rpx(10) * 2, // 半径
      _start, // 开始弧度
      _end, // 结束弧度
      false // false=>顺时针 true=>逆时针
    );
    // 开始画线
    ctx.stroke();
    // 关闭画笔路径
    ctx.closePath();
  }
  function drawProgress() {
    // 没有进度就不画粗线条了
    if (!progress) return;
    let ctx = ref.current.ctx!;
    ctx.beginPath();
    ctx.lineWidth = rpx(15);
    ctx.lineCap = 'round';
    ctx.strokeStyle = 'rgba(255,255,255)';
    const _start = 0;
    const _end = (Math.PI / 180) * (180 * progress);
    ctx.arc(
      ref.current.center,
      ref.current.center + rpx(10) * 2,
      ref.current.center - rpx(10) * 2,
      _start,
      _end,
      false
    );
    ctx.stroke();
    ctx.closePath();
  }

  return <div id={'aceProgress' + sid} className="cricle-progress"></div>;
}

function rpx(t: number) {
  return (t / 375) * window.innerWidth;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值