Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to animate the pie charts developed using core-plot library?

In the iPhone application Roambi, the pie chart shown can be animated to rotate with the user as if rotating a disc. We can hold and do lot of stuff with that.

Someone mentioned that the Roambi app was developed using core-plot library:

What library use Roambi app iPhone to draw chart?

How can I manipulate a pie chart developed using Core plot?

like image 705
RK- Avatar asked Mar 09 '11 05:03

RK-


3 Answers

For a simple pie chart, even with the aforementioned animations, Core Plot is not necessary. If you only want a Core Plot solution, then please disregard this answer. However, here is a simple solution that requires no external packages or even any frameworks.

Create a UIView called PieChartView. In PieChartView.h:

#import <UIKit/UIKit.h>

@interface PieChartView : UIView {
    float zeroAngle;
    NSMutableArray *valueArray;
    NSMutableArray *colorArray;
}
@property (nonatomic) float zeroAngle;
@property (nonatomic, retain) NSMutableArray *valueArray;
@property (nonatomic, retain) NSMutableArray *colorArray;
@end

Then the implementation in PieChartView.m:

#import "PieChartView.h"

@implementation PieChartView
@synthesize zeroAngle;
@synthesize valueArray, colorArray;

- (id)initWithFrame:(CGRect)frame {
    if ((self = [super initWithFrame:frame])) {
    }
    return self;
}


- (void)drawRect:(CGRect)rect {
    CGContextRef context = UIGraphicsGetCurrentContext();

    // DETERMINE NUMBER OF WEDGES OF PIE
    int wedges = [valueArray count];
    if (wedges > [colorArray count]) {
        NSLog(@"INSUFFICENT COLORS FOR PIE CHART: Please add %d additional colors.",wedges-[colorArray count]);
        for (int i=[colorArray count] ; i<wedges ; ++i) {
            [colorArray addObject:[UIColor whiteColor]];
        }
    }

    // DETERMINE TOTAL VOLUME OF PIE
    float sum = 0.0;
    for (int i=0; i<wedges ; ++i) {
        sum += [[valueArray objectAtIndex:i] floatValue];
    }
    float frac = 2.0*M_PI/sum;

    // DETERMINE CENTER AND MAXIMUM RADIUS OF INSCRIBED CIRCLE
    int center_x = rect.size.width/2.0;
    int center_y = rect.size.height/2.0;
    int radius = (center_x > center_y ? center_x : center_y);

    // DRAW WEDGES CLOCKWISE FROM POSITIVE X-AXIS
    float startAngle=zeroAngle;
    float endAngle=zeroAngle;
    for (int i=0; i<wedges; ++i) {
        startAngle = endAngle;
        endAngle += [[valueArray objectAtIndex:i] floatValue]*frac;
        [[colorArray objectAtIndex:i] setFill];
        CGContextMoveToPoint(context, center_x, center_y);
        CGContextAddArc(context, center_x, center_y, radius, startAngle, endAngle, 0);
        CGContextClosePath(context);
        CGContextFillPath(context);
    }
}

- (void)dealloc {
    [valueArray release];
    [colorArray release];
    [super dealloc];
}
@end

Now you can bind the float zeroAngle to the accelerometer in any way you wish to achieve the desired animation.

like image 28
PengOne Avatar answered Nov 11 '22 12:11

PengOne


I didn't know CorePlot, and it might be some use for me in the near future, so I just gave it a look. CorePlot is interesting and is active.

Concerning Animations with CorePlot:

  1. CorePlot documentation mentions an Animation system, but it is not implemented yet...
  2. Even if based on Core Animation, it doesnt mean CorePlot graph will be easily animatable.

Interesting reading on the topic on google groups.

So here are your options (by my order of preference):

  1. Look for another plotting library handling animations like Roambi does.
  2. Implement your animations based on CorePlot (means a good understanding of this framework and Core Animation)
  3. Do everything yourself, depending on what you want, again, might be not that hard... But Core Animation skills needed, again.

I doubt Roambi uses CorePlot, but if they do, they use it as a base with TONS of custom in house code...

like image 39
Vincent Guerci Avatar answered Nov 11 '22 13:11

Vincent Guerci


A quick look at the Core Plot source code reveals that CPPieChart's inheritance looks like this:

CPPieChart : CPPlot : CPAnnotationHostLayer : CPLayer : CALayer

So you can see that in the end, CPPieChart is just a heavily subclassed CALayer. I might be entirely incorrect here, but there's nothing that indicates that this can't be animated like any other CALayer. Try the following code to rotate the layer by 360 degrees:

CABasicAnimation *rotation = [CABasicAnimation animationWithKeyPath:@"transform"];
CATransform3D transform = CATransform3DMakeRotation(DegreesToRadians(360), 0, 0, 1);
rotation.toValue = [NSValue valueWithCATransform3D:transform];
rotation.duration = 10.0f;
[pieChart addAnimation:rotation forKey:@"rotation"];

If you can get this working then its just a matter of reading the values from the accelerometer and converting them to rotation angles.

like image 54
indragie Avatar answered Nov 11 '22 11:11

indragie