You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

290 lines
12 KiB

//
// ZHLineChartView.m
// ZHLineChart
//
// Created by 周亚楠 on 2020/3/1.
// Copyright © 2020 Zhou. All rights reserved.
//
#import "ZHLineChartView.h"
#import "UIBezierPath+ThroughPointsBezier.h"
@interface ZHLineChartView ()
@property (nonatomic, strong) NSMutableArray *pointArr;
@end
@implementation ZHLineChartView
- (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
self.backgroundColor = [UIColor whiteColor];
self.circleRadius = 3.f;
self.lineWidth = 1.5f;
self.horizontalLineWidth = 0.5f;
self.horizontalBottomLineWidth = 1.f;
self.dataTextWidth = 20;
self.leftTextWidth = 25;
self.scaleOffset = 0.f;
self.showCalibration = YES;
self.bottomOffset = 20.f;
self.lineToLeftOffset = 5;
self.angle = M_PI * 1.75;
self.textFontSize = 10;
self.edge = UIEdgeInsetsMake(25, 5, 40, 15);
self.showKeyPoint = YES;
self.circleStrokeColor = KLineColor;
self.circleFillColor = [UIColor whiteColor];
self.textColor = KTextColor;
self.lineColor = KLineColor;
self.horizontalLineColor = KHorizontalLineColor;
self.horizontalBottomLineColor = KHorizontalBottomLineColor;
self.addCurve = YES;
self.toCenter = YES;
self.supplement = NO;
self.showLineData = YES;
self.showColorGradient = YES;
self.showHorizontalLine = YES;
self.horizontalLineStyle = 0;
self.showVerticalLine = YES;
self.verticalLineStyle = 0;
self.colorArr = [NSArray arrayWithObjects:(id)[[self.lineColor colorWithAlphaComponent:0.4] CGColor],(id)[[[UIColor whiteColor] colorWithAlphaComponent:0.1] CGColor], nil];
}
return self;
}
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
NSLog(@"开始触摸");
}
-(void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
UITouch* touch = [touches anyObject];
CGPoint currentPoint = [touch locationInView:self]; // 当前视图内的坐标
NSLog(@"移动的点 currentPointX: %f currentPointY: %f", currentPoint.x, currentPoint.y);
}
/**
* 渲染折线图
*/
- (void)drawLineChart
{
NSMutableArray *pointArr = [NSMutableArray array];
CGFloat labelHeight = self.textFontSize;
NSInteger numSpace = (self.max.integerValue - self.min.integerValue) / self.splitCount;
CGFloat spaceY = (self.frame.size.height - self.edge.top - self.edge.bottom - ((self.splitCount + 1) * labelHeight)) / self.splitCount;
CGFloat minMidY = 0.f;
CGFloat maxMidY;
for (int i = 0; i < self.splitCount + 1; i ++) {
//创建纵轴文本
UILabel *leftLabel = [[UILabel alloc] init];
leftLabel.frame = CGRectMake(self.edge.left, self.leftTextWidth + (spaceY + labelHeight) * i, self.leftTextWidth, labelHeight);
leftLabel.textColor = self.textColor;
leftLabel.textAlignment = NSTextAlignmentRight;
leftLabel.font = [UIFont systemFontOfSize:self.textFontSize];
NSInteger leftNum = self.max.integerValue - numSpace * i;
if (i == self.splitCount) {
leftNum = self.min.integerValue;
}
leftLabel.text = [NSString stringWithFormat:@"%ld",leftNum];
[self addSubview:leftLabel];
if (!i) {
minMidY = CGRectGetMidY(leftLabel.frame);
}
UIBezierPath *linePath = [UIBezierPath bezierPath];
CGFloat minX = CGRectGetMaxX(leftLabel.frame) + self.lineToLeftOffset;
CGFloat maxX = CGRectGetMaxX(self.frame) - self.edge.right;
[linePath moveToPoint:CGPointMake(minX, CGRectGetMidY(leftLabel.frame))];
[linePath addLineToPoint:CGPointMake(maxX, CGRectGetMidY(leftLabel.frame))];
CAShapeLayer *hLineLayer = [CAShapeLayer layer];
if (i == self.splitCount) {
hLineLayer.strokeColor = self.horizontalBottomLineColor.CGColor;
hLineLayer.lineWidth = self.horizontalBottomLineWidth;
CGFloat spaceX = (maxX - minX) / (self.horizontalDataArr.count - (self.toCenter ? 0 : 1));
maxMidY = CGRectGetMidY(leftLabel.frame);
if(self.showCalibration){ //是否需要刻度
//创建刻度
UIBezierPath *bezierPath = [UIBezierPath bezierPath];
NSInteger count = self.horizontalDataArr.count;
if (self.toCenter) {
count = self.horizontalDataArr.count + 1;
}
for (int j = 0 ; j < count; j ++) {
[bezierPath moveToPoint:CGPointMake(minX + spaceX * j, maxMidY + self.scaleOffset)];
[bezierPath addLineToPoint:CGPointMake(minX + spaceX * j, maxMidY + 2 + self.scaleOffset)];
[linePath appendPath:bezierPath];
}
}
//创建横轴文本
CGFloat bottomLabelWidth = spaceX + 20;
CGFloat ratio = (maxMidY - minMidY) / (self.max.floatValue - self.min.floatValue);
for (int k = 0; k < self.horizontalDataArr.count; k ++) {
CGFloat midX = minX + (spaceX * k) + (self.toCenter ? spaceX / 2 : 0);
UILabel *bottomLabel = [[UILabel alloc] init];
bottomLabel.frame = CGRectMake(midX - bottomLabelWidth / 2, maxMidY + self.bottomOffset, bottomLabelWidth, labelHeight);
bottomLabel.textColor = self.textColor;
bottomLabel.textAlignment = NSTextAlignmentCenter;
bottomLabel.font = [UIFont systemFontOfSize:self.textFontSize];
bottomLabel.text = self.horizontalDataArr[k];
[self addSubview:bottomLabel];
//旋转
bottomLabel.transform = CGAffineTransformMakeRotation(self.angle);
//构造关键点
NSNumber *tempNum = self.lineDataAry[k];
CGFloat y = maxMidY - (tempNum.integerValue - self.min.floatValue) * ratio;
if (self.toCenter && self.supplement && !k) {
NSValue *value = [NSValue valueWithCGPoint:CGPointMake(minX, y)];
[pointArr addObject:value];
}
NSValue *value = [NSValue valueWithCGPoint:CGPointMake(midX, y)];
[pointArr addObject:value];
if (self.toCenter && self.supplement && k == self.lineDataAry.count - 1) {
NSValue *value = [NSValue valueWithCGPoint:CGPointMake(maxX, y)];
[pointArr addObject:value];
}
}
//绘制折线
[self drawLineLayerWithPointArr:pointArr maxMidY:maxMidY];
} else {
hLineLayer.strokeColor = self.horizontalLineColor.CGColor;
hLineLayer.lineWidth = self.horizontalLineWidth;
}
hLineLayer.path = linePath.CGPath;
hLineLayer.fillColor = [UIColor clearColor].CGColor;
hLineLayer.lineCap = kCALineCapRound;
hLineLayer.lineJoin = kCALineJoinRound;
hLineLayer.contentsScale = [UIScreen mainScreen].scale;
[self.layer addSublayer:hLineLayer];
}
}
/**
* 绘制折线及渐变
*/
- (void)drawLineLayerWithPointArr:(NSMutableArray *)pointArr maxMidY:(CGFloat)maxMidY
{
CGPoint startPoint = [[pointArr firstObject] CGPointValue];
CGPoint endPoint = [[pointArr lastObject] CGPointValue];
UIBezierPath *linePath = [UIBezierPath bezierPath];
[linePath moveToPoint:startPoint];
if (self.addCurve) {
[linePath addBezierThroughPoints:pointArr];
} else {
[linePath addNormalBezierThroughPoints:pointArr];
}
CAShapeLayer *lineLayer = [CAShapeLayer layer];
lineLayer.path = linePath.CGPath;
lineLayer.strokeColor = self.lineColor.CGColor;
lineLayer.fillColor = [UIColor clearColor].CGColor;
lineLayer.lineWidth = self.lineWidth;
lineLayer.lineCap = kCALineCapRound;
lineLayer.lineJoin = kCALineJoinRound;
lineLayer.contentsScale = [UIScreen mainScreen].scale;
[self.layer addSublayer:lineLayer];
//颜色渐变
if (self.showColorGradient) {
UIBezierPath *colorPath = [UIBezierPath bezierPath];
colorPath.lineWidth = 1.f;
[colorPath moveToPoint:startPoint];
if (self.addCurve) {
[colorPath addBezierThroughPoints:pointArr];
} else {
[colorPath addNormalBezierThroughPoints:pointArr];
}
[colorPath addLineToPoint:CGPointMake(endPoint.x, maxMidY)];
[colorPath addLineToPoint:CGPointMake(startPoint.x, maxMidY)];
[colorPath addLineToPoint:CGPointMake(startPoint.x, startPoint.y)];
CAShapeLayer *bgLayer = [CAShapeLayer layer];
bgLayer.path = colorPath.CGPath;
bgLayer.frame = self.bounds;
CAGradientLayer *colorLayer = [CAGradientLayer layer];
colorLayer.frame = bgLayer.frame;
colorLayer.mask = bgLayer;
colorLayer.startPoint = CGPointMake(0, 0);
colorLayer.endPoint = CGPointMake(0, 1);
colorLayer.colors = self.colorArr;
[self.layer addSublayer:colorLayer];
}
// CABasicAnimation *maxPathAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
// maxPathAnimation.duration = 12;
// maxPathAnimation.repeatCount = 1;
// maxPathAnimation.removedOnCompletion = YES;
// maxPathAnimation.fromValue = @0.f;
// maxPathAnimation.toValue = @1;
// [maxLineLayer addAnimation:maxPathAnimation forKey:@"strokeEnd"];
//绘制关键折线及关键点
if(self.showKeyPoint){
[self buildDotWithPointsArr:pointArr];
}
}
/**
* 绘制关键点及关键点数据展示
*/
- (void)buildDotWithPointsArr:(NSMutableArray *)pointsArr
{
for (int i = 0; i < pointsArr.count; i ++) {
if (self.toCenter && self.supplement && (!i || i == pointsArr.count - 1)) {
continue;
}
NSValue *point = pointsArr[i];
//关键点绘制
UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:CGPointMake(point.CGPointValue.x, point.CGPointValue.y) radius:self.circleRadius startAngle:0 endAngle:M_PI * 2 clockwise:NO];
CAShapeLayer *circleLayer = [CAShapeLayer layer];
circleLayer.path = path.CGPath;
circleLayer.strokeColor = self.circleStrokeColor.CGColor;
circleLayer.fillColor = self.circleFillColor.CGColor;
circleLayer.lineWidth = self.lineWidth;
circleLayer.lineCap = kCALineCapRound;
circleLayer.lineJoin = kCALineJoinRound;
circleLayer.contentsScale = [UIScreen mainScreen].scale;
[self.layer addSublayer:circleLayer];
//关键点数据
if (self.showLineData) {
UILabel *numLabel = [[UILabel alloc] init];
numLabel.frame = CGRectMake(point.CGPointValue.x - self.dataTextWidth / 2, point.CGPointValue.y - 18, self.dataTextWidth, self.textFontSize);
numLabel.textColor = self.textColor;
numLabel.textAlignment = NSTextAlignmentRight;
numLabel.font = [UIFont systemFontOfSize:self.textFontSize];
NSInteger index = i;
if (self.toCenter && self.supplement) {
index = i - 1;
}
numLabel.text = [NSString stringWithFormat:@"%@",self.lineDataAry[index]];
[self addSubview:numLabel];
}
}
}
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect {
// Drawing code
}
*/
@end