欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

iOS 折线图、柱状图的简单实现

程序员文章站 2022-06-05 14:33:52
首先我得感谢某位博主,非常抱歉,因为之前直接下载博主提供这篇文章的demo,然后去研究了,没记住博主的名字。再次非常感谢。 而这个dome我又修改了一些,完善了一些不美观的bug,当然还有,后面会陆续更新。 1 、一开始需要给坐标轴初始一个画布 2、然后画坐标轴,包括x、y轴的直线、箭头、字符串的索 ......

首先我得感谢某位博主,非常抱歉,因为之前直接下载博主提供这篇文章的demo,然后去研究了,没记住博主的名字。再次非常感谢。

而这个dome我又修改了一些,完善了一些不美观的bug,当然还有,后面会陆续更新。

1 、一开始需要给坐标轴初始一个画布

//初始化画布
+(instancetype)initwithframe:(cgrect)frame{
    //找到名称叫beziercurveview的xib视图
    beziercurveview *beziercurveview = [[nsbundle mainbundle] loadnibnamed:@"beziercurveview" owner:self options:nil].lastobject;
    beziercurveview.frame = frame;
    
    //背景视图
    uiview *backview = [[uiview alloc] initwithframe:cgrectmake(0, 0, frame.size.width, frame.size.height)];
    backview.backgroundcolor = xyqcolor(255, 229, 239);
    [beziercurveview addsubview:backview];
    
    myframe = frame;
    return beziercurveview;
}

2、然后画坐标轴,包括x、y轴的直线、箭头、字符串的索引、路径的渲染。

/**
 *  画坐标轴
 */
-(void)drawxyline:(nsmutablearray *)x_names adddistancevalues:(nsinteger )adddistance startingvalues:(nsinteger)starting proportionvaluess:(nsinteger)proportion{
    
    uibezierpath *path = [uibezierpath bezierpath];
    
    //1.y轴、x轴的直线
    [path movetopoint:cgpointmake(margin+adddistance, cgrectgetheight(myframe)-margin)];
    [path addlinetopoint:cgpointmake(margin+adddistance, margin)];
    
    [path movetopoint:cgpointmake(margin+adddistance, cgrectgetheight(myframe)-margin)];
    [path addlinetopoint:cgpointmake(margin+cgrectgetwidth(myframe)-2*margin+adddistance, cgrectgetheight(myframe)-margin)];
    
    //2.添加箭头
    [path movetopoint:cgpointmake(margin+adddistance, margin)];
    [path addlinetopoint:cgpointmake(margin-5+adddistance, margin+5)];
    [path movetopoint:cgpointmake(margin+adddistance, margin)];
    [path addlinetopoint:cgpointmake(margin+5+adddistance, margin+5)];
    
    [path movetopoint:cgpointmake(margin+cgrectgetwidth(myframe)-2*margin+adddistance, cgrectgetheight(myframe)-margin)];
    [path addlinetopoint:cgpointmake(margin+cgrectgetwidth(myframe)-2*margin-5+adddistance, cgrectgetheight(myframe)-margin-5)];
    [path movetopoint:cgpointmake(margin+cgrectgetwidth(myframe)-2*margin+adddistance, cgrectgetheight(myframe)-margin)];
    [path addlinetopoint:cgpointmake(margin+cgrectgetwidth(myframe)-2*margin-5+adddistance, cgrectgetheight(myframe)-margin+5)];

    //3.添加索引格
    //x轴
    for (int i=0; i<x_names.count; i++) {
        cgfloat x = margin + margin*(i+1);
        cgpoint point = cgpointmake(x+adddistance,cgrectgetheight(myframe)-margin);
        [path movetopoint:point];
        [path addlinetopoint:cgpointmake(point.x, point.y-3)];
    }
    //y轴(实际长度为200,此处比例缩小一倍使用)
    for (int i=0; i<11; i++) {
        cgfloat y = cgrectgetheight(myframe)-margin-y_every_margin*i;
        cgpoint point = cgpointmake(margin+adddistance,y);
        [path movetopoint:point];
        [path addlinetopoint:cgpointmake(point.x+3, point.y)];
    }
    
    //4.添加索引格文字
    //x轴
    for (int i=0; i<x_names.count+1; i++) {
        cgfloat x = margin + 15 + margin*i;
        uilabel *textlabel = [[uilabel alloc] initwithframe:cgrectmake(x+adddistance, cgrectgetheight(myframe)-margin, margin, 20)];
        if(i < x_names.count){
            textlabel.text = x_names[i];
        }
        else{
            textlabel.text = @"年/月";
        }
        textlabel.font = [uifont systemfontofsize:10];
        textlabel.textalignment = nstextalignmentcenter;
        textlabel.textcolor = [uicolor bluecolor];
        [self addsubview:textlabel];
        
    }
    
    //y轴
    for (int i=0; i<11; i++) {
        cgfloat y = cgrectgetheight(myframe)-margin-y_every_margin*i;
        uilabel *textlabel = [[uilabel alloc] initwithframe:cgrectmake(0, y-5, margin+adddistance, 10)];
        textlabel.text = [nsstring stringwithformat:@"%ld",starting+proportion*10*i];
        textlabel.font = [uifont systemfontofsize:10];
        textlabel.textalignment = nstextalignmentcenter;
        textlabel.textcolor = [uicolor redcolor];
        [self addsubview:textlabel];
    }

    //5.渲染路径
    cashapelayer *shapelayer = [cashapelayer layer];
    shapelayer.path = path.cgpath;
    shapelayer.strokecolor = [uicolor blackcolor].cgcolor;
    shapelayer.fillcolor = [uicolor clearcolor].cgcolor;
    shapelayer.borderwidth = 2.0;
    [self.subviews[0].layer addsublayer:shapelayer];
}

