由于最近公司要求画折线图,搞得头都大了~
不过研究一段时间后发现PNChart还挺好用的,作者人也不错哦!😁
虽然自己不知道这是不是 真的作者,但还是蛮开心的😊😊
而且网络上的讲解资料只是描绘了大概的谱,更详细的界面搭建和绘制则需要进一步研究、了解!!
所以就着自己的经验,分享一下PNChart里面LineChart的细节使用!
导入头文件
#import <PNChart.h>
#define kScreenWidth \
([[UIScreen mainScreen] respondsToSelector:@selector(nativeBounds)] ? [UIScreen mainScreen].nativeBounds.size.width/[UIScreen mainScreen].nativeScale : [UIScreen mainScreen].bounds.size.width)
#define kScreenHeight \
([[UIScreen mainScreen] respondsToSelector:@selector(nativeBounds)] ? [UIScreen mainScreen].nativeBounds.size.height/[UIScreen mainScreen].nativeScale : [UIScreen mainScreen].bounds.size.height)
定义全局变量:
// 绘图数据
NSArray * _chart_X_LabelArr; //字符串形式
NSArray * _chart_Y_LabelArr; //字符串形式 或 Number类型
// 绘图数据
_chart_X_LabelArr = @[@"1",@"2",@"3",@"4",@"5",@"6",@"7",@"8",@"9"]; //字符串形式
_chart_Y_LabelArr = @[@100,@105,@150,@60,@20,@160,@290,@110,@60]; //Number类型(或字符串形式)
PNLineChart * lineChart_2 = [[PNLineChart alloc] initWithFrame:CGRectMake(0, 50 + kScreenHeight/2.f , kScreenWidth, kScreenHeight/3.f) ];
lineChart_2.yLabelFormat = @"%1.1f"; // 格式化Y坐标
lineChart_2.showCoordinateAxis = YES; // 是否显示坐标轴 (默认 不显示)
lineChart_2.showGenYLabels = NO;
// lineChart_2.showLabel = NO; //显示x、y轴的标签 (默认展示)
lineChart_2.thousandsSeparator = YES;
[lineChart_2 setYLabelColor:[UIColor redColor] ]; //y轴标签 颜色
[lineChart_2 setXLabelColor:[UIColor blackColor]]; //x轴标签 颜
lineChart_2.yFixedValueMax = 200.f; //y轴最大值
lineChart_2.yFixedValueMin = 0.f; //y轴最小值
//Y轴 各标签的值 (一般 固定)
[lineChart_2 setYLabels:@[@"0",@"50",@"100",@"150",@"200"] ];
[lineChart_2 setXLabels:_chart_X_LabelArr]; //x轴 标签的值
// 折线图各时刻 心率值 数据 添加
PNLineChartData * beatData2 = [PNLineChartData new];
beatData2.color = PNGreen; // 折线的颜色
beatData2.alpha = 0.7f;
beatData2.lineWidth = 1.5f; // 线宽
beatData2.itemCount = _chart_X_LabelArr.count; //绘制的 点数
beatData2.getData = ^(NSUInteger index) {
CGFloat yValue;
yValue = [_chart_Y_LabelArr[index] floatValue]; // 转化为数值(基本类型)
return [PNLineChartDataItem dataItemWithY:yValue];
};
lineChart_2.chartData = @[beatData2]; //添加好数据
lineChart_2.backgroundColor = [UIColor colorWithRed:1 green:0 blue:1 alpha:0.3f]; // 设置(淡紫色)背景色
[self.view addSubview:lineChart_2];
[lineChart_2 strokeChart]; //绘制曲线
超出Y轴的值。 ( 有效显示范围 )不会显示出来,但是会绘制到哪里。
我自己觉得的缺点:
1.X轴最后一位标签和箭头重合,不美观!(坐标轴及有效显示范围的大小 会根据数据的内容进行变化)
2.图形的点与X轴位置不对应。
当然通过以下属性 可以设置好点的对应关系,但是标签值 又不对应了。
lineChart_2.chartMarginLeft = 21.f; //左
这几个属性慎用:(反正 我没 搞懂怎么用。。。😂😂)。还望明白的同志交流、提示一下。
lineChart_2.chartMarginLeft //左
// lineChart_2.chartMarginRight //右
// lineChart_2.chartMarginTop //上
// lineChart_2.chartMarginBottom //下
进阶使用
- 1.有效显示范围
有效显示范围宽度:chartCavanWidth
有效显示范围高度:chartCavanHeight - 2.协议代理的点击显示
- 3.获得折线图各点的坐标
PNLineChart * lineChart_1 = [[PNLineChart alloc] initWithFrame:CGRectMake(0, 30, kScreenWidth, kScreenHeight/2.f) ];
lineChart_1.yLabelFormat = @"%1.1f"; // 格式化Y坐标
//⭐️折线图形显示的 ⭐️⭐️有效范围⭐️⭐️
lineChart_1.chartCavanWidth = 220.f;
lineChart_1.chartCavanHeight = 200.f;
lineChart_1.showGenYLabels = YES;
lineChart_1.showLabel = YES;
[lineChart_1 setXLabelColor:[UIColor blackColor]];
lineChart_1.showCoordinateAxis = YES; // 是否显示坐标轴 (默认 不显示)
lineChart_1.yFixedValueMax = 200.f; //y轴最大值
lineChart_1.yFixedValueMin = 0.f;
//Y轴 各倍数点
[lineChart_1 setYLabels:@[@"0",@"50",@"100",@"150",@"200" ] ];
//X轴 标签值数组
[lineChart_1 setXLabels:_chart_X_LabelArr];
// 折线图各时刻 心率值 数据 添加
PNLineChartData * beatData = [PNLineChartData new];
beatData.color = PNGreen;
beatData.alpha = 0.7f;
beatData.lineWidth = 1.5f;
beatData.itemCount = _chart_X_LabelArr.count; //绘制的 点数
// 折线点的样式 及 大小 (⭐️醒目)
beatData.inflexionPointStyle = PNLineChartPointStyleCircle; //数据折点格式
beatData.inflexionPointWidth = 3.8f; //数据折点 宽度(大小)
beatData.getData = ^(NSUInteger index) {
CGFloat yValue = [_chart_Y_LabelArr[index] floatValue];
return [PNLineChartDataItem dataItemWithY:yValue];
};
lineChart_1.chartData = @[beatData]; //添加好数据
[self.view addSubview:lineChart_1];
[lineChart_1 strokeChart]; //绘制曲线
lineChart_1.backgroundColor = [UIColor colorWithRed:1 green:0 blue:0 alpha:0.3]; // (浅红)背景色
lineChart_1.delegate = self; //设置协议代理
// 得到 首个点 X坐标 (用于 计算 偏移度)
NSLog(@"lineChart_1.pathPoints %@",lineChart_1.pathPoints); //所有的数据 (应该是 其各分段的所有数据)
NSLog(@"[lineChart_1.pathPoints firstObject] %@",[lineChart_1.pathPoints firstObject]); // 取唯一的 一条线的数据
打印出来的值:
//首个点位置
NSString * firstPoint_Str = [NSString stringWithFormat:@"%@",[[lineChart_1.pathPoints firstObject] firstObject] ];
NSLog(@"firstPoint_Str %@",firstPoint_Str);
NSCharacterSet * str_first_set = [NSCharacterSet characterSetWithCharactersInString:@"{,"];
NSLog(@"str_first_set %@",str_first_set);
打印出来的值:
NSString * first_X_str;
if (![firstPoint_Str isEqualToString:@"(null)"]) { // 第一个点存在
NSArray * iNFO_first_arr = [firstPoint_Str componentsSeparatedByCharactersInSet:str_first_set];
first_X_str = iNFO_first_arr[1]; // 获取第一个点的X轴 坐标
NSLog(@"iNFO_first_arr %@",iNFO_first_arr);
}
打印出来的值:
有效范围:绘制的折线图的显示范围
x轴起点 通过第一个点的值( [first_X_str floatValue] ) 求出
y轴起点 通过自己创建好的Chart视图的⭐️比例关系 求出
//有效显示范围
float effect_V_X = [first_X_str floatValue]; // 首个点 的x轴坐标
float effect_V_Y = beatChart_H * 0.0785f; // (比例关系) 起始 Y位置
float effect_V_W = lineChart_1.chartCavanWidth; //有效范围 宽度
float effect_V_H = lineChart_1.chartCavanHeight; //有效范围 高度
UIView * effect_V = [[UIImageView alloc] initWithFrame:CGRectMake(effect_V_X, effect_V_Y, effect_V_W, effect_V_H)];
effect_V.backgroundColor = [UIColor colorWithRed:1 green:1 blue:0 alpha:0.3]; //(黄色)背景色
[lineChart_1 addSubview:effect_V];
效果:X、Y轴的起点确定,即可设置自己的 坐标轴 了
@interface ViewController ( ) <PNChartDelegate>
//MARK:PNChart代理 点击方法
- (void)userClickedOnLinePoint:(CGPoint)point lineIndex:(NSInteger)lineIndex {
NSLog(@"chosed lineIndex(线 下标) %ld",lineIndex);
} // 线
- (void)userClickedOnLineKeyPoint:(CGPoint)point lineIndex:(NSInteger)lineIndex pointIndex:(NSInteger)pointIndex {
NSLog(@"lineIndex(第几根线):%ld 选择点的pointIndex %ld",lineIndex + 1,pointIndex);
NSLog(@"X:%@ Y:%@",_chart_X_LabelArr[pointIndex],_chart_Y_LabelArr[pointIndex]);
} //点
效果:点击响应事件 及 其绘制的动画效果(点多(数据量大)效果更明显)
有个点(290) , 点不到~😂😂😂
比例位置关系
由于chart图像绘制好,放入的另一个视图及自身的比例是固定。所以计算出有效显示范围,就可以确定 X轴起始点 和 显示高度(及 Y轴结束点:最顶端 )!!
那么我们就可以自己绘制Y轴 和 X轴的视图放置上去。
自己绘制X轴 与 Y轴的原因:
1.chart绘制好以后,若其需要其显示的长度大于和屏幕的宽度,就需要一个用于显示Y轴且固定好的视图;
例子:
属性:
//放置折线图的scrollView
@property (strong, nonatomic) UIScrollView *numChart_ScrollV;
// UIScrollView
float chart_Scroll_X = 0.f;
float chart_Scroll_W = kScreenWidth;
float chart_Scroll_H = kScreenWidth * 7/10.f;
float chart_Scroll_Y = kScreenHeight - chart_Scroll_H - 20.f;
self.numChart_ScrollV = [[UIScrollView alloc] initWithFrame:CGRectMake(chart_Scroll_X, chart_Scroll_Y, chart_Scroll_W, chart_Scroll_H)];
self.numChart_ScrollV.backgroundColor = [UIColor colorWithRed:0 green:0 blue:1 alpha:0.2f]; //(淡蓝色)背景色
[self.view addSubview:self.numChart_ScrollV];
self.numChart_ScrollV.scrollEnabled = YES; //可滑动
// Chart设置为 两倍屏宽
PNLineChart * lineChart_1 = [[PNLineChart alloc] initWithFrame:CGRectMake(0, 0, 2 * kScreenWidth, chart_Scroll_H) ];
// ScrollView的显示范围
self.numChart_ScrollV.contentSize = CGSizeMake(lineChart_1.frame.size.width, lineChart_1.frame.size.height);
//折线图形显示的有效范围
lineChart_1.chartCavanWidth = 500.f;
lineChart_1.chartCavanHeight = 160.f;
[self.numChart_ScrollV addSubview:lineChart_1];
效果:Y轴不固定
所以确定 起点的X轴坐标 及 有效显示范围的上面那条边对应 顶点的Y值(Y轴显示标签最大值) 就可以了。
2.X轴里面的标签值的字符串长度过大,并不会自适应宽度,所有最好自定制一个X轴的视图。
例子:
// 把X轴的数据的长度 更改 过大
_chart_X_LabelArr = @[@"100",@"2",@"3333.232",@"4004",@"55",@"6666.66",@"7777",@"8888.8888",@"99"];
效果:显示的大小不统一且出现了换行。
位置关系的总结
由于与父视图左侧、顶部 重合。放入的绘图数据 变化时,其显示的Y轴最大标签值 的顶部 到父视图顶部距离固定。计算出其距离可确定有效范围(黄色区域)的起点,即可知道Y轴的位置了。
有效范围的X轴起点坐标:从第一个点的坐标获取;
有效范围的Y轴起点坐标:根据 放置自己的Chart高度的比例,就可计算出其值。(Chart高度固定(或 比例确定),有效范围的Y轴标签的顶点坐标 即固定)
⭐️由于ScrollView和Chart的视图位置、大小关系固定,即可在ScrollView或者在Chart里面添加自己绘制的X轴坐标的视图。
我自己公司项目里面没使用LineChart自带的坐标轴,全部自己绘制。主要是其坐标轴:1.在适配时,比例不一;2.在(X轴 坐标)数据量不同时,比例也不一致。就自己根据位置、比例关系,计算好位置 并 放置上X轴与Y轴(⭐️放置在self.view上,且置于最顶层)的自定制视图。
自己只顾到了位置上的效果!
如果什么地方有悖于作者原本的思想,还望指出!谢谢~