1.折线统计图的绘制分析
折线统计图主要由x轴,y轴以及连接起来的虚线,绘制的点组成。
2.折线统计图的绘制
这里我主要是用CAShapeLayer 和 UIBezierPath 去绘制。
第一步先绘制x轴和y轴。
- (void)drawXAxisLine {
CAShapeLayer *layer = [CAShapeLayer layer];
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:CGPointMake(0, self.drawLineScrollView.height - BOTTOM_HEIGHT)];
[path addLineToPoint:CGPointMake(_xEveryWidth * (_statisticalModel.xTitleArray.count - 1), self.drawLineScrollView.height - BOTTOM_HEIGHT)];
layer.frame = CGRectMake(0, 0, self.drawLineScrollView.contentSize.width, self.drawLineScrollView.contentSize.height - BOTTOM_HEIGHT);
layer.path = path.CGPath;
layer.strokeColor = [UIColor grayColor].CGColor;
layer.lineWidth = 1;
layer.fillColor = nil;
[self.drawLineScrollView.layer addSublayer:layer];
for (int i = 0; i < _statisticalModel.xTitleArray.count; i ++) {
UILabel *label = [[UILabel alloc] init];
label.font = [UIFont systemFontOfSize:12];
label.textColor = [UIColor blackColor];
label.textAlignment = NSTextAlignmentCenter;
label.text = _statisticalModel.xTitleArray[i];
[label sizeToFit];
if (i == 0) {
label.x = [_xAxisPointArray[i] CGPointValue].x;
}else {
label.x = [_xAxisPointArray[i] CGPointValue].x - label.width / 2;
}
label.y = [_xAxisPointArray[i] CGPointValue].y + label.height / 2;
[self.drawLineScrollView addSubview:label];
}
}
- (void)drawYAxisLine {
CAShapeLayer *layer = [CAShapeLayer layer];
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:CGPointMake(LEFT_MARGIN, self.height - BOTTOM_HEIGHT)];
[path addLineToPoint:CGPointMake(LEFT_MARGIN, 0)];
layer.frame = CGRectMake(0, 0, self.width, self.height - BOTTOM_HEIGHT);
layer.path = path.CGPath;
layer.strokeColor = [UIColor grayColor].CGColor;
layer.lineWidth = 1;
layer.fillColor = nil;
[self.layer addSublayer:layer];
for (int i = 0; i < _statisticalModel.yTitleArray.count; i ++) {
UILabel *label = [[UILabel alloc] init];
label.font = [UIFont systemFontOfSize:12];
label.textColor = [UIColor blackColor];
label.textAlignment = NSTextAlignmentCenter;
label.text = _statisticalModel.yTitleArray[i];
[label sizeToFit];
label.x = [_yAxisPointArray[i] CGPointValue].x - label.width + LEFT_MARGIN - RIGHT_MARGIN / 4;
label.y = [_yAxisPointArray[i] CGPointValue].y - label.height / 2 - RIGHT_MARGIN / 5;
[self addSubview:label];
}
}
第二步,绘制虚线,将每个点连接起来
- (void)drawDottedLine {
CAShapeLayer *layer = [CAShapeLayer layer];
UIBezierPath *path = [UIBezierPath bezierPath];
for (int i = 0; i < _statisticalModel.yTitleArray.count; i ++) {
for (int j = 0; j < _statisticalModel.xTitleArray.count; j ++) {
[path moveToPoint:CGPointMake(0,i * _yEveryHeight)];
[path addLineToPoint:CGPointMake((_statisticalModel.xTitleArray.count - 1) * _xEveryWidth, i * _yEveryHeight)];
[path moveToPoint:CGPointMake(j * _xEveryWidth,self.height - BOTTOM_HEIGHT)];
[path addLineToPoint:CGPointMake(j * _xEveryWidth, 0)];
}
}
layer.frame = CGRectMake(0, 0, self.drawLineScrollView.contentSize.width, self.drawLineScrollView.contentSize.height);
layer.path = path.CGPath;
layer.strokeColor = [[UIColor lightGrayColor] colorWithAlphaComponent:0.5].CGColor;
layer.lineWidth = 0.5;
layer.lineDashPattern = @[@5,@5];
layer.fillColor = nil;
[self.drawLineScrollView.layer addSublayer:layer];
}
第三步,也是最为重要的转换坐标,计算单位1长度。根据所要描绘的点,首先拿到x轴和y轴的最大最小值,然后再计算每个点在坐标系中的位置,在iOS中,起点为(0,0)的点在视图的左上角,在坐标系中起点(0,0)在视图的左下角,所以这里要注意转换一下。
- (void)changePoint {
for (int i = 0; i < self.statisticalModel.pointArray.count; i ++) {
NSArray *pointArray = self.statisticalModel.pointArray[i];
CGFloat maxX = -MAXFLOAT;
CGFloat minX = MAXFLOAT;
CGFloat maxY = -MAXFLOAT;
CGFloat minY = MAXFLOAT;
// 转换坐标
NSMutableArray *pointMutArray = [NSMutableArray arrayWithCapacity:pointArray.count];
for (NSValue *value in pointArray) {
CGPoint point = [value CGPointValue];
if (point.x > maxX) {
maxX = point.x;
}
if (point.x < minX) {
minX = point.x;
}
if (point.y > maxY) {
maxY = point.y;
}
if (point.y < minY) {
minY = point.y;
}
CGFloat xUnitLong = [self getNumber:((maxX - minX) / (CGFloat)_statisticalModel.xTitleArray.count)];
CGFloat yUnitLong = [self getNumber:(maxY - minY) / (CGFloat)_statisticalModel.yTitleArray.count];
point.y = [self getNumber:self.height - BOTTOM_HEIGHT - point.y * yUnitLong * _yEveryHeight];
point.x = [self getNumber:point.x * xUnitLong * _xEveryWidth];
[pointMutArray addObject:[NSValue valueWithCGPoint:point]];
}
[self drawLineWithPointArray:pointMutArray withIndex:i];
}
}
第四部就是去画线。
- (void)drawLineWithPointArray:(NSArray *)pointArray withIndex:(NSInteger)index {
// 绘制
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:[pointArray[0] CGPointValue]];
for (int i = 1; i < pointArray.count; i ++) {
[path addLineToPoint:[pointArray[i] CGPointValue]];
}
CAShapeLayer *layer = [CAShapeLayer layer];
layer.frame = CGRectMake(0, 0, self.drawLineScrollView.contentSize.width, self.drawLineScrollView.contentSize.height);
layer.path = path.CGPath;
layer.strokeColor = (__bridge CGColorRef _Nullable)(self.statisticalModel.lineColors[index]);
layer.lineWidth = [self.statisticalModel.lineWidths[index] floatValue];
layer.fillColor = [UIColor clearColor].CGColor;
[self.drawLineScrollView.layer addSublayer:layer];
if (self.statisticalModel.colors.count > 0) {
[self fillColorWithPointArray:pointArray withIndex:index];
}
}
这里还有个方法就是填充颜色。
- (void)fillColorWithPointArray:(NSArray *)pointArray withIndex:(NSInteger)index {
// 绘制
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:[pointArray[0] CGPointValue]];
for (int i = 1; i < pointArray.count; i ++) {
[path addLineToPoint:[pointArray[i] CGPointValue]];
}
[path addLineToPoint:CGPointMake([pointArray.lastObject CGPointValue].x, self.drawLineScrollView.height - BOTTOM_HEIGHT)];
CAGradientLayer *gradientaLayer = [CAGradientLayer layer];
gradientaLayer.frame = CGRectMake(0, 0, self.drawLineScrollView.contentSize.width, self.drawLineScrollView.height - BOTTOM_HEIGHT);
gradientaLayer.locations = @[@0.5];
gradientaLayer.startPoint = CGPointMake(0, 0);
gradientaLayer.endPoint = CGPointMake(1, 0);
gradientaLayer.colors = self.statisticalModel.colors[index];
CAShapeLayer *layer = [CAShapeLayer layer];
layer.frame = CGRectMake(0, 0, self.drawLineScrollView.contentSize.width, self.drawLineScrollView.contentSize.height);
layer.path = path.CGPath;
gradientaLayer.mask = layer;
[self.drawLineScrollView.layer addSublayer:gradientaLayer];
}
核心的思路大概就是这些,具体想要看demo的同学请点击上方下载。
绘制效果如下: