iOS折线图

object-c折线,效果如图


折线图
- (void)viewDidLoad {
    [super viewDidLoad];
    //x y 轴上的标注数值
    NSArray *xArr = @[@"0",@"5",@"10",@"15",@"20",@"25",@"30",];
    NSArray *yArr = @[@"0",@"2",@"4",@"6",@"8",@"10",@"12",];
    //要画的折线图的各个点
    NSMutableArray *pointArr = [NSMutableArray array];
    for (int i=0; i<=20; i++)
    {
        CGPoint point = CGPointMake(i*1.5, random()%12);
        NSValue *value = [NSValue valueWithCGPoint:point];
        [pointArr addObject:value];
    }
    //传入数值,画折线图
    BrokenLineDemo *demo = [[BrokenLineDemo alloc]initWithFrame:CGRectMake(50, 100, 300, 300) andXValue:xArr YValueArr:yArr andPointArr:pointArr];
    [self.view addSubview:demo];
}

主要其实就是画线。重写drawRect,再用CGContextRef。

#define kChartLineColor         [UIColor grayColor]
#define kLightFrayColor         [UIColor colorWithWhite:0.8 alpha:1]
#define kChartTextColor         [UIColor lightGrayColor]

#define k_Space 10
#import "BrokenLineDemo.h"
@interface BrokenLineDemo()
@property(nonatomic,strong)NSArray *xValueArr;//x轴上的标注值
@property(nonatomic,strong)NSArray *yValueArr;//y轴上的标注值

@property(nonatomic,assign)float xSpace;//x轴每个标注之间相隔的frame距离
@property(nonatomic,assign)float ySpace;//y轴每个标注之间相隔的frame距离
@property(nonatomic,assign)float xValueSpace;//x轴每个标注之间相隔的数值 0 5 10 15
@property(nonatomic,assign)float yValueSpace;//y轴每个标注之间相隔的数值 0 2 4 6 8

@property(nonatomic,assign)CGPoint startPoint;//坐标起始点

@property(nonatomic,strong)NSMutableArray *pointArr;//要画的点的数组
@property(nonatomic,strong)NSMutableArray *lastPointArr;//将要画的点转化为此坐标轴上的点(传过来的点的坐标轴原点在左上方,转为此坐标轴的原点在左下方)
@end

重写init

-(instancetype)initWithFrame:(CGRect)frame andXValue:(NSArray *)xValueArr YValueArr:(NSArray *)yValueArr andPointArr:(NSMutableArray *)pointArr
{
    if (self=[super initWithFrame:frame])
    {
        self.xValueArr = xValueArr;//x轴的标注
        self.yValueArr = yValueArr;//y轴的标注
        self.pointArr = pointArr;//要画的点的数值
        self.lastPointArr = [NSMutableArray array];//存放转化坐标轴之后的点
        
        
        float xMin = [[xValueArr firstObject]floatValue];
        float xMax = [[xValueArr lastObject]floatValue];
        float yMin = [[yValueArr firstObject]floatValue];
        float yMax = [[yValueArr lastObject]floatValue];
        // x y 轴上每格的frame间距
        self.xSpace = (frame.size.width-k_Space*3)/(xValueArr.count-1);
        self.ySpace = (frame.size.height-k_Space*3)/(yValueArr.count-1);
        // x y 轴上每格的标注间隔数值,此x轴为5,y轴为2
        self.xValueSpace = (xMax-xMin)/(self.xValueArr.count-1);
        self.yValueSpace = (yMax-yMin)/(self.yValueArr.count-1);
        //画图的起点,原点
         self.startPoint = CGPointMake(k_Space*2, frame.size.height-k_Space*2);
        //转化坐标 例:传入数值是(0,0),原点在左上方;转化后因为原点在左下方上面一点点,因此点要画在(k_Space*2, frame.size.height-k_Space*2)处
        for (int i=0; i<self.pointArr.count; i++)
        {
            NSValue *value = self.pointArr[i];
            CGPoint point = value.CGPointValue;
            CGPoint lastPoint = CGPointMake((point.x/_xValueSpace)*(_xSpace)+_startPoint.x, _startPoint.y-(point.y/_yValueSpace)*(_ySpace));
            [_lastPointArr addObject:[NSValue valueWithCGPoint:lastPoint]];
        }
    }
    return self;
}

