Showing
2 changed files
with
97 additions
and
65 deletions
| @@ -150,6 +150,8 @@ | @@ -150,6 +150,8 @@ | ||
| 150 | } | 150 | } |
| 151 | } | 151 | } |
| 152 | 152 | ||
| 153 | +#pragma mark - Touch at point | ||
| 154 | + | ||
| 153 | - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event | 155 | - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event |
| 154 | { | 156 | { |
| 155 | [self touchPoint:touches withEvent:event]; | 157 | [self touchPoint:touches withEvent:event]; |
| @@ -224,111 +226,157 @@ | @@ -224,111 +226,157 @@ | ||
| 224 | } | 226 | } |
| 225 | } | 227 | } |
| 226 | 228 | ||
| 229 | +#pragma mark - Draw Chart | ||
| 230 | + | ||
| 227 | - (void)strokeChart | 231 | - (void)strokeChart |
| 228 | { | 232 | { |
| 229 | _chartPath = [[NSMutableArray alloc] init]; | 233 | _chartPath = [[NSMutableArray alloc] init]; |
| 230 | _pointPath = [[NSMutableArray alloc] init]; | 234 | _pointPath = [[NSMutableArray alloc] init]; |
| 231 | 235 | ||
| 236 | + [self calculateChartPath:_chartPath andPointsPath:_pointPath andPathKeyPoints:_pathPoints]; | ||
| 232 | // Draw each line | 237 | // Draw each line |
| 233 | for (NSUInteger lineIndex = 0; lineIndex < self.chartData.count; lineIndex++) { | 238 | for (NSUInteger lineIndex = 0; lineIndex < self.chartData.count; lineIndex++) { |
| 234 | PNLineChartData *chartData = self.chartData[lineIndex]; | 239 | PNLineChartData *chartData = self.chartData[lineIndex]; |
| 235 | CAShapeLayer *chartLine = (CAShapeLayer *)self.chartLineArray[lineIndex]; | 240 | CAShapeLayer *chartLine = (CAShapeLayer *)self.chartLineArray[lineIndex]; |
| 236 | CAShapeLayer *pointLayer = (CAShapeLayer *)self.chartPointArray[lineIndex]; | 241 | CAShapeLayer *pointLayer = (CAShapeLayer *)self.chartPointArray[lineIndex]; |
| 242 | + UIGraphicsBeginImageContext(self.frame.size); | ||
| 243 | + // setup the color of the chart line | ||
| 244 | + if (chartData.color) { | ||
| 245 | + chartLine.strokeColor = [chartData.color CGColor]; | ||
| 246 | + } else { | ||
| 247 | + chartLine.strokeColor = [PNGreen CGColor]; | ||
| 248 | + pointLayer.strokeColor = [PNGreen CGColor]; | ||
| 249 | + } | ||
| 250 | + | ||
| 251 | + UIBezierPath *progressline = [_chartPath objectAtIndex:lineIndex]; | ||
| 252 | + UIBezierPath *pointPath = [_pointPath objectAtIndex:lineIndex]; | ||
| 253 | + | ||
| 254 | + chartLine.path = progressline.CGPath; | ||
| 255 | + pointLayer.path = pointPath.CGPath; | ||
| 256 | + | ||
| 257 | + [CATransaction begin]; | ||
| 258 | + CABasicAnimation *pathAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"]; | ||
| 259 | + pathAnimation.duration = 1.0; | ||
| 260 | + pathAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; | ||
| 261 | + pathAnimation.fromValue = @0.0f; | ||
| 262 | + pathAnimation.toValue = @1.0f; | ||
| 263 | + | ||
| 264 | + [chartLine addAnimation:pathAnimation forKey:@"strokeEndAnimation"]; | ||
| 265 | + chartLine.strokeEnd = 1.0; | ||
| 266 | + | ||
| 267 | + // if you want cancel the point animation, conment this code, the point will show immediately | ||
| 268 | + if (chartData.inflexionPointStyle != PNLineChartPointStyleNone) { | ||
| 269 | + [pointLayer addAnimation:pathAnimation forKey:@"strokeEndAnimation"]; | ||
| 270 | + } | ||
| 271 | + | ||
| 272 | + [CATransaction commit]; | ||
| 237 | 273 | ||
| 274 | + UIGraphicsEndImageContext(); | ||
| 275 | + } | ||
| 276 | +} | ||
| 277 | + | ||
| 278 | + | ||
| 279 | +- (void)calculateChartPath:(NSMutableArray *)chartPath andPointsPath:(NSMutableArray *)pointsPath andPathKeyPoints:(NSMutableArray *)pathPoints | ||
| 280 | +{ | ||
| 281 | + | ||
| 282 | + // Draw each line | ||
| 283 | + for (NSUInteger lineIndex = 0; lineIndex < self.chartData.count; lineIndex++) { | ||
| 284 | + PNLineChartData *chartData = self.chartData[lineIndex]; | ||
| 285 | + | ||
| 238 | CGFloat yValue; | 286 | CGFloat yValue; |
| 239 | CGFloat innerGrade; | 287 | CGFloat innerGrade; |
| 240 | 288 | ||
| 241 | - UIGraphicsBeginImageContext(self.frame.size); | 289 | + |
| 242 | - | ||
| 243 | UIBezierPath *progressline = [UIBezierPath bezierPath]; | 290 | UIBezierPath *progressline = [UIBezierPath bezierPath]; |
| 244 | [progressline setLineWidth:chartData.lineWidth]; | 291 | [progressline setLineWidth:chartData.lineWidth]; |
| 245 | [progressline setLineCapStyle:kCGLineCapRound]; | 292 | [progressline setLineCapStyle:kCGLineCapRound]; |
| 246 | [progressline setLineJoinStyle:kCGLineJoinRound]; | 293 | [progressline setLineJoinStyle:kCGLineJoinRound]; |
| 247 | - | 294 | + |
| 248 | UIBezierPath *pointPath = [UIBezierPath bezierPath]; | 295 | UIBezierPath *pointPath = [UIBezierPath bezierPath]; |
| 249 | [pointPath setLineWidth:chartData.lineWidth]; | 296 | [pointPath setLineWidth:chartData.lineWidth]; |
| 250 | - | 297 | + |
| 251 | - [_chartPath addObject:progressline]; | 298 | + |
| 252 | - [_pointPath addObject:pointPath]; | 299 | + [chartPath insertObject:progressline atIndex:lineIndex]; |
| 253 | - | 300 | + [pointsPath insertObject:pointPath atIndex:lineIndex]; |
| 301 | + | ||
| 254 | if (!_showLabel) { | 302 | if (!_showLabel) { |
| 255 | _chartCavanHeight = self.frame.size.height - 2 * _yLabelHeight; | 303 | _chartCavanHeight = self.frame.size.height - 2 * _yLabelHeight; |
| 256 | _chartCavanWidth = self.frame.size.width; | 304 | _chartCavanWidth = self.frame.size.width; |
| 257 | _chartMargin = chartData.inflexionPointWidth; | 305 | _chartMargin = chartData.inflexionPointWidth; |
| 258 | _xLabelWidth = (_chartCavanWidth / ([_xLabels count] - 1)); | 306 | _xLabelWidth = (_chartCavanWidth / ([_xLabels count] - 1)); |
| 259 | } | 307 | } |
| 260 | - | 308 | + |
| 261 | NSMutableArray *linePointsArray = [[NSMutableArray alloc] init]; | 309 | NSMutableArray *linePointsArray = [[NSMutableArray alloc] init]; |
| 262 | - | 310 | + |
| 263 | int last_x = 0; | 311 | int last_x = 0; |
| 264 | int last_y = 0; | 312 | int last_y = 0; |
| 265 | CGFloat inflexionWidth = chartData.inflexionPointWidth; | 313 | CGFloat inflexionWidth = chartData.inflexionPointWidth; |
| 266 | - | 314 | + |
| 267 | for (NSUInteger i = 0; i < chartData.itemCount; i++) { | 315 | for (NSUInteger i = 0; i < chartData.itemCount; i++) { |
| 268 | - | 316 | + |
| 269 | yValue = chartData.getData(i).y; | 317 | yValue = chartData.getData(i).y; |
| 270 | - | 318 | + |
| 271 | if (!(_yValueMax - _yValueMin)) { | 319 | if (!(_yValueMax - _yValueMin)) { |
| 272 | innerGrade = 0.5; | 320 | innerGrade = 0.5; |
| 273 | } else { | 321 | } else { |
| 274 | innerGrade = (yValue - _yValueMin) / (_yValueMax - _yValueMin); | 322 | innerGrade = (yValue - _yValueMin) / (_yValueMax - _yValueMin); |
| 275 | } | 323 | } |
| 276 | - | 324 | + |
| 277 | CGFloat offSetX = (_chartCavanWidth) / (chartData.itemCount); | 325 | CGFloat offSetX = (_chartCavanWidth) / (chartData.itemCount); |
| 278 | - | 326 | + |
| 279 | int x = 2 * _chartMargin + (i * offSetX); | 327 | int x = 2 * _chartMargin + (i * offSetX); |
| 280 | int y = _chartCavanHeight - (innerGrade * _chartCavanHeight) + (_yLabelHeight / 2); | 328 | int y = _chartCavanHeight - (innerGrade * _chartCavanHeight) + (_yLabelHeight / 2); |
| 281 | - | 329 | + |
| 282 | // Circular point | 330 | // Circular point |
| 283 | if (chartData.inflexionPointStyle == PNLineChartPointStyleCircle) { | 331 | if (chartData.inflexionPointStyle == PNLineChartPointStyleCircle) { |
| 284 | - | 332 | + |
| 285 | CGRect circleRect = CGRectMake(x - inflexionWidth / 2, y - inflexionWidth / 2, inflexionWidth, inflexionWidth); | 333 | CGRect circleRect = CGRectMake(x - inflexionWidth / 2, y - inflexionWidth / 2, inflexionWidth, inflexionWidth); |
| 286 | CGPoint circleCenter = CGPointMake(circleRect.origin.x + (circleRect.size.width / 2), circleRect.origin.y + (circleRect.size.height / 2)); | 334 | CGPoint circleCenter = CGPointMake(circleRect.origin.x + (circleRect.size.width / 2), circleRect.origin.y + (circleRect.size.height / 2)); |
| 287 | - | 335 | + |
| 288 | [pointPath moveToPoint:CGPointMake(circleCenter.x + (inflexionWidth / 2), circleCenter.y)]; | 336 | [pointPath moveToPoint:CGPointMake(circleCenter.x + (inflexionWidth / 2), circleCenter.y)]; |
| 289 | [pointPath addArcWithCenter:circleCenter radius:inflexionWidth / 2 startAngle:0 endAngle:2 * M_PI clockwise:YES]; | 337 | [pointPath addArcWithCenter:circleCenter radius:inflexionWidth / 2 startAngle:0 endAngle:2 * M_PI clockwise:YES]; |
| 290 | - | 338 | + |
| 291 | if ( i != 0 ) { | 339 | if ( i != 0 ) { |
| 292 | - | 340 | + |
| 293 | // calculate the point for line | 341 | // calculate the point for line |
| 294 | float distance = sqrt(pow(x - last_x, 2) + pow(y - last_y, 2) ); | 342 | float distance = sqrt(pow(x - last_x, 2) + pow(y - last_y, 2) ); |
| 295 | float last_x1 = last_x + (inflexionWidth / 2) / distance * (x - last_x); | 343 | float last_x1 = last_x + (inflexionWidth / 2) / distance * (x - last_x); |
| 296 | float last_y1 = last_y + (inflexionWidth / 2) / distance * (y - last_y); | 344 | float last_y1 = last_y + (inflexionWidth / 2) / distance * (y - last_y); |
| 297 | float x1 = x - (inflexionWidth / 2) / distance * (x - last_x); | 345 | float x1 = x - (inflexionWidth / 2) / distance * (x - last_x); |
| 298 | float y1 = y - (inflexionWidth / 2) / distance * (y - last_y); | 346 | float y1 = y - (inflexionWidth / 2) / distance * (y - last_y); |
| 299 | - | 347 | + |
| 300 | [progressline moveToPoint:CGPointMake(last_x1, last_y1)]; | 348 | [progressline moveToPoint:CGPointMake(last_x1, last_y1)]; |
| 301 | [progressline addLineToPoint:CGPointMake(x1, y1)]; | 349 | [progressline addLineToPoint:CGPointMake(x1, y1)]; |
| 302 | } | 350 | } |
| 303 | - | 351 | + |
| 304 | last_x = x; | 352 | last_x = x; |
| 305 | last_y = y; | 353 | last_y = y; |
| 306 | } | 354 | } |
| 307 | // Square point | 355 | // Square point |
| 308 | else if (chartData.inflexionPointStyle == PNLineChartPointStyleSquare) { | 356 | else if (chartData.inflexionPointStyle == PNLineChartPointStyleSquare) { |
| 309 | - | 357 | + |
| 310 | CGRect squareRect = CGRectMake(x - inflexionWidth / 2, y - inflexionWidth / 2, inflexionWidth, inflexionWidth); | 358 | CGRect squareRect = CGRectMake(x - inflexionWidth / 2, y - inflexionWidth / 2, inflexionWidth, inflexionWidth); |
| 311 | CGPoint squareCenter = CGPointMake(squareRect.origin.x + (squareRect.size.width / 2), squareRect.origin.y + (squareRect.size.height / 2)); | 359 | CGPoint squareCenter = CGPointMake(squareRect.origin.x + (squareRect.size.width / 2), squareRect.origin.y + (squareRect.size.height / 2)); |
| 312 | - | 360 | + |
| 313 | [pointPath moveToPoint:CGPointMake(squareCenter.x - (inflexionWidth / 2), squareCenter.y - (inflexionWidth / 2))]; | 361 | [pointPath moveToPoint:CGPointMake(squareCenter.x - (inflexionWidth / 2), squareCenter.y - (inflexionWidth / 2))]; |
| 314 | [pointPath addLineToPoint:CGPointMake(squareCenter.x + (inflexionWidth / 2), squareCenter.y - (inflexionWidth / 2))]; | 362 | [pointPath addLineToPoint:CGPointMake(squareCenter.x + (inflexionWidth / 2), squareCenter.y - (inflexionWidth / 2))]; |
| 315 | [pointPath addLineToPoint:CGPointMake(squareCenter.x + (inflexionWidth / 2), squareCenter.y + (inflexionWidth / 2))]; | 363 | [pointPath addLineToPoint:CGPointMake(squareCenter.x + (inflexionWidth / 2), squareCenter.y + (inflexionWidth / 2))]; |
| 316 | [pointPath addLineToPoint:CGPointMake(squareCenter.x - (inflexionWidth / 2), squareCenter.y + (inflexionWidth / 2))]; | 364 | [pointPath addLineToPoint:CGPointMake(squareCenter.x - (inflexionWidth / 2), squareCenter.y + (inflexionWidth / 2))]; |
| 317 | [pointPath closePath]; | 365 | [pointPath closePath]; |
| 318 | - | 366 | + |
| 319 | if ( i != 0 ) { | 367 | if ( i != 0 ) { |
| 320 | - | 368 | + |
| 321 | // calculate the point for line | 369 | // calculate the point for line |
| 322 | float distance = sqrt(pow(x - last_x, 2) + pow(y - last_y, 2) ); | 370 | float distance = sqrt(pow(x - last_x, 2) + pow(y - last_y, 2) ); |
| 323 | float last_x1 = last_x + (inflexionWidth / 2); | 371 | float last_x1 = last_x + (inflexionWidth / 2); |
| 324 | float last_y1 = last_y + (inflexionWidth / 2) / distance * (y - last_y); | 372 | float last_y1 = last_y + (inflexionWidth / 2) / distance * (y - last_y); |
| 325 | float x1 = x - (inflexionWidth / 2); | 373 | float x1 = x - (inflexionWidth / 2); |
| 326 | float y1 = y - (inflexionWidth / 2) / distance * (y - last_y); | 374 | float y1 = y - (inflexionWidth / 2) / distance * (y - last_y); |
| 327 | - | 375 | + |
| 328 | [progressline moveToPoint:CGPointMake(last_x1, last_y1)]; | 376 | [progressline moveToPoint:CGPointMake(last_x1, last_y1)]; |
| 329 | [progressline addLineToPoint:CGPointMake(x1, y1)]; | 377 | [progressline addLineToPoint:CGPointMake(x1, y1)]; |
| 330 | } | 378 | } |
| 331 | - | 379 | + |
| 332 | last_x = x; | 380 | last_x = x; |
| 333 | last_y = y; | 381 | last_y = y; |
| 334 | } | 382 | } |
| @@ -356,59 +404,30 @@ | @@ -356,59 +404,30 @@ | ||
| 356 | 404 | ||
| 357 | [progressline moveToPoint:CGPointMake(last_x1, last_y1)]; | 405 | [progressline moveToPoint:CGPointMake(last_x1, last_y1)]; |
| 358 | [progressline addLineToPoint:CGPointMake(x1, y1)]; | 406 | [progressline addLineToPoint:CGPointMake(x1, y1)]; |
| 359 | - } | 407 | + } |
| 360 | 408 | ||
| 361 | last_x = x; | 409 | last_x = x; |
| 362 | last_y = y; | 410 | last_y = y; |
| 363 | 411 | ||
| 364 | } else { | 412 | } else { |
| 365 | - | 413 | + |
| 366 | if ( i != 0 ) { | 414 | if ( i != 0 ) { |
| 367 | [progressline addLineToPoint:CGPointMake(x, y)]; | 415 | [progressline addLineToPoint:CGPointMake(x, y)]; |
| 368 | } | 416 | } |
| 369 | - | 417 | + |
| 370 | [progressline moveToPoint:CGPointMake(x, y)]; | 418 | [progressline moveToPoint:CGPointMake(x, y)]; |
| 371 | } | 419 | } |
| 372 | - | 420 | + |
| 373 | [linePointsArray addObject:[NSValue valueWithCGPoint:CGPointMake(x, y)]]; | 421 | [linePointsArray addObject:[NSValue valueWithCGPoint:CGPointMake(x, y)]]; |
| 374 | } | 422 | } |
| 375 | - | 423 | + |
| 376 | - [_pathPoints addObject:[linePointsArray copy]]; | 424 | + [pathPoints addObject:[linePointsArray copy]]; |
| 377 | - | 425 | + |
| 378 | - // setup the color of the chart line | ||
| 379 | - if (chartData.color) { | ||
| 380 | - chartLine.strokeColor = [chartData.color CGColor]; | ||
| 381 | - } else { | ||
| 382 | - chartLine.strokeColor = [PNGreen CGColor]; | ||
| 383 | - pointLayer.strokeColor = [PNGreen CGColor]; | ||
| 384 | - } | ||
| 385 | - | ||
| 386 | - [progressline stroke]; | ||
| 387 | - | ||
| 388 | - chartLine.path = progressline.CGPath; | ||
| 389 | - pointLayer.path = pointPath.CGPath; | ||
| 390 | - | ||
| 391 | - [CATransaction begin]; | ||
| 392 | - CABasicAnimation *pathAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"]; | ||
| 393 | - pathAnimation.duration = 1.0; | ||
| 394 | - pathAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; | ||
| 395 | - pathAnimation.fromValue = @0.0f; | ||
| 396 | - pathAnimation.toValue = @1.0f; | ||
| 397 | - | ||
| 398 | - [chartLine addAnimation:pathAnimation forKey:@"strokeEndAnimation"]; | ||
| 399 | - chartLine.strokeEnd = 1.0; | ||
| 400 | - | ||
| 401 | - // if you want cancel the point animation, conment this code, the point will show immediately | ||
| 402 | - if (chartData.inflexionPointStyle != PNLineChartPointStyleNone) { | ||
| 403 | - [pointLayer addAnimation:pathAnimation forKey:@"strokeEndAnimation"]; | ||
| 404 | - } | ||
| 405 | - | ||
| 406 | - [CATransaction commit]; | ||
| 407 | - | ||
| 408 | - UIGraphicsEndImageContext(); | ||
| 409 | } | 426 | } |
| 410 | } | 427 | } |
| 411 | 428 | ||
| 429 | +#pragma mark - Set Chart Data | ||
| 430 | + | ||
| 412 | - (void)setChartData:(NSArray *)data | 431 | - (void)setChartData:(NSArray *)data |
| 413 | { | 432 | { |
| 414 | if (data != _chartData) { | 433 | if (data != _chartData) { |
| @@ -479,6 +498,13 @@ | @@ -479,6 +498,13 @@ | ||
| 479 | } | 498 | } |
| 480 | } | 499 | } |
| 481 | 500 | ||
| 501 | +#pragma mark - Update Chart Data | ||
| 502 | + | ||
| 503 | +- (void)updateChartData:(NSArray *)data | ||
| 504 | +{ | ||
| 505 | + | ||
| 506 | +} | ||
| 507 | + | ||
| 482 | #define IOS7_OR_LATER [[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0 | 508 | #define IOS7_OR_LATER [[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0 |
| 483 | 509 | ||
| 484 | - (void)drawRect:(CGRect)rect | 510 | - (void)drawRect:(CGRect)rect |
-
Please register or login to post a comment