iPhone レーダーチャート

成績表などで複数のカテゴリーを一目で比較する際によく使うグラフ「レーダーチャート(クモの巣グラフ)」を表示するiPhoneアプリの作成方法を書いてみます。今回は5つのカテゴリーに、1から5までのランクをつける五角形にしてみます。


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

ポイント
グラフの基準点として、カテゴリ×ランクの計25個のCGPointをループの中で計算しておき、赤い線で結ぶところをintで5個用意、初期値は{3, 3, 3, 3, 3}とオール3にしました。グラフの増減は、UISegmentControllerの値とランクの値をTargetActionの呼び出しの中で連動させています。

サンプルコード

#import “ViewController.h”

#import <QuartzCore/QuartzCore.h>

@interface ViewController () {

    CGPoint points[25];

    int level[5];

    UIView *chart;

    

    CAShapeLayer *redline;

}

@end

@implementation ViewController

– (void)viewDidLoad

{

    [super viewDidLoad];

    

    self.view.backgroundColor = [UIColor darkGrayColor];

    

    [self setupPoints];

    

    [self setChartFrame];

    

    [self createBars];

    

    [self showGraph];

}

– (void)setupPoints

{

    for (int i=0; i<25; i++) {

        float angle = (i/5) * (M_PI / 2.5) – M_PI/2.0;

        float length = (i % 5 + 1) * 30;

        points[i] = CGPointMake(length * cos(angle) + 160, length * sin(angle) + 160);

    }

    

    for(int i=0; i<5; i++) {

        level[i] = 3;

    }

}

– (void)setChartFrame

{

    chart = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 310)];

    chart.backgroundColor = [UIColor colorWithWhite:0.9 alpha:1];

    chart.layer.borderColor = [UIColor darkGrayColor].CGColor;

    chart.layer.borderWidth = 10;

    [self.view addSubview:chart];

    

    for (int i=0; i<25; i++) {

        UIView *mark = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 3, 3)];

        mark.layer.cornerRadius = 1.5;

        mark.backgroundColor = [UIColor darkGrayColor];

        mark.center = points[i];

        [chart addSubview:mark];

    }

    

    UIBezierPath *outpath = [UIBezierPath bezierPath];

    for (int i=0; i<5; i++) {

        [outpath moveToPoint:points[i]];

        [outpath addLineToPoint:points[i+5]];

        [outpath addLineToPoint:points[i+10]];

        [outpath addLineToPoint:points[i+15]];

        [outpath addLineToPoint:points[i+20]];

        [outpath addLineToPoint:points[i]];

    }

    

    for (int i=0; i<5; i++) {

        [outpath moveToPoint:CGPointMake(160, 160)];

        [outpath addLineToPoint:points[i * 5 + 4]];

    }

    

    CAShapeLayer *outline = [[CAShapeLayer alloc] init];

    outline.fillColor = [UIColor clearColor].CGColor;

    outline.strokeColor = [UIColor darkGrayColor].CGColor;

    outline.lineWidth = 1;

    outline.path = outpath.CGPath;

    

    [chart.layer addSublayer:outline];

}

– (void)showGraph

{

    if(!redline) {

        redline = [[CAShapeLayer alloc] init];

        redline.fillColor = [UIColor colorWithRed:1 green:0 blue:0 alpha:0.3].CGColor;

        redline.strokeColor = [UIColor redColor].CGColor;

        redline.lineWidth = 6;

        [chart.layer addSublayer:redline];

    }

    

    UIBezierPath *path = [UIBezierPath bezierPath];

    [path moveToPoint:points[level[0] – 1]];

    [path addLineToPoint:points[level[1] + 4]];

    [path addLineToPoint:points[level[2] + 9]];

    [path addLineToPoint:points[level[3] + 14]];

    [path addLineToPoint:points[level[4] + 19]];

    [path addLineToPoint:points[level[0] – 1]];

    

    redline.path = path.CGPath;

}

– (void)createBars

{

    for (int i=0; i<5; i++) {

        UISegmentedControl *sgc = [[UISegmentedControl alloc] initWithItems:[NSArray arrayWithObjects:@”1″, @”2″, @”3″, @”4″, @”5″, nil]];

        sgc.frame = CGRectMake(10, 320 + i * 40, 300, 30);

        sgc.segmentedControlStyle = UISegmentedControlStylePlain;

        sgc.selectedSegmentIndex = 2;

        sgc.tag = i;

        [self.view addSubview:sgc];

        

        [sgc addTarget:self action:@selector(change:) forControlEvents:UIControlEventValueChanged];

    }

}

– (void)change:(UISegmentedControl*)sgc

{

    int type = sgc.tag;

    level[type] = sgc.selectedSegmentIndex + 1;

    [self showGraph];

}

– (void)didReceiveMemoryWarning

{

    [super didReceiveMemoryWarning];

    // Dispose of any resources that can be recreated.

}

@end