画线其实很简单,调用CGContextRef的方法就好,难点在于坐标的转化。传入的数值,都是以原点在左上方的坐标轴为标准的数值。如图,(0,0),(0,1),(0,2)等,你要是直接用此数值,那点就直接画在最上边的那条线上,显然是不对的。如图
传入数值的坐标原点

我们要以左下方的那个点为坐标原点,进行转换坐标。假如传入的坐标是(10,6),显然x轴上标注数值相隔为5,y轴标注数值相隔为2;设x轴每小格frame的间距为xSpace(即:x轴上每单元格在屏幕上的长度),y轴上每小格的间距为ySpace(这两个值都可以计算出来,请看源码);现原点(0,0)距离重写的view左边间距为为20,下边距为20;则
传入为(10,6)应该画在屏幕上的点为:
X为


x

Y为(frame是重写的view的frame)


y

以下方为坐标原点

坐标转化后就可以直接画点了,再讲所有的点连线,over。
思路就是这样下面贴drawRect重写。(源码地址:https://pan.baidu.com/s/1qYwrpBA
重写drawRect

- (void)drawRect:(CGRect)rect
{
    CGContextRef context =UIGraphicsGetCurrentContext();
    //x轴上的值
    for (int i=0; i<_xValueArr.count; i++)
    {
        //x轴上的值
        NSString *xTitle = _xValueArr[i];
        [[UIColor blackColor]set];
        NSDictionary *attr =@{NSFontAttributeName:[UIFont systemFontOfSize:10]};
        CGSize labelSize = [xTitle sizeWithAttributes:attr];
        float originX = k_Space*2+(_xSpace)*i;
        CGRect xTitleRect  = CGRectMake(originX-labelSize.width/2, rect.size.height-k_Space-5, labelSize.width, labelSize.height);
         [self drawStr:xTitle withRect:xTitleRect textFontSize:10 textColor:kChartTextColor];
        //x轴上的竖线
        [self drawLine:context
            startPoint:CGPointMake(originX, rect.size.height-k_Space*2)
              endPoint:CGPointMake(originX, rect.size.height-k_Space*2-5)
             lineColor:kChartLineColor
             lineWidth:1];
    }
    //X轴
    [self drawLine:context
        startPoint:CGPointMake(k_Space*2, rect.size.height-k_Space*2)
          endPoint:CGPointMake(self.frame.size.width, rect.size.height-k_Space*2)
         lineColor:kChartLineColor
         lineWidth:1];
    for (int i=0; i<_yValueArr.count; i++)
    {
        //y轴上的值
        NSString *yTitle = _yValueArr[i];
        [[UIColor blackColor]set];
        NSDictionary *attr =@{NSFontAttributeName:[UIFont systemFontOfSize:10]};
        CGSize labelSize = [yTitle sizeWithAttributes:attr];
        
        float yOrigin =  _startPoint.y-(_ySpace*i);
        CGRect yTitleRect  = CGRectMake(k_Space, yOrigin-labelSize.height/2, labelSize.width, labelSize.height);
         [self drawStr:yTitle withRect:yTitleRect textFontSize:10 textColor:kChartTextColor];
         //画y轴上的横线
        if (i>0)
        {
            [self drawLine:context
                startPoint:CGPointMake(_startPoint.x,yOrigin)
                  endPoint:CGPointMake(rect.size.width,yOrigin)
                 lineColor:kLightFrayColor
                 lineWidth:1];
        }
    }
    //y轴
    [self drawLine:context
        startPoint:_startPoint
          endPoint:CGPointMake(_startPoint.x,0)
         lineColor:kChartLineColor
         lineWidth:1];
    
    //画point
    for (int i=0; i<self.pointArr.count; i++)
    {
        NSValue *value = self.lastPointArr[i];
        CGPoint point = value.CGPointValue;
        //画点
        [self drawPointWithContext:context point:point color:[UIColor lightGrayColor]];
        
        //画点上的值
        NSValue *oldValue = self.pointArr[i];
        CGPoint oldPoint = oldValue.CGPointValue;
        NSString *valueStr = [NSString stringWithFormat:@"%.2f",oldPoint.y];
        CGSize labelSize = [valueStr sizeWithAttributes:@{NSFontAttributeName:[UIFont systemFontOfSize:10]}];
        CGRect valueStrRect  = CGRectMake(point.x-labelSize.width/2, point.y-5-labelSize.height, labelSize.width, labelSize.height);
        [self drawStr:valueStr withRect:valueStrRect textFontSize:10 textColor:kChartTextColor];
        //画折线
        if (i<_lastPointArr.count-1)
        {
            NSValue * endValaue = _lastPointArr[i+1];
            CGPoint endPoint =[endValaue CGPointValue];
            //画折线
              [self drawLine:context startPoint:point endPoint:endPoint lineColor:[UIColor colorWithRed:26/255.0 green:135/255.0 blue:254/255.0 alpha:1] lineWidth:1];
        }
    }
}
//画文字
- (void)drawStr:(NSString *)titleStr  withRect:(CGRect)rect textFontSize:(float)fontSize textColor:(UIColor *)textColor
{
    UIFont *font =  [UIFont systemFontOfSize:fontSize];
      [titleStr drawInRect:rect withAttributes:@{NSFontAttributeName :font,NSForegroundColorAttributeName:textColor}];
}

//画点
-(void)drawPointWithContext:(CGContextRef)context point:(CGPoint )point color:(UIColor *)pointColor
{
    CGContextSetFillColorWithColor(context, pointColor.CGColor);//填充颜色
    CGContextAddArc(context, point.x, point.y, 2, 0, 2*M_PI, 0); //添加一个圆
    CGContextDrawPath(context, kCGPathFill);//绘制填充
}
//画线
- (void)drawLine:(CGContextRef)context startPoint:(CGPoint)startPoint endPoint:(CGPoint)endPoint lineColor:(UIColor *)lineColor lineWidth:(CGFloat)width {
    
    CGContextSetShouldAntialias(context, YES ); //抗锯齿
    CGColorSpaceRef Linecolorspace1 = CGColorSpaceCreateDeviceRGB();
    CGContextSetStrokeColorSpace(context, Linecolorspace1);
    CGContextSetLineWidth(context, width);
    CGContextSetStrokeColorWithColor(context, lineColor.CGColor);
    CGContextMoveToPoint(context, startPoint.x, startPoint.y);
    CGContextAddLineToPoint(context, endPoint.x, endPoint.y);
    CGContextStrokePath(context);
    CGColorSpaceRelease(Linecolorspace1);
}

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

推荐阅读更多精彩内容

  • PNChart 去年项目中用到了折线图,当时因为项目赶的紧,于是下载了GitHub上排行前几名的图表框架,看一下哪...
    堂吉诃德灬阅读 1,732评论 8 12
  • 总结一下最近项目中需要使用到的折线图的展示,首先说下折线图演示的一下几种情况1 当数据出现有正数和负数,那么折现就...
    嘿晴天阅读 1,242评论 1 2
  • 一、画出X,Y轴 二、分别给X坐标和Y坐标添加代表的属性值 三、画折线图 结果图
    管你爱不爱阅读 817评论 0 1
  • 从开始使用初始化说起首先初始化个LineGraph视图,赋值XY轴数组,XY轴的最大值,XY轴的颜色,每条折线所代...
    马大俊不是啥好人阅读 1,327评论 2 3
  • 最近一直在断断续续的搞一些简单的动画效果,感觉效果还不错,其中也有很多道友对效果的实现提出了有意义的建议(十分感谢...
    健健锅阅读 25,897评论 21 132