# ohos-MPChart
**Repository Path**: cbd_work/ohos-MPChart
## Basic Information
- **Project Name**: ohos-MPChart
- **Description**: No description available
- **Primary Language**: Unknown
- **License**: Apache-2.0
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 101
- **Created**: 2022-04-25
- **Last Updated**: 2024-06-04
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# ohos-MPChart
## 简介
ohos-MPChart各种类型的图表库,主要用于业务数据汇总,例如销售数据走势图,股价走势图等场景中使用,方便开发者快速实现图表UI,ohos-MPChart主要包括曲线图、柱形图、饼状图、蜡烛图、气泡图,雷达图等自定义图表库。
## 效果展示:
## 安装教程
1. 参考安装教程 [如何安装OpenHarmony npm包](https://gitee.com/openharmony-tpc/docs/blob/master/OpenHarmony_npm_usage.md)
2. 安装命令如下:
```
npm install @ohos/ohos_mpchart --save
```
## 使用说明
### 曲线图
1. 曲线图初始化数据
```
private aboutToAppear() {
this.lineData = this.initCurveData(45, 100);
this.topAxis.setLabelCount(5, false);
this.topAxis.setPosition(XAxisPosition.TOP);
this.topAxis.setAxisMinimum(0);
this.topAxis.setAxisMaximum(50);
this.bottomAxis.setLabelCount(5, false);
this.bottomAxis.setPosition(XAxisPosition.BOTTOM);
this.bottomAxis.setAxisMinimum(0);
this.bottomAxis.setAxisMaximum(50);
this.bottomAxis.setDrawAxisLine(false);
this.bottomAxis.setDrawLabels(false)
this.leftAxis = new YAxis(AxisDependency.LEFT);
this.leftAxis.setLabelCount(7, false);
this.leftAxis.setPosition(YAxisLabelPosition.OUTSIDE_CHART);
this.leftAxis.setSpaceTop(15);
this.leftAxis.setAxisMinimum(-50);
this.leftAxis.setAxisMaximum(200);
this.leftAxis.enableGridDashedLine(5,5,0)
this.rightAxis = new YAxis(AxisDependency.RIGHT);
this.rightAxis.setDrawGridLines(false);
this.rightAxis.setLabelCount(7, false);
this.rightAxis.setSpaceTop(11);
this.rightAxis.setAxisMinimum(-50); // this replaces setStartAtZero(true)
this.rightAxis.setAxisMaximum(200);
this.rightAxis.setDrawAxisLine(false);
var upperLimtLine:LimitLine= new LimitLine(150, "Upper Limit");
upperLimtLine.setLineWidth(4);
upperLimtLine.enableDashedLine(10, 10, 0);
upperLimtLine.setLabelPosition(LimitLabelPosition.RIGHT_TOP);
upperLimtLine.setTextSize(10);
var lowerLimtLine:LimitLine= new LimitLine(-30, "Lower Limit");
lowerLimtLine.setLineWidth(4);
lowerLimtLine.enableDashedLine(5, 5, 0);
lowerLimtLine.setLabelPosition(LimitLabelPosition.RIGHT_BOTTOM);
lowerLimtLine.setTextSize(10);
this.leftAxis.setDrawLimitLinesBehindData(true);
this.leftAxis.addLimitLine(upperLimtLine);
this.leftAxis.addLimitLine(lowerLimtLine);
}
private initCurveData(count: number, range: number): LineData {
let values = new JArrayList();
for (let i = 0; i < 50; i++) {
let val: number = Math.random() * 180 - 30;
values.add(new EntryOhos(i, val));
}
let gradientFillColor = new Array();
gradientFillColor.push(['#ffff0000', 0.1])
gradientFillColor.push(['#00ff0000', 1.0])
let dataSet = new JArrayList();
let set1 = new LineDataSet(values, "DataSet 1");
set1.setDrawFilled(true);
set1.enableDashedLine(10,5,0)
set1.setMode(Mode.LINEAR);
set1.setGradientFillColor(gradientFillColor)
set1.setColorByColor(Color.Black);
set1.setLineWidth(1)
set1.setDrawCircles(true);
set1.setCircleColor(Color.Black);
set1.setCircleRadius(2);
set1.setCircleHoleRadius(1)
set1.setCircleHoleColor(Color.Green)
set1.setDrawCircleHole(false)
dataSet.add(set1);
return new LineData(dataSet)
}
```
2. 添加数据到自定义曲线图表组件
```
build() {
Stack({ alignContent: Alignment.TopStart }) {
LineChart({
topAxis: this.topAxis,
bottomAxis: this.bottomAxis,
width: this.width,
height: this.height,
minOffset: this.minOffset,
leftAxis: this.leftAxis,
rightAxis: this.rightAxis,
lineData: this.lineData,
})
}
}
```
### 柱形图
1. 竖向柱形图初始化数据
```
private aboutToAppear(){
this.leftAxis = new YAxis(AxisDependency.LEFT);
this.leftAxis.setLabelCount(11, false);
this.leftAxis.setPosition(YAxisLabelPosition.OUTSIDE_CHART);
this.leftAxis.setSpaceTop(15);
this.leftAxis.setAxisMinimum(0);
this.leftAxis.setAxisMaximum(100);
this.leftAxis.enableGridDashedLine(10,10,0)
this.rightAxis = new YAxis(AxisDependency.RIGHT);
this.rightAxis.setDrawGridLines(false);
this.rightAxis.setLabelCount(7, false);
this.rightAxis.setSpaceTop(11);
this.rightAxis.setAxisMinimum(0); // this replaces setStartAtZero(true)
this.rightAxis.setAxisMaximum(100);
this.bottomAxis.setLabelCount(6, false);
this.bottomAxis.setPosition(XAxisPosition.BOTTOM);
this.bottomAxis.setAxisMinimum(0);
this.bottomAxis.setAxisMaximum(12);
this.setData(this.bottomAxis.getAxisMaximum(),this.leftAxis.getAxisMaximum())
this.model.width = this.width;
this.model.height = this.height;
this.model.init();
this.model.setDrawBarShadow(false);
this.model.setDrawValueAboveBar(true);
this.model.getDescription().setEnabled(false);
this.model.setMaxVisibleValueCount(60);
this.model.setLeftYAxis(this.leftAxis);
this.model.setRightYAxis(this.rightAxis);
this.model.setXAxis(this.bottomAxis)
this.model.mRenderer.initBuffers();
this.model.prepareMatrixValuePx();
}
private setData(count: number, range: number) {
let start: number = 1;
let values:JArrayList = new JArrayList();
for (let i = start; i < start + count; i++) {
let val: number = (Math.random() * range);
if (Math.random() * 100 < 25) {
let paint:ImagePaint = new ImagePaint();
paint.setIcon("app.media.star");
values.add(new BarEntry(i, val, paint));
} else {
values.add(new BarEntry(i, val));
}
}
let set1: BarDataSet;
if (this.model.getBarData() != null &&
this.model.getBarData().getDataSetCount() > 0) {
set1 = this.model.getBarData().getDataSetByIndex(0) as BarDataSet;
set1.setValues(values);
this.model.getBarData().notifyDataChanged();
this.model.notifyDataSetChanged();
} else {
set1 = new BarDataSet(values, "The year 2017");
set1.setDrawIcons(false);
let startColor1: number = 0xffffbb33;
let startColor2 = 0xff33b5e5;
let startColor3 = 0xffffbb33;
let startColor4 = 0xff99cc00;
let startColor5 = 0xffff4444;
let endColor1 = 0xff0099cc;
let endColor2 = 0xffaa66cc;
let endColor3 = 0xff669900;
let endColor4 = 0xffcc0000;
let endColor5 = 0xffff8800;
let gradientFills:JArrayList = new JArrayList();
gradientFills.add(new Fill(null,startColor1, endColor1));
gradientFills.add(new Fill(null,startColor2, endColor2));
gradientFills.add(new Fill(null,startColor3, endColor3));
gradientFills.add(new Fill(null,startColor4, endColor4));
gradientFills.add(new Fill(null,startColor5, endColor5));
set1.setFills(gradientFills);
let dataSets: JArrayList = new JArrayList();
dataSets.add(set1);
let data: BarData = new BarData(dataSets);
data.setValueTextSize(10);
data.setBarWidth(0.9);
this.model.setData(data);
}
}
```
2. 添加数据到自定义竖向柱形图表组件
```
build() {
Stack({ alignContent: Alignment.TopStart }) {
BarChart({model:this.model})
}
}
```
3. 横向柱形图初始化数据
```
private aboutToAppear(){
this.leftAxis = new YAxis(AxisDependency.LEFT);
this.leftAxis.setLabelCount(11, false);
this.leftAxis.setPosition(YAxisLabelPosition.OUTSIDE_CHART);
this.leftAxis.setSpaceTop(15);
this.leftAxis.setAxisMinimum(0);
this.leftAxis.setAxisMaximum(12);
this.leftAxis.enableGridDashedLine(10,10,0)
this.topAxis.setLabelCount(6, false);
this.topAxis.setPosition(XAxisPosition.TOP);
this.topAxis.setAxisMinimum(0);
this.topAxis.setAxisMaximum(100);
this.bottomAxis.setLabelCount(6, false);
this.bottomAxis.setPosition(XAxisPosition.BOTTOM);
this.bottomAxis.setAxisMinimum(0);
this.bottomAxis.setAxisMaximum(100);
this.setData(this.leftAxis.getAxisMaximum(),this.bottomAxis.getAxisMaximum())
this.model.width = this.width;
this.model.height = this.height;
this.model.init();
this.model.setDrawBarShadow(false);
this.model.setDrawValueAboveBar(true);
this.model.getDescription().setEnabled(false);
this.model.setMaxVisibleValueCount(60);
this.model.setLeftYAxis(this.leftAxis);
this.model.setTopXAxis(this.topAxis);
this.model.setBottomXAxis(this.bottomAxis)
this.model.mRenderer.initBuffers();
this.model.prepareMatrixValuePx();
}
private setData(count: number, range: number) {
let start: number = 1;
let values:JArrayList = new JArrayList();
for (let i = start; i < start + count; i++) {
let val: number = (Math.random() * range);
if (Math.random() * 100 < 25) {
let paint:ImagePaint = new ImagePaint();
paint.setIcon("app.media.star");
values.add(new BarEntry(val, i, paint));
} else {
values.add(new BarEntry(val, i));
}
}
let set1: BarDataSet;
if (this.model.getBarData() != null &&
this.model.getBarData().getDataSetCount() > 0) {
set1 = this.model.getBarData().getDataSetByIndex(0) as BarDataSet;
set1.setValues(values);
this.model.getBarData().notifyDataChanged();
this.model.notifyDataSetChanged();
} else {
set1 = new BarDataSet(values, "The year 2017");
set1.setDrawIcons(false);
let startColor1: number = 0xffffbb33;
let startColor2 = 0xff33b5e5;
let startColor3 = 0xffffbb33;
let startColor4 = 0xff99cc00;
let startColor5 = 0xffff4444;
let endColor1 = 0xff0099cc;
let endColor2 = 0xffaa66cc;
let endColor3 = 0xff669900;
let endColor4 = 0xffcc0000;
let endColor5 = 0xffff8800;
let gradientFills:JArrayList = new JArrayList();
gradientFills.add(new Fill(null,startColor1, endColor1));
gradientFills.add(new Fill(null,startColor2, endColor2));
gradientFills.add(new Fill(null,startColor3, endColor3));
gradientFills.add(new Fill(null,startColor4, endColor4));
gradientFills.add(new Fill(null,startColor5, endColor5));
set1.setFills(gradientFills);
let dataSets: JArrayList = new JArrayList();
dataSets.add(set1);
let data: BarData = new BarData(dataSets);
data.setValueTextSize(10);
data.setBarWidth(0.9);
this.model.setData(data);
}
}
```
4. 添加数据到自定义横向柱形图表组件
```
build() {
Stack({ alignContent: Alignment.TopStart }) {
BarChart({model:this.model})
}
}
```
### 饼状图
1. 饼状图初始化数据
```
private aboutToAppear():void {
this.pieData = this.initPieData(4, 10);
this.pieModel.setDrawAngles([80,40,140,100])
.setPieData(this.pieData)
.setRadius(500)
.setHoleRadius(0.5)
}
private initPieData(count:number, range:number):PieData{
let entries = new JArrayList();
for (var i = 0; i < count ; i++) {
entries.add(new PieEntry(((Math.random() * range) + range / 5),this.parties[i % this.parties.length]))
}
let dataSet:PieDataSet = new PieDataSet(entries, "Election Results");
dataSet.setDrawIcons(false);
dataSet.setSliceSpace(3);
dataSet.setIconsOffset(new MPPointF(0, 40));
dataSet.setSelectionShift(5);
// add a lot of colors
let colors:JArrayList = new JArrayList();
for (var index = 0; index < ColorTemplate.VORDIPLOM_COLORS.length; index++) {
colors.add( ColorTemplate.VORDIPLOM_COLORS[index]);
}
for (var index = 0; index < ColorTemplate.JOYFUL_COLORS.length; index++) {
colors.add( ColorTemplate.JOYFUL_COLORS[index]);
}
for (var index = 0; index < ColorTemplate.COLORFUL_COLORS.length; index++) {
colors.add( ColorTemplate.COLORFUL_COLORS[index]);
}
for (var index = 0; index < ColorTemplate.LIBERTY_COLORS.length; index++) {
colors.add( ColorTemplate.LIBERTY_COLORS[index]);
}
for (var index = 0; index < ColorTemplate.PASTEL_COLORS.length; index++) {
colors.add( ColorTemplate.PASTEL_COLORS[index]);
}
colors.add(ColorTemplate.getHoloBlue());
dataSet.setColorsByList(colors);
return new PieData(dataSet)
}
```
2. 添加数据到自定义饼状图表组件
```
build() {
Stack({ alignContent: Alignment.TopStart }) {
PieChart({
model:this.pieModel
})
}
}
```
### 气泡图
1. 气泡图初始化数据
```
private aboutToAppear() {
this.data=this.initBubbleData( 5,50)
this.topAxis.setLabelCount(6, false);
this.topAxis.setPosition(XAxisPosition.TOP);
this.topAxis.setAxisMinimum(0);
this.topAxis.setAxisMaximum(this.data.getXMax());
this.topAxis.enableGridDashedLine(10,10,0)
this.topAxis.setDrawAxisLine(false);
this.topAxis.setDrawLabels(false)
this.bottomAxis.setLabelCount(6, false);
this.bottomAxis.setPosition(XAxisPosition.BOTTOM);
this.bottomAxis.setAxisMinimum(0);
this.bottomAxis.setAxisMaximum(this.data.getXMax());
this.bottomAxis.setDrawAxisLine(false);
this.bottomAxis.setDrawLabels(true)
this.leftAxis = new YAxis(AxisDependency.LEFT);
this.leftAxis.setLabelCount(5, false);
this.leftAxis.setPosition(YAxisLabelPosition.OUTSIDE_CHART);
this.leftAxis.setSpaceTop(15);
this.leftAxis.setAxisMinimum(0);
this.leftAxis.setAxisMaximum(this.data.getYMax());
this.leftAxis.enableGridDashedLine(10,10,0)
this.rightAxis = new YAxis(AxisDependency.RIGHT);
this.rightAxis.setDrawGridLines(false);
this.rightAxis.setLabelCount(7, false);
this.rightAxis.setSpaceTop(15);
this.rightAxis.setAxisMinimum(0); // this replaces setStartAtZero(true)
this.rightAxis.setAxisMaximum(this.data.getYMax());
let textPaint:TextPaint = new TextPaint();
textPaint.setTextSize(this.leftAxis.getTextSize());
var leftTextWidth=Utils.calcTextWidth(textPaint,this.getFormattedValue(this.leftAxis.getAxisMaximum()));
let left = this.leftAxis.getSpaceTop() + leftTextWidth;
let top = this.minOffset;
let right = this.width - this.minOffset - leftTextWidth;
let bottom = this.height - this.minOffset;
this.data.mDisplayRect = new MyRect(left, top, right, bottom);
}
private initBubbleData(count: number, range: number): BubbleData {
let values1 = new JArrayList();
let values2 = new JArrayList();
let values3 = new JArrayList();
let imgePaint:ImagePaint=new ImagePaint();
imgePaint.setIcon($r('app.media.star'))
imgePaint.setWidth(px2vp(32))
imgePaint.setHeight(px2vp(32));
for (let i = 0; i < count; i++) {
values1.add(new BubbleEntry(i, Math.random() * range, Math.random() * range,imgePaint));
values2.add(new BubbleEntry(i, Math.random() * range, Math.random() * range));
values3.add(new BubbleEntry(i, Math.random() * range, Math.random() * range));
}
let set1:BubbleDataSet = new BubbleDataSet(values1, "DS 1");
set1.setDrawIcons(false);
set1.setColorByAlpha(ColorTemplate.COLORFUL_COLORS[0], 130);
set1.setIconsOffset(new MPPointF(0, px2vp(0)));
set1.setDrawValues(true);
let set2:BubbleDataSet = new BubbleDataSet(values2, "DS 2");
set2.setDrawIcons(false);
set2.setIconsOffset(new MPPointF(0, 15));
set2.setColorByAlpha(ColorTemplate.COLORFUL_COLORS[1], 130);
set2.setDrawValues(true);
let set3:BubbleDataSet = new BubbleDataSet(values3, "DS 3");
set3.setDrawIcons(false);
set3.setIconsOffset(new MPPointF(0, 0));
set3.setColorByAlpha(ColorTemplate.COLORFUL_COLORS[2], 130);
set3.setDrawValues(true);
let dataSets = new JArrayList();
dataSets.add(set1);
dataSets.add(set2);
dataSets.add(set3);
let dataResult:BubbleData = new BubbleData(dataSets);
dataResult.setDrawValues(true);
dataResult.setValueTextSize(8);
dataResult.setValueTextColor(Color.White);
dataResult.setHighlightCircleWidth(1.5);
return dataResult;
}
```
2. 添加数据到自定义气泡图表组件
```
build() {
Stack({ alignContent: Alignment.TopStart }) {
BubbleChart({
topAxis:this.topAxis,
bottomAxis:this.bottomAxis,
width:this.width,
height:this.height,
minOffset:this.minOffset,
leftAxis:this.leftAxis,
rightAxis:this.rightAxis,
data:this.data,
})
}
}
```
### candleStick蜡烛图
1. candleStick蜡烛图初始化数据
```
private aboutToAppear() {
this.candleData = this.initCandleData(40, 100);
}
private initCandleData(count: number, ranged: number): CandleData {
let values = new JArrayList();
values.add(new MyCandleEntry(40, 580, 380, 520, 430));
values.add(new MyCandleEntry(60, 510, 300, 350, 440));
values.add(new MyCandleEntry(80, 520, 320, 480, 380));
values.add(new MyCandleEntry(100, 580, 300, 400, 500));
values.add(new MyCandleEntry(120, 580, 400, 560, 460));
values.add(new MyCandleEntry(140, 540, 320, 370, 470));
values.add(new MyCandleEntry(160, 460, 230, 400, 300));
values.add(new MyCandleEntry(180, 520, 330, 390, 480));
values.add(new MyCandleEntry(200, 590, 350, 530, 450));
values.add(new MyCandleEntry(220, 540, 380, 420, 490));
values.add(new MyCandleEntry(240, 530, 260, 460, 350));
values.add(new MyCandleEntry(260, 450, 240, 300, 390));
values.add(new MyCandleEntry(280, 300, 100, 240, 160));
values.add(new MyCandleEntry(300, 240, 30, 90, 180));
values.add(new MyCandleEntry(320, 570, 360, 510, 420));
values.add(new MyCandleEntry(340, 440, 220, 280, 380));
let dataSets = new JArrayList();
let set1 = new MyCandleDataSet(values, "Data Set");
dataSets.add(set1);
return new MyCandleData(dataSets);
}
```
2. 添加数据到自定义candleStick蜡烛图表组件
```
build() {
Stack({ alignContent: Alignment.TopStart }) {
BubbleChart({
topAxis:this.topAxis,
bottomAxis:this.bottomAxis,
width:this.width,
height:this.height,
minOffset:this.minOffset,
leftAxis:this.leftAxis,
rightAxis:this.rightAxis,
data:this.data,
})
}
}
```
## 接口说明
`let values = new JArrayList();`
1. 添加数据
`values.append(element:T)`
2. 移除数据
`values.remove(element:T)`
3. 获取数据
`values.get(pos:number)`
4. 清除数据
`values.clear()`
`let barEntry=new BarEntry(35, [ -17, 17 ]);`
1. 复制对象
`barEntry.copy()`
2. 设置Y轴数组
`barEntry.setVals(vals: number[])`
3. 是否层叠
`barEntry.isStacked()`
4. 计算Y轴最小值
`barEntry.calcYValsMin()`
5. 计算Y轴范围
`barEntry.calcRanges()`
`let paint : Paint = new Paint();`
1. 设置颜色
`paint.setColor(value: Color | number | string | Resource)`
2. 设置文字大小
`paint.setTextSize(value: number)`
3. 社会填充
`paint.setFill(value: Color | number | string | Resource)`
4. 设置边框颜色
`paint.setStroke(value: Color | number | string | Resource)`
5. 设置透明度
`paint.setAlpha(value: number)`
`let set1:BubbleDataSet = new BubbleDataSet(values1, "DS 1");`
1. 设置是否需要绘制图标
`set1.setDrawIcons(false)`
2. 设置绘制颜色
`set1.setColorByColor(0x88c12552);`
3. 设置图标偏移距离
`set1.setIconsOffset(new MPPointF(0, px2vp(0)))`
4. 设置是否绘制值
`set1.setDrawValues(true);`
`let set1: ScatterDataSet = new ScatterDataSet(values, "DS 1");`
1. 设置绘制形状
`set1.setScatterShape(ScatterShape.SQUARE)`
2. 设置绘制半径
` set1.setScatterShapeHoleRadius(3);`
3. 设置绘制图形大小
`set1.setScatterShapeSize(8);`
`let topAxis: XAxis = new XAxis();`
1. 设置轴文字label数量
`topAxis.setLabelCount(6, false);`
2. 设置轴文本位置
`topAxis.setPosition(XAxisPosition.TOP)`
3. 设置最小值
`topAxis.setAxisMinimum(10)`
4. 设置最大自值
`topAxis.setAxisMaximum(50)`
5. 设置网格线虚线间隔
`topAxis.enableGridDashedLine(10,10,0)`
`let model:HorizontalBarChartModel = new HorizontalBarChartModel();`
1. 初始化数据
`model.init();`
2. 计算值数据
`model.prepareMatrixValuePx()`
3. 设置最大显示label数量
`model.setMaxVisibleValueCount(count: number)`
4. 设置描述对象
`model.setDescription(desc: Description)`
5. 设置左侧Y轴
`model.setLeftYAxis(axis:YAxis)`
6. 设置底部X轴
`model.setBottomXAxis(axis:XAxis)`
`let rect: MyRect = new MyRect();`
1. 复制对象
`rect.copyOrNull(r: MyRect);`
2. 对比对象
`rect.equals(o: Object):`
3. 计算宽度
`rect.width()`
4. 计算高度
`rect.height()`
5. 计算中心点X轴值
`rect.centerX()`
6. 计算中心点Y轴值
`rect.centerY()`
## 兼容性
支持OpenHarmony API version 8 及以上版本
## 目录结构
````
|---- MPChart
| |---- entry # 示例代码文件夹
| |---- ohos_MPChart # ohos_MPChart库文件夹
| |---- index.ets # 对外接口
│ ├----components # 框架代码目录
│ ├----animation # 动画目录
│ │
│ ├----buffer # 缓存相关目录
│ │
│ ├----charts # 各类型图表目录
│ │
│ ├----components # 自定义组件目录
│ │
│ ├----data # 数据实体目录
│ │
│ ├----exception # 异常处理目录
│ │
│ ├----formatter # 各种数据格式化目录
│ │
│ ├----highlight # 各种图表中高亮显示操作目录
│ │
│ ├----interfaces # 对外接口目录
│ │
│ ├----jobs # 动画工作线程目录
│ │
│ ├----listener # 手势监听目录
│ │
│ ├----matrix # 3D 效果计算目录
│ │
│ ├----model # 过渡颜色
│ │
│ ├----renderer # 各种图表绘制属性设置目录
│ │
│ └----utils # 工具类目录
│
└─resources # 资源文件
| |---- README.MD # 安装使用方法
````
## 贡献代码
使用过程中发现任何问题都可以提 [Issue](https://gitee.com/hihopeorg/ohos-MPChart/issues) 给我们,当然,我们也非常欢迎你给我们发 [PR](https://gitee.com/hihopeorg/ohos-MPChart/pulls) 。
## 开源协议
本项目基于 [Apache License 2.0](https://gitee.com/hihopeorg/ohos-MPChart/blob/master/LICENSE) ,请自由地享受和参与开源。