• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录

wkin

  • 博客园
  • 联系
  • 订阅
  • 管理

公告

View Post

扇形图比例封装

扇形图主要依靠CanvasRenderingContext2D的arc接口来实现。

封装:

// 扇形图子组件
@Component
export struct CustomPieChart {
  // 获取上下文
  private settings: RenderingContextSettings = new RenderingContextSettings(true)
  private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)

  // 饼图数据
  @Prop picChartElements: PicChartElement[] = [
    new PicChartElement('A', 10.00),
    new PicChartElement('B', 10.00),
    new PicChartElement('C', 10.00),
    new PicChartElement('D', 10.00),
    new PicChartElement('E', 10.00)
  ]

  // 圆半径
  @State circle_radius: number = 60
  // 单位
  @State unit: string = ""
  // 总资产
  @Prop money: string = ''

  // 颜色数组
  @Prop colors: string[] = [
    "#3c6ef5", "#76a0ff", "#79d4fe", "#926cfd", "#ae5dba",
    "#c67cd3", "#c43f5e", "#f4a994", "#fe6833", "#efd796"
  ]

  /**
   * 计算并绘制饼图
   */
  private drawPieChart(): void {
    // 计算总数
    let total = 0
    this.picChartElements.forEach((value) => {
      total += value.quantity
    })

    // 初始化弧线的起始弧度
    let startAngle = -0.5 * Math.PI

    // 为每个扇形计算角度和颜色
    this.picChartElements.forEach((value, index) => {
      const percent = value.quantity / total
      value.percent = percent
      value.beginAngle = startAngle
      value.endAngle = startAngle + (percent * 2 * Math.PI)
      value.color = this.colors[index % this.colors.length]

      // 更新起始角度为当前扇形的结束角度
      startAngle = value.endAngle
    })

    // 重置画布并绘制饼图
    this.context.reset()

    this.picChartElements.forEach((item) => {
      // 开始新的路径
      this.context.beginPath()

      // 移动到圆心
      this.context.moveTo(this.circle_radius, this.circle_radius)

      // 绘制扇形弧线
      this.context.arc(
        this.circle_radius,
        this.circle_radius,
        this.circle_radius,
        item.beginAngle,
        item.endAngle
      )

      // 闭合路径回到圆心
      this.context.closePath()

      // 设置填充颜色并填充
      this.context.fillStyle = item.color
      this.context.fill()
    })
  }

  aboutToAppear() {
    this.drawPieChart()
  }

  build() {
    Row({ space: 10 }) {
      // 饼图区域
      Stack() {
        Canvas(this.context)
          .height('100%')
          .width('100%')
          .onReady(() => {
            this.drawPieChart()
          })

        // 中心圆和总资产显示
        Stack() {
          Circle({ width: this.circle_radius * 2 - 15, height: this.circle_radius * 2 - 15 })
            .stroke('#FFFFFF')
            .fill('#FFFFFF')

          Text(this.money + '\n总资产')
            .textAlign(TextAlign.Center)
            .maxLines(-1)
            .width('100%')
            .height('100%')
        }
        .width(this.circle_radius * 2 - 15)
        .height(this.circle_radius * 2 - 15)
      }
      .width(this.circle_radius * 2)
      .height(this.circle_radius * 2)

      // 间距
      Blank()
        .layoutWeight(1)

      // 图例区域
      Column() {
        ForEach(this.picChartElements, (item: PicChartElement) => {
          Row({ space: 10 }) {
            // 颜色标识
            Divider()
              .vertical(true)
              .height(10)
              .strokeWidth(5)
              .color(item.color)

            // 文本和数值
            Row() {
              Text(item.element)
                .fontSize(12)
                .textAlign(TextAlign.Start)
                .layoutWeight(1)

              Text(item.quantity + this.unit)
                .fontSize(12)
                .textAlign(TextAlign.End)
            }
            .layoutWeight(1)
            .justifyContent(FlexAlign.SpaceBetween)
          }
          .width('100%')
          .height(30)
          .alignItems(VerticalAlign.Center)
        })
      }
      .width(130)
    }
    .width('100%')
    .padding({ left: 20, right: 20 })
  }
}

/**
 * 饼图元素数据类
 */
export class PicChartElement {
  element: Resource | string // 显示文本
  quantity: number // 数量
  percent: number = 0 // 百分比
  beginAngle: number = 0 // 弧线的起始弧度
  endAngle: number = 0 // 弧线的终止弧度
  color: string // 颜色

  constructor(element: Resource | string, quantity: number, color: string = '') {
    this.element = element
    this.quantity = quantity
    this.color = color
  }
}

使用:

@Entry
@Component
struct Page {
  @State message: string = 'Hello World';

  build() {
    Column() {
      CustomPieChart({
        picChartElements: [
          new PicChartElement('A', 10.00),
          new PicChartElement('B', 10.00),
          new PicChartElement('C', 10.00),
        ],
        money: '¥ 10,000.00',
        unit: '万',
        colors: [
          "#c67cd3", "#c43f5e", "#f4a994", "#fe6833", "#efd796"
        ],
      })

    }
    .width('100%')
    .height('100%')

  }
}

posted on 2025-10-09 15:27  带头大哥d小弟  阅读(5)  评论(0)    收藏  举报

刷新页面返回顶部
 
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3