折れ線グラフを書いてみる

iPhoneアプリ 折れ線グラフ

「折れ線グラフ」をiPhoneアプリで書いてみます。データAを青い四角、データBを赤い丸でプロットし、直線で繋いでいきましょう。


動作イメージ
XcodeからiOS6 iPhone Simulatorで動かすとこんな感じになります。




ポイント
データAとデータB、この二つの折れ線を描いていきます。UIBezierPathとCAShapLayerでグラフの線を作り、表示の際にはアニメーションするようにしています。


サンプルコード


#import "ViewController.h"

#import <QuartzCore/QuartzCore.h>


@interface ViewController () {

    NSArray *dataA;

    NSArray *dataB;

    BOOL showA;

    BOOL showB;

    CAShapeLayer *slA;

    CAShapeLayer *slB;


}

@end


@implementation ViewController


- (void)viewDidLoad

{

    [super viewDidLoad];

    self.view.backgroundColor = [UIColor whiteColor];

    

    showA = YES;

    showB = YES;

    

[self createDataSheet];


    [self drawChart];

    

    [self createLabel];

}


- (void)createDataSheet

{

    dataA = @[@1, @2, @3, @4, @5, @6];

    dataB = @[@2, @8, @9, @12, @8, @10];

    

    slA = [[CAShapeLayer alloc] init];

    slA.fillColor = [UIColor clearColor].CGColor;

    slA.strokeColor = [UIColor blueColor].CGColor;

    slA.lineWidth = 2;

    [self.view.layer addSublayer:slA];

    

    slB = [[CAShapeLayer alloc] init];

    slB.fillColor = [UIColor clearColor].CGColor;

    slB.strokeColor = [UIColor redColor].CGColor;

    slB.lineWidth = 2;

    [self.view.layer addSublayer:slB];

}


- (void)drawChart

{

    float dx = 90;

    float dy = 20;

    float x = 50;

    float y = 280;

    

    BOOL animA = NO;

    BOOL animB = NO;

    

    if (!slA.path) {

        animA = YES;

    }

    if (!slB.path) {

        animB = YES;

    }

    

    if (showA) {

        UIBezierPath *path = [[UIBezierPath alloc] init];

        for (int i=0; i<[dataA count]; i++) {

            float px = x + dx * i;

            float py = y - [[dataA objectAtIndex:i] intValue] * dy;

            if (i == 0) {

                [path appendPath:[UIBezierPath bezierPathWithRect:CGRectMake(px, py, 10, 10)]];

                [path moveToPoint:CGPointMake(px + 5, py + 5)];

            } else {

                [path addLineToPoint:CGPointMake(px + 5, py + 5)];

                [path appendPath:[UIBezierPath bezierPathWithRect:CGRectMake(px, py, 10, 10)]];

                [path moveToPoint:CGPointMake(px + 5, py + 5)];

            }

        }

        slA.path = path.CGPath;

    } else {

        slA.path = nil;

    }

    

    if (showB) {

        UIBezierPath *path = [[UIBezierPath alloc] init];

        for (int i=0; i<[dataB count]; i++) {

            float px = x + dx * i;

            float py = y - [[dataB objectAtIndex:i] intValue] * dy;

            if (i == 0) {

                [path appendPath:[UIBezierPath bezierPathWithRoundedRect:CGRectMake(px, py, 10, 10) cornerRadius:5]];

                [path moveToPoint:CGPointMake(px + 5, py + 5)];

            } else {

                [path addLineToPoint:CGPointMake(px + 5, py + 5)];

                [path appendPath:[UIBezierPath bezierPathWithRoundedRect:CGRectMake(px, py, 10, 10) cornerRadius:5]];

                [path moveToPoint:CGPointMake(px + 5, py + 5)];

            }        }

        slB.path = path.CGPath;

    } else {

        slB.path = nil;

    }

    

    if (animA) {

        [self startDraw:slA duration:0.3];

    }

    if (animB) {

        [self startDraw:slB duration:0.3];

    }

}


- (void)createLabel

{

    UIView *lframe = [[UIView alloc] initWithFrame:CGRectMake(20, 20, 100, 60)];

    lframe.backgroundColor = [UIColor colorWithWhite:0 alpha:0.6];

    lframe.layer.cornerRadius = 10;

    [self.view addSubview:lframe];

    

    UILabel *a = [[UILabel alloc] initWithFrame:CGRectMake(10, 8, 70, 20)];

    a.text = @"data A";

    a.textColor = [UIColor whiteColor];

    a.backgroundColor = [UIColor colorWithWhite:0 alpha:0.0001];

    a.textAlignment = NSTextAlignmentRight;

    [lframe addSubview:a];

    UIView *markA = [[UIView alloc] initWithFrame:CGRectMake(0, 5, 10, 10)];

    markA.backgroundColor = [UIColor blueColor];

    [a addSubview:markA];

    

    UILabel *b = [[UILabel alloc] initWithFrame:CGRectMake(10, 33, 70, 20)];

    b.text = @"data B";

    b.textColor = [UIColor whiteColor];

    b.backgroundColor = [UIColor colorWithWhite:0 alpha:0.0001];

    b.textAlignment = NSTextAlignmentRight;

    [lframe addSubview:b];

    UIView *markB = [[UIView alloc] initWithFrame:CGRectMake(0, 5, 10, 10)];

    markB.backgroundColor = [UIColor redColor];

    [b addSubview:markB];

    

    NSArray *labels = @[a, b];

    for (UILabel *l in labels) {

        l.userInteractionEnabled = YES;

        UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapLabel:)];

        [l addGestureRecognizer:tap];

    }

}


- (void)tapLabel:(UITapGestureRecognizer*)gr

{

    UILabel *l = (UILabel*)gr.view;

    

    if ([l.text isEqual:@"data A"]) {

        showA = !showA;

    }

    

    if ([l.text isEqual:@"data B"]) {

        showB = !showB;

    }

    

    [self drawChart];

}


- (void)startDraw:(CALayer*)l duration:(float)duration

{

    CABasicAnimation *a = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];

    a.duration = duration;

    a.fromValue = @0;

    a.toValue = @1;

    [l addAnimation:a forKey:@"strokeEnd"];

}


- (void)didReceiveMemoryWarning

{

    [super didReceiveMemoryWarning];

    // Dispose of any resources that can be recreated.

}


@end