9afce6f6创建于 2025年5月7日历史提交
/*
 * Copyright (c) 2024 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import {
  BarChart, // 柱状图图表类
  BarChartModel, // 柱状图配置构建类
  BarData, // 柱状图数据包
  BarDataSet, // 柱状图数据集合
  BarEntry, // 柱状图数据结构
  Description, // 图表Description(描述)部件
  IAxisValueFormatter, // 图表高亮数据
  IBarDataSet, // 柱状图数据集合的操作类
  JArrayList, // 工具类:数据集合
  Legend, // 图表Legend(图例)部件
  LimitLabelPosition, // 图表的LimitLine标签位置枚举类
  LimitLine, // 图表LimitLine
  XAxis, // 图表X轴部件
  XAxisPosition, // 图表X轴标签位置枚举类
  YAxis, // 图表Y轴部件
  ChartColor as Colors
} from '@ohos/mpchart';

const GRID_BG_COLOR: string = '#FFFBF9EC';
const STEP_TARGET: string = '目标 250';
const STEP_TARGET_NUMBER: number = 250;
const CALORIE: string = '卡路里';
const VISIBLE_VALUE_COUNT: number = 7;
const LINE_WIDTH: number = 2;
const DASHED_LINE_LENGTH: number = 20;
const DASHED_SPACE_LENGTH: number = 3;
const TEXT_SIZE: number = 16;
const ZERO: number = 0;
const LABEL_COUNT: number = 7;
const BAR_WIDTH: number = 0.3;

/**
 * 场景描述:当前组件为柱状图组件 BarChartModel。
 * 构造新的对象模型后通过模型的方法设置属性。
 * 具体实现见aboutToAppear内注释。
 */
@Component
export struct BarCharts {
  @Prop calorieData: Array<number | null> = [233, 285, 458, 268, 237, 278, 407]; // 卡路里数据
  model: BarChartModel | null = null; // 柱状图模型
  private leftAxis: YAxis | null = null; // 左侧Y轴数据
  private rightAxis: YAxis | null = null; // 右侧Y轴数据
  private xAxis: XAxis | null = null; // X轴数据
  data: BarData | null = null; // 柱状图数据
  limitLine: LimitLine | null = null; // 限制线类型

