iOS学习资料恩美第二个APP项目iOS开发

LineChart:折线图 详解 (PNChart三方库)

2016-12-25  本文已影响1191人  goyohol

由于最近公司要求画折线图,搞得头都大了~


不过研究一段时间后发现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类型



在- (void)viewDidLoad { }里面:

  // 绘图数据
  _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        //下





进阶使用


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轴的起点确定,即可设置自己的 坐标轴

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上,且置于最顶层)的自定制视图。

自己只顾到了位置上的效果!
如果什么地方有悖于作者原本的思想,还望指出!谢谢~
















goyohol's essay

上一篇 下一篇

猜你喜欢

热点阅读