Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 7546609
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: May 30, 20262026-05-30T09:14:37+00:00 2026-05-30T09:14:37+00:00

I have a pie chart which is made using UIBezierPath’s. I now need those

  • 0

I have a pie chart which is made using UIBezierPath’s. I now need those individual paths (pie pieces) to be scalable. I believe you need a view to be able to use pinch scaling, so I think touchesMoved: is the way to go (unless there’s a workaround).

Any advice or help is appreciated!

Updated/Progress code

MySliceClass.m

+ (UIBezierPath *)sliceRadius:(float)radius andStartingAngle:(float)startingAngle andFinishingAngle:(float)finishingAngle
{
  static UIBezierPath *path = nil;
  path = [UIBezierPath bezierPath];
  CGPoint center = {300,300};
  [path moveToPoint:center];
  [path addArcWithCenter:center radius:radius startAngle:radians(startingAngle) endAngle:radians(finishingAngle) clockwise:YES];
  [path closePath];
  path.lineWidth = 1;

  [[UIColor redColor] setFill];
  [path fill];

  return path;
}

MySliceView.m

- (void)drawRect:(CGRect)rect 
{
  NSArray *arrayOfSlices = [NSArray arrayWithObjects:
                            slice01 = [WordplaySlice sliceRadius:200 andStartingAngle:0.5 andFinishingAngle:29.5],
                            slice02 = [WordplaySlice sliceRadius:200 andStartingAngle:30.5 andFinishingAngle:59.5],
                            slice03 = [WordplaySlice sliceRadius:200 andStartingAngle:60.5 andFinishingAngle:89.5],
                            slice04 = [WordplaySlice sliceRadius:200 andStartingAngle:90.5 andFinishingAngle:119.5],
                            slice05 = [WordplaySlice sliceRadius:200 andStartingAngle:120.5 andFinishingAngle:149.5],
                            slice06 = [WordplaySlice sliceRadius:200 andStartingAngle:150.5 andFinishingAngle:179.5],
                            slice07 = [WordplaySlice sliceRadius:200 andStartingAngle:180.5 andFinishingAngle:209.5],
                            slice08 = [WordplaySlice sliceRadius:200 andStartingAngle:210.5 andFinishingAngle:239.5],
                            slice09 = [WordplaySlice sliceRadius:200 andStartingAngle:240.5 andFinishingAngle:269.5],
                            slice10 = [WordplaySlice sliceRadius:200 andStartingAngle:270.5 andFinishingAngle:299.5],
                            slice11 = [WordplaySlice sliceRadius:200 andStartingAngle:300.5 andFinishingAngle:329.5],
                            slice12 = [WordplaySlice sliceRadius:200 andStartingAngle:330.5 andFinishingAngle:359.5], nil];                             
}
  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-05-30T09:14:38+00:00Added an answer on May 30, 2026 at 9:14 am

    I think you will find it easier if you create a view for each slice, and use a UIPinchGestureRecognizer. Here’s how.

    First, we need a UIView subclass that draws one slice. It should also override pointInside:withEvent: to ignore a touch that lands outside the slice (even if the touch is inside the view’s rectangular bounds).

    So we’ll make a class called SliceView. It uses CAShapeLayer to do the slice drawing:

    @interface SliceView : UIView
    
    @property (nonatomic) CGFloat padding;
    @property (nonatomic) CGFloat startRadians;
    @property (nonatomic) CGFloat endRadians;
    @property (nonatomic, strong) UIColor *fillColor;
    
    @end
    
    @implementation SliceView
    
    @synthesize padding = _padding;
    @synthesize startRadians = _startRadians;
    @synthesize endRadians = _endRadians;
    @synthesize fillColor = _fillColor;
    

    We tell it to use a CAShapeLayer instead of a plain CALayer by overriding the layerClass method. We’ll also add a handy method that returns the view’s layer as a CAShapeLayer.

    + (Class)layerClass {
        return [CAShapeLayer class];
    }
    
    - (CAShapeLayer *)shapeLayer {
        return (CAShapeLayer *)self.layer;
    }
    

    We’ll compute the path of the slice in layoutSubviews, because the view receives the layoutSubviews message any time its size is changed.

    We’re going to lay out each slice view to cover the entire pie, but only draw its wedge of the pie. Each slice’s frame will cover the entire screen (if the pie is full-screen). That means the slice view knows that the center of its arc is at the center of its bounds. But then we use a little trigonometry to put in the padding between adjacent slices.

    We also adjust the anchor point of the layer; this is the point in the layer that doesn’t move when you scale or rotate the layer. We want the anchor point to be at the corner of the slice nearest the center.

    - (void)layoutSubviews {
        CAShapeLayer *layer = self.shapeLayer;
        CGRect bounds = self.bounds;
        CGFloat radius = MIN(bounds.size.width, bounds.size.height) / 2 - 2 * _padding;
        CGPoint center = CGPointMake(CGRectGetMidX(bounds), CGRectGetMidY(bounds));
        CGFloat sine = sinf((_startRadians + _endRadians) * 0.5f);
        CGFloat cosine = cosf((_startRadians + _endRadians) * 0.5f);
        center.x += _padding * cosine;
        center.y += _padding * sine;
        UIBezierPath *path = [UIBezierPath bezierPath];
        [path moveToPoint:center];
        [path addArcWithCenter:center radius:radius startAngle:_startRadians endAngle:_endRadians clockwise:YES];
        [path closePath];
        layer.path = path.CGPath;
    
        // Move my anchor point to the corner of my path so scaling will leave the corner in the same place.
        CGPoint cornerInSuperview = [self convertPoint:center toView:self.superview];
        layer.anchorPoint = CGPointMake(center.x / bounds.size.width, center.y / bounds.size.height);
        self.center = cornerInSuperview;
    }
    

    When any of the view’s properties relating to the slice are changed, we need to recompute the path outlining the slice. And when the fill color of the slice is changed, we need to pass that change along to the layer. So we’ll override the property setters.

    - (void)setPadding:(CGFloat)padding {
        _padding = padding;
        [self setNeedsLayout];
    }
    
    - (void)setStartRadians:(CGFloat)startRadians {
        _startRadians = startRadians;
        [self setNeedsLayout];
    }
    
    - (void)setEndRadians:(CGFloat)endRadians {
        _endRadians = endRadians;
        [self setNeedsLayout];
    }
    
    - (void)setFillColor:(UIColor *)color {
        _fillColor = color;
        self.shapeLayer.fillColor = color.CGColor;
    }
    

    Finally, we override pointInside:withEvent: so that hit-testing will only assign a touch to a slice view if the touch is actually inside the path of the slice. This is critical since all of the slice views will have a frame that covers the whole screen.

    - (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
        return CGPathContainsPoint(self.shapeLayer.path, NULL, point, NO);
    }
    
    @end
    

    Now that we have a handy SliceView class, we can use it to draw a pie chart with zoomable slices. It’s hard to fit two fingers into a slice on an iPhone screen, so we’ll let the user tap a slice to select it, and pinch anywhere to scale the selected slice. (This interface also makes it testable in the simulator.)

    @implementation ViewController {
        __weak SliceView *_selectedSlice;
    }
    

    We’ll draw unselected slices in red and the selected slice in blue.

    + (UIColor *)unselectedSliceFillColor {
        return UIColor.redColor;
    }
    
    + (UIColor *)selectedSliceFillColor {
        return UIColor.blueColor;
    }
    

    When the user taps a slice, we’ll need to change the colors of the prior selection and the new selection, and record the new selection.

    - (IBAction)sliceWasTapped:(UITapGestureRecognizer *)tapper {
        _selectedSlice.fillColor = self.class.unselectedSliceFillColor;
        _selectedSlice = (SliceView *)tapper.view;
        _selectedSlice.fillColor = self.class.selectedSliceFillColor;
    }
    

    When the user pinches, we adjust the transform of the selected slice, if there is one.

    - (IBAction)pinched:(UIPinchGestureRecognizer *)pincher {
        if (!_selectedSlice)
            return;
        CGFloat scale = pincher.scale;
        pincher.scale = 1;
        _selectedSlice.transform = CGAffineTransformScale(_selectedSlice.transform, scale, scale);
    }
    

    Finally, we need to actually create the slice views and the gesture recognizers. We create one tap recognizer for each slice, and one “global” pinch recognizer attached to the background view.

    - (void)viewDidLoad {
        static int const SliceCount = 12;
        CGRect bounds = self.view.bounds;
        for (int i = 0; i < SliceCount; ++i) {
            SliceView *slice = [[SliceView alloc] initWithFrame:bounds];
            slice.startRadians = 2 * M_PI * i / SliceCount;
            slice.endRadians = 2 * M_PI * (i + 1) / SliceCount;
            slice.padding = 4;
            slice.fillColor = self.class.unselectedSliceFillColor;
            slice.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
            [self.view addSubview:slice];
    
            UITapGestureRecognizer *tapper = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(sliceWasTapped:)];
            [slice addGestureRecognizer:tapper];
        }
    
        UIPinchGestureRecognizer *pincher = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(pinched:)];
        [self.view addGestureRecognizer:pincher];
    }
    
    - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
    {
        return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
    }
    
    @end
    

    And here’s what it looks like:

    SliceView demo screen shot

    You can download my test project here: http://dl.dropbox.com/u/26919672/pie.zip

    UPDATE

    In response to your comment asking about limiting the scale, I would suggest adding some more properties to SliceView:

    @property (nonatomic) CGFloat minScale;
    @property (nonatomic) CGFloat maxScale;
    @property (nonatomic) CGFloat scale;
    

    Important: You will need to initialize all three properties to 1 in initWithFrame: and initWithCoder:.

    Then, implement the scale setter to actually enforce the limits and set the scale:

    - (void)setScale:(CGFloat)scale {
        _scale = MAX(minScale, MIN(scale, maxScale));
        self.transform = CGAffineTransformMakeScale(_scale, _scale);
    }
    

    In pinched:, you update the scale property of the view instead of setting the view’s transform property directly:

    - (IBAction)pinched:(UIPinchGestureRecognizer *)pincher {
        if (!_selectedSlice)
            return;
        CGFloat scale = pincher.scale;
        pincher.scale = 1;
        _selectedSlice.scale = _selectedSlice.scale * scale;
    }
    
    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

I have developed an animated Pie Chart, in which when a user clicks on
Now I'm doing a project which need draw multiple pie charts with text. Can
I have a pie chart that I build using Core Plot. Also I used
I am attempting to have a Pie chart using the ASP.Net Charting controls. Everything's
I want to generate random colours which can be attractive in pie charts.I have
I have a pie chart in BIRT and about 80 data points. I'm looking
RS2008 - pie chart I have 'outside' labels with lines pointing to the segment
I have some code that generates image of a pie chart. It's a general
I have need to produce LINE, BAR, and PIE charts in Rails. I have
I have the following script which I need to modify a little. Here is

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.