andi

merge

... ... @@ -157,7 +157,7 @@ displayCountingLabel:(BOOL)displayCountingLabel
[_circle addAnimation:pathAnimation forKey:@"strokeEndAnimation"];
_circle.strokeEnd = [_current floatValue] / [_total floatValue];
[_countingLabel countFrom:0 to:[_current floatValue] withDuration:self.duration];
[_countingLabel countFrom:0 to:[_current floatValue]/([_total floatValue]/100.0) withDuration:self.duration];
// Check if user wants to add a gradient from the start color to the bar color
... ... @@ -235,4 +235,4 @@ displayCountingLabel:(BOOL)displayCountingLabel
_total = total;
}
@end
\ No newline at end of file
@end
... ...
... ... @@ -104,6 +104,20 @@
}
}
- (CGFloat)computeEqualWidthForXLabels:(NSArray *)xLabels
{
CGFloat xLabelWidth;
if (_showLabel) {
xLabelWidth = _chartCavanWidth / [xLabels count];
} else {
xLabelWidth = (self.frame.size.width) / [xLabels count];
}
return xLabelWidth;
}
- (void)setXLabels:(NSArray *)xLabels
{
CGFloat xLabelWidth;
... ...
... ... @@ -12,21 +12,24 @@
@interface PNPieChart()
@property (nonatomic, readwrite) NSArray *items;
@property (nonatomic) CGFloat total;
@property (nonatomic) CGFloat currentTotal;
@property (nonatomic) NSArray *items;
@property (nonatomic) NSArray *endPercentages;
@property (nonatomic) CGFloat outerCircleRadius;
@property (nonatomic) CGFloat innerCircleRadius;
@property (nonatomic) UIView *contentView;
@property (nonatomic) CAShapeLayer *pieLayer;
@property (nonatomic) UIView *contentView;
@property (nonatomic) CAShapeLayer *pieLayer;
@property (nonatomic) NSMutableArray *descriptionLabels;
- (void)loadDefault;
- (UILabel *)descriptionLabelForItemAtIndex:(NSUInteger)index;
- (PNPieChartDataItem *)dataItemForIndex:(NSUInteger)index;
- (CGFloat)startPercentageForItemAtIndex:(NSUInteger)index;
- (CGFloat)endPercentageForItemAtIndex:(NSUInteger)index;
- (CGFloat)ratioForItemAtIndex:(NSUInteger)index;
- (CAShapeLayer *)newCircleLayerWithRadius:(CGFloat)radius
borderWidth:(CGFloat)borderWidth
... ... @@ -42,89 +45,86 @@
@implementation PNPieChart
-(id)initWithFrame:(CGRect)frame items:(NSArray *)items{
self = [self initWithFrame:frame];
if(self){
_items = [NSArray arrayWithArray:items];
_outerCircleRadius = 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];
self = [self initWithFrame:frame];
if(self){
_items = [NSArray arrayWithArray:items];
_outerCircleRadius = 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;
_duration = 1.0;
[self loadDefault];
}
return self;
[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];
__block CGFloat currentTotal = 0;
CGFloat total = [[self.items valueForKeyPath:@"@sum.value"] floatValue];
NSMutableArray *endPercentages = [NSMutableArray new];
[_items enumerateObjectsUsingBlock:^(PNPieChartDataItem *item, NSUInteger idx, BOOL *stop) {
if (total == 0){
[endPercentages addObject:@(1.0 / _items.count * (idx + 1))];
}else{
currentTotal += item.value;
[endPercentages addObject:@(currentTotal / total)];
}
}];
self.endPercentages = [endPercentages copy];
[_contentView removeFromSuperview];
_contentView = [[UIView alloc] initWithFrame:self.bounds];
[self addSubview:_contentView];
_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 + (_outerCircleRadius - _innerCircleRadius)/2
borderWidth:_outerCircleRadius - _innerCircleRadius
[self loadDefault];
PNPieChartDataItem *currentItem;
for (int i = 0; i < _items.count; i++) {
currentItem = [self dataItemForIndex:i];
CGFloat startPercnetage = [self startPercentageForItemAtIndex:i];
CGFloat endPercentage = [self endPercentageForItemAtIndex:i];
CGFloat radius = _innerCircleRadius + (_outerCircleRadius - _innerCircleRadius) / 2;
CGFloat borderWidth = _outerCircleRadius - _innerCircleRadius;
CAShapeLayer *currentPieLayer = [self newCircleLayerWithRadius:radius
borderWidth:borderWidth
fillColor:[UIColor clearColor]
borderColor:currentItem.color
startPercentage:startPercnetage
endPercentage:endPercentage];
[_pieLayer addSublayer:currentPieLayer];
currentValue+=currentItem.value;
}
[self maskChart];
currentValue = 0;
[_pieLayer addSublayer:currentPieLayer];
}
[self maskChart];
for (int i = 0; i < _items.count; i++) {
currentItem = [self dataItemForIndex:i];
UILabel *descriptionLabel = [self descriptionLabelForItemAtIndex:i];
[_contentView addSubview:descriptionLabel];
currentValue+=currentItem.value;
UILabel *descriptionLabel = [self descriptionLabelForItemAtIndex:i];
[_contentView addSubview:descriptionLabel];
[_descriptionLabels addObject:descriptionLabel];
}
}
}
- (UILabel *)descriptionLabelForItemAtIndex:(NSUInteger)index{
PNPieChartDataItem *currentDataItem = [self dataItemForIndex:index];
PNPieChartDataItem *currentDataItem = [self dataItemForIndex:index];
CGFloat distance = _innerCircleRadius + (_outerCircleRadius - _innerCircleRadius) / 2;
CGFloat centerPercentage =(_currentTotal + currentDataItem.value /2 ) / _total;
CGFloat centerPercentage = ([self startPercentageForItemAtIndex:index] + [self endPercentageForItemAtIndex:index])/ 2;
CGFloat rad = centerPercentage * 2 * M_PI;
_currentTotal += currentDataItem.value;
UILabel *descriptionLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 100, 80)];
NSString *titleText = currentDataItem.textDescription;
NSString *titleValue;
... ... @@ -132,7 +132,7 @@
if (self.showAbsoluteValues) {
titleValue = [NSString stringWithFormat:@"%.0f",currentDataItem.value];
}else{
titleValue = [NSString stringWithFormat:@"%.0f%%",currentDataItem.value/ _total * 100];
titleValue = [NSString stringWithFormat:@"%.0f%%",[self ratioForItemAtIndex:index] * 100];
}
if(!titleText || self.showOnlyValues){
descriptionLabel.text = titleValue;
... ... @@ -147,22 +147,37 @@
descriptionLabel.font = _descriptionTextFont;
CGSize labelSize = [descriptionLabel.text sizeWithAttributes:@{NSFontAttributeName:descriptionLabel.font}];
descriptionLabel.frame = CGRectMake(
descriptionLabel.frame.origin.x, descriptionLabel.frame.origin.y,
descriptionLabel.frame.size.width, labelSize.height);
descriptionLabel.numberOfLines = 0;
descriptionLabel.textColor = _descriptionTextColor;
descriptionLabel.shadowColor = _descriptionTextShadowColor;
descriptionLabel.shadowOffset = _descriptionTextShadowOffset;
descriptionLabel.textAlignment = NSTextAlignmentCenter;
descriptionLabel.center = center;
descriptionLabel.alpha = 0;
descriptionLabel.frame = CGRectMake(descriptionLabel.frame.origin.x, descriptionLabel.frame.origin.y,
descriptionLabel.frame.size.width, labelSize.height);
descriptionLabel.numberOfLines = 0;
descriptionLabel.textColor = _descriptionTextColor;
descriptionLabel.shadowColor = _descriptionTextShadowColor;
descriptionLabel.shadowOffset = _descriptionTextShadowOffset;
descriptionLabel.textAlignment = NSTextAlignmentCenter;
descriptionLabel.center = center;
descriptionLabel.alpha = 0;
descriptionLabel.backgroundColor = [UIColor clearColor];
return descriptionLabel;
return descriptionLabel;
}
- (PNPieChartDataItem *)dataItemForIndex:(NSUInteger)index{
return self.items[index];
return self.items[index];
}
- (CGFloat)startPercentageForItemAtIndex:(NSUInteger)index{
if(index == 0){
return 0;
}
return [_endPercentages[index - 1] floatValue];
}
- (CGFloat)endPercentageForItemAtIndex:(NSUInteger)index{
return [_endPercentages[index] floatValue];
}
- (CGFloat)ratioForItemAtIndex:(NSUInteger)index{
return [self endPercentageForItemAtIndex:index] - [self startPercentageForItemAtIndex:index];
}
#pragma mark private methods
... ... @@ -190,38 +205,42 @@
circle.lineWidth = borderWidth;
circle.path = path.CGPath;
return circle;
return circle;
}
- (void)maskChart{
CAShapeLayer *maskLayer = [self newCircleLayerWithRadius:_innerCircleRadius + (_outerCircleRadius - _innerCircleRadius)/2
borderWidth:_outerCircleRadius - _innerCircleRadius
CGFloat radius = _innerCircleRadius + (_outerCircleRadius - _innerCircleRadius) / 2;
CGFloat borderWidth = _outerCircleRadius - _innerCircleRadius;
CAShapeLayer *maskLayer = [self newCircleLayerWithRadius:radius
borderWidth:borderWidth
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;
_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"];
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)createArcAnimationForLayer:(CAShapeLayer *)layer
forKey:(NSString *)key
fromValue:(NSNumber *)from
toValue:(NSNumber *)to
delegate:(id)delegate{
CABasicAnimation *arcAnimation = [CABasicAnimation animationWithKeyPath:key];
arcAnimation.fromValue = @0;
arcAnimation.toValue = to;
arcAnimation.delegate = delegate;
arcAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionDefault];
[layer addAnimation:arcAnimation forKey:key];
[layer setValue:to forKey:key];
}
- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag{
... ...
... ... @@ -27,4 +27,11 @@
return item;
}
- (void)setValue:(CGFloat)value{
NSAssert(value >= 0, @"value should >= 0");
if (value != _value){
_value = value;
}
}
@end
... ...
... ... @@ -156,6 +156,24 @@
}
}
- (NSArray*) getAxisMinMax:(NSArray*)xValues
{
float min = [xValues[0] floatValue];
float max = [xValues[0] floatValue];
for (NSNumber *number in xValues)
{
if ([number floatValue] > max)
max = [number floatValue];
if ([number floatValue] < min)
min = [number floatValue];
}
NSArray *result = @[[NSNumber numberWithFloat:min], [NSNumber numberWithFloat:max]];
return result;
}
- (void)setAxisXLabel:(NSArray *)array {
if(array.count == ++_AxisX_partNumber){
[_axisX_labels removeAllObjects];
... ...
... ... @@ -64,7 +64,6 @@ data02.getData = ^(NSUInteger index) {
lineChart.chartData = @[data01, data02];
[lineChart strokeChart];
```
[![](https://dl.dropboxusercontent.com/u/1599662/bar.png)](https://dl.dropboxusercontent.com/u/1599662/bar.png)
... ... @@ -150,6 +149,46 @@ CGPoint end = CGPointMake(80, 45);
scatterChart.delegate = self;
```
#### Legend
Legend has been added to PNChart for Line and Pie Charts. Legend items position can be stacked or in series.
[![](https://dl.dropboxusercontent.com/u/4904447/pnchart_legend_1.png)](https://dl.dropboxusercontent.com/u/4904447/pnchart_legend_1.png)
[![](https://dl.dropboxusercontent.com/u/4904447/pnchart_legend_2.png)](https://dl.dropboxusercontent.com/u/4904447/pnchart_legend_2.png)
```objective-c
#import "PNChart.h"
//For Line Chart
//Add Line Titles for the Legend
data01.dataTitle = @"Alpha";
data02.dataTitle = @"Beta Beta Beta Beta";
//Build the legend
self.lineChart.legendStyle = PNLegendItemStyleSerial;
self.lineChart.legendFontSize = 12.0;
UIView *legend = [self.lineChart getLegendWithMaxWidth:320];
//Move legend to the desired position and add to view
[legend setFrame:CGRectMake(100, 400, legend.frame.size.width, legend.frame.size.height)];
[self.view addSubview:legend];
//For Pie Chart
//Build the legend
self.pieChart.legendStyle = PNLegendItemStyleStacked;
self.pieChart.legendFontSize = 12.0;
UIView *legend = [self.pieChart getLegendWithMaxWidth:200];
//Move legend to the desired position and add to view
[legend setFrame:CGRectMake(130, 350, legend.frame.size.width, legend.frame.size.height)];
[self.view addSubview:legend];
```
#### Update Value
Now it's easy to update value in real time
... ...