Kevin

Merge pull request #53 from ZhangHang/master

Simple Pie chart for PNChart
... ... @@ -16,3 +16,4 @@
#import "PNBarChart.h"
#import "PNCircleChart.h"
#import "PNChartDelegate.h"
#import "PNPieChart.h"
... ...
//
// PNPieChart.h
// PNChartDemo
//
// Created by Hang Zhang on 14-5-5.
// Copyright (c) 2014年 kevinzhow. All rights reserved.
//
#import <UIKit/UIKit.h>
#import "PNPieChartDataItem.h"
@interface PNPieChart : UIView
- (id)initWithFrame:(CGRect)frame items:(NSArray *)items;
@property (nonatomic, readonly) NSArray *items;
@property (nonatomic) UIFont *descriptionTextFont; //default is [UIFont fontWithName:@"Avenir-Medium" size:18.0];
@property (nonatomic) UIColor *descriptionTextColor; //default is [UIColor whiteColor]
@property (nonatomic) UIColor *descriptionTextShadowColor; //default is [[UIColor blackColor] colorWithAlphaComponent:0.4]
@property (nonatomic) CGSize descriptionTextShadowOffset; //default is CGSizeMake(0, 1)
@property (nonatomic) NSTimeInterval duration;//default is 1.0
- (void)strokeChart;
@end
... ...
//
// PNPieChart.m
// PNChartDemo
//
// Created by Hang Zhang on 14-5-5.
// Copyright (c) 2014年 kevinzhow. All rights reserved.
//
#import "PNPieChart.h"
@interface PNPieChart()
@property (nonatomic, readwrite) NSArray *items;
@property (nonatomic) CGFloat total;
@property (nonatomic) CGFloat currentTotal;
@property (nonatomic) CGFloat outterCircleRadius;
@property (nonatomic) CGFloat innerCircleRadius;
@property (nonatomic) UIView *contentView;
@property (nonatomic) CAShapeLayer *pieLayer;
@property (nonatomic) NSMutableArray *descriptionLabels;
- (void)loadDefault;
- (UILabel *)descriptionLabelForItemAtIndex:(NSUInteger)index;
- (PNPieChartDataItem *)dataItemForIndex:(NSUInteger)index;
- (CAShapeLayer *)newCircleLayerWithRadius:(CGFloat)radius
borderWidth:(CGFloat)borderWidth
fillColor:(UIColor *)fillColor
borderColor:(UIColor *)borderColor
startPercentage:(CGFloat)startPercentage
endPercentage:(CGFloat)endPercentage;
@end
@implementation PNPieChart
-(id)initWithFrame:(CGRect)frame items:(NSArray *)items{
self = [self initWithFrame:frame];
if(self){
_items = [NSArray arrayWithArray:items];
_outterCircleRadius = CGRectGetWidth(self.bounds)/2;
_innerCircleRadius = CGRectGetWidth(self.bounds)/6;
_descriptionTextColor = [UIColor whiteColor];
_descriptionTextFont = [UIFont fontWithName:@"Avenir-Medium" size:18.0];
_descriptionTextShadowColor = [[UIColor blackColor] colorWithAlphaComponent:0.4];
_descriptionTextShadowOffset = CGSizeMake(0, 1);
_duration = 1.0;
[self loadDefault];
}
return self;
}
- (void)loadDefault{
_currentTotal = 0;
_total = 0;
[_contentView removeFromSuperview];
_contentView = [[UIView alloc] initWithFrame:self.bounds];
[self addSubview:_contentView];
[_descriptionLabels removeAllObjects];
_descriptionLabels = [NSMutableArray new];
_pieLayer = [CAShapeLayer layer];
[_contentView.layer addSublayer:_pieLayer];
}
#pragma mark -
- (void)strokeChart{
[self loadDefault];
[self.items enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
_total +=((PNPieChartDataItem *)obj).value;
}];
PNPieChartDataItem *currentItem;
CGFloat currentValue = 0;
for (int i = 0; i < _items.count; i++) {
currentItem = [self dataItemForIndex:i];
CGFloat startPercnetage = currentValue/_total;
CGFloat endPercentage = (currentValue + currentItem.value)/_total;
CAShapeLayer *currentPieLayer = [self newCircleLayerWithRadius:_innerCircleRadius + (_outterCircleRadius - _innerCircleRadius)/2
borderWidth:_outterCircleRadius - _innerCircleRadius
fillColor:[UIColor clearColor]
borderColor:currentItem.color
startPercentage:startPercnetage
endPercentage:endPercentage];
[_pieLayer addSublayer:currentPieLayer];
currentValue+=currentItem.value;
}
[self maskChart];
currentValue = 0;
for (int i = 0; i < _items.count; i++) {
currentItem = [self dataItemForIndex:i];
UILabel *descriptionLabel = [self descriptionLabelForItemAtIndex:i];
[_contentView addSubview:descriptionLabel];
currentValue+=currentItem.value;
[_descriptionLabels addObject:descriptionLabel];
}
}
- (UILabel *)descriptionLabelForItemAtIndex:(NSUInteger)index{
PNPieChartDataItem *currentDataItem = [self dataItemForIndex:index];
CGFloat distance = _innerCircleRadius + (_outterCircleRadius - _innerCircleRadius) / 2;
CGFloat centerPercentage =(_currentTotal + currentDataItem.value /2 ) / _total;
CGFloat rad = centerPercentage * 2 * M_PI;
_currentTotal += currentDataItem.value;
NSString *titleText = currentDataItem.description;
if(!titleText){
titleText = [NSString stringWithFormat:@"%.0f%%",currentDataItem.value/ _total * 100];
}
CGPoint center = CGPointMake(_outterCircleRadius + distance * sin(rad),
_outterCircleRadius - distance * cos(rad));
CGRect frame;
frame.size = CGSizeMake(100, 80);
UILabel *descriptionLabel = [[UILabel alloc] initWithFrame:frame];
[descriptionLabel setText:titleText];
[descriptionLabel setFont:_descriptionTextFont];
[descriptionLabel setTextColor:_descriptionTextColor];
[descriptionLabel setShadowColor:_descriptionTextShadowColor];
[descriptionLabel setShadowOffset:_descriptionTextShadowOffset];
[descriptionLabel setTextAlignment:NSTextAlignmentCenter];
[descriptionLabel setCenter:center];
[descriptionLabel setAlpha:0];
return descriptionLabel;
}
- (PNPieChartDataItem *)dataItemForIndex:(NSUInteger)index{
return self.items[index];
}
#pragma mark private methods
- (CAShapeLayer *)newCircleLayerWithRadius:(CGFloat)radius
borderWidth:(CGFloat)borderWidth
fillColor:(UIColor *)fillColor
borderColor:(UIColor *)borderColor
startPercentage:(CGFloat)startPercentage
endPercentage:(CGFloat)endPercentage{
CAShapeLayer *circle = [CAShapeLayer layer];
CGPoint center = CGPointMake(CGRectGetMidX(self.bounds),CGRectGetMidY(self.bounds));
UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:center
radius:radius
startAngle:-M_PI_2
endAngle:M_PI_2 * 3
clockwise:YES];
circle.fillColor = fillColor.CGColor;
circle.strokeColor = borderColor.CGColor;
circle.strokeStart = startPercentage;
circle.strokeEnd = endPercentage;
circle.lineWidth = borderWidth;
circle.path = path.CGPath;
return circle;
}
- (void)maskChart{
CAShapeLayer *maskLayer = [self newCircleLayerWithRadius:_innerCircleRadius + (_outterCircleRadius - _innerCircleRadius)/2
borderWidth:_outterCircleRadius - _innerCircleRadius
fillColor:[UIColor clearColor]
borderColor:[UIColor blackColor]
startPercentage:0
endPercentage:1];
_pieLayer.mask = maskLayer;
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
animation.duration = _duration;
animation.fromValue = @0;
animation.toValue = @1;
animation.delegate = self;
animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
animation.removedOnCompletion = YES;
[maskLayer addAnimation:animation forKey:@"circleAnimation"];
}
- (void)createArcAnimationForLayer:(CAShapeLayer *)layer ForKey:(NSString *)key fromValue:(NSNumber *)from toValue:(NSNumber *)to Delegate:(id)delegate
{
CABasicAnimation *arcAnimation = [CABasicAnimation animationWithKeyPath:key];
arcAnimation.fromValue = @0;
[arcAnimation setToValue:to];
[arcAnimation setDelegate:delegate];
[arcAnimation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionDefault]];
[layer addAnimation:arcAnimation forKey:key];
[layer setValue:to forKey:key];
}
- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag{
[_descriptionLabels enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
[UIView animateWithDuration:0.2 animations:^(){
[obj setAlpha:1];
}];
}];
}
@end
... ...
//
// PNPieChartDataItem.h
// PNChartDemo
//
// Created by Hang Zhang on 14-5-5.
// Copyright (c) 2014年 kevinzhow. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface PNPieChartDataItem : NSObject
+ (instancetype)dataItemWithValue:(CGFloat)value
color:(UIColor*)color;
+ (instancetype)dataItemWithValue:(CGFloat)value
color:(UIColor*)color
description:(NSString *)description;
@property (nonatomic, readonly) CGFloat value;
@property (nonatomic, readonly) UIColor *color;
@property (nonatomic, readonly) NSString *description;
@end
... ...
//
// PNPieChartDataItem.m
// PNChartDemo
//
// Created by Hang Zhang on 14-5-5.
// Copyright (c) 2014年 kevinzhow. All rights reserved.
//
#import "PNPieChartDataItem.h"
@interface PNPieChartDataItem()
@property (nonatomic, readwrite) CGFloat value;
@property (nonatomic, readwrite) UIColor *color;
@property (nonatomic, readwrite) NSString *description;
@end
@implementation PNPieChartDataItem
+ (instancetype)dataItemWithValue:(CGFloat)value
color:(UIColor*)color{
PNPieChartDataItem *item = [PNPieChartDataItem new];
item.value = value;
item.color = color;
return item;
}
+ (instancetype)dataItemWithValue:(CGFloat)value
color:(UIColor*)color
description:(NSString *)description{
PNPieChartDataItem *item = [PNPieChartDataItem dataItemWithValue:value color:color];
item.description = description;
return item;
}
@end
... ...
... ... @@ -32,6 +32,8 @@
9FE15DFC190BB014004129F5 /* PNLineChartData.m in Sources */ = {isa = PBXBuildFile; fileRef = 9FE15DF3190BB014004129F5 /* PNLineChartData.m */; };
9FE15DFD190BB014004129F5 /* PNLineChartDataItem.m in Sources */ = {isa = PBXBuildFile; fileRef = 9FE15DF5190BB014004129F5 /* PNLineChartDataItem.m */; };
E2C3ED5773A1409C8367CC70 /* libPods.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3BA6321352024B1FBA0158B0 /* libPods.a */; };
F938F7E11917727E00B4448E /* PNPieChart.m in Sources */ = {isa = PBXBuildFile; fileRef = F938F7E01917727E00B4448E /* PNPieChart.m */; };
F938F7E4191772F200B4448E /* PNPieChartDataItem.m in Sources */ = {isa = PBXBuildFile; fileRef = F938F7E3191772F200B4448E /* PNPieChartDataItem.m */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
... ... @@ -87,6 +89,10 @@
9FE15DF4190BB014004129F5 /* PNLineChartDataItem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PNLineChartDataItem.h; sourceTree = "<group>"; };
9FE15DF5190BB014004129F5 /* PNLineChartDataItem.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PNLineChartDataItem.m; sourceTree = "<group>"; };
F161CF4F7A8C4BD2AB65FB4F /* Pods.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.xcconfig; path = Pods/Pods.xcconfig; sourceTree = "<group>"; };
F938F7DF1917727E00B4448E /* PNPieChart.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PNPieChart.h; sourceTree = "<group>"; };
F938F7E01917727E00B4448E /* PNPieChart.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PNPieChart.m; sourceTree = "<group>"; };
F938F7E2191772F200B4448E /* PNPieChartDataItem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PNPieChartDataItem.h; sourceTree = "<group>"; };
F938F7E3191772F200B4448E /* PNPieChartDataItem.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PNPieChartDataItem.m; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
... ... @@ -205,6 +211,7 @@
9FE15DE0190BB014004129F5 /* PNChart */ = {
isa = PBXGroup;
children = (
F938F7DE191770FE00B4448E /* PNPieChart */,
9FE15DE1190BB014004129F5 /* PNBarChart */,
9FE15DE6190BB014004129F5 /* PNChart.h */,
9FE15DE7190BB014004129F5 /* PNChartDelegate.h */,
... ... @@ -251,6 +258,17 @@
path = PNLineChart;
sourceTree = "<group>";
};
F938F7DE191770FE00B4448E /* PNPieChart */ = {
isa = PBXGroup;
children = (
F938F7DF1917727E00B4448E /* PNPieChart.h */,
F938F7E01917727E00B4448E /* PNPieChart.m */,
F938F7E2191772F200B4448E /* PNPieChartDataItem.h */,
F938F7E3191772F200B4448E /* PNPieChartDataItem.m */,
);
path = PNPieChart;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
... ... @@ -392,9 +410,11 @@
9FE15DFD190BB014004129F5 /* PNLineChartDataItem.m in Sources */,
9FA23B10184A5944002DBBA4 /* PCChartsTableViewController.m in Sources */,
9FE15DF9190BB014004129F5 /* PNCircleChart.m in Sources */,
F938F7E4191772F200B4448E /* PNPieChartDataItem.m in Sources */,
0AF7A874182AA9F6003645C4 /* main.m in Sources */,
9FE15DFC190BB014004129F5 /* PNLineChartData.m in Sources */,
9FE15DF7190BB014004129F5 /* PNBarChart.m in Sources */,
F938F7E11917727E00B4448E /* PNPieChart.m in Sources */,
0AF7A878182AA9F6003645C4 /* PCAppDelegate.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
... ...
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="4514" systemVersion="13A2093" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" initialViewController="9Rt-UT-IxH">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="5056" systemVersion="13C1021" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" initialViewController="9Rt-UT-IxH">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="3747"/>
<deployment defaultVersion="1536" identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="3733"/>
</dependencies>
<scenes>
<!--Chart View Controller - PNChart-->
... ... @@ -94,6 +95,26 @@
<segue destination="Tha-Wr-sPW" kind="push" identifier="circleChart" id="WSA-oe-ed1"/>
</connections>
</tableViewCell>
<tableViewCell contentMode="scaleToFill" selectionStyle="blue" accessoryType="disclosureIndicator" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" textLabel="N5A-vO-fq4" style="IBUITableViewCellStyleDefault" id="1Ha-E5-to7">
<rect key="frame" x="0.0" y="196" width="320" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="1Ha-E5-to7" id="3YW-gb-VCd">
<rect key="frame" x="0.0" y="0.0" width="287" height="43"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="left" text="PieChart" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="N5A-vO-fq4">
<rect key="frame" x="15" y="0.0" width="270" height="43"/>
<autoresizingMask key="autoresizingMask"/>
<fontDescription key="fontDescription" type="system" pointSize="18"/>
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
</tableViewCellContentView>
<connections>
<segue destination="Tha-Wr-sPW" kind="push" identifier="pieChart" id="pvQ-oy-a9a"/>
</connections>
</tableViewCell>
</cells>
</tableViewSection>
</sections>
... ... @@ -126,6 +147,6 @@
<simulatedScreenMetrics key="destination" type="retina4"/>
</simulatedMetricsContainer>
<inferredMetricsTieBreakers>
<segue reference="XHj-XM-h67"/>
<segue reference="pvQ-oy-a9a"/>
</inferredMetricsTieBreakers>
</document>
... ...
... ... @@ -145,6 +145,36 @@
[viewController.view addSubview:circleChart];
viewController.title = @"Circle Chart";
}else if ([segue.identifier isEqualToString:@"pieChart"])
{
//Add LineChart
UILabel * pieChartLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 90, SCREEN_WIDTH, 30)];
pieChartLabel.text = @"Pie Chart";
pieChartLabel.textColor = PNFreshGreen;
pieChartLabel.font = [UIFont fontWithName:@"Avenir-Medium" size:23.0];
pieChartLabel.textAlignment = NSTextAlignmentCenter;
NSArray *items = @[[PNPieChartDataItem dataItemWithValue:10 color:PNRed],
[PNPieChartDataItem dataItemWithValue:20 color:PNBlue description:@"WWDC"],
[PNPieChartDataItem dataItemWithValue:40 color:PNGreen description:@"Google I/O"],
];
PNPieChart *pieChart = [[PNPieChart alloc] initWithFrame:CGRectMake(0, 135.0, SCREEN_WIDTH, SCREEN_WIDTH) items:items];
pieChart.descriptionTextColor = [UIColor whiteColor];
pieChart.descriptionTextFont = [UIFont fontWithName:@"Avenir-Medium" size:18.0];
[pieChart strokeChart];
[viewController.view addSubview:pieChartLabel];
[viewController.view addSubview:pieChart];
viewController.title = @"Pie Chart";
}
}
... ...