I'am trying to learn and understand CoreGraphics. What i'am trying to do is making a pie chart.
The pie chart is working fine and looks great, but i'am having trouble with clipping an inner circle.
This the code for each slide in the pie:
CGPoint center = CGPointMake((self.bounds.size.width/2) + self.centerOffset, (self.bounds.size.height/2) - self.centerOffset);
CGFloat radius = MIN(center.x, center.y) - 25;
radius *= self.pieScale;
CGContextBeginPath(ctx);
CGContextMoveToPoint(ctx, center.x, center.y);
CGPoint p1 = CGPointMake(center.x + radius * cosf(self.startAngle), center.y + radius * sinf(self.startAngle));
CGContextAddLineToPoint(ctx, p1.x, p1.y);
int clockwise = self.startAngle > self.endAngle;
CGContextAddArc(ctx, center.x, center.y, radius, self.startAngle, self.endAngle, clockwise);
CGContextClosePath(ctx);
CGContextMoveToPoint(ctx, center.x, center.y);
CGContextAddArc(ctx, center.x, center.y, radius*0.5, self.startAngle, self.endAngle, clockwise);
CGContextSetFillColorWithColor(ctx, self.fillColor.CGColor);
CGContextSetStrokeColorWithColor(ctx, self.strokeColor.CGColor);
CGContextSetLineWidth(ctx, self.strokeWidth);
self.pathRef = CGContextCopyPath(ctx);
CGContextDrawPath(ctx, kCGPathFillStroke);
My current pie looks like this:
I managed to add an inner circle by drawing a new path with a smaller radius.
I try to clip the second path with CGContextClip(ctx);
but leaves me only with the inner circle like this:
It kind of makes sense to me why this is happening but i can't figure what else i should be doing.
Edit:
Code now looks like:
CGPoint center = CGPointMake((self.bounds.size.width/2) + self.centerOffset, (self.bounds.size.height/2) - self.centerOffset);
CGFloat radius = MIN(center.x, center.y) - 25;
radius *= self.pieScale;
CGPoint p1 = CGPointMake(center.x + radius * cosf(self.startAngle), center.y + radius * sinf(self.startAngle));
int clockwise = self.startAngle > self.endAngle;
CGContextBeginPath(ctx);
CGContextMoveToPoint(ctx, center.x, center.y);
CGContextAddLineToPoint(ctx, p1.x, p1.y);
CGContextAddArc(ctx, center.x, center.y, radius, self.startAngle, self.endAngle, clockwise);
CGContextClosePath(ctx);
CGContextMoveToPoint(ctx, center.x, center.y);
CGContextAddArc(ctx, center.x, center.y, radius*0.5, self.startAngle, self.endAngle, !clockwise);
CGContextSetFillColorWithColor(ctx, self.fillColor.CGColor);
CGContextSetStrokeColorWithColor(ctx, self.strokeColor.CGColor);
CGContextSetLineWidth(ctx, self.strokeWidth);
self.pathRef = CGContextCopyPath(ctx);
CGContextDrawPath(ctx, kCGPathFillStroke);
Looks like:
All drawing code:
My class is a subclass of CALayer. This code is drawing a single slice in the pie.
-(void)drawInContext:(CGContextRef)ctx
{
CGPoint center = CGPointMake((self.bounds.size.width/2) + self.centerOffset, (self.bounds.size.height/2) - self.centerOffset);
CGFloat radius = MIN(center.x, center.y) - 25;
radius *= self.pieScale;
int clockwise = self.startAngle > self.endAngle;
/* Clipping should be done first so the next path(s) are not creating the clipping mask */
CGContextMoveToPoint(ctx, center.x, center.y);
CGContextAddArc(ctx, center.x, center.y, radius*0.5, self.startAngle, self.endAngle, !clockwise);
//CGContextClipPath(ctx);
CGContextClip(ctx);
/* Now, start drawing your graph and filling things in... */
CGContextBeginPath(ctx);
CGContextMoveToPoint(ctx, center.x, center.y);
CGPoint p1 = CGPointMake(center.x + radius * cosf(self.startAngle), center.y + radius * sinf(self.startAngle));
CGContextAddLineToPoint(ctx, p1.x, p1.y);
CGContextAddArc(ctx, center.x, center.y, radius, self.startAngle, self.endAngle, clockwise);
CGContextClosePath(ctx);
CGContextSetFillColorWithColor(ctx, self.fillColor.CGColor);
CGContextSetStrokeColorWithColor(ctx, self.strokeColor.CGColor);
CGContextSetLineWidth(ctx, self.strokeWidth);
self.pathRef = CGContextCopyPath(ctx);
CGContextDrawPath(ctx, kCGPathFillStroke);
// LABELS
UIGraphicsPushContext(ctx);
CGContextSetFillColorWithColor(ctx, self.labelColor.CGColor);
CGFloat distance = [self angleDistance:(self.startAngle * 180/M_PI) angle2:(self.endAngle * 180/M_PI)];
CGFloat arcDistanceAngle = distance * M_PI/180;
CGFloat arcCenterAngle = self.startAngle + arcDistanceAngle/2;
CGPoint labelPoint = CGPointMake(center.x + radius * cosf(arcCenterAngle), center.y + radius * sinf(arcCenterAngle));
/*
Basic drawing of lines to labels.. Disabled for now..
CGContextBeginPath(ctx);
CGContextMoveToPoint(ctx, labelPoint.x, labelPoint.y);
*/
if(labelPoint.x <= center.x)
labelPoint.x -= 50;
else
labelPoint.x += 5;
if(labelPoint.y <= center.y)
labelPoint.y -= 25;
/*
Basic drawing of lines to labels.. Disabled for now..
CGContextAddLineToPoint(ctx, labelPoint.x, labelPoint.y);
CGContextClosePath(ctx);
CGContextSetFillColorWithColor(ctx, self.fillColor.CGColor);
CGContextSetStrokeColorWithColor(ctx, self.strokeColor.CGColor);
CGContextSetLineWidth(ctx, self.strokeWidth);
CGContextDrawPath(ctx, kCGPathFillStroke);
*/
[self.labelString drawAtPoint:labelPoint forWidth:50.0f withFont:[UIFont systemFontOfSize:18] lineBreakMode:NSLineBreakByClipping];
UIGraphicsPopContext();
}