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

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


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





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

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,657评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,662评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,143评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,732评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,837评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,036评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,126评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,868评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,315评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,641评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,773评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,470评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,126评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,859评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,095评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,584评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,676评论 2 351

推荐阅读更多精彩内容