美文网首页iOS点点滴滴iOS Developer
LMChartView-曲线,折线,柱状图

LMChartView-曲线,折线,柱状图

作者: Cooci_和谐学习_不急不躁 | 来源:发表于2018-01-09 12:24 被阅读70次
    效果图.png

    Demo源码: LMChartView

    看完前任3,最大感悟: 初闻不识曲中意,再听已是曲中人

    浮世三千,吾爱有三:日,月与卿。日为朝,月为暮,卿为朝朝暮暮.

    大家都知道:男人越来越值钱,殊不知你爱的女人:越来越沧桑.,在这个不相信眼泪的城市,不停的打拼.你说都是为了她而奋斗,但是没有了她你就不奋斗了;你说再过几年就回去,再过几年,你难道不知道这几年是你们最为青春年少,芳华绝代的年纪,既然你做好回去的打算,而她也无心来这个钢铁混凝土的城市,何不加快你的脚步,在这美好的时间,彼此厮守.你说现在买房买车压力大,小城市没有高工资,没有工作机会.没错,但是你们的终极目标,是幸福生活.正如一个故事:http://video.tudou.com/v/XMTc4NTgyOTg0NA==.html.

    悟已往之不谏,知来者之可追,实迷途其未远,觉今是而昨非


    现在来说一下,这个Demo主要纪念我之前不怎么认真的地方,遇到图标都是找的第三方:
    Charts
    GRMustache
    ZFChart
    chartee
    ...

    这个demo就根据项目需求,自定义写得,完全利用UIBezierPath画图:

    pragma mark -坐标系的X,Y都是通过一条一条线画成

    - (void)drawVerticalLine {
        //画竖线
        NSInteger spaceCount = self.shuXianAccount - 1;
        CGFloat space = HorizontalLineW / spaceCount;
        CGFloat startX;
        CGFloat startY;
        CGFloat endX;
        CGFloat endY;
        CGFloat lineW;
        UIColor *lineColor;
        
        for (NSInteger i = 1; i <= self.shuXianAccount; i ++) {
            if (i == 1) {
                lineW = Fix375(2);
                lineColor = Col_0x77cecd;
                startY = Fix375(7);
                endY = LineStartY + VerticalLineH + lineW / 2;
            } else {
                lineW = Fix375(1);
                lineColor = UIColorFromRGB(0xf5f5f5);
                startY = LineStartY;
                endY = LineStartY + VerticalLineH;
            }
            startX = LineStartX + (i - 1) * space - lineW / 2;
            endX = LineStartX + (i - 1) * space - lineW / 2;
            
            CGPoint startPoint = CGPointMake(startX, startY);
            CGPoint endPoint = CGPointMake(endX, endY);
            
            [self drawLineWithContext:context startPoint:startPoint endPoint:endPoint lineColor:lineColor lineWidth:lineW];
            
        }
        
        //X轴文字
        CGFloat textX;
        CGFloat textY;
        CGFloat textW;
        CGFloat textH;
        
        for (NSInteger i = 1; i <= self.xTitlesArr.count; i++) {
            UIColor *textColor;
            if (i == self.xTitlesArr.count) {
                textColor = Col_0x77cecd;
            } else {
                textColor = Col_0x999999;
            }
            
            NSString *xTitleStr = self.xTitlesArr[i - 1];
            NSDictionary *attDic = @{NSFontAttributeName : [UIFont systemFontOfSize:Fix375(9)],
                                     NSForegroundColorAttributeName:textColor};
            CGSize xTitleStrSize = [xTitleStr sizeWithAttributes:attDic];
            
            CGFloat textSpace =   HorizontalLineW / (self.xTitlesArr.count - 1);
            
            textX = LineStartX + (i - 1) * textSpace - xTitleStrSize.width / 2;
            textY = LineStartY + VerticalLineH + Fix375(5);
            textW = xTitleStrSize.width;
            textH = xTitleStrSize.height;
            
            CGRect xTitleStrRect = CGRectMake(textX ,textY , textW,textH);
            
            [xTitleStr drawInRect:xTitleStrRect withAttributes:attDic];
        }
        
        NSString *danwei;
        if (self.timeType == USkinTimeTypeDay) {
            danwei = @"(h)";
        } else {
            danwei = @"(d)";
        }
        
        NSDictionary *danweiAttDic = @{NSFontAttributeName : [UIFont systemFontOfSize:Fix375(9)],
                                       NSForegroundColorAttributeName:Col_0x999999};
        CGSize danweiStrSize = [danwei sizeWithAttributes:danweiAttDic];
        CGFloat textSpace =   HorizontalLineW / (self.xTitlesArr.count - 1);
    
        textX = LineStartX + (self.xTitlesArr.count - 1) * textSpace - danweiStrSize.width / 2 + Fix375(17);
        textY = LineStartY + VerticalLineH + Fix375(5);
        textW = danweiStrSize.width;
        textH = danweiStrSize.height;
        
        CGRect danweiRect = CGRectMake(textX, textY,textW, textH);
        [danwei drawInRect:danweiRect withAttributes:danweiAttDic];
        
      }
    

    横线和竖线一样的原理

    pragma mark - 画箭头

    - (void)drawXArrowWithContext:(CGContextRef)context{
        UIBezierPath *xArrowPath = [self xArrrowPath];
        CGContextSetAllowsAntialiasing(context, YES);
        CGContextSetFillColorWithColor(context, Col_0x77cecd.CGColor);
        CGContextSetLineWidth(context, 1);
        CGContextAddPath(context, xArrowPath.CGPath);
        CGContextDrawPath(context, kCGPathFill);
    }
    - (void)drawYArrowWithContext:(CGContextRef)context {
        UIBezierPath *xArrowPath = [self yArrrowPath];
        CGContextSetAllowsAntialiasing(context, YES);
        CGContextSetFillColorWithColor(context, Col_0x77cecd.CGColor);
        CGContextSetLineWidth(context, 1);
        CGContextAddPath(context, xArrowPath.CGPath);
        CGContextDrawPath(context, kCGPathFill);
    }
    - (UIBezierPath *)xArrrowPath {
        UIBezierPath *path = [UIBezierPath bezierPath];
        CGPoint topPoint = CGPointMake(LineStartX + HorizontalLineW + Fix375(11) - Fix375(3), LineStartY + VerticalLineH - Fix375(4) + Fix375(1));
        CGPoint centerPoint = CGPointMake(LineStartX + HorizontalLineW + Fix375(11), LineStartY + VerticalLineH + Fix375(1));
        CGPoint bottomPoint = CGPointMake(LineStartX + HorizontalLineW + Fix375(11) - Fix375(3), LineStartY + VerticalLineH + Fix375(4) + Fix375(1));
        CGPoint rightPoint = CGPointMake(LineStartX + HorizontalLineW + Fix375(11) + Fix375(10), LineStartY + VerticalLineH + Fix375(1));
        
        
        [path moveToPoint:topPoint];
        [path addLineToPoint:centerPoint];
        [path addLineToPoint:bottomPoint];
        [path addLineToPoint:rightPoint];
        [path addLineToPoint:topPoint];
        
        return path;
    }
    - (UIBezierPath *)yArrrowPath {
        UIBezierPath *path = [UIBezierPath bezierPath];
        CGPoint topPoint = CGPointMake(LineStartX - Fix375(1), 0);
        CGPoint leftPoint = CGPointMake(LineStartX - Fix375(1)  - Fix375(4), Fix375(10));
        CGPoint centerPoint = CGPointMake(LineStartX - Fix375(1) , Fix375(10) - Fix375(3));
        CGPoint rightPoint = CGPointMake(LineStartX - Fix375(1) + Fix375(4),Fix375(10));
        
        [path moveToPoint:topPoint];
        [path addLineToPoint:leftPoint];
        [path addLineToPoint:centerPoint];
        [path addLineToPoint:rightPoint];
        [path addLineToPoint:topPoint];
        
        return path;
    }
    

    无论画坐标还是三角形还有标度都是利用:UIBezierPath的基本用法:moveToPoint,addLineToPoint,drawInRect

    接下来根据数据画图,还是基本用法

    - (UIBezierPath *)linePathWihtYvalueArr:(NSArray *)yValueArr {
        UIBezierPath *path = [UIBezierPath bezierPath];
        for (NSInteger i = 0; i < yValueArr.count; i++) {
            CGPoint onePoint = [self linePointWithYvalue:yValueArr[i]  index:i];
            if (i == 0) {
                [path moveToPoint:onePoint];
            } else {
                [path addLineToPoint:onePoint];
            }
        }
        return path;
    }
    

    下面是填充,制作渐变效果

    -(void)setGradientColor {
        UIBezierPath *linePath = [self fillPathWihtYvalueArr:self.yValuesArr];
        CAShapeLayer *shapeLayer = [CAShapeLayer layer];
        shapeLayer.fillColor = [UIColor whiteColor].CGColor;
        shapeLayer.strokeColor = Col_0x77cecd.CGColor;
        shapeLayer.path = linePath.CGPath;
        shapeLayer.lineWidth = 1.0f;
        
        CAGradientLayer *gradientLayer = [CAGradientLayer layer];
        gradientLayer.frame = CGRectMake(0, 0, self.width, self.height);
        [gradientLayer setColors:[NSArray arrayWithObjects:(id)Col_0x77cecd.CGColor,(id)Col_0xffffff.CGColor, nil]];
        gradientLayer.locations = @[@0, @1.0];
        gradientLayer.borderWidth  = 0.1;
        [gradientLayer setMask:shapeLayer];
        
        [self.layer addSublayer:gradientLayer];
    }
    

    中间写得还是比较仔细,尽量封装

    外部使用

      NSArray *array = @[@"0",@"1",@"2",@"3",@"4",@"5",@"6",@"7",@"8",@"9",@"10",@"11",@"12",@"13",@"14",@"15",@"16",@"17",@"18",@"19",@"20",@"21",@"22",@"23"];
    
    LMChartView1 *chart = [[LMChartView1 alloc] initWithXtitlesArr:array yTilesArr:nil timeType:USkinTimeTypeDay];
    chart.backgroundColor = Col_0xffffff;
    NSMutableArray *yValuesArr = @[@"0.1",@"0.11",@"0.2",@"0.23",@"0.54",@"0.5",@"0.46",@"0.37",@"0.68",@"0.9",@"0.51",@"0.11",@"0.12",@"0.13",@"0.14",@"0.15",@"0.16",@"0.17",@"0.18",@"0.19",@"0.32",@"0.21",@"0.12",@"0.02"].mutableCopy;
    chart.frame = CGRectMake(0, 100, self.view.bounds.size.width,  Fix375(212));
    [chart fillDataWithArr:yValuesArr];
    [self.view addSubview:chart];
    

    针对曲线,我写了一个分类,因为画曲线:addCurveToPoint , addQuadCurveToPoint

    贝塞尔曲线的画法是由起点、终点、控制点三个参数来画的.

    我很随意的定义了三个点,为了清楚显示它们的位置,我放了三个矩形在上面以便观察,然后调用 path.moveToPoint(startPoint) 让它移动到起始点,然后调用path.addQuadCurveToPoint(endPoint, controlPoint: controlPoint) 这个方法告诉它结束点和控制点,这样它就能画出一条有弧度的线条了,如果把fillColor设置一个颜色,那么它就会变成一个很丑的形状了,示例图如下

    三点画曲线.png

    控制点决定了它的曲率,曲线的顶点不等于控制点的位置,具体可以看一下贝塞尔曲线的定义,你还可以使用两个控制点来画,两个控制点可以使用方法 path.addCurveToPoint(endPoint, controlPoint1: controlPoint, controlPoint2: controlPoint2)来搞定

    两个控制点来画.png

    这个分类添加曲度和 三点控制,四点控制

    -(void)addBezierThroughPoints:(NSArray *)pointArray
        {
            NSAssert(pointArray.count > 0, @"没有点");
            
            if (pointArray.count < 3) {
                switch (pointArray.count) {
                    case 1:
                    {
                        NSValue * point0Value = pointArray[0];
                        CGPoint point0 = [point0Value CGPointValue];
                        [self addLineToPoint:point0];
                    }
                        break;
                    case 2:
                    {
                        NSValue * point0Value = pointArray[0];
                        CGPoint point0 = [point0Value CGPointValue];
                        NSValue * point1Value = pointArray[1];
                        CGPoint point1 = [point1Value CGPointValue];
                        [self addQuadCurveToPoint:point1 controlPoint:ControlPointForTheBezierCanThrough3Point(self.currentPoint, point0, point1)];
                    }
                        break;
                    default:
                        break;
                }
            }
            
            CGPoint previousPoint = CGPointZero;
            
            CGPoint previousCenterPoint = CGPointZero;
            CGPoint centerPoint = CGPointZero;
            CGFloat centerPointDistance = 0;
            
            CGFloat obliqueRatio = 0;
            CGFloat obliqueAngle = 0;
            
            CGPoint previousControlPoint1 = CGPointZero;
            CGPoint previousControlPoint2 = CGPointZero;
            CGPoint controlPoint1 = CGPointZero;
            
            previousPoint = self.currentPoint;
            
            for (int i = 0; i < pointArray.count; i++) {
                
                NSValue * pointIValue = pointArray[I];
                CGPoint pointI = [pointIValue CGPointValue];
                
                if (i > 0) {
                    
                    previousCenterPoint = CenterPointOf(self.currentPoint, previousPoint);
                    centerPoint = CenterPointOf(previousPoint, pointI);
                    
                    centerPointDistance = DistanceBetweenPoint(previousCenterPoint, centerPoint);
                    
                    if (previousCenterPoint.x != centerPoint.x) {
                        
                        obliqueRatio = (centerPoint.y - previousCenterPoint.y) / (centerPoint.x - previousCenterPoint.x);
                        obliqueAngle = atan(obliqueRatio);
                    }
                    else {
                        obliqueAngle = M_PI_2;
                    }
                    
                    previousControlPoint2 = CGPointMake(previousPoint.x - 0.5 * self.contractionFactor * centerPointDistance * cos(obliqueAngle), previousPoint.y - 0.5 * self.contractionFactor * centerPointDistance * sin(obliqueAngle));
                    controlPoint1 = CGPointMake(previousPoint.x + 0.5 * self.contractionFactor * centerPointDistance * cos(obliqueAngle), previousPoint.y + 0.5 * self.contractionFactor * centerPointDistance * sin(obliqueAngle));
                }
                
                if (i == 1) {
                    
                    [self addQuadCurveToPoint:previousPoint controlPoint:previousControlPoint2];
                }
                else if (i > 1 && i < pointArray.count - 1) {
                    
                    [self addCurveToPoint:previousPoint controlPoint1:previousControlPoint1 controlPoint2:previousControlPoint2];
                }
                else if (i == pointArray.count - 1) {
                    
                    [self addCurveToPoint:previousPoint controlPoint1:previousControlPoint1 controlPoint2:previousControlPoint2];
                    [self addQuadCurveToPoint:pointI controlPoint:controlPoint1];
                }
                else {
                    
                }
                
                previousControlPoint1 = controlPoint1;
                previousPoint = pointI;
            }
        }
    

    感谢大家的支持,以后会尽量更多干货.
    最后愿祝大家:有情人终成眷属,幸福永康

    相关文章

      网友评论

        本文标题:LMChartView-曲线,折线,柱状图

        本文链接:https://www.haomeiwen.com/subject/gbzbnxtx.html