3、实现的方法

/**
 *  画折线图
 *  @param x_names      x轴值的所有值名称
 *  @param targetvalues 所有目标值
 *  @param linetype     直线类型
 *  @param adddistance  y轴的字符串长度的增加距离
 *  @param starting     坐标轴原点的大小数值
 *  @param proportion   y轴上的数值比例差为10的倍数
 */
-(void)drawlinechartviewwithx_value_names:(nsmutablearray *)x_names targetvalues:(nsmutablearray *)targetvalues linetype:(linetype) linetype adddistancevalues:(nsinteger )adddistance  startingvalues:(nsinteger)starting proportionvaluess:(nsinteger)proportion;
/**
 *  画柱状图
 *  @param x_names      x轴值的所有值名称
 *  @param targetvalues 所有目标值
 *  @param adddistance  y轴的字符串长度的增加距离
 *  @param starting     坐标轴原点的大小数值
 *  @param proportion   y轴上的数值比例差为10的倍数
 */
-(void)drawbarchartviewwithx_value_names:(nsmutablearray *)x_names targetvalues:(nsmutablearray *)targetvalues adddistancevalues:(nsinteger )adddistance  startingvalues:(nsinteger)starting proportionvaluess:(nsinteger)proportion;

4、折线图的实现

/**
 *  画折线图
 */
-(void)drawlinechartviewwithx_value_names:(nsmutablearray *)x_names targetvalues:(nsmutablearray *)targetvalues linetype:(linetype) linetype adddistancevalues:(nsinteger )adddistance  startingvalues:(nsinteger)starting proportionvaluess:(nsinteger)proportion{
    
    //1.画坐标轴
    [self drawxyline:x_names adddistancevalues:adddistance startingvalues:starting proportionvaluess:proportion];
    nsmutablearray * targetvalues1 =[[nsmutablearray alloc]init];
    for (int i=0; i<targetvalues.count; i++  ){
        cgfloat coed =[targetvalues[i] integervalue];
        [targetvalues1 addobject:@((coed-starting)/proportion)];

    }
   
    //2.获取目标值点坐标
    nsmutablearray *allpoints = [nsmutablearray array];
    for (int i=0; i<targetvalues1.count; i++) {
        cgfloat doublevalue = 2*[targetvalues1[i] floatvalue]; //目标值放大两倍
        cgfloat x = margin+adddistance + margin*(i+1);
        cgfloat y = cgrectgetheight(myframe)-margin-doublevalue;
        cgpoint point = cgpointmake(x,y);
        uibezierpath *path = [uibezierpath bezierpathwithroundedrect:cgrectmake(point.x-1, point.y-1, 2.5, 2.5) cornerradius:2.5];
        cashapelayer *layer = [cashapelayer layer];
        layer.strokecolor = [uicolor purplecolor].cgcolor;
        layer.fillcolor = [uicolor purplecolor].cgcolor;
        layer.path = path.cgpath;
        [self.subviews[0].layer addsublayer:layer];
        [allpoints addobject:[nsvalue valuewithcgpoint:point]];
    }

    //3.坐标连线
    uibezierpath *path = [uibezierpath bezierpath];
    [path movetopoint:[allpoints[0] cgpointvalue]];
    cgpoint preponit;
    switch (linetype) {
        case linetype_straight: //直线
            for (int i =1; i<allpoints.count; i++) {
                cgpoint point = [allpoints[i] cgpointvalue];
                [path addlinetopoint:point];
            }
            break;
        case linetype_curve:   //曲线
            for (int i =0; i<allpoints.count; i++) {
                if (i==0) {
                    preponit = [allpoints[0] cgpointvalue];
                }else{
                    cgpoint nowpoint = [allpoints[i] cgpointvalue];
                    [path addcurvetopoint:nowpoint controlpoint1:cgpointmake((preponit.x+nowpoint.x)/2, preponit.y) controlpoint2:cgpointmake((preponit.x+nowpoint.x)/2, nowpoint.y)]; //三次曲线
                    preponit = nowpoint;
                }
            }
            break;
    }
    cashapelayer *shapelayer = [cashapelayer layer];
    shapelayer.path = path.cgpath;
    shapelayer.strokecolor = [uicolor greencolor].cgcolor;
    shapelayer.fillcolor = [uicolor clearcolor].cgcolor;
    shapelayer.borderwidth = 2.0;
    [self.subviews[0].layer addsublayer:shapelayer];
    
    //4.添加目标值文字
    for (int i =0; i<allpoints.count; i++) {
        uilabel *label = [[uilabel alloc] init];
        label.textcolor = [uicolor purplecolor];
        label.textalignment = nstextalignmentcenter;
        label.font = [uifont systemfontofsize:10];
        [self.subviews[0] addsubview:label];
        
        if (i==0) {
            cgpoint nowpoint = [allpoints[0] cgpointvalue];
            label.text = [nsstring stringwithformat:@"%.0lf",starting+proportion*(cgrectgetheight(myframe)-nowpoint.y-margin)/2];
            label.frame = cgrectmake(nowpoint.x-margin/2, nowpoint.y-20, margin+adddistance, 20);
            preponit = nowpoint;
        }else{
            cgpoint nowpoint = [allpoints[i] cgpointvalue];
            if (nowpoint.y<preponit.y) {  //文字置于点上方
                label.frame = cgrectmake(nowpoint.x-margin/2, nowpoint.y-20, margin+adddistance, 20);
            }else{ //文字置于点下方
                label.frame = cgrectmake(nowpoint.x-margin/2, nowpoint.y, margin+adddistance, 20);
            }
            
            label.text = [nsstring stringwithformat:@"%.0lf",starting+proportion*(cgrectgetheight(myframe)-nowpoint.y-margin)/2];
       
            preponit = nowpoint;
        }
    }
}

