iOS 纯手工打造折线图,柱状图

折线图.png
柱状图.png
//
//  LYChartView.h
//  LYChartView
//
//  Created by HENAN on 17/1/6.
//  Copyright © 2017年 LYS. All rights reserved.
//

#import <UIKit/UIKit.h>
@class LYChartView;
typedef NS_ENUM(NSInteger,LYChartViewType) {
    LYChartViewTypeLine,       // 折线
    LYChartViewTypeHistogram   // 柱状
};
@interface LYChartView : UIView
/*
 * 功能:重写初始化方法
 * 参数:frame,column,type,title,unit
 * 返回:图表对象
 */
- (instancetype)initWithFrame:(CGRect)frame
                       column:(NSInteger)column
                          row:(NSInteger)row
                         type:(LYChartViewType)type
                        title:(NSString *)title
                         unit:(NSString *)unit;
/*
 * 功能:设置是否动画
 * 参数animation:是否动画
 */
- (void)customAnimation:(BOOL)animation;
/*
 * 功能:更新下标字体大小
 * 参数font:字体大小
 */
- (void)customIndexFont:(CGFloat)font;
/*
 * 功能:更新标题字体大小
 * 参数font:字体大小
 */
- (void)customTitleFont:(CGFloat)font;
/*
 * 功能:更新填充样式
 * 参数color:返回颜色回调
 */
- (void)customColor:(UIColor *(^)(NSInteger index,LYChartViewType type))color;
/*
 * 功能:更改类型
 * 参数type:要更改的类型
 */
- (void)customType:(LYChartViewType)type;
/*
 * 功能:更新frame
 * 参数frame:更改的frame
 */
- (void)customFrame:(CGRect)frame;
/*
 * 功能:设置标题的位置
 * 参数alignment:标题的位置
 */
- (void)customTitleAlignment:(NSTextAlignment)alignment;
/*
 * 功能:设置内边距
 * 参数edgeInsets:内边距
 */
- (void)customEdgeInsets:(UIEdgeInsets)edgeInsets;
/*
 * 功能:设置下标
 * 参数data:下标数组
 */
- (void)customColumnIndexData:(NSArray *)data;
/*
 * 功能:设置数据
 * 参数data:数值数组
 */
- (void)customValueData:(NSArray *)data;
/*
 * 功能:柱状图点击事件回调
 * 参数action:柱状图点击时间回调
 */
- (void)histogramSelectAction:(void(^)(NSInteger index))action;
/*
 * 功能:设置右上角图片视图
 * 参数action:图表右上角视图
 */
- (void)customRightTopView:(void(^)(UIView *view))action;
/*
 * 功能:刷新数据(以上所有调整,要想展示在图表上,就必须调用这个刷新方法,否则不起效)
 */
- (void)reloadData;
@end
//
//  LYChartView.m
//  LYChartView
//
//  Created by HENAN on 17/1/6.
//  Copyright © 2017年 LYS. All rights reserved.
//

