ios - CALayer clip CGContextAddArc (making a donut slide/pie chart) -
i'am trying learn , understand coregraphics. i'am trying making pie chart.
the pie chart working fine , looks great, i'am having trouble clipping inner circle.
this code each slide in 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 this:
i managed add inner circle drawing new path smaller radius.
i try clip second path cgcontextclip(ctx);
leaves me inner circle this:
it kind of makes sense me why happening can't figure else should doing.
edit:
code 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 subclass of calayer. code drawing single slice in 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 done first next path(s) not creating 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 graph , 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 labels.. disabled 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 labels.. disabled 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(); }
if understand question correctly, want have hole in center , trying use clipping mask that. thing therefore need reverse direction draw inner path tried clip. then, because of fill rules, cut out nice hole you.
your code should this:
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 done first next path(s) not creating clipping mask */ cgcontextmovetopoint(ctx, center.x, center.y); /* create outer path going clockwise */ cgcontextaddarc(ctx, center.x, center.y, radius*3, 0, 2*m_pi, clockwise); /* create inner path / mask going counter-clockwise make 'hole' in center */ cgcontextaddarc(ctx, center.x, center.y, radius*0.5, 0, 2*m_pi, !clockwise); cgcontextclip(ctx); /* now, start drawing graph , filling things in... */ cgcontextbeginpath(ctx); /* here's stroke of inner circle */ cgpoint p1 = cgpointmake(center.x + radius/2 * cosf(self.endangle), center.y + radius/2 * sinf(self.endangle)); cgcontextmovetopoint(ctx, p1.x, p1.y); cgcontextaddarc(ctx, center.x, center.y, radius / 2 + 1, self.endangle, self.startangle, !clockwise); 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);
update: i've fixed code , run code on github , works. hopefully, fix "hole" problem. (excuse pun)
here's gist of example of technique: https://gist.github.com/rcdilorenzo/6437406
Comments
Post a Comment