  // 图表数据初始化
  aboutToAppear() {
    // TODO 知识点:必须初始化图表配置构建类
    this.model = new BarChartModel();
    this.model.setPinchZoom(false);
    // TODO 知识点:配置图表指定样式,各部件间没有先后之分
    // 获取图表描述部件,设置图表描述部件不可用,即图表不进行绘制描述部件
    const description: Description | null = this.model.getDescription();
    if (description) {
      description.setEnabled(false);
    }
    // 获取图表图例部件,设置图表图例部件不可用
    const legend: Legend | null = this.model.getLegend();
    if (legend) {
      legend.setEnabled(false);
    }
    // 设置图表数据最大的绘制数,如果超过该数值,则不进行绘制图表的数值标签
    this.model.setMaxVisibleValueCount(VISIBLE_VALUE_COUNT);
    // 是否绘制图表的背景色,绘制范围为图表柱状图的绘制范围,不包含轴线之外的部分
    this.model.setDrawGridBackground(true);
    // 设置图表的背景色,颜色的规格需要满足CanvasRenderingContext2D.fillstyle/strokestyle规格
    this.model.setGridBackgroundColor(GRID_BG_COLOR);
    // 设置不绘制柱状图的柱体阴影背景
    this.model.setDrawBarShadow(false);
    // 设置柱状图的数值在柱体上方
    this.model.setDrawValueAboveBar(true);
    // 设置柱状图的高亮范围是否为整个柱体,只在堆叠柱状图中有区别
    this.model.setHighlightFullBarEnabled(true);
    // 为左Y轴设置LimitLine,可设置限制线的宽度,线段样式,限制标签的位置,标签字体大小等
    this.limitLine = new LimitLine(STEP_TARGET_NUMBER, STEP_TARGET);
    // 设置限制线的宽度
    this.limitLine.setLineWidth(LINE_WIDTH);
    // 设置限制线虚线类型的长度
    this.limitLine.enableDashedLine(DASHED_LINE_LENGTH, DASHED_SPACE_LENGTH, ZERO);
    // 设置限制线的颜色
    this.limitLine.setLineColor(Color.Gray);
    // 设置限制线的位置
    this.limitLine.setLabelPosition(LimitLabelPosition.RIGHT_TOP);
    // 设置限制线上文本的大小
    this.limitLine.setTextSize(TEXT_SIZE);
    // 设置图表左Y轴信息
    this.leftAxis = this.model.getAxisLeft();
    if (this.leftAxis) {
      // 设置图表左Y轴最小值
      this.leftAxis.setAxisMinimum(ZERO);
      // 设置图表左Y轴是否在数据后绘制限制线
      this.leftAxis.setDrawLimitLinesBehindData(false);
      // 设置图表左Y轴数据的格式转换器
      this.leftAxis.setValueFormatter(new YValueFormatter());
      // 添加LimitLines
      this.leftAxis.addLimitLine(this.limitLine);
    }
    // 设置图表右Y轴信息
    this.rightAxis = this.model.getAxisRight();
    if (this.rightAxis) {
      // 设置图表右Y轴是否显示
      this.rightAxis.setEnabled(false);
      // 设置图表右Y轴最小值
      this.rightAxis.setAxisMinimum(ZERO);
    }
    // 设置X轴信息
    this.xAxis = this.model.getXAxis();
    if (this.xAxis) {
      // 设置X轴是否绘制网格线
      this.xAxis.setDrawGridLines(false);
      // 设置绘制标签个数
      this.xAxis.setLabelCount(LABEL_COUNT, false);
      //设置标签位置
      this.xAxis.setPosition(XAxisPosition.BOTTOM);
      // 设置数据的格式转换器
      this.xAxis.setValueFormatter(new XValueFormatter());
    }
    // //设置是否支持双击放大
    this.model.setDoubleTapToZoomEnabled(false);
    // 生成单一颜色数据
    this.data = this.getNormalData();
    // TODO 知识点:将数据与图表配置类绑定
    this.model.setData(this.data);
  }

  // 生成柱状图数据
  private getNormalData(): BarData {
    const START: number = 0;
    const values: JArrayList<BarEntry> = new JArrayList<BarEntry>();
    for (let i = START; i < this.calorieData.length; i++) {
      values.add(new BarEntry(i, this.calorieData[i]));
    }
    const dataSet: BarDataSet = new BarDataSet(values, CALORIE);
    dataSet.setHighLightColor(Color.Gray);
    dataSet.setDrawIcons(false);
    dataSet.setDrawValues(true);
    dataSet.setHighlightEnabled(false);
    // 为柱体添加颜色信息
    dataSet.setColorByColor(Colors.rgb(34, 177, 48));
    const dataSetList: JArrayList<IBarDataSet> = new JArrayList<IBarDataSet>();
    dataSetList.add(dataSet);
    const barData: BarData = new BarData(dataSetList);
    //设置柱状图宽度
    barData.setBarWidth(BAR_WIDTH);
    return barData;
  }

  build() {
    BarChart({ model: this.model })
      .width($r('app.string.bar_chart_health_layout_full_size'))
      .height($r('app.string.bar_chart_health_layout_forty'))
      .margin({ bottom: $r('app.integer.bar_chart_health_margin_twenty') })
  }
}

// 设置X轴数据的格式转换器
class XValueFormatter implements IAxisValueFormatter {
  getFormattedValue(value: number): string {
    return `1/${(value + 1).toFixed(0)}`;
  }
}

// 设置Y轴数据的格式转换器
class YValueFormatter implements IAxisValueFormatter {
  getFormattedValue(value: number): string {
    return value.toFixed(0);
  }
}