#import "LYChartView.h"
@implementation LYChartView
{
    CGRect _frame;
    NSInteger _column;
    NSInteger _row;
    CGFloat _columnSpace;
    CGFloat _rowSpace;
    LYChartViewType _type;
    CGPoint _zeroPoint;
    CGFloat _width;
    CGFloat _height;
    UIEdgeInsets _edgeInsets;
    NSInteger _valueNum;
    NSArray *_valueDataAry;
    NSArray *_columnIndexAry;
    NSArray *_rowIndexAry;
    NSString *_title;
    NSString *_unit;
    void(^_distogramSelectAction)(NSInteger index);
    UIView *_view;
    NSTextAlignment _alignment;
    CGFloat _indexFont;
    CGFloat _titleFont;
    UIColor *(^_histogramColor)(NSInteger index,LYChartViewType type);
    UIColor *_fillColor;
    
    NSMutableArray *_histogramLayerAry;
    NSMutableArray *_histogramLayerHeightAry;
    NSMutableArray *_histogramLayerCurrentHeightAry;
    NSMutableArray *_histogramLayerIndexValueAry;
    CADisplayLink *_displayLink;
    
    
    CAShapeLayer *_lineLayer;
    CAShapeLayer *_chartOverstriking;
    NSMutableArray *_linePointAry;
    NSMutableArray *_lineCurrentPointAry;
    
    CGFloat _scale;
    
    BOOL _animation;
}
// 初始化创建方法
- (instancetype)initWithFrame:(CGRect)frame column:(NSInteger)column row:(NSInteger)row type:(LYChartViewType)type title:(NSString *)title unit:(NSString *)unit 
{
    self = [super initWithFrame:frame];
    if (self) {
        _animation = YES;
        if (title) {
            _edgeInsets = UIEdgeInsetsMake(35, 35, 30, 25);
            _titleFont = 12;
        }else {
            _edgeInsets = UIEdgeInsetsMake(20, 35, 30, 25);
        }
        _indexFont = 8;
        _fillColor = [[UIColor colorWithRed:24 / 255.0 green:171 / 255.0 blue:255 / 255.0 alpha:1.0] colorWithAlphaComponent:0.5];
        [self refreshArgument:frame valueNum:column row:row type:type title:title unit:unit alignment:NSTextAlignmentCenter];
    }
    return self;
}
// 更新下标字体大小
- (void)customIndexFont:(CGFloat)font{
    _indexFont = font;
}
// 更新标题字体大小
- (void)customTitleFont:(CGFloat)font{
    if (_title) {
        _edgeInsets = UIEdgeInsetsMake(_edgeInsets.top + (font - _titleFont), _edgeInsets.left, _edgeInsets.bottom, _edgeInsets.right);
        [self refreshArgument:_frame valueNum:_valueNum row:_row type:_type title:_title unit:_unit alignment:_alignment];
         _titleFont = font;
    }
}
// 更新参数
- (void)refreshArgument:(CGRect)frame valueNum:(NSInteger)valueNum row:(NSInteger)row type:(LYChartViewType)type title:(NSString *)title unit:(NSString *)unit alignment:(NSTextAlignment)alignment{
    _frame = frame;
    _row = row;
    _title = title;
    _unit = unit;
    _type = type;
    _valueNum = valueNum;
    _alignment = alignment;
    
    if (_type == LYChartViewTypeLine) {_column = _valueNum - 1;}
    if (_type == LYChartViewTypeHistogram) {_column = _valueNum;}
    _width = CGRectGetWidth(_frame) - _edgeInsets.left - _edgeInsets.right;
    _height = CGRectGetHeight(_frame) - _edgeInsets.top - _edgeInsets.bottom;
    _zeroPoint = CGPointMake(_edgeInsets.left,CGRectGetHeight(_frame) - _edgeInsets.bottom);
    _columnSpace = _width / _column;
    _rowSpace = _height / _row;
    
}
// 更改类型
- (void)customType:(LYChartViewType)type{
    [self refreshArgument:_frame valueNum:_valueNum row:_row type:type title:_title unit:_unit alignment:_alignment];
}
// 更新frame
- (void)customFrame:(CGRect)frame{
    [self refreshArgument:frame valueNum:_valueNum row:_row type:_type title:_title unit:_unit alignment:_alignment];
    self.frame = frame;
}
// 设置标题的位置
- (void)customTitleAlignment:(NSTextAlignment)alignment{
    [self refreshArgument:_frame valueNum:_valueNum row:_row type:_type title:_title unit:_unit alignment:alignment];
}
// 设置右上角图片视图
- (void)customRightTopView:(void(^)(UIView *view))action{
    if (action) {
        if (!_view) {
            _view = [[UIView alloc] initWithFrame:CGRectMake(2, 2, _frame.size.width - 4, 20)];
            _view.backgroundColor = [UIColor clearColor];
            [self addSubview:_view];
        }
        action(_view);
    }
}
// 设置列下标
- (void)customColumnIndexData:(NSArray *)data{
    if (data) {
        NSMutableArray *tempAry = [NSMutableArray array];
        for (id obj in data) {
            [tempAry addObject:[NSString stringWithFormat:@"%@",obj]];
        }
        _columnIndexAry = [NSArray arrayWithArray:tempAry];
    }
}
// 设置数据和行下标
- (void)customValueData:(NSArray *)data{
    if (data) {
        NSMutableArray *tempAry = [NSMutableArray array];
        for (id obj in data) {
            [tempAry addObject:[NSString stringWithFormat:@"%@",obj]];
        }
        _valueDataAry = [NSArray arrayWithArray:tempAry];
        CGFloat space_Value = [self spaceValue];
        NSMutableArray *rowIndexAry = [NSMutableArray array];
        for (int i = 0; i <= _row; i++) {
            NSInteger index = i * space_Value;
            [rowIndexAry addObject:[NSString stringWithFormat:@"%ld",index]];
        }
        _rowIndexAry = [NSArray arrayWithArray:rowIndexAry];
    }
}
// 设置内边距
- (void)customEdgeInsets:(UIEdgeInsets)edgeInsets{
    _edgeInsets = edgeInsets;
    [self refreshArgument:_frame valueNum:_valueNum row:_row type:_type title:_title unit:_unit alignment:_alignment];
}
// 更新柱状图填充颜色
- (void)customColor:(UIColor *(^)(NSInteger index,LYChartViewType type))color{
    if (color) {
        _histogramColor = color;
    }
}
// 刷新数据
- (void)reloadData{
    [self customSubViews];
}
// 开始布局
- (void)customSubViews{
    // 移除所有layer
    NSArray *tempAry = [NSArray arrayWithArray:self.layer.sublayers];
    for (CALayer *layer in tempAry) {
        [layer removeFromSuperlayer];
    }
    // 设置坐标轴
    [self customAxis];
    
    // 设置列和行线,以及遮盖
    [self customColumn_Row_CoverView];
    
    // 设置单位
    [self customUNITAndTitle];
    
    // 添加折线或者柱状图
    [self addChartOrHistogram:_animation];
    
    if (_view) {  // 防止上面的移除,会清楚掉这个view
        [self addSubview:_view];
    }
}
- (void)customAnimation:(BOOL)animation{
    _animation = animation;
}
// 添加折线或者柱状图
- (void)addChartOrHistogram:(BOOL)animation{
    CGFloat space_Value = [self spaceValue];
    _scale = space_Value / _rowSpace;  // 比例
    if (_type == LYChartViewTypeLine) {
        if (animation) {
            if (_displayLink) {
                [_displayLink invalidate];
                _displayLink = nil;
            }
            _displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(animationDisPlayLine)];
            [_displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:(NSDefaultRunLoopMode)];
            
        }
        NSMutableArray *pointAry = [NSMutableArray array];
        for (int i = 0; i < [_valueDataAry count]; i++) {
            CGPoint point  = CGPointMake(_zeroPoint.x + (i * _columnSpace),_zeroPoint.y - ([[_valueDataAry objectAtIndex:i] floatValue] / _scale));
            [pointAry addObject:[NSValue valueWithCGPoint:point]];
        }
        // 绘制折线
        if (_histogramColor) {
            _fillColor = _histogramColor(0,_type);
        }
        _lineLayer = nil;
        _linePointAry = [NSMutableArray arrayWithArray:pointAry];
        _lineCurrentPointAry = [NSMutableArray array];
        for (NSValue *value in pointAry) {
            CGPoint point = [value CGPointValue];
            point.y = _zeroPoint.y;
            [_lineCurrentPointAry addObject:[NSValue valueWithCGPoint:point]];
        }
        _lineLayer = [CAShapeLayer layer];
        _lineLayer.fillColor = _fillColor.CGColor;
        UIBezierPath *layerPath = [self createChartLayer:pointAry];
        _lineLayer.path = layerPath.CGPath;
     
        [self.layer addSublayer:_lineLayer];
        _chartOverstriking = [CAShapeLayer layer];
        _chartOverstriking.strokeColor = _fillColor.CGColor;
        _chartOverstriking.path = [self createChartOverstrikingLine:pointAry].CGPath;
        [self.layer addSublayer:_chartOverstriking];
        // 绘制圆点
        for (NSValue *pointValue in pointAry) {
            CAShapeLayer *dot = [self createDot:[pointValue CGPointValue] color:[UIColor colorWithRed:24 / 255.0 green:171 / 255.0 blue:255 / 255.0 alpha:1.0]];
            [self.layer addSublayer:dot];
        }
        // 绘制标记值
        BOOL adjust = NO;
        for (int i = 0;i < pointAry.count;i++) {
            if ((i == [_valueDataAry count] - 1) && ([[NSString stringWithFormat:@"%@",_valueDataAry[i]] length] > 5)) {
                adjust = YES;
            }
            CATextLayer *text = [self createValueLineTextLayer:[pointAry[i] CGPointValue] text:_valueDataAry[i] adjust:adjust];
            [self.layer addSublayer:text];
        }
    }
    if (_type == LYChartViewTypeHistogram) {
        if (animation) {
            if (_displayLink) {
                [_displayLink invalidate];
                _displayLink = nil;
            }
            _displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(animationDisPlayHistogram)];
            [_displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:(NSDefaultRunLoopMode)];
        }
        CGFloat width = _columnSpace - 2;
        _histogramLayerAry = [NSMutableArray array];
        _histogramLayerHeightAry = [NSMutableArray array];
        _histogramLayerCurrentHeightAry = [NSMutableArray array];
        _histogramLayerIndexValueAry = [NSMutableArray array];
        // 绘制柱状图
        for (int i = 0; i < [_valueDataAry count]; i++) {
            CGPoint point  = CGPointMake(_zeroPoint.x + (i * _columnSpace) + 1,_zeroPoint.y);
            UIColor *fillColor = nil;
            if (_histogramColor) {
                fillColor = _histogramColor(i,_type);
            }else {
                fillColor = _fillColor;
            }
            CAShapeLayer *layer = [CAShapeLayer layer];
            [_histogramLayerAry addObject:layer];
            [_histogramLayerHeightAry addObject:[NSNumber numberWithFloat:[[_valueDataAry objectAtIndex:i] floatValue] / _scale]];
            [_histogramLayerCurrentHeightAry addObject:@(0)];
            layer.fillColor = fillColor.CGColor;
            UIBezierPath *path = [self createHistogram:point width:width height:[[_valueDataAry objectAtIndex:i] floatValue] / _scale];
            layer.path = path.CGPath;
            [self.layer addSublayer:layer];
            
            CATextLayer *text = [self createValueHistogramLayer:CGPointMake(point.x + (width / 2.0), point.y - [[_valueDataAry objectAtIndex:i] floatValue] / _scale) text:_valueDataAry[i]];
            [_histogramLayerIndexValueAry addObject:text];
            if (animation) {
                text.opacity = 0;
            }else {
                text.opacity = 1;
            }
            [self.layer addSublayer:text];
        }
    }
}
// 动态更改折线路径
- (void)animationDisPlayLine{
    
    for (int i = 0; i < [_linePointAry count]; i++) {
        CGFloat last_y = [[_linePointAry objectAtIndex:i] CGPointValue].y;
        CGFloat current_y = [[_lineCurrentPointAry objectAtIndex:i] CGPointValue].y;
        CGFloat speed = (last_y - current_y) / 10;
        _lineCurrentPointAry[i] = [NSValue valueWithCGPoint:CGPointMake([_lineCurrentPointAry[i] CGPointValue].x, current_y + speed)];
    }
    UIBezierPath *linePath = [self createChartLayer:_lineCurrentPointAry];
    _lineLayer.path = linePath.CGPath;
    _chartOverstriking.path = [self createChartOverstrikingLine:_lineCurrentPointAry].CGPath;
    BOOL success = YES;
    for (int i = 0; i < [_lineCurrentPointAry count]; i++) {
        NSString *currentStr = [NSString stringWithFormat:@"%.2f",[[_lineCurrentPointAry objectAtIndex:i] CGPointValue].y];
        CGFloat current = [currentStr floatValue];
        NSString *lastStr = [NSString stringWithFormat:@"%.2f",[[_linePointAry objectAtIndex:i] CGPointValue].y];
        CGFloat last = [lastStr floatValue];
        if (current > last) {
            success = NO;
        }
    }
    if (success) {
        [_displayLink invalidate];
        _displayLink = nil;
        _linePointAry = nil;
        _lineCurrentPointAry = nil;
    }

}
// 动态更改路径
- (void)animationDisPlayHistogram{
    CGFloat width = _columnSpace - 2;
    for (int i = 0; i < [_histogramLayerCurrentHeightAry count]; i++) {
        CGFloat currentHeight = [_histogramLayerCurrentHeightAry[i] floatValue];
        CGFloat lastHeight = [_histogramLayerHeightAry[i] floatValue];
        CGFloat speed = ceilf((lastHeight - currentHeight) / 10);
        _histogramLayerCurrentHeightAry[i] = [NSNumber numberWithFloat:currentHeight + speed];
    }
    for (int i = 0; i < [_histogramLayerAry count]; i++) {
        CGPoint point  = CGPointMake(_zeroPoint.x + (i * _columnSpace) + 1,_zeroPoint.y);
        UIBezierPath *path = [self createHistogram:point width:width height:[_histogramLayerCurrentHeightAry[i] floatValue]];
        [[_histogramLayerAry objectAtIndex:i] setPath:path.CGPath];
    }
    BOOL success = YES;
    for (int i = 0; i < [_histogramLayerHeightAry count]; i++) {
        if ([[_histogramLayerCurrentHeightAry objectAtIndex:i] floatValue] < [[_histogramLayerHeightAry objectAtIndex:i] floatValue]) {
            success = NO;
        }
    }
    if (success) {
        [_displayLink invalidate];
        _displayLink = nil;
        for (CATextLayer *text in _histogramLayerIndexValueAry) {
            text.opacity = 1;
        }
        
        _histogramLayerAry = nil;
        _histogramLayerHeightAry = nil;
        _histogramLayerCurrentHeightAry = nil;
        _histogramLayerIndexValueAry = nil;
    }

}
// 获取数据最大值,并计算每一行间隔值
- (CGFloat)spaceValue{
    if ([_unit isEqualToString:@"%"]) {
        return 20;
    }
    CGFloat minValue = MAXFLOAT;
    CGFloat maxValue = -MAXFLOAT;
    for (int i = 0; i < [_valueDataAry count]; i++) {
        if ([_valueDataAry[i] floatValue] > maxValue) {
            maxValue = [_valueDataAry[i] floatValue];
        }
        if ([_valueDataAry[i] floatValue] < minValue) {
            minValue = [_valueDataAry[i] floatValue];
        }
    }
    int max = (int)[self getNumber:maxValue];
    CGFloat space_Value = 0;
    if (max >= 10) {
        NSInteger tenValue = 1;
        while (max / 10) {
            max = max / 10;
            tenValue *= 10;
        }
        space_Value = ceil((CGFloat)((max + 1) * tenValue) / _row);  // y轴间隔数值(真实数值)
    }
    else if (max >= 1 && max < 10) {
        space_Value = 2;
    }
    else if (max >= 0 && max < 1) {
        space_Value = 1;
    }
    if (space_Value == 0) {space_Value = 1;}
    return space_Value;
}
// 只取小数点之前的数字
- (CGFloat)getNumber:(CGFloat)value{
    NSString *string = [NSString stringWithFormat:@"%f",value];
    if (![[NSMutableString stringWithString:string] containsString:@"."]) {
        return value;
    }
    return [[[string componentsSeparatedByString:@"."] firstObject] floatValue];
}
// 设置单位和标题
- (void)customUNITAndTitle{
    if (_unit) {
        CATextLayer *textLayer = [self createTextUNITLayer:CGPointMake(_edgeInsets.left / 2.0, _zeroPoint.y - _height - 2) text:[NSString stringWithFormat:@"单位:%@",_unit]];
        [self.layer addSublayer:textLayer];
    }
    if (_title) {
        CATextLayer *textLayer = nil;
        if (_alignment == NSTextAlignmentCenter) {
            textLayer = [self createTitleLayer:CGPointMake(CGRectGetWidth(_frame) / 2.0, 2) text:_title];
        }
        if (_alignment == NSTextAlignmentLeft) {
            textLayer = [self createTitleLayer:CGPointMake(2, 2) text:_title];
        }
        if (_alignment == NSTextAlignmentRight) {
            textLayer = [self createTitleLayer:CGPointMake(CGRectGetWidth(_frame) - 2, 2) text:_title];
        }
        [self.layer addSublayer:textLayer];
    }
}
// 设置列和行线,以及遮盖
- (void)customColumn_Row_CoverView{
    // 设置列线
    for (int i = 1; i <= _column; i++) {
        CAShapeLayer *axisVertical = [self createVerticalLine:CGPointMake(_zeroPoint.x + (_columnSpace * i), _zeroPoint.y) height:_height color:[[UIColor lightGrayColor] colorWithAlphaComponent:0.1] lineWidth:0.5];
        [self.layer addSublayer:axisVertical];
    }
    // 设置下标数值
    for (int i = 0; i < [_columnIndexAry count]; i++) {
        if (_type == LYChartViewTypeLine) {
            CGPoint point = CGPointMake(_zeroPoint.x + (_columnSpace * i), _zeroPoint.y);
            CATextLayer *text = [self createTextLayer:point text:_columnIndexAry[i]];
            [self.layer addSublayer:text];
        }
        if (_type == LYChartViewTypeHistogram) {
            CGPoint point = CGPointMake(_zeroPoint.x + (_columnSpace * i) + _columnSpace / 2.0, _zeroPoint.y);
            CATextLayer *text = [self createTextLayer:point text:_columnIndexAry[i]];
            [self.layer addSublayer:text];
        }
    }
    // 设置水平线
    for (int i = 1; i <= _row; i++) {
        CAShapeLayer *axisHorizontal = [self createHorizontalLine:CGPointMake(_zeroPoint.x, _zeroPoint.y - (_rowSpace * i)) width:_width color:[[UIColor lightGrayColor] colorWithAlphaComponent:0.1] lineHeight:0.5];
        [self.layer addSublayer:axisHorizontal];
    }
    // 设置水平下标值
    for (int i = 1; i < [_rowIndexAry count]; i++) {
        CGPoint point = CGPointMake(_zeroPoint.x, _zeroPoint.y - (i * _rowSpace));
        NSString *text = [NSString stringWithFormat:@"%@",_rowIndexAry[i]];
        CATextLayer *textLayer = [self createHorizontalTextLayer:point text:text];
        [self.layer addSublayer:textLayer];
    }
    // 设置遮盖
    for (int i = 1; i <= _row; i++) {
        if (i % 2 != 0) {
            CAShapeLayer *coverLayer = [self createCoverViewPosition:CGPointMake(_zeroPoint.x, _zeroPoint.y - (_rowSpace * i)) width:_width height:_rowSpace color:[[UIColor lightGrayColor] colorWithAlphaComponent:0.05]];
            [self.layer addSublayer:coverLayer];
        }
    }
}
// 设置坐标轴
- (void)customAxis{
    UIColor *color = [UIColor lightGrayColor];
    CGFloat lineWidth = 1;
    // 创建X轴
    CAShapeLayer *axis_X = [self createHorizontalLine:_zeroPoint width:_width color:color lineHeight:lineWidth];
    [self.layer addSublayer:axis_X];
    
    // 创建Y轴
    CAShapeLayer *axis_Y = [self createVerticalLine:_zeroPoint height:_height color:color lineWidth:lineWidth];
    [self.layer addSublayer:axis_Y];
}
// 创建竖线
- (CAShapeLayer *)createVerticalLine:(CGPoint)bottomPoint height:(CGFloat)height color:(UIColor *)color lineWidth:(CGFloat)lineWidth{
    CAShapeLayer *line = [CAShapeLayer layer];
    line.bounds = CGRectMake(0, 0, lineWidth, height);
    line.position = CGPointMake(bottomPoint.x, bottomPoint.y - (height / 2.0));
    line.backgroundColor = color.CGColor;
    return line;
}
// 创建水平线
- (CAShapeLayer *)createHorizontalLine:(CGPoint)leftPoint width:(CGFloat)width color:(UIColor *)color lineHeight:(CGFloat)lineHeight{
    CAShapeLayer *line = [CAShapeLayer layer];
    line.bounds = CGRectMake(0, 0, width, lineHeight);
    line.position = CGPointMake(leftPoint.x + (width / 2.0), leftPoint.y);
    line.backgroundColor = color.CGColor;
    return line;
}
// 创建遮盖
- (CAShapeLayer *)createCoverViewPosition:(CGPoint)positionPoint width:(CGFloat)width height:(CGFloat)height color:(UIColor *)color{
    CAShapeLayer *layer = [CAShapeLayer layer];
    layer.bounds = CGRectMake(0, 0, width, height);
    layer.position = CGPointMake(positionPoint.x + (width / 2.0), positionPoint.y + (height / 2.0));
    layer.backgroundColor = color.CGColor;
    return layer;
}
// 创建折线
- (UIBezierPath *)createChartLayer:(NSArray<NSValue *> *)points{
    if (points && [points count]) {
        UIBezierPath *layerPath = [UIBezierPath bezierPath];
        [layerPath moveToPoint:[[points firstObject] CGPointValue]];
        for (int i = 1; i < points.count; i++) {
            [layerPath addLineToPoint:[points[i] CGPointValue]];
        }
        [layerPath addLineToPoint:CGPointMake([[points lastObject] CGPointValue].x, _zeroPoint.y)];
        [layerPath addLineToPoint:_zeroPoint];
        return layerPath;
    }
    return nil;
}
// 创建折线加粗线
- (UIBezierPath *)createChartOverstrikingLine:(NSArray<NSValue *> *)points{
    UIBezierPath *layerPath = [UIBezierPath bezierPath];
    [layerPath moveToPoint:[[points firstObject] CGPointValue]];
    for (int i = 1; i < points.count; i++) {
        [layerPath addLineToPoint:[points[i] CGPointValue]];
    }
    for (int i = (int)(points.count - 1); i > 0; i--) {
        [layerPath addLineToPoint:[points[i] CGPointValue]];
    }
    return layerPath;
}
// 创建圆点
- (CAShapeLayer *)createDot:(CGPoint)center color:(UIColor *)color{
    CAShapeLayer *dot = [CAShapeLayer layer];
    dot.bounds = CGRectMake(0, 0, 5, 5);
    dot.cornerRadius = 2.5;
    dot.position = center;
    dot.backgroundColor = color.CGColor;
    return dot;
}
// 创建柱状图
- (UIBezierPath *)createHistogram:(CGPoint)positionPoint width:(CGFloat)width height:(CGFloat)height{
    UIBezierPath *path = [UIBezierPath bezierPath];
    [path moveToPoint:CGPointMake(positionPoint.x , _zeroPoint.y)];
    [path addLineToPoint:CGPointMake(positionPoint.x + width, _zeroPoint.y)];
    [path addLineToPoint:CGPointMake(positionPoint.x + width, _zeroPoint.y - height)];
    [path addLineToPoint:CGPointMake(positionPoint.x, _zeroPoint.y - height)];
    return path;
}
// 创建下标标题
- (CATextLayer *)createTextLayer:(CGPoint)positionPoint text:(NSString *)text{
    CATextLayer *textLayer = [CATextLayer layer];
    CGRect rect = [self ly_rectWithSize:CGSizeMake(100, 100) attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:_indexFont]} forStr:text];
    textLayer.string = text;
    textLayer.foregroundColor = [UIColor lightGrayColor].CGColor;
    textLayer.position = CGPointMake(positionPoint.x, positionPoint.y + hypot(rect.size.width, rect.size.height) / 2.0 + 5);
    textLayer.fontSize = _indexFont;
    textLayer.bounds = CGRectMake(0, 0, rect.size.width, rect.size.height);
    textLayer.alignmentMode = kCAAlignmentCenter;
    textLayer.contentsScale = [[UIScreen mainScreen] scale];
    textLayer.transform = CATransform3DRotate(textLayer.transform, 1, 0, 0,(3.14159265359 * -20)/ 180);
    return textLayer;
}
// 获取字符串在指定区域的rect
- (CGRect)ly_rectWithSize:(CGSize)size attributes:(NSDictionary<NSString *,id> *)attributes forStr:(NSString *)string{
    NSStringDrawingOptions options =  NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading;
    CGRect rect = [string boundingRectWithSize:size options:options attributes:attributes context:nil];
    return rect;
}
// 创建横坐标标题
- (CATextLayer *)createHorizontalTextLayer:(CGPoint)positionPoint text:(NSString *)text{
    CATextLayer *textLayer = [CATextLayer layer];
    CGRect rect = [self ly_rectWithSize:CGSizeMake(100, 100) attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:_indexFont]} forStr:text];
    textLayer.string = text;
    textLayer.foregroundColor = [UIColor lightGrayColor].CGColor;
    textLayer.position = CGPointMake(positionPoint.x - (rect.size.width / 2.0) - 2, positionPoint.y + 5);
    textLayer.fontSize = _indexFont;
    textLayer.bounds = CGRectMake(0, 0, rect.size.width, rect.size.height);
    textLayer.alignmentMode = kCAAlignmentCenter;
    textLayer.contentsScale = [[UIScreen mainScreen] scale];
    return textLayer;
}
// 创建折线标记值
- (CATextLayer *)createValueLineTextLayer:(CGPoint)positionPoint text:(NSString *)text adjust:(BOOL)adjust{
    CATextLayer *textLayer = [CATextLayer layer];
    CGRect rect = [self ly_rectWithSize:CGSizeMake(100, 100) attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:_indexFont]} forStr:text];
    textLayer.string = text;
    textLayer.foregroundColor = [UIColor blackColor].CGColor;
    if (adjust) {
        textLayer.position = CGPointMake(positionPoint.x, positionPoint.y + (rect.size.height));
    }else {
        textLayer.position = CGPointMake(positionPoint.x + (rect.size.width / 4.5), positionPoint.y - (rect.size.height));
    }
    textLayer.fontSize = _indexFont;
    textLayer.bounds = CGRectMake(0, 0, rect.size.width, rect.size.height);
    textLayer.alignmentMode = kCAAlignmentCenter;
    textLayer.contentsScale = [[UIScreen mainScreen] scale];
    return textLayer;
}
// 绘制柱状图标记值
- (CATextLayer *)createValueHistogramLayer:(CGPoint)positionPoint text:(NSString *)text{
    CATextLayer *textLayer = [CATextLayer layer];
    CGRect rect = [self ly_rectWithSize:CGSizeMake(100, 100) attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:_indexFont]} forStr:text];
    textLayer.string = text;
    textLayer.foregroundColor = [UIColor blackColor].CGColor;
    textLayer.position = CGPointMake(positionPoint.x, positionPoint.y - (rect.size.height));
    textLayer.fontSize = _indexFont;
    textLayer.bounds = CGRectMake(0, 0, rect.size.width, rect.size.height);
    textLayer.alignmentMode = kCAAlignmentCenter;
    textLayer.contentsScale = [[UIScreen mainScreen] scale];
    return textLayer;
}
// 创建单位
- (CATextLayer *)createTextUNITLayer:(CGPoint)leftBottomPoint text:(NSString *)text{
    CATextLayer *textLayer = [CATextLayer layer];
    CGRect rect = [self ly_rectWithSize:CGSizeMake(100, 100) attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:_indexFont]} forStr:text];
    textLayer.string = text;
    textLayer.foregroundColor = [UIColor blackColor].CGColor;
    textLayer.position = CGPointMake(leftBottomPoint.x, leftBottomPoint.y - (rect.size.height / 2.0));
    textLayer.fontSize = _indexFont;
    textLayer.bounds = CGRectMake(0, 0, rect.size.width, rect.size.height);
    textLayer.alignmentMode = kCAAlignmentCenter;
    textLayer.contentsScale = [[UIScreen mainScreen] scale];
    return textLayer;
}
// 创建标题
- (CATextLayer *)createTitleLayer:(CGPoint)positionPoint text:(NSString *)text{
    CATextLayer *textLayer = [CATextLayer layer];
    CGRect rect = [self ly_rectWithSize:CGSizeMake(100, 100) attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:_titleFont]} forStr:text];
    textLayer.string = text;
    textLayer.foregroundColor = [UIColor blackColor].CGColor;
    if (_alignment == NSTextAlignmentCenter) {
        textLayer.position = CGPointMake(positionPoint.x, positionPoint.y + rect.size.height / 2.0);
    }
    if (_alignment == NSTextAlignmentLeft) {
        textLayer.position = CGPointMake(positionPoint.x + rect.size.width / 2.0, positionPoint.y + rect.size.height / 2.0);
    }
    if (_alignment == NSTextAlignmentRight) {
        textLayer.position = CGPointMake(positionPoint.x - rect.size.width / 2.0, positionPoint.y + rect.size.height / 2.0);
    }
    textLayer.fontSize = _titleFont;
    textLayer.bounds = CGRectMake(0, 0, rect.size.width, rect.size.height);
    textLayer.alignmentMode = kCAAlignmentCenter;
    textLayer.contentsScale = [[UIScreen mainScreen] scale];
    return textLayer;
}
- (void)histogramSelectAction:(void(^)(NSInteger index))action{
    if (action) {
        _distogramSelectAction = action;
    }
}
#pragma mark - 处理柱状图点击事件 -
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    UITouch *touch = [touches anyObject];
    if (_type == LYChartViewTypeHistogram) {
        CGPoint point = [touch preciseLocationInView:self];
        if ((point.x >= _zeroPoint.x) && (point.x <= (_zeroPoint.x + _width))) {
            if ((point.y <= _zeroPoint.y) && (point.y >= _edgeInsets.top)) {
                NSInteger index = (point.x - _zeroPoint.x) / _columnSpace;
                
                if (index < [_valueDataAry count]) {
                    if (_distogramSelectAction) {
                        _distogramSelectAction(index);
                    }
                }
                
            }
        }
    }
}
@end

github地址:
https://github.com/LYSBuildCode/LYChartView

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

推荐阅读更多精彩内容