5、柱状图的实现

/**
 *  画柱状图
 */
-(void)drawbarchartviewwithx_value_names:(nsmutablearray *)x_names targetvalues:(nsmutablearray *)targetvalues adddistancevalues:(nsinteger )adddistance  startingvalues:(nsinteger)starting proportionvaluess:(nsinteger)proportion{
    
    //1.画坐标轴
    
    [self drawxyline:x_names adddistancevalues:adddistance startingvalues:starting proportionvaluess:proportion];
    nsmutablearray * targetvalues1 =[[nsmutablearray alloc]init];
    for (int i=0; i<targetvalues.count; i++  ){
        cgfloat coed =[targetvalues[i] integervalue];
        [targetvalues1 addobject:@((coed-starting)/proportion)];
       
    }
    //2.每一个目标值点坐标
    for (int i=0; i<targetvalues1.count; i++) {
        cgfloat doublevalue = 2*[targetvalues1[i] floatvalue]; //目标值放大两倍
        cgfloat x = margin + margin*(i+1)+5;
        cgfloat y = cgrectgetheight(myframe)-margin-doublevalue;
        uibezierpath *path = [uibezierpath bezierpathwithrect:cgrectmake(x-margin/2+adddistance, y, margin-10, doublevalue)];
        cashapelayer *shapelayer = [cashapelayer layer];
        shapelayer.path = path.cgpath;
        shapelayer.strokecolor = [uicolor clearcolor].cgcolor;
        shapelayer.fillcolor = xyqrandomcolor.cgcolor;
        shapelayer.borderwidth = 2.0;
        [self.subviews[0].layer addsublayer:shapelayer];
        
        //3.添加文字
        uilabel *label = [[uilabel alloc] initwithframe:cgrectmake(x-margin/2, y-20, margin-10+adddistance*2, 20)];
        label.text = [nsstring stringwithformat:@"%.0lf",starting+proportion*(cgrectgetheight(myframe)-y-margin)/2];
        label.textcolor = [uicolor purplecolor];
        label.textalignment = nstextalignmentcenter;
        label.font = [uifont systemfontofsize:10];
        [self.subviews[0] addsubview:label];
    }
}

6、父视图view部分代码

- (void)viewdidload {
    [super viewdidload];
    self.view.layer.backgroundcolor=[uicolor whitecolor].cgcolor;
    //1.初始化
    self.bezierview = [beziercurveview initwithframe:cgrectmake(20, 30, screen_w-40, 280)];
    self.bezierview.center = self.view.center;
    [self.view addsubview:self.bezierview];
    //2.折线图
   // [self drawlinechart];
    //3.柱状图
  //  [self drawbasechart];
}

//画折线图
-(void)drawlinechart{
    
    //直线
    //    [self.bezierview drawlinechartviewwithx_value_names:self.x_names targetvalues:self.targets linetype:linetype_straight adddistancevalues:20  startingvalues:120000 proportionvaluess:100];

   // [self.bezierview drawlinechartviewwithx_value_names:self.x_names targetvalues:self.targets linetype:linetype_curve adddistancevalues:10  startingvalues:50000 proportionvaluess:100];
   // [self.bezierview drawlinechartviewwithx_value_names:self.x_names targetvalues:self.targets linetype:linetype_curve adddistancevalues:20  startingvalues:120000 proportionvaluess:100];
}

7、iponexr演示结果图片iOS 折线图、柱状图的简单实现iOS 折线图、柱状图的简单实现