# Simple implementation of sector charts

Posted by markmil2002 on Sat, 04 Jul 2020 16:40:48 +0200

## Main Code

### 1. Traverse the proportions of all sectors, calculate the start and end angles of each sector area, and then draw FanShapeLayer

``````int max = 0;
for (NSNumber * obj in self.angles) {
max += [obj intValue];
}

CGFloat startAngle = self.startAngle;// Start 0 represents the positive direction of the x-axis

for (int i = 0; i < self.angles.count; i ++) {
NSNumber * obj = [self.angles objectAtIndex:i];

CGFloat rate = [obj intValue];
CGFloat angle = rate / max * M_PI * 2.0;

// Calculate the drawing angle - Endpoint The drawing direction is counterclockwise so it is subtracted
CGFloat endAngle = startAngle - angle;

// Set Colors
UIColor * color = randomColor;

// Create FanShapeLayer
FanShapeLayer * layer = [[FanShapeLayer alloc]init];
layer.fillColor = color.CGColor;
layer.name = [NSString stringWithFormat:@"layer = %d",i];
layer.startAngle = startAngle;
layer.endAngle = endAngle;
layer.centerPoint = self.chartPoint;
// Draw path (set parameters first)
[layer drawPath];

// Calculate the starting point of the next drawing
startAngle -= angle;
}
``````

### 2. After setting the parameters of FanShapeLayer, first draw CGMutablePathRef, which is a closed sector, then assign CGMutablePathRef to FanShapeLayer

``````CGMutablePathRef path = CGPathCreateMutable();
CGAffineTransform transform = CGAffineTransformMakeTranslation(1, 1);
CGPathMoveToPoint(path, &transform, self.centerPoint.x, self.centerPoint.y);
CGPathCloseSubpath(path);
``````

### 3. Mainly Click to zoom in. CALyer does not respond to click events. This is achieved by getting whether the point of the touch object is in the layer area or not.

You can find layers on the web that you can click on in the following ways, but here you get nil, and you don't know why.
CALayer * layer = [self.layer hitTest:point];

``````- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
// Get the center point of a click
UITouch * touch = [touches anyObject];
CGPoint point = [touch locationInView:self];
// Gets whether the click area contains a CAShapeLayer
FanShapeLayer * layer = [self touchLayer:point];
if (layer) {
NSLog(@"%@", layer.name);
// Set Selected to Unselected
NSPredicate * predicate = [NSPredicate predicateWithFormat:@"isSelected = YES"];
NSArray * selectArray = [self.fansArray filteredArrayUsingPredicate:predicate];
[selectArray makeObjectsPerformSelector:@selector(setIsSelected:) withObject:@NO];
if ([selectArray containsObject:layer]) {
return ;
}
layer.isSelected = YES;
}
}

- (FanShapeLayer *)touchLayer:(CGPoint)point{
// Get the clicked area layer
for (FanShapeLayer * layer in self.fansArray) {
// Get the inPoint, coordinates in the layer
CGPoint inPoint = [layer convertPoint:point fromLayer:self.layer];

if (CGPathContainsPoint(layer.path, 0, inPoint, YES)) {
return layer;
}
}
return nil;
}
``````

### 4. Finally add zoom animation when clicking

``````  // Add animation
CABasicAnimation *animation = [CABasicAnimation animation];
// Which property of the keyPath content object requires animation
animation.keyPath = @"path";
// Set up proxy
animation.delegate = self;
// The value at the end of the changed property
animation.toValue = (__bridge id _Nullable)(self.endPath);
// Animation duration
animation.duration = 0.25;
// Do not remove after completion
animation.removedOnCompletion = NO;
animation.fillMode = kCAFillModeForwards;