Merge pull request #31 from Np2x/master
fixed #29, #24 & #23
Showing
3 changed files
with
86 additions
and
61 deletions
| @@ -11,6 +11,8 @@ | @@ -11,6 +11,8 @@ | ||
| 11 | #import "PNChart.h" | 11 | #import "PNChart.h" |
| 12 | #import "PNColor.h" | 12 | #import "PNColor.h" |
| 13 | #import "PNLineChart.h" | 13 | #import "PNLineChart.h" |
| 14 | +#import "PNLineChartData.h" | ||
| 15 | +#import "PNLineChartDataItem.h" | ||
| 14 | #import "PNBarChart.h" | 16 | #import "PNBarChart.h" |
| 15 | #import "PNCircleChart.h" | 17 | #import "PNCircleChart.h" |
| 16 | #import "PNChartDelegate.h" | 18 | #import "PNChartDelegate.h" |
| @@ -11,9 +11,8 @@ | @@ -11,9 +11,8 @@ | ||
| 11 | #import <QuartzCore/QuartzCore.h> | 11 | #import <QuartzCore/QuartzCore.h> |
| 12 | #import "PNChartDelegate.h" | 12 | #import "PNChartDelegate.h" |
| 13 | 13 | ||
| 14 | -#define chartMargin 10 | 14 | + |
| 15 | -#define yLabelMargin 15 | 15 | + |
| 16 | -#define yLabelHeight 11 | ||
| 17 | 16 | ||
| 18 | @interface PNLineChart : UIView | 17 | @interface PNLineChart : UIView |
| 19 | 18 | ||
| @@ -30,19 +29,29 @@ | @@ -30,19 +29,29 @@ | ||
| 30 | @property (strong, nonatomic) NSArray * yLabels; | 29 | @property (strong, nonatomic) NSArray * yLabels; |
| 31 | 30 | ||
| 32 | /** | 31 | /** |
| 33 | -* Array of `LineChartData` objects, one for each line. | 32 | + * Array of `LineChartData` objects, one for each line. |
| 34 | -*/ | 33 | + */ |
| 35 | @property (strong, nonatomic) NSArray *chartData; | 34 | @property (strong, nonatomic) NSArray *chartData; |
| 36 | 35 | ||
| 37 | @property (strong, nonatomic) NSMutableArray * pathPoints; | 36 | @property (strong, nonatomic) NSMutableArray * pathPoints; |
| 38 | 37 | ||
| 39 | @property (nonatomic) CGFloat xLabelWidth; | 38 | @property (nonatomic) CGFloat xLabelWidth; |
| 40 | 39 | ||
| 41 | -@property (nonatomic) float yValueMax; | 40 | +@property (nonatomic) CGFloat yValueMax; |
| 41 | + | ||
| 42 | +@property (nonatomic) CGFloat yValueMin; | ||
| 43 | + | ||
| 44 | +@property (nonatomic) NSInteger yLabelNum; | ||
| 45 | + | ||
| 46 | +@property (nonatomic) CGFloat yLabelHeight; | ||
| 47 | + | ||
| 48 | +@property (nonatomic) CGFloat chartCavanHeight; | ||
| 49 | + | ||
| 50 | +@property (nonatomic) CGFloat chartCavanWidth; | ||
| 51 | + | ||
| 52 | +@property (nonatomic) CGFloat chartMargin; | ||
| 42 | 53 | ||
| 43 | -@property (nonatomic) float chartCavanHeight; | ||
| 44 | 54 | ||
| 45 | -@property (nonatomic) float xLabelHeight; | ||
| 46 | 55 | ||
| 47 | @property (nonatomic) BOOL showLabel; | 56 | @property (nonatomic) BOOL showLabel; |
| 48 | 57 |
| @@ -54,34 +54,35 @@ | @@ -54,34 +54,35 @@ | ||
| 54 | 54 | ||
| 55 | -(void)setYLabels:(NSArray *)yLabels | 55 | -(void)setYLabels:(NSArray *)yLabels |
| 56 | { | 56 | { |
| 57 | - | 57 | + |
| 58 | - float level = _yValueMax / 5.0; | 58 | + CGFloat yStep = (_yValueMax-_yValueMin) / _yLabelNum; |
| 59 | - | 59 | + CGFloat yStepHeight = _chartCavanHeight / _yLabelNum; |
| 60 | + | ||
| 61 | + | ||
| 60 | NSInteger index = 0; | 62 | NSInteger index = 0; |
| 61 | - NSInteger num = [yLabels count] + 1; | 63 | + NSInteger num = _yLabelNum+1; |
| 62 | while (num > 0) { | 64 | while (num > 0) { |
| 63 | - CGFloat levelHeight = _chartCavanHeight /5.0; | 65 | + PNChartLabel * label = [[PNChartLabel alloc] initWithFrame:CGRectMake(0.0, (_chartCavanHeight - index * yStepHeight), _chartMargin, _yLabelHeight)]; |
| 64 | - PNChartLabel * label = [[PNChartLabel alloc] initWithFrame:CGRectMake(0.0,_chartCavanHeight - index * levelHeight + (levelHeight - yLabelHeight) , 20.0, yLabelHeight)]; | ||
| 65 | [label setTextAlignment:NSTextAlignmentRight]; | 66 | [label setTextAlignment:NSTextAlignmentRight]; |
| 66 | - label.text = [NSString stringWithFormat:@"%1.f",level * index]; | 67 | + label.text = [NSString stringWithFormat:@"%1.f",_yValueMin + (yStep * index)]; |
| 67 | [self addSubview:label]; | 68 | [self addSubview:label]; |
| 68 | index +=1 ; | 69 | index +=1 ; |
| 69 | num -= 1; | 70 | num -= 1; |
| 70 | } | 71 | } |
| 71 | - | 72 | + |
| 72 | } | 73 | } |
| 73 | 74 | ||
| 74 | -(void)setXLabels:(NSArray *)xLabels | 75 | -(void)setXLabels:(NSArray *)xLabels |
| 75 | { | 76 | { |
| 76 | _xLabels = xLabels; | 77 | _xLabels = xLabels; |
| 77 | - | 78 | + NSString* labelText; |
| 78 | if(_showLabel){ | 79 | if(_showLabel){ |
| 79 | - _xLabelWidth = (self.frame.size.width - chartMargin - 30.0)/[xLabels count]; | 80 | + _xLabelWidth = _chartCavanWidth/[xLabels count]; |
| 80 | 81 | ||
| 81 | for(int index = 0; index < xLabels.count; index++) | 82 | for(int index = 0; index < xLabels.count; index++) |
| 82 | { | 83 | { |
| 83 | - NSString* labelText = xLabels[index]; | 84 | + labelText = xLabels[index]; |
| 84 | - PNChartLabel * label = [[PNChartLabel alloc] initWithFrame:CGRectMake(index * _xLabelWidth + 30.0, self.frame.size.height - 30.0, _xLabelWidth, 20.0)]; | 85 | + PNChartLabel * label = [[PNChartLabel alloc] initWithFrame:CGRectMake(2*_chartMargin + (index * _xLabelWidth) - (_xLabelWidth / 2), _chartMargin + _chartCavanHeight, _xLabelWidth, _chartMargin)]; |
| 85 | [label setTextAlignment:NSTextAlignmentCenter]; | 86 | [label setTextAlignment:NSTextAlignmentCenter]; |
| 86 | label.text = labelText; | 87 | label.text = labelText; |
| 87 | [self addSubview:label]; | 88 | [self addSubview:label]; |
| @@ -137,44 +138,45 @@ | @@ -137,44 +138,45 @@ | ||
| 137 | for (NSUInteger lineIndex = 0; lineIndex < self.chartData.count; lineIndex++) { | 138 | for (NSUInteger lineIndex = 0; lineIndex < self.chartData.count; lineIndex++) { |
| 138 | PNLineChartData *chartData = self.chartData[lineIndex]; | 139 | PNLineChartData *chartData = self.chartData[lineIndex]; |
| 139 | CAShapeLayer *chartLine = (CAShapeLayer *) self.chartLineArray[lineIndex]; | 140 | CAShapeLayer *chartLine = (CAShapeLayer *) self.chartLineArray[lineIndex]; |
| 140 | - | 141 | + CGFloat yValue; |
| 142 | + CGFloat innerGrade; | ||
| 143 | + CGPoint point; | ||
| 144 | + | ||
| 141 | UIGraphicsBeginImageContext(self.frame.size); | 145 | UIGraphicsBeginImageContext(self.frame.size); |
| 142 | UIBezierPath * progressline = [UIBezierPath bezierPath]; | 146 | UIBezierPath * progressline = [UIBezierPath bezierPath]; |
| 143 | [_chartPath addObject:progressline]; | 147 | [_chartPath addObject:progressline]; |
| 144 | 148 | ||
| 145 | - PNLineChartDataItem *firstDataItem = chartData.getData(0); | ||
| 146 | - CGFloat firstValue = firstDataItem.y; | ||
| 147 | - | ||
| 148 | - CGFloat xPosition = _xLabelWidth; | ||
| 149 | 149 | ||
| 150 | + | ||
| 150 | if(!_showLabel){ | 151 | if(!_showLabel){ |
| 151 | - _chartCavanHeight = self.frame.size.height - _xLabelHeight*2; | 152 | + _chartCavanHeight = self.frame.size.height - 2*_yLabelHeight; |
| 152 | - xPosition = 0; | 153 | + _chartCavanWidth = self.frame.size.width; |
| 154 | + _chartMargin = 0.0; | ||
| 155 | + _xLabelWidth = (_chartCavanWidth / ([_xLabels count] -1)); | ||
| 153 | } | 156 | } |
| 154 | - | 157 | + |
| 155 | - CGFloat grade = (float)firstValue / _yValueMax; | ||
| 156 | NSMutableArray * linePointsArray = [[NSMutableArray alloc] init]; | 158 | NSMutableArray * linePointsArray = [[NSMutableArray alloc] init]; |
| 157 | - [progressline moveToPoint:CGPointMake( xPosition, _chartCavanHeight - grade * _chartCavanHeight + _xLabelHeight)]; | ||
| 158 | - [linePointsArray addObject:[NSValue valueWithCGPoint:CGPointMake( xPosition, _chartCavanHeight - grade * _chartCavanHeight + _xLabelHeight)]]; | ||
| 159 | [progressline setLineWidth:3.0]; | 159 | [progressline setLineWidth:3.0]; |
| 160 | [progressline setLineCapStyle:kCGLineCapRound]; | 160 | [progressline setLineCapStyle:kCGLineCapRound]; |
| 161 | [progressline setLineJoinStyle:kCGLineJoinRound]; | 161 | [progressline setLineJoinStyle:kCGLineJoinRound]; |
| 162 | - | ||
| 163 | 162 | ||
| 164 | - NSInteger index = 0; | 163 | + |
| 164 | + | ||
| 165 | + | ||
| 165 | for (NSUInteger i = 0; i < chartData.itemCount; i++) { | 166 | for (NSUInteger i = 0; i < chartData.itemCount; i++) { |
| 166 | 167 | ||
| 167 | - PNLineChartDataItem *dataItem = chartData.getData(i); | 168 | + yValue = chartData.getData(i).y; |
| 168 | - float value = dataItem.y; | 169 | + |
| 169 | - | 170 | + innerGrade = (yValue - _yValueMin) / ( _yValueMax - _yValueMin); |
| 170 | - CGFloat innerGrade = value / _yValueMax; | 171 | + |
| 171 | - if (index != 0) { | 172 | + point = CGPointMake(2*_chartMargin + (i * _xLabelWidth), _chartCavanHeight - (innerGrade * _chartCavanHeight) + ( _yLabelHeight /2 )); |
| 172 | - CGPoint point = CGPointMake(index * _xLabelWidth + 30.0 + _xLabelWidth / 2.0, _chartCavanHeight - (innerGrade * _chartCavanHeight) + _xLabelHeight); | 173 | + |
| 173 | - [linePointsArray addObject:[NSValue valueWithCGPoint:point]]; | 174 | + if (i != 0) { |
| 174 | [progressline addLineToPoint:point]; | 175 | [progressline addLineToPoint:point]; |
| 175 | - [progressline moveToPoint:point]; | ||
| 176 | } | 176 | } |
| 177 | - index += 1; | 177 | + |
| 178 | + [progressline moveToPoint:point]; | ||
| 179 | + [linePointsArray addObject:[NSValue valueWithCGPoint:point]]; | ||
| 178 | } | 180 | } |
| 179 | [_pathPoints addObject:[linePointsArray copy]]; | 181 | [_pathPoints addObject:[linePointsArray copy]]; |
| 180 | // setup the color of the chart line | 182 | // setup the color of the chart line |
| @@ -183,38 +185,39 @@ | @@ -183,38 +185,39 @@ | ||
| 183 | }else{ | 185 | }else{ |
| 184 | chartLine.strokeColor = [PNGreen CGColor]; | 186 | chartLine.strokeColor = [PNGreen CGColor]; |
| 185 | } | 187 | } |
| 186 | - | 188 | + |
| 187 | [progressline stroke]; | 189 | [progressline stroke]; |
| 188 | - | 190 | + |
| 189 | chartLine.path = progressline.CGPath; | 191 | chartLine.path = progressline.CGPath; |
| 190 | - | 192 | + |
| 191 | CABasicAnimation *pathAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"]; | 193 | CABasicAnimation *pathAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"]; |
| 192 | pathAnimation.duration = 1.0; | 194 | pathAnimation.duration = 1.0; |
| 193 | pathAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; | 195 | pathAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; |
| 194 | pathAnimation.fromValue = [NSNumber numberWithFloat:0.0f]; | 196 | pathAnimation.fromValue = [NSNumber numberWithFloat:0.0f]; |
| 195 | pathAnimation.toValue = [NSNumber numberWithFloat:1.0f]; | 197 | pathAnimation.toValue = [NSNumber numberWithFloat:1.0f]; |
| 196 | [chartLine addAnimation:pathAnimation forKey:@"strokeEndAnimation"]; | 198 | [chartLine addAnimation:pathAnimation forKey:@"strokeEndAnimation"]; |
| 197 | - | 199 | + |
| 198 | chartLine.strokeEnd = 1.0; | 200 | chartLine.strokeEnd = 1.0; |
| 199 | - | 201 | + |
| 200 | UIGraphicsEndImageContext(); | 202 | UIGraphicsEndImageContext(); |
| 201 | } | 203 | } |
| 202 | } | 204 | } |
| 203 | 205 | ||
| 204 | - (void)setChartData:(NSArray *)data { | 206 | - (void)setChartData:(NSArray *)data { |
| 205 | if (data != _chartData) { | 207 | if (data != _chartData) { |
| 206 | - | 208 | + |
| 207 | NSMutableArray *yLabelsArray = [NSMutableArray arrayWithCapacity:data.count]; | 209 | NSMutableArray *yLabelsArray = [NSMutableArray arrayWithCapacity:data.count]; |
| 208 | CGFloat yMax = 0.0f; | 210 | CGFloat yMax = 0.0f; |
| 209 | - | 211 | + CGFloat yMin = MAXFLOAT; |
| 212 | + CGFloat yValue; | ||
| 210 | // remove all shape layers before adding new ones | 213 | // remove all shape layers before adding new ones |
| 211 | for (CALayer *layer in self.chartLineArray) { | 214 | for (CALayer *layer in self.chartLineArray) { |
| 212 | [layer removeFromSuperlayer]; | 215 | [layer removeFromSuperlayer]; |
| 213 | } | 216 | } |
| 214 | self.chartLineArray = [NSMutableArray arrayWithCapacity:data.count]; | 217 | self.chartLineArray = [NSMutableArray arrayWithCapacity:data.count]; |
| 215 | - | 218 | + |
| 216 | for (PNLineChartData *chartData in data) { | 219 | for (PNLineChartData *chartData in data) { |
| 217 | - | 220 | + |
| 218 | // create as many chart line layers as there are data-lines | 221 | // create as many chart line layers as there are data-lines |
| 219 | CAShapeLayer *chartLine = [CAShapeLayer layer]; | 222 | CAShapeLayer *chartLine = [CAShapeLayer layer]; |
| 220 | chartLine.lineCap = kCALineCapRound; | 223 | chartLine.lineCap = kCALineCapRound; |
| @@ -224,27 +227,32 @@ | @@ -224,27 +227,32 @@ | ||
| 224 | chartLine.strokeEnd = 0.0; | 227 | chartLine.strokeEnd = 0.0; |
| 225 | [self.layer addSublayer:chartLine]; | 228 | [self.layer addSublayer:chartLine]; |
| 226 | [self.chartLineArray addObject:chartLine]; | 229 | [self.chartLineArray addObject:chartLine]; |
| 227 | - | 230 | + |
| 228 | for (NSUInteger i = 0; i < chartData.itemCount; i++) { | 231 | for (NSUInteger i = 0; i < chartData.itemCount; i++) { |
| 229 | - PNLineChartDataItem *dataItem = chartData.getData(i); | 232 | + yValue = chartData.getData(i).y; |
| 230 | - CGFloat yValue = dataItem.y; | ||
| 231 | [yLabelsArray addObject:[NSString stringWithFormat:@"%2f", yValue]]; | 233 | [yLabelsArray addObject:[NSString stringWithFormat:@"%2f", yValue]]; |
| 232 | - yMax = fmaxf(yMax, dataItem.y); | 234 | + yMax = fmaxf(yMax, yValue); |
| 235 | + yMin = fminf(yMin, yValue); | ||
| 233 | } | 236 | } |
| 234 | } | 237 | } |
| 235 | - | 238 | + |
| 236 | // Min value for Y label | 239 | // Min value for Y label |
| 237 | if (yMax < 5) { | 240 | if (yMax < 5) { |
| 238 | yMax = 5.0f; | 241 | yMax = 5.0f; |
| 239 | } | 242 | } |
| 243 | + if (yMin < 0){ | ||
| 244 | + yMin = 0.0f; | ||
| 245 | + } | ||
| 246 | + | ||
| 247 | + _yValueMin = yMin; | ||
| 240 | _yValueMax = yMax; | 248 | _yValueMax = yMax; |
| 241 | - | 249 | + |
| 242 | _chartData = data; | 250 | _chartData = data; |
| 243 | - | 251 | + |
| 244 | if (_showLabel) { | 252 | if (_showLabel) { |
| 245 | [self setYLabels:yLabelsArray]; | 253 | [self setYLabels:yLabelsArray]; |
| 246 | } | 254 | } |
| 247 | - | 255 | + |
| 248 | [self setNeedsDisplay]; | 256 | [self setNeedsDisplay]; |
| 249 | } | 257 | } |
| 250 | } | 258 | } |
| @@ -259,8 +267,14 @@ | @@ -259,8 +267,14 @@ | ||
| 259 | _showLabel = YES; | 267 | _showLabel = YES; |
| 260 | _pathPoints = [[NSMutableArray alloc] init]; | 268 | _pathPoints = [[NSMutableArray alloc] init]; |
| 261 | self.userInteractionEnabled = YES; | 269 | self.userInteractionEnabled = YES; |
| 262 | - _xLabelHeight = 20.0; | 270 | + |
| 263 | - _chartCavanHeight = self.frame.size.height - chartMargin * 2 - _xLabelHeight*2 ; | 271 | + _yLabelNum = 5.0; |
| 272 | + _yLabelHeight = [[[[PNChartLabel alloc] init] font] pointSize]; | ||
| 273 | + | ||
| 274 | + _chartMargin = 30; | ||
| 275 | + | ||
| 276 | + _chartCavanWidth = self.frame.size.width - _chartMargin *2; | ||
| 277 | + _chartCavanHeight = self.frame.size.height - _chartMargin * 2; | ||
| 264 | } | 278 | } |
| 265 | 279 | ||
| 266 | @end | 280 | @end |
-
Please register or login to post a comment