Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Animated pie chart in iOS

I'm trying to create an animated pie chart in iOS that acts basically like this:

Pie chart progression

In a nutshell, it starts as a grey circle, and as the animation progresses the arrow moves around the circle until it gets to the percentage I specify.

I've used the sample code that Zachary Waldowski posted in this SO question:

Animated CAShapeLayer Pie

That's gotten me to the point where I can create the basic animation. The maroon pie piece grows to hit the correct size. What I'm struggling with is how to map the arrow to the animation so that it gets dragged along as the pie piece grows.

Any thoughts on how I can accomplish this?

like image 867
Axeva Avatar asked Jan 06 '14 14:01

Axeva


2 Answers

Okay, I've found the solution.

Building on the work Zachary Waldowski created (see my original post), I was able to do the entire thing in a CALayer.

In a nutshell, I draw one outer circle in maroon, a smaller circle in light gray, a stroked path in white, then draw the triangle for the tip of the arrow by hand.

Here's the relevant section of code that does the magic:

- (void)drawInContext:(CGContextRef)context {
    CGRect circleRect = CGRectInset(self.bounds, 1, 1);
    CGFloat startAngle = -M_PI / 2;
    CGFloat endAngle = self.progress * 2 * M_PI + startAngle;

    CGColorRef outerPieColor = [[UIColor colorWithRed: 137.0 / 255.0 green: 12.0 / 255.0 blue: 88.0 / 255.0 alpha: 1.0] CGColor];
    CGColorRef innerPieColor = [[UIColor colorWithRed: 235.0 / 255.0 green: 214.0 / 255.0 blue: 227.0 / 255.0 alpha: 1.0] CGColor];
    CGColorRef arrowColor = [[UIColor whiteColor] CGColor];

    // Draw outer pie
    CGFloat outerRadius = CGRectGetMidX(circleRect);
    CGPoint center = CGPointMake(CGRectGetMidX(circleRect), CGRectGetMidY(circleRect));

    CGContextSetFillColorWithColor(context, outerPieColor);
    CGContextMoveToPoint(context, center.x, center.y);
    CGContextAddArc(context, center.x, center.y, outerRadius, startAngle, endAngle, 0);
    CGContextClosePath(context);
    CGContextFillPath(context);

    // Draw inner pie
    CGFloat innerRadius = CGRectGetMidX(circleRect) * 0.45;

    CGContextSetFillColorWithColor(context, innerPieColor);
    CGContextMoveToPoint(context, center.x, center.y);
    CGContextAddArc(context, center.x, center.y, innerRadius, startAngle, endAngle, 0);
    CGContextClosePath(context);
    CGContextFillPath(context);

    // Draw the White Line
    CGFloat lineRadius = CGRectGetMidX(circleRect) * 0.72;
    CGFloat arrowWidth = 0.35;

    CGContextSetStrokeColorWithColor(context, arrowColor);
    CGContextSetFillColorWithColor(context, arrowColor);

    CGMutablePathRef path = CGPathCreateMutable();
    CGContextSetLineWidth(context, 16);
    CGFloat lineEndAngle = ((endAngle - startAngle) >= arrowWidth) ? endAngle - arrowWidth : endAngle;
    CGPathAddArc(path, NULL, center.x, center.y, lineRadius, startAngle, lineEndAngle, 0);
    CGContextAddPath(context, path);
    CGContextStrokePath(context);

    // Draw the Triangle pointer
    CGFloat arrowStartAngle = lineEndAngle - 0.01;
    CGFloat arrowOuterRadius = CGRectGetMidX(circleRect) * 0.90;
    CGFloat arrowInnerRadius = CGRectGetMidX(circleRect) * 0.54;

    CGFloat arrowX = center.x + (arrowOuterRadius * cosf(arrowStartAngle));
    CGFloat arrowY = center.y + (arrowOuterRadius * sinf(arrowStartAngle));

    CGContextMoveToPoint   (context, arrowX, arrowY);  // top corner

    arrowX = center.x + (arrowInnerRadius * cosf(arrowStartAngle));
    arrowY = center.y + (arrowInnerRadius * sinf(arrowStartAngle));

    CGContextAddLineToPoint(context, arrowX, arrowY);  // bottom corner

    arrowX = center.x + (lineRadius * cosf(endAngle));
    arrowY = center.y + (lineRadius * sinf(endAngle));

    CGContextAddLineToPoint(context, arrowX, arrowY);  // point
    CGContextClosePath(context);
    CGContextFillPath(context);

    [super drawInContext: context];
}
like image 182
Axeva Avatar answered Sep 27 '22 21:09

Axeva


Have the pie with the arrow as an image.

In every step, draw this image, rotating it a little. Draw the gray pie over the image, choosing correct angles for the image rotation.

like image 24
Sulthan Avatar answered Sep 27 '22 21:09

Sulthan