Zhang Hang

PieChart divides equally when all value of data items are 0

@@ -11,8 +11,7 @@ @@ -11,8 +11,7 @@
11 @interface PNPieChart() 11 @interface PNPieChart()
12 12
13 @property (nonatomic, readwrite) NSArray *items; 13 @property (nonatomic, readwrite) NSArray *items;
14 -@property (nonatomic) CGFloat total; 14 +@property (nonatomic) NSArray *endPercentages;
15 -@property (nonatomic) CGFloat currentTotal;  
16 15
17 @property (nonatomic) CGFloat outerCircleRadius; 16 @property (nonatomic) CGFloat outerCircleRadius;
18 @property (nonatomic) CGFloat innerCircleRadius; 17 @property (nonatomic) CGFloat innerCircleRadius;
@@ -21,11 +20,14 @@ @@ -21,11 +20,14 @@
21 @property (nonatomic) CAShapeLayer *pieLayer; 20 @property (nonatomic) CAShapeLayer *pieLayer;
22 @property (nonatomic) NSMutableArray *descriptionLabels; 21 @property (nonatomic) NSMutableArray *descriptionLabels;
23 22
  23 +
24 - (void)loadDefault; 24 - (void)loadDefault;
25 25
26 - (UILabel *)descriptionLabelForItemAtIndex:(NSUInteger)index; 26 - (UILabel *)descriptionLabelForItemAtIndex:(NSUInteger)index;
27 - (PNPieChartDataItem *)dataItemForIndex:(NSUInteger)index; 27 - (PNPieChartDataItem *)dataItemForIndex:(NSUInteger)index;
28 - 28 +- (CGFloat)startPercentageForItemAtIndex:(NSUInteger)index;
  29 +- (CGFloat)endPercentageForItemAtIndex:(NSUInteger)index;
  30 +- (CGFloat)ratioForItemAtIndex:(NSUInteger)index;
29 - (CAShapeLayer *)newCircleLayerWithRadius:(CGFloat)radius 31 - (CAShapeLayer *)newCircleLayerWithRadius:(CGFloat)radius
30 borderWidth:(CGFloat)borderWidth 32 borderWidth:(CGFloat)borderWidth
31 fillColor:(UIColor *)fillColor 33 fillColor:(UIColor *)fillColor
@@ -58,15 +60,23 @@ @@ -58,15 +60,23 @@
58 return self; 60 return self;
59 } 61 }
60 62
61 -  
62 - (void)loadDefault{ 63 - (void)loadDefault{
63 - _currentTotal = 0; 64 + __block CGFloat currentTotal = 0;
64 - _total = 0; 65 + CGFloat total = [[self.items valueForKeyPath:@"@sum.value"] floatValue];
  66 + NSMutableArray *endPercentages = [NSMutableArray new];
  67 + [_items enumerateObjectsUsingBlock:^(PNPieChartDataItem *item, NSUInteger idx, BOOL *stop) {
  68 + if (total == 0){
  69 + [endPercentages addObject:@(1.0/_items.count*(idx+1))];
  70 + }else{
  71 + currentTotal += item.value;
  72 + [endPercentages addObject:@(currentTotal/total)];
  73 + }
  74 + }];
  75 + self.endPercentages = [endPercentages copy];
65 76
66 [_contentView removeFromSuperview]; 77 [_contentView removeFromSuperview];
67 _contentView = [[UIView alloc] initWithFrame:self.bounds]; 78 _contentView = [[UIView alloc] initWithFrame:self.bounds];
68 [self addSubview:_contentView]; 79 [self addSubview:_contentView];
69 - [_descriptionLabels removeAllObjects];  
70 _descriptionLabels = [NSMutableArray new]; 80 _descriptionLabels = [NSMutableArray new];
71 81
72 _pieLayer = [CAShapeLayer layer]; 82 _pieLayer = [CAShapeLayer layer];
@@ -78,39 +88,30 @@ @@ -78,39 +88,30 @@
78 - (void)strokeChart{ 88 - (void)strokeChart{
79 [self loadDefault]; 89 [self loadDefault];
80 90
81 - [self.items enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {  
82 - _total +=((PNPieChartDataItem *)obj).value;  
83 - }];  
84 -  
85 PNPieChartDataItem *currentItem; 91 PNPieChartDataItem *currentItem;
86 - CGFloat currentValue = 0;  
87 for (int i = 0; i < _items.count; i++) { 92 for (int i = 0; i < _items.count; i++) {
88 currentItem = [self dataItemForIndex:i]; 93 currentItem = [self dataItemForIndex:i];
89 94
90 95
91 - CGFloat startPercnetage = currentValue/_total; 96 + CGFloat startPercnetage = [self startPercentageForItemAtIndex:i];
92 - CGFloat endPercentage = (currentValue + currentItem.value)/_total; 97 + CGFloat endPercentage = [self endPercentageForItemAtIndex:i];
93 98
94 - CAShapeLayer *currentPieLayer = [self newCircleLayerWithRadius:_innerCircleRadius + (_outerCircleRadius - _innerCircleRadius)/2 99 + CGFloat radius = _innerCircleRadius + (_outerCircleRadius - _innerCircleRadius)/2;
95 - borderWidth:_outerCircleRadius - _innerCircleRadius 100 + CGFloat borderWidth = _outerCircleRadius - _innerCircleRadius;
  101 + CAShapeLayer *currentPieLayer = [self newCircleLayerWithRadius:radius
  102 + borderWidth:borderWidth
96 fillColor:[UIColor clearColor] 103 fillColor:[UIColor clearColor]
97 borderColor:currentItem.color 104 borderColor:currentItem.color
98 startPercentage:startPercnetage 105 startPercentage:startPercnetage
99 endPercentage:endPercentage]; 106 endPercentage:endPercentage];
100 [_pieLayer addSublayer:currentPieLayer]; 107 [_pieLayer addSublayer:currentPieLayer];
101 -  
102 - currentValue+=currentItem.value;  
103 -  
104 } 108 }
105 109
106 [self maskChart]; 110 [self maskChart];
107 111
108 - currentValue = 0;  
109 for (int i = 0; i < _items.count; i++) { 112 for (int i = 0; i < _items.count; i++) {
110 - currentItem = [self dataItemForIndex:i];  
111 UILabel *descriptionLabel = [self descriptionLabelForItemAtIndex:i]; 113 UILabel *descriptionLabel = [self descriptionLabelForItemAtIndex:i];
112 [_contentView addSubview:descriptionLabel]; 114 [_contentView addSubview:descriptionLabel];
113 - currentValue+=currentItem.value;  
114 [_descriptionLabels addObject:descriptionLabel]; 115 [_descriptionLabels addObject:descriptionLabel];
115 } 116 }
116 } 117 }
@@ -118,19 +119,17 @@ @@ -118,19 +119,17 @@
118 - (UILabel *)descriptionLabelForItemAtIndex:(NSUInteger)index{ 119 - (UILabel *)descriptionLabelForItemAtIndex:(NSUInteger)index{
119 PNPieChartDataItem *currentDataItem = [self dataItemForIndex:index]; 120 PNPieChartDataItem *currentDataItem = [self dataItemForIndex:index];
120 CGFloat distance = _innerCircleRadius + (_outerCircleRadius - _innerCircleRadius) / 2; 121 CGFloat distance = _innerCircleRadius + (_outerCircleRadius - _innerCircleRadius) / 2;
121 - CGFloat centerPercentage =(_currentTotal + currentDataItem.value /2 ) / _total; 122 + CGFloat centerPercentage = ([self startPercentageForItemAtIndex:index] + [self endPercentageForItemAtIndex:index])/2;
122 CGFloat rad = centerPercentage * 2 * M_PI; 123 CGFloat rad = centerPercentage * 2 * M_PI;
123 124
124 - _currentTotal += currentDataItem.value;  
125 -  
126 UILabel *descriptionLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 100, 80)]; 125 UILabel *descriptionLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 100, 80)];
127 NSString *titleText = currentDataItem.textDescription; 126 NSString *titleText = currentDataItem.textDescription;
128 if(!titleText){ 127 if(!titleText){
129 - titleText = [NSString stringWithFormat:@"%.0f%%",currentDataItem.value/ _total * 100]; 128 + titleText = [NSString stringWithFormat:@"%.0f%%",[self ratioForItemAtIndex:index] * 100];
130 descriptionLabel.text = titleText ; 129 descriptionLabel.text = titleText ;
131 } 130 }
132 else { 131 else {
133 - NSString* str = [NSString stringWithFormat:@"%.0f%%\n",currentDataItem.value/ _total * 100]; 132 + NSString* str = [NSString stringWithFormat:@"%.0f%%\n",[self ratioForItemAtIndex:index] * 100];
134 str = [str stringByAppendingString:titleText]; 133 str = [str stringByAppendingString:titleText];
135 descriptionLabel.text = str ; 134 descriptionLabel.text = str ;
136 } 135 }
@@ -158,6 +157,22 @@ @@ -158,6 +157,22 @@
158 return self.items[index]; 157 return self.items[index];
159 } 158 }
160 159
  160 +- (CGFloat)startPercentageForItemAtIndex:(NSUInteger)index{
  161 + if(index == 0){
  162 + return 0;
  163 + }
  164 +
  165 + return [_endPercentages[index - 1] floatValue];
  166 +}
  167 +
  168 +- (CGFloat)endPercentageForItemAtIndex:(NSUInteger)index{
  169 + return [_endPercentages[index] floatValue];
  170 +}
  171 +
  172 +- (CGFloat)ratioForItemAtIndex:(NSUInteger)index{
  173 + return [self endPercentageForItemAtIndex:index] - [self startPercentageForItemAtIndex:index];
  174 +}
  175 +
161 #pragma mark private methods 176 #pragma mark private methods
162 177
163 - (CAShapeLayer *)newCircleLayerWithRadius:(CGFloat)radius 178 - (CAShapeLayer *)newCircleLayerWithRadius:(CGFloat)radius
@@ -188,8 +203,10 @@ @@ -188,8 +203,10 @@
188 } 203 }
189 204
190 - (void)maskChart{ 205 - (void)maskChart{
191 - CAShapeLayer *maskLayer = [self newCircleLayerWithRadius:_innerCircleRadius + (_outerCircleRadius - _innerCircleRadius)/2 206 + CGFloat radius = _innerCircleRadius + (_outerCircleRadius - _innerCircleRadius)/2;
192 - borderWidth:_outerCircleRadius - _innerCircleRadius 207 + CGFloat borderWidth = _outerCircleRadius - _innerCircleRadius;
  208 + CAShapeLayer *maskLayer = [self newCircleLayerWithRadius:radius
  209 + borderWidth:borderWidth
193 fillColor:[UIColor clearColor] 210 fillColor:[UIColor clearColor]
194 borderColor:[UIColor blackColor] 211 borderColor:[UIColor blackColor]
195 startPercentage:0 212 startPercentage:0