From 764722d0366346dc435aa906abdd25655e3b0769 Mon Sep 17 00:00:00 2001
From: 单军华 <WindShan@danjunhuas-MacBook-Pro.local>
Date: Fri, 03 Mar 2017 09:54:19 +0800
Subject: [PATCH] 图形绘制demo
---
PNChartdemo/PNChartdemo/PNChart/PNChartDelegate.h | 33
PNChartdemo/PNChartdemo/UICountingLabel/UICountingLabel.m | 234 +
PNChartdemo/PNChart/PNScatterChart.m | 445 ++
PNChartdemo/PNChartdemo/PNChart/PNScatterChart.h | 69
PNChartdemo/PNChart/PNPieChart.h | 68
PNChartdemo/PNChart/PNChart.h | 22
PNChartdemo/PNChart/PNScatterChart.h | 69
PNChartdemo/PNChart/PNLineChart.m | 1285 ++++++
PNChartdemo/PNChart/PNLineChartDataItem.m | 38
PNChartdemo/PNChart/PNPieChart.m | 508 ++
PNChartdemo/PNChartdemo/PCChartViewController.m | 490 ++
PNChartdemo/PNChartdemo/PNChart/PNScatterChartDataItem.m | 37
PNChartdemo/PNChart/PNLineChartDataItem.h | 17
PNChartdemo/PNChart/PNLineChart.h | 110
PNChartdemo/PNChart/PNScatterChartData.h | 38
PNChartdemo/PNChartdemo/PCChartViewController.h | 38
PNChartdemo/PNChartdemo/PNChart/PNLineChart.h | 110
PNChartdemo/PNChart/PNBar.h | 37
PNChartdemo/PNChartdemo/ViewController.m | 4
PNChartdemo/PNChartdemo/AppDelegate.m | 4
PNChartdemo/PNChart/PNBar.m | 288 +
PNChartdemo/PNChartdemo/ViewController.h | 4
PNChartdemo/PNChartdemo/AppDelegate.h | 4
PNChartdemo/PNChartdemo/UICountingLabel/UICountingLabel.h | 36
PNChartdemo/PNChart/PNRadarChart.h | 52
PNChartdemo/PNChartdemo/Base.lproj/Main.storyboard | 300 +
PNChartdemo/PNChartdemo/PNChart/PNPieChartDataItem.h | 25
PNChartdemo/PNChart/PNCircleChart.m | 267 +
PNChartdemo/PNChart/PNBarChart.m | 459 ++
PNChartdemo/PNChartdemo.xcodeproj/xcuserdata/WindShan.xcuserdatad/xcschemes/PNChartdemo.xcscheme | 91
PNChartdemo/PNChartdemo/PNChart/PNScatterChartDataItem.h | 19
PNChartdemo/PNChartdemo/PNChart/PNColor.h | 53
PNChartdemo/PNChartdemo/PNChart/PNPieChart.h | 68
PNChartdemo/PNChart/PNCircleChart.h | 74
PNChartdemo/PNChartdemo/PNChart/PNColor.m | 29
PNChartdemo/PNChartdemo/PNChart/PNChartLabel.m | 32
PNChartdemo/PNChartdemo/PNChart/PNPieChartDataItem.m | 38
PNChartdemo/PNChartdemo/PNChart/PNPieChart.m | 508 ++
PNChartdemo/PNChart/PNGenericChart.m | 54
PNChartdemo/PNChartdemo/PNChart/PNScatterChart.m | 445 ++
PNChartdemo/PNChartdemo/PNChart/PNChartLabel.h | 13
PNChartdemo/PNChartdemo/PNChart/PNLineChartDataItem.h | 17
PNChartdemo/PNChart/PNRadarChart.m | 373 +
PNChartdemo/PNChart/PNGenericChart.h | 48
PNChartdemo/PNChartdemo.xcodeproj/xcuserdata/WindShan.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist | 55
PNChartdemo/PNChartdemo/PNChart/PNBarChart.h | 123
PNChartdemo/PNChartdemo/PNChart/PNGenericChart.m | 54
PNChartdemo/PNChart/PNColor.h | 53
PNChartdemo/PNChartdemo/PNChart/PNBarChart.m | 459 ++
PNChartdemo/PNChartdemo/PNChart/PNLineChartDataItem.m | 38
PNChartdemo/PNChart/PNColor.m | 29
PNChartdemo/PNChartdemo/PNChart/PNChart.h | 22
PNChartdemo/PNChartdemo.xcodeproj/project.pbxproj | 479 ++
PNChartdemo/PNChartdemo/PNChart/PNGenericChart.h | 48
PNChartdemo/PNChart/PNPieChartDataItem.m | 38
PNChartdemo/PNChartdemo/Info.plist | 0
PNChartdemo/PNChart/PNBarChart.h | 123
PNChartdemo/PNChart/PNPieChartDataItem.h | 25
PNChartdemo/PNChartdemo/PCChartsTableViewController.h | 13
PNChartdemo/PNChartdemo/PNChartDemo-Prefix.pch | 16
PNChartdemo/PNChartdemo.xcodeproj/xcuserdata/WindShan.xcuserdatad/xcschemes/xcschememanagement.plist | 4
PNChartdemo/PNChartdemo/PCChartsTableViewController.m | 56
PNChartdemo/PNChartdemo/PNChart/PNRadarChart.h | 52
PNChartdemo/PNChartdemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata | 2
PNChartdemo/PNChartdemo/PNChart/PNCircleChart.h | 74
PNChartdemo/PNChart/PNRadarChartDataItem.m | 29
PNChartdemo/PNChartdemo/Base.lproj/LaunchScreen.storyboard | 0
PNChartdemo/PNChart/PNChartLabel.m | 32
PNChartdemo/PNChartdemo/PNChart/PNRadarChart.m | 373 +
PNChartdemo/PNChart/PNRadarChartDataItem.h | 19
PNChartdemo/PNChartdemo/PNChart/PNCircleChart.m | 267 +
PNChartdemo/PNChart/PNChartLabel.h | 13
PNChartdemo/PNChartdemo/PNChart/PNLineChart.m | 1284 ++++++
PNChartdemo/PNChartdemo.xcodeproj/project.xcworkspace/xcuserdata/WindShan.xcuserdatad/UserInterfaceState.xcuserstate | 0
PNChartdemo/PNChart/PNChartDelegate.h | 33
PNChartdemo/PNChart/PNScatterChartData.m | 31
PNChartdemo/PNChartdemo/PNChart/PNBar.h | 37
PNChartdemo/PNChartdemo/PNChart/PNScatterChartData.m | 31
/dev/null | 114
PNChartdemo/PNChart/PNLineChartData.m | 54
PNChartdemo/PNChart/PNScatterChartDataItem.h | 19
PNChartdemo/PNChartdemo/main.m | 4
PNChartdemo/PNChartdemo/PNChart/PNBar.m | 288 +
PNChartdemo/PNChartdemo/PNChart/PNRadarChartDataItem.m | 29
PNChartdemo/PNChart/PNScatterChartDataItem.m | 37
PNChartdemo/PNChartdemo/PNChart/PNScatterChartData.h | 38
PNChartdemo/PNChartdemo/PNChart/PNRadarChartDataItem.h | 19
PNChartdemo/PNChartdemo/Assets.xcassets/AppIcon.appiconset/Contents.json | 0
PNChartdemo/PNChartdemo/PNChart/PNLineChartData.m | 54
PNChartdemo/PNChartdemo/PNChart/PNLineChartData.h | 61
PNChartdemo/PNChart/PNLineChartData.h | 61
91 files changed, 11,516 insertions(+), 127 deletions(-)
diff --git a/PNChartdemo/PNChart/PNBar.h b/PNChartdemo/PNChart/PNBar.h
new file mode 100755
index 0000000..68e6b0b
--- /dev/null
+++ b/PNChartdemo/PNChart/PNBar.h
@@ -0,0 +1,37 @@
+//
+// PNBar.h
+// PNChartDemo
+//
+// Created by kevin on 11/7/13.
+// Copyright (c) 2013��� kevinzhow. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+#import <QuartzCore/QuartzCore.h>
+
+@interface PNBar : UIView
+
+
+- (void)rollBack;
+
+@property (nonatomic) float grade;
+@property (nonatomic) float maxDivisor;
+
+@property (nonatomic) CAShapeLayer *chartLine;
+@property (nonatomic) UIColor *barColor;
+@property (nonatomic) UIColor *barColorGradientStart;
+@property (nonatomic) CGFloat barRadius;
+@property (nonatomic) CAShapeLayer *gradientMask;
+
+@property (nonatomic) CAShapeLayer *gradeLayer;
+@property (nonatomic) CATextLayer* textLayer;
+
+/** Text color for all bars in the chart. */
+@property (nonatomic) UIColor * labelTextColor;
+
+@property (nonatomic, assign) BOOL isNegative; //!< ���������������
+@property (nonatomic, assign) BOOL isShowNumber; //!< ������������numbers
+
+/** Display the bar with or without animation. Default is YES. **/
+@property (nonatomic) BOOL displayAnimated;
+@end
diff --git a/PNChartdemo/PNChart/PNBar.m b/PNChartdemo/PNChart/PNBar.m
new file mode 100755
index 0000000..8ea5fc9
--- /dev/null
+++ b/PNChartdemo/PNChart/PNBar.m
@@ -0,0 +1,288 @@
+//
+// PNBar.m
+// PNChartDemo
+//
+// Created by kevin on 11/7/13.
+// Copyright (c) 2013��� kevinzhow. All rights reserved.
+//
+
+#import "PNBar.h"
+#import "PNColor.h"
+#import <CoreText/CoreText.h>
+
+@interface PNBar ()
+
+@property (nonatomic) float copyGrade;
+
+@end
+
+@implementation PNBar
+
+- (id)initWithFrame:(CGRect)frame
+{
+ self = [super initWithFrame:frame];
+
+ if (self) {
+ _chartLine = [CAShapeLayer layer];
+ _chartLine.lineCap = kCALineCapButt;
+ _chartLine.fillColor = [[UIColor whiteColor] CGColor];
+ _chartLine.lineWidth = self.frame.size.width;
+ _chartLine.strokeEnd = 0.0;
+ self.clipsToBounds = YES;
+ [self.layer addSublayer:_chartLine];
+ self.barRadius = 2.0;
+ }
+
+ return self;
+}
+
+-(void)setBarRadius:(CGFloat)barRadius
+{
+ _barRadius = barRadius;
+ self.layer.cornerRadius = _barRadius;
+}
+
+
+- (void)setGrade:(float)grade
+{
+ _copyGrade = grade;
+ CGFloat startPosY = (1 - grade) * self.frame.size.height;
+
+ UIBezierPath *progressline = [UIBezierPath bezierPath];
+
+ [progressline moveToPoint:CGPointMake(self.frame.size.width / 2.0, self.frame.size.height)];
+ [progressline addLineToPoint:CGPointMake(self.frame.size.width / 2.0, startPosY)];
+
+ [progressline setLineWidth:1.0];
+ [progressline setLineCapStyle:kCGLineCapSquare];
+ [self addAnimationIfNeededWithProgressLine:progressline];
+
+
+ if (_barColor) {
+ _chartLine.strokeColor = [_barColor CGColor];
+ }
+ else {
+ _chartLine.strokeColor = [PNGreen CGColor];
+ }
+
+ if (_grade) {
+
+ _chartLine.path = progressline.CGPath;
+
+ if (_barColorGradientStart) {
+
+ // Add gradient
+ self.gradientMask.path = progressline.CGPath;
+
+ CABasicAnimation* opacityAnimation = [self fadeAnimation];
+ [self.textLayer addAnimation:opacityAnimation forKey:nil];
+
+ }
+
+ }else{
+ _chartLine.strokeEnd = 1.0;
+
+ _chartLine.path = progressline.CGPath;
+ // Check if user wants to add a gradient from the start color to the bar color
+ if (_barColorGradientStart) {
+
+ // Add gradient
+ self.gradientMask = [CAShapeLayer layer];
+ self.gradientMask.fillColor = [[UIColor clearColor] CGColor];
+ self.gradientMask.strokeColor = [[UIColor blackColor] CGColor];
+ self.gradientMask.lineWidth = self.frame.size.width;
+ self.gradientMask.frame = CGRectMake(0, 0, self.bounds.size.width, self.bounds.size.height);
+ self.gradientMask.path = progressline.CGPath;
+
+ CAGradientLayer *gradientLayer = [CAGradientLayer layer];
+ gradientLayer.startPoint = CGPointMake(0.0,0.0);
+ gradientLayer.endPoint = CGPointMake(1.0 ,0.0);
+ gradientLayer.frame = CGRectMake(0, 0, self.bounds.size.width, self.bounds.size.height);
+ UIColor *middleColor = [UIColor colorWithWhite:255/255 alpha:0.8];
+ NSArray *colors = @[
+ (__bridge id)self.barColor.CGColor,
+ (__bridge id)middleColor.CGColor,
+ (__bridge id)self.barColor.CGColor
+ ];
+ gradientLayer.colors = colors;
+
+ [gradientLayer setMask:self.gradientMask];
+
+ [_chartLine addSublayer:gradientLayer];
+
+ self.gradientMask.strokeEnd = 1.0;
+
+ CABasicAnimation* opacityAnimation = [self fadeAnimation];
+ [self.textLayer addAnimation:opacityAnimation forKey:nil];
+ }
+ }
+
+ _grade = grade;
+
+}
+
+
+- (void)rollBack
+{
+ [UIView animateWithDuration:0.3 delay:0.0 options:UIViewAnimationOptionCurveEaseOut animations: ^{
+ _chartLine.strokeColor = [UIColor clearColor].CGColor;
+ } completion:nil];
+}
+
+- (void)setBarColorGradientStart:(UIColor *)barColorGradientStart
+{
+ // Set gradient color, remove any existing sublayer first
+ for (CALayer *sublayer in [_chartLine sublayers]) {
+ [sublayer removeFromSuperlayer];
+ }
+ _barColorGradientStart = barColorGradientStart;
+
+ [self setGrade:_grade];
+
+}
+
+// Only override drawRect: if you perform custom drawing.
+// An empty implementation adversely affects performance during animation.
+- (void)drawRect:(CGRect)rect
+{
+ CGContextRef context = UIGraphicsGetCurrentContext();
+
+ CGContextSetFillColorWithColor(context, self.backgroundColor.CGColor);
+ CGContextFillRect(context, rect);
+}
+
+
+// add number display on the top of bar
+-(CGPathRef)gradePath:(CGRect)rect
+{
+ return nil;
+}
+
+-(CATextLayer*)textLayer
+{
+ if (!_textLayer) {
+ _textLayer = [[CATextLayer alloc]init];
+ [_textLayer setString:@"0"];
+ [_textLayer setAlignmentMode:kCAAlignmentCenter];
+ [_textLayer setForegroundColor:[_labelTextColor CGColor]];
+ _textLayer.hidden = YES;
+
+ }
+
+ return _textLayer;
+}
+
+- (void) setLabelTextColor:(UIColor *)labelTextColor {
+ _labelTextColor = labelTextColor;
+ [_textLayer setForegroundColor:[_labelTextColor CGColor]];
+}
+
+-(void)setGradeFrame:(CGFloat)grade startPosY:(CGFloat)startPosY
+{
+ CGFloat textheigt = self.bounds.size.height*self.grade;
+
+ CGFloat topSpace = self.bounds.size.height * (1-self.grade);
+ CGFloat textWidth = self.bounds.size.width;
+
+ [_chartLine addSublayer:self.textLayer];
+ [self.textLayer setFontSize:18.0];
+
+ [self.textLayer setString:[[NSString alloc]initWithFormat:@"%0.f",grade*self.maxDivisor]];
+
+ CGSize size = CGSizeMake(320,2000); //������������������������
+ NSDictionary *attributes = @{NSFontAttributeName:[UIFont systemFontOfSize:18.0]};
+ size = [self.textLayer.string boundingRectWithSize:size options:NSStringDrawingUsesLineFragmentOrigin attributes:attributes context:nil].size;
+ float verticalY ;
+
+ if (size.height>=textheigt) {
+
+ verticalY = topSpace - size.height;
+ } else {
+ verticalY = topSpace + (textheigt-size.height)/2.0;
+ }
+
+ [self.textLayer setFrame:CGRectMake((textWidth-size.width)/2.0,verticalY, size.width,size.height)];
+ self.textLayer.contentsScale = [UIScreen mainScreen].scale;
+
+}
+
+- (void)setIsShowNumber:(BOOL)isShowNumber{
+ if (isShowNumber) {
+ self.textLayer.hidden = NO;
+ [self setGradeFrame:_copyGrade startPosY:0];
+ }else{
+ self.textLayer.hidden = YES;
+ }
+}
+- (void)setIsNegative:(BOOL)isNegative{
+ if (isNegative) {
+ [self.textLayer setString:[[NSString alloc]initWithFormat:@"- %1.f",_grade*self.maxDivisor]];
+
+ CGSize size = CGSizeMake(320,2000); //������������������������
+ NSDictionary *attributes = @{NSFontAttributeName:[UIFont systemFontOfSize:18.0]};
+ size = [self.textLayer.string boundingRectWithSize:size options:NSStringDrawingUsesLineFragmentOrigin attributes:attributes context:nil].size;
+ CGRect frame = self.textLayer.frame;
+ frame.origin.x = (self.bounds.size.width - size.width)/2.0;
+ frame.size = size;
+ self.textLayer.frame = frame;
+
+ [self addRotationAnimationIfNeeded];
+ }
+}
+
+-(CABasicAnimation*)fadeAnimation
+{
+ CABasicAnimation* fadeAnimation = nil;
+ if (self.displayAnimated) {
+ fadeAnimation = [CABasicAnimation animationWithKeyPath:@"opacity"];
+ fadeAnimation.fromValue = [NSNumber numberWithFloat:0.0];
+ fadeAnimation.toValue = [NSNumber numberWithFloat:1.0];
+ fadeAnimation.duration = 2.0;
+ }
+ return fadeAnimation;
+}
+
+-(void)addAnimationIfNeededWithProgressLine:(UIBezierPath *)progressline
+{
+ if (self.displayAnimated) {
+ CABasicAnimation *pathAnimation = nil;
+
+ if (_grade) {
+ pathAnimation = [CABasicAnimation animationWithKeyPath:@"path"];
+ pathAnimation.fromValue = (id)_chartLine.path;
+ pathAnimation.toValue = (id)[progressline CGPath];
+ pathAnimation.duration = 0.5f;
+ pathAnimation.autoreverses = NO;
+ pathAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
+ [_chartLine addAnimation:pathAnimation forKey:@"animationKey"];
+ }
+ else {
+ pathAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
+ pathAnimation.duration = 1.0;
+ pathAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
+ pathAnimation.fromValue = @0.0f;
+ pathAnimation.toValue = @1.0f;
+ [_chartLine addAnimation:pathAnimation forKey:@"strokeEndAnimation"];
+ }
+
+ [self.gradientMask addAnimation:pathAnimation forKey:@"animationKey"];
+ }
+}
+
+- (void)addRotationAnimationIfNeeded
+{
+ if (self.displayAnimated) {
+ CABasicAnimation* rotationAnimation;
+ rotationAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
+ rotationAnimation.toValue = [NSNumber numberWithFloat: M_PI];
+ [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
+ rotationAnimation.duration = 0.1;
+ rotationAnimation.repeatCount = 0;//������������������������������������
+ rotationAnimation.cumulative = NO;
+ rotationAnimation.removedOnCompletion = NO;
+ rotationAnimation.fillMode = kCAFillModeForwards;
+ [self.textLayer addAnimation:rotationAnimation forKey:@"Rotation"];
+ }
+}
+
+@end
diff --git a/PNChartdemo/PNChart/PNBarChart.h b/PNChartdemo/PNChart/PNBarChart.h
new file mode 100755
index 0000000..e628c08
--- /dev/null
+++ b/PNChartdemo/PNChart/PNBarChart.h
@@ -0,0 +1,123 @@
+//
+// PNBarChart.h
+// PNChartDemo
+//
+// Created by kevin on 11/7/13.
+// Copyright (c) 2013��� kevinzhow. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+#import "PNGenericChart.h"
+#import "PNChartDelegate.h"
+#import "PNBar.h"
+
+#define kXLabelMargin 15
+#define kYLabelMargin 15
+#define kYLabelHeight 11
+#define kXLabelHeight 20
+
+typedef NSString *(^PNYLabelFormatter)(CGFloat yLabelValue);
+
+@interface PNBarChart : PNGenericChart
+
+/**
+ * Draws the chart in an animated fashion.
+ */
+- (void)strokeChart;
+
+@property (nonatomic) NSArray *xLabels;
+@property (nonatomic) NSArray *yLabels;
+@property (nonatomic) NSArray *yValues;
+
+@property (nonatomic) NSMutableArray * bars;
+
+@property (nonatomic) CGFloat xLabelWidth;
+@property (nonatomic) float yValueMax;
+@property (nonatomic) UIColor *strokeColor;
+@property (nonatomic) NSArray *strokeColors;
+
+
+/** Update Values. */
+- (void)updateChartData:(NSArray *)data;
+
+/** Changes chart margin. */
+@property (nonatomic) CGFloat yChartLabelWidth;
+
+/** Formats the ylabel text. */
+@property (copy) PNYLabelFormatter yLabelFormatter;
+
+/** Prefix to y label values, none if unset. */
+@property (nonatomic) NSString *yLabelPrefix;
+
+/** Suffix to y label values, none if unset. */
+@property (nonatomic) NSString *yLabelSuffix;
+
+@property (nonatomic) CGFloat chartMarginLeft;
+@property (nonatomic) CGFloat chartMarginRight;
+@property (nonatomic) CGFloat chartMarginTop;
+@property (nonatomic) CGFloat chartMarginBottom;
+
+/** Controls whether labels should be displayed. */
+@property (nonatomic) BOOL showLabel;
+
+/** Controls whether the chart border line should be displayed. */
+@property (nonatomic) BOOL showChartBorder;
+
+@property (nonatomic) UIColor *chartBorderColor;
+
+/** Controls whether the chart Horizontal separator should be displayed. */
+@property (nonatomic, assign) BOOL showLevelLine;
+
+/** Chart bottom border, co-linear with the x-axis. */
+@property (nonatomic) CAShapeLayer * chartBottomLine;
+
+/** Chart bottom border, level separator-linear with the x-axis. */
+@property (nonatomic) CAShapeLayer * chartLevelLine;
+
+/** Chart left border, co-linear with the y-axis. */
+@property (nonatomic) CAShapeLayer * chartLeftLine;
+
+/** Corner radius for all bars in the chart. */
+@property (nonatomic) CGFloat barRadius;
+
+/** Width of all bars in the chart. */
+@property (nonatomic) CGFloat barWidth;
+
+@property (nonatomic) CGFloat labelMarginTop;
+
+/** Background color of all bars in the chart. */
+@property (nonatomic) UIColor * barBackgroundColor;
+
+/** Text color for all bars in the chart. */
+@property (nonatomic) UIColor * labelTextColor;
+
+/** Font for all bars in the chart. */
+@property (nonatomic) UIFont * labelFont;
+
+/** How many labels on the x-axis to skip in between displaying labels. */
+@property (nonatomic) NSInteger xLabelSkip;
+
+/** How many labels on the y-axis to skip in between displaying labels. */
+@property (nonatomic) NSInteger yLabelSum;
+
+/** The maximum for the range of values to display on the y-axis. */
+@property (nonatomic) CGFloat yMaxValue;
+
+/** The minimum for the range of values to display on the y-axis. */
+@property (nonatomic) CGFloat yMinValue;
+
+/** Controls whether each bar should have a gradient fill. */
+@property (nonatomic) UIColor *barColorGradientStart;
+
+/** Controls whether text for x-axis be straight or rotate 45 degree. */
+@property (nonatomic) BOOL rotateForXAxisText;
+
+@property (nonatomic, weak) id<PNChartDelegate> delegate;
+
+/**whether show gradient bar*/
+@property (nonatomic, assign) BOOL isGradientShow;
+
+/** whether show numbers*/
+@property (nonatomic, assign) BOOL isShowNumbers;
+
+@end
diff --git a/PNChartdemo/PNChart/PNBarChart.m b/PNChartdemo/PNChart/PNBarChart.m
new file mode 100755
index 0000000..50e035c
--- /dev/null
+++ b/PNChartdemo/PNChart/PNBarChart.m
@@ -0,0 +1,459 @@
+//
+// PNBarChart.m
+// PNChartDemo
+//
+// Created by kevin on 11/7/13.
+// Copyright (c) 2013��� kevinzhow. All rights reserved.
+//
+
+#import "PNBarChart.h"
+#import "PNColor.h"
+#import "PNChartLabel.h"
+
+@interface PNBarChart () {
+ NSMutableArray *_xChartLabels;
+ NSMutableArray *_yChartLabels;
+}
+
+- (UIColor *)barColorAtIndex:(NSUInteger)index;
+
+@end
+
+@implementation PNBarChart
+
+- (id)initWithCoder:(NSCoder *)aDecoder
+{
+ self = [super initWithCoder:aDecoder];
+
+ if (self) {
+ [self setupDefaultValues];
+ }
+ return self;
+}
+
+- (id)initWithFrame:(CGRect)frame
+{
+ self = [super initWithFrame:frame];
+
+ if (self) {
+ [self setupDefaultValues];
+ }
+
+ return self;
+}
+
+- (void)setupDefaultValues
+{
+ [super setupDefaultValues];
+ self.backgroundColor = [UIColor whiteColor];
+ self.clipsToBounds = YES;
+ _showLabel = YES;
+ _barBackgroundColor = PNLightGrey;
+ _labelTextColor = [UIColor grayColor];
+ _labelFont = [UIFont systemFontOfSize:11.0f];
+ _xChartLabels = [NSMutableArray array];
+ _yChartLabels = [NSMutableArray array];
+ _bars = [NSMutableArray array];
+ _xLabelSkip = 1;
+ _yLabelSum = 4;
+ _labelMarginTop = 2;
+ _chartMarginLeft = 25.0;
+ _chartMarginRight = 25.0;
+ _chartMarginTop = 25.0;
+ _chartMarginBottom = 25.0;
+ _barRadius = 2.0;
+ _showChartBorder = NO;
+ _chartBorderColor = PNLightGrey;
+ _showLevelLine = NO;
+ _yChartLabelWidth = 18;
+ _rotateForXAxisText = false;
+ _isGradientShow = YES;
+ _isShowNumbers = YES;
+ _yLabelPrefix = @"";
+ _yLabelSuffix = @"";
+ _yLabelFormatter = ^(CGFloat yValue){
+ return [NSString stringWithFormat:@"%1.f",yValue];
+ };
+}
+
+- (void)setYValues:(NSArray *)yValues
+{
+ _yValues = yValues;
+ //make the _yLabelSum value dependant of the distinct values of yValues to avoid duplicates on yAxis
+
+ if (_showLabel) {
+ [self __addYCoordinateLabelsValues];
+ } else {
+ [self processYMaxValue];
+ }
+}
+
+- (void)processYMaxValue {
+ NSArray *yAxisValues = _yLabels ? _yLabels : _yValues;
+ _yLabelSum = _yLabels ? _yLabels.count - 1 :_yLabelSum;
+ if (_yMaxValue) {
+ _yValueMax = _yMaxValue;
+ } else {
+ [self getYValueMax:yAxisValues];
+ }
+
+ if (_yLabelSum==4) {
+ _yLabelSum = yAxisValues.count;
+ (_yLabelSum % 2 == 0) ? _yLabelSum : _yLabelSum++;
+ }
+}
+
+#pragma mark - Private Method
+#pragma mark - Add Y Label
+- (void)__addYCoordinateLabelsValues{
+
+ [self viewCleanupForCollection:_yChartLabels];
+
+ [self processYMaxValue];
+
+ float sectionHeight = (self.frame.size.height - _chartMarginTop - _chartMarginBottom - kXLabelHeight) / _yLabelSum;
+
+ for (int i = 0; i <= _yLabelSum; i++) {
+ NSString *labelText;
+ if (_yLabels) {
+ float yAsixValue = [_yLabels[_yLabels.count - i - 1] floatValue];
+ labelText= _yLabelFormatter(yAsixValue);
+ } else {
+ labelText = _yLabelFormatter((float)_yValueMax * ( (_yLabelSum - i) / (float)_yLabelSum ));
+ }
+
+ PNChartLabel *label = [[PNChartLabel alloc] initWithFrame:CGRectZero];
+ label.font = _labelFont;
+ label.textColor = _labelTextColor;
+ [label setTextAlignment:NSTextAlignmentRight];
+ label.text = [NSString stringWithFormat:@"%@%@%@", _yLabelPrefix, labelText, _yLabelSuffix];
+
+ [self addSubview:label];
+
+ label.frame = (CGRect){0, sectionHeight * i + _chartMarginTop - kYLabelHeight/2.0 + kXLabelHeight + _labelMarginTop, _yChartLabelWidth, kYLabelHeight};
+
+ [_yChartLabels addObject:label];
+ }
+}
+
+-(void)updateChartData:(NSArray *)data{
+ self.yValues = data;
+ [self updateBar];
+}
+
+- (void)getYValueMax:(NSArray *)yLabels
+{
+ CGFloat max = [[yLabels valueForKeyPath:@"@max.floatValue"] floatValue];
+
+ //ensure max is even
+ _yValueMax = max ;
+
+ if (_yValueMax == 0) {
+ _yValueMax = _yMinValue;
+ }
+}
+
+- (void)setXLabels:(NSArray *)xLabels
+{
+ _xLabels = xLabels;
+
+ if (_xChartLabels) {
+ [self viewCleanupForCollection:_xChartLabels];
+ }else{
+ _xChartLabels = [NSMutableArray new];
+ }
+
+ _xLabelWidth = (self.frame.size.width - _chartMarginLeft - _chartMarginRight) / [xLabels count];
+
+ if (_showLabel) {
+ int labelAddCount = 0;
+ for (int index = 0; index < _xLabels.count; index++) {
+ labelAddCount += 1;
+
+ if (labelAddCount == _xLabelSkip) {
+ NSString *labelText = [_xLabels[index] description];
+ PNChartLabel * label = [[PNChartLabel alloc] initWithFrame:CGRectMake(0, 0, _xLabelWidth, kXLabelHeight)];
+ label.font = _labelFont;
+ label.textColor = _labelTextColor;
+ [label setTextAlignment:NSTextAlignmentCenter];
+ label.text = labelText;
+ //[label sizeToFit];
+ CGFloat labelXPosition;
+ if (_rotateForXAxisText){
+ label.transform = CGAffineTransformMakeRotation(M_PI / 4);
+ labelXPosition = (index * _xLabelWidth + _chartMarginLeft + _xLabelWidth /1.5);
+ }
+ else{
+ labelXPosition = (index * _xLabelWidth + _chartMarginLeft + _xLabelWidth /2.0 );
+ }
+ label.center = CGPointMake(labelXPosition,
+ self.frame.size.height - _chartMarginTop + label.frame.size.height /2.0 + _labelMarginTop);
+ labelAddCount = 0;
+
+ [_xChartLabels addObject:label];
+ [self addSubview:label];
+ }
+ }
+ }
+}
+
+
+- (void)setStrokeColor:(UIColor *)strokeColor
+{
+ _strokeColor = strokeColor;
+}
+
+- (void)updateBar
+{
+
+ //Add bars
+ CGFloat chartCavanHeight = self.frame.size.height - _chartMarginTop - _chartMarginBottom - kXLabelHeight;
+ NSInteger index = 0;
+
+ for (NSNumber *valueString in _yValues) {
+
+ PNBar *bar;
+
+ if (_bars.count == _yValues.count) {
+ bar = [_bars objectAtIndex:index];
+ }else{
+ CGFloat barWidth;
+ CGFloat barXPosition;
+
+ if (_barWidth) {
+ barWidth = _barWidth;
+ barXPosition = index * _xLabelWidth + _chartMarginLeft + _xLabelWidth /2.0 - _barWidth /2.0;
+ }else{
+ barXPosition = index * _xLabelWidth + _chartMarginLeft + _xLabelWidth * 0.25;
+ if (_showLabel) {
+ barWidth = _xLabelWidth * 0.5;
+
+ }
+ else {
+ barWidth = _xLabelWidth * 0.6;
+
+ }
+ }
+
+ bar = [[PNBar alloc] initWithFrame:CGRectMake(barXPosition, //Bar X position
+ self.frame.size.height - chartCavanHeight - kXLabelHeight - _chartMarginBottom + _chartMarginTop , //Bar Y position
+ barWidth, // Bar witdh
+ self.showLevelLine ? chartCavanHeight/2.0:chartCavanHeight)]; //Bar height
+
+ //Change Bar Radius
+ bar.barRadius = _barRadius;
+
+ //Set Bar Animation
+ bar.displayAnimated = self.displayAnimated;
+
+ //Change Bar Background color
+ bar.backgroundColor = _barBackgroundColor;
+ //Bar StrokColor First
+ if (self.strokeColor) {
+ bar.barColor = self.strokeColor;
+ }else{
+ bar.barColor = [self barColorAtIndex:index];
+ }
+
+ if (self.labelTextColor) {
+ bar.labelTextColor = self.labelTextColor;
+ }
+
+ // Add gradient
+ if (self.isGradientShow) {
+ bar.barColorGradientStart = bar.barColor;
+ }
+
+ //For Click Index
+ bar.tag = index;
+
+ [_bars addObject:bar];
+ [self addSubview:bar];
+ }
+
+ //Height Of Bar
+ float value = [valueString floatValue];
+ float grade =fabsf((float)value / (float)_yValueMax);
+
+ if (isnan(grade)) {
+ grade = 0;
+ }
+ bar.maxDivisor = (float)_yValueMax;
+ bar.grade = grade;
+ bar.isShowNumber = self.isShowNumbers;
+ CGRect originalFrame = bar.frame;
+ NSString *currentNumber = [NSString stringWithFormat:@"%f",value];
+
+ if ([[currentNumber substringToIndex:1] isEqualToString:@"-"] && self.showLevelLine) {
+ CGAffineTransform transform =CGAffineTransformMakeRotation(M_PI);
+ [bar setTransform:transform];
+ originalFrame.origin.y = bar.frame.origin.y + bar.frame.size.height;
+ bar.frame = originalFrame;
+ bar.isNegative = YES;
+
+ }
+ index += 1;
+ }
+}
+
+- (void)strokeChart
+{
+ //Add Labels
+
+ [self viewCleanupForCollection:_bars];
+
+
+ //Update Bar
+
+ [self updateBar];
+
+ //Add chart border lines
+
+ if (_showChartBorder) {
+ _chartBottomLine = [CAShapeLayer layer];
+ _chartBottomLine.lineCap = kCALineCapButt;
+ _chartBottomLine.fillColor = [[UIColor whiteColor] CGColor];
+ _chartBottomLine.lineWidth = 1.0;
+ _chartBottomLine.strokeEnd = 0.0;
+
+ UIBezierPath *progressline = [UIBezierPath bezierPath];
+
+ [progressline moveToPoint:CGPointMake(_chartMarginLeft, self.frame.size.height - kXLabelHeight - _chartMarginBottom + _chartMarginTop)];
+ [progressline addLineToPoint:CGPointMake(self.frame.size.width - _chartMarginRight, self.frame.size.height - kXLabelHeight - _chartMarginBottom + _chartMarginTop)];
+
+ [progressline setLineWidth:1.0];
+ [progressline setLineCapStyle:kCGLineCapSquare];
+ _chartBottomLine.path = progressline.CGPath;
+ _chartBottomLine.strokeColor = [_chartBorderColor CGColor];;
+ _chartBottomLine.strokeEnd = 1.0;
+
+ [self.layer addSublayer:_chartBottomLine];
+
+ //Add left Chart Line
+
+ _chartLeftLine = [CAShapeLayer layer];
+ _chartLeftLine.lineCap = kCALineCapButt;
+ _chartLeftLine.fillColor = [[UIColor whiteColor] CGColor];
+ _chartLeftLine.lineWidth = 1.0;
+ _chartLeftLine.strokeEnd = 0.0;
+
+ UIBezierPath *progressLeftline = [UIBezierPath bezierPath];
+
+ [progressLeftline moveToPoint:CGPointMake(_chartMarginLeft, self.frame.size.height - kXLabelHeight - _chartMarginBottom + _chartMarginTop)];
+ [progressLeftline addLineToPoint:CGPointMake(_chartMarginLeft, _chartMarginTop)];
+
+ [progressLeftline setLineWidth:1.0];
+ [progressLeftline setLineCapStyle:kCGLineCapSquare];
+ _chartLeftLine.path = progressLeftline.CGPath;
+ _chartLeftLine.strokeColor = [_chartBorderColor CGColor];
+ _chartLeftLine.strokeEnd = 1.0;
+
+ [self addBorderAnimationIfNeeded];
+ [self.layer addSublayer:_chartLeftLine];
+ }
+
+ // Add Level Separator Line
+ if (_showLevelLine) {
+ _chartLevelLine = [CAShapeLayer layer];
+ _chartLevelLine.lineCap = kCALineCapButt;
+ _chartLevelLine.fillColor = [[UIColor whiteColor] CGColor];
+ _chartLevelLine.lineWidth = 1.0;
+ _chartLevelLine.strokeEnd = 0.0;
+
+ UIBezierPath *progressline = [UIBezierPath bezierPath];
+
+ [progressline moveToPoint:CGPointMake(_chartMarginLeft, (self.frame.size.height - kXLabelHeight )/2.0)];
+ [progressline addLineToPoint:CGPointMake(self.frame.size.width - _chartMarginLeft - _chartMarginRight, (self.frame.size.height - kXLabelHeight )/2.0)];
+
+ [progressline setLineWidth:1.0];
+ [progressline setLineCapStyle:kCGLineCapSquare];
+ _chartLevelLine.path = progressline.CGPath;
+
+ _chartLevelLine.strokeColor = PNLightGrey.CGColor;
+
+ [self addSeparatorAnimationIfNeeded];
+ _chartLevelLine.strokeEnd = 1.0;
+
+ [self.layer addSublayer:_chartLevelLine];
+ } else {
+ if (_chartLevelLine) {
+ [_chartLevelLine removeFromSuperlayer];
+ _chartLevelLine = nil;
+ }
+ }
+}
+
+- (void)addBorderAnimationIfNeeded
+{
+ if (self.displayAnimated) {
+ CABasicAnimation *pathAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
+ pathAnimation.duration = 0.5;
+ pathAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
+ pathAnimation.fromValue = @0.0f;
+ pathAnimation.toValue = @1.0f;
+ [_chartBottomLine addAnimation:pathAnimation forKey:@"strokeEndAnimation"];
+
+ CABasicAnimation *pathLeftAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
+ pathLeftAnimation.duration = 0.5;
+ pathLeftAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
+ pathLeftAnimation.fromValue = @0.0f;
+ pathLeftAnimation.toValue = @1.0f;
+ [_chartLeftLine addAnimation:pathLeftAnimation forKey:@"strokeEndAnimation"];
+ }
+}
+
+- (void)addSeparatorAnimationIfNeeded
+{
+ if (self.displayAnimated) {
+ CABasicAnimation *pathAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
+ pathAnimation.duration = 0.5;
+ pathAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
+ pathAnimation.fromValue = @0.0f;
+ pathAnimation.toValue = @1.0f;
+ [_chartLevelLine addAnimation:pathAnimation forKey:@"strokeEndAnimation"];
+ }
+}
+
+- (void)viewCleanupForCollection:(NSMutableArray *)array
+{
+ if (array.count) {
+ [array makeObjectsPerformSelector:@selector(removeFromSuperview)];
+ [array removeAllObjects];
+ }
+}
+
+
+#pragma mark - Class extension methods
+
+- (UIColor *)barColorAtIndex:(NSUInteger)index
+{
+ if ([self.strokeColors count] == [self.yValues count]) {
+ return self.strokeColors[index];
+ }
+ else {
+ return self.strokeColor;
+ }
+}
+
+#pragma mark - Touch detection
+
+- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
+{
+ [self touchPoint:touches withEvent:event];
+ [super touchesBegan:touches withEvent:event];
+}
+
+- (void)touchPoint:(NSSet *)touches withEvent:(UIEvent *)event
+{
+ //Get the point user touched
+ UITouch *touch = [touches anyObject];
+ CGPoint touchPoint = [touch locationInView:self];
+ UIView *subview = [self hitTest:touchPoint withEvent:nil];
+
+ if ([subview isKindOfClass:[PNBar class]] && [self.delegate respondsToSelector:@selector(userClickedOnBarAtIndex:)]) {
+ [self.delegate userClickedOnBarAtIndex:subview.tag];
+ }
+}
+
+
+@end
diff --git a/PNChartdemo/PNChart/PNChart.h b/PNChartdemo/PNChart/PNChart.h
new file mode 100755
index 0000000..0835d39
--- /dev/null
+++ b/PNChartdemo/PNChart/PNChart.h
@@ -0,0 +1,22 @@
+//
+// PNChart.h
+// Version 0.1
+// PNChart
+//
+// Created by kevin on 10/3/13.
+// Copyright (c) 2013��� kevinzhow. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+#import "PNChart.h"
+#import "PNColor.h"
+#import "PNLineChart.h"
+#import "PNLineChartData.h"
+#import "PNLineChartDataItem.h"
+#import "PNBarChart.h"
+#import "PNCircleChart.h"
+#import "PNChartDelegate.h"
+#import "PNPieChart.h"
+#import "PNScatterChart.h"
+#import "PNRadarChart.h"
+#import "PNRadarChartDataItem.h"
diff --git a/PNChartdemo/PNChart/PNChartDelegate.h b/PNChartdemo/PNChart/PNChartDelegate.h
new file mode 100755
index 0000000..6d49f7c
--- /dev/null
+++ b/PNChartdemo/PNChart/PNChartDelegate.h
@@ -0,0 +1,33 @@
+//
+// PNChartDelegate.h
+// PNChartDemo
+//
+// Created by kevinzhow on 13-12-11.
+// Copyright (c) 2013��� kevinzhow. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+
+@protocol PNChartDelegate <NSObject>
+@optional
+/**
+ * Callback method that gets invoked when the user taps on the chart line.
+ */
+- (void)userClickedOnLinePoint:(CGPoint)point lineIndex:(NSInteger)lineIndex;
+
+/**
+ * Callback method that gets invoked when the user taps on a chart line key point.
+ */
+- (void)userClickedOnLineKeyPoint:(CGPoint)point
+ lineIndex:(NSInteger)lineIndex
+ pointIndex:(NSInteger)pointIndex;
+
+/**
+ * Callback method that gets invoked when the user taps on a chart bar.
+ */
+- (void)userClickedOnBarAtIndex:(NSInteger)barIndex;
+
+
+- (void)userClickedOnPieIndexItem:(NSInteger)pieIndex;
+- (void)didUnselectPieItem;
+@end
diff --git a/PNChartdemo/PNChart/PNChartLabel.h b/PNChartdemo/PNChart/PNChartLabel.h
new file mode 100755
index 0000000..9ba6afa
--- /dev/null
+++ b/PNChartdemo/PNChart/PNChartLabel.h
@@ -0,0 +1,13 @@
+//
+// PNChartLabel.h
+// PNChart
+//
+// Created by kevin on 10/3/13.
+// Copyright (c) 2013��� kevinzhow. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+
+@interface PNChartLabel : UILabel
+
+@end
diff --git a/PNChartdemo/PNChart/PNChartLabel.m b/PNChartdemo/PNChart/PNChartLabel.m
new file mode 100755
index 0000000..b0980d1
--- /dev/null
+++ b/PNChartdemo/PNChart/PNChartLabel.m
@@ -0,0 +1,32 @@
+//
+// PNChartLabel.m
+// PNChart
+//
+// Created by kevin on 10/3/13.
+// Copyright (c) 2013��� kevinzhow. All rights reserved.
+//
+
+#import "PNChartLabel.h"
+
+@implementation PNChartLabel
+
+- (id)initWithFrame:(CGRect)frame
+{
+ self = [super initWithFrame:frame];
+
+ if (self) {
+ self.font = [UIFont boldSystemFontOfSize:11.0f];
+ self.backgroundColor = [UIColor clearColor];
+ self.textAlignment = NSTextAlignmentCenter;
+ self.userInteractionEnabled = YES;
+ self.adjustsFontSizeToFitWidth = YES;
+ self.numberOfLines = 0;
+ /* if you want to see ... in large labels un-comment this line
+ self.minimumScaleFactor = 0.8;
+ */
+ }
+
+ return self;
+}
+
+@end
diff --git a/PNChartdemo/PNChart/PNCircleChart.h b/PNChartdemo/PNChart/PNCircleChart.h
new file mode 100755
index 0000000..f9fc06d
--- /dev/null
+++ b/PNChartdemo/PNChart/PNCircleChart.h
@@ -0,0 +1,74 @@
+//
+// PNCircleChart.h
+// PNChartDemo
+//
+// Created by kevinzhow on 13-11-30.
+// Copyright (c) 2013��� kevinzhow. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+#import "PNColor.h"
+#import "UICountingLabel.h"
+
+typedef NS_ENUM (NSUInteger, PNChartFormatType) {
+ PNChartFormatTypePercent,
+ PNChartFormatTypeDollar,
+ PNChartFormatTypeNone,
+ PNChartFormatTypeDecimal,
+ PNChartFormatTypeDecimalTwoPlaces,
+};
+
+#define DEGREES_TO_RADIANS(angle) ((angle) / 180.0 * M_PI)
+
+@interface PNCircleChart : UIView
+
+- (void)strokeChart;
+- (void)growChartByAmount:(NSNumber *)growAmount;
+- (void)updateChartByCurrent:(NSNumber *)current;
+- (void)updateChartByCurrent:(NSNumber *)current byTotal:(NSNumber *)total;
+- (id)initWithFrame:(CGRect)frame
+ total:(NSNumber *)total
+ current:(NSNumber *)current
+ clockwise:(BOOL)clockwise;
+
+- (id)initWithFrame:(CGRect)frame
+ total:(NSNumber *)total
+ current:(NSNumber *)current
+ clockwise:(BOOL)clockwise
+ shadow:(BOOL)hasBackgroundShadow
+ shadowColor:(UIColor *)backgroundShadowColor;
+
+- (id)initWithFrame:(CGRect)frame
+ total:(NSNumber *)total
+ current:(NSNumber *)current
+ clockwise:(BOOL)clockwise
+ shadow:(BOOL)hasBackgroundShadow
+ shadowColor:(UIColor *)backgroundShadowColor
+displayCountingLabel:(BOOL)displayCountingLabel;
+
+- (id)initWithFrame:(CGRect)frame
+ total:(NSNumber *)total
+ current:(NSNumber *)current
+ clockwise:(BOOL)clockwise
+ shadow:(BOOL)hasBackgroundShadow
+ shadowColor:(UIColor *)backgroundShadowColor
+displayCountingLabel:(BOOL)displayCountingLabel
+ overrideLineWidth:(NSNumber *)overrideLineWidth;
+
+@property (strong, nonatomic) UICountingLabel *countingLabel;
+@property (nonatomic) UIColor *strokeColor;
+@property (nonatomic) UIColor *strokeColorGradientStart;
+@property (nonatomic) NSNumber *total;
+@property (nonatomic) NSNumber *current;
+@property (nonatomic) NSNumber *lineWidth;
+@property (nonatomic) NSTimeInterval duration;
+@property (nonatomic) PNChartFormatType chartType;
+
+@property (nonatomic) CAShapeLayer *circle;
+@property (nonatomic) CAShapeLayer *gradientMask;
+@property (nonatomic) CAShapeLayer *circleBackground;
+
+@property (nonatomic) BOOL displayCountingLabel;
+@property (nonatomic) BOOL displayAnimated;
+
+@end
diff --git a/PNChartdemo/PNChart/PNCircleChart.m b/PNChartdemo/PNChart/PNCircleChart.m
new file mode 100755
index 0000000..19f70e5
--- /dev/null
+++ b/PNChartdemo/PNChart/PNCircleChart.m
@@ -0,0 +1,267 @@
+//
+// PNCircleChart.m
+// PNChartDemo
+//
+// Created by kevinzhow on 13-11-30.
+// Copyright (c) 2013��� kevinzhow. All rights reserved.
+//
+
+#import "PNCircleChart.h"
+
+@interface PNCircleChart ()
+@end
+
+@implementation PNCircleChart
+
+- (id)initWithFrame:(CGRect)frame total:(NSNumber *)total current:(NSNumber *)current clockwise:(BOOL)clockwise {
+
+ return [self initWithFrame:frame
+ total:total
+ current:current
+ clockwise:clockwise
+ shadow:NO
+ shadowColor:[UIColor clearColor]
+ displayCountingLabel:YES
+ overrideLineWidth:@8.0f];
+
+}
+
+- (id)initWithFrame:(CGRect)frame total:(NSNumber *)total current:(NSNumber *)current clockwise:(BOOL)clockwise shadow:(BOOL)hasBackgroundShadow shadowColor:(UIColor *)backgroundShadowColor {
+
+ return [self initWithFrame:frame
+ total:total
+ current:current
+ clockwise:clockwise
+ shadow:shadow
+ shadowColor:backgroundShadowColor
+ displayCountingLabel:YES
+ overrideLineWidth:@8.0f];
+
+}
+
+- (id)initWithFrame:(CGRect)frame total:(NSNumber *)total current:(NSNumber *)current clockwise:(BOOL)clockwise shadow:(BOOL)hasBackgroundShadow shadowColor:(UIColor *)backgroundShadowColor displayCountingLabel:(BOOL)displayCountingLabel {
+
+ return [self initWithFrame:frame
+ total:total
+ current:current
+ clockwise:clockwise
+ shadow:shadow
+ shadowColor:backgroundShadowColor
+ displayCountingLabel:displayCountingLabel
+ overrideLineWidth:@8.0f];
+
+}
+
+- (id)initWithFrame:(CGRect)frame
+ total:(NSNumber *)total
+ current:(NSNumber *)current
+ clockwise:(BOOL)clockwise
+ shadow:(BOOL)hasBackgroundShadow
+ shadowColor:(UIColor *)backgroundShadowColor
+displayCountingLabel:(BOOL)displayCountingLabel
+ overrideLineWidth:(NSNumber *)overrideLineWidth
+{
+ self = [super initWithFrame:frame];
+
+ if (self) {
+ _total = total;
+ _current = current;
+ _strokeColor = PNFreshGreen;
+ _duration = 1.0;
+ _chartType = PNChartFormatTypePercent;
+ _displayAnimated = YES;
+
+ _displayCountingLabel = displayCountingLabel;
+
+ CGFloat startAngle = clockwise ? -90.0f : 270.0f;
+ CGFloat endAngle = clockwise ? -90.01f : 270.01f;
+
+ _lineWidth = overrideLineWidth;
+
+ UIBezierPath *circlePath = [UIBezierPath bezierPathWithArcCenter:CGPointMake(self.frame.size.width/2.0f, self.frame.size.height/2.0f)
+ radius:(self.frame.size.height * 0.5) - ([_lineWidth floatValue]/2.0f)
+ startAngle:DEGREES_TO_RADIANS(startAngle)
+ endAngle:DEGREES_TO_RADIANS(endAngle)
+ clockwise:clockwise];
+
+ _circle = [CAShapeLayer layer];
+ _circle.path = circlePath.CGPath;
+ _circle.lineCap = kCALineCapRound;
+ _circle.fillColor = [UIColor clearColor].CGColor;
+ _circle.lineWidth = [_lineWidth floatValue];
+ _circle.zPosition = 1;
+
+ _circleBackground = [CAShapeLayer layer];
+ _circleBackground.path = circlePath.CGPath;
+ _circleBackground.lineCap = kCALineCapRound;
+ _circleBackground.fillColor = [UIColor clearColor].CGColor;
+ _circleBackground.lineWidth = [_lineWidth floatValue];
+ _circleBackground.strokeColor = (hasBackgroundShadow ? backgroundShadowColor.CGColor : [UIColor clearColor].CGColor);
+ _circleBackground.strokeEnd = 1.0;
+ _circleBackground.zPosition = -1;
+
+ [self.layer addSublayer:_circle];
+ [self.layer addSublayer:_circleBackground];
+
+ _countingLabel = [[UICountingLabel alloc] initWithFrame:CGRectMake(0, 0, 100.0, 50.0)];
+ [_countingLabel setTextAlignment:NSTextAlignmentCenter];
+ [_countingLabel setFont:[UIFont boldSystemFontOfSize:16.0f]];
+ [_countingLabel setTextColor:[UIColor grayColor]];
+ [_countingLabel setBackgroundColor:[UIColor clearColor]];
+ [_countingLabel setCenter:CGPointMake(self.frame.size.width/2.0f, self.frame.size.height/2.0f)];
+ _countingLabel.method = UILabelCountingMethodEaseInOut;
+ if (_displayCountingLabel) {
+ [self addSubview:_countingLabel];
+ }
+ }
+
+ return self;
+}
+
+
+- (void)strokeChart
+{
+ // Add counting label
+
+ if (_displayCountingLabel) {
+ NSString *format;
+ switch (self.chartType) {
+ case PNChartFormatTypePercent:
+ format = @"%d%%";
+ break;
+ case PNChartFormatTypeDollar:
+ format = @"$%d";
+ break;
+ case PNChartFormatTypeDecimal:
+ format = @"%.1f";
+ break;
+ case PNChartFormatTypeDecimalTwoPlaces:
+ format = @"%.2f";
+ break;
+ case PNChartFormatTypeNone:
+ default:
+ format = @"%d";
+ break;
+ }
+ self.countingLabel.format = format;
+ [self addSubview:self.countingLabel];
+ }
+
+
+ // Add circle params
+
+ _circle.lineWidth = [_lineWidth floatValue];
+ _circleBackground.lineWidth = [_lineWidth floatValue];
+ _circleBackground.strokeEnd = 1.0;
+ _circle.strokeColor = _strokeColor.CGColor;
+ _circle.strokeEnd = [_current floatValue] / [_total floatValue];
+
+ // Check if user wants to add a gradient from the start color to the bar color
+ if (_strokeColorGradientStart) {
+
+ // Add gradient
+ self.gradientMask = [CAShapeLayer layer];
+ self.gradientMask.fillColor = [[UIColor clearColor] CGColor];
+ self.gradientMask.strokeColor = [[UIColor blackColor] CGColor];
+ self.gradientMask.lineWidth = _circle.lineWidth;
+ self.gradientMask.lineCap = kCALineCapRound;
+ CGRect gradientFrame = CGRectMake(0, 0, 2*self.bounds.size.width, 2*self.bounds.size.height);
+ self.gradientMask.frame = gradientFrame;
+ self.gradientMask.path = _circle.path;
+
+ CAGradientLayer *gradientLayer = [CAGradientLayer layer];
+ gradientLayer.startPoint = CGPointMake(0.5,1.0);
+ gradientLayer.endPoint = CGPointMake(0.5,0.0);
+ gradientLayer.frame = gradientFrame;
+ UIColor *endColor = (_strokeColor ? _strokeColor : [UIColor greenColor]);
+ NSArray *colors = @[
+ (id)endColor.CGColor,
+ (id)_strokeColorGradientStart.CGColor
+ ];
+ gradientLayer.colors = colors;
+
+ [gradientLayer setMask:self.gradientMask];
+
+ [_circle addSublayer:gradientLayer];
+
+ self.gradientMask.strokeEnd = [_current floatValue] / [_total floatValue];
+ }
+
+ [self addAnimationIfNeeded];
+}
+
+
+
+- (void)growChartByAmount:(NSNumber *)growAmount
+{
+ NSNumber *updatedValue = [NSNumber numberWithFloat:[_current floatValue] + [growAmount floatValue]];
+
+ // Add animation
+ [self updateChartByCurrent:updatedValue];
+}
+
+
+-(void)updateChartByCurrent:(NSNumber *)current{
+
+ [self updateChartByCurrent:current
+ byTotal:_total];
+
+}
+
+-(void)updateChartByCurrent:(NSNumber *)current byTotal:(NSNumber *)total {
+ double totalPercentageValue = [current floatValue]/([total floatValue]/100.0);
+
+ if (_strokeColorGradientStart) {
+ self.gradientMask.strokeEnd = _circle.strokeEnd;
+ }
+
+ // Add animation
+ if (self.displayAnimated) {
+ CABasicAnimation *pathAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
+ pathAnimation.duration = self.duration;
+ pathAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
+ pathAnimation.fromValue = @([_current floatValue] / [_total floatValue]);
+ pathAnimation.toValue = @([current floatValue] / [total floatValue]);
+
+ if (_strokeColorGradientStart) {
+ [self.gradientMask addAnimation:pathAnimation forKey:@"strokeEndAnimation"];
+ }
+ [_circle addAnimation:pathAnimation forKey:@"strokeEndAnimation"];
+
+ if (_displayCountingLabel) {
+ [self.countingLabel countFrom:fmin([_current floatValue], [_total floatValue]) to:totalPercentageValue withDuration:self.duration];
+ }
+
+ }
+ else if (_displayCountingLabel) {
+ [self.countingLabel countFrom:totalPercentageValue to:totalPercentageValue withDuration:self.duration];
+ }
+
+ _circle.strokeEnd = [current floatValue] / [total floatValue];
+ _current = current;
+ _total = total;
+}
+
+- (void)addAnimationIfNeeded
+{
+ double percentageValue = [_current floatValue]/([_total floatValue]/100.0);
+
+ if (self.displayAnimated) {
+ CABasicAnimation *pathAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
+ pathAnimation.duration = self.duration;
+ pathAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
+ pathAnimation.fromValue = @(0.0f);
+ pathAnimation.toValue = @([_current floatValue] / [_total floatValue]);
+ [_circle addAnimation:pathAnimation forKey:@"strokeEndAnimation"];
+ [_countingLabel countFrom:0 to:percentageValue withDuration:self.duration];
+
+ if (self.gradientMask && _strokeColorGradientStart) {
+ [self.gradientMask addAnimation:pathAnimation forKey:@"strokeEndAnimation"];
+ }
+ }
+ else {
+ [_countingLabel countFrom:percentageValue to:percentageValue withDuration:self.duration];
+ }
+}
+
+@end
diff --git a/PNChartdemo/PNChart/PNColor.h b/PNChartdemo/PNChart/PNColor.h
new file mode 100755
index 0000000..cfd3ff8
--- /dev/null
+++ b/PNChartdemo/PNChart/PNColor.h
@@ -0,0 +1,53 @@
+//
+// PNColor.h
+// PNChart
+//
+// Created by kevin on 13-6-8.
+// Copyright (c) 2013��� kevinzhow. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+#import <UIKit/UIKit.h>
+
+/*
+ * System Versioning Preprocessor Macros
+ */
+
+#define SCREEN_WIDTH ([UIScreen mainScreen].bounds.size.width)
+
+#define PNGrey [UIColor colorWithRed:246.0 / 255.0 green:246.0 / 255.0 blue:246.0 / 255.0 alpha:1.0f]
+#define PNLightBlue [UIColor colorWithRed:94.0 / 255.0 green:147.0 / 255.0 blue:196.0 / 255.0 alpha:1.0f]
+#define PNGreen [UIColor colorWithRed:77.0 / 255.0 green:186.0 / 255.0 blue:122.0 / 255.0 alpha:1.0f]
+#define PNTitleColor [UIColor colorWithRed:0.0 / 255.0 green:189.0 / 255.0 blue:113.0 / 255.0 alpha:1.0f]
+#define PNButtonGrey [UIColor colorWithRed:141.0 / 255.0 green:141.0 / 255.0 blue:141.0 / 255.0 alpha:1.0f]
+#define PNLightGreen [UIColor colorWithRed:77.0 / 255.0 green:216.0 / 255.0 blue:122.0 / 255.0 alpha:1.0f]
+#define PNFreshGreen [UIColor colorWithRed:77.0 / 255.0 green:196.0 / 255.0 blue:122.0 / 255.0 alpha:1.0f]
+#define PNDeepGreen [UIColor colorWithRed:77.0 / 255.0 green:176.0 / 255.0 blue:122.0 / 255.0 alpha:1.0f]
+#define PNRed [UIColor colorWithRed:245.0 / 255.0 green:94.0 / 255.0 blue:78.0 / 255.0 alpha:1.0f]
+#define PNMauve [UIColor colorWithRed:88.0 / 255.0 green:75.0 / 255.0 blue:103.0 / 255.0 alpha:1.0f]
+#define PNBrown [UIColor colorWithRed:119.0 / 255.0 green:107.0 / 255.0 blue:95.0 / 255.0 alpha:1.0f]
+#define PNBlue [UIColor colorWithRed:82.0 / 255.0 green:116.0 / 255.0 blue:188.0 / 255.0 alpha:1.0f]
+#define PNDarkBlue [UIColor colorWithRed:121.0 / 255.0 green:134.0 / 255.0 blue:142.0 / 255.0 alpha:1.0f]
+#define PNYellow [UIColor colorWithRed:242.0 / 255.0 green:197.0 / 255.0 blue:117.0 / 255.0 alpha:1.0f]
+#define PNWhite [UIColor colorWithRed:255.0 / 255.0 green:255.0 / 255.0 blue:255.0 / 255.0 alpha:1.0f]
+#define PNDeepGrey [UIColor colorWithRed:99.0 / 255.0 green:99.0 / 255.0 blue:99.0 / 255.0 alpha:1.0f]
+#define PNPinkGrey [UIColor colorWithRed:200.0 / 255.0 green:193.0 / 255.0 blue:193.0 / 255.0 alpha:1.0f]
+#define PNHealYellow [UIColor colorWithRed:245.0 / 255.0 green:242.0 / 255.0 blue:238.0 / 255.0 alpha:1.0f]
+#define PNLightGrey [UIColor colorWithRed:225.0 / 255.0 green:225.0 / 255.0 blue:225.0 / 255.0 alpha:1.0f]
+#define PNCleanGrey [UIColor colorWithRed:251.0 / 255.0 green:251.0 / 255.0 blue:251.0 / 255.0 alpha:1.0f]
+#define PNLightYellow [UIColor colorWithRed:241.0 / 255.0 green:240.0 / 255.0 blue:240.0 / 255.0 alpha:1.0f]
+#define PNDarkYellow [UIColor colorWithRed:152.0 / 255.0 green:150.0 / 255.0 blue:159.0 / 255.0 alpha:1.0f]
+#define PNPinkDark [UIColor colorWithRed:170.0 / 255.0 green:165.0 / 255.0 blue:165.0 / 255.0 alpha:1.0f]
+#define PNCloudWhite [UIColor colorWithRed:244.0 / 255.0 green:244.0 / 255.0 blue:244.0 / 255.0 alpha:1.0f]
+#define PNBlack [UIColor colorWithRed:45.0 / 255.0 green:45.0 / 255.0 blue:45.0 / 255.0 alpha:1.0f]
+#define PNStarYellow [UIColor colorWithRed:252.0 / 255.0 green:223.0 / 255.0 blue:101.0 / 255.0 alpha:1.0f]
+#define PNTwitterColor [UIColor colorWithRed:0.0 / 255.0 green:171.0 / 255.0 blue:243.0 / 255.0 alpha:1.0]
+#define PNWeiboColor [UIColor colorWithRed:250.0 / 255.0 green:0.0 / 255.0 blue:33.0 / 255.0 alpha:1.0]
+#define PNiOSGreenColor [UIColor colorWithRed:98.0 / 255.0 green:247.0 / 255.0 blue:77.0 / 255.0 alpha:1.0]
+
+
+@interface PNColor : NSObject
+
+- (UIImage *)imageFromColor:(UIColor *)color;
+
+@end
diff --git a/PNChartdemo/PNChart/PNColor.m b/PNChartdemo/PNChart/PNColor.m
new file mode 100755
index 0000000..2ebc8c0
--- /dev/null
+++ b/PNChartdemo/PNChart/PNColor.m
@@ -0,0 +1,29 @@
+//
+// PNColor.m
+// PNChart
+//
+// Created by kevin on 13-6-8.
+// Copyright (c) 2013��� kevinzhow. All rights reserved.
+//
+
+#import "PNColor.h"
+#import <UIKit/UIKit.h>
+
+@implementation PNColor
+
+- (UIImage *)imageFromColor:(UIColor *)color
+{
+ CGRect rect = CGRectMake(0, 0, 1, 1);
+
+ UIGraphicsBeginImageContext(rect.size);
+ CGContextRef context = UIGraphicsGetCurrentContext();
+ CGContextSetFillColorWithColor(context, [color CGColor]);
+ CGContextFillRect(context, rect);
+ UIImage *img = UIGraphicsGetImageFromCurrentImageContext();
+ UIGraphicsEndImageContext();
+
+ return img;
+}
+
+
+@end
diff --git a/PNChartdemo/PNChart/PNGenericChart.h b/PNChartdemo/PNChart/PNGenericChart.h
new file mode 100755
index 0000000..829d84a
--- /dev/null
+++ b/PNChartdemo/PNChart/PNGenericChart.h
@@ -0,0 +1,48 @@
+//
+// PNGenericChart.h
+// PNChartDemo
+//
+// Created by Andi Palo on 26/02/15.
+// Copyright (c) 2015 kevinzhow. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+
+typedef NS_ENUM(NSUInteger, PNLegendPosition) {
+ PNLegendPositionTop = 0,
+ PNLegendPositionBottom = 1,
+ PNLegendPositionLeft = 2,
+ PNLegendPositionRight = 3
+};
+
+typedef NS_ENUM(NSUInteger, PNLegendItemStyle) {
+ PNLegendItemStyleStacked = 0,
+ PNLegendItemStyleSerial = 1
+};
+
+@interface PNGenericChart : UIView
+
+@property (assign, nonatomic) BOOL hasLegend;
+@property (assign, nonatomic) PNLegendPosition legendPosition;
+@property (assign, nonatomic) PNLegendItemStyle legendStyle;
+
+@property (assign, nonatomic) UIFont *legendFont;
+@property (assign, nonatomic) UIColor *legendFontColor;
+@property (assign, nonatomic) NSUInteger labelRowsInSerialMode;
+
+/** Display the chart with or without animation. Default is YES. **/
+@property (nonatomic) BOOL displayAnimated;
+
+/**
+ * returns the Legend View, or nil if no chart data is present.
+ * The origin of the legend frame is 0,0 but you can set it with setFrame:(CGRect)
+ *
+ * @param mWidth Maximum width of legend. Height will depend on this and font size
+ *
+ * @return UIView of Legend
+ */
+- (UIView*) getLegendWithMaxWidth:(CGFloat)mWidth;
+
+
+- (void) setupDefaultValues;
+@end
diff --git a/PNChartdemo/PNChart/PNGenericChart.m b/PNChartdemo/PNChart/PNGenericChart.m
new file mode 100755
index 0000000..c54ac37
--- /dev/null
+++ b/PNChartdemo/PNChart/PNGenericChart.m
@@ -0,0 +1,54 @@
+//
+// PNGenericChart.m
+// PNChartDemo
+//
+// Created by Andi Palo on 26/02/15.
+// Copyright (c) 2015 kevinzhow. All rights reserved.
+//
+
+#import "PNGenericChart.h"
+
+@interface PNGenericChart ()
+
+
+
+@end
+
+@implementation PNGenericChart
+
+/*
+// Only override drawRect: if you perform custom drawing.
+// An empty implementation adversely affects performance during animation.
+- (void)drawRect:(CGRect)rect {
+ // Drawing code
+}
+*/
+
+- (void) setupDefaultValues{
+ self.hasLegend = YES;
+ self.legendPosition = PNLegendPositionBottom;
+ self.legendStyle = PNLegendItemStyleStacked;
+ self.labelRowsInSerialMode = 1;
+ self.displayAnimated = YES;
+}
+
+
+
+/**
+ * to be implemented in subclass
+ */
+- (UIView*) getLegendWithMaxWidth:(CGFloat)mWidth{
+ [self doesNotRecognizeSelector:_cmd];
+ return nil;
+}
+
+- (void) setLabelRowsInSerialMode:(NSUInteger)num{
+ if (self.legendStyle == PNLegendItemStyleSerial) {
+ _labelRowsInSerialMode = num;
+ }else{
+ _labelRowsInSerialMode = 1;
+ }
+}
+
+
+@end
diff --git a/PNChartdemo/PNChart/PNLineChart.h b/PNChartdemo/PNChart/PNLineChart.h
new file mode 100755
index 0000000..b30878a
--- /dev/null
+++ b/PNChartdemo/PNChart/PNLineChart.h
@@ -0,0 +1,110 @@
+//
+// PNLineChart.h
+// PNChartDemo
+//
+// Created by kevin on 11/7/13.
+// Copyright (c) 2013��� kevinzhow. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+#import <QuartzCore/QuartzCore.h>
+#import "PNChartDelegate.h"
+#import "PNGenericChart.h"
+
+@interface PNLineChart : PNGenericChart
+
+/**
+ * Draws the chart in an animated fashion.
+ */
+- (void)strokeChart;
+
+@property (nonatomic, weak) id<PNChartDelegate> delegate;
+
+@property (nonatomic) NSArray *xLabels;
+@property (nonatomic) NSArray *yLabels;
+
+/**
+ * Array of `LineChartData` objects, one for each line.
+ */
+@property (nonatomic) NSArray *chartData;
+
+@property (nonatomic) NSMutableArray *pathPoints;
+@property (nonatomic) NSMutableArray *xChartLabels;
+@property (nonatomic) NSMutableArray *yChartLabels;
+
+@property (nonatomic) CGFloat xLabelWidth;
+@property (nonatomic) UIFont *xLabelFont;
+@property (nonatomic) UIColor *xLabelColor;
+@property (nonatomic) CGFloat yValueMax;
+@property (nonatomic) CGFloat yFixedValueMax;
+@property (nonatomic) CGFloat yFixedValueMin;
+@property (nonatomic) CGFloat yValueMin;
+@property (nonatomic) NSInteger yLabelNum;
+@property (nonatomic) CGFloat yLabelHeight;
+@property (nonatomic) UIFont *yLabelFont;
+@property (nonatomic) UIColor *yLabelColor;
+@property (nonatomic) CGFloat chartCavanHeight;
+@property (nonatomic) CGFloat chartCavanWidth;
+@property (nonatomic) BOOL showLabel;
+@property (nonatomic) BOOL showGenYLabels;
+@property (nonatomic) BOOL showYGridLines;
+@property (nonatomic) UIColor *yGridLinesColor;
+@property (nonatomic) BOOL thousandsSeparator;
+
+@property (nonatomic) CGFloat chartMarginLeft;
+@property (nonatomic) CGFloat chartMarginRight;
+@property (nonatomic) CGFloat chartMarginTop;
+@property (nonatomic) CGFloat chartMarginBottom;
+
+/**
+ * Controls whether to show the coordinate axis. Default is NO.
+ */
+@property (nonatomic, getter = isShowCoordinateAxis) BOOL showCoordinateAxis;
+@property (nonatomic) UIColor *axisColor;
+@property (nonatomic) CGFloat axisWidth;
+
+@property (nonatomic, strong) NSString *xUnit;
+@property (nonatomic, strong) NSString *yUnit;
+
+/**
+ * String formatter for float values in y-axis labels. If not set, defaults to @"%1.f"
+ */
+@property (nonatomic, strong) NSString *yLabelFormat;
+
+/**
+ * Block formatter for custom string in y-axis labels. If not set, defaults to yLabelFormat
+ */
+@property (nonatomic, copy) NSString* (^yLabelBlockFormatter)(CGFloat);
+
+
+/**
+ * Controls whether to curve the line chart or not
+ */
+@property (nonatomic) BOOL showSmoothLines;
+
+- (void)setXLabels:(NSArray *)xLabels withWidth:(CGFloat)width;
+
+/**
+ * Update Chart Value
+ */
+
+- (void)updateChartData:(NSArray *)data;
+
+
+/**
+ * returns the Legend View, or nil if no chart data is present.
+ * The origin of the legend frame is 0,0 but you can set it with setFrame:(CGRect)
+ *
+ * @param mWidth Maximum width of legend. Height will depend on this and font size
+ *
+ * @return UIView of Legend
+ */
+- (UIView*) getLegendWithMaxWidth:(CGFloat)mWidth;
+
+
++ (CGSize)sizeOfString:(NSString *)text withWidth:(float)width font:(UIFont *)font;
+
++ (CGPoint)midPointBetweenPoint1:(CGPoint)point1 andPoint2:(CGPoint)point2;
++ (CGPoint)controlPointBetweenPoint1:(CGPoint)point1 andPoint2:(CGPoint)point2;
+
+@end
diff --git a/PNChartdemo/PNChart/PNLineChart.m b/PNChartdemo/PNChart/PNLineChart.m
new file mode 100755
index 0000000..fda132d
--- /dev/null
+++ b/PNChartdemo/PNChart/PNLineChart.m
@@ -0,0 +1,1285 @@
+//
+// PNLineChart.m
+// PNChartDemo
+//
+// Created by kevin on 11/7/13.
+// Copyright (c) 2013��� kevinzhow. All rights reserved.
+//
+
+#import "PNLineChart.h"
+#import "PNColor.h"
+#import "PNChartLabel.h"
+#import "PNLineChartData.h"
+#import "PNLineChartDataItem.h"
+
+@interface PNLineChart ()
+
+@property(nonatomic) NSMutableArray *chartLineArray; // Array[CAShapeLayer]
+@property(nonatomic) NSMutableArray *chartPointArray; // Array[CAShapeLayer] save the point layer
+
+@property(nonatomic) NSMutableArray *chartPath; // Array of line path, one for each line.
+@property(nonatomic) NSMutableArray *pointPath; // Array of point path, one for each line
+@property(nonatomic) NSMutableArray *endPointsOfPath; // Array of start and end points of each line path, one for each line
+
+@property(nonatomic) CABasicAnimation *pathAnimation; // will be set to nil if _displayAnimation is NO
+
+// display grade
+@property(nonatomic) NSMutableArray *gradeStringPaths;
+@property(nonatomic) NSMutableArray *progressLinePathsColors; //Array of colors when drawing each line.if chartData.rangeColors is set then different colors will be
+
+@end
+
+@implementation PNLineChart
+
+@synthesize pathAnimation = _pathAnimation;
+
+#pragma mark initialization
+
+- (id)initWithCoder:(NSCoder *)coder {
+ self = [super initWithCoder:coder];
+
+ if (self) {
+ [self setupDefaultValues];
+ }
+
+ return self;
+}
+
+- (id)initWithFrame:(CGRect)frame {
+ self = [super initWithFrame:frame];
+
+ if (self) {
+ [self setupDefaultValues];
+ }
+
+ return self;
+}
+
+
+#pragma mark instance methods
+
+- (void)setYLabels {
+ CGFloat yStep = (_yValueMax - _yValueMin) / _yLabelNum;
+ CGFloat yStepHeight = _chartCavanHeight / _yLabelNum;
+
+ if (_yChartLabels) {
+ for (PNChartLabel *label in _yChartLabels) {
+ [label removeFromSuperview];
+ }
+ } else {
+ _yChartLabels = [NSMutableArray new];
+ }
+
+ if (yStep == 0.0) {
+ PNChartLabel *minLabel = [[PNChartLabel alloc] initWithFrame:CGRectMake(0.0, (NSInteger) _chartCavanHeight, (NSInteger) _chartMarginBottom, (NSInteger) _yLabelHeight)];
+ minLabel.text = [self formatYLabel:0.0];
+ [self setCustomStyleForYLabel:minLabel];
+ [self addSubview:minLabel];
+ [_yChartLabels addObject:minLabel];
+
+ PNChartLabel *midLabel = [[PNChartLabel alloc] initWithFrame:CGRectMake(0.0, (NSInteger) (_chartCavanHeight / 2), (NSInteger) _chartMarginBottom, (NSInteger) _yLabelHeight)];
+ midLabel.text = [self formatYLabel:_yValueMax];
+ [self setCustomStyleForYLabel:midLabel];
+ [self addSubview:midLabel];
+ [_yChartLabels addObject:midLabel];
+
+ PNChartLabel *maxLabel = [[PNChartLabel alloc] initWithFrame:CGRectMake(0.0, 0.0, (NSInteger) _chartMarginBottom, (NSInteger) _yLabelHeight)];
+ maxLabel.text = [self formatYLabel:_yValueMax * 2];
+ [self setCustomStyleForYLabel:maxLabel];
+ [self addSubview:maxLabel];
+ [_yChartLabels addObject:maxLabel];
+
+ } else {
+ NSInteger index = 0;
+ NSInteger num = _yLabelNum + 1;
+
+ while (num > 0) {
+ CGRect labelFrame = CGRectMake(0.0,
+ (NSInteger) (_chartCavanHeight + _chartMarginTop - index * yStepHeight),
+ (CGFloat) ((NSInteger) _chartMarginLeft * 0.9),
+ (NSInteger) _yLabelHeight);
+ PNChartLabel *label = [[PNChartLabel alloc] initWithFrame:labelFrame];
+ [label setTextAlignment:NSTextAlignmentRight];
+ label.text = [self formatYLabel:_yValueMin + (yStep * index)];
+ [self setCustomStyleForYLabel:label];
+ [self addSubview:label];
+ [_yChartLabels addObject:label];
+ index += 1;
+ num -= 1;
+ }
+ }
+}
+
+- (void)setYLabels:(NSArray *)yLabels {
+ _showGenYLabels = NO;
+ _yLabelNum = yLabels.count - 1;
+
+ CGFloat yLabelHeight;
+ if (_showLabel) {
+ yLabelHeight = _chartCavanHeight / [yLabels count];
+ } else {
+ yLabelHeight = (self.frame.size.height) / [yLabels count];
+ }
+
+ return [self setYLabels:yLabels withHeight:yLabelHeight];
+}
+
+- (void)setYLabels:(NSArray *)yLabels withHeight:(CGFloat)height {
+ _yLabels = yLabels;
+ _yLabelHeight = height;
+ if (_yChartLabels) {
+ for (PNChartLabel *label in _yChartLabels) {
+ [label removeFromSuperview];
+ }
+ } else {
+ _yChartLabels = [NSMutableArray new];
+ }
+
+ NSString *labelText;
+
+ if (_showLabel) {
+ CGFloat yStepHeight = _chartCavanHeight / _yLabelNum;
+
+ for (int index = 0; index < yLabels.count; index++) {
+ labelText = yLabels[(NSUInteger) index];
+
+ NSInteger y = (NSInteger) (_chartCavanHeight + _chartMarginTop - index * yStepHeight);
+
+ PNChartLabel *label = [[PNChartLabel alloc] initWithFrame:CGRectMake(0.0, y, (CGFloat) ((NSInteger) _chartMarginLeft * 0.9), (NSInteger) _yLabelHeight)];
+ [label setTextAlignment:NSTextAlignmentRight];
+ label.text = labelText;
+ [self setCustomStyleForYLabel:label];
+ [self addSubview:label];
+ [_yChartLabels addObject:label];
+ }
+ }
+}
+
+- (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;
+
+ if (_showLabel) {
+ xLabelWidth = _chartCavanWidth / [xLabels count];
+ } else {
+ xLabelWidth = (self.frame.size.width - _chartMarginLeft - _chartMarginRight) / [xLabels count];
+ }
+
+ return [self setXLabels:xLabels withWidth:xLabelWidth];
+}
+
+- (void)setXLabels:(NSArray *)xLabels withWidth:(CGFloat)width {
+ _xLabels = xLabels;
+ _xLabelWidth = width;
+ if (_xChartLabels) {
+ for (PNChartLabel *label in _xChartLabels) {
+ [label removeFromSuperview];
+ }
+ } else {
+ _xChartLabels = [NSMutableArray new];
+ }
+
+ NSString *labelText;
+
+ if (_showLabel) {
+ for (NSUInteger index = 0; index < xLabels.count; index++) {
+ labelText = xLabels[index];
+
+ NSInteger x = (NSInteger) (index * _xLabelWidth + _chartMarginLeft);
+ NSInteger y = (NSInteger) (_chartMarginBottom + _chartCavanHeight);
+
+ PNChartLabel *label = [[PNChartLabel alloc] initWithFrame:CGRectMake(x, y, (NSInteger) _xLabelWidth, (NSInteger) _chartMarginBottom)];
+ [label setTextAlignment:NSTextAlignmentCenter];
+ label.text = labelText;
+ [self setCustomStyleForXLabel:label];
+ [self addSubview:label];
+ [_xChartLabels addObject:label];
+ }
+ }
+}
+
+- (void)setCustomStyleForXLabel:(UILabel *)label {
+ if (_xLabelFont) {
+ label.font = _xLabelFont;
+ }
+
+ if (_xLabelColor) {
+ label.textColor = _xLabelColor;
+ }
+
+}
+
+- (void)setCustomStyleForYLabel:(UILabel *)label {
+ if (_yLabelFont) {
+ label.font = _yLabelFont;
+ }
+
+ if (_yLabelColor) {
+ label.textColor = _yLabelColor;
+ }
+}
+
+#pragma mark - Touch at point
+
+- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
+ [self touchPoint:touches withEvent:event];
+ [self touchKeyPoint:touches withEvent:event];
+}
+
+- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
+ [self touchPoint:touches withEvent:event];
+ [self touchKeyPoint:touches withEvent:event];
+}
+
+- (void)touchPoint:(NSSet *)touches withEvent:(UIEvent *)event {
+ // Get the point user touched
+ UITouch *touch = [touches anyObject];
+ CGPoint touchPoint = [touch locationInView:self];
+
+ for (NSUInteger p = 0; p < _pathPoints.count; p++) {
+ NSArray *linePointsArray = _endPointsOfPath[p];
+
+ for (NSUInteger i = 0; i < (int) linePointsArray.count - 1; i += 2) {
+ CGPoint p1 = [linePointsArray[i] CGPointValue];
+ CGPoint p2 = [linePointsArray[i + 1] CGPointValue];
+
+ // Closest distance from point to line
+ float distance = (float) fabs(((p2.x - p1.x) * (touchPoint.y - p1.y)) - ((p1.x - touchPoint.x) * (p1.y - p2.y)));
+ distance /= hypot(p2.x - p1.x, p1.y - p2.y);
+
+ if (distance <= 5.0) {
+ // Conform to delegate parameters, figure out what bezier path this CGPoint belongs to.
+ NSUInteger lineIndex = 0;
+ for (NSArray<UIBezierPath *> *paths in _chartPath) {
+ for (UIBezierPath *path in paths) {
+ BOOL pointContainsPath = CGPathContainsPoint(path.CGPath, NULL, p1, NO);
+ if (pointContainsPath) {
+ [_delegate userClickedOnLinePoint:touchPoint lineIndex:lineIndex];
+ return;
+ }
+ }
+ lineIndex++;
+ }
+ }
+ }
+ }
+}
+
+- (void)touchKeyPoint:(NSSet *)touches withEvent:(UIEvent *)event {
+ // Get the point user touched
+ UITouch *touch = [touches anyObject];
+ CGPoint touchPoint = [touch locationInView:self];
+
+ for (NSUInteger p = 0; p < _pathPoints.count; p++) {
+ NSArray *linePointsArray = _pathPoints[p];
+
+ for (NSUInteger i = 0; i < (int) linePointsArray.count - 1; i += 1) {
+ CGPoint p1 = [linePointsArray[i] CGPointValue];
+ CGPoint p2 = [linePointsArray[i + 1] CGPointValue];
+
+ float distanceToP1 = (float) fabs(hypot(touchPoint.x - p1.x, touchPoint.y - p1.y));
+ float distanceToP2 = (float) hypot(touchPoint.x - p2.x, touchPoint.y - p2.y);
+
+ float distance = MIN(distanceToP1, distanceToP2);
+
+ if (distance <= 10.0) {
+ [_delegate userClickedOnLineKeyPoint:touchPoint
+ lineIndex:p
+ pointIndex:(distance == distanceToP2 ? i + 1 : i)];
+
+ return;
+ }
+ }
+ }
+}
+
+#pragma mark - Draw Chart
+
+- (void)populateChartLines {
+ for (NSUInteger lineIndex = 0; lineIndex < self.chartData.count; lineIndex++) {
+ NSArray<UIBezierPath *> *progressLines = self.chartPath[lineIndex];
+ // each chart line can be divided into multiple paths because
+ // we need ot draw each path with different color
+ // if there is not rangeColors then there is only one progressLinePath per chart
+ NSArray<UIColor *> *progressLineColors = self.progressLinePathsColors[lineIndex];
+ [self.chartLineArray[lineIndex] removeAllObjects];
+ NSUInteger progressLineIndex = 0;;
+ for (UIBezierPath *progressLinePath in progressLines) {
+ PNLineChartData *chartData = self.chartData[lineIndex];
+ CAShapeLayer *chartLine = [CAShapeLayer layer];
+ chartLine.lineCap = kCALineCapButt;
+ chartLine.lineJoin = kCALineJoinMiter;
+ chartLine.fillColor = self.backgroundColor.CGColor;
+ chartLine.lineWidth = chartData.lineWidth;
+ chartLine.path = progressLinePath.CGPath;
+ chartLine.strokeEnd = 0.0;
+ chartLine.strokeColor = progressLineColors[progressLineIndex].CGColor;
+ [self.layer addSublayer:chartLine];
+ [self.chartLineArray[lineIndex] addObject:chartLine];
+ progressLineIndex++;
+ }
+ }
+}
+
+/*
+ * strokeChart should remove the previously drawn chart lines and points
+ * and then proceed to draw the new lines
+ */
+- (void)strokeChart {
+ [self removeLayers];
+ // remove all shape layers before adding new ones
+ [self recreatePointLayers];
+ // Cavan height and width needs to be set before
+ // setNeedsDisplay is invoked because setNeedsDisplay
+ // will invoke drawRect and if Cavan dimensions is not
+ // set the chart will be misplaced
+ [self resetCavanHeight];
+ [self prepareYLabelsWithData:_chartData];
+
+ _chartPath = [[NSMutableArray alloc] init];
+ _pointPath = [[NSMutableArray alloc] init];
+ _gradeStringPaths = [NSMutableArray array];
+ _progressLinePathsColors = [[NSMutableArray alloc] init];
+
+ [self calculateChartPath:_chartPath
+ andPointsPath:_pointPath
+ andPathKeyPoints:_pathPoints
+ andPathStartEndPoints:_endPointsOfPath
+ andProgressLinePathsColors:_progressLinePathsColors];
+ [self populateChartLines];
+ // Draw each line
+ for (NSUInteger lineIndex = 0; lineIndex < self.chartData.count; lineIndex++) {
+ PNLineChartData *chartData = self.chartData[lineIndex];
+ NSArray<CAShapeLayer *> *chartLines =self.chartLineArray[lineIndex];
+ CAShapeLayer *pointLayer = (CAShapeLayer *) self.chartPointArray[lineIndex];
+ UIGraphicsBeginImageContext(self.frame.size);
+ if (chartData.inflexionPointColor) {
+ pointLayer.strokeColor = [[chartData.inflexionPointColor
+ colorWithAlphaComponent:chartData.alpha] CGColor];
+ } else {
+ pointLayer.strokeColor = [PNGreen CGColor];
+ }
+ // setup the color of the chart line
+ NSArray<UIBezierPath *> *progressLines = _chartPath[lineIndex];
+ UIBezierPath *pointPath = _pointPath[lineIndex];
+
+ pointLayer.path = pointPath.CGPath;
+
+ [CATransaction begin];
+ for (NSUInteger index = 0; index < progressLines.count; index++) {
+ CAShapeLayer *chartLine = chartLines[index];
+ //chartLine strokeColor is already set. no need to override here
+ [chartLine addAnimation:self.pathAnimation forKey:@"strokeEndAnimation"];
+ chartLine.strokeEnd = 1.0;
+ }
+
+ // if you want cancel the point animation, comment this code, the point will show immediately
+ if (chartData.inflexionPointStyle != PNLineChartPointStyleNone) {
+ [pointLayer addAnimation:self.pathAnimation forKey:@"strokeEndAnimation"];
+ }
+
+ [CATransaction commit];
+
+ NSMutableArray *textLayerArray = self.gradeStringPaths[lineIndex];
+ for (CATextLayer *textLayer in textLayerArray) {
+ CABasicAnimation *fadeAnimation = [self fadeAnimation];
+ [textLayer addAnimation:fadeAnimation forKey:nil];
+ }
+
+ UIGraphicsEndImageContext();
+ }
+ [self setNeedsDisplay];
+}
+
+
+- (void)calculateChartPath:(NSMutableArray *)chartPath
+ andPointsPath:(NSMutableArray *)pointsPath
+ andPathKeyPoints:(NSMutableArray *)pathPoints
+ andPathStartEndPoints:(NSMutableArray *)pointsOfPath
+andProgressLinePathsColors:(NSMutableArray *)progressLinePathsColors {
+
+ // Draw each line
+
+ for (NSUInteger lineIndex = 0; lineIndex < self.chartData.count; lineIndex++) {
+ PNLineChartData *chartData = self.chartData[lineIndex];
+
+ CGFloat yValue;
+ NSMutableArray<UIBezierPath *> *progressLines = [NSMutableArray new];
+ NSMutableArray<UIColor *> *progressLineColors = [NSMutableArray new];
+
+ UIBezierPath *pointPath = [UIBezierPath bezierPath];
+
+
+ [chartPath insertObject:progressLines atIndex:lineIndex];
+ [pointsPath insertObject:pointPath atIndex:lineIndex];
+ [progressLinePathsColors insertObject:progressLineColors atIndex:lineIndex];
+
+
+ NSMutableArray *gradePathArray = [NSMutableArray array];
+ [self.gradeStringPaths addObject:gradePathArray];
+
+ NSMutableArray *linePointsArray = [[NSMutableArray alloc] init];
+ NSMutableArray *lineStartEndPointsArray = [[NSMutableArray alloc] init];
+ int last_x = 0;
+ int last_y = 0;
+ NSMutableArray<NSDictionary<NSString *, NSValue *> *> *progressLinePaths = [NSMutableArray new];
+ UIColor *defaultColor = chartData.color != nil ? chartData.color : [UIColor greenColor];
+ CGFloat inflexionWidth = chartData.inflexionPointWidth;
+
+ for (NSUInteger i = 0; i < chartData.itemCount; i++) {
+
+ NSValue *from = nil;
+ NSValue *to = nil;
+
+ yValue = chartData.getData(i).y;
+
+ int x = (int) (i * _xLabelWidth + _chartMarginLeft + _xLabelWidth / 2.0);
+ int y = (int)[self yValuePositionInLineChart:yValue];
+
+ // Circular point
+ if (chartData.inflexionPointStyle == PNLineChartPointStyleCircle)
+ {
+
+ CGRect circleRect = CGRectMake(x - inflexionWidth / 2, y - inflexionWidth / 2, inflexionWidth, inflexionWidth);
+ CGPoint circleCenter = CGPointMake(circleRect.origin.x + (circleRect.size.width / 2), circleRect.origin.y + (circleRect.size.height / 2));
+
+ [pointPath moveToPoint:CGPointMake(circleCenter.x + (inflexionWidth / 2), circleCenter.y)];
+ [pointPath addArcWithCenter:circleCenter radius:inflexionWidth / 2 startAngle:0 endAngle:(CGFloat) (2 * M_PI) clockwise:YES];
+
+ //jet text display text
+ if (chartData.showPointLabel) {
+ [gradePathArray addObject:[self createPointLabelFor:chartData.getData(i).rawY pointCenter:circleCenter width:inflexionWidth withChartData:chartData]];
+ }
+
+ if (i > 0) {
+
+ // calculate the point for line
+ float distance = (float) sqrt(pow(x - last_x, 2) + pow(y - last_y, 2));
+ float last_x1 = last_x + (inflexionWidth / 2) / distance * (x - last_x);
+ float last_y1 = last_y + (inflexionWidth / 2) / distance * (y - last_y);
+ float x1 = x - (inflexionWidth / 2) / distance * (x - last_x);
+ float y1 = y - (inflexionWidth / 2) / distance * (y - last_y);
+ from = [NSValue valueWithCGPoint:CGPointMake(last_x1, last_y1)];
+ to = [NSValue valueWithCGPoint:CGPointMake(x1, y1)];
+ }
+ }
+ // Square point
+ else if (chartData.inflexionPointStyle == PNLineChartPointStyleSquare) {
+
+ CGRect squareRect = CGRectMake(x - inflexionWidth / 2, y - inflexionWidth / 2, inflexionWidth, inflexionWidth);
+ CGPoint squareCenter = CGPointMake(squareRect.origin.x + (squareRect.size.width / 2), squareRect.origin.y + (squareRect.size.height / 2));
+
+ [pointPath moveToPoint:CGPointMake(squareCenter.x - (inflexionWidth / 2), squareCenter.y - (inflexionWidth / 2))];
+ [pointPath addLineToPoint:CGPointMake(squareCenter.x + (inflexionWidth / 2), squareCenter.y - (inflexionWidth / 2))];
+ [pointPath addLineToPoint:CGPointMake(squareCenter.x + (inflexionWidth / 2), squareCenter.y + (inflexionWidth / 2))];
+ [pointPath addLineToPoint:CGPointMake(squareCenter.x - (inflexionWidth / 2), squareCenter.y + (inflexionWidth / 2))];
+ [pointPath closePath];
+
+ // text display text
+ if (chartData.showPointLabel) {
+ [gradePathArray addObject:[self createPointLabelFor:chartData.getData(i).rawY pointCenter:squareCenter width:inflexionWidth withChartData:chartData]];
+ }
+
+ if (i > 0) {
+
+ // calculate the point for line
+ float distance = (float) sqrt(pow(x - last_x, 2) + pow(y - last_y, 2));
+ float last_x1 = last_x + (inflexionWidth / 2);
+ float last_y1 = last_y + (inflexionWidth / 2) / distance * (y - last_y);
+ float x1 = x - (inflexionWidth / 2);
+ float y1 = y - (inflexionWidth / 2) / distance * (y - last_y);
+ from = [NSValue valueWithCGPoint:CGPointMake(last_x1, last_y1)];
+ to = [NSValue valueWithCGPoint:CGPointMake(x1, y1)];
+ }
+ }
+ // Triangle point
+ else if (chartData.inflexionPointStyle == PNLineChartPointStyleTriangle) {
+
+ CGRect squareRect = CGRectMake(x - inflexionWidth / 2, y - inflexionWidth / 2, inflexionWidth, inflexionWidth);
+
+ CGPoint startPoint = CGPointMake(squareRect.origin.x, squareRect.origin.y + squareRect.size.height);
+ CGPoint endPoint = CGPointMake(squareRect.origin.x + (squareRect.size.width / 2), squareRect.origin.y);
+ CGPoint middlePoint = CGPointMake(squareRect.origin.x + (squareRect.size.width), squareRect.origin.y + squareRect.size.height);
+
+ [pointPath moveToPoint:startPoint];
+ [pointPath addLineToPoint:middlePoint];
+ [pointPath addLineToPoint:endPoint];
+ [pointPath closePath];
+
+ // text display text
+ if (chartData.showPointLabel) {
+ [gradePathArray addObject:[self createPointLabelFor:chartData.getData(i).rawY pointCenter:middlePoint width:inflexionWidth withChartData:chartData]];
+ }
+
+ if (i > 0) {
+ // calculate the point for triangle
+ float distance = (float) (sqrt(pow(x - last_x, 2) + pow(y - last_y, 2)) * 1.4);
+ float last_x1 = last_x + (inflexionWidth / 2) / distance * (x - last_x);
+ float last_y1 = last_y + (inflexionWidth / 2) / distance * (y - last_y);
+ float x1 = x - (inflexionWidth / 2) / distance * (x - last_x);
+ float y1 = y - (inflexionWidth / 2) / distance * (y - last_y);
+ from = [NSValue valueWithCGPoint:CGPointMake(last_x1, last_y1)];
+ to = [NSValue valueWithCGPoint:CGPointMake(x1, y1)];
+ }
+ } else {
+
+ if (i > 0) {
+ from = [NSValue valueWithCGPoint:CGPointMake(last_x, last_y)];
+ to = [NSValue valueWithCGPoint:CGPointMake(x, y)];
+ }
+ }
+ if(from != nil && to != nil) {
+ [progressLinePaths addObject:@{@"from": from, @"to":to}];
+ [lineStartEndPointsArray addObject:from];
+ [lineStartEndPointsArray addObject:to];
+ }
+ [linePointsArray addObject:[NSValue valueWithCGPoint:CGPointMake(x, y)]];
+ last_x = x;
+ last_y = y;
+ }
+
+ [pointsOfPath addObject:[lineStartEndPointsArray copy]];
+ [pathPoints addObject:[linePointsArray copy]];
+ // if rangeColors is not nil then it means we need to draw the chart
+ // with different colors. colorRangesBetweenP1.. function takes care of
+ // partitioning the p1->p2 into segments from which we can create UIBezierPath
+ if (self.showSmoothLines && chartData.itemCount >= 4) {
+ for (NSDictionary<NSString *, NSValue *> *item in progressLinePaths) {
+ NSArray<NSDictionary *> *calculatedRanges =
+ [self colorRangesBetweenP1:[item[@"from"] CGPointValue]
+ P2:[item[@"to"] CGPointValue]
+ rangeColors:chartData.rangeColors
+ defaultColor:defaultColor];
+ for (NSDictionary *range in calculatedRanges) {
+// NSLog(@"range : %@ range: %@ color %@", range[@"from"], range[@"to"], range[@"color"]);
+ UIBezierPath *currentProgressLine = [UIBezierPath bezierPath];
+ CGPoint segmentP1 = [range[@"from"] CGPointValue];
+ CGPoint segmentP2 = [range[@"to"] CGPointValue];
+ [currentProgressLine moveToPoint:segmentP1];
+ CGPoint midPoint = [PNLineChart midPointBetweenPoint1:segmentP1 andPoint2:segmentP2];
+ [currentProgressLine addQuadCurveToPoint:midPoint
+ controlPoint:[PNLineChart controlPointBetweenPoint1:midPoint andPoint2:segmentP1]];
+ [currentProgressLine addQuadCurveToPoint:segmentP2
+ controlPoint:[PNLineChart controlPointBetweenPoint1:midPoint andPoint2:segmentP2]];
+ [progressLines addObject:currentProgressLine];
+ [progressLineColors addObject:range[@"color"]];
+ }
+ }
+ } else {
+ for (NSDictionary<NSString *, NSValue *> *item in progressLinePaths) {
+ NSArray<NSDictionary *> *calculatedRanges =
+ [self colorRangesBetweenP1:[item[@"from"] CGPointValue]
+ P2:[item[@"to"] CGPointValue]
+ rangeColors:chartData.rangeColors
+ defaultColor:defaultColor];
+ for (NSDictionary *range in calculatedRanges) {
+// NSLog(@"range : %@ range: %@ color %@", range[@"from"], range[@"to"], range[@"color"]);
+ UIBezierPath *currentProgressLine = [UIBezierPath bezierPath];
+ [currentProgressLine moveToPoint:[range[@"from"] CGPointValue]];
+ [currentProgressLine addLineToPoint:[range[@"to"] CGPointValue]];
+ [progressLines addObject:currentProgressLine];
+ [progressLineColors addObject:range[@"color"]];
+ }
+ }
+ }
+ }
+}
+
+#pragma mark - Set Chart Data
+
+- (void)setChartData:(NSArray *)data {
+ if (data != _chartData) {
+ _chartData = data;
+ }
+}
+
+
+- (void)removeLayers {
+ for (NSArray<CALayer *> *layers in self.chartLineArray) {
+ for (CALayer *layer in layers) {
+ [layer removeFromSuperlayer];
+ }
+ }
+ for (CALayer *layer in self.chartPointArray) {
+ [layer removeFromSuperlayer];
+ }
+ self.chartLineArray = [NSMutableArray arrayWithCapacity:_chartData.count];
+ self.chartPointArray = [NSMutableArray arrayWithCapacity:_chartData.count];
+}
+
+-(void) resetCavanHeight {
+ _chartCavanHeight = self.frame.size.height - _chartMarginBottom - _chartMarginTop;
+ if (!_showLabel) {
+ _chartCavanHeight = self.frame.size.height - 2 * _yLabelHeight;
+ _chartCavanWidth = self.frame.size.width;
+ //_chartMargin = chartData.inflexionPointWidth;
+ _xLabelWidth = (_chartCavanWidth / ([_xLabels count]));
+ }
+}
+
+- (void)recreatePointLayers {
+ for (PNLineChartData *chartData in _chartData) {
+ // create as many chart line layers as there are data-lines
+ [self.chartLineArray addObject:[NSMutableArray new]];
+
+ // create point
+ CAShapeLayer *pointLayer = [CAShapeLayer layer];
+ pointLayer.strokeColor = [[chartData.color colorWithAlphaComponent:chartData.alpha] CGColor];
+ pointLayer.lineCap = kCALineCapRound;
+ pointLayer.lineJoin = kCALineJoinBevel;
+ pointLayer.fillColor = nil;
+ pointLayer.lineWidth = chartData.lineWidth;
+ [self.layer addSublayer:pointLayer];
+ [self.chartPointArray addObject:pointLayer];
+ }
+}
+
+- (void)prepareYLabelsWithData:(NSArray *)data {
+ CGFloat yMax = 0.0f;
+ CGFloat yMin = MAXFLOAT;
+ NSMutableArray *yLabelsArray = [NSMutableArray new];
+
+ for (PNLineChartData *chartData in data) {
+ // create as many chart line layers as there are data-lines
+
+ for (NSUInteger i = 0; i < chartData.itemCount; i++) {
+ CGFloat yValue = chartData.getData(i).y;
+ [yLabelsArray addObject:[NSString stringWithFormat:@"%2f", yValue]];
+ yMax = fmaxf(yMax, yValue);
+ yMin = fminf(yMin, yValue);
+ }
+ }
+
+
+ if (_yValueMin == -FLT_MAX) {
+ _yValueMin = (_yFixedValueMin > -FLT_MAX) ? _yFixedValueMin : yMin;
+ }
+ if (_yValueMax == -FLT_MAX) {
+ _yValueMax = (CGFloat) ((_yFixedValueMax > -FLT_MAX) ? _yFixedValueMax : yMax + yMax / 10.0);
+ }
+
+ if (_showGenYLabels) {
+ [self setYLabels];
+ }
+
+}
+
+#pragma mark - Update Chart Data
+
+- (void)updateChartData:(NSArray *)data {
+ _chartData = data;
+
+ [self prepareYLabelsWithData:data];
+
+ [self calculateChartPath:_chartPath
+ andPointsPath:_pointPath
+ andPathKeyPoints:_pathPoints
+ andPathStartEndPoints:_endPointsOfPath
+ andProgressLinePathsColors:_progressLinePathsColors];
+
+ for (NSUInteger lineIndex = 0; lineIndex < self.chartData.count; lineIndex++) {
+
+ CAShapeLayer *chartLine = (CAShapeLayer *) self.chartLineArray[lineIndex];
+ CAShapeLayer *pointLayer = (CAShapeLayer *) self.chartPointArray[lineIndex];
+
+
+ NSArray<UIBezierPath *> *progressLines = _chartPath[lineIndex];
+ UIBezierPath *pointPath = _pointPath[lineIndex];
+
+ for(UIBezierPath *progressLine in progressLines) {
+ CABasicAnimation *pathAnimation = [CABasicAnimation animationWithKeyPath:@"path"];
+ pathAnimation.fromValue = (id) chartLine.path;
+ pathAnimation.toValue = (__bridge id) [progressLine CGPath];
+ pathAnimation.duration = 0.5f;
+ pathAnimation.autoreverses = NO;
+ pathAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
+ [chartLine addAnimation:pathAnimation forKey:@"animationKey"];
+ chartLine.path = progressLine.CGPath;
+ }
+
+ CABasicAnimation *pointPathAnimation = [CABasicAnimation animationWithKeyPath:@"path"];
+ pointPathAnimation.fromValue = (id) pointLayer.path;
+ pointPathAnimation.toValue = (__bridge id) [pointPath CGPath];
+ pointPathAnimation.duration = 0.5f;
+ pointPathAnimation.autoreverses = NO;
+ pointPathAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
+ [pointLayer addAnimation:pointPathAnimation forKey:@"animationKey"];
+
+ pointLayer.path = pointPath.CGPath;
+
+
+ }
+
+}
+
+#define IOS7_OR_LATER [[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0
+
+- (void)drawRect:(CGRect)rect {
+ if (self.isShowCoordinateAxis) {
+ CGFloat yAxisOffset = 10.f;
+
+ CGContextRef ctx = UIGraphicsGetCurrentContext();
+ UIGraphicsPopContext();
+ UIGraphicsPushContext(ctx);
+ CGContextSetLineWidth(ctx, self.axisWidth);
+ CGContextSetStrokeColorWithColor(ctx, [self.axisColor CGColor]);
+
+ CGFloat xAxisWidth = CGRectGetWidth(rect) - (_chartMarginLeft + _chartMarginRight) / 2;
+ CGFloat yAxisHeight = _chartMarginBottom + _chartCavanHeight;
+
+ // draw coordinate axis
+ CGContextMoveToPoint(ctx, _chartMarginBottom + yAxisOffset, 0);
+ CGContextAddLineToPoint(ctx, _chartMarginBottom + yAxisOffset, yAxisHeight);
+ CGContextAddLineToPoint(ctx, xAxisWidth, yAxisHeight);
+ CGContextStrokePath(ctx);
+
+ // draw y axis arrow
+ CGContextMoveToPoint(ctx, _chartMarginBottom + yAxisOffset - 3, 6);
+ CGContextAddLineToPoint(ctx, _chartMarginBottom + yAxisOffset, 0);
+ CGContextAddLineToPoint(ctx, _chartMarginBottom + yAxisOffset + 3, 6);
+ CGContextStrokePath(ctx);
+
+ // draw x axis arrow
+ CGContextMoveToPoint(ctx, xAxisWidth - 6, yAxisHeight - 3);
+ CGContextAddLineToPoint(ctx, xAxisWidth, yAxisHeight);
+ CGContextAddLineToPoint(ctx, xAxisWidth - 6, yAxisHeight + 3);
+ CGContextStrokePath(ctx);
+
+ if (self.showLabel) {
+
+ // draw x axis separator
+ CGPoint point;
+ for (NSUInteger i = 0; i < [self.xLabels count]; i++) {
+ point = CGPointMake(2 * _chartMarginLeft + (i * _xLabelWidth), _chartMarginBottom + _chartCavanHeight);
+ CGContextMoveToPoint(ctx, point.x, point.y - 2);
+ CGContextAddLineToPoint(ctx, point.x, point.y);
+ CGContextStrokePath(ctx);
+ }
+
+ // draw y axis separator
+ CGFloat yStepHeight = _chartCavanHeight / _yLabelNum;
+ for (NSUInteger i = 0; i < [self.xLabels count]; i++) {
+ point = CGPointMake(_chartMarginBottom + yAxisOffset, (_chartCavanHeight - i * yStepHeight + _yLabelHeight / 2));
+ CGContextMoveToPoint(ctx, point.x, point.y);
+ CGContextAddLineToPoint(ctx, point.x + 2, point.y);
+ CGContextStrokePath(ctx);
+ }
+ }
+
+ UIFont *font = [UIFont systemFontOfSize:11];
+
+ // draw y unit
+ if ([self.yUnit length]) {
+ CGFloat height = [PNLineChart sizeOfString:self.yUnit withWidth:30.f font:font].height;
+ CGRect drawRect = CGRectMake(_chartMarginLeft + 10 + 5, 0, 30.f, height);
+ [self drawTextInContext:ctx text:self.yUnit inRect:drawRect font:font color:self.yLabelColor];
+ }
+
+ // draw x unit
+ if ([self.xUnit length]) {
+ CGFloat height = [PNLineChart sizeOfString:self.xUnit withWidth:30.f font:font].height;
+ CGRect drawRect = CGRectMake(CGRectGetWidth(rect) - _chartMarginLeft + 5, _chartMarginBottom + _chartCavanHeight - height / 2, 25.f, height);
+ [self drawTextInContext:ctx text:self.xUnit inRect:drawRect font:font color:self.xLabelColor];
+ }
+ }
+ if (self.showYGridLines) {
+ CGContextRef ctx = UIGraphicsGetCurrentContext();
+ CGFloat yAxisOffset = _showLabel ? 10.f : 0.0f;
+ CGPoint point;
+ CGFloat yStepHeight = _chartCavanHeight / _yLabelNum;
+ if (self.yGridLinesColor) {
+ CGContextSetStrokeColorWithColor(ctx, self.yGridLinesColor.CGColor);
+ } else {
+ CGContextSetStrokeColorWithColor(ctx, [UIColor lightGrayColor].CGColor);
+ }
+ for (NSUInteger i = 0; i < _yLabelNum; i++) {
+ point = CGPointMake(_chartMarginLeft + yAxisOffset, (_chartCavanHeight - i * yStepHeight + _yLabelHeight / 2));
+ CGContextMoveToPoint(ctx, point.x, point.y);
+ // add dotted style grid
+ CGFloat dash[] = {6, 5};
+ // dot diameter is 20 points
+ CGContextSetLineWidth(ctx, 0.5);
+ CGContextSetLineCap(ctx, kCGLineCapRound);
+ CGContextSetLineDash(ctx, 0.0, dash, 2);
+ CGContextAddLineToPoint(ctx, CGRectGetWidth(rect) - _chartMarginLeft + 5, point.y);
+ CGContextStrokePath(ctx);
+ }
+ }
+
+ [super drawRect:rect];
+}
+
+#pragma mark private methods
+
+/*
+ * helper function that maps a y value ( from chartData) to
+ * a position in the chart ( between _yValueMin and _yValueMax)
+ */
+- (CGFloat)yValuePositionInLineChart:(CGFloat)y {
+ CGFloat innerGrade;
+ if (!(_yValueMax - _yValueMin)) {
+ innerGrade = 0.5;
+ } else {
+ innerGrade = ((CGFloat) y - _yValueMin) / (_yValueMax - _yValueMin);
+ }
+ return _chartCavanHeight - (innerGrade * _chartCavanHeight) - (_yLabelHeight / 2) + _chartMarginTop;
+}
+
+/**
+ * return array of segments which represents the color and path
+ * for each segments.
+ * for instance if p1.y=1 and p2.y=10
+ * and rangeColor = use blue for 2<y<3 and red for 4<y<6
+ * then this function divides the space between p1 and p2 into three segments
+ * segment #1 : 1-2 : default color
+ * segment #2 : 2-3 : blue
+ * segment #3 : 3-4 : default color
+ * segment #4 : 4-6 : red
+ * segment #5: 6-10 : default color
+ *
+ * keep in mind that the rangeColors values are based on the chartData so it needs to
+ * convert those values to coordinates which are valid between yValueMin and yValueMax
+ *
+ * in order to find whether there is an overlap between any of the rangeColors and the
+ * p1-p2 it uses NSIntersectionRange to intersect their yValues.
+ *
+ * @param p1
+ * @param p2
+ * @param rangeColors
+ * @param defaultColor
+ * @return
+ */
+- (NSArray *)colorRangesBetweenP1:(CGPoint)p1 P2:(CGPoint)p2
+ rangeColors:(NSArray<PNLineChartColorRange *> *)rangeColors
+ defaultColor:(UIColor *)defaultColor {
+ if (rangeColors && rangeColors.count > 0 && p2.x > p1.x) {
+ PNLineChartColorRange *colorForRangeInfo = [[rangeColors firstObject] copy];
+ NSArray *remainingRanges = nil;
+ if (rangeColors.count > 1) {
+ remainingRanges = [rangeColors subarrayWithRange:NSMakeRange(1, rangeColors.count - 1)];
+ }
+ // tRange : convert the rangeColors.range values to value between yValueMin and yValueMax
+ CGFloat transformedStart = [self yValuePositionInLineChart:(CGFloat)
+ colorForRangeInfo.range.location];
+ CGFloat transformedEnd = [self yValuePositionInLineChart:(CGFloat)
+ (colorForRangeInfo.range.location + colorForRangeInfo.range.length)];
+
+ NSRange pathRange = NSMakeRange((NSUInteger) fmin(p1.y, p2.y), (NSUInteger) fabs(p2.y - p1.y));
+ NSRange tRange = NSMakeRange((NSUInteger) fmin(transformedStart, transformedEnd),
+ (NSUInteger) fabs(transformedEnd - transformedStart));
+ if (NSIntersectionRange(tRange, pathRange).length > 0) {
+ CGPoint partition1EndPoint;
+ CGPoint partition2EndPoint;
+ NSArray *partition1 = @[];
+ NSDictionary *partition2 = nil;
+ NSArray *partition3 = @[];
+ if (p2.y >= p1.y) {
+ partition1EndPoint = CGPointMake([PNLineChart xOfY:(CGFloat) fmax(p1.y, tRange.location)
+ betweenPoint1:p1
+ andPoint2:p2], (CGFloat) fmax(p1.y, tRange.location));
+ partition2EndPoint = CGPointMake([PNLineChart xOfY:(CGFloat) fmin(p2.y, tRange.location + tRange.length)
+ betweenPoint1:p1
+ andPoint2:p2], (CGFloat) fmin(p2.y, tRange.location + tRange.length));
+ } else {
+ partition1EndPoint = CGPointMake([PNLineChart xOfY:(CGFloat) fmin(p1.y, tRange.location + tRange.length)
+ betweenPoint1:p1
+ andPoint2:p2], (CGFloat) fmin(p1.y, tRange.location + tRange.length));
+ partition2EndPoint = CGPointMake([PNLineChart xOfY:(CGFloat) fmax(p2.y, tRange.location)
+ betweenPoint1:p1
+ andPoint2:p2], (CGFloat) fmax(p2.y, tRange.location));
+ }
+ if (p1.y != partition1EndPoint.y) {
+ partition1 = [self colorRangesBetweenP1:p1
+ P2:partition1EndPoint
+ rangeColors:remainingRanges
+ defaultColor:defaultColor];
+ }
+ partition2 = @{
+ @"color": colorForRangeInfo.color,
+ @"from": [NSValue valueWithCGPoint:partition1EndPoint],
+ @"to": [NSValue valueWithCGPoint:partition2EndPoint]};
+ if (p2.y != partition2EndPoint.y) {
+ partition3 = [self colorRangesBetweenP1:partition2EndPoint
+ P2:p2
+ rangeColors:remainingRanges
+ defaultColor:defaultColor];
+ }
+ return [[partition1 arrayByAddingObject:partition2] arrayByAddingObjectsFromArray:partition3];
+ } else {
+
+ return [self colorRangesBetweenP1:p1
+ P2:p2
+ rangeColors:remainingRanges
+ defaultColor:defaultColor];
+ }
+ } else {
+ return @[@{
+ @"color": defaultColor,
+ @"from": [NSValue valueWithCGPoint:p1],
+ @"to": [NSValue valueWithCGPoint:p2]}];
+ }
+}
+
+
+- (void)setupDefaultValues {
+ [super setupDefaultValues];
+ // Initialization code
+ self.backgroundColor = [UIColor whiteColor];
+ self.clipsToBounds = YES;
+ self.chartLineArray = [NSMutableArray new];
+ _showLabel = YES;
+ _showGenYLabels = YES;
+ _pathPoints = [[NSMutableArray alloc] init];
+ _endPointsOfPath = [[NSMutableArray alloc] init];
+ self.userInteractionEnabled = YES;
+
+ _yFixedValueMin = -FLT_MAX;
+ _yFixedValueMax = -FLT_MAX;
+ _yValueMax = -FLT_MAX;
+ _yValueMin = -FLT_MAX;
+ _yLabelNum = 5;
+ _yLabelHeight = [[[[PNChartLabel alloc] init] font] pointSize];
+
+// _chartMargin = 40;
+
+ _chartMarginLeft = 25.0;
+ _chartMarginRight = 25.0;
+ _chartMarginTop = 25.0;
+ _chartMarginBottom = 25.0;
+
+ _yLabelFormat = @"%1.f";
+
+ _chartCavanWidth = self.frame.size.width - _chartMarginLeft - _chartMarginRight;
+ _chartCavanHeight = self.frame.size.height - _chartMarginBottom - _chartMarginTop;
+
+ // Coordinate Axis Default Values
+ _showCoordinateAxis = NO;
+ _axisColor = [UIColor colorWithRed:0.4f green:0.4f blue:0.4f alpha:1.f];
+ _axisWidth = 1.f;
+
+ // do not create curved line chart by default
+ _showSmoothLines = NO;
+
+}
+
+#pragma mark - tools
+
++ (CGSize)sizeOfString:(NSString *)text withWidth:(float)width font:(UIFont *)font {
+ CGSize size = CGSizeMake(width, MAXFLOAT);
+
+ if ([text respondsToSelector:@selector(boundingRectWithSize:options:attributes:context:)]) {
+ NSDictionary *tdic = @{NSFontAttributeName: font};
+ size = [text boundingRectWithSize:size
+ options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading
+ attributes:tdic
+ context:nil].size;
+ } else {
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+ size = [text sizeWithFont:font constrainedToSize:size lineBreakMode:NSLineBreakByCharWrapping];
+#pragma clang diagnostic pop
+ }
+
+ return size;
+}
+
++ (CGPoint)midPointBetweenPoint1:(CGPoint)point1 andPoint2:(CGPoint)point2 {
+ return CGPointMake((point1.x + point2.x) / 2, (point1.y + point2.y) / 2);
+}
+
++ (CGFloat)xOfY:(CGFloat)y betweenPoint1:(CGPoint)point1 andPoint2:(CGPoint)point2 {
+ CGFloat m = (point2.y - point1.y) / (point2.x - point1.x);
+ // formulate = y - y1 = m (x - x1) = mx - mx1 -> mx = y - y1 + mx1 ->
+ // x = (y - y1 + mx1) / m
+ return (y - point1.y + m * point1.x) / m;
+}
+
+
++ (CGPoint)controlPointBetweenPoint1:(CGPoint)point1 andPoint2:(CGPoint)point2 {
+ CGPoint controlPoint = [self midPointBetweenPoint1:point1 andPoint2:point2];
+ CGFloat diffY = abs((int) (point2.y - controlPoint.y));
+ if (point1.y < point2.y)
+ controlPoint.y += diffY;
+ else if (point1.y > point2.y)
+ controlPoint.y -= diffY;
+ return controlPoint;
+}
+
+- (void)drawTextInContext:(CGContextRef)ctx text:(NSString *)text inRect:(CGRect)rect font:(UIFont *)font color:(UIColor *)color {
+ if (IOS7_OR_LATER) {
+ NSMutableParagraphStyle *priceParagraphStyle = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
+ priceParagraphStyle.lineBreakMode = NSLineBreakByTruncatingTail;
+ priceParagraphStyle.alignment = NSTextAlignmentLeft;
+
+ if (color != nil) {
+ [text drawInRect:rect
+ withAttributes:@{NSParagraphStyleAttributeName: priceParagraphStyle, NSFontAttributeName: font,
+ NSForegroundColorAttributeName: color}];
+ } else {
+ [text drawInRect:rect
+ withAttributes:@{NSParagraphStyleAttributeName: priceParagraphStyle, NSFontAttributeName: font}];
+ }
+ } else {
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+ [text drawInRect:rect
+ withFont:font
+ lineBreakMode:NSLineBreakByTruncatingTail
+ alignment:NSTextAlignmentLeft];
+#pragma clang diagnostic pop
+ }
+}
+
+- (NSString *)formatYLabel:(double)value {
+
+ if (self.yLabelBlockFormatter) {
+ return self.yLabelBlockFormatter((CGFloat) value);
+ } else {
+ if (!self.thousandsSeparator) {
+ NSString *format = self.yLabelFormat ?: @"%1.f";
+ return [NSString stringWithFormat:format, value];
+ }
+
+ NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init];
+ [numberFormatter setFormatterBehavior:NSNumberFormatterBehavior10_4];
+ [numberFormatter setNumberStyle:NSNumberFormatterDecimalStyle];
+ return [numberFormatter stringFromNumber:@(value)];
+ }
+}
+
+- (UIView *)getLegendWithMaxWidth:(CGFloat)mWidth {
+ if ([self.chartData count] < 1) {
+ return nil;
+ }
+
+ /* This is a short line that refers to the chart data */
+ CGFloat legendLineWidth = 40;
+
+ /* x and y are the coordinates of the starting point of each legend item */
+ CGFloat x = 0;
+ CGFloat y = 0;
+
+ /* accumulated height */
+ CGFloat totalHeight = 0;
+ CGFloat totalWidth = 0;
+
+ NSMutableArray *legendViews = [[NSMutableArray alloc] init];
+
+ /* Determine the max width of each legend item */
+ CGFloat maxLabelWidth;
+ if (self.legendStyle == PNLegendItemStyleStacked) {
+ maxLabelWidth = mWidth - legendLineWidth;
+ } else {
+ maxLabelWidth = MAXFLOAT;
+ }
+
+ /* this is used when labels wrap text and the line
+ * should be in the middle of the first row */
+ CGFloat singleRowHeight = [PNLineChart sizeOfString:@"Test"
+ withWidth:MAXFLOAT
+ font:self.legendFont ? self.legendFont : [UIFont systemFontOfSize:12.0f]].height;
+
+ NSUInteger counter = 0;
+ NSUInteger rowWidth = 0;
+ NSUInteger rowMaxHeight = 0;
+
+ for (PNLineChartData *pdata in self.chartData) {
+ /* Expected label size*/
+ CGSize labelsize = [PNLineChart sizeOfString:pdata.dataTitle
+ withWidth:maxLabelWidth
+ font:self.legendFont ? self.legendFont : [UIFont systemFontOfSize:12.0f]];
+
+ /* draw lines */
+ if ((rowWidth + labelsize.width + legendLineWidth > mWidth) && (self.legendStyle == PNLegendItemStyleSerial)) {
+ rowWidth = 0;
+ x = 0;
+ y += rowMaxHeight;
+ rowMaxHeight = 0;
+ }
+ rowWidth += labelsize.width + legendLineWidth;
+ totalWidth = self.legendStyle == PNLegendItemStyleSerial ? fmaxf(rowWidth, totalWidth) : fmaxf(totalWidth, labelsize.width + legendLineWidth);
+
+ /* If there is inflection decorator, the line is composed of two lines
+ * and this is the space that separates two lines in order to put inflection
+ * decorator */
+
+ CGFloat inflexionWidthSpacer = pdata.inflexionPointStyle == PNLineChartPointStyleTriangle ? pdata.inflexionPointWidth / 2 : pdata.inflexionPointWidth;
+
+ CGFloat halfLineLength;
+
+ if (pdata.inflexionPointStyle != PNLineChartPointStyleNone) {
+ halfLineLength = (CGFloat) ((legendLineWidth * 0.8 - inflexionWidthSpacer) / 2);
+ } else {
+ halfLineLength = (CGFloat) (legendLineWidth * 0.8);
+ }
+
+ UIView *line = [[UIView alloc] initWithFrame:CGRectMake((CGFloat) (x + legendLineWidth * 0.1), y + (singleRowHeight - pdata.lineWidth) / 2, halfLineLength, pdata.lineWidth)];
+
+ line.backgroundColor = pdata.color;
+ line.alpha = pdata.alpha;
+ [legendViews addObject:line];
+
+ if (pdata.inflexionPointStyle != PNLineChartPointStyleNone) {
+ line = [[UIView alloc] initWithFrame:CGRectMake((CGFloat) (x + legendLineWidth * 0.1 + halfLineLength + inflexionWidthSpacer), y + (singleRowHeight - pdata.lineWidth) / 2, halfLineLength, pdata.lineWidth)];
+ line.backgroundColor = pdata.color;
+ line.alpha = pdata.alpha;
+ [legendViews addObject:line];
+ }
+
+ // Add inflexion type
+ UIColor *inflexionPointColor = pdata.inflexionPointColor;
+ if (!inflexionPointColor) {
+ inflexionPointColor = pdata.color;
+ }
+ [legendViews addObject:[self drawInflexion:pdata.inflexionPointWidth
+ center:CGPointMake(x + legendLineWidth / 2, y + singleRowHeight / 2)
+ strokeWidth:pdata.lineWidth
+ inflexionStyle:pdata.inflexionPointStyle
+ andColor:inflexionPointColor
+ andAlpha:pdata.alpha]];
+
+ UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(x + legendLineWidth, y, labelsize.width, labelsize.height)];
+ label.text = pdata.dataTitle;
+ label.textColor = self.legendFontColor ? self.legendFontColor : [UIColor blackColor];
+ label.font = self.legendFont ? self.legendFont : [UIFont systemFontOfSize:12.0f];
+ label.lineBreakMode = NSLineBreakByWordWrapping;
+ label.numberOfLines = 0;
+
+ rowMaxHeight = (NSUInteger) fmaxf(rowMaxHeight, labelsize.height);
+ x += self.legendStyle == PNLegendItemStyleStacked ? 0 : labelsize.width + legendLineWidth;
+ y += self.legendStyle == PNLegendItemStyleStacked ? labelsize.height : 0;
+
+
+ totalHeight = self.legendStyle == PNLegendItemStyleSerial ? fmaxf(totalHeight, rowMaxHeight + y) : totalHeight + labelsize.height;
+
+ [legendViews addObject:label];
+ counter++;
+ }
+
+ UIView *legend = [[UIView alloc] initWithFrame:CGRectMake(0, 0, mWidth, totalHeight)];
+
+ for (UIView *v in legendViews) {
+ [legend addSubview:v];
+ }
+ return legend;
+}
+
+
+- (UIImageView *)drawInflexion:(CGFloat)size center:(CGPoint)center strokeWidth:(CGFloat)sw inflexionStyle:(PNLineChartPointStyle)type andColor:(UIColor *)color andAlpha:(CGFloat)alfa {
+ //Make the size a little bigger so it includes also border stroke
+ CGSize aSize = CGSizeMake(size + sw, size + sw);
+
+
+ UIGraphicsBeginImageContextWithOptions(aSize, NO, 0.0);
+ CGContextRef context = UIGraphicsGetCurrentContext();
+
+
+ if (type == PNLineChartPointStyleCircle) {
+ CGContextAddArc(context, (size + sw) / 2, (size + sw) / 2, size / 2, 0, (CGFloat) (M_PI * 2), YES);
+ } else if (type == PNLineChartPointStyleSquare) {
+ CGContextAddRect(context, CGRectMake(sw / 2, sw / 2, size, size));
+ } else if (type == PNLineChartPointStyleTriangle) {
+ CGContextMoveToPoint(context, sw / 2, size + sw / 2);
+ CGContextAddLineToPoint(context, size + sw / 2, size + sw / 2);
+ CGContextAddLineToPoint(context, size / 2 + sw / 2, sw / 2);
+ CGContextAddLineToPoint(context, sw / 2, size + sw / 2);
+ CGContextClosePath(context);
+ }
+
+ //Set some stroke properties
+ CGContextSetLineWidth(context, sw);
+ CGContextSetAlpha(context, alfa);
+ CGContextSetStrokeColorWithColor(context, color.CGColor);
+
+ //Finally draw
+ CGContextDrawPath(context, kCGPathStroke);
+
+ //now get the image from the context
+ UIImage *squareImage = UIGraphicsGetImageFromCurrentImageContext();
+
+ UIGraphicsEndImageContext();
+
+ //// Translate origin
+ CGFloat originX = (CGFloat) (center.x - (size + sw) / 2.0);
+ CGFloat originY = (CGFloat) (center.y - (size + sw) / 2.0);
+
+ UIImageView *squareImageView = [[UIImageView alloc] initWithImage:squareImage];
+ [squareImageView setFrame:CGRectMake(originX, originY, size + sw, size + sw)];
+ return squareImageView;
+}
+
+#pragma mark setter and getter
+
+- (CATextLayer *)createPointLabelFor:(CGFloat)grade pointCenter:(CGPoint)pointCenter width:(CGFloat)width withChartData:(PNLineChartData *)chartData {
+ CATextLayer *textLayer = [[CATextLayer alloc] init];
+ [textLayer setAlignmentMode:kCAAlignmentCenter];
+ [textLayer setForegroundColor:[chartData.pointLabelColor CGColor]];
+ [textLayer setBackgroundColor:self.backgroundColor.CGColor];
+// [textLayer setBackgroundColor:[self.backgroundColor colorWithAlphaComponent:0.8].CGColor];
+// [textLayer setCornerRadius:(CGFloat) (textLayer.fontSize / 8.0)];
+
+ if (chartData.pointLabelFont != nil) {
+ [textLayer setFont:(__bridge CFTypeRef) (chartData.pointLabelFont)];
+ textLayer.fontSize = [chartData.pointLabelFont pointSize];
+ }
+
+ CGFloat textHeight = (CGFloat) (textLayer.fontSize * 1.1);
+ // FIXME: convert the grade to string and use its length instead of hardcoding 8
+ CGFloat textWidth = width * 8;
+ CGFloat textStartPosY;
+
+ textStartPosY = pointCenter.y - textLayer.fontSize;
+
+ [self.layer addSublayer:textLayer];
+
+ if (chartData.pointLabelFormat != nil) {
+ [textLayer setString:[[NSString alloc] initWithFormat:chartData.pointLabelFormat, grade]];
+ } else {
+ [textLayer setString:[[NSString alloc] initWithFormat:_yLabelFormat, grade]];
+ }
+
+ [textLayer setFrame:CGRectMake(0, 0, textWidth, textHeight)];
+ [textLayer setPosition:CGPointMake(pointCenter.x, textStartPosY)];
+ textLayer.contentsScale = [UIScreen mainScreen].scale;
+
+ return textLayer;
+}
+
+- (CABasicAnimation *)fadeAnimation {
+ CABasicAnimation *fadeAnimation = nil;
+ if (self.displayAnimated) {
+ fadeAnimation = [CABasicAnimation animationWithKeyPath:@"opacity"];
+ fadeAnimation.fromValue = @0.0F;
+ fadeAnimation.toValue = @1.0F;
+ fadeAnimation.duration = 2.0;
+ }
+ return fadeAnimation;
+}
+
+- (CABasicAnimation *)pathAnimation {
+ if (self.displayAnimated && !_pathAnimation) {
+ _pathAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
+ _pathAnimation.duration = 1.0;
+ _pathAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
+ _pathAnimation.fromValue = @0.0f;
+ _pathAnimation.toValue = @1.0f;
+ }
+ if(!self.displayAnimated) {
+ _pathAnimation = nil;
+ }
+ return _pathAnimation;
+}
+
+@end
diff --git a/PNChartdemo/PNChart/PNLineChartData.h b/PNChartdemo/PNChart/PNLineChartData.h
new file mode 100755
index 0000000..2158e8e
--- /dev/null
+++ b/PNChartdemo/PNChart/PNLineChartData.h
@@ -0,0 +1,61 @@
+//
+// Created by J��rg Polakowski on 14/12/13.
+// Copyright (c) 2013 kevinzhow. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+#import <UIKit/UIKit.h>
+
+typedef NS_ENUM(NSUInteger, PNLineChartPointStyle) {
+ PNLineChartPointStyleNone = 0,
+ PNLineChartPointStyleCircle = 1,
+ PNLineChartPointStyleSquare = 3,
+ PNLineChartPointStyleTriangle = 4
+};
+
+@class PNLineChartDataItem;
+
+typedef PNLineChartDataItem *(^LCLineChartDataGetter)(NSUInteger item);
+
+@interface PNLineChartColorRange : NSObject<NSCopying>
+
+@property(nonatomic) NSRange range;
+@property(nonatomic) BOOL inclusive;
+@property(nonatomic, retain) UIColor *color;
+
+- (id)initWithRange:(NSRange)range color:(UIColor *)color;
+
+@end
+
+@interface PNLineChartData : NSObject
+
+@property (strong) UIColor *color;
+@property (nonatomic) CGFloat alpha;
+@property NSUInteger itemCount;
+@property (copy) LCLineChartDataGetter getData;
+@property (strong, nonatomic) NSString *dataTitle;
+
+@property (nonatomic) BOOL showPointLabel;
+@property (nonatomic) UIColor *pointLabelColor;
+@property (nonatomic) UIFont *pointLabelFont;
+@property (nonatomic) NSString *pointLabelFormat;
+
+@property (nonatomic, assign) PNLineChartPointStyle inflexionPointStyle;
+@property (nonatomic) UIColor *inflexionPointColor;
+
+/**
+ * if rangeColor is set and the lineChartData values are within any
+ * of the given range then use the rangeColor.color otherwise use
+ * self.color for the rest of the graph
+ */
+@property(strong) NSArray<PNLineChartColorRange *> *rangeColors;
+
+/**
+ * If PNLineChartPointStyle is circle, this returns the circle's diameter.
+ * If PNLineChartPointStyle is square, each point is a square with each side equal in length to this value.
+ */
+@property (nonatomic, assign) CGFloat inflexionPointWidth;
+
+@property (nonatomic, assign) CGFloat lineWidth;
+
+@end
diff --git a/PNChartdemo/PNChart/PNLineChartData.m b/PNChartdemo/PNChart/PNLineChartData.m
new file mode 100755
index 0000000..bbf2647
--- /dev/null
+++ b/PNChartdemo/PNChart/PNLineChartData.m
@@ -0,0 +1,54 @@
+//
+// Created by J��rg Polakowski on 14/12/13.
+// Copyright (c) 2013 kevinzhow. All rights reserved.
+//
+
+#import "PNLineChartData.h"
+
+
+@implementation PNLineChartColorRange
+
+- (id)initWithRange:(NSRange)range color:(UIColor *)color {
+ self = [super init];
+ if (self) {
+ self.range = range;
+ self.color = color;
+ }
+ return self;
+}
+
+
+- (id)copyWithZone:(NSZone *)zone {
+ PNLineChartColorRange *copy = [[self class] allocWithZone:zone];
+ copy.color = self.color;
+ copy.range = self.range;
+ return copy;
+}
+
+@end
+
+@implementation PNLineChartData
+
+- (id)init
+{
+ self = [super init];
+ if (self) {
+ [self setupDefaultValues];
+ }
+
+ return self;
+}
+
+- (void)setupDefaultValues
+{
+ _inflexionPointStyle = PNLineChartPointStyleNone;
+ _inflexionPointWidth = 6.f;
+ _lineWidth = 2.f;
+ _alpha = 1.f;
+ _showPointLabel = NO;
+ _pointLabelColor = [UIColor blackColor];
+ _pointLabelFormat = @"%1.f";
+ _rangeColors = nil;
+}
+
+@end
diff --git a/PNChartdemo/PNChart/PNLineChartDataItem.h b/PNChartdemo/PNChart/PNLineChartDataItem.h
new file mode 100755
index 0000000..ad2d23d
--- /dev/null
+++ b/PNChartdemo/PNChart/PNLineChartDataItem.h
@@ -0,0 +1,17 @@
+//
+// Created by J��rg Polakowski on 14/12/13.
+// Copyright (c) 2013 kevinzhow. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+#import <UIKit/UIKit.h>
+
+@interface PNLineChartDataItem : NSObject
+
++ (PNLineChartDataItem *)dataItemWithY:(CGFloat)y;
++ (PNLineChartDataItem *)dataItemWithY:(CGFloat)y andRawY:(CGFloat)rawY;
+
+@property (readonly) CGFloat y; // should be within the y range
+@property (readonly) CGFloat rawY; // this is the raw value, used for point label.
+
+@end
diff --git a/PNChartdemo/PNChart/PNLineChartDataItem.m b/PNChartdemo/PNChart/PNLineChartDataItem.m
new file mode 100755
index 0000000..1beea91
--- /dev/null
+++ b/PNChartdemo/PNChart/PNLineChartDataItem.m
@@ -0,0 +1,38 @@
+//
+// Created by J��rg Polakowski on 14/12/13.
+// Copyright (c) 2013 kevinzhow. All rights reserved.
+//
+
+#import "PNLineChartDataItem.h"
+
+@interface PNLineChartDataItem ()
+
+- (id)initWithY:(CGFloat)y andRawY:(CGFloat)rawY;
+
+@property (readwrite) CGFloat y; // should be within the y range
+@property (readwrite) CGFloat rawY; // this is the raw value, used for point label.
+
+@end
+
+@implementation PNLineChartDataItem
+
++ (PNLineChartDataItem *)dataItemWithY:(CGFloat)y
+{
+ return [[PNLineChartDataItem alloc] initWithY:y andRawY:y];
+}
+
++ (PNLineChartDataItem *)dataItemWithY:(CGFloat)y andRawY:(CGFloat)rawY {
+ return [[PNLineChartDataItem alloc] initWithY:y andRawY:rawY];
+}
+
+- (id)initWithY:(CGFloat)y andRawY:(CGFloat)rawY
+{
+ if ((self = [super init])) {
+ self.y = y;
+ self.rawY = rawY;
+ }
+
+ return self;
+}
+
+@end
diff --git a/PNChartdemo/PNChart/PNPieChart.h b/PNChartdemo/PNChart/PNPieChart.h
new file mode 100755
index 0000000..204afb5
--- /dev/null
+++ b/PNChartdemo/PNChart/PNPieChart.h
@@ -0,0 +1,68 @@
+//
+// 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"
+#import "PNGenericChart.h"
+#import "PNChartDelegate.h"
+
+@interface PNPieChart : PNGenericChart
+
+- (id)initWithFrame:(CGRect)frame items:(NSArray *)items;
+
+@property (nonatomic, readonly) NSArray *items;
+
+/** Default is 18-point Avenir Medium. */
+@property (nonatomic) UIFont *descriptionTextFont;
+
+/** Default is white. */
+@property (nonatomic) UIColor *descriptionTextColor;
+
+/** Default is black, with an alpha of 0.4. */
+@property (nonatomic) UIColor *descriptionTextShadowColor;
+
+/** Default is CGSizeMake(0, 1). */
+@property (nonatomic) CGSize descriptionTextShadowOffset;
+
+/** Default is 1.0. */
+@property (nonatomic) NSTimeInterval duration;
+
+/** Show only values, this is useful when legend is present */
+@property (nonatomic) BOOL showOnlyValues;
+
+/** Show absolute values not relative i.e. percentages */
+@property (nonatomic) BOOL showAbsoluteValues;
+
+/** Hide percentage labels less than cutoff value */
+@property (nonatomic, assign) CGFloat labelPercentageCutoff;
+
+/** Default YES. */
+@property (nonatomic) BOOL shouldHighlightSectorOnTouch;
+
+/** Current outer radius. Override recompute() to change this. **/
+@property (nonatomic) CGFloat outerCircleRadius;
+
+/** Current inner radius. Override recompute() to change this. **/
+@property (nonatomic) CGFloat innerCircleRadius;
+
+@property (nonatomic, weak) id<PNChartDelegate> delegate;
+
+/** Update chart items. Does not update chart itself. */
+- (void)updateChartData:(NSArray *)data;
+
+/** Multiple selection */
+@property (nonatomic, assign) BOOL enableMultipleSelection;
+
+/** show only tiles, not values or percentage */
+@property (nonatomic) BOOL hideValues;
+
+- (void)strokeChart;
+
+- (void)recompute;
+
+@end
diff --git a/PNChartdemo/PNChart/PNPieChart.m b/PNChartdemo/PNChart/PNPieChart.m
new file mode 100755
index 0000000..ae9ab7a
--- /dev/null
+++ b/PNChartdemo/PNChart/PNPieChart.m
@@ -0,0 +1,508 @@
+//
+// PNPieChart.m
+// PNChartDemo
+//
+// Created by Hang Zhang on 14-5-5.
+// Copyright (c) 2014��� kevinzhow. All rights reserved.
+//
+
+#import "PNPieChart.h"
+//needed for the expected label size
+#import "PNLineChart.h"
+
+@interface PNPieChart()
+
+@property (nonatomic) NSArray *items;
+@property (nonatomic) NSArray *endPercentages;
+
+@property (nonatomic) UIView *contentView;
+@property (nonatomic) CAShapeLayer *pieLayer;
+@property (nonatomic) NSMutableArray *descriptionLabels;
+@property (strong, nonatomic) CAShapeLayer *sectorHighlight;
+
+@property (nonatomic, strong) NSMutableDictionary *selectedItems;
+
+- (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
+ 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];
+ [self baseInit];
+ }
+
+ return self;
+}
+
+- (void)awakeFromNib{
+ [super awakeFromNib];
+ [self baseInit];
+}
+
+- (void)baseInit{
+ _selectedItems = [NSMutableDictionary dictionary];
+ //������������������,���������������������������������������������,������������������,���������������,���������������view���������,���������������������������������
+
+ CGFloat minimal = (CGRectGetWidth(self.bounds) < CGRectGetHeight(self.bounds)) ? CGRectGetWidth(self.bounds) : CGRectGetHeight(self.bounds);
+
+ _outerCircleRadius = minimal / 2;
+ _innerCircleRadius = minimal / 6;
+// _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;
+ _shouldHighlightSectorOnTouch = YES;
+ _enableMultipleSelection = NO;
+ _hideValues = NO;
+
+ [super setupDefaultValues];
+ [self loadDefault];
+}
+
+- (void)loadDefault{
+ __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];
+
+}
+
+/** Override this to change how inner attributes are computed. **/
+- (void)recompute {
+
+ //������
+ CGFloat minimal = (CGRectGetWidth(self.bounds) < CGRectGetHeight(self.bounds)) ? CGRectGetWidth(self.bounds) : CGRectGetHeight(self.bounds);
+ self.outerCircleRadius = minimal / 2;
+ self.innerCircleRadius = minimal / 6;
+}
+
+#pragma mark -
+
+- (void)strokeChart{
+ [self loadDefault];
+ [self recompute];
+
+ PNPieChartDataItem *currentItem;
+ for (int i = 0; i < _items.count; i++) {
+ currentItem = [self dataItemForIndex:i];
+
+
+ CGFloat startPercentage = [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:startPercentage
+ endPercentage:endPercentage];
+ [_pieLayer addSublayer:currentPieLayer];
+ }
+
+ [self maskChart];
+
+ for (int i = 0; i < _items.count; i++) {
+ UILabel *descriptionLabel = [self descriptionLabelForItemAtIndex:i];
+ [_contentView addSubview:descriptionLabel];
+ [_descriptionLabels addObject:descriptionLabel];
+ }
+
+ [self addAnimationIfNeeded];
+}
+
+- (UILabel *)descriptionLabelForItemAtIndex:(NSUInteger)index{
+ PNPieChartDataItem *currentDataItem = [self dataItemForIndex:index];
+ CGFloat distance = _innerCircleRadius + (_outerCircleRadius - _innerCircleRadius) / 2;
+ CGFloat centerPercentage = ([self startPercentageForItemAtIndex:index] + [self endPercentageForItemAtIndex:index])/ 2;
+ CGFloat rad = centerPercentage * 2 * M_PI;
+
+ UILabel *descriptionLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 100, 80)];
+ NSString *titleText = currentDataItem.textDescription;
+
+ NSString *titleValue;
+
+ if (self.showAbsoluteValues) {
+ titleValue = [NSString stringWithFormat:@"%.0f",currentDataItem.value];
+ }else{
+ titleValue = [NSString stringWithFormat:@"%.0f%%",[self ratioForItemAtIndex:index] * 100];
+ }
+
+ if (self.hideValues)
+ descriptionLabel.text = titleText;
+ else if(!titleText || self.showOnlyValues)
+ descriptionLabel.text = titleValue;
+ else {
+ NSString* str = [titleValue stringByAppendingString:[NSString stringWithFormat:@"\n%@",titleText]];
+ descriptionLabel.text = str ;
+ }
+
+ //If value is less than cutoff, show no label
+ if ([self ratioForItemAtIndex:index] < self.labelPercentageCutoff )
+ {
+ descriptionLabel.text = nil;
+ }
+
+ CGPoint center = CGPointMake(_outerCircleRadius + distance * sin(rad),
+ _outerCircleRadius - distance * cos(rad));
+
+ 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.backgroundColor = [UIColor clearColor];
+ return descriptionLabel;
+}
+
+- (void)updateChartData:(NSArray *)items {
+ self.items = items;
+}
+
+- (PNPieChartDataItem *)dataItemForIndex:(NSUInteger)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
+
+- (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{
+ 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;
+}
+
+- (void)addAnimationIfNeeded{
+ if (self.displayAnimated) {
+ 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;
+ [_pieLayer.mask addAnimation:animation forKey:@"circleAnimation"];
+ }
+ else {
+ // Add description labels since no animation is required
+ [_descriptionLabels enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
+ [obj setAlpha:1];
+ }];
+ }
+}
+
+- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag{
+ [_descriptionLabels enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
+ [UIView animateWithDuration:0.2 animations:^(){
+ [obj setAlpha:1];
+ }];
+ }];
+}
+
+- (void)didTouchAt:(CGPoint)touchLocation
+{
+ CGPoint circleCenter = CGPointMake(_contentView.bounds.size.width/2, _contentView.bounds.size.height/2);
+
+ CGFloat distanceFromCenter = sqrtf(powf((touchLocation.y - circleCenter.y),2) + powf((touchLocation.x - circleCenter.x),2));
+
+ if (distanceFromCenter < _innerCircleRadius) {
+ if ([self.delegate respondsToSelector:@selector(didUnselectPieItem)]) {
+ [self.delegate didUnselectPieItem];
+ }
+ [self.sectorHighlight removeFromSuperlayer];
+ return;
+ }
+
+ CGFloat percentage = [self findPercentageOfAngleInCircle:circleCenter fromPoint:touchLocation];
+ int index = 0;
+ while (percentage > [self endPercentageForItemAtIndex:index]) {
+ index ++;
+ }
+
+ if ([self.delegate respondsToSelector:@selector(userClickedOnPieIndexItem:)]) {
+ [self.delegate userClickedOnPieIndexItem:index];
+ }
+
+ if (self.shouldHighlightSectorOnTouch)
+ {
+ if (!self.enableMultipleSelection)
+ {
+ if (self.sectorHighlight)
+ [self.sectorHighlight removeFromSuperlayer];
+ }
+
+ PNPieChartDataItem *currentItem = [self dataItemForIndex:index];
+
+ CGFloat red,green,blue,alpha;
+ UIColor *old = currentItem.color;
+ [old getRed:&red green:&green blue:&blue alpha:&alpha];
+ alpha /= 2;
+ UIColor *newColor = [UIColor colorWithRed:red green:green blue:blue alpha:alpha];
+
+ CGFloat startPercentage = [self startPercentageForItemAtIndex:index];
+ CGFloat endPercentage = [self endPercentageForItemAtIndex:index];
+
+ self.sectorHighlight = [self newCircleLayerWithRadius:_outerCircleRadius + 5
+ borderWidth:10
+ fillColor:[UIColor clearColor]
+ borderColor:newColor
+ startPercentage:startPercentage
+ endPercentage:endPercentage];
+
+ if (self.enableMultipleSelection)
+ {
+ NSString *dictIndex = [NSString stringWithFormat:@"%d", index];
+ CAShapeLayer *indexShape = [self.selectedItems valueForKey:dictIndex];
+ if (indexShape)
+ {
+ [indexShape removeFromSuperlayer];
+ [self.selectedItems removeObjectForKey:dictIndex];
+ }
+ else
+ {
+ [self.selectedItems setObject:self.sectorHighlight forKey:dictIndex];
+ [_contentView.layer addSublayer:self.sectorHighlight];
+ }
+ }
+ else
+ {
+ [_contentView.layer addSublayer:self.sectorHighlight];
+ }
+ }
+}
+
+- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
+{
+ for (UITouch *touch in touches) {
+ CGPoint touchLocation = [touch locationInView:_contentView];
+ [self didTouchAt:touchLocation];
+ }
+}
+
+- (CGFloat) findPercentageOfAngleInCircle:(CGPoint)center fromPoint:(CGPoint)reference{
+ //Find angle of line Passing In Reference And Center
+ CGFloat angleOfLine = atanf((reference.y - center.y) / (reference.x - center.x));
+ CGFloat percentage = (angleOfLine + M_PI/2)/(2 * M_PI);
+ return (reference.x - center.x) > 0 ? percentage : percentage + .5;
+}
+
+- (UIView*) getLegendWithMaxWidth:(CGFloat)mWidth{
+ if ([self.items count] < 1) {
+ return nil;
+ }
+
+ /* This is a small circle that refers to the chart data */
+ CGFloat legendCircle = 16;
+
+ CGFloat hSpacing = 0;
+
+ CGFloat beforeLabel = legendCircle + hSpacing;
+
+ /* x and y are the coordinates of the starting point of each legend item */
+ CGFloat x = 0;
+ CGFloat y = 0;
+
+ /* accumulated width and height */
+ CGFloat totalWidth = 0;
+ CGFloat totalHeight = 0;
+
+ NSMutableArray *legendViews = [[NSMutableArray alloc] init];
+
+ /* Determine the max width of each legend item */
+ CGFloat maxLabelWidth;
+ if (self.legendStyle == PNLegendItemStyleStacked) {
+ maxLabelWidth = mWidth - beforeLabel;
+ }else{
+ maxLabelWidth = MAXFLOAT;
+ }
+
+ /* this is used when labels wrap text and the line
+ * should be in the middle of the first row */
+ CGFloat singleRowHeight = [PNLineChart sizeOfString:@"Test"
+ withWidth:MAXFLOAT
+ font:self.legendFont ? self.legendFont : [UIFont systemFontOfSize:12.0f]].height;
+
+ NSUInteger counter = 0;
+ NSUInteger rowWidth = 0;
+ NSUInteger rowMaxHeight = 0;
+
+ for (PNPieChartDataItem *pdata in self.items) {
+ /* Expected label size*/
+ CGSize labelsize = [PNLineChart sizeOfString:pdata.textDescription
+ withWidth:maxLabelWidth
+ font:self.legendFont ? self.legendFont : [UIFont systemFontOfSize:12.0f]];
+
+ if ((rowWidth + labelsize.width + beforeLabel > mWidth)&&(self.legendStyle == PNLegendItemStyleSerial)) {
+ rowWidth = 0;
+ x = 0;
+ y += rowMaxHeight;
+ rowMaxHeight = 0;
+ }
+ rowWidth += labelsize.width + beforeLabel;
+ totalWidth = self.legendStyle == PNLegendItemStyleSerial ? fmaxf(rowWidth, totalWidth) : fmaxf(totalWidth, labelsize.width + beforeLabel);
+ // Add inflexion type
+ [legendViews addObject:[self drawInflexion:legendCircle * .6
+ center:CGPointMake(x + legendCircle / 2, y + singleRowHeight / 2)
+ andColor:pdata.color]];
+
+
+ UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(x + beforeLabel, y, labelsize.width, labelsize.height)];
+ label.text = pdata.textDescription;
+ label.textColor = self.legendFontColor ? self.legendFontColor : [UIColor blackColor];
+ label.font = self.legendFont ? self.legendFont : [UIFont systemFontOfSize:12.0f];
+ label.lineBreakMode = NSLineBreakByWordWrapping;
+ label.numberOfLines = 0;
+
+
+ rowMaxHeight = fmaxf(rowMaxHeight, labelsize.height);
+ x += self.legendStyle == PNLegendItemStyleStacked ? 0 : labelsize.width + beforeLabel;
+ y += self.legendStyle == PNLegendItemStyleStacked ? labelsize.height : 0;
+
+
+ totalHeight = self.legendStyle == PNLegendItemStyleSerial ? fmaxf(totalHeight, rowMaxHeight + y) : totalHeight + labelsize.height;
+ [legendViews addObject:label];
+ counter ++;
+ }
+
+ UIView *legend = [[UIView alloc] initWithFrame:CGRectMake(0, 0, totalWidth, totalHeight)];
+
+ for (UIView* v in legendViews) {
+ [legend addSubview:v];
+ }
+ return legend;
+}
+
+
+- (UIImageView*)drawInflexion:(CGFloat)size center:(CGPoint)center andColor:(UIColor*)color
+{
+ //Make the size a little bigger so it includes also border stroke
+ CGSize aSize = CGSizeMake(size, size);
+
+
+ UIGraphicsBeginImageContextWithOptions(aSize, NO, 0.0);
+ CGContextRef context = UIGraphicsGetCurrentContext();
+
+ CGContextAddArc(context, size/2, size/ 2, size/2, 0, M_PI*2, YES);
+
+
+ //Set some fill color
+ CGContextSetFillColorWithColor(context, color.CGColor);
+
+ //Finally draw
+ CGContextDrawPath(context, kCGPathFill);
+
+ //now get the image from the context
+ UIImage *squareImage = UIGraphicsGetImageFromCurrentImageContext();
+
+ UIGraphicsEndImageContext();
+
+ //// Translate origin
+ CGFloat originX = center.x - (size) / 2.0;
+ CGFloat originY = center.y - (size) / 2.0;
+
+ UIImageView *squareImageView = [[UIImageView alloc]initWithImage:squareImage];
+ [squareImageView setFrame:CGRectMake(originX, originY, size, size)];
+ return squareImageView;
+}
+
+/* Redraw the chart on autolayout */
+-(void)layoutSubviews {
+ [super layoutSubviews];
+ [self strokeChart];
+}
+
+@end
diff --git a/PNChartdemo/PNChart/PNPieChartDataItem.h b/PNChartdemo/PNChart/PNPieChartDataItem.h
new file mode 100755
index 0000000..08d48e9
--- /dev/null
+++ b/PNChartdemo/PNChart/PNPieChartDataItem.h
@@ -0,0 +1,25 @@
+//
+// PNPieChartDataItem.h
+// PNChartDemo
+//
+// Created by Hang Zhang on 14-5-5.
+// Copyright (c) 2014��� kevinzhow. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+#import <UIKit/UIKit.h>
+
+@interface PNPieChartDataItem : NSObject
+
++ (instancetype)dataItemWithValue:(CGFloat)value
+ color:(UIColor*)color;
+
++ (instancetype)dataItemWithValue:(CGFloat)value
+ color:(UIColor*)color
+ description:(NSString *)description;
+
+@property (nonatomic) CGFloat value;
+@property (nonatomic) UIColor *color;
+@property (nonatomic) NSString *textDescription;
+
+@end
diff --git a/PNChartdemo/PNChart/PNPieChartDataItem.m b/PNChartdemo/PNChart/PNPieChartDataItem.m
new file mode 100755
index 0000000..4bda818
--- /dev/null
+++ b/PNChartdemo/PNChart/PNPieChartDataItem.m
@@ -0,0 +1,38 @@
+//
+// PNPieChartDataItem.m
+// PNChartDemo
+//
+// Created by Hang Zhang on 14-5-5.
+// Copyright (c) 2014��� kevinzhow. All rights reserved.
+//
+
+#import "PNPieChartDataItem.h"
+#import <UIKit/UIKit.h>
+
+@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.textDescription = description;
+ return item;
+}
+
+- (void)setValue:(CGFloat)value{
+ NSAssert(value >= 0, @"value should >= 0");
+ if (value != _value){
+ _value = value;
+ }
+}
+
+@end
diff --git a/PNChartdemo/PNChart/PNRadarChart.h b/PNChartdemo/PNChart/PNRadarChart.h
new file mode 100755
index 0000000..87871d0
--- /dev/null
+++ b/PNChartdemo/PNChart/PNRadarChart.h
@@ -0,0 +1,52 @@
+//
+// PNRadarChart.h
+// PNChartDemo
+//
+// Created by Lei on 15/7/1.
+// Copyright (c) 2015��� kevinzhow. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+#import "PNGenericChart.h"
+#import "PNRadarChartDataItem.h"
+
+#define MAXCIRCLE 20
+
+typedef NS_ENUM(NSUInteger, PNRadarChartLabelStyle) {
+ PNRadarChartLabelStyleCircle = 0,
+ PNRadarChartLabelStyleHorizontal,
+ PNRadarChartLabelStyleHidden,
+};
+
+@interface PNRadarChart : PNGenericChart
+
+-(id)initWithFrame:(CGRect)frame items:(NSArray *)items valueDivider:(CGFloat)unitValue;
+/**
+ *Draws the chart in an animated fashion.
+ */
+-(void)strokeChart;
+
+/** Array of `RadarChartDataItem` objects, one for each corner. */
+@property (nonatomic) NSArray *chartData;
+/** The unit of this chart ,default is 1 */
+@property (nonatomic) CGFloat valueDivider;
+/** The maximum for the range of values to display on the chart */
+@property (nonatomic) CGFloat maxValue;
+/** Default is gray. */
+@property (nonatomic) UIColor *webColor;
+/** Default is green , with an alpha of 0.7 */
+@property (nonatomic) UIColor *plotColor;
+/** Default is black */
+@property (nonatomic) UIColor *fontColor;
+/** Default is orange */
+@property (nonatomic) UIColor *graduationColor;
+/** Default is 15 */
+@property (nonatomic) CGFloat fontSize;
+/** Controls the labels display style that around chart */
+@property (nonatomic, assign) PNRadarChartLabelStyle labelStyle;
+/** Tap the label will display detail value ,default is YES. */
+@property (nonatomic, assign) BOOL isLabelTouchable;
+/** is show graduation on the chart ,default is NO. */
+@property (nonatomic, assign) BOOL isShowGraduation;
+
+@end
diff --git a/PNChartdemo/PNChart/PNRadarChart.m b/PNChartdemo/PNChart/PNRadarChart.m
new file mode 100755
index 0000000..9dace2b
--- /dev/null
+++ b/PNChartdemo/PNChart/PNRadarChart.m
@@ -0,0 +1,373 @@
+//
+// PNRadarChart.m
+// PNChartDemo
+//
+// Created by Lei on 15/7/1.
+// Copyright (c) 2015��� kevinzhow. All rights reserved.
+//
+
+#import "PNRadarChart.h"
+
+@interface PNRadarChart()
+
+@property (nonatomic) CGFloat centerX;
+@property (nonatomic) CGFloat centerY;
+@property (nonatomic) NSMutableArray *pointsToWebArrayArray;
+@property (nonatomic) NSMutableArray *pointsToPlotArray;
+@property (nonatomic) UILabel *detailLabel;
+@property (nonatomic) CGFloat lengthUnit;
+@property (nonatomic) CAShapeLayer *chartPlot;
+
+@end
+
+
+@implementation PNRadarChart
+
+- (id)initWithFrame:(CGRect)frame items:(NSArray *)items valueDivider:(CGFloat)unitValue {
+ self=[super initWithFrame:frame];
+ if (self) {
+ self.backgroundColor = [UIColor clearColor];
+ self.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
+
+ //Public iVar
+ if ([items count]< 3)//At least three corners of A polygon ,If the count of items is less than 3 will add 3 default values
+ {
+ NSLog( @"At least three items!");
+ NSArray *defaultArray = @[[PNRadarChartDataItem dataItemWithValue:0 description:@"Default"],
+ [PNRadarChartDataItem dataItemWithValue:0 description:@"Default"],
+ [PNRadarChartDataItem dataItemWithValue:0 description:@"Default"],
+ ];
+ defaultArray = [defaultArray arrayByAddingObjectsFromArray:items];
+ _chartData = [NSArray arrayWithArray:defaultArray];
+ }else{
+ _chartData = [NSArray arrayWithArray:items];
+ }
+ _valueDivider = unitValue;
+ _maxValue = 1;
+ _webColor = [UIColor grayColor];
+ _plotColor = [UIColor colorWithRed:.4 green:.8 blue:.4 alpha:.7];
+ _fontColor = [UIColor blackColor];
+ _graduationColor = [UIColor orangeColor];
+ _fontSize = 15;
+ _labelStyle = PNRadarChartLabelStyleHorizontal;
+ _isLabelTouchable = YES;
+ _isShowGraduation = NO;
+
+ //Private iVar
+ _centerX = frame.size.width/2;
+ _centerY = frame.size.height/2;
+ _pointsToWebArrayArray = [NSMutableArray array];
+ _pointsToPlotArray = [NSMutableArray array];
+ _lengthUnit = 0;
+ _chartPlot = [CAShapeLayer layer];
+ _chartPlot.lineCap = kCALineCapButt;
+ _chartPlot.lineWidth = 1.0;
+ [self.layer addSublayer:_chartPlot];
+
+ [super setupDefaultValues];
+ //init detailLabel
+ _detailLabel = [[UILabel alloc] init];
+ _detailLabel.backgroundColor = [UIColor colorWithRed:.9 green:.9 blue:.1 alpha:.9];
+ _detailLabel.textAlignment = NSTextAlignmentCenter;
+ _detailLabel.textColor = [UIColor colorWithWhite:1 alpha:1];
+ _detailLabel.font = [UIFont systemFontOfSize:15];
+ [_detailLabel setHidden:YES];
+ [self addSubview:_detailLabel];
+
+ [self strokeChart];
+ }
+ return self;
+}
+
+#pragma mark - main
+- (void)calculateChartPoints {
+ [_pointsToPlotArray removeAllObjects];
+ [_pointsToWebArrayArray removeAllObjects];
+
+ //init Descriptions , Values and Angles.
+ NSMutableArray *descriptions = [NSMutableArray array];
+ NSMutableArray *values = [NSMutableArray array];
+ NSMutableArray *angles = [NSMutableArray array];
+ for (int i=0;i<_chartData.count;i++) {
+ PNRadarChartDataItem *item = (PNRadarChartDataItem *)[_chartData objectAtIndex:i];
+ [descriptions addObject:item.textDescription];
+ [values addObject:[NSNumber numberWithFloat:item.value]];
+ CGFloat angleValue = (float)i/(float)[_chartData count]*2*M_PI;
+ [angles addObject:[NSNumber numberWithFloat:angleValue]];
+ }
+
+ //calculate all the lengths
+ _maxValue = [self getMaxValueFromArray:values];
+ CGFloat margin = 0;
+ if (_labelStyle==PNRadarChartLabelStyleCircle) {
+ margin = MIN(_centerX , _centerY)*3/10;
+ }else if (_labelStyle==PNRadarChartLabelStyleHorizontal) {
+ margin = [self getMaxWidthLabelFromArray:descriptions withFontSize:_fontSize];
+ }
+ CGFloat maxLength = ceil(MIN(_centerX, _centerY) - margin);
+ int plotCircles = (_maxValue/_valueDivider);
+ if (plotCircles > MAXCIRCLE) {
+ NSLog(@"Circle number is higher than max");
+ plotCircles = MAXCIRCLE;
+ _valueDivider = _maxValue/plotCircles;
+ }
+ _lengthUnit = maxLength/plotCircles;
+ NSArray *lengthArray = [self getLengthArrayWithCircleNum:(int)plotCircles];
+
+ //get all the points and plot
+ for (NSNumber *lengthNumber in lengthArray) {
+ CGFloat length = [lengthNumber floatValue];
+ [_pointsToWebArrayArray addObject:[self getWebPointWithLength:length angleArray:angles]];
+ }
+ int section = 0;
+ for (id value in values) {
+ CGFloat valueFloat = [value floatValue];
+ if (valueFloat>_maxValue) {
+ NSString *reason = [NSString stringWithFormat:@"Value number is higher than max -value: %f - maxValue: %f",valueFloat,_maxValue];
+ @throw [NSException exceptionWithName:NSInvalidArgumentException reason:reason userInfo:nil];
+ return;
+ }
+
+ CGFloat length = valueFloat/_maxValue*maxLength;
+ CGFloat angle = [[angles objectAtIndex:section] floatValue];
+ CGFloat x = _centerX +length*cos(angle);
+ CGFloat y = _centerY +length*sin(angle);
+ NSValue* point = [NSValue valueWithCGPoint:CGPointMake(x, y)];
+ [_pointsToPlotArray addObject:point];
+ section++;
+ }
+ //set the labels
+ [self drawLabelWithMaxLength:maxLength labelArray:descriptions angleArray:angles];
+
+ }
+#pragma mark - Draw
+
+- (void)drawRect:(CGRect)rect {
+ // Drawing backgound
+ CGContextRef context = UIGraphicsGetCurrentContext();
+ CGContextClearRect(context, rect);
+ int section = 0;
+ //circles
+ for(NSArray *pointArray in _pointsToWebArrayArray){
+ //plot backgound
+ CGContextRef graphContext = UIGraphicsGetCurrentContext();
+ CGContextBeginPath(graphContext);
+ CGPoint beginPoint = [[pointArray objectAtIndex:0] CGPointValue];
+ CGContextMoveToPoint(graphContext, beginPoint.x, beginPoint.y);
+ for(NSValue* pointValue in pointArray){
+ CGPoint point = [pointValue CGPointValue];
+ CGContextAddLineToPoint(graphContext, point.x, point.y);
+ }
+ CGContextAddLineToPoint(graphContext, beginPoint.x, beginPoint.y);
+ CGContextSetStrokeColorWithColor(graphContext, _webColor.CGColor);
+ CGContextStrokePath(graphContext);
+
+ }
+ //cuts
+ NSArray *largestPointArray = [_pointsToWebArrayArray lastObject];
+ for (NSValue *pointValue in largestPointArray){
+ section++;
+ if (section==1&&_isShowGraduation)continue;
+
+ CGContextRef graphContext = UIGraphicsGetCurrentContext();
+ CGContextBeginPath(graphContext);
+ CGContextMoveToPoint(graphContext, _centerX, _centerY);
+ CGPoint point = [pointValue CGPointValue];
+ CGContextAddLineToPoint(graphContext, point.x, point.y);
+ CGContextSetStrokeColorWithColor(graphContext, _webColor.CGColor);
+ CGContextStrokePath(graphContext);
+ }
+
+
+}
+
+- (void)strokeChart {
+
+ [self calculateChartPoints];
+ [self setNeedsDisplay];
+ [_detailLabel setHidden:YES];
+
+ //Draw plot
+ [_chartPlot removeAllAnimations];
+ UIBezierPath *plotline = [UIBezierPath bezierPath];
+ CGPoint beginPoint = [[_pointsToPlotArray objectAtIndex:0] CGPointValue];
+ [plotline moveToPoint:CGPointMake(beginPoint.x, beginPoint.y)];
+ for(NSValue *pointValue in _pointsToPlotArray){
+ CGPoint point = [pointValue CGPointValue];
+ [plotline addLineToPoint:CGPointMake(point.x ,point.y)];
+
+ }
+ [plotline setLineWidth:1];
+ [plotline setLineCapStyle:kCGLineCapButt];
+
+ _chartPlot.path = plotline.CGPath;
+
+ _chartPlot.fillColor = _plotColor.CGColor;
+
+ [self addAnimationIfNeeded];
+ [self showGraduation];
+}
+
+#pragma mark - Helper
+
+- (void)drawLabelWithMaxLength:(CGFloat)maxLength labelArray:(NSArray *)labelArray angleArray:(NSArray *)angleArray {
+ //set labels
+ int labelTag = 121;
+ while (true) {
+ UIView *label = [self viewWithTag:labelTag];
+ if(!label)break;
+ [label removeFromSuperview];
+ }
+ int section = 0;
+ CGFloat labelLength = maxLength + maxLength/10;
+
+ for (NSString *labelString in labelArray) {
+ CGFloat angle = [[angleArray objectAtIndex:section] floatValue];
+ CGFloat x = _centerX + labelLength *cos(angle);
+ CGFloat y = _centerY + labelLength *sin(angle);
+
+ UILabel *label = [[UILabel alloc] init] ;
+ label.backgroundColor = [UIColor clearColor];
+ label.font = [UIFont systemFontOfSize:_fontSize];
+ label.text = labelString;
+ label.tag = labelTag;
+ CGSize detailSize = [labelString sizeWithAttributes:@{NSFontAttributeName:[UIFont systemFontOfSize:_fontSize]}];
+
+ switch (_labelStyle) {
+ case PNRadarChartLabelStyleCircle:
+ label.frame = CGRectMake(x-5*_fontSize/2, y-_fontSize/2, 5*_fontSize, _fontSize);
+ label.transform = CGAffineTransformMakeRotation(((float)section/[labelArray count])*(2*M_PI)+M_PI_2);
+ label.textAlignment = NSTextAlignmentCenter;
+
+ break;
+ case PNRadarChartLabelStyleHorizontal:
+ if (x<_centerX) {
+ label.frame = CGRectMake(x-detailSize.width, y-detailSize.height/2, detailSize.width, detailSize.height);
+ label.textAlignment = NSTextAlignmentRight;
+ }else{
+ label.frame = CGRectMake(x, y-detailSize.height/2, detailSize.width , detailSize.height);
+ label.textAlignment = NSTextAlignmentLeft;
+ }
+ break;
+ case PNRadarChartLabelStyleHidden:
+ [label setHidden:YES];
+ break;
+ default:
+ break;
+ }
+ [label sizeToFit];
+
+ label.userInteractionEnabled = YES;
+ UITapGestureRecognizer *tapLabelGesture = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(tapLabel:)];
+ [label addGestureRecognizer:tapLabelGesture];
+ [self addSubview:label];
+
+ section ++;
+ }
+
+}
+
+- (void)tapLabel:(UITapGestureRecognizer *)recognizer {
+ UILabel *label=(UILabel*)recognizer.view;
+ _detailLabel.frame = CGRectMake(label.frame.origin.x, label.frame.origin.y-30, 50, 25);
+ for (PNRadarChartDataItem *item in _chartData) {
+ if ([label.text isEqualToString:item.textDescription]) {
+ _detailLabel.text = [NSString stringWithFormat:@"%.2f", item.value];
+ break;
+ }
+ }
+ [_detailLabel setHidden:NO];
+
+}
+
+- (void)showGraduation {
+ int labelTag = 112;
+ while (true) {
+ UIView *label = [self viewWithTag:labelTag];
+ if(!label)break;
+ [label removeFromSuperview];
+ }
+ int section = 0;
+ for (NSArray *pointsArray in _pointsToWebArrayArray) {
+ section++;
+ CGPoint labelPoint = [[pointsArray objectAtIndex:0] CGPointValue];
+ UILabel *graduationLabel = [[UILabel alloc] initWithFrame:CGRectMake(labelPoint.x-_lengthUnit, labelPoint.y-_lengthUnit*5/8, _lengthUnit*5/8, _lengthUnit)];
+ graduationLabel.adjustsFontSizeToFitWidth = YES;
+ graduationLabel.tag = labelTag;
+ graduationLabel.font = [UIFont systemFontOfSize:ceil(_lengthUnit)];
+ graduationLabel.textColor = [UIColor orangeColor];
+ graduationLabel.text = [NSString stringWithFormat:@"%.0f",_valueDivider*section];
+ [self addSubview:graduationLabel];
+ if (_isShowGraduation) {
+ [graduationLabel setHidden:NO];
+ }else{
+ [graduationLabel setHidden:YES];}
+ }
+
+}
+
+- (NSArray *)getWebPointWithLength:(CGFloat)length angleArray:(NSArray *)angleArray {
+ NSMutableArray *pointArray = [NSMutableArray array];
+ for (NSNumber *angleNumber in angleArray) {
+ CGFloat angle = [angleNumber floatValue];
+ CGFloat x = _centerX + length*cos(angle);
+ CGFloat y = _centerY + length*sin(angle);
+ [pointArray addObject:[NSValue valueWithCGPoint:CGPointMake(x,y)]];
+ }
+ return pointArray;
+
+}
+
+- (NSArray *)getLengthArrayWithCircleNum:(int)plotCircles {
+ NSMutableArray *lengthArray = [NSMutableArray array];
+ CGFloat length = 0;
+ for (int i = 0; i < plotCircles; i++) {
+ length += _lengthUnit;
+ [lengthArray addObject:[NSNumber numberWithFloat:length]];
+ }
+ return lengthArray;
+}
+
+- (CGFloat)getMaxWidthLabelFromArray:(NSArray *)keyArray withFontSize:(CGFloat)size {
+ CGFloat maxWidth = 0;
+ for (NSString *str in keyArray) {
+ CGSize detailSize = [str sizeWithAttributes:@{NSFontAttributeName:[UIFont systemFontOfSize:_fontSize]}];
+ maxWidth = MAX(maxWidth, detailSize.width);
+ }
+ return maxWidth;
+}
+
+- (CGFloat)getMaxValueFromArray:(NSArray *)valueArray {
+ CGFloat max = _maxValue;
+ for (NSNumber *valueNum in valueArray) {
+ CGFloat valueFloat = [valueNum floatValue];
+ max = MAX(valueFloat, max);
+ }
+ return ceil(max);
+}
+
+- (void)addAnimationIfNeeded
+{
+ if (self.displayAnimated) {
+ CABasicAnimation *animateScale = [CABasicAnimation animationWithKeyPath:@"transform.scale"];
+ animateScale.fromValue = [NSNumber numberWithFloat:0.f];
+ animateScale.toValue = [NSNumber numberWithFloat:1.0f];
+
+ CABasicAnimation *animateMove = [CABasicAnimation animationWithKeyPath:@"position"];
+ animateMove.fromValue = [NSValue valueWithCGPoint:CGPointMake(_centerX, _centerY)];
+ animateMove.toValue = [NSValue valueWithCGPoint:CGPointMake(0, 0)];
+
+ CABasicAnimation *animateAlpha = [CABasicAnimation animationWithKeyPath:@"opacity"];
+ animateAlpha.fromValue = [NSNumber numberWithFloat:0.f];
+
+ CAAnimationGroup *aniGroup = [CAAnimationGroup animation];
+ aniGroup.duration = 1.f;
+ aniGroup.repeatCount = 1;
+ aniGroup.animations = [NSArray arrayWithObjects:animateScale,animateMove,animateAlpha, nil];
+ aniGroup.removedOnCompletion = YES;
+
+ [_chartPlot addAnimation:aniGroup forKey:nil];
+ }
+}
+
+@end
diff --git a/PNChartdemo/PNChart/PNRadarChartDataItem.h b/PNChartdemo/PNChart/PNRadarChartDataItem.h
new file mode 100755
index 0000000..e67429c
--- /dev/null
+++ b/PNChartdemo/PNChart/PNRadarChartDataItem.h
@@ -0,0 +1,19 @@
+//
+// PNRadarChartDataItem.h
+// PNChartDemo
+//
+// Created by Lei on 15/7/1.
+// Copyright (c) 2015��� kevinzhow. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+
+@interface PNRadarChartDataItem : NSObject
+
++ (instancetype)dataItemWithValue:(CGFloat)value
+ description:(NSString *)description;
+
+@property (nonatomic) CGFloat value;
+@property (nonatomic,copy) NSString *textDescription;
+
+@end
diff --git a/PNChartdemo/PNChart/PNRadarChartDataItem.m b/PNChartdemo/PNChart/PNRadarChartDataItem.m
new file mode 100755
index 0000000..218ef6e
--- /dev/null
+++ b/PNChartdemo/PNChart/PNRadarChartDataItem.m
@@ -0,0 +1,29 @@
+//
+// PNRadarChartDataItem.m
+// PNChartDemo
+//
+// Created by Lei on 15/7/1.
+// Copyright (c) 2015��� kevinzhow. All rights reserved.
+//
+
+#import "PNRadarChartDataItem.h"
+
+@implementation PNRadarChartDataItem
+
++ (instancetype)dataItemWithValue:(CGFloat)value
+ description:(NSString *)description {
+ PNRadarChartDataItem *item = [PNRadarChartDataItem new];
+ item.value = value;
+ item.textDescription = description;
+ return item;
+}
+
+- (void)setValue:(CGFloat)value {
+ if (value < 0) {
+ value = 0;
+ NSLog(@"Value value can not be negative");
+ }
+ _value = value;
+}
+
+@end
diff --git a/PNChartdemo/PNChart/PNScatterChart.h b/PNChartdemo/PNChart/PNScatterChart.h
new file mode 100755
index 0000000..aa4eab8
--- /dev/null
+++ b/PNChartdemo/PNChart/PNScatterChart.h
@@ -0,0 +1,69 @@
+//
+// PNScatterChart.h
+// PNChartDemo
+//
+// Created by Alireza Arabi on 12/4/14.
+// Copyright (c) 2014 kevinzhow. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+#import <QuartzCore/QuartzCore.h>
+#import "PNChartDelegate.h"
+#import "PNGenericChart.h"
+#import "PNScatterChartData.h"
+#import "PNScatterChartDataItem.h"
+
+@interface PNScatterChart : PNGenericChart
+
+@property (nonatomic, retain) id<PNChartDelegate> delegate;
+
+/** Array of `ScatterChartData` objects, one for each line. */
+@property (nonatomic) NSArray *chartData;
+
+/** Controls whether to show the coordinate axis. Default is NO. */
+@property (nonatomic, getter = isShowCoordinateAxis) BOOL showCoordinateAxis;
+@property (nonatomic) UIColor *axisColor;
+@property (nonatomic) CGFloat axisWidth;
+
+/** String formatter for float values in x-axis/y-axis labels. If not set, defaults to @"%1.f" */
+@property (nonatomic, strong) NSString *xLabelFormat;
+@property (nonatomic, strong) NSString *yLabelFormat;
+
+/** Default is true. */
+@property (nonatomic) BOOL showLabel;
+
+/** Default is 18-point Avenir Medium. */
+@property (nonatomic) UIFont *descriptionTextFont;
+
+/** Default is white. */
+@property (nonatomic) UIColor *descriptionTextColor;
+
+/** Default is black, with an alpha of 0.4. */
+@property (nonatomic) UIColor *descriptionTextShadowColor;
+
+/** Default is CGSizeMake(0, 1). */
+@property (nonatomic) CGSize descriptionTextShadowOffset;
+
+/** Default is 1.0. */
+@property (nonatomic) NSTimeInterval duration;
+
+@property (nonatomic) CGFloat AxisX_minValue;
+@property (nonatomic) CGFloat AxisX_maxValue;
+
+@property (nonatomic) CGFloat AxisY_minValue;
+@property (nonatomic) CGFloat AxisY_maxValue;
+
+- (void) setAxisXWithMinimumValue:(CGFloat)minVal andMaxValue:(CGFloat)maxVal toTicks:(int)numberOfTicks;
+- (void) setAxisYWithMinimumValue:(CGFloat)minVal andMaxValue:(CGFloat)maxVal toTicks:(int)numberOfTicks;
+- (void) setAxisXLabel:(NSArray *)array;
+- (void) setAxisYLabel:(NSArray *)array;
+- (void) setup;
+- (void) drawLineFromPoint : (CGPoint) startPoint ToPoint : (CGPoint) endPoint WithLineWith : (CGFloat) lineWidth AndWithColor : (UIColor*) color;
+
+/**
+ * Update Chart Value
+ */
+
+- (void)updateChartData:(NSArray *)data;
+
+@end
diff --git a/PNChartdemo/PNChart/PNScatterChart.m b/PNChartdemo/PNChart/PNScatterChart.m
new file mode 100755
index 0000000..a16cf85
--- /dev/null
+++ b/PNChartdemo/PNChart/PNScatterChart.m
@@ -0,0 +1,445 @@
+//
+// PNScatterChart.m
+// PNChartDemo
+//
+// Created by Alireza Arabi on 12/4/14.
+// Copyright (c) 2014 kevinzhow. All rights reserved.
+//
+
+#import "PNScatterChart.h"
+#import "PNColor.h"
+#import "PNChartLabel.h"
+#import "PNScatterChartData.h"
+#import "PNScatterChartDataItem.h"
+
+@interface PNScatterChart ()
+
+@property (nonatomic, weak) CAShapeLayer *pathLayer;
+@property (nonatomic, weak) NSMutableArray *verticalLineLayer;
+@property (nonatomic, weak) NSMutableArray *horizentalLinepathLayer;
+
+@property (nonatomic) CGPoint startPoint;
+
+@property (nonatomic) CGPoint startPointVectorX;
+@property (nonatomic) CGPoint endPointVecotrX;
+
+@property (nonatomic) CGPoint startPointVectorY;
+@property (nonatomic) CGPoint endPointVecotrY;
+
+@property (nonatomic) CGFloat vectorX_Steps;
+@property (nonatomic) CGFloat vectorY_Steps;
+
+@property (nonatomic) CGFloat vectorX_Size;
+@property (nonatomic) CGFloat vectorY_Size;
+
+@property (nonatomic) NSMutableArray *axisX_labels;
+@property (nonatomic) NSMutableArray *axisY_labels;
+
+@property (nonatomic) int AxisX_partNumber ;
+@property (nonatomic) int AxisY_partNumber ;
+
+@property (nonatomic) CGFloat AxisX_step ;
+@property (nonatomic) CGFloat AxisY_step ;
+
+@property (nonatomic) CGFloat AxisX_Margin;
+@property (nonatomic) CGFloat AxisY_Margin;
+
+@property (nonatomic) BOOL isForUpdate;
+
+@end
+
+
+@implementation PNScatterChart
+
+#pragma mark initialization
+
+- (id)initWithCoder:(NSCoder *)coder
+{
+ self = [super initWithCoder:coder];
+
+ if (self) {
+ [self setupDefaultValues];
+ }
+ return self;
+}
+
+- (id)initWithFrame:(CGRect)frame
+{
+ self = [super initWithFrame:frame];
+
+ if (self) {
+ [self setupDefaultValues];
+ }
+ return self;
+}
+
+- (void) setup
+{
+ [self vectorXSetup];
+ [self vectorYSetup];
+}
+
+- (void)setupDefaultValues
+{
+ [super setupDefaultValues];
+
+ // Initialization code
+ self.backgroundColor = [UIColor whiteColor];
+ self.clipsToBounds = YES;
+ _showLabel = YES;
+ _isForUpdate = NO;
+ self.userInteractionEnabled = YES;
+
+ // Coordinate Axis Default Values
+ _showCoordinateAxis = YES;
+ _axisColor = [UIColor colorWithRed:0.4f green:0.4f blue:0.4f alpha:1.f];
+ _axisWidth = 1.f;
+
+ // Initialization code
+ _AxisX_Margin = 30 ;
+ _AxisY_Margin = 30 ;
+
+// self.frame = CGRectMake((SCREEN_WIDTH - self.frame.size.width) / 2, 200, self.frame.size.width, self.frame.size.height) ;
+ self.backgroundColor = [UIColor clearColor];
+
+ _startPoint.y = self.frame.size.height - self.AxisY_Margin ;
+ _startPoint.x = self.AxisX_Margin ;
+
+ _axisX_labels = [NSMutableArray array];
+ _axisY_labels = [NSMutableArray array];
+
+ _descriptionTextColor = [UIColor blackColor];
+ _descriptionTextFont = [UIFont fontWithName:@"Avenir-Medium" size:9.0];
+ _descriptionTextShadowColor = [[UIColor blackColor] colorWithAlphaComponent:0.4];
+ _descriptionTextShadowOffset = CGSizeMake(0, 1);
+ _duration = 1.0;
+
+}
+
+#pragma mark calculating axis
+
+- (void) setAxisXWithMinimumValue:(CGFloat)minVal andMaxValue:(CGFloat)maxVal toTicks:(int)numberOfTicks
+{
+ _AxisX_minValue = minVal ;
+ _AxisX_maxValue = maxVal ;
+ _AxisX_partNumber = numberOfTicks - 1;
+ _AxisX_step = (float)((maxVal - minVal)/_AxisX_partNumber);
+
+ NSString *LabelFormat = self.xLabelFormat ? : @"%1.f";
+ CGFloat tempValue = minVal ;
+ UILabel *label = [[UILabel alloc] init];
+ label.text = [NSString stringWithFormat:LabelFormat,minVal] ;
+ [_axisX_labels addObject:label];
+ for (int i = 0 ; i < _AxisX_partNumber; i++) {
+ tempValue = tempValue + _AxisX_step;
+ UILabel *tempLabel = [[UILabel alloc] init];
+ tempLabel.text = [NSString stringWithFormat:LabelFormat,tempValue] ;
+ [_axisX_labels addObject:tempLabel];
+ }
+}
+
+- (void) setAxisYWithMinimumValue:(CGFloat)minVal andMaxValue:(CGFloat)maxVal toTicks:(int)numberOfTicks
+{
+ _AxisY_minValue = minVal ;
+ _AxisY_maxValue = maxVal ;
+ _AxisY_partNumber = numberOfTicks - 1;
+ _AxisY_step = (float)((maxVal - minVal)/_AxisY_partNumber);
+
+ NSString *LabelFormat = self.yLabelFormat ? : @"%1.f";
+ CGFloat tempValue = minVal ;
+ UILabel *label = [[UILabel alloc] init];
+ label.text = [NSString stringWithFormat:LabelFormat,minVal] ;
+ [_axisY_labels addObject:label];
+ for (int i = 0 ; i < _AxisY_partNumber; i++) {
+ tempValue = tempValue + _AxisY_step;
+ UILabel *tempLabel = [[UILabel alloc] init];
+ tempLabel.text = [NSString stringWithFormat:LabelFormat,tempValue] ;
+ [_axisY_labels addObject:tempLabel];
+ }
+}
+
+- (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];
+ for(int i=0;i<array.count;i++){
+ UILabel *label = [[UILabel alloc] init];
+ label.text = [array objectAtIndex:i];
+ [_axisX_labels addObject:label];
+ }
+ }
+}
+
+- (void)setAxisYLabel:(NSArray *)array {
+ if(array.count == ++_AxisY_partNumber){
+ [_axisY_labels removeAllObjects];
+ for(int i=0;i<array.count;i++){
+ UILabel *label = [[UILabel alloc] init];
+ label.text = [array objectAtIndex:i];
+ [_axisY_labels addObject:label];
+ }
+ }
+}
+
+- (void) vectorXSetup
+{
+ _AxisX_partNumber += 1;
+ _vectorX_Size = self.frame.size.width - (_AxisX_Margin) - 15 ;
+ _vectorX_Steps = (_vectorX_Size) / (_AxisX_partNumber) ;
+ _endPointVecotrX = CGPointMake(_startPoint.x + _vectorX_Size, _startPoint.y) ;
+ _startPointVectorX = _startPoint ;
+}
+
+- (void) vectorYSetup
+{
+ _AxisY_partNumber += 1;
+ _vectorY_Size = self.frame.size.height - (_AxisY_Margin) - 15;
+ _vectorY_Steps = (_vectorY_Size) / (_AxisY_partNumber);
+ _endPointVecotrY = CGPointMake(_startPoint.x, _startPoint.y - _vectorY_Size) ;
+ _startPointVectorY = _startPoint ;
+}
+
+- (void) showXLabel : (UILabel *) descriptionLabel InPosition : (CGPoint) point
+{
+ CGRect frame = CGRectMake(point.x, point.y, 30, 10);
+ descriptionLabel.frame = frame;
+ descriptionLabel.font = _descriptionTextFont;
+ descriptionLabel.textColor = _descriptionTextColor;
+ descriptionLabel.shadowColor = _descriptionTextShadowColor;
+ descriptionLabel.shadowOffset = _descriptionTextShadowOffset;
+ descriptionLabel.textAlignment = NSTextAlignmentCenter;
+ descriptionLabel.backgroundColor = [UIColor clearColor];
+ [self addSubview:descriptionLabel];
+}
+
+- (void)setChartData:(NSArray *)data
+{
+ __block CGFloat yFinilizeValue , xFinilizeValue;
+ __block CGFloat yValue , xValue;
+
+ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
+ if (self.displayAnimated) {
+ [NSThread sleepForTimeInterval:1];
+ }
+ // update UI on the main thread
+ dispatch_async(dispatch_get_main_queue(), ^{
+ for (PNScatterChartData *chartData in data) {
+ for (NSUInteger i = 0; i < chartData.itemCount; i++) {
+ yValue = chartData.getData(i).y;
+ xValue = chartData.getData(i).x;
+ if (!(xValue >= _AxisX_minValue && xValue <= _AxisX_maxValue) || !(yValue >= _AxisY_minValue && yValue <= _AxisY_maxValue)) {
+ NSLog(@"input is not in correct range.");
+ exit(0);
+ }
+ xFinilizeValue = [self mappingIsForAxisX:true WithValue:xValue];
+ yFinilizeValue = [self mappingIsForAxisX:false WithValue:yValue];
+ CAShapeLayer *shape = [self drawingPointsForChartData:chartData AndWithX:xFinilizeValue AndWithY:yFinilizeValue];
+ self.pathLayer = shape ;
+ [self.layer addSublayer:self.pathLayer];
+
+ [self addAnimationIfNeeded];
+ }
+ }
+ });
+ });
+}
+
+- (void)addAnimationIfNeeded{
+
+ if (self.displayAnimated) {
+ CABasicAnimation *pathAnimation = [CABasicAnimation animationWithKeyPath:@"opacity"];
+ pathAnimation.duration = _duration;
+ pathAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
+ pathAnimation.fromValue = @(0.0f);
+ pathAnimation.toValue = @(1.0f);
+ pathAnimation.fillMode = kCAFillModeForwards;
+ self.layer.opacity = 1;
+ [self.pathLayer addAnimation:pathAnimation forKey:@"fade"];
+ }
+}
+
+- (CGFloat) mappingIsForAxisX : (BOOL) isForAxisX WithValue : (CGFloat) value{
+
+ if (isForAxisX) {
+ float temp = _startPointVectorX.x + (_vectorX_Steps / 2) ;
+ CGFloat xPos = temp + (((value - _AxisX_minValue)/_AxisX_step) * _vectorX_Steps) ;
+ return xPos;
+ }
+ else {
+ float temp = _startPointVectorY.y - (_vectorY_Steps / 2) ;
+ CGFloat yPos = temp - (((value - _AxisY_minValue) /_AxisY_step) * _vectorY_Steps);
+ return yPos;
+ }
+ return 0;
+}
+
+#pragma mark - Update Chart Data
+
+- (void)updateChartData:(NSArray *)data
+{
+ _chartData = data;
+
+ // will be work in future.
+}
+
+#pragma drawing methods
+
+- (void)drawRect:(CGRect)rect
+{
+ [super drawRect:rect];
+
+ CGContextRef context = UIGraphicsGetCurrentContext();
+ if (_showCoordinateAxis) {
+ CGContextSetStrokeColorWithColor(context, [_axisColor CGColor]);
+ CGContextSetLineWidth(context, _axisWidth);
+ //drawing x vector
+ CGContextMoveToPoint(context, _startPoint.x, _startPoint.y);
+ CGContextAddLineToPoint(context, _endPointVecotrX.x, _endPointVecotrX.y);
+ //drawing y vector
+ CGContextMoveToPoint(context, _startPoint.x, _startPoint.y);
+ CGContextAddLineToPoint(context, _endPointVecotrY.x, _endPointVecotrY.y);
+ //drawing x arrow vector
+ CGContextMoveToPoint(context, _endPointVecotrX.x, _endPointVecotrX.y);
+ CGContextAddLineToPoint(context, _endPointVecotrX.x - 5, _endPointVecotrX.y + 3);
+ CGContextMoveToPoint(context, _endPointVecotrX.x, _endPointVecotrX.y);
+ CGContextAddLineToPoint(context, _endPointVecotrX.x - 5, _endPointVecotrX.y - 3);
+ //drawing y arrow vector
+ CGContextMoveToPoint(context, _endPointVecotrY.x, _endPointVecotrY.y);
+ CGContextAddLineToPoint(context, _endPointVecotrY.x - 3, _endPointVecotrY.y + 5);
+ CGContextMoveToPoint(context, _endPointVecotrY.x, _endPointVecotrY.y);
+ CGContextAddLineToPoint(context, _endPointVecotrY.x + 3, _endPointVecotrY.y + 5);
+ }
+
+ if (_showLabel) {
+ //drawing x steps vector and putting axis x labels
+ float temp = _startPointVectorX.x + (_vectorX_Steps / 2) ;
+ for (int i = 0; i < _axisX_labels.count; i++) {
+ UIBezierPath *path = [UIBezierPath bezierPath];
+ [path moveToPoint:CGPointMake(temp, _startPointVectorX.y - 2)];
+ [path addLineToPoint:CGPointMake(temp, _startPointVectorX.y + 3)];
+ CAShapeLayer *shapeLayer = [CAShapeLayer layer];
+ shapeLayer.path = [path CGPath];
+ shapeLayer.strokeColor = [_axisColor CGColor];
+ shapeLayer.lineWidth = _axisWidth;
+ shapeLayer.fillColor = [_axisColor CGColor];
+ [self.horizentalLinepathLayer addObject:shapeLayer];
+ [self.layer addSublayer:shapeLayer];
+ UILabel *lb = [_axisX_labels objectAtIndex:i] ;
+ [self showXLabel:lb InPosition:CGPointMake(temp - 15, _startPointVectorX.y + 10 )];
+ temp = temp + _vectorX_Steps ;
+ }
+ //drawing y steps vector and putting axis x labels
+ temp = _startPointVectorY.y - (_vectorY_Steps / 2) ;
+ for (int i = 0; i < _axisY_labels.count; i++) {
+ UIBezierPath *path = [UIBezierPath bezierPath];
+ [path moveToPoint:CGPointMake(_startPointVectorY.x - 3, temp)];
+ [path addLineToPoint:CGPointMake( _startPointVectorY.x + 2, temp)];
+ CAShapeLayer *shapeLayer = [CAShapeLayer layer];
+ shapeLayer.path = [path CGPath];
+ shapeLayer.strokeColor = [_axisColor CGColor];
+ shapeLayer.lineWidth = _axisWidth;
+ shapeLayer.fillColor = [_axisColor CGColor];
+ [self.verticalLineLayer addObject:shapeLayer];
+ [self.layer addSublayer:shapeLayer];
+ UILabel *lb = [_axisY_labels objectAtIndex:i];
+ [self showXLabel:lb InPosition:CGPointMake(_startPointVectorY.x - 30, temp - 5)];
+ temp = temp - _vectorY_Steps ;
+ }
+ }
+ CGContextDrawPath(context, kCGPathStroke);
+}
+
+- (CAShapeLayer*) drawingPointsForChartData : (PNScatterChartData *) chartData AndWithX : (CGFloat) X AndWithY : (CGFloat) Y
+{
+ if (chartData.inflexionPointStyle == PNScatterChartPointStyleCircle) {
+ float radius = chartData.size;
+ CAShapeLayer *circle = [CAShapeLayer layer];
+ // Make a circular shape
+ circle.path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(X - radius, Y - radius, 2.0*radius, 2.0*radius)
+ cornerRadius:radius].CGPath;
+ // Configure the appearence of the circle
+ circle.fillColor = [chartData.fillColor CGColor];
+ circle.strokeColor = [chartData.strokeColor CGColor];
+ circle.lineWidth = 1;
+
+ // Add to parent layer
+ return circle;
+ }
+ else if (chartData.inflexionPointStyle == PNScatterChartPointStyleSquare) {
+ float side = chartData.size;
+ CAShapeLayer *square = [CAShapeLayer layer];
+ // Make a circular shape
+ square.path = [UIBezierPath bezierPathWithRect:CGRectMake(X - (side/2) , Y - (side/2), side, side)].CGPath ;
+ // Configure the apperence of the circle
+ square.fillColor = [chartData.fillColor CGColor];
+ square.strokeColor = [chartData.strokeColor CGColor];
+ square.lineWidth = 1;
+
+ // Add to parent layer
+ return square;
+ }
+ else {
+ // you cann add your own scatter chart point here
+ }
+ return nil ;
+}
+
+- (void) drawLineFromPoint : (CGPoint) startPoint ToPoint : (CGPoint) endPoint WithLineWith : (CGFloat) lineWidth AndWithColor : (UIColor*) color{
+
+ // call the same method on a background thread
+ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
+ if (self.displayAnimated) {
+ [NSThread sleepForTimeInterval:2];
+ }
+ // calculating start and end point
+ __block CGFloat startX = [self mappingIsForAxisX:true WithValue:startPoint.x];
+ __block CGFloat startY = [self mappingIsForAxisX:false WithValue:startPoint.y];
+ __block CGFloat endX = [self mappingIsForAxisX:true WithValue:endPoint.x];
+ __block CGFloat endY = [self mappingIsForAxisX:false WithValue:endPoint.y];
+ // update UI on the main thread
+ dispatch_async(dispatch_get_main_queue(), ^{
+ // drawing path between two points
+ UIBezierPath *path = [UIBezierPath bezierPath];
+ [path moveToPoint:CGPointMake(startX, startY)];
+ [path addLineToPoint:CGPointMake(endX, endY)];
+ CAShapeLayer *shapeLayer = [CAShapeLayer layer];
+ shapeLayer.path = [path CGPath];
+ shapeLayer.strokeColor = [color CGColor];
+ shapeLayer.lineWidth = lineWidth;
+ shapeLayer.fillColor = [color CGColor];
+ // adding animation to path
+ [self addStrokeEndAnimationIfNeededToLayer:shapeLayer];
+ [self.layer addSublayer:shapeLayer];
+ });
+ });
+}
+
+- (void)addStrokeEndAnimationIfNeededToLayer:(CAShapeLayer *)shapeLayer{
+
+ if (self.displayAnimated) {
+ CABasicAnimation *animateStrokeEnd = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
+ animateStrokeEnd.duration = _duration;
+ animateStrokeEnd.fromValue = [NSNumber numberWithFloat:0.0f];
+ animateStrokeEnd.toValue = [NSNumber numberWithFloat:1.0f];
+ [shapeLayer addAnimation:animateStrokeEnd forKey:nil];
+ }
+}
+
+@end
diff --git a/PNChartdemo/PNChart/PNScatterChartData.h b/PNChartdemo/PNChart/PNScatterChartData.h
new file mode 100755
index 0000000..40b7b0e
--- /dev/null
+++ b/PNChartdemo/PNChart/PNScatterChartData.h
@@ -0,0 +1,38 @@
+//
+// PNScatterChartData.h
+// PNChartDemo
+//
+// Created by Alireza Arabi on 12/4/14.
+// Copyright (c) 2014 kevinzhow. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+#import <UIKit/UIKit.h>
+
+typedef NS_ENUM(NSUInteger, PNScatterChartPointStyle) {
+ PNScatterChartPointStyleCircle = 0,
+ PNScatterChartPointStyleSquare = 1,
+};
+
+@class PNScatterChartDataItem;
+
+typedef PNScatterChartDataItem *(^LCScatterChartDataGetter)(NSUInteger item);
+
+@interface PNScatterChartData : NSObject
+
+@property (strong) UIColor *fillColor;
+@property (strong) UIColor *strokeColor;
+
+@property NSUInteger itemCount;
+@property (copy) LCScatterChartDataGetter getData;
+
+@property (nonatomic, assign) PNScatterChartPointStyle inflexionPointStyle;
+
+/**
+ * If PNLineChartPointStyle is circle, this returns the circle's diameter.
+ * If PNLineChartPointStyle is square, each point is a square with each side equal in length to this value.
+ */
+@property (nonatomic, assign) CGFloat size;
+
+
+@end
diff --git a/PNChartdemo/PNChart/PNScatterChartData.m b/PNChartdemo/PNChart/PNScatterChartData.m
new file mode 100755
index 0000000..a53a5c2
--- /dev/null
+++ b/PNChartdemo/PNChart/PNScatterChartData.m
@@ -0,0 +1,31 @@
+//
+// PNScatterChartData.m
+// PNChartDemo
+//
+// Created by Alireza Arabi on 12/4/14.
+// Copyright (c) 2014 kevinzhow. All rights reserved.
+//
+
+#import "PNScatterChartData.h"
+
+@implementation PNScatterChartData
+
+- (id)init
+{
+ self = [super init];
+ if (self) {
+ [self setupDefaultValues];
+ }
+
+ return self;
+}
+
+- (void)setupDefaultValues
+{
+ _inflexionPointStyle = PNScatterChartPointStyleCircle;
+ _fillColor = [UIColor grayColor];
+ _strokeColor = [UIColor clearColor];
+ _size = 3 ;
+}
+
+@end
diff --git a/PNChartdemo/PNChart/PNScatterChartDataItem.h b/PNChartdemo/PNChart/PNScatterChartDataItem.h
new file mode 100755
index 0000000..f38ee4e
--- /dev/null
+++ b/PNChartdemo/PNChart/PNScatterChartDataItem.h
@@ -0,0 +1,19 @@
+//
+// PNScatterChartDataItem.h
+// PNChartDemo
+//
+// Created by Alireza Arabi on 12/4/14.
+// Copyright (c) 2014 kevinzhow. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+#import <UIKit/UIKit.h>
+
+@interface PNScatterChartDataItem : NSObject
+
++ (PNScatterChartDataItem *)dataItemWithX:(CGFloat)x AndWithY:(CGFloat)y;
+
+@property (readonly) CGFloat x; // should be within the x range
+@property (readonly) CGFloat y; // should be within the y range
+
+@end
diff --git a/PNChartdemo/PNChart/PNScatterChartDataItem.m b/PNChartdemo/PNChart/PNScatterChartDataItem.m
new file mode 100755
index 0000000..a454459
--- /dev/null
+++ b/PNChartdemo/PNChart/PNScatterChartDataItem.m
@@ -0,0 +1,37 @@
+//
+// PNScatterChartDataItem.m
+// PNChartDemo
+//
+// Created by Alireza Arabi on 12/4/14.
+// Copyright (c) 2014 kevinzhow. All rights reserved.
+//
+
+#import "PNScatterChartDataItem.h"
+
+@interface PNScatterChartDataItem ()
+
+- (id)initWithX:(CGFloat)x AndWithY:(CGFloat)y;
+
+@property (readwrite) CGFloat x; // should be within the x range
+@property (readwrite) CGFloat y; // should be within the y range
+
+@end
+
+@implementation PNScatterChartDataItem
+
++ (PNScatterChartDataItem *)dataItemWithX:(CGFloat)x AndWithY:(CGFloat)y
+{
+ return [[PNScatterChartDataItem alloc] initWithX:x AndWithY:y];
+}
+
+- (id)initWithX:(CGFloat)x AndWithY:(CGFloat)y
+{
+ if ((self = [super init])) {
+ self.x = x;
+ self.y = y;
+ }
+
+ return self;
+}
+
+@end
diff --git a/PNChartdemo/PNChartdemo.xcodeproj/project.pbxproj b/PNChartdemo/PNChartdemo.xcodeproj/project.pbxproj
new file mode 100644
index 0000000..651d89c
--- /dev/null
+++ b/PNChartdemo/PNChartdemo.xcodeproj/project.pbxproj
@@ -0,0 +1,479 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 46;
+ objects = {
+
+/* Begin PBXBuildFile section */
+ E56E9F2E1E68F54300412830 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = E56E9F2D1E68F54300412830 /* main.m */; };
+ E56E9F311E68F54300412830 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = E56E9F301E68F54300412830 /* AppDelegate.m */; };
+ E56E9F341E68F54300412830 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = E56E9F331E68F54300412830 /* ViewController.m */; };
+ E56E9F371E68F54300412830 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = E56E9F351E68F54300412830 /* Main.storyboard */; };
+ E56E9F391E68F54300412830 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = E56E9F381E68F54300412830 /* Assets.xcassets */; };
+ E56E9F3C1E68F54300412830 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = E56E9F3A1E68F54300412830 /* LaunchScreen.storyboard */; };
+ E56E9F661E68F55F00412830 /* PNBar.m in Sources */ = {isa = PBXBuildFile; fileRef = E56E9F451E68F55F00412830 /* PNBar.m */; };
+ E56E9F671E68F55F00412830 /* PNBarChart.m in Sources */ = {isa = PBXBuildFile; fileRef = E56E9F471E68F55F00412830 /* PNBarChart.m */; };
+ E56E9F681E68F55F00412830 /* PNChartLabel.m in Sources */ = {isa = PBXBuildFile; fileRef = E56E9F4B1E68F55F00412830 /* PNChartLabel.m */; };
+ E56E9F691E68F55F00412830 /* PNCircleChart.m in Sources */ = {isa = PBXBuildFile; fileRef = E56E9F4D1E68F55F00412830 /* PNCircleChart.m */; };
+ E56E9F6A1E68F55F00412830 /* PNColor.m in Sources */ = {isa = PBXBuildFile; fileRef = E56E9F4F1E68F55F00412830 /* PNColor.m */; };
+ E56E9F6B1E68F55F00412830 /* PNGenericChart.m in Sources */ = {isa = PBXBuildFile; fileRef = E56E9F511E68F55F00412830 /* PNGenericChart.m */; };
+ E56E9F6C1E68F55F00412830 /* PNLineChart.m in Sources */ = {isa = PBXBuildFile; fileRef = E56E9F531E68F55F00412830 /* PNLineChart.m */; };
+ E56E9F6D1E68F55F00412830 /* PNLineChartData.m in Sources */ = {isa = PBXBuildFile; fileRef = E56E9F551E68F55F00412830 /* PNLineChartData.m */; };
+ E56E9F6E1E68F55F00412830 /* PNLineChartDataItem.m in Sources */ = {isa = PBXBuildFile; fileRef = E56E9F571E68F55F00412830 /* PNLineChartDataItem.m */; };
+ E56E9F6F1E68F55F00412830 /* PNPieChart.m in Sources */ = {isa = PBXBuildFile; fileRef = E56E9F591E68F55F00412830 /* PNPieChart.m */; };
+ E56E9F701E68F55F00412830 /* PNPieChartDataItem.m in Sources */ = {isa = PBXBuildFile; fileRef = E56E9F5B1E68F55F00412830 /* PNPieChartDataItem.m */; };
+ E56E9F711E68F55F00412830 /* PNRadarChart.m in Sources */ = {isa = PBXBuildFile; fileRef = E56E9F5D1E68F55F00412830 /* PNRadarChart.m */; };
+ E56E9F721E68F55F00412830 /* PNRadarChartDataItem.m in Sources */ = {isa = PBXBuildFile; fileRef = E56E9F5F1E68F55F00412830 /* PNRadarChartDataItem.m */; };
+ E56E9F731E68F55F00412830 /* PNScatterChart.m in Sources */ = {isa = PBXBuildFile; fileRef = E56E9F611E68F55F00412830 /* PNScatterChart.m */; };
+ E56E9F741E68F55F00412830 /* PNScatterChartData.m in Sources */ = {isa = PBXBuildFile; fileRef = E56E9F631E68F55F00412830 /* PNScatterChartData.m */; };
+ E56E9F751E68F55F00412830 /* PNScatterChartDataItem.m in Sources */ = {isa = PBXBuildFile; fileRef = E56E9F651E68F55F00412830 /* PNScatterChartDataItem.m */; };
+ E56E9F781E68F59F00412830 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E56E9F771E68F59F00412830 /* CoreGraphics.framework */; };
+ E56E9F7A1E68F5A900412830 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E56E9F791E68F5A900412830 /* QuartzCore.framework */; };
+ E56E9F7C1E68F5B300412830 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E56E9F7B1E68F5B300412830 /* UIKit.framework */; };
+ E56E9F7E1E68F5B800412830 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E56E9F7D1E68F5B800412830 /* Foundation.framework */; };
+ E56E9F861E68F84700412830 /* UICountingLabel.m in Sources */ = {isa = PBXBuildFile; fileRef = E56E9F851E68F84700412830 /* UICountingLabel.m */; };
+ E56E9F891E68F89200412830 /* PCChartsTableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = E56E9F881E68F89200412830 /* PCChartsTableViewController.m */; };
+ E56E9F8C1E68F8F600412830 /* PCChartViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = E56E9F8B1E68F8F600412830 /* PCChartViewController.m */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXFileReference section */
+ E56E9F291E68F54300412830 /* PNChartdemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = PNChartdemo.app; sourceTree = BUILT_PRODUCTS_DIR; };
+ E56E9F2D1E68F54300412830 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
+ E56E9F2F1E68F54300412830 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
+ E56E9F301E68F54300412830 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
+ E56E9F321E68F54300412830 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = "<group>"; };
+ E56E9F331E68F54300412830 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = "<group>"; };
+ E56E9F361E68F54300412830 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
+ E56E9F381E68F54300412830 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
+ E56E9F3B1E68F54300412830 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
+ E56E9F3D1E68F54300412830 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
+ E56E9F441E68F55F00412830 /* PNBar.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PNBar.h; sourceTree = "<group>"; };
+ E56E9F451E68F55F00412830 /* PNBar.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PNBar.m; sourceTree = "<group>"; };
+ E56E9F461E68F55F00412830 /* PNBarChart.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PNBarChart.h; sourceTree = "<group>"; };
+ E56E9F471E68F55F00412830 /* PNBarChart.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PNBarChart.m; sourceTree = "<group>"; };
+ E56E9F481E68F55F00412830 /* PNChart.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PNChart.h; sourceTree = "<group>"; };
+ E56E9F491E68F55F00412830 /* PNChartDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PNChartDelegate.h; sourceTree = "<group>"; };
+ E56E9F4A1E68F55F00412830 /* PNChartLabel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PNChartLabel.h; sourceTree = "<group>"; };
+ E56E9F4B1E68F55F00412830 /* PNChartLabel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PNChartLabel.m; sourceTree = "<group>"; };
+ E56E9F4C1E68F55F00412830 /* PNCircleChart.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PNCircleChart.h; sourceTree = "<group>"; };
+ E56E9F4D1E68F55F00412830 /* PNCircleChart.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PNCircleChart.m; sourceTree = "<group>"; };
+ E56E9F4E1E68F55F00412830 /* PNColor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PNColor.h; sourceTree = "<group>"; };
+ E56E9F4F1E68F55F00412830 /* PNColor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PNColor.m; sourceTree = "<group>"; };
+ E56E9F501E68F55F00412830 /* PNGenericChart.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PNGenericChart.h; sourceTree = "<group>"; };
+ E56E9F511E68F55F00412830 /* PNGenericChart.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PNGenericChart.m; sourceTree = "<group>"; };
+ E56E9F521E68F55F00412830 /* PNLineChart.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PNLineChart.h; sourceTree = "<group>"; };
+ E56E9F531E68F55F00412830 /* PNLineChart.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PNLineChart.m; sourceTree = "<group>"; };
+ E56E9F541E68F55F00412830 /* PNLineChartData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PNLineChartData.h; sourceTree = "<group>"; };
+ E56E9F551E68F55F00412830 /* PNLineChartData.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PNLineChartData.m; sourceTree = "<group>"; };
+ E56E9F561E68F55F00412830 /* PNLineChartDataItem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PNLineChartDataItem.h; sourceTree = "<group>"; };
+ E56E9F571E68F55F00412830 /* PNLineChartDataItem.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PNLineChartDataItem.m; sourceTree = "<group>"; };
+ E56E9F581E68F55F00412830 /* PNPieChart.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PNPieChart.h; sourceTree = "<group>"; };
+ E56E9F591E68F55F00412830 /* PNPieChart.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PNPieChart.m; sourceTree = "<group>"; };
+ E56E9F5A1E68F55F00412830 /* PNPieChartDataItem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PNPieChartDataItem.h; sourceTree = "<group>"; };
+ E56E9F5B1E68F55F00412830 /* PNPieChartDataItem.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PNPieChartDataItem.m; sourceTree = "<group>"; };
+ E56E9F5C1E68F55F00412830 /* PNRadarChart.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PNRadarChart.h; sourceTree = "<group>"; };
+ E56E9F5D1E68F55F00412830 /* PNRadarChart.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PNRadarChart.m; sourceTree = "<group>"; };
+ E56E9F5E1E68F55F00412830 /* PNRadarChartDataItem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PNRadarChartDataItem.h; sourceTree = "<group>"; };
+ E56E9F5F1E68F55F00412830 /* PNRadarChartDataItem.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PNRadarChartDataItem.m; sourceTree = "<group>"; };
+ E56E9F601E68F55F00412830 /* PNScatterChart.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PNScatterChart.h; sourceTree = "<group>"; };
+ E56E9F611E68F55F00412830 /* PNScatterChart.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PNScatterChart.m; sourceTree = "<group>"; };
+ E56E9F621E68F55F00412830 /* PNScatterChartData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PNScatterChartData.h; sourceTree = "<group>"; };
+ E56E9F631E68F55F00412830 /* PNScatterChartData.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PNScatterChartData.m; sourceTree = "<group>"; };
+ E56E9F641E68F55F00412830 /* PNScatterChartDataItem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PNScatterChartDataItem.h; sourceTree = "<group>"; };
+ E56E9F651E68F55F00412830 /* PNScatterChartDataItem.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PNScatterChartDataItem.m; sourceTree = "<group>"; };
+ E56E9F771E68F59F00412830 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; };
+ E56E9F791E68F5A900412830 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; };
+ E56E9F7B1E68F5B300412830 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
+ E56E9F7D1E68F5B800412830 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
+ E56E9F7F1E68F64800412830 /* PNChartDemo-Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "PNChartDemo-Prefix.pch"; sourceTree = "<group>"; };
+ E56E9F841E68F84700412830 /* UICountingLabel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UICountingLabel.h; sourceTree = "<group>"; };
+ E56E9F851E68F84700412830 /* UICountingLabel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UICountingLabel.m; sourceTree = "<group>"; };
+ E56E9F871E68F89200412830 /* PCChartsTableViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PCChartsTableViewController.h; sourceTree = "<group>"; };
+ E56E9F881E68F89200412830 /* PCChartsTableViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PCChartsTableViewController.m; sourceTree = "<group>"; };
+ E56E9F8A1E68F8F600412830 /* PCChartViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PCChartViewController.h; sourceTree = "<group>"; };
+ E56E9F8B1E68F8F600412830 /* PCChartViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PCChartViewController.m; sourceTree = "<group>"; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ E56E9F261E68F54300412830 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ E56E9F7E1E68F5B800412830 /* Foundation.framework in Frameworks */,
+ E56E9F7C1E68F5B300412830 /* UIKit.framework in Frameworks */,
+ E56E9F7A1E68F5A900412830 /* QuartzCore.framework in Frameworks */,
+ E56E9F781E68F59F00412830 /* CoreGraphics.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ E56E9F201E68F54300412830 = {
+ isa = PBXGroup;
+ children = (
+ E56E9F431E68F55F00412830 /* PNChart */,
+ E56E9F2B1E68F54300412830 /* PNChartdemo */,
+ E56E9F2A1E68F54300412830 /* Products */,
+ E56E9F761E68F59E00412830 /* Frameworks */,
+ );
+ sourceTree = "<group>";
+ };
+ E56E9F2A1E68F54300412830 /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ E56E9F291E68F54300412830 /* PNChartdemo.app */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+ E56E9F2B1E68F54300412830 /* PNChartdemo */ = {
+ isa = PBXGroup;
+ children = (
+ E56E9F8A1E68F8F600412830 /* PCChartViewController.h */,
+ E56E9F8B1E68F8F600412830 /* PCChartViewController.m */,
+ E56E9F871E68F89200412830 /* PCChartsTableViewController.h */,
+ E56E9F881E68F89200412830 /* PCChartsTableViewController.m */,
+ E56E9F831E68F84700412830 /* UICountingLabel */,
+ E56E9F2F1E68F54300412830 /* AppDelegate.h */,
+ E56E9F301E68F54300412830 /* AppDelegate.m */,
+ E56E9F321E68F54300412830 /* ViewController.h */,
+ E56E9F331E68F54300412830 /* ViewController.m */,
+ E56E9F351E68F54300412830 /* Main.storyboard */,
+ E56E9F381E68F54300412830 /* Assets.xcassets */,
+ E56E9F3A1E68F54300412830 /* LaunchScreen.storyboard */,
+ E56E9F2C1E68F54300412830 /* Supporting Files */,
+ );
+ path = PNChartdemo;
+ sourceTree = "<group>";
+ };
+ E56E9F2C1E68F54300412830 /* Supporting Files */ = {
+ isa = PBXGroup;
+ children = (
+ E56E9F7F1E68F64800412830 /* PNChartDemo-Prefix.pch */,
+ E56E9F3D1E68F54300412830 /* Info.plist */,
+ E56E9F2D1E68F54300412830 /* main.m */,
+ );
+ name = "Supporting Files";
+ sourceTree = "<group>";
+ };
+ E56E9F431E68F55F00412830 /* PNChart */ = {
+ isa = PBXGroup;
+ children = (
+ E56E9F441E68F55F00412830 /* PNBar.h */,
+ E56E9F451E68F55F00412830 /* PNBar.m */,
+ E56E9F461E68F55F00412830 /* PNBarChart.h */,
+ E56E9F471E68F55F00412830 /* PNBarChart.m */,
+ E56E9F481E68F55F00412830 /* PNChart.h */,
+ E56E9F491E68F55F00412830 /* PNChartDelegate.h */,
+ E56E9F4A1E68F55F00412830 /* PNChartLabel.h */,
+ E56E9F4B1E68F55F00412830 /* PNChartLabel.m */,
+ E56E9F4C1E68F55F00412830 /* PNCircleChart.h */,
+ E56E9F4D1E68F55F00412830 /* PNCircleChart.m */,
+ E56E9F4E1E68F55F00412830 /* PNColor.h */,
+ E56E9F4F1E68F55F00412830 /* PNColor.m */,
+ E56E9F501E68F55F00412830 /* PNGenericChart.h */,
+ E56E9F511E68F55F00412830 /* PNGenericChart.m */,
+ E56E9F521E68F55F00412830 /* PNLineChart.h */,
+ E56E9F531E68F55F00412830 /* PNLineChart.m */,
+ E56E9F541E68F55F00412830 /* PNLineChartData.h */,
+ E56E9F551E68F55F00412830 /* PNLineChartData.m */,
+ E56E9F561E68F55F00412830 /* PNLineChartDataItem.h */,
+ E56E9F571E68F55F00412830 /* PNLineChartDataItem.m */,
+ E56E9F581E68F55F00412830 /* PNPieChart.h */,
+ E56E9F591E68F55F00412830 /* PNPieChart.m */,
+ E56E9F5A1E68F55F00412830 /* PNPieChartDataItem.h */,
+ E56E9F5B1E68F55F00412830 /* PNPieChartDataItem.m */,
+ E56E9F5C1E68F55F00412830 /* PNRadarChart.h */,
+ E56E9F5D1E68F55F00412830 /* PNRadarChart.m */,
+ E56E9F5E1E68F55F00412830 /* PNRadarChartDataItem.h */,
+ E56E9F5F1E68F55F00412830 /* PNRadarChartDataItem.m */,
+ E56E9F601E68F55F00412830 /* PNScatterChart.h */,
+ E56E9F611E68F55F00412830 /* PNScatterChart.m */,
+ E56E9F621E68F55F00412830 /* PNScatterChartData.h */,
+ E56E9F631E68F55F00412830 /* PNScatterChartData.m */,
+ E56E9F641E68F55F00412830 /* PNScatterChartDataItem.h */,
+ E56E9F651E68F55F00412830 /* PNScatterChartDataItem.m */,
+ );
+ path = PNChart;
+ sourceTree = "<group>";
+ };
+ E56E9F761E68F59E00412830 /* Frameworks */ = {
+ isa = PBXGroup;
+ children = (
+ E56E9F7D1E68F5B800412830 /* Foundation.framework */,
+ E56E9F7B1E68F5B300412830 /* UIKit.framework */,
+ E56E9F791E68F5A900412830 /* QuartzCore.framework */,
+ E56E9F771E68F59F00412830 /* CoreGraphics.framework */,
+ );
+ name = Frameworks;
+ sourceTree = "<group>";
+ };
+ E56E9F831E68F84700412830 /* UICountingLabel */ = {
+ isa = PBXGroup;
+ children = (
+ E56E9F841E68F84700412830 /* UICountingLabel.h */,
+ E56E9F851E68F84700412830 /* UICountingLabel.m */,
+ );
+ path = UICountingLabel;
+ sourceTree = "<group>";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+ E56E9F281E68F54300412830 /* PNChartdemo */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = E56E9F401E68F54300412830 /* Build configuration list for PBXNativeTarget "PNChartdemo" */;
+ buildPhases = (
+ E56E9F251E68F54300412830 /* Sources */,
+ E56E9F261E68F54300412830 /* Frameworks */,
+ E56E9F271E68F54300412830 /* Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = PNChartdemo;
+ productName = PNChartdemo;
+ productReference = E56E9F291E68F54300412830 /* PNChartdemo.app */;
+ productType = "com.apple.product-type.application";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ E56E9F211E68F54300412830 /* Project object */ = {
+ isa = PBXProject;
+ attributes = {
+ LastUpgradeCheck = 0820;
+ ORGANIZATIONNAME = WindShan;
+ TargetAttributes = {
+ E56E9F281E68F54300412830 = {
+ CreatedOnToolsVersion = 8.2.1;
+ DevelopmentTeam = VGXA77XL6T;
+ ProvisioningStyle = Automatic;
+ };
+ };
+ };
+ buildConfigurationList = E56E9F241E68F54300412830 /* Build configuration list for PBXProject "PNChartdemo" */;
+ compatibilityVersion = "Xcode 3.2";
+ developmentRegion = English;
+ hasScannedForEncodings = 0;
+ knownRegions = (
+ en,
+ Base,
+ );
+ mainGroup = E56E9F201E68F54300412830;
+ productRefGroup = E56E9F2A1E68F54300412830 /* Products */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ E56E9F281E68F54300412830 /* PNChartdemo */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+ E56E9F271E68F54300412830 /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ E56E9F3C1E68F54300412830 /* LaunchScreen.storyboard in Resources */,
+ E56E9F391E68F54300412830 /* Assets.xcassets in Resources */,
+ E56E9F371E68F54300412830 /* Main.storyboard in Resources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+ E56E9F251E68F54300412830 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ E56E9F6C1E68F55F00412830 /* PNLineChart.m in Sources */,
+ E56E9F671E68F55F00412830 /* PNBarChart.m in Sources */,
+ E56E9F6A1E68F55F00412830 /* PNColor.m in Sources */,
+ E56E9F891E68F89200412830 /* PCChartsTableViewController.m in Sources */,
+ E56E9F711E68F55F00412830 /* PNRadarChart.m in Sources */,
+ E56E9F721E68F55F00412830 /* PNRadarChartDataItem.m in Sources */,
+ E56E9F341E68F54300412830 /* ViewController.m in Sources */,
+ E56E9F661E68F55F00412830 /* PNBar.m in Sources */,
+ E56E9F741E68F55F00412830 /* PNScatterChartData.m in Sources */,
+ E56E9F6E1E68F55F00412830 /* PNLineChartDataItem.m in Sources */,
+ E56E9F681E68F55F00412830 /* PNChartLabel.m in Sources */,
+ E56E9F311E68F54300412830 /* AppDelegate.m in Sources */,
+ E56E9F751E68F55F00412830 /* PNScatterChartDataItem.m in Sources */,
+ E56E9F701E68F55F00412830 /* PNPieChartDataItem.m in Sources */,
+ E56E9F2E1E68F54300412830 /* main.m in Sources */,
+ E56E9F6D1E68F55F00412830 /* PNLineChartData.m in Sources */,
+ E56E9F731E68F55F00412830 /* PNScatterChart.m in Sources */,
+ E56E9F691E68F55F00412830 /* PNCircleChart.m in Sources */,
+ E56E9F8C1E68F8F600412830 /* PCChartViewController.m in Sources */,
+ E56E9F861E68F84700412830 /* UICountingLabel.m in Sources */,
+ E56E9F6F1E68F55F00412830 /* PNPieChart.m in Sources */,
+ E56E9F6B1E68F55F00412830 /* PNGenericChart.m in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXVariantGroup section */
+ E56E9F351E68F54300412830 /* Main.storyboard */ = {
+ isa = PBXVariantGroup;
+ children = (
+ E56E9F361E68F54300412830 /* Base */,
+ );
+ name = Main.storyboard;
+ sourceTree = "<group>";
+ };
+ E56E9F3A1E68F54300412830 /* LaunchScreen.storyboard */ = {
+ isa = PBXVariantGroup;
+ children = (
+ E56E9F3B1E68F54300412830 /* Base */,
+ );
+ name = LaunchScreen.storyboard;
+ sourceTree = "<group>";
+ };
+/* End PBXVariantGroup section */
+
+/* Begin XCBuildConfiguration section */
+ E56E9F3E1E68F54300412830 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = dwarf;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ ENABLE_TESTABILITY = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "DEBUG=1",
+ "$(inherited)",
+ );
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 10.2;
+ MTL_ENABLE_DEBUG_INFO = YES;
+ ONLY_ACTIVE_ARCH = YES;
+ SDKROOT = iphoneos;
+ };
+ name = Debug;
+ };
+ E56E9F3F1E68F54300412830 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ ENABLE_NS_ASSERTIONS = NO;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 10.2;
+ MTL_ENABLE_DEBUG_INFO = NO;
+ SDKROOT = iphoneos;
+ VALIDATE_PRODUCT = YES;
+ };
+ name = Release;
+ };
+ E56E9F411E68F54300412830 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ DEVELOPMENT_TEAM = VGXA77XL6T;
+ GCC_PREFIX_HEADER = "PNChartdemo/PNChartDemo-Prefix.pch";
+ INFOPLIST_FILE = PNChartdemo/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
+ PRODUCT_BUNDLE_IDENTIFIER = com.moral.PNChartdemo.PNChartdemo;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Debug;
+ };
+ E56E9F421E68F54300412830 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ DEVELOPMENT_TEAM = VGXA77XL6T;
+ GCC_PREFIX_HEADER = "PNChartdemo/PNChartDemo-Prefix.pch";
+ INFOPLIST_FILE = PNChartdemo/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
+ PRODUCT_BUNDLE_IDENTIFIER = com.moral.PNChartdemo.PNChartdemo;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ E56E9F241E68F54300412830 /* Build configuration list for PBXProject "PNChartdemo" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ E56E9F3E1E68F54300412830 /* Debug */,
+ E56E9F3F1E68F54300412830 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ E56E9F401E68F54300412830 /* Build configuration list for PBXNativeTarget "PNChartdemo" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ E56E9F411E68F54300412830 /* Debug */,
+ E56E9F421E68F54300412830 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = E56E9F211E68F54300412830 /* Project object */;
+}
diff --git a/camerademo/camerademo.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/PNChartdemo/PNChartdemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata
similarity index 69%
rename from camerademo/camerademo.xcodeproj/project.xcworkspace/contents.xcworkspacedata
rename to PNChartdemo/PNChartdemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata
index ac29a49..3674b57 100644
--- a/camerademo/camerademo.xcodeproj/project.xcworkspace/contents.xcworkspacedata
+++ b/PNChartdemo/PNChartdemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata
@@ -2,6 +2,6 @@
<Workspace
version = "1.0">
<FileRef
- location = "self:camerademo.xcodeproj">
+ location = "self:PNChartdemo.xcodeproj">
</FileRef>
</Workspace>
diff --git a/PNChartdemo/PNChartdemo.xcodeproj/project.xcworkspace/xcuserdata/WindShan.xcuserdatad/UserInterfaceState.xcuserstate b/PNChartdemo/PNChartdemo.xcodeproj/project.xcworkspace/xcuserdata/WindShan.xcuserdatad/UserInterfaceState.xcuserstate
new file mode 100644
index 0000000..ee124fb
--- /dev/null
+++ b/PNChartdemo/PNChartdemo.xcodeproj/project.xcworkspace/xcuserdata/WindShan.xcuserdatad/UserInterfaceState.xcuserstate
Binary files differ
diff --git a/PNChartdemo/PNChartdemo.xcodeproj/xcuserdata/WindShan.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/PNChartdemo/PNChartdemo.xcodeproj/xcuserdata/WindShan.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist
new file mode 100644
index 0000000..ce2e85d
--- /dev/null
+++ b/PNChartdemo/PNChartdemo.xcodeproj/xcuserdata/WindShan.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Bucket
+ type = "1"
+ version = "2.0">
+ <Breakpoints>
+ <BreakpointProxy
+ BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
+ <BreakpointContent
+ shouldBeEnabled = "Yes"
+ ignoreCount = "0"
+ continueAfterRunningActions = "No"
+ filePath = "PNChartdemo/PCChartViewController.m"
+ timestampString = "510197037.819375"
+ startingColumnNumber = "9223372036854775807"
+ endingColumnNumber = "9223372036854775807"
+ startingLineNumber = "403"
+ endingLineNumber = "403"
+ landmarkName = "-rightSwitchChanged:"
+ landmarkType = "7">
+ </BreakpointContent>
+ </BreakpointProxy>
+ <BreakpointProxy
+ BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
+ <BreakpointContent
+ shouldBeEnabled = "Yes"
+ ignoreCount = "0"
+ continueAfterRunningActions = "No"
+ filePath = "PNChartdemo/PCChartViewController.m"
+ timestampString = "510197037.819375"
+ startingColumnNumber = "9223372036854775807"
+ endingColumnNumber = "9223372036854775807"
+ startingLineNumber = "412"
+ endingLineNumber = "412"
+ landmarkName = "-centerSwitchChanged:"
+ landmarkType = "7">
+ </BreakpointContent>
+ </BreakpointProxy>
+ <BreakpointProxy
+ BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
+ <BreakpointContent
+ shouldBeEnabled = "Yes"
+ ignoreCount = "0"
+ continueAfterRunningActions = "No"
+ filePath = "PNChartdemo/PCChartViewController.m"
+ timestampString = "510197037.819375"
+ startingColumnNumber = "9223372036854775807"
+ endingColumnNumber = "9223372036854775807"
+ startingLineNumber = "433"
+ endingLineNumber = "433"
+ landmarkName = "-leftSwitchChanged:"
+ landmarkType = "7">
+ </BreakpointContent>
+ </BreakpointProxy>
+ </Breakpoints>
+</Bucket>
diff --git a/PNChartdemo/PNChartdemo.xcodeproj/xcuserdata/WindShan.xcuserdatad/xcschemes/PNChartdemo.xcscheme b/PNChartdemo/PNChartdemo.xcodeproj/xcuserdata/WindShan.xcuserdatad/xcschemes/PNChartdemo.xcscheme
new file mode 100644
index 0000000..8666a26
--- /dev/null
+++ b/PNChartdemo/PNChartdemo.xcodeproj/xcuserdata/WindShan.xcuserdatad/xcschemes/PNChartdemo.xcscheme
@@ -0,0 +1,91 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Scheme
+ LastUpgradeVersion = "0820"
+ version = "1.3">
+ <BuildAction
+ parallelizeBuildables = "YES"
+ buildImplicitDependencies = "YES">
+ <BuildActionEntries>
+ <BuildActionEntry
+ buildForTesting = "YES"
+ buildForRunning = "YES"
+ buildForProfiling = "YES"
+ buildForArchiving = "YES"
+ buildForAnalyzing = "YES">
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "E56E9F281E68F54300412830"
+ BuildableName = "PNChartdemo.app"
+ BlueprintName = "PNChartdemo"
+ ReferencedContainer = "container:PNChartdemo.xcodeproj">
+ </BuildableReference>
+ </BuildActionEntry>
+ </BuildActionEntries>
+ </BuildAction>
+ <TestAction
+ buildConfiguration = "Debug"
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ shouldUseLaunchSchemeArgsEnv = "YES">
+ <Testables>
+ </Testables>
+ <MacroExpansion>
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "E56E9F281E68F54300412830"
+ BuildableName = "PNChartdemo.app"
+ BlueprintName = "PNChartdemo"
+ ReferencedContainer = "container:PNChartdemo.xcodeproj">
+ </BuildableReference>
+ </MacroExpansion>
+ <AdditionalOptions>
+ </AdditionalOptions>
+ </TestAction>
+ <LaunchAction
+ buildConfiguration = "Debug"
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ launchStyle = "0"
+ useCustomWorkingDirectory = "NO"
+ ignoresPersistentStateOnLaunch = "NO"
+ debugDocumentVersioning = "YES"
+ debugServiceExtension = "internal"
+ allowLocationSimulation = "YES">
+ <BuildableProductRunnable
+ runnableDebuggingMode = "0">
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "E56E9F281E68F54300412830"
+ BuildableName = "PNChartdemo.app"
+ BlueprintName = "PNChartdemo"
+ ReferencedContainer = "container:PNChartdemo.xcodeproj">
+ </BuildableReference>
+ </BuildableProductRunnable>
+ <AdditionalOptions>
+ </AdditionalOptions>
+ </LaunchAction>
+ <ProfileAction
+ buildConfiguration = "Release"
+ shouldUseLaunchSchemeArgsEnv = "YES"
+ savedToolIdentifier = ""
+ useCustomWorkingDirectory = "NO"
+ debugDocumentVersioning = "YES">
+ <BuildableProductRunnable
+ runnableDebuggingMode = "0">
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "E56E9F281E68F54300412830"
+ BuildableName = "PNChartdemo.app"
+ BlueprintName = "PNChartdemo"
+ ReferencedContainer = "container:PNChartdemo.xcodeproj">
+ </BuildableReference>
+ </BuildableProductRunnable>
+ </ProfileAction>
+ <AnalyzeAction
+ buildConfiguration = "Debug">
+ </AnalyzeAction>
+ <ArchiveAction
+ buildConfiguration = "Release"
+ revealArchiveInOrganizer = "YES">
+ </ArchiveAction>
+</Scheme>
diff --git a/camerademo/camerademo.xcodeproj/xcuserdata/WindShan.xcuserdatad/xcschemes/xcschememanagement.plist b/PNChartdemo/PNChartdemo.xcodeproj/xcuserdata/WindShan.xcuserdatad/xcschemes/xcschememanagement.plist
similarity index 84%
rename from camerademo/camerademo.xcodeproj/xcuserdata/WindShan.xcuserdatad/xcschemes/xcschememanagement.plist
rename to PNChartdemo/PNChartdemo.xcodeproj/xcuserdata/WindShan.xcuserdatad/xcschemes/xcschememanagement.plist
index 01e9d0f..d85d839 100644
--- a/camerademo/camerademo.xcodeproj/xcuserdata/WindShan.xcuserdatad/xcschemes/xcschememanagement.plist
+++ b/PNChartdemo/PNChartdemo.xcodeproj/xcuserdata/WindShan.xcuserdatad/xcschemes/xcschememanagement.plist
@@ -4,7 +4,7 @@
<dict>
<key>SchemeUserState</key>
<dict>
- <key>camerademo.xcscheme</key>
+ <key>PNChartdemo.xcscheme</key>
<dict>
<key>orderHint</key>
<integer>0</integer>
@@ -12,7 +12,7 @@
</dict>
<key>SuppressBuildableAutocreation</key>
<dict>
- <key>E52F59EA1E5C21890084B3E2</key>
+ <key>E56E9F281E68F54300412830</key>
<dict>
<key>primary</key>
<true/>
diff --git a/camerademo/camerademo/AppDelegate.h b/PNChartdemo/PNChartdemo/AppDelegate.h
similarity index 80%
rename from camerademo/camerademo/AppDelegate.h
rename to PNChartdemo/PNChartdemo/AppDelegate.h
index ca2a55e..e933d75 100644
--- a/camerademo/camerademo/AppDelegate.h
+++ b/PNChartdemo/PNChartdemo/AppDelegate.h
@@ -1,8 +1,8 @@
//
// AppDelegate.h
-// camerademo
+// PNChartdemo
//
-// Created by WindShan on 2017/2/21.
+// Created by WindShan on 2017/3/3.
// Copyright �� 2017��� WindShan. All rights reserved.
//
diff --git a/camerademo/camerademo/AppDelegate.m b/PNChartdemo/PNChartdemo/AppDelegate.m
similarity index 96%
rename from camerademo/camerademo/AppDelegate.m
rename to PNChartdemo/PNChartdemo/AppDelegate.m
index c5b854e..93c0cbb 100644
--- a/camerademo/camerademo/AppDelegate.m
+++ b/PNChartdemo/PNChartdemo/AppDelegate.m
@@ -1,8 +1,8 @@
//
// AppDelegate.m
-// camerademo
+// PNChartdemo
//
-// Created by WindShan on 2017/2/21.
+// Created by WindShan on 2017/3/3.
// Copyright �� 2017��� WindShan. All rights reserved.
//
diff --git a/camerademo/camerademo/Assets.xcassets/AppIcon.appiconset/Contents.json b/PNChartdemo/PNChartdemo/Assets.xcassets/AppIcon.appiconset/Contents.json
similarity index 100%
rename from camerademo/camerademo/Assets.xcassets/AppIcon.appiconset/Contents.json
rename to PNChartdemo/PNChartdemo/Assets.xcassets/AppIcon.appiconset/Contents.json
diff --git a/camerademo/camerademo/Base.lproj/LaunchScreen.storyboard b/PNChartdemo/PNChartdemo/Base.lproj/LaunchScreen.storyboard
similarity index 100%
rename from camerademo/camerademo/Base.lproj/LaunchScreen.storyboard
rename to PNChartdemo/PNChartdemo/Base.lproj/LaunchScreen.storyboard
diff --git a/PNChartdemo/PNChartdemo/Base.lproj/Main.storyboard b/PNChartdemo/PNChartdemo/Base.lproj/Main.storyboard
new file mode 100755
index 0000000..f75524f
--- /dev/null
+++ b/PNChartdemo/PNChartdemo/Base.lproj/Main.storyboard
@@ -0,0 +1,300 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="11762" systemVersion="16C67" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" colorMatched="YES" initialViewController="9Rt-UT-IxH">
+ <device id="retina4_7" orientation="portrait">
+ <adaptation id="fullscreen"/>
+ </device>
+ <dependencies>
+ <deployment identifier="iOS"/>
+ <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11757"/>
+ <capability name="Constraints to layout margins" minToolsVersion="6.0"/>
+ <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
+ </dependencies>
+ <scenes>
+ <!--PNChart-->
+ <scene sceneID="lC9-iu-Smd">
+ <objects>
+ <viewController id="Tha-Wr-sPW" customClass="PCChartViewController" sceneMemberID="viewController">
+ <layoutGuides>
+ <viewControllerLayoutGuide type="top" id="znr-YO-4a4"/>
+ <viewControllerLayoutGuide type="bottom" id="61B-jM-QAH"/>
+ </layoutGuides>
+ <view key="view" contentMode="scaleToFill" id="PPb-b8-nBo">
+ <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
+ <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
+ <subviews>
+ <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="L3F-13-Wf5">
+ <rect key="frame" x="140" y="364" width="95" height="30"/>
+ <state key="normal" title="Change Value">
+ <color key="titleShadowColor" red="0.5" green="0.5" blue="0.5" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+ </state>
+ <connections>
+ <action selector="changeValue:" destination="Tha-Wr-sPW" eventType="touchUpInside" id="zeG-Cp-Wjs"/>
+ </connections>
+ </button>
+ <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="FUU-vZ-jMd">
+ <rect key="frame" x="159" y="81" width="57" height="32"/>
+ <fontDescription key="fontDescription" name="Avenir-Medium" family="Avenir" pointSize="23"/>
+ <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+ <nil key="highlightedColor"/>
+ </label>
+ <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Percentage" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="IKu-qh-ksi">
+ <rect key="frame" x="16" y="539" width="88" height="21"/>
+ <fontDescription key="fontDescription" type="system" pointSize="17"/>
+ <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+ <nil key="highlightedColor"/>
+ </label>
+ <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Show Labels" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Ifm-a9-Wkq">
+ <rect key="frame" x="260" y="538" width="99" height="21"/>
+ <constraints>
+ <constraint firstAttribute="width" constant="99" id="KZW-Ru-GZO"/>
+ </constraints>
+ <fontDescription key="fontDescription" type="system" pointSize="17"/>
+ <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+ <nil key="highlightedColor"/>
+ </label>
+ <switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" translatesAutoresizingMaskIntoConstraints="NO" id="kav-3r-blI">
+ <rect key="frame" x="16" y="434" width="51" height="31"/>
+ <connections>
+ <action selector="centerSwitchChanged:" destination="Tha-Wr-sPW" eventType="valueChanged" id="ETI-hb-d8F"/>
+ </connections>
+ </switch>
+ <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Multiple Selection" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="sMF-o9-dZX">
+ <rect key="frame" x="16" y="471" width="137" height="21"/>
+ <fontDescription key="fontDescription" type="system" pointSize="17"/>
+ <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+ <nil key="highlightedColor"/>
+ </label>
+ <switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="ORA-mb-hJl">
+ <rect key="frame" x="16" y="500" width="51" height="31"/>
+ <connections>
+ <action selector="leftSwitchChanged:" destination="Tha-Wr-sPW" eventType="valueChanged" id="q9T-QK-Sas"/>
+ </connections>
+ </switch>
+ <switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Mnm-Is-oih" userLabel="Animations Switch">
+ <rect key="frame" x="310" y="434" width="51" height="31"/>
+ <connections>
+ <action selector="animationsSwitchChanged:" destination="Tha-Wr-sPW" eventType="valueChanged" id="lC4-5M-rlC"/>
+ </connections>
+ </switch>
+ <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Animations" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="lc1-oP-FNw">
+ <rect key="frame" x="273" y="471" width="86" height="21"/>
+ <fontDescription key="fontDescription" type="system" pointSize="17"/>
+ <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+ <nil key="highlightedColor"/>
+ </label>
+ <switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="qR7-40-7ir">
+ <rect key="frame" x="310" y="500" width="51" height="31"/>
+ <connections>
+ <action selector="rightSwitchChanged:" destination="Tha-Wr-sPW" eventType="valueChanged" id="n6V-lL-r8Q"/>
+ </connections>
+ </switch>
+ </subviews>
+ <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+ <constraints>
+ <constraint firstItem="Mnm-Is-oih" firstAttribute="centerY" secondItem="kav-3r-blI" secondAttribute="centerY" id="0NI-PI-ATH"/>
+ <constraint firstItem="ORA-mb-hJl" firstAttribute="centerY" secondItem="qR7-40-7ir" secondAttribute="centerY" id="7c9-My-TTD"/>
+ <constraint firstItem="IKu-qh-ksi" firstAttribute="top" secondItem="ORA-mb-hJl" secondAttribute="bottom" constant="8" id="7vb-uB-f1x"/>
+ <constraint firstItem="Ifm-a9-Wkq" firstAttribute="top" secondItem="qR7-40-7ir" secondAttribute="bottom" constant="7" id="9ET-Wq-Yen"/>
+ <constraint firstItem="qR7-40-7ir" firstAttribute="top" secondItem="lc1-oP-FNw" secondAttribute="bottom" constant="8" id="A54-NU-I6K"/>
+ <constraint firstItem="FUU-vZ-jMd" firstAttribute="top" secondItem="znr-YO-4a4" secondAttribute="bottom" constant="17" id="DLv-qJ-h7R"/>
+ <constraint firstItem="sMF-o9-dZX" firstAttribute="top" secondItem="kav-3r-blI" secondAttribute="bottom" constant="6" id="Fy1-r9-rOd"/>
+ <constraint firstItem="Ifm-a9-Wkq" firstAttribute="trailing" secondItem="qR7-40-7ir" secondAttribute="trailing" id="Im7-AC-dup"/>
+ <constraint firstItem="ORA-mb-hJl" firstAttribute="top" secondItem="sMF-o9-dZX" secondAttribute="bottom" constant="8" symbolic="YES" id="K0Z-Kz-m2p"/>
+ <constraint firstAttribute="trailingMargin" secondItem="qR7-40-7ir" secondAttribute="trailing" id="KZ9-eM-6oW"/>
+ <constraint firstItem="kav-3r-blI" firstAttribute="leading" secondItem="PPb-b8-nBo" secondAttribute="leadingMargin" id="KrJ-mU-I6l"/>
+ <constraint firstAttribute="centerX" secondItem="FUU-vZ-jMd" secondAttribute="centerX" id="YGT-a5-Zka"/>
+ <constraint firstItem="lc1-oP-FNw" firstAttribute="trailing" secondItem="Mnm-Is-oih" secondAttribute="trailing" id="YrP-Jx-D1J"/>
+ <constraint firstItem="lc1-oP-FNw" firstAttribute="top" secondItem="Mnm-Is-oih" secondAttribute="bottom" constant="6" id="Zsm-LK-7NY"/>
+ <constraint firstAttribute="trailingMargin" secondItem="Mnm-Is-oih" secondAttribute="trailing" id="bnI-nC-1qS"/>
+ <constraint firstItem="kav-3r-blI" firstAttribute="top" secondItem="L3F-13-Wf5" secondAttribute="bottom" constant="40" id="eO9-bU-rZY"/>
+ <constraint firstItem="L3F-13-Wf5" firstAttribute="top" secondItem="znr-YO-4a4" secondAttribute="bottom" constant="300" id="ewm-kv-p8k"/>
+ <constraint firstItem="IKu-qh-ksi" firstAttribute="leading" secondItem="PPb-b8-nBo" secondAttribute="leadingMargin" id="m9a-Ug-SfK"/>
+ <constraint firstItem="ORA-mb-hJl" firstAttribute="leading" secondItem="PPb-b8-nBo" secondAttribute="leadingMargin" id="oZO-il-Fd5"/>
+ <constraint firstItem="sMF-o9-dZX" firstAttribute="leading" secondItem="kav-3r-blI" secondAttribute="leading" id="qtt-KE-YfT"/>
+ <constraint firstAttribute="centerX" secondItem="L3F-13-Wf5" secondAttribute="centerX" id="zXw-WV-mro"/>
+ </constraints>
+ </view>
+ <navigationItem key="navigationItem" title="PNChart" id="Ukg-Sg-E2z"/>
+ <connections>
+ <outlet property="animationsSwitch" destination="Mnm-Is-oih" id="haB-27-exI"/>
+ <outlet property="centerSwitch" destination="kav-3r-blI" id="aDA-mR-FhR"/>
+ <outlet property="centerSwitchLabel" destination="sMF-o9-dZX" id="Epf-8v-NeL"/>
+ <outlet property="changeValueButton" destination="L3F-13-Wf5" id="JnI-y3-Xpj"/>
+ <outlet property="leftLabel" destination="IKu-qh-ksi" id="CPy-oy-qCP"/>
+ <outlet property="leftSwitch" destination="ORA-mb-hJl" id="u1M-2f-6P1"/>
+ <outlet property="rightLabel" destination="Ifm-a9-Wkq" id="QhE-j2-qpe"/>
+ <outlet property="rightSwitch" destination="qR7-40-7ir" id="noL-6R-d3a"/>
+ <outlet property="titleLabel" destination="FUU-vZ-jMd" id="dA3-KC-Ht4"/>
+ </connections>
+ </viewController>
+ <placeholder placeholderIdentifier="IBFirstResponder" id="kDa-u3-t6i" userLabel="First Responder" sceneMemberID="firstResponder"/>
+ </objects>
+ <point key="canvasLocation" x="536" y="31"/>
+ </scene>
+ <!--PNChart-->
+ <scene sceneID="pBo-qW-N8B">
+ <objects>
+ <tableViewController id="cc5-BF-Ga2" customClass="PCChartsTableViewController" sceneMemberID="viewController">
+ <tableView key="view" opaque="NO" clipsSubviews="YES" clearsContextBeforeDrawing="NO" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="static" style="plain" separatorStyle="default" rowHeight="44" sectionHeaderHeight="22" sectionFooterHeight="22" id="EAk-8x-zLw">
+ <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
+ <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+ <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+ <sections>
+ <tableViewSection id="Rtv-33-iAC">
+ <cells>
+ <tableViewCell contentMode="scaleToFill" selectionStyle="blue" accessoryType="disclosureIndicator" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" textLabel="dtA-8k-dgn" style="IBUITableViewCellStyleDefault" id="irc-98-Qkg">
+ <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
+ <autoresizingMask key="autoresizingMask"/>
+ <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="irc-98-Qkg" id="QVQ-E4-AgU">
+ <rect key="frame" x="0.0" y="0.0" width="342" height="43"/>
+ <autoresizingMask key="autoresizingMask"/>
+ <subviews>
+ <label opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="left" text="LineChart" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="dtA-8k-dgn">
+ <rect key="frame" x="15" y="0.0" width="325" height="43"/>
+ <autoresizingMask key="autoresizingMask"/>
+ <fontDescription key="fontDescription" type="system" pointSize="18"/>
+ <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+ <nil key="highlightedColor"/>
+ </label>
+ </subviews>
+ </tableViewCellContentView>
+ <connections>
+ <segue destination="Tha-Wr-sPW" kind="push" identifier="lineChart" id="XHj-XM-h67"/>
+ </connections>
+ </tableViewCell>
+ <tableViewCell contentMode="scaleToFill" selectionStyle="blue" accessoryType="disclosureIndicator" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" textLabel="sGJ-nJ-Evy" style="IBUITableViewCellStyleDefault" id="uiU-qo-XNI">
+ <rect key="frame" x="0.0" y="44" width="375" height="44"/>
+ <autoresizingMask key="autoresizingMask"/>
+ <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="uiU-qo-XNI" id="QSW-pF-BtE">
+ <rect key="frame" x="0.0" y="0.0" width="342" height="43"/>
+ <autoresizingMask key="autoresizingMask"/>
+ <subviews>
+ <label opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="left" text="BarChart" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="sGJ-nJ-Evy">
+ <rect key="frame" x="15" y="0.0" width="325" height="43"/>
+ <autoresizingMask key="autoresizingMask"/>
+ <fontDescription key="fontDescription" type="system" pointSize="18"/>
+ <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+ <nil key="highlightedColor"/>
+ </label>
+ </subviews>
+ </tableViewCellContentView>
+ <connections>
+ <segue destination="Tha-Wr-sPW" kind="push" identifier="barChart" id="BAm-LA-QbM"/>
+ </connections>
+ </tableViewCell>
+ <tableViewCell contentMode="scaleToFill" selectionStyle="blue" accessoryType="disclosureIndicator" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" textLabel="Bn9-8g-5UP" style="IBUITableViewCellStyleDefault" id="xKf-5i-9cT">
+ <rect key="frame" x="0.0" y="88" width="375" height="44"/>
+ <autoresizingMask key="autoresizingMask"/>
+ <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="xKf-5i-9cT" id="0Fm-qD-hZk">
+ <rect key="frame" x="0.0" y="0.0" width="342" height="43"/>
+ <autoresizingMask key="autoresizingMask"/>
+ <subviews>
+ <label opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="left" text="CircleChart" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="Bn9-8g-5UP">
+ <rect key="frame" x="15" y="0.0" width="325" height="43"/>
+ <autoresizingMask key="autoresizingMask"/>
+ <fontDescription key="fontDescription" type="system" pointSize="18"/>
+ <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+ <nil key="highlightedColor"/>
+ </label>
+ </subviews>
+ </tableViewCellContentView>
+ <connections>
+ <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="132" width="375" 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="342" 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="325" height="43"/>
+ <autoresizingMask key="autoresizingMask"/>
+ <fontDescription key="fontDescription" type="system" pointSize="18"/>
+ <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+ <nil key="highlightedColor"/>
+ </label>
+ </subviews>
+ </tableViewCellContentView>
+ <connections>
+ <segue destination="Tha-Wr-sPW" kind="push" identifier="pieChart" id="pvQ-oy-a9a"/>
+ </connections>
+ </tableViewCell>
+ <tableViewCell contentMode="scaleToFill" selectionStyle="blue" accessoryType="disclosureIndicator" indentationLevel="1" indentationWidth="0.0" textLabel="YOU-SK-mQU" style="IBUITableViewCellStyleDefault" id="JJR-oU-C7n">
+ <rect key="frame" x="0.0" y="176" width="375" height="44"/>
+ <autoresizingMask key="autoresizingMask"/>
+ <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="JJR-oU-C7n" id="iJk-3W-tcy">
+ <rect key="frame" x="0.0" y="0.0" width="342" height="43"/>
+ <autoresizingMask key="autoresizingMask"/>
+ <subviews>
+ <label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="ScatterChart" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="YOU-SK-mQU">
+ <rect key="frame" x="15" y="0.0" width="325" height="43"/>
+ <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
+ <fontDescription key="fontDescription" type="system" pointSize="18"/>
+ <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+ <nil key="highlightedColor"/>
+ </label>
+ </subviews>
+ </tableViewCellContentView>
+ <connections>
+ <segue destination="Tha-Wr-sPW" kind="push" identifier="scatterChart" id="V7s-JV-4Nx"/>
+ </connections>
+ </tableViewCell>
+ <tableViewCell contentMode="scaleToFill" selectionStyle="blue" accessoryType="disclosureIndicator" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" textLabel="Sjk-AS-XhW" style="IBUITableViewCellStyleDefault" id="bev-fA-J4Q">
+ <rect key="frame" x="0.0" y="220" width="375" height="44"/>
+ <autoresizingMask key="autoresizingMask"/>
+ <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="bev-fA-J4Q" id="nSV-Wu-TAu">
+ <rect key="frame" x="0.0" y="0.0" width="342" height="43"/>
+ <autoresizingMask key="autoresizingMask"/>
+ <subviews>
+ <label opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="left" text="RadarChart" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="Sjk-AS-XhW">
+ <rect key="frame" x="15" y="0.0" width="325" height="43"/>
+ <autoresizingMask key="autoresizingMask"/>
+ <fontDescription key="fontDescription" type="system" pointSize="18"/>
+ <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+ <nil key="highlightedColor"/>
+ </label>
+ </subviews>
+ </tableViewCellContentView>
+ <connections>
+ <segue destination="Tha-Wr-sPW" kind="push" identifier="radarChart" id="4D9-t3-nzn"/>
+ </connections>
+ </tableViewCell>
+ </cells>
+ </tableViewSection>
+ </sections>
+ </tableView>
+ <navigationItem key="navigationItem" title="PNChart" id="wPu-Ht-gOr"/>
+ </tableViewController>
+ <placeholder placeholderIdentifier="IBFirstResponder" id="JMX-8U-h8G" userLabel="First Responder" sceneMemberID="firstResponder"/>
+ </objects>
+ <point key="canvasLocation" x="50" y="31"/>
+ </scene>
+ <!--Navigation Controller-->
+ <scene sceneID="adz-gG-u3z">
+ <objects>
+ <navigationController definesPresentationContext="YES" id="9Rt-UT-IxH" sceneMemberID="viewController">
+ <navigationBar key="navigationBar" contentMode="scaleToFill" id="Vgs-8d-rE2">
+ <rect key="frame" x="0.0" y="0.0" width="1000" height="1000"/>
+ <autoresizingMask key="autoresizingMask"/>
+ </navigationBar>
+ <connections>
+ <segue destination="cc5-BF-Ga2" kind="relationship" relationship="rootViewController" id="Jdg-FU-XfU"/>
+ </connections>
+ </navigationController>
+ <placeholder placeholderIdentifier="IBFirstResponder" id="RN0-OP-dIr" userLabel="First Responder" sceneMemberID="firstResponder"/>
+ </objects>
+ <point key="canvasLocation" x="-318" y="31"/>
+ </scene>
+ </scenes>
+ <simulatedMetricsContainer key="defaultSimulatedMetrics">
+ <simulatedStatusBarMetrics key="statusBar"/>
+ <simulatedOrientationMetrics key="orientation"/>
+ <simulatedScreenMetrics key="destination" type="retina4_7.fullscreen"/>
+ </simulatedMetricsContainer>
+ <inferredMetricsTieBreakers>
+ <segue reference="pvQ-oy-a9a"/>
+ </inferredMetricsTieBreakers>
+</document>
diff --git a/camerademo/camerademo/Info.plist b/PNChartdemo/PNChartdemo/Info.plist
similarity index 100%
rename from camerademo/camerademo/Info.plist
rename to PNChartdemo/PNChartdemo/Info.plist
diff --git a/PNChartdemo/PNChartdemo/PCChartViewController.h b/PNChartdemo/PNChartdemo/PCChartViewController.h
new file mode 100755
index 0000000..d8954b3
--- /dev/null
+++ b/PNChartdemo/PNChartdemo/PCChartViewController.h
@@ -0,0 +1,38 @@
+//
+// PCChartViewController.h
+// PNChartDemo
+//
+// Created by kevin on 11/7/13.
+// Copyright (c) 2013��� kevinzhow. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+#import "PNChartDelegate.h"
+#import "PNChart.h"
+
+@interface PCChartViewController : UIViewController<PNChartDelegate>
+
+@property (nonatomic) PNLineChart * lineChart;
+@property (nonatomic) PNBarChart * barChart;
+@property (nonatomic) PNCircleChart * circleChart;
+@property (nonatomic) PNPieChart *pieChart;
+@property (nonatomic) PNScatterChart *scatterChart;
+@property (nonatomic) PNRadarChart *radarChart;
+@property (weak, nonatomic) IBOutlet UILabel *centerSwitchLabel;
+
+@property (weak, nonatomic) IBOutlet UILabel *titleLabel;
+
+- (IBAction)changeValue:(id)sender;
+@property (weak, nonatomic) IBOutlet UIButton *changeValueButton;
+
+@property (weak, nonatomic) IBOutlet UISwitch *animationsSwitch;
+@property (weak, nonatomic) IBOutlet UISwitch *leftSwitch;
+@property (weak, nonatomic) IBOutlet UISwitch *centerSwitch;
+@property (weak, nonatomic) IBOutlet UISwitch *rightSwitch;
+@property (weak, nonatomic) IBOutlet UILabel *leftLabel;
+@property (weak, nonatomic) IBOutlet UILabel *rightLabel;
+
+- (IBAction)rightSwitchChanged:(id)sender;
+- (IBAction)leftSwitchChanged:(id)sender;
+
+@end
diff --git a/PNChartdemo/PNChartdemo/PCChartViewController.m b/PNChartdemo/PNChartdemo/PCChartViewController.m
new file mode 100755
index 0000000..ba59f98
--- /dev/null
+++ b/PNChartdemo/PNChartdemo/PCChartViewController.m
@@ -0,0 +1,490 @@
+//
+// PCChartViewController.m
+// PNChartDemo
+//
+// Created by kevin on 11/7/13.
+// Copyright (c) 2013��� kevinzhow. All rights reserved.
+//
+
+#import "PCChartViewController.h"
+
+#define ARC4RANDOM_MAX 0x100000000
+
+@implementation PCChartViewController
+
+
+- (void)viewDidLoad
+{
+ [super viewDidLoad];
+ self.titleLabel.textColor = PNFreshGreen;
+ self.leftSwitch.hidden = YES;
+ self.rightSwitch.hidden = YES;
+ self.leftLabel.hidden = YES;
+ self.rightLabel.hidden = YES;
+ self.centerSwitch.hidden = YES;
+ self.centerSwitchLabel.hidden = YES;
+
+ self.changeValueButton.hidden = YES;
+
+ if ([self.title isEqualToString:@"Line Chart"])
+ {
+
+ self.titleLabel.text = @"Line Chart";
+
+ self.rightSwitch.hidden = NO;
+ self.rightLabel.hidden = NO;
+ self.leftSwitch.hidden = NO;
+ self.leftLabel.hidden = NO;
+ self.animationsSwitch.hidden = NO;
+
+ self.leftLabel.text = @"Dark Background";
+ self.rightLabel.text = @"Show Curved Lines";
+
+ self.animationsSwitch.enabled = YES;
+ self.rightSwitch.enabled = YES;
+ self.leftSwitch.enabled = YES;
+ [self.animationsSwitch setOn:NO];
+ [self.rightSwitch setOn:NO];
+ [self.leftSwitch setOn:NO];
+
+
+ self.lineChart.backgroundColor = [UIColor whiteColor];
+ self.lineChart.yGridLinesColor = [UIColor grayColor];
+ [self.lineChart.chartData enumerateObjectsUsingBlock:^(PNLineChartData *obj, NSUInteger idx, BOOL *stop) {
+ obj.pointLabelColor = [UIColor blackColor];
+ }];
+
+ self.lineChart = [[PNLineChart alloc] initWithFrame:CGRectMake(0, 135.0, SCREEN_WIDTH, 200.0)];
+ self.lineChart.showCoordinateAxis = YES; // ���������������������
+ self.lineChart.yLabelFormat = @"%1.1f"; //���Y���������float���������������������
+ self.lineChart.xLabelFont = [UIFont fontWithName:@"Helvetica-Light" size:8.0];
+ [self.lineChart setXLabels:@[@"SEP 1", @"SEP 2", @"SEP 3", @"SEP 4", @"SEP 5", @"SEP 6", @"SEP 7"]];
+ self.lineChart.yLabelColor = [UIColor blackColor];
+ self.lineChart.xLabelColor = [UIColor blackColor];
+
+ // added an example to show how yGridLines can be enabled
+ // the color is set to clearColor so that the demo remains the same
+ self.lineChart.showGenYLabels = NO;
+ self.lineChart.showYGridLines = YES;
+
+ //Use yFixedValueMax and yFixedValueMin to Fix the Max and Min Y Value
+ //Only if you needed
+ self.lineChart.yFixedValueMax = 300.0;
+ self.lineChart.yFixedValueMin = 0.0;
+
+ self.lineChart.showSmoothLines = YES;
+
+ [self.lineChart setYLabels:@[
+ @"0",
+ @"50",
+ @"100",
+ @"150",
+ @"200",
+ @"250",
+ @"300",
+ ]
+ ];
+
+// // Line Chart #1
+// NSArray *data01Array = @[@15.1, @60.1, @110.4, @10.0, @186.2, @197.2, @276.2];
+// data01Array = [[data01Array reverseObjectEnumerator] allObjects];
+// PNLineChartData *data01 = [PNLineChartData new];
+//
+// data01.rangeColors = @[
+// [[PNLineChartColorRange alloc] initWithRange:NSMakeRange(10, 30) color:[UIColor redColor]],
+// [[PNLineChartColorRange alloc] initWithRange:NSMakeRange(100, 200) color:[UIColor purpleColor]]
+// ];
+// data01.dataTitle = @"Alpha";
+// data01.color = PNFreshGreen;
+// data01.pointLabelColor = [UIColor blackColor];
+// data01.alpha = 0.3f;
+// data01.showPointLabel = YES;
+// data01.pointLabelFont = [UIFont fontWithName:@"Helvetica-Light" size:9.0];
+// data01.itemCount = data01Array.count;
+// data01.inflexionPointColor = PNRed;
+// data01.inflexionPointStyle = PNLineChartPointStyleTriangle;
+// data01.getData = ^(NSUInteger index) {
+// CGFloat yValue = [data01Array[index] floatValue];
+// return [PNLineChartDataItem dataItemWithY:yValue];
+// };
+
+ // Line Chart #2
+ NSArray *data02Array = @[@0.0, @180.1, @26.4, @202.2, @126.2, @167.2, @276.2];
+ PNLineChartData *data02 = [PNLineChartData new];
+ data02.dataTitle = @"Beta";
+ data02.pointLabelColor = [UIColor blackColor];
+ data02.color = PNTwitterColor;
+ data02.alpha = 0.5f;
+ data02.itemCount = data02Array.count;
+ data02.inflexionPointStyle = PNLineChartPointStyleCircle;
+ data02.getData = ^(NSUInteger index)
+ {
+ CGFloat yValue = [data02Array[index] floatValue];
+ return [PNLineChartDataItem dataItemWithY:yValue];
+ };
+
+ //self.lineChart.chartData = @[data01, data02];
+ self.lineChart.chartData = @[data02];
+ [self.lineChart.chartData enumerateObjectsUsingBlock:^(PNLineChartData *obj, NSUInteger idx, BOOL *stop)
+ {
+ obj.pointLabelColor = [UIColor blackColor];
+ }];
+
+
+ [self.lineChart strokeChart];
+ self.lineChart.delegate = self;
+
+
+ [self.view addSubview:self.lineChart];
+
+ self.lineChart.legendStyle = PNLegendItemStyleStacked;
+ self.lineChart.legendFont = [UIFont boldSystemFontOfSize:12.0f];
+ self.lineChart.legendFontColor = [UIColor redColor];
+
+ UIView *legend = [self.lineChart getLegendWithMaxWidth:320];
+ [legend setFrame:CGRectMake(30, 340, legend.frame.size.width, legend.frame.size.width)];
+ [self.view addSubview:legend];
+ }
+ else if ([self.title isEqualToString:@"Bar Chart"])
+ {
+ static NSNumberFormatter *barChartFormatter;
+ if (!barChartFormatter) {
+ barChartFormatter = [[NSNumberFormatter alloc] init];
+ barChartFormatter.numberStyle = NSNumberFormatterCurrencyStyle;
+ barChartFormatter.allowsFloats = NO;
+ barChartFormatter.maximumFractionDigits = 0;
+ }
+ self.titleLabel.text = @"Bar Chart";
+
+ self.barChart = [[PNBarChart alloc] initWithFrame:CGRectMake(0, 135.0, SCREEN_WIDTH, 200.0)];
+// self.barChart.showLabel = NO;
+ self.barChart.yLabelFormatter = ^(CGFloat yValue) {
+ return [barChartFormatter stringFromNumber:@(yValue)];
+ };
+
+ self.barChart.yChartLabelWidth = 20.0;
+ self.barChart.chartMarginLeft = 30.0;
+ self.barChart.chartMarginRight = 10.0;
+ self.barChart.chartMarginTop = 5.0;
+ self.barChart.chartMarginBottom = 10.0;
+
+
+ self.barChart.labelMarginTop = 5.0;
+ self.barChart.showChartBorder = YES;
+ [self.barChart setXLabels:@[@"2", @"3", @"4", @"5", @"2", @"3", @"4", @"5"]];
+// self.barChart.yLabels = @[@-10,@0,@10];
+// [self.barChart setYValues:@[@10000.0,@30000.0,@10000.0,@100000.0,@500000.0,@1000000.0,@1150000.0,@2150000.0]];
+ [self.barChart setYValues:@[@10.82, @1.88, @6.96, @33.93, @10.82, @1.88, @6.96, @33.93]];
+ [self.barChart setStrokeColors:@[PNGreen, PNGreen, PNRed, PNGreen, PNGreen, PNGreen, PNRed, PNGreen]];
+ self.barChart.isGradientShow = NO;
+ self.barChart.isShowNumbers = NO;
+
+ [self.barChart strokeChart];
+
+ self.barChart.delegate = self;
+
+ [self.view addSubview:self.barChart];
+ } else if ([self.title isEqualToString:@"Circle Chart"]) {
+ self.titleLabel.text = @"Circle Chart";
+
+
+ self.circleChart = [[PNCircleChart alloc] initWithFrame:CGRectMake(0, 150.0, SCREEN_WIDTH, 100.0)
+ total:@100
+ current:@60
+ clockwise:YES];
+
+ self.circleChart.backgroundColor = [UIColor whiteColor];
+
+ [self.circleChart setStrokeColor:[UIColor clearColor]];
+ [self.circleChart setStrokeColorGradientStart:[UIColor blueColor]];
+ [self.circleChart strokeChart];
+
+ [self.view addSubview:self.circleChart];
+ } else if ([self.title isEqualToString:@"Pie Chart"]) {
+ self.titleLabel.text = @"Pie Chart";
+ self.leftSwitch.hidden = NO;
+ self.rightSwitch.hidden = NO;
+ self.leftLabel.hidden = NO;
+ self.rightLabel.hidden = NO;
+ self.centerSwitch.hidden = NO;
+ self.centerSwitchLabel.hidden = NO;
+
+
+ NSArray *items = @[[PNPieChartDataItem dataItemWithValue:10 color:PNLightGreen],
+ [PNPieChartDataItem dataItemWithValue:20 color:PNFreshGreen description:@"WWDC"],
+ [PNPieChartDataItem dataItemWithValue:40 color:PNDeepGreen description:@"GOOG I/O"],
+ ];
+
+ self.pieChart = [[PNPieChart alloc] initWithFrame:CGRectMake((CGFloat) (SCREEN_WIDTH / 2.0 - 100), 135, 200.0, 200.0) items:items];
+ self.pieChart.descriptionTextColor = [UIColor whiteColor];
+ self.pieChart.descriptionTextFont = [UIFont fontWithName:@"Avenir-Medium" size:11.0];
+ self.pieChart.descriptionTextShadowColor = [UIColor clearColor];
+ self.pieChart.showAbsoluteValues = NO;
+ self.pieChart.showOnlyValues = NO;
+ [self.pieChart strokeChart];
+
+
+ self.pieChart.legendStyle = PNLegendItemStyleStacked;
+ self.pieChart.legendFont = [UIFont boldSystemFontOfSize:12.0f];
+
+ UIView *legend = [self.pieChart getLegendWithMaxWidth:200];
+ [legend setFrame:CGRectMake(130, 350, legend.frame.size.width, legend.frame.size.height)];
+ [self.view addSubview:legend];
+
+ [self.view addSubview:self.pieChart];
+ self.changeValueButton.hidden = YES;
+ } else if ([self.title isEqualToString:@"Scatter Chart"]) {
+ self.animationsSwitch.hidden = YES;
+
+ self.titleLabel.text = @"Scatter Chart";
+
+ self.scatterChart = [[PNScatterChart alloc] initWithFrame:CGRectMake((CGFloat) (SCREEN_WIDTH / 6.0 - 30), 135, 280, 200)];
+// self.scatterChart.yLabelFormat = @"xxx %1.1f";
+ [self.scatterChart setAxisXWithMinimumValue:20 andMaxValue:100 toTicks:6];
+ [self.scatterChart setAxisYWithMinimumValue:30 andMaxValue:50 toTicks:5];
+ [self.scatterChart setAxisXLabel:@[@"x1", @"x2", @"x3", @"x4", @"x5", @"x6"]];
+ [self.scatterChart setAxisYLabel:@[@"y1", @"y2", @"y3", @"y4", @"y5"]];
+
+ NSArray *data01Array = [self randomSetOfObjects];
+ PNScatterChartData *data01 = [PNScatterChartData new];
+ data01.strokeColor = PNGreen;
+ data01.fillColor = PNFreshGreen;
+ data01.size = 2;
+ data01.itemCount = [data01Array[0] count];
+ data01.inflexionPointStyle = PNScatterChartPointStyleCircle;
+ __block NSMutableArray *XAr1 = [NSMutableArray arrayWithArray:data01Array[0]];
+ __block NSMutableArray *YAr1 = [NSMutableArray arrayWithArray:data01Array[1]];
+
+ data01.getData = ^(NSUInteger index) {
+ CGFloat xValue;
+ xValue = [XAr1[index] floatValue];
+ CGFloat yValue = [YAr1[index] floatValue];
+ return [PNScatterChartDataItem dataItemWithX:xValue AndWithY:yValue];
+ };
+
+ [self.scatterChart setup];
+ self.scatterChart.chartData = @[data01];
+/***
+ this is for drawing line to compare
+ CGPoint start = CGPointMake(20, 35);
+ CGPoint end = CGPointMake(80, 45);
+ [self.scatterChart drawLineFromPoint:start ToPoint:end WithLineWith:2 AndWithColor:PNBlack];
+***/
+ self.scatterChart.delegate = self;
+ self.changeValueButton.hidden = YES;
+ [self.view addSubview:self.scatterChart];
+ } else if ([self.title isEqualToString:@"Radar Chart"]) {
+ self.titleLabel.text = @"Radar Chart";
+
+ self.leftSwitch.hidden = NO;
+ self.rightSwitch.hidden = NO;
+ self.leftLabel.hidden = NO;
+ self.rightLabel.hidden = NO;
+ self.leftLabel.text = @"Labels Style";
+ self.rightLabel.text = @"Graduation";
+
+
+ NSArray *items = @[[PNRadarChartDataItem dataItemWithValue:3 description:@"Art"],
+ [PNRadarChartDataItem dataItemWithValue:2 description:@"Math"],
+ [PNRadarChartDataItem dataItemWithValue:8 description:@"Sports"],
+ [PNRadarChartDataItem dataItemWithValue:5 description:@"Literature"],
+ [PNRadarChartDataItem dataItemWithValue:4 description:@"Other"],
+ ];
+ self.radarChart = [[PNRadarChart alloc] initWithFrame:CGRectMake(0, 135.0, SCREEN_WIDTH, 300.0) items:items valueDivider:1];
+
+ self.radarChart.plotColor = [UIColor redColor];
+
+ [self.radarChart strokeChart];
+
+ [self.view addSubview:self.radarChart];
+ }
+
+}
+
+
+- (void)userClickedOnLineKeyPoint:(CGPoint)point lineIndex:(NSInteger)lineIndex pointIndex:(NSInteger)pointIndex {
+ NSLog(@"Click Key on line %f, %f line index is %d and point index is %d", point.x, point.y, (int) lineIndex, (int) pointIndex);
+}
+
+- (void)userClickedOnLinePoint:(CGPoint)point lineIndex:(NSInteger)lineIndex {
+ NSLog(@"Click on line %f, %f, line index is %d", point.x, point.y, (int) lineIndex);
+}
+
+
+- (IBAction)changeValue:(id)sender {
+
+ if ([self.title isEqualToString:@"Line Chart"]) {
+
+ // Line Chart #1
+ NSArray *data01Array = @[@(arc4random() % 300), @(arc4random() % 300), @(arc4random() % 300), @(arc4random() % 300), @(arc4random() % 300), @(arc4random() % 300), @(arc4random() % 300)];
+ PNLineChartData *data01 = [PNLineChartData new];
+ data01.color = PNFreshGreen;
+ data01.itemCount = data01Array.count;
+ data01.inflexionPointColor = PNRed;
+ data01.inflexionPointStyle = PNLineChartPointStyleTriangle;
+ data01.getData = ^(NSUInteger index) {
+ CGFloat yValue = [data01Array[index] floatValue];
+ return [PNLineChartDataItem dataItemWithY:yValue];
+ };
+
+ // Line Chart #2
+ NSArray *data02Array = @[@(arc4random() % 300), @(arc4random() % 300), @(arc4random() % 300), @(arc4random() % 300), @(arc4random() % 300), @(arc4random() % 300), @(arc4random() % 300)];
+ PNLineChartData *data02 = [PNLineChartData new];
+ data02.color = PNTwitterColor;
+ data02.itemCount = data02Array.count;
+ data02.inflexionPointStyle = PNLineChartPointStyleSquare;
+ data02.getData = ^(NSUInteger index) {
+ CGFloat yValue = [data02Array[index] floatValue];
+ return [PNLineChartDataItem dataItemWithY:yValue];
+ };
+
+ [self.lineChart setXLabels:@[@"DEC 1", @"DEC 2", @"DEC 3", @"DEC 4", @"DEC 5", @"DEC 6", @"DEC 7"]];
+ [self.lineChart updateChartData:@[data01, data02]];
+
+ } else if ([self.title isEqualToString:@"Bar Chart"]) {
+ [self.barChart setXLabels:@[@"Jan 1", @"Jan 2", @"Jan 3", @"Jan 4", @"Jan 5", @"Jan 6", @"Jan 7"]];
+ [self.barChart updateChartData:@[@(arc4random() % 30), @(arc4random() % 30), @(arc4random() % 30), @(arc4random() % 30), @(arc4random() % 30), @(arc4random() % 30), @(arc4random() % 30)]];
+ } else if ([self.title isEqualToString:@"Circle Chart"]) {
+ [self.circleChart updateChartByCurrent:@(arc4random() % 100)];
+ } else if ([self.title isEqualToString:@"Scatter Chart"]) {
+ // will be code soon.
+ }
+
+}
+
+- (void)userClickedOnBarAtIndex:(NSInteger)barIndex {
+
+ NSLog(@"Click on bar %@", @(barIndex));
+
+ PNBar *bar = self.barChart.bars[(NSUInteger) barIndex];
+
+ CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"transform.scale"];
+
+ animation.fromValue = @1.0;
+ animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
+ animation.toValue = @1.1;
+ animation.duration = 0.2;
+ animation.repeatCount = 0;
+ animation.autoreverses = YES;
+ animation.removedOnCompletion = YES;
+ animation.fillMode = kCAFillModeForwards;
+
+ [bar.layer addAnimation:animation forKey:@"Float"];
+}
+
+/* this function is used only for creating random points */
+- (NSArray *)randomSetOfObjects {
+ NSMutableArray *array = [NSMutableArray array];
+ NSString *LabelFormat = @"%1.f";
+ NSMutableArray *XAr = [NSMutableArray array];
+ NSMutableArray *YAr = [NSMutableArray array];
+ for (int i = 0; i < 25; i++) {
+ [XAr addObject:[NSString stringWithFormat:LabelFormat, (((double) arc4random() / ARC4RANDOM_MAX) * (self.scatterChart.AxisX_maxValue - self.scatterChart.AxisX_minValue) + self.scatterChart.AxisX_minValue)]];
+ [YAr addObject:[NSString stringWithFormat:LabelFormat, (((double) arc4random() / ARC4RANDOM_MAX) * (self.scatterChart.AxisY_maxValue - self.scatterChart.AxisY_minValue) + self.scatterChart.AxisY_minValue)]];
+ }
+ [array addObject:XAr];
+ [array addObject:YAr];
+ return array;
+}
+
+- (IBAction)rightSwitchChanged:(id)sender
+{
+ if ([self.title isEqualToString:@"Pie Chart"]) {
+ UISwitch *showLabels = (UISwitch *) sender;
+ self.pieChart.showOnlyValues = !showLabels.on;
+ [self.pieChart strokeChart];
+ }
+ if ([self.title isEqualToString:@"Radar Chart"]) {
+ UISwitch *showLabels = (UISwitch *) sender;
+ self.radarChart.isShowGraduation = !showLabels.on;
+ [self.radarChart strokeChart];
+ } else if ([self.title isEqualToString:@"Line Chart"])
+ {
+ UISwitch *showLabels = (UISwitch *) sender;
+ self.lineChart.showSmoothLines = showLabels.on;
+ NSLog(@"self.lineChart.showSmoothLines : %d", self.lineChart.showSmoothLines);
+ [self.lineChart strokeChart];
+ }
+}
+
+- (IBAction)centerSwitchChanged:(id)sender {
+ if (self.pieChart) {
+ [self.pieChart setEnableMultipleSelection:self.centerSwitch.on];
+ [self.pieChart strokeChart];
+ }
+
+}
+
+- (IBAction)leftSwitchChanged:(id)sender {
+ if ([self.title isEqualToString:@"Pie Chart"]) {
+ UISwitch *showRelative = (UISwitch *) sender;
+ self.pieChart.showAbsoluteValues = !showRelative.on;
+ [self.pieChart strokeChart];
+ } else if ([self.title isEqualToString:@"Radar Chart"]) {
+ UISwitch *showRelative = (UISwitch *) sender;
+ if (showRelative.on) {
+ self.radarChart.labelStyle = PNRadarChartLabelStyleHorizontal;
+ } else {
+ self.radarChart.labelStyle = PNRadarChartLabelStyleCircle;
+ }
+ [self.radarChart strokeChart];
+
+ } else if ([self.title isEqualToString:@"Line Chart"]) {
+ UISwitch *senderSwitch = (UISwitch *) sender;
+ if (senderSwitch.isOn) {
+ UIColor *lineChartLabelColor = [UIColor cyanColor];
+ UIColor *darkBackgroundColor = [UIColor colorWithRed:0.47 green:0.47 blue:0.47 alpha:1.0];
+
+ UIColor *gridLinesForDarkBackgroundColor = [UIColor colorWithRed:242 / 255.0 green:242 / 255.0 blue:242 / 255.0 alpha:1.0];
+ self.lineChart.backgroundColor = darkBackgroundColor;
+ self.lineChart.yGridLinesColor = gridLinesForDarkBackgroundColor;
+ self.lineChart.showYGridLines = YES;
+ self.lineChart.yLabelColor = lineChartLabelColor;
+ self.lineChart.xLabelColor = lineChartLabelColor;
+ [self.lineChart.chartData enumerateObjectsUsingBlock:^(PNLineChartData *obj, NSUInteger idx, BOOL *stop) {
+ obj.pointLabelColor = lineChartLabelColor;
+ }];
+ } else {
+ self.lineChart.backgroundColor = [UIColor whiteColor];
+ self.lineChart.yGridLinesColor = [UIColor grayColor];
+ self.lineChart.yLabelColor = [UIColor blackColor];
+ self.lineChart.xLabelColor = [UIColor blackColor];
+ [self.lineChart.chartData enumerateObjectsUsingBlock:^(PNLineChartData *obj, NSUInteger idx, BOOL *stop) {
+ obj.pointLabelColor = [UIColor blackColor];
+ }];
+ }
+ [self.lineChart setXLabels:@[@"DEC 1", @"DEC 2", @"DEC 3", @"DEC 4", @"DEC 5", @"DEC 6", @"DEC 7"]];
+ [self.lineChart setYLabels:@[
+ @"0 min",
+ @"50 min",
+ @"100 min",
+ @"150 min",
+ @"200 min",
+ @"250 min",
+ @"300 min",
+ ]
+ ];
+ [self.lineChart strokeChart];
+ }
+}
+
+- (IBAction)animationsSwitchChanged:(UISwitch *)sender {
+ if ([self.title isEqualToString:@"Circle Chart"]) {
+ self.circleChart.displayAnimated = sender.on;
+ [self.circleChart strokeChart];
+ } else if ([self.title isEqualToString:@"Line Chart"]) {
+ self.lineChart.displayAnimated = sender.on;
+ [self.lineChart strokeChart];
+ } else if ([self.title isEqualToString:@"Bar Chart"]) {
+ self.barChart.displayAnimated = sender.on;
+ [self.barChart strokeChart];
+ } else if ([self.title isEqualToString:@"Pie Chart"]) {
+ self.pieChart.displayAnimated = sender.on;
+ [self.pieChart strokeChart];
+ } else if ([self.title isEqualToString:@"Radar Chart"]) {
+ self.radarChart.displayAnimated = sender.on;
+ [self.radarChart strokeChart];
+ }
+}
+
+@end
diff --git a/PNChartdemo/PNChartdemo/PCChartsTableViewController.h b/PNChartdemo/PNChartdemo/PCChartsTableViewController.h
new file mode 100755
index 0000000..bc25f8e
--- /dev/null
+++ b/PNChartdemo/PNChartdemo/PCChartsTableViewController.h
@@ -0,0 +1,13 @@
+//
+// PCChartsTableViewController.h
+// PNChartDemo
+//
+// Created by kevinzhow on 13-12-1.
+// Copyright (c) 2013��� kevinzhow. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+
+@interface PCChartsTableViewController : UITableViewController
+
+@end
diff --git a/PNChartdemo/PNChartdemo/PCChartsTableViewController.m b/PNChartdemo/PNChartdemo/PCChartsTableViewController.m
new file mode 100755
index 0000000..39d923e
--- /dev/null
+++ b/PNChartdemo/PNChartdemo/PCChartsTableViewController.m
@@ -0,0 +1,56 @@
+//
+// PCChartsTableViewController.m
+// PNChartDemo
+//
+// Created by kevinzhow on 13-12-1.
+// Copyright (c) 2013��� kevinzhow. All rights reserved.
+//
+
+#import "PCChartsTableViewController.h"
+
+@implementation PCChartsTableViewController
+
+// In a story board-based application, you will often want to do a little preparation before navigation
+- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
+{
+ // Get the new view controller using [segue destinationViewController].
+ // Pass the selected object to the new view controller.
+
+ UIViewController * viewController = [segue destinationViewController];
+
+ if ([segue.identifier isEqualToString:@"lineChart"]) {
+
+ //Add line chart
+
+ viewController.title = @"Line Chart";
+
+ } else if ([segue.identifier isEqualToString:@"barChart"])
+ {
+ //Add bar chart
+
+ viewController.title = @"Bar Chart";
+ } else if ([segue.identifier isEqualToString:@"circleChart"])
+ {
+ //Add circle chart
+
+ viewController.title = @"Circle Chart";
+
+ } else if ([segue.identifier isEqualToString:@"pieChart"])
+ {
+ //Add pie chart
+
+ viewController.title = @"Pie Chart";
+ } else if ([segue.identifier isEqualToString:@"scatterChart"])
+ {
+ //Add scatter chart
+
+ viewController.title = @"Scatter Chart";
+ }else if ([segue.identifier isEqualToString:@"radarChart"])
+ {
+ //Add radar chart
+
+ viewController.title = @"Radar Chart";
+ }
+}
+
+@end
diff --git a/PNChartdemo/PNChartdemo/PNChart/PNBar.h b/PNChartdemo/PNChartdemo/PNChart/PNBar.h
new file mode 100755
index 0000000..68e6b0b
--- /dev/null
+++ b/PNChartdemo/PNChartdemo/PNChart/PNBar.h
@@ -0,0 +1,37 @@
+//
+// PNBar.h
+// PNChartDemo
+//
+// Created by kevin on 11/7/13.
+// Copyright (c) 2013��� kevinzhow. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+#import <QuartzCore/QuartzCore.h>
+
+@interface PNBar : UIView
+
+
+- (void)rollBack;
+
+@property (nonatomic) float grade;
+@property (nonatomic) float maxDivisor;
+
+@property (nonatomic) CAShapeLayer *chartLine;
+@property (nonatomic) UIColor *barColor;
+@property (nonatomic) UIColor *barColorGradientStart;
+@property (nonatomic) CGFloat barRadius;
+@property (nonatomic) CAShapeLayer *gradientMask;
+
+@property (nonatomic) CAShapeLayer *gradeLayer;
+@property (nonatomic) CATextLayer* textLayer;
+
+/** Text color for all bars in the chart. */
+@property (nonatomic) UIColor * labelTextColor;
+
+@property (nonatomic, assign) BOOL isNegative; //!< ���������������
+@property (nonatomic, assign) BOOL isShowNumber; //!< ������������numbers
+
+/** Display the bar with or without animation. Default is YES. **/
+@property (nonatomic) BOOL displayAnimated;
+@end
diff --git a/PNChartdemo/PNChartdemo/PNChart/PNBar.m b/PNChartdemo/PNChartdemo/PNChart/PNBar.m
new file mode 100755
index 0000000..8ea5fc9
--- /dev/null
+++ b/PNChartdemo/PNChartdemo/PNChart/PNBar.m
@@ -0,0 +1,288 @@
+//
+// PNBar.m
+// PNChartDemo
+//
+// Created by kevin on 11/7/13.
+// Copyright (c) 2013��� kevinzhow. All rights reserved.
+//
+
+#import "PNBar.h"
+#import "PNColor.h"
+#import <CoreText/CoreText.h>
+
+@interface PNBar ()
+
+@property (nonatomic) float copyGrade;
+
+@end
+
+@implementation PNBar
+
+- (id)initWithFrame:(CGRect)frame
+{
+ self = [super initWithFrame:frame];
+
+ if (self) {
+ _chartLine = [CAShapeLayer layer];
+ _chartLine.lineCap = kCALineCapButt;
+ _chartLine.fillColor = [[UIColor whiteColor] CGColor];
+ _chartLine.lineWidth = self.frame.size.width;
+ _chartLine.strokeEnd = 0.0;
+ self.clipsToBounds = YES;
+ [self.layer addSublayer:_chartLine];
+ self.barRadius = 2.0;
+ }
+
+ return self;
+}
+
+-(void)setBarRadius:(CGFloat)barRadius
+{
+ _barRadius = barRadius;
+ self.layer.cornerRadius = _barRadius;
+}
+
+
+- (void)setGrade:(float)grade
+{
+ _copyGrade = grade;
+ CGFloat startPosY = (1 - grade) * self.frame.size.height;
+
+ UIBezierPath *progressline = [UIBezierPath bezierPath];
+
+ [progressline moveToPoint:CGPointMake(self.frame.size.width / 2.0, self.frame.size.height)];
+ [progressline addLineToPoint:CGPointMake(self.frame.size.width / 2.0, startPosY)];
+
+ [progressline setLineWidth:1.0];
+ [progressline setLineCapStyle:kCGLineCapSquare];
+ [self addAnimationIfNeededWithProgressLine:progressline];
+
+
+ if (_barColor) {
+ _chartLine.strokeColor = [_barColor CGColor];
+ }
+ else {
+ _chartLine.strokeColor = [PNGreen CGColor];
+ }
+
+ if (_grade) {
+
+ _chartLine.path = progressline.CGPath;
+
+ if (_barColorGradientStart) {
+
+ // Add gradient
+ self.gradientMask.path = progressline.CGPath;
+
+ CABasicAnimation* opacityAnimation = [self fadeAnimation];
+ [self.textLayer addAnimation:opacityAnimation forKey:nil];
+
+ }
+
+ }else{
+ _chartLine.strokeEnd = 1.0;
+
+ _chartLine.path = progressline.CGPath;
+ // Check if user wants to add a gradient from the start color to the bar color
+ if (_barColorGradientStart) {
+
+ // Add gradient
+ self.gradientMask = [CAShapeLayer layer];
+ self.gradientMask.fillColor = [[UIColor clearColor] CGColor];
+ self.gradientMask.strokeColor = [[UIColor blackColor] CGColor];
+ self.gradientMask.lineWidth = self.frame.size.width;
+ self.gradientMask.frame = CGRectMake(0, 0, self.bounds.size.width, self.bounds.size.height);
+ self.gradientMask.path = progressline.CGPath;
+
+ CAGradientLayer *gradientLayer = [CAGradientLayer layer];
+ gradientLayer.startPoint = CGPointMake(0.0,0.0);
+ gradientLayer.endPoint = CGPointMake(1.0 ,0.0);
+ gradientLayer.frame = CGRectMake(0, 0, self.bounds.size.width, self.bounds.size.height);
+ UIColor *middleColor = [UIColor colorWithWhite:255/255 alpha:0.8];
+ NSArray *colors = @[
+ (__bridge id)self.barColor.CGColor,
+ (__bridge id)middleColor.CGColor,
+ (__bridge id)self.barColor.CGColor
+ ];
+ gradientLayer.colors = colors;
+
+ [gradientLayer setMask:self.gradientMask];
+
+ [_chartLine addSublayer:gradientLayer];
+
+ self.gradientMask.strokeEnd = 1.0;
+
+ CABasicAnimation* opacityAnimation = [self fadeAnimation];
+ [self.textLayer addAnimation:opacityAnimation forKey:nil];
+ }
+ }
+
+ _grade = grade;
+
+}
+
+
+- (void)rollBack
+{
+ [UIView animateWithDuration:0.3 delay:0.0 options:UIViewAnimationOptionCurveEaseOut animations: ^{
+ _chartLine.strokeColor = [UIColor clearColor].CGColor;
+ } completion:nil];
+}
+
+- (void)setBarColorGradientStart:(UIColor *)barColorGradientStart
+{
+ // Set gradient color, remove any existing sublayer first
+ for (CALayer *sublayer in [_chartLine sublayers]) {
+ [sublayer removeFromSuperlayer];
+ }
+ _barColorGradientStart = barColorGradientStart;
+
+ [self setGrade:_grade];
+
+}
+
+// Only override drawRect: if you perform custom drawing.
+// An empty implementation adversely affects performance during animation.
+- (void)drawRect:(CGRect)rect
+{
+ CGContextRef context = UIGraphicsGetCurrentContext();
+
+ CGContextSetFillColorWithColor(context, self.backgroundColor.CGColor);
+ CGContextFillRect(context, rect);
+}
+
+
+// add number display on the top of bar
+-(CGPathRef)gradePath:(CGRect)rect
+{
+ return nil;
+}
+
+-(CATextLayer*)textLayer
+{
+ if (!_textLayer) {
+ _textLayer = [[CATextLayer alloc]init];
+ [_textLayer setString:@"0"];
+ [_textLayer setAlignmentMode:kCAAlignmentCenter];
+ [_textLayer setForegroundColor:[_labelTextColor CGColor]];
+ _textLayer.hidden = YES;
+
+ }
+
+ return _textLayer;
+}
+
+- (void) setLabelTextColor:(UIColor *)labelTextColor {
+ _labelTextColor = labelTextColor;
+ [_textLayer setForegroundColor:[_labelTextColor CGColor]];
+}
+
+-(void)setGradeFrame:(CGFloat)grade startPosY:(CGFloat)startPosY
+{
+ CGFloat textheigt = self.bounds.size.height*self.grade;
+
+ CGFloat topSpace = self.bounds.size.height * (1-self.grade);
+ CGFloat textWidth = self.bounds.size.width;
+
+ [_chartLine addSublayer:self.textLayer];
+ [self.textLayer setFontSize:18.0];
+
+ [self.textLayer setString:[[NSString alloc]initWithFormat:@"%0.f",grade*self.maxDivisor]];
+
+ CGSize size = CGSizeMake(320,2000); //������������������������
+ NSDictionary *attributes = @{NSFontAttributeName:[UIFont systemFontOfSize:18.0]};
+ size = [self.textLayer.string boundingRectWithSize:size options:NSStringDrawingUsesLineFragmentOrigin attributes:attributes context:nil].size;
+ float verticalY ;
+
+ if (size.height>=textheigt) {
+
+ verticalY = topSpace - size.height;
+ } else {
+ verticalY = topSpace + (textheigt-size.height)/2.0;
+ }
+
+ [self.textLayer setFrame:CGRectMake((textWidth-size.width)/2.0,verticalY, size.width,size.height)];
+ self.textLayer.contentsScale = [UIScreen mainScreen].scale;
+
+}
+
+- (void)setIsShowNumber:(BOOL)isShowNumber{
+ if (isShowNumber) {
+ self.textLayer.hidden = NO;
+ [self setGradeFrame:_copyGrade startPosY:0];
+ }else{
+ self.textLayer.hidden = YES;
+ }
+}
+- (void)setIsNegative:(BOOL)isNegative{
+ if (isNegative) {
+ [self.textLayer setString:[[NSString alloc]initWithFormat:@"- %1.f",_grade*self.maxDivisor]];
+
+ CGSize size = CGSizeMake(320,2000); //������������������������
+ NSDictionary *attributes = @{NSFontAttributeName:[UIFont systemFontOfSize:18.0]};
+ size = [self.textLayer.string boundingRectWithSize:size options:NSStringDrawingUsesLineFragmentOrigin attributes:attributes context:nil].size;
+ CGRect frame = self.textLayer.frame;
+ frame.origin.x = (self.bounds.size.width - size.width)/2.0;
+ frame.size = size;
+ self.textLayer.frame = frame;
+
+ [self addRotationAnimationIfNeeded];
+ }
+}
+
+-(CABasicAnimation*)fadeAnimation
+{
+ CABasicAnimation* fadeAnimation = nil;
+ if (self.displayAnimated) {
+ fadeAnimation = [CABasicAnimation animationWithKeyPath:@"opacity"];
+ fadeAnimation.fromValue = [NSNumber numberWithFloat:0.0];
+ fadeAnimation.toValue = [NSNumber numberWithFloat:1.0];
+ fadeAnimation.duration = 2.0;
+ }
+ return fadeAnimation;
+}
+
+-(void)addAnimationIfNeededWithProgressLine:(UIBezierPath *)progressline
+{
+ if (self.displayAnimated) {
+ CABasicAnimation *pathAnimation = nil;
+
+ if (_grade) {
+ pathAnimation = [CABasicAnimation animationWithKeyPath:@"path"];
+ pathAnimation.fromValue = (id)_chartLine.path;
+ pathAnimation.toValue = (id)[progressline CGPath];
+ pathAnimation.duration = 0.5f;
+ pathAnimation.autoreverses = NO;
+ pathAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
+ [_chartLine addAnimation:pathAnimation forKey:@"animationKey"];
+ }
+ else {
+ pathAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
+ pathAnimation.duration = 1.0;
+ pathAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
+ pathAnimation.fromValue = @0.0f;
+ pathAnimation.toValue = @1.0f;
+ [_chartLine addAnimation:pathAnimation forKey:@"strokeEndAnimation"];
+ }
+
+ [self.gradientMask addAnimation:pathAnimation forKey:@"animationKey"];
+ }
+}
+
+- (void)addRotationAnimationIfNeeded
+{
+ if (self.displayAnimated) {
+ CABasicAnimation* rotationAnimation;
+ rotationAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
+ rotationAnimation.toValue = [NSNumber numberWithFloat: M_PI];
+ [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
+ rotationAnimation.duration = 0.1;
+ rotationAnimation.repeatCount = 0;//������������������������������������
+ rotationAnimation.cumulative = NO;
+ rotationAnimation.removedOnCompletion = NO;
+ rotationAnimation.fillMode = kCAFillModeForwards;
+ [self.textLayer addAnimation:rotationAnimation forKey:@"Rotation"];
+ }
+}
+
+@end
diff --git a/PNChartdemo/PNChartdemo/PNChart/PNBarChart.h b/PNChartdemo/PNChartdemo/PNChart/PNBarChart.h
new file mode 100755
index 0000000..e628c08
--- /dev/null
+++ b/PNChartdemo/PNChartdemo/PNChart/PNBarChart.h
@@ -0,0 +1,123 @@
+//
+// PNBarChart.h
+// PNChartDemo
+//
+// Created by kevin on 11/7/13.
+// Copyright (c) 2013��� kevinzhow. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+#import "PNGenericChart.h"
+#import "PNChartDelegate.h"
+#import "PNBar.h"
+
+#define kXLabelMargin 15
+#define kYLabelMargin 15
+#define kYLabelHeight 11
+#define kXLabelHeight 20
+
+typedef NSString *(^PNYLabelFormatter)(CGFloat yLabelValue);
+
+@interface PNBarChart : PNGenericChart
+
+/**
+ * Draws the chart in an animated fashion.
+ */
+- (void)strokeChart;
+
+@property (nonatomic) NSArray *xLabels;
+@property (nonatomic) NSArray *yLabels;
+@property (nonatomic) NSArray *yValues;
+
+@property (nonatomic) NSMutableArray * bars;
+
+@property (nonatomic) CGFloat xLabelWidth;
+@property (nonatomic) float yValueMax;
+@property (nonatomic) UIColor *strokeColor;
+@property (nonatomic) NSArray *strokeColors;
+
+
+/** Update Values. */
+- (void)updateChartData:(NSArray *)data;
+
+/** Changes chart margin. */
+@property (nonatomic) CGFloat yChartLabelWidth;
+
+/** Formats the ylabel text. */
+@property (copy) PNYLabelFormatter yLabelFormatter;
+
+/** Prefix to y label values, none if unset. */
+@property (nonatomic) NSString *yLabelPrefix;
+
+/** Suffix to y label values, none if unset. */
+@property (nonatomic) NSString *yLabelSuffix;
+
+@property (nonatomic) CGFloat chartMarginLeft;
+@property (nonatomic) CGFloat chartMarginRight;
+@property (nonatomic) CGFloat chartMarginTop;
+@property (nonatomic) CGFloat chartMarginBottom;
+
+/** Controls whether labels should be displayed. */
+@property (nonatomic) BOOL showLabel;
+
+/** Controls whether the chart border line should be displayed. */
+@property (nonatomic) BOOL showChartBorder;
+
+@property (nonatomic) UIColor *chartBorderColor;
+
+/** Controls whether the chart Horizontal separator should be displayed. */
+@property (nonatomic, assign) BOOL showLevelLine;
+
+/** Chart bottom border, co-linear with the x-axis. */
+@property (nonatomic) CAShapeLayer * chartBottomLine;
+
+/** Chart bottom border, level separator-linear with the x-axis. */
+@property (nonatomic) CAShapeLayer * chartLevelLine;
+
+/** Chart left border, co-linear with the y-axis. */
+@property (nonatomic) CAShapeLayer * chartLeftLine;
+
+/** Corner radius for all bars in the chart. */
+@property (nonatomic) CGFloat barRadius;
+
+/** Width of all bars in the chart. */
+@property (nonatomic) CGFloat barWidth;
+
+@property (nonatomic) CGFloat labelMarginTop;
+
+/** Background color of all bars in the chart. */
+@property (nonatomic) UIColor * barBackgroundColor;
+
+/** Text color for all bars in the chart. */
+@property (nonatomic) UIColor * labelTextColor;
+
+/** Font for all bars in the chart. */
+@property (nonatomic) UIFont * labelFont;
+
+/** How many labels on the x-axis to skip in between displaying labels. */
+@property (nonatomic) NSInteger xLabelSkip;
+
+/** How many labels on the y-axis to skip in between displaying labels. */
+@property (nonatomic) NSInteger yLabelSum;
+
+/** The maximum for the range of values to display on the y-axis. */
+@property (nonatomic) CGFloat yMaxValue;
+
+/** The minimum for the range of values to display on the y-axis. */
+@property (nonatomic) CGFloat yMinValue;
+
+/** Controls whether each bar should have a gradient fill. */
+@property (nonatomic) UIColor *barColorGradientStart;
+
+/** Controls whether text for x-axis be straight or rotate 45 degree. */
+@property (nonatomic) BOOL rotateForXAxisText;
+
+@property (nonatomic, weak) id<PNChartDelegate> delegate;
+
+/**whether show gradient bar*/
+@property (nonatomic, assign) BOOL isGradientShow;
+
+/** whether show numbers*/
+@property (nonatomic, assign) BOOL isShowNumbers;
+
+@end
diff --git a/PNChartdemo/PNChartdemo/PNChart/PNBarChart.m b/PNChartdemo/PNChartdemo/PNChart/PNBarChart.m
new file mode 100755
index 0000000..50e035c
--- /dev/null
+++ b/PNChartdemo/PNChartdemo/PNChart/PNBarChart.m
@@ -0,0 +1,459 @@
+//
+// PNBarChart.m
+// PNChartDemo
+//
+// Created by kevin on 11/7/13.
+// Copyright (c) 2013��� kevinzhow. All rights reserved.
+//
+
+#import "PNBarChart.h"
+#import "PNColor.h"
+#import "PNChartLabel.h"
+
+@interface PNBarChart () {
+ NSMutableArray *_xChartLabels;
+ NSMutableArray *_yChartLabels;
+}
+
+- (UIColor *)barColorAtIndex:(NSUInteger)index;
+
+@end
+
+@implementation PNBarChart
+
+- (id)initWithCoder:(NSCoder *)aDecoder
+{
+ self = [super initWithCoder:aDecoder];
+
+ if (self) {
+ [self setupDefaultValues];
+ }
+ return self;
+}
+
+- (id)initWithFrame:(CGRect)frame
+{
+ self = [super initWithFrame:frame];
+
+ if (self) {
+ [self setupDefaultValues];
+ }
+
+ return self;
+}
+
+- (void)setupDefaultValues
+{
+ [super setupDefaultValues];
+ self.backgroundColor = [UIColor whiteColor];
+ self.clipsToBounds = YES;
+ _showLabel = YES;
+ _barBackgroundColor = PNLightGrey;
+ _labelTextColor = [UIColor grayColor];
+ _labelFont = [UIFont systemFontOfSize:11.0f];
+ _xChartLabels = [NSMutableArray array];
+ _yChartLabels = [NSMutableArray array];
+ _bars = [NSMutableArray array];
+ _xLabelSkip = 1;
+ _yLabelSum = 4;
+ _labelMarginTop = 2;
+ _chartMarginLeft = 25.0;
+ _chartMarginRight = 25.0;
+ _chartMarginTop = 25.0;
+ _chartMarginBottom = 25.0;
+ _barRadius = 2.0;
+ _showChartBorder = NO;
+ _chartBorderColor = PNLightGrey;
+ _showLevelLine = NO;
+ _yChartLabelWidth = 18;
+ _rotateForXAxisText = false;
+ _isGradientShow = YES;
+ _isShowNumbers = YES;
+ _yLabelPrefix = @"";
+ _yLabelSuffix = @"";
+ _yLabelFormatter = ^(CGFloat yValue){
+ return [NSString stringWithFormat:@"%1.f",yValue];
+ };
+}
+
+- (void)setYValues:(NSArray *)yValues
+{
+ _yValues = yValues;
+ //make the _yLabelSum value dependant of the distinct values of yValues to avoid duplicates on yAxis
+
+ if (_showLabel) {
+ [self __addYCoordinateLabelsValues];
+ } else {
+ [self processYMaxValue];
+ }
+}
+
+- (void)processYMaxValue {
+ NSArray *yAxisValues = _yLabels ? _yLabels : _yValues;
+ _yLabelSum = _yLabels ? _yLabels.count - 1 :_yLabelSum;
+ if (_yMaxValue) {
+ _yValueMax = _yMaxValue;
+ } else {
+ [self getYValueMax:yAxisValues];
+ }
+
+ if (_yLabelSum==4) {
+ _yLabelSum = yAxisValues.count;
+ (_yLabelSum % 2 == 0) ? _yLabelSum : _yLabelSum++;
+ }
+}
+
+#pragma mark - Private Method
+#pragma mark - Add Y Label
+- (void)__addYCoordinateLabelsValues{
+
+ [self viewCleanupForCollection:_yChartLabels];
+
+ [self processYMaxValue];
+
+ float sectionHeight = (self.frame.size.height - _chartMarginTop - _chartMarginBottom - kXLabelHeight) / _yLabelSum;
+
+ for (int i = 0; i <= _yLabelSum; i++) {
+ NSString *labelText;
+ if (_yLabels) {
+ float yAsixValue = [_yLabels[_yLabels.count - i - 1] floatValue];
+ labelText= _yLabelFormatter(yAsixValue);
+ } else {
+ labelText = _yLabelFormatter((float)_yValueMax * ( (_yLabelSum - i) / (float)_yLabelSum ));
+ }
+
+ PNChartLabel *label = [[PNChartLabel alloc] initWithFrame:CGRectZero];
+ label.font = _labelFont;
+ label.textColor = _labelTextColor;
+ [label setTextAlignment:NSTextAlignmentRight];
+ label.text = [NSString stringWithFormat:@"%@%@%@", _yLabelPrefix, labelText, _yLabelSuffix];
+
+ [self addSubview:label];
+
+ label.frame = (CGRect){0, sectionHeight * i + _chartMarginTop - kYLabelHeight/2.0 + kXLabelHeight + _labelMarginTop, _yChartLabelWidth, kYLabelHeight};
+
+ [_yChartLabels addObject:label];
+ }
+}
+
+-(void)updateChartData:(NSArray *)data{
+ self.yValues = data;
+ [self updateBar];
+}
+
+- (void)getYValueMax:(NSArray *)yLabels
+{
+ CGFloat max = [[yLabels valueForKeyPath:@"@max.floatValue"] floatValue];
+
+ //ensure max is even
+ _yValueMax = max ;
+
+ if (_yValueMax == 0) {
+ _yValueMax = _yMinValue;
+ }
+}
+
+- (void)setXLabels:(NSArray *)xLabels
+{
+ _xLabels = xLabels;
+
+ if (_xChartLabels) {
+ [self viewCleanupForCollection:_xChartLabels];
+ }else{
+ _xChartLabels = [NSMutableArray new];
+ }
+
+ _xLabelWidth = (self.frame.size.width - _chartMarginLeft - _chartMarginRight) / [xLabels count];
+
+ if (_showLabel) {
+ int labelAddCount = 0;
+ for (int index = 0; index < _xLabels.count; index++) {
+ labelAddCount += 1;
+
+ if (labelAddCount == _xLabelSkip) {
+ NSString *labelText = [_xLabels[index] description];
+ PNChartLabel * label = [[PNChartLabel alloc] initWithFrame:CGRectMake(0, 0, _xLabelWidth, kXLabelHeight)];
+ label.font = _labelFont;
+ label.textColor = _labelTextColor;
+ [label setTextAlignment:NSTextAlignmentCenter];
+ label.text = labelText;
+ //[label sizeToFit];
+ CGFloat labelXPosition;
+ if (_rotateForXAxisText){
+ label.transform = CGAffineTransformMakeRotation(M_PI / 4);
+ labelXPosition = (index * _xLabelWidth + _chartMarginLeft + _xLabelWidth /1.5);
+ }
+ else{
+ labelXPosition = (index * _xLabelWidth + _chartMarginLeft + _xLabelWidth /2.0 );
+ }
+ label.center = CGPointMake(labelXPosition,
+ self.frame.size.height - _chartMarginTop + label.frame.size.height /2.0 + _labelMarginTop);
+ labelAddCount = 0;
+
+ [_xChartLabels addObject:label];
+ [self addSubview:label];
+ }
+ }
+ }
+}
+
+
+- (void)setStrokeColor:(UIColor *)strokeColor
+{
+ _strokeColor = strokeColor;
+}
+
+- (void)updateBar
+{
+
+ //Add bars
+ CGFloat chartCavanHeight = self.frame.size.height - _chartMarginTop - _chartMarginBottom - kXLabelHeight;
+ NSInteger index = 0;
+
+ for (NSNumber *valueString in _yValues) {
+
+ PNBar *bar;
+
+ if (_bars.count == _yValues.count) {
+ bar = [_bars objectAtIndex:index];
+ }else{
+ CGFloat barWidth;
+ CGFloat barXPosition;
+
+ if (_barWidth) {
+ barWidth = _barWidth;
+ barXPosition = index * _xLabelWidth + _chartMarginLeft + _xLabelWidth /2.0 - _barWidth /2.0;
+ }else{
+ barXPosition = index * _xLabelWidth + _chartMarginLeft + _xLabelWidth * 0.25;
+ if (_showLabel) {
+ barWidth = _xLabelWidth * 0.5;
+
+ }
+ else {
+ barWidth = _xLabelWidth * 0.6;
+
+ }
+ }
+
+ bar = [[PNBar alloc] initWithFrame:CGRectMake(barXPosition, //Bar X position
+ self.frame.size.height - chartCavanHeight - kXLabelHeight - _chartMarginBottom + _chartMarginTop , //Bar Y position
+ barWidth, // Bar witdh
+ self.showLevelLine ? chartCavanHeight/2.0:chartCavanHeight)]; //Bar height
+
+ //Change Bar Radius
+ bar.barRadius = _barRadius;
+
+ //Set Bar Animation
+ bar.displayAnimated = self.displayAnimated;
+
+ //Change Bar Background color
+ bar.backgroundColor = _barBackgroundColor;
+ //Bar StrokColor First
+ if (self.strokeColor) {
+ bar.barColor = self.strokeColor;
+ }else{
+ bar.barColor = [self barColorAtIndex:index];
+ }
+
+ if (self.labelTextColor) {
+ bar.labelTextColor = self.labelTextColor;
+ }
+
+ // Add gradient
+ if (self.isGradientShow) {
+ bar.barColorGradientStart = bar.barColor;
+ }
+
+ //For Click Index
+ bar.tag = index;
+
+ [_bars addObject:bar];
+ [self addSubview:bar];
+ }
+
+ //Height Of Bar
+ float value = [valueString floatValue];
+ float grade =fabsf((float)value / (float)_yValueMax);
+
+ if (isnan(grade)) {
+ grade = 0;
+ }
+ bar.maxDivisor = (float)_yValueMax;
+ bar.grade = grade;
+ bar.isShowNumber = self.isShowNumbers;
+ CGRect originalFrame = bar.frame;
+ NSString *currentNumber = [NSString stringWithFormat:@"%f",value];
+
+ if ([[currentNumber substringToIndex:1] isEqualToString:@"-"] && self.showLevelLine) {
+ CGAffineTransform transform =CGAffineTransformMakeRotation(M_PI);
+ [bar setTransform:transform];
+ originalFrame.origin.y = bar.frame.origin.y + bar.frame.size.height;
+ bar.frame = originalFrame;
+ bar.isNegative = YES;
+
+ }
+ index += 1;
+ }
+}
+
+- (void)strokeChart
+{
+ //Add Labels
+
+ [self viewCleanupForCollection:_bars];
+
+
+ //Update Bar
+
+ [self updateBar];
+
+ //Add chart border lines
+
+ if (_showChartBorder) {
+ _chartBottomLine = [CAShapeLayer layer];
+ _chartBottomLine.lineCap = kCALineCapButt;
+ _chartBottomLine.fillColor = [[UIColor whiteColor] CGColor];
+ _chartBottomLine.lineWidth = 1.0;
+ _chartBottomLine.strokeEnd = 0.0;
+
+ UIBezierPath *progressline = [UIBezierPath bezierPath];
+
+ [progressline moveToPoint:CGPointMake(_chartMarginLeft, self.frame.size.height - kXLabelHeight - _chartMarginBottom + _chartMarginTop)];
+ [progressline addLineToPoint:CGPointMake(self.frame.size.width - _chartMarginRight, self.frame.size.height - kXLabelHeight - _chartMarginBottom + _chartMarginTop)];
+
+ [progressline setLineWidth:1.0];
+ [progressline setLineCapStyle:kCGLineCapSquare];
+ _chartBottomLine.path = progressline.CGPath;
+ _chartBottomLine.strokeColor = [_chartBorderColor CGColor];;
+ _chartBottomLine.strokeEnd = 1.0;
+
+ [self.layer addSublayer:_chartBottomLine];
+
+ //Add left Chart Line
+
+ _chartLeftLine = [CAShapeLayer layer];
+ _chartLeftLine.lineCap = kCALineCapButt;
+ _chartLeftLine.fillColor = [[UIColor whiteColor] CGColor];
+ _chartLeftLine.lineWidth = 1.0;
+ _chartLeftLine.strokeEnd = 0.0;
+
+ UIBezierPath *progressLeftline = [UIBezierPath bezierPath];
+
+ [progressLeftline moveToPoint:CGPointMake(_chartMarginLeft, self.frame.size.height - kXLabelHeight - _chartMarginBottom + _chartMarginTop)];
+ [progressLeftline addLineToPoint:CGPointMake(_chartMarginLeft, _chartMarginTop)];
+
+ [progressLeftline setLineWidth:1.0];
+ [progressLeftline setLineCapStyle:kCGLineCapSquare];
+ _chartLeftLine.path = progressLeftline.CGPath;
+ _chartLeftLine.strokeColor = [_chartBorderColor CGColor];
+ _chartLeftLine.strokeEnd = 1.0;
+
+ [self addBorderAnimationIfNeeded];
+ [self.layer addSublayer:_chartLeftLine];
+ }
+
+ // Add Level Separator Line
+ if (_showLevelLine) {
+ _chartLevelLine = [CAShapeLayer layer];
+ _chartLevelLine.lineCap = kCALineCapButt;
+ _chartLevelLine.fillColor = [[UIColor whiteColor] CGColor];
+ _chartLevelLine.lineWidth = 1.0;
+ _chartLevelLine.strokeEnd = 0.0;
+
+ UIBezierPath *progressline = [UIBezierPath bezierPath];
+
+ [progressline moveToPoint:CGPointMake(_chartMarginLeft, (self.frame.size.height - kXLabelHeight )/2.0)];
+ [progressline addLineToPoint:CGPointMake(self.frame.size.width - _chartMarginLeft - _chartMarginRight, (self.frame.size.height - kXLabelHeight )/2.0)];
+
+ [progressline setLineWidth:1.0];
+ [progressline setLineCapStyle:kCGLineCapSquare];
+ _chartLevelLine.path = progressline.CGPath;
+
+ _chartLevelLine.strokeColor = PNLightGrey.CGColor;
+
+ [self addSeparatorAnimationIfNeeded];
+ _chartLevelLine.strokeEnd = 1.0;
+
+ [self.layer addSublayer:_chartLevelLine];
+ } else {
+ if (_chartLevelLine) {
+ [_chartLevelLine removeFromSuperlayer];
+ _chartLevelLine = nil;
+ }
+ }
+}
+
+- (void)addBorderAnimationIfNeeded
+{
+ if (self.displayAnimated) {
+ CABasicAnimation *pathAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
+ pathAnimation.duration = 0.5;
+ pathAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
+ pathAnimation.fromValue = @0.0f;
+ pathAnimation.toValue = @1.0f;
+ [_chartBottomLine addAnimation:pathAnimation forKey:@"strokeEndAnimation"];
+
+ CABasicAnimation *pathLeftAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
+ pathLeftAnimation.duration = 0.5;
+ pathLeftAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
+ pathLeftAnimation.fromValue = @0.0f;
+ pathLeftAnimation.toValue = @1.0f;
+ [_chartLeftLine addAnimation:pathLeftAnimation forKey:@"strokeEndAnimation"];
+ }
+}
+
+- (void)addSeparatorAnimationIfNeeded
+{
+ if (self.displayAnimated) {
+ CABasicAnimation *pathAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
+ pathAnimation.duration = 0.5;
+ pathAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
+ pathAnimation.fromValue = @0.0f;
+ pathAnimation.toValue = @1.0f;
+ [_chartLevelLine addAnimation:pathAnimation forKey:@"strokeEndAnimation"];
+ }
+}
+
+- (void)viewCleanupForCollection:(NSMutableArray *)array
+{
+ if (array.count) {
+ [array makeObjectsPerformSelector:@selector(removeFromSuperview)];
+ [array removeAllObjects];
+ }
+}
+
+
+#pragma mark - Class extension methods
+
+- (UIColor *)barColorAtIndex:(NSUInteger)index
+{
+ if ([self.strokeColors count] == [self.yValues count]) {
+ return self.strokeColors[index];
+ }
+ else {
+ return self.strokeColor;
+ }
+}
+
+#pragma mark - Touch detection
+
+- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
+{
+ [self touchPoint:touches withEvent:event];
+ [super touchesBegan:touches withEvent:event];
+}
+
+- (void)touchPoint:(NSSet *)touches withEvent:(UIEvent *)event
+{
+ //Get the point user touched
+ UITouch *touch = [touches anyObject];
+ CGPoint touchPoint = [touch locationInView:self];
+ UIView *subview = [self hitTest:touchPoint withEvent:nil];
+
+ if ([subview isKindOfClass:[PNBar class]] && [self.delegate respondsToSelector:@selector(userClickedOnBarAtIndex:)]) {
+ [self.delegate userClickedOnBarAtIndex:subview.tag];
+ }
+}
+
+
+@end
diff --git a/PNChartdemo/PNChartdemo/PNChart/PNChart.h b/PNChartdemo/PNChartdemo/PNChart/PNChart.h
new file mode 100755
index 0000000..0835d39
--- /dev/null
+++ b/PNChartdemo/PNChartdemo/PNChart/PNChart.h
@@ -0,0 +1,22 @@
+//
+// PNChart.h
+// Version 0.1
+// PNChart
+//
+// Created by kevin on 10/3/13.
+// Copyright (c) 2013��� kevinzhow. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+#import "PNChart.h"
+#import "PNColor.h"
+#import "PNLineChart.h"
+#import "PNLineChartData.h"
+#import "PNLineChartDataItem.h"
+#import "PNBarChart.h"
+#import "PNCircleChart.h"
+#import "PNChartDelegate.h"
+#import "PNPieChart.h"
+#import "PNScatterChart.h"
+#import "PNRadarChart.h"
+#import "PNRadarChartDataItem.h"
diff --git a/PNChartdemo/PNChartdemo/PNChart/PNChartDelegate.h b/PNChartdemo/PNChartdemo/PNChart/PNChartDelegate.h
new file mode 100755
index 0000000..6d49f7c
--- /dev/null
+++ b/PNChartdemo/PNChartdemo/PNChart/PNChartDelegate.h
@@ -0,0 +1,33 @@
+//
+// PNChartDelegate.h
+// PNChartDemo
+//
+// Created by kevinzhow on 13-12-11.
+// Copyright (c) 2013��� kevinzhow. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+
+@protocol PNChartDelegate <NSObject>
+@optional
+/**
+ * Callback method that gets invoked when the user taps on the chart line.
+ */
+- (void)userClickedOnLinePoint:(CGPoint)point lineIndex:(NSInteger)lineIndex;
+
+/**
+ * Callback method that gets invoked when the user taps on a chart line key point.
+ */
+- (void)userClickedOnLineKeyPoint:(CGPoint)point
+ lineIndex:(NSInteger)lineIndex
+ pointIndex:(NSInteger)pointIndex;
+
+/**
+ * Callback method that gets invoked when the user taps on a chart bar.
+ */
+- (void)userClickedOnBarAtIndex:(NSInteger)barIndex;
+
+
+- (void)userClickedOnPieIndexItem:(NSInteger)pieIndex;
+- (void)didUnselectPieItem;
+@end
diff --git a/PNChartdemo/PNChartdemo/PNChart/PNChartLabel.h b/PNChartdemo/PNChartdemo/PNChart/PNChartLabel.h
new file mode 100755
index 0000000..9ba6afa
--- /dev/null
+++ b/PNChartdemo/PNChartdemo/PNChart/PNChartLabel.h
@@ -0,0 +1,13 @@
+//
+// PNChartLabel.h
+// PNChart
+//
+// Created by kevin on 10/3/13.
+// Copyright (c) 2013��� kevinzhow. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+
+@interface PNChartLabel : UILabel
+
+@end
diff --git a/PNChartdemo/PNChartdemo/PNChart/PNChartLabel.m b/PNChartdemo/PNChartdemo/PNChart/PNChartLabel.m
new file mode 100755
index 0000000..b0980d1
--- /dev/null
+++ b/PNChartdemo/PNChartdemo/PNChart/PNChartLabel.m
@@ -0,0 +1,32 @@
+//
+// PNChartLabel.m
+// PNChart
+//
+// Created by kevin on 10/3/13.
+// Copyright (c) 2013��� kevinzhow. All rights reserved.
+//
+
+#import "PNChartLabel.h"
+
+@implementation PNChartLabel
+
+- (id)initWithFrame:(CGRect)frame
+{
+ self = [super initWithFrame:frame];
+
+ if (self) {
+ self.font = [UIFont boldSystemFontOfSize:11.0f];
+ self.backgroundColor = [UIColor clearColor];
+ self.textAlignment = NSTextAlignmentCenter;
+ self.userInteractionEnabled = YES;
+ self.adjustsFontSizeToFitWidth = YES;
+ self.numberOfLines = 0;
+ /* if you want to see ... in large labels un-comment this line
+ self.minimumScaleFactor = 0.8;
+ */
+ }
+
+ return self;
+}
+
+@end
diff --git a/PNChartdemo/PNChartdemo/PNChart/PNCircleChart.h b/PNChartdemo/PNChartdemo/PNChart/PNCircleChart.h
new file mode 100755
index 0000000..0c57376
--- /dev/null
+++ b/PNChartdemo/PNChartdemo/PNChart/PNCircleChart.h
@@ -0,0 +1,74 @@
+//
+// PNCircleChart.h
+// PNChartDemo
+//
+// Created by kevinzhow on 13-11-30.
+// Copyright (c) 2013��� kevinzhow. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+#import "PNColor.h"
+#import <UICountingLabel/UICountingLabel.h>
+
+typedef NS_ENUM (NSUInteger, PNChartFormatType) {
+ PNChartFormatTypePercent,
+ PNChartFormatTypeDollar,
+ PNChartFormatTypeNone,
+ PNChartFormatTypeDecimal,
+ PNChartFormatTypeDecimalTwoPlaces,
+};
+
+#define DEGREES_TO_RADIANS(angle) ((angle) / 180.0 * M_PI)
+
+@interface PNCircleChart : UIView
+
+- (void)strokeChart;
+- (void)growChartByAmount:(NSNumber *)growAmount;
+- (void)updateChartByCurrent:(NSNumber *)current;
+- (void)updateChartByCurrent:(NSNumber *)current byTotal:(NSNumber *)total;
+- (id)initWithFrame:(CGRect)frame
+ total:(NSNumber *)total
+ current:(NSNumber *)current
+ clockwise:(BOOL)clockwise;
+
+- (id)initWithFrame:(CGRect)frame
+ total:(NSNumber *)total
+ current:(NSNumber *)current
+ clockwise:(BOOL)clockwise
+ shadow:(BOOL)hasBackgroundShadow
+ shadowColor:(UIColor *)backgroundShadowColor;
+
+- (id)initWithFrame:(CGRect)frame
+ total:(NSNumber *)total
+ current:(NSNumber *)current
+ clockwise:(BOOL)clockwise
+ shadow:(BOOL)hasBackgroundShadow
+ shadowColor:(UIColor *)backgroundShadowColor
+displayCountingLabel:(BOOL)displayCountingLabel;
+
+- (id)initWithFrame:(CGRect)frame
+ total:(NSNumber *)total
+ current:(NSNumber *)current
+ clockwise:(BOOL)clockwise
+ shadow:(BOOL)hasBackgroundShadow
+ shadowColor:(UIColor *)backgroundShadowColor
+displayCountingLabel:(BOOL)displayCountingLabel
+ overrideLineWidth:(NSNumber *)overrideLineWidth;
+
+@property (strong, nonatomic) UICountingLabel *countingLabel;
+@property (nonatomic) UIColor *strokeColor;
+@property (nonatomic) UIColor *strokeColorGradientStart;
+@property (nonatomic) NSNumber *total;
+@property (nonatomic) NSNumber *current;
+@property (nonatomic) NSNumber *lineWidth;
+@property (nonatomic) NSTimeInterval duration;
+@property (nonatomic) PNChartFormatType chartType;
+
+@property (nonatomic) CAShapeLayer *circle;
+@property (nonatomic) CAShapeLayer *gradientMask;
+@property (nonatomic) CAShapeLayer *circleBackground;
+
+@property (nonatomic) BOOL displayCountingLabel;
+@property (nonatomic) BOOL displayAnimated;
+
+@end
diff --git a/PNChartdemo/PNChartdemo/PNChart/PNCircleChart.m b/PNChartdemo/PNChartdemo/PNChart/PNCircleChart.m
new file mode 100755
index 0000000..19f70e5
--- /dev/null
+++ b/PNChartdemo/PNChartdemo/PNChart/PNCircleChart.m
@@ -0,0 +1,267 @@
+//
+// PNCircleChart.m
+// PNChartDemo
+//
+// Created by kevinzhow on 13-11-30.
+// Copyright (c) 2013��� kevinzhow. All rights reserved.
+//
+
+#import "PNCircleChart.h"
+
+@interface PNCircleChart ()
+@end
+
+@implementation PNCircleChart
+
+- (id)initWithFrame:(CGRect)frame total:(NSNumber *)total current:(NSNumber *)current clockwise:(BOOL)clockwise {
+
+ return [self initWithFrame:frame
+ total:total
+ current:current
+ clockwise:clockwise
+ shadow:NO
+ shadowColor:[UIColor clearColor]
+ displayCountingLabel:YES
+ overrideLineWidth:@8.0f];
+
+}
+
+- (id)initWithFrame:(CGRect)frame total:(NSNumber *)total current:(NSNumber *)current clockwise:(BOOL)clockwise shadow:(BOOL)hasBackgroundShadow shadowColor:(UIColor *)backgroundShadowColor {
+
+ return [self initWithFrame:frame
+ total:total
+ current:current
+ clockwise:clockwise
+ shadow:shadow
+ shadowColor:backgroundShadowColor
+ displayCountingLabel:YES
+ overrideLineWidth:@8.0f];
+
+}
+
+- (id)initWithFrame:(CGRect)frame total:(NSNumber *)total current:(NSNumber *)current clockwise:(BOOL)clockwise shadow:(BOOL)hasBackgroundShadow shadowColor:(UIColor *)backgroundShadowColor displayCountingLabel:(BOOL)displayCountingLabel {
+
+ return [self initWithFrame:frame
+ total:total
+ current:current
+ clockwise:clockwise
+ shadow:shadow
+ shadowColor:backgroundShadowColor
+ displayCountingLabel:displayCountingLabel
+ overrideLineWidth:@8.0f];
+
+}
+
+- (id)initWithFrame:(CGRect)frame
+ total:(NSNumber *)total
+ current:(NSNumber *)current
+ clockwise:(BOOL)clockwise
+ shadow:(BOOL)hasBackgroundShadow
+ shadowColor:(UIColor *)backgroundShadowColor
+displayCountingLabel:(BOOL)displayCountingLabel
+ overrideLineWidth:(NSNumber *)overrideLineWidth
+{
+ self = [super initWithFrame:frame];
+
+ if (self) {
+ _total = total;
+ _current = current;
+ _strokeColor = PNFreshGreen;
+ _duration = 1.0;
+ _chartType = PNChartFormatTypePercent;
+ _displayAnimated = YES;
+
+ _displayCountingLabel = displayCountingLabel;
+
+ CGFloat startAngle = clockwise ? -90.0f : 270.0f;
+ CGFloat endAngle = clockwise ? -90.01f : 270.01f;
+
+ _lineWidth = overrideLineWidth;
+
+ UIBezierPath *circlePath = [UIBezierPath bezierPathWithArcCenter:CGPointMake(self.frame.size.width/2.0f, self.frame.size.height/2.0f)
+ radius:(self.frame.size.height * 0.5) - ([_lineWidth floatValue]/2.0f)
+ startAngle:DEGREES_TO_RADIANS(startAngle)
+ endAngle:DEGREES_TO_RADIANS(endAngle)
+ clockwise:clockwise];
+
+ _circle = [CAShapeLayer layer];
+ _circle.path = circlePath.CGPath;
+ _circle.lineCap = kCALineCapRound;
+ _circle.fillColor = [UIColor clearColor].CGColor;
+ _circle.lineWidth = [_lineWidth floatValue];
+ _circle.zPosition = 1;
+
+ _circleBackground = [CAShapeLayer layer];
+ _circleBackground.path = circlePath.CGPath;
+ _circleBackground.lineCap = kCALineCapRound;
+ _circleBackground.fillColor = [UIColor clearColor].CGColor;
+ _circleBackground.lineWidth = [_lineWidth floatValue];
+ _circleBackground.strokeColor = (hasBackgroundShadow ? backgroundShadowColor.CGColor : [UIColor clearColor].CGColor);
+ _circleBackground.strokeEnd = 1.0;
+ _circleBackground.zPosition = -1;
+
+ [self.layer addSublayer:_circle];
+ [self.layer addSublayer:_circleBackground];
+
+ _countingLabel = [[UICountingLabel alloc] initWithFrame:CGRectMake(0, 0, 100.0, 50.0)];
+ [_countingLabel setTextAlignment:NSTextAlignmentCenter];
+ [_countingLabel setFont:[UIFont boldSystemFontOfSize:16.0f]];
+ [_countingLabel setTextColor:[UIColor grayColor]];
+ [_countingLabel setBackgroundColor:[UIColor clearColor]];
+ [_countingLabel setCenter:CGPointMake(self.frame.size.width/2.0f, self.frame.size.height/2.0f)];
+ _countingLabel.method = UILabelCountingMethodEaseInOut;
+ if (_displayCountingLabel) {
+ [self addSubview:_countingLabel];
+ }
+ }
+
+ return self;
+}
+
+
+- (void)strokeChart
+{
+ // Add counting label
+
+ if (_displayCountingLabel) {
+ NSString *format;
+ switch (self.chartType) {
+ case PNChartFormatTypePercent:
+ format = @"%d%%";
+ break;
+ case PNChartFormatTypeDollar:
+ format = @"$%d";
+ break;
+ case PNChartFormatTypeDecimal:
+ format = @"%.1f";
+ break;
+ case PNChartFormatTypeDecimalTwoPlaces:
+ format = @"%.2f";
+ break;
+ case PNChartFormatTypeNone:
+ default:
+ format = @"%d";
+ break;
+ }
+ self.countingLabel.format = format;
+ [self addSubview:self.countingLabel];
+ }
+
+
+ // Add circle params
+
+ _circle.lineWidth = [_lineWidth floatValue];
+ _circleBackground.lineWidth = [_lineWidth floatValue];
+ _circleBackground.strokeEnd = 1.0;
+ _circle.strokeColor = _strokeColor.CGColor;
+ _circle.strokeEnd = [_current floatValue] / [_total floatValue];
+
+ // Check if user wants to add a gradient from the start color to the bar color
+ if (_strokeColorGradientStart) {
+
+ // Add gradient
+ self.gradientMask = [CAShapeLayer layer];
+ self.gradientMask.fillColor = [[UIColor clearColor] CGColor];
+ self.gradientMask.strokeColor = [[UIColor blackColor] CGColor];
+ self.gradientMask.lineWidth = _circle.lineWidth;
+ self.gradientMask.lineCap = kCALineCapRound;
+ CGRect gradientFrame = CGRectMake(0, 0, 2*self.bounds.size.width, 2*self.bounds.size.height);
+ self.gradientMask.frame = gradientFrame;
+ self.gradientMask.path = _circle.path;
+
+ CAGradientLayer *gradientLayer = [CAGradientLayer layer];
+ gradientLayer.startPoint = CGPointMake(0.5,1.0);
+ gradientLayer.endPoint = CGPointMake(0.5,0.0);
+ gradientLayer.frame = gradientFrame;
+ UIColor *endColor = (_strokeColor ? _strokeColor : [UIColor greenColor]);
+ NSArray *colors = @[
+ (id)endColor.CGColor,
+ (id)_strokeColorGradientStart.CGColor
+ ];
+ gradientLayer.colors = colors;
+
+ [gradientLayer setMask:self.gradientMask];
+
+ [_circle addSublayer:gradientLayer];
+
+ self.gradientMask.strokeEnd = [_current floatValue] / [_total floatValue];
+ }
+
+ [self addAnimationIfNeeded];
+}
+
+
+
+- (void)growChartByAmount:(NSNumber *)growAmount
+{
+ NSNumber *updatedValue = [NSNumber numberWithFloat:[_current floatValue] + [growAmount floatValue]];
+
+ // Add animation
+ [self updateChartByCurrent:updatedValue];
+}
+
+
+-(void)updateChartByCurrent:(NSNumber *)current{
+
+ [self updateChartByCurrent:current
+ byTotal:_total];
+
+}
+
+-(void)updateChartByCurrent:(NSNumber *)current byTotal:(NSNumber *)total {
+ double totalPercentageValue = [current floatValue]/([total floatValue]/100.0);
+
+ if (_strokeColorGradientStart) {
+ self.gradientMask.strokeEnd = _circle.strokeEnd;
+ }
+
+ // Add animation
+ if (self.displayAnimated) {
+ CABasicAnimation *pathAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
+ pathAnimation.duration = self.duration;
+ pathAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
+ pathAnimation.fromValue = @([_current floatValue] / [_total floatValue]);
+ pathAnimation.toValue = @([current floatValue] / [total floatValue]);
+
+ if (_strokeColorGradientStart) {
+ [self.gradientMask addAnimation:pathAnimation forKey:@"strokeEndAnimation"];
+ }
+ [_circle addAnimation:pathAnimation forKey:@"strokeEndAnimation"];
+
+ if (_displayCountingLabel) {
+ [self.countingLabel countFrom:fmin([_current floatValue], [_total floatValue]) to:totalPercentageValue withDuration:self.duration];
+ }
+
+ }
+ else if (_displayCountingLabel) {
+ [self.countingLabel countFrom:totalPercentageValue to:totalPercentageValue withDuration:self.duration];
+ }
+
+ _circle.strokeEnd = [current floatValue] / [total floatValue];
+ _current = current;
+ _total = total;
+}
+
+- (void)addAnimationIfNeeded
+{
+ double percentageValue = [_current floatValue]/([_total floatValue]/100.0);
+
+ if (self.displayAnimated) {
+ CABasicAnimation *pathAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
+ pathAnimation.duration = self.duration;
+ pathAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
+ pathAnimation.fromValue = @(0.0f);
+ pathAnimation.toValue = @([_current floatValue] / [_total floatValue]);
+ [_circle addAnimation:pathAnimation forKey:@"strokeEndAnimation"];
+ [_countingLabel countFrom:0 to:percentageValue withDuration:self.duration];
+
+ if (self.gradientMask && _strokeColorGradientStart) {
+ [self.gradientMask addAnimation:pathAnimation forKey:@"strokeEndAnimation"];
+ }
+ }
+ else {
+ [_countingLabel countFrom:percentageValue to:percentageValue withDuration:self.duration];
+ }
+}
+
+@end
diff --git a/PNChartdemo/PNChartdemo/PNChart/PNColor.h b/PNChartdemo/PNChartdemo/PNChart/PNColor.h
new file mode 100755
index 0000000..cfd3ff8
--- /dev/null
+++ b/PNChartdemo/PNChartdemo/PNChart/PNColor.h
@@ -0,0 +1,53 @@
+//
+// PNColor.h
+// PNChart
+//
+// Created by kevin on 13-6-8.
+// Copyright (c) 2013��� kevinzhow. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+#import <UIKit/UIKit.h>
+
+/*
+ * System Versioning Preprocessor Macros
+ */
+
+#define SCREEN_WIDTH ([UIScreen mainScreen].bounds.size.width)
+
+#define PNGrey [UIColor colorWithRed:246.0 / 255.0 green:246.0 / 255.0 blue:246.0 / 255.0 alpha:1.0f]
+#define PNLightBlue [UIColor colorWithRed:94.0 / 255.0 green:147.0 / 255.0 blue:196.0 / 255.0 alpha:1.0f]
+#define PNGreen [UIColor colorWithRed:77.0 / 255.0 green:186.0 / 255.0 blue:122.0 / 255.0 alpha:1.0f]
+#define PNTitleColor [UIColor colorWithRed:0.0 / 255.0 green:189.0 / 255.0 blue:113.0 / 255.0 alpha:1.0f]
+#define PNButtonGrey [UIColor colorWithRed:141.0 / 255.0 green:141.0 / 255.0 blue:141.0 / 255.0 alpha:1.0f]
+#define PNLightGreen [UIColor colorWithRed:77.0 / 255.0 green:216.0 / 255.0 blue:122.0 / 255.0 alpha:1.0f]
+#define PNFreshGreen [UIColor colorWithRed:77.0 / 255.0 green:196.0 / 255.0 blue:122.0 / 255.0 alpha:1.0f]
+#define PNDeepGreen [UIColor colorWithRed:77.0 / 255.0 green:176.0 / 255.0 blue:122.0 / 255.0 alpha:1.0f]
+#define PNRed [UIColor colorWithRed:245.0 / 255.0 green:94.0 / 255.0 blue:78.0 / 255.0 alpha:1.0f]
+#define PNMauve [UIColor colorWithRed:88.0 / 255.0 green:75.0 / 255.0 blue:103.0 / 255.0 alpha:1.0f]
+#define PNBrown [UIColor colorWithRed:119.0 / 255.0 green:107.0 / 255.0 blue:95.0 / 255.0 alpha:1.0f]
+#define PNBlue [UIColor colorWithRed:82.0 / 255.0 green:116.0 / 255.0 blue:188.0 / 255.0 alpha:1.0f]
+#define PNDarkBlue [UIColor colorWithRed:121.0 / 255.0 green:134.0 / 255.0 blue:142.0 / 255.0 alpha:1.0f]
+#define PNYellow [UIColor colorWithRed:242.0 / 255.0 green:197.0 / 255.0 blue:117.0 / 255.0 alpha:1.0f]
+#define PNWhite [UIColor colorWithRed:255.0 / 255.0 green:255.0 / 255.0 blue:255.0 / 255.0 alpha:1.0f]
+#define PNDeepGrey [UIColor colorWithRed:99.0 / 255.0 green:99.0 / 255.0 blue:99.0 / 255.0 alpha:1.0f]
+#define PNPinkGrey [UIColor colorWithRed:200.0 / 255.0 green:193.0 / 255.0 blue:193.0 / 255.0 alpha:1.0f]
+#define PNHealYellow [UIColor colorWithRed:245.0 / 255.0 green:242.0 / 255.0 blue:238.0 / 255.0 alpha:1.0f]
+#define PNLightGrey [UIColor colorWithRed:225.0 / 255.0 green:225.0 / 255.0 blue:225.0 / 255.0 alpha:1.0f]
+#define PNCleanGrey [UIColor colorWithRed:251.0 / 255.0 green:251.0 / 255.0 blue:251.0 / 255.0 alpha:1.0f]
+#define PNLightYellow [UIColor colorWithRed:241.0 / 255.0 green:240.0 / 255.0 blue:240.0 / 255.0 alpha:1.0f]
+#define PNDarkYellow [UIColor colorWithRed:152.0 / 255.0 green:150.0 / 255.0 blue:159.0 / 255.0 alpha:1.0f]
+#define PNPinkDark [UIColor colorWithRed:170.0 / 255.0 green:165.0 / 255.0 blue:165.0 / 255.0 alpha:1.0f]
+#define PNCloudWhite [UIColor colorWithRed:244.0 / 255.0 green:244.0 / 255.0 blue:244.0 / 255.0 alpha:1.0f]
+#define PNBlack [UIColor colorWithRed:45.0 / 255.0 green:45.0 / 255.0 blue:45.0 / 255.0 alpha:1.0f]
+#define PNStarYellow [UIColor colorWithRed:252.0 / 255.0 green:223.0 / 255.0 blue:101.0 / 255.0 alpha:1.0f]
+#define PNTwitterColor [UIColor colorWithRed:0.0 / 255.0 green:171.0 / 255.0 blue:243.0 / 255.0 alpha:1.0]
+#define PNWeiboColor [UIColor colorWithRed:250.0 / 255.0 green:0.0 / 255.0 blue:33.0 / 255.0 alpha:1.0]
+#define PNiOSGreenColor [UIColor colorWithRed:98.0 / 255.0 green:247.0 / 255.0 blue:77.0 / 255.0 alpha:1.0]
+
+
+@interface PNColor : NSObject
+
+- (UIImage *)imageFromColor:(UIColor *)color;
+
+@end
diff --git a/PNChartdemo/PNChartdemo/PNChart/PNColor.m b/PNChartdemo/PNChartdemo/PNChart/PNColor.m
new file mode 100755
index 0000000..2ebc8c0
--- /dev/null
+++ b/PNChartdemo/PNChartdemo/PNChart/PNColor.m
@@ -0,0 +1,29 @@
+//
+// PNColor.m
+// PNChart
+//
+// Created by kevin on 13-6-8.
+// Copyright (c) 2013��� kevinzhow. All rights reserved.
+//
+
+#import "PNColor.h"
+#import <UIKit/UIKit.h>
+
+@implementation PNColor
+
+- (UIImage *)imageFromColor:(UIColor *)color
+{
+ CGRect rect = CGRectMake(0, 0, 1, 1);
+
+ UIGraphicsBeginImageContext(rect.size);
+ CGContextRef context = UIGraphicsGetCurrentContext();
+ CGContextSetFillColorWithColor(context, [color CGColor]);
+ CGContextFillRect(context, rect);
+ UIImage *img = UIGraphicsGetImageFromCurrentImageContext();
+ UIGraphicsEndImageContext();
+
+ return img;
+}
+
+
+@end
diff --git a/PNChartdemo/PNChartdemo/PNChart/PNGenericChart.h b/PNChartdemo/PNChartdemo/PNChart/PNGenericChart.h
new file mode 100755
index 0000000..829d84a
--- /dev/null
+++ b/PNChartdemo/PNChartdemo/PNChart/PNGenericChart.h
@@ -0,0 +1,48 @@
+//
+// PNGenericChart.h
+// PNChartDemo
+//
+// Created by Andi Palo on 26/02/15.
+// Copyright (c) 2015 kevinzhow. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+
+typedef NS_ENUM(NSUInteger, PNLegendPosition) {
+ PNLegendPositionTop = 0,
+ PNLegendPositionBottom = 1,
+ PNLegendPositionLeft = 2,
+ PNLegendPositionRight = 3
+};
+
+typedef NS_ENUM(NSUInteger, PNLegendItemStyle) {
+ PNLegendItemStyleStacked = 0,
+ PNLegendItemStyleSerial = 1
+};
+
+@interface PNGenericChart : UIView
+
+@property (assign, nonatomic) BOOL hasLegend;
+@property (assign, nonatomic) PNLegendPosition legendPosition;
+@property (assign, nonatomic) PNLegendItemStyle legendStyle;
+
+@property (assign, nonatomic) UIFont *legendFont;
+@property (assign, nonatomic) UIColor *legendFontColor;
+@property (assign, nonatomic) NSUInteger labelRowsInSerialMode;
+
+/** Display the chart with or without animation. Default is YES. **/
+@property (nonatomic) BOOL displayAnimated;
+
+/**
+ * returns the Legend View, or nil if no chart data is present.
+ * The origin of the legend frame is 0,0 but you can set it with setFrame:(CGRect)
+ *
+ * @param mWidth Maximum width of legend. Height will depend on this and font size
+ *
+ * @return UIView of Legend
+ */
+- (UIView*) getLegendWithMaxWidth:(CGFloat)mWidth;
+
+
+- (void) setupDefaultValues;
+@end
diff --git a/PNChartdemo/PNChartdemo/PNChart/PNGenericChart.m b/PNChartdemo/PNChartdemo/PNChart/PNGenericChart.m
new file mode 100755
index 0000000..c54ac37
--- /dev/null
+++ b/PNChartdemo/PNChartdemo/PNChart/PNGenericChart.m
@@ -0,0 +1,54 @@
+//
+// PNGenericChart.m
+// PNChartDemo
+//
+// Created by Andi Palo on 26/02/15.
+// Copyright (c) 2015 kevinzhow. All rights reserved.
+//
+
+#import "PNGenericChart.h"
+
+@interface PNGenericChart ()
+
+
+
+@end
+
+@implementation PNGenericChart
+
+/*
+// Only override drawRect: if you perform custom drawing.
+// An empty implementation adversely affects performance during animation.
+- (void)drawRect:(CGRect)rect {
+ // Drawing code
+}
+*/
+
+- (void) setupDefaultValues{
+ self.hasLegend = YES;
+ self.legendPosition = PNLegendPositionBottom;
+ self.legendStyle = PNLegendItemStyleStacked;
+ self.labelRowsInSerialMode = 1;
+ self.displayAnimated = YES;
+}
+
+
+
+/**
+ * to be implemented in subclass
+ */
+- (UIView*) getLegendWithMaxWidth:(CGFloat)mWidth{
+ [self doesNotRecognizeSelector:_cmd];
+ return nil;
+}
+
+- (void) setLabelRowsInSerialMode:(NSUInteger)num{
+ if (self.legendStyle == PNLegendItemStyleSerial) {
+ _labelRowsInSerialMode = num;
+ }else{
+ _labelRowsInSerialMode = 1;
+ }
+}
+
+
+@end
diff --git a/PNChartdemo/PNChartdemo/PNChart/PNLineChart.h b/PNChartdemo/PNChartdemo/PNChart/PNLineChart.h
new file mode 100755
index 0000000..b30878a
--- /dev/null
+++ b/PNChartdemo/PNChartdemo/PNChart/PNLineChart.h
@@ -0,0 +1,110 @@
+//
+// PNLineChart.h
+// PNChartDemo
+//
+// Created by kevin on 11/7/13.
+// Copyright (c) 2013��� kevinzhow. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+#import <QuartzCore/QuartzCore.h>
+#import "PNChartDelegate.h"
+#import "PNGenericChart.h"
+
+@interface PNLineChart : PNGenericChart
+
+/**
+ * Draws the chart in an animated fashion.
+ */
+- (void)strokeChart;
+
+@property (nonatomic, weak) id<PNChartDelegate> delegate;
+
+@property (nonatomic) NSArray *xLabels;
+@property (nonatomic) NSArray *yLabels;
+
+/**
+ * Array of `LineChartData` objects, one for each line.
+ */
+@property (nonatomic) NSArray *chartData;
+
+@property (nonatomic) NSMutableArray *pathPoints;
+@property (nonatomic) NSMutableArray *xChartLabels;
+@property (nonatomic) NSMutableArray *yChartLabels;
+
+@property (nonatomic) CGFloat xLabelWidth;
+@property (nonatomic) UIFont *xLabelFont;
+@property (nonatomic) UIColor *xLabelColor;
+@property (nonatomic) CGFloat yValueMax;
+@property (nonatomic) CGFloat yFixedValueMax;
+@property (nonatomic) CGFloat yFixedValueMin;
+@property (nonatomic) CGFloat yValueMin;
+@property (nonatomic) NSInteger yLabelNum;
+@property (nonatomic) CGFloat yLabelHeight;
+@property (nonatomic) UIFont *yLabelFont;
+@property (nonatomic) UIColor *yLabelColor;
+@property (nonatomic) CGFloat chartCavanHeight;
+@property (nonatomic) CGFloat chartCavanWidth;
+@property (nonatomic) BOOL showLabel;
+@property (nonatomic) BOOL showGenYLabels;
+@property (nonatomic) BOOL showYGridLines;
+@property (nonatomic) UIColor *yGridLinesColor;
+@property (nonatomic) BOOL thousandsSeparator;
+
+@property (nonatomic) CGFloat chartMarginLeft;
+@property (nonatomic) CGFloat chartMarginRight;
+@property (nonatomic) CGFloat chartMarginTop;
+@property (nonatomic) CGFloat chartMarginBottom;
+
+/**
+ * Controls whether to show the coordinate axis. Default is NO.
+ */
+@property (nonatomic, getter = isShowCoordinateAxis) BOOL showCoordinateAxis;
+@property (nonatomic) UIColor *axisColor;
+@property (nonatomic) CGFloat axisWidth;
+
+@property (nonatomic, strong) NSString *xUnit;
+@property (nonatomic, strong) NSString *yUnit;
+
+/**
+ * String formatter for float values in y-axis labels. If not set, defaults to @"%1.f"
+ */
+@property (nonatomic, strong) NSString *yLabelFormat;
+
+/**
+ * Block formatter for custom string in y-axis labels. If not set, defaults to yLabelFormat
+ */
+@property (nonatomic, copy) NSString* (^yLabelBlockFormatter)(CGFloat);
+
+
+/**
+ * Controls whether to curve the line chart or not
+ */
+@property (nonatomic) BOOL showSmoothLines;
+
+- (void)setXLabels:(NSArray *)xLabels withWidth:(CGFloat)width;
+
+/**
+ * Update Chart Value
+ */
+
+- (void)updateChartData:(NSArray *)data;
+
+
+/**
+ * returns the Legend View, or nil if no chart data is present.
+ * The origin of the legend frame is 0,0 but you can set it with setFrame:(CGRect)
+ *
+ * @param mWidth Maximum width of legend. Height will depend on this and font size
+ *
+ * @return UIView of Legend
+ */
+- (UIView*) getLegendWithMaxWidth:(CGFloat)mWidth;
+
+
++ (CGSize)sizeOfString:(NSString *)text withWidth:(float)width font:(UIFont *)font;
+
++ (CGPoint)midPointBetweenPoint1:(CGPoint)point1 andPoint2:(CGPoint)point2;
++ (CGPoint)controlPointBetweenPoint1:(CGPoint)point1 andPoint2:(CGPoint)point2;
+
+@end
diff --git a/PNChartdemo/PNChartdemo/PNChart/PNLineChart.m b/PNChartdemo/PNChartdemo/PNChart/PNLineChart.m
new file mode 100755
index 0000000..d03e494
--- /dev/null
+++ b/PNChartdemo/PNChartdemo/PNChart/PNLineChart.m
@@ -0,0 +1,1284 @@
+//
+// PNLineChart.m
+// PNChartDemo
+//
+// Created by kevin on 11/7/13.
+// Copyright (c) 2013��� kevinzhow. All rights reserved.
+//
+
+#import "PNLineChart.h"
+#import "PNColor.h"
+#import "PNChartLabel.h"
+#import "PNLineChartData.h"
+#import "PNLineChartDataItem.h"
+
+@interface PNLineChart ()
+
+@property(nonatomic) NSMutableArray *chartLineArray; // Array[CAShapeLayer]
+@property(nonatomic) NSMutableArray *chartPointArray; // Array[CAShapeLayer] save the point layer
+
+@property(nonatomic) NSMutableArray *chartPath; // Array of line path, one for each line.
+@property(nonatomic) NSMutableArray *pointPath; // Array of point path, one for each line
+@property(nonatomic) NSMutableArray *endPointsOfPath; // Array of start and end points of each line path, one for each line
+
+@property(nonatomic) CABasicAnimation *pathAnimation; // will be set to nil if _displayAnimation is NO
+
+// display grade
+@property(nonatomic) NSMutableArray *gradeStringPaths;
+@property(nonatomic) NSMutableArray *progressLinePathsColors; //Array of colors when drawing each line.if chartData.rangeColors is set then different colors will be
+
+@end
+
+@implementation PNLineChart
+
+@synthesize pathAnimation = _pathAnimation;
+
+#pragma mark initialization
+
+- (id)initWithCoder:(NSCoder *)coder {
+ self = [super initWithCoder:coder];
+
+ if (self) {
+ [self setupDefaultValues];
+ }
+
+ return self;
+}
+
+- (id)initWithFrame:(CGRect)frame {
+ self = [super initWithFrame:frame];
+
+ if (self) {
+ [self setupDefaultValues];
+ }
+
+ return self;
+}
+
+
+#pragma mark instance methods
+
+- (void)setYLabels {
+ CGFloat yStep = (_yValueMax - _yValueMin) / _yLabelNum;
+ CGFloat yStepHeight = _chartCavanHeight / _yLabelNum;
+
+ if (_yChartLabels) {
+ for (PNChartLabel *label in _yChartLabels) {
+ [label removeFromSuperview];
+ }
+ } else {
+ _yChartLabels = [NSMutableArray new];
+ }
+
+ if (yStep == 0.0) {
+ PNChartLabel *minLabel = [[PNChartLabel alloc] initWithFrame:CGRectMake(0.0, (NSInteger) _chartCavanHeight, (NSInteger) _chartMarginBottom, (NSInteger) _yLabelHeight)];
+ minLabel.text = [self formatYLabel:0.0];
+ [self setCustomStyleForYLabel:minLabel];
+ [self addSubview:minLabel];
+ [_yChartLabels addObject:minLabel];
+
+ PNChartLabel *midLabel = [[PNChartLabel alloc] initWithFrame:CGRectMake(0.0, (NSInteger) (_chartCavanHeight / 2), (NSInteger) _chartMarginBottom, (NSInteger) _yLabelHeight)];
+ midLabel.text = [self formatYLabel:_yValueMax];
+ [self setCustomStyleForYLabel:midLabel];
+ [self addSubview:midLabel];
+ [_yChartLabels addObject:midLabel];
+
+ PNChartLabel *maxLabel = [[PNChartLabel alloc] initWithFrame:CGRectMake(0.0, 0.0, (NSInteger) _chartMarginBottom, (NSInteger) _yLabelHeight)];
+ maxLabel.text = [self formatYLabel:_yValueMax * 2];
+ [self setCustomStyleForYLabel:maxLabel];
+ [self addSubview:maxLabel];
+ [_yChartLabels addObject:maxLabel];
+
+ } else {
+ NSInteger index = 0;
+ NSInteger num = _yLabelNum + 1;
+
+ while (num > 0) {
+ CGRect labelFrame = CGRectMake(0.0,
+ (NSInteger) (_chartCavanHeight + _chartMarginTop - index * yStepHeight),
+ (CGFloat) ((NSInteger) _chartMarginLeft * 0.9),
+ (NSInteger) _yLabelHeight);
+ PNChartLabel *label = [[PNChartLabel alloc] initWithFrame:labelFrame];
+ [label setTextAlignment:NSTextAlignmentRight];
+ label.text = [self formatYLabel:_yValueMin + (yStep * index)];
+ [self setCustomStyleForYLabel:label];
+ [self addSubview:label];
+ [_yChartLabels addObject:label];
+ index += 1;
+ num -= 1;
+ }
+ }
+}
+
+- (void)setYLabels:(NSArray *)yLabels {
+ _showGenYLabels = NO;
+ _yLabelNum = yLabels.count - 1;
+
+ CGFloat yLabelHeight;
+ if (_showLabel) {
+ yLabelHeight = _chartCavanHeight / [yLabels count];
+ } else {
+ yLabelHeight = (self.frame.size.height) / [yLabels count];
+ }
+
+ return [self setYLabels:yLabels withHeight:yLabelHeight];
+}
+
+- (void)setYLabels:(NSArray *)yLabels withHeight:(CGFloat)height {
+ _yLabels = yLabels;
+ _yLabelHeight = height;
+ if (_yChartLabels) {
+ for (PNChartLabel *label in _yChartLabels) {
+ [label removeFromSuperview];
+ }
+ } else {
+ _yChartLabels = [NSMutableArray new];
+ }
+
+ NSString *labelText;
+
+ if (_showLabel) {
+ CGFloat yStepHeight = _chartCavanHeight / _yLabelNum;
+
+ for (int index = 0; index < yLabels.count; index++) {
+ labelText = yLabels[(NSUInteger) index];
+
+ NSInteger y = (NSInteger) (_chartCavanHeight + _chartMarginTop - index * yStepHeight);
+
+ PNChartLabel *label = [[PNChartLabel alloc] initWithFrame:CGRectMake(0.0, y, (CGFloat) ((NSInteger) _chartMarginLeft * 0.9), (NSInteger) _yLabelHeight)];
+ [label setTextAlignment:NSTextAlignmentRight];
+ label.text = labelText;
+ [self setCustomStyleForYLabel:label];
+ [self addSubview:label];
+ [_yChartLabels addObject:label];
+ }
+ }
+}
+
+- (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;
+
+ if (_showLabel) {
+ xLabelWidth = _chartCavanWidth / [xLabels count];
+ } else {
+ xLabelWidth = (self.frame.size.width - _chartMarginLeft - _chartMarginRight) / [xLabels count];
+ }
+
+ return [self setXLabels:xLabels withWidth:xLabelWidth];
+}
+
+- (void)setXLabels:(NSArray *)xLabels withWidth:(CGFloat)width {
+ _xLabels = xLabels;
+ _xLabelWidth = width;
+ if (_xChartLabels) {
+ for (PNChartLabel *label in _xChartLabels) {
+ [label removeFromSuperview];
+ }
+ } else {
+ _xChartLabels = [NSMutableArray new];
+ }
+
+ NSString *labelText;
+
+ if (_showLabel) {
+ for (NSUInteger index = 0; index < xLabels.count; index++) {
+ labelText = xLabels[index];
+
+ NSInteger x = (NSInteger) (index * _xLabelWidth + _chartMarginLeft);
+ NSInteger y = (NSInteger) (_chartMarginBottom + _chartCavanHeight);
+
+ PNChartLabel *label = [[PNChartLabel alloc] initWithFrame:CGRectMake(x, y, (NSInteger) _xLabelWidth, (NSInteger) _chartMarginBottom)];
+ [label setTextAlignment:NSTextAlignmentCenter];
+ label.text = labelText;
+ [self setCustomStyleForXLabel:label];
+ [self addSubview:label];
+ [_xChartLabels addObject:label];
+ }
+ }
+}
+
+- (void)setCustomStyleForXLabel:(UILabel *)label {
+ if (_xLabelFont) {
+ label.font = _xLabelFont;
+ }
+
+ if (_xLabelColor) {
+ label.textColor = _xLabelColor;
+ }
+
+}
+
+- (void)setCustomStyleForYLabel:(UILabel *)label {
+ if (_yLabelFont) {
+ label.font = _yLabelFont;
+ }
+
+ if (_yLabelColor) {
+ label.textColor = _yLabelColor;
+ }
+}
+
+#pragma mark - Touch at point
+
+- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
+ [self touchPoint:touches withEvent:event];
+ [self touchKeyPoint:touches withEvent:event];
+}
+
+- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
+ [self touchPoint:touches withEvent:event];
+ [self touchKeyPoint:touches withEvent:event];
+}
+
+- (void)touchPoint:(NSSet *)touches withEvent:(UIEvent *)event {
+ // Get the point user touched
+ UITouch *touch = [touches anyObject];
+ CGPoint touchPoint = [touch locationInView:self];
+
+ for (NSUInteger p = 0; p < _pathPoints.count; p++) {
+ NSArray *linePointsArray = _endPointsOfPath[p];
+
+ for (NSUInteger i = 0; i < (int) linePointsArray.count - 1; i += 2) {
+ CGPoint p1 = [linePointsArray[i] CGPointValue];
+ CGPoint p2 = [linePointsArray[i + 1] CGPointValue];
+
+ // Closest distance from point to line
+ float distance = (float) fabs(((p2.x - p1.x) * (touchPoint.y - p1.y)) - ((p1.x - touchPoint.x) * (p1.y - p2.y)));
+ distance /= hypot(p2.x - p1.x, p1.y - p2.y);
+
+ if (distance <= 5.0) {
+ // Conform to delegate parameters, figure out what bezier path this CGPoint belongs to.
+ NSUInteger lineIndex = 0;
+ for (NSArray<UIBezierPath *> *paths in _chartPath) {
+ for (UIBezierPath *path in paths) {
+ BOOL pointContainsPath = CGPathContainsPoint(path.CGPath, NULL, p1, NO);
+ if (pointContainsPath) {
+ [_delegate userClickedOnLinePoint:touchPoint lineIndex:lineIndex];
+ return;
+ }
+ }
+ lineIndex++;
+ }
+ }
+ }
+ }
+}
+
+- (void)touchKeyPoint:(NSSet *)touches withEvent:(UIEvent *)event {
+ // Get the point user touched
+ UITouch *touch = [touches anyObject];
+ CGPoint touchPoint = [touch locationInView:self];
+
+ for (NSUInteger p = 0; p < _pathPoints.count; p++) {
+ NSArray *linePointsArray = _pathPoints[p];
+
+ for (NSUInteger i = 0; i < (int) linePointsArray.count - 1; i += 1) {
+ CGPoint p1 = [linePointsArray[i] CGPointValue];
+ CGPoint p2 = [linePointsArray[i + 1] CGPointValue];
+
+ float distanceToP1 = (float) fabs(hypot(touchPoint.x - p1.x, touchPoint.y - p1.y));
+ float distanceToP2 = (float) hypot(touchPoint.x - p2.x, touchPoint.y - p2.y);
+
+ float distance = MIN(distanceToP1, distanceToP2);
+
+ if (distance <= 10.0) {
+ [_delegate userClickedOnLineKeyPoint:touchPoint
+ lineIndex:p
+ pointIndex:(distance == distanceToP2 ? i + 1 : i)];
+
+ return;
+ }
+ }
+ }
+}
+
+#pragma mark - Draw Chart
+
+- (void)populateChartLines {
+ for (NSUInteger lineIndex = 0; lineIndex < self.chartData.count; lineIndex++) {
+ NSArray<UIBezierPath *> *progressLines = self.chartPath[lineIndex];
+ // each chart line can be divided into multiple paths because
+ // we need ot draw each path with different color
+ // if there is not rangeColors then there is only one progressLinePath per chart
+ NSArray<UIColor *> *progressLineColors = self.progressLinePathsColors[lineIndex];
+ [self.chartLineArray[lineIndex] removeAllObjects];
+ NSUInteger progressLineIndex = 0;;
+ for (UIBezierPath *progressLinePath in progressLines) {
+ PNLineChartData *chartData = self.chartData[lineIndex];
+ CAShapeLayer *chartLine = [CAShapeLayer layer];
+ chartLine.lineCap = kCALineCapButt;
+ chartLine.lineJoin = kCALineJoinMiter;
+ chartLine.fillColor = self.backgroundColor.CGColor;
+ chartLine.lineWidth = chartData.lineWidth;
+ chartLine.path = progressLinePath.CGPath;
+ chartLine.strokeEnd = 0.0;
+ chartLine.strokeColor = progressLineColors[progressLineIndex].CGColor;
+ [self.layer addSublayer:chartLine];
+ [self.chartLineArray[lineIndex] addObject:chartLine];
+ progressLineIndex++;
+ }
+ }
+}
+
+/*
+ * strokeChart should remove the previously drawn chart lines and points
+ * and then proceed to draw the new lines
+ */
+- (void)strokeChart {
+ [self removeLayers];
+ // remove all shape layers before adding new ones
+ [self recreatePointLayers];
+ // Cavan height and width needs to be set before
+ // setNeedsDisplay is invoked because setNeedsDisplay
+ // will invoke drawRect and if Cavan dimensions is not
+ // set the chart will be misplaced
+ [self resetCavanHeight];
+ [self prepareYLabelsWithData:_chartData];
+
+ _chartPath = [[NSMutableArray alloc] init];
+ _pointPath = [[NSMutableArray alloc] init];
+ _gradeStringPaths = [NSMutableArray array];
+ _progressLinePathsColors = [[NSMutableArray alloc] init];
+
+ [self calculateChartPath:_chartPath
+ andPointsPath:_pointPath
+ andPathKeyPoints:_pathPoints
+ andPathStartEndPoints:_endPointsOfPath
+ andProgressLinePathsColors:_progressLinePathsColors];
+ [self populateChartLines];
+ // Draw each line
+ for (NSUInteger lineIndex = 0; lineIndex < self.chartData.count; lineIndex++) {
+ PNLineChartData *chartData = self.chartData[lineIndex];
+ NSArray<CAShapeLayer *> *chartLines =self.chartLineArray[lineIndex];
+ CAShapeLayer *pointLayer = (CAShapeLayer *) self.chartPointArray[lineIndex];
+ UIGraphicsBeginImageContext(self.frame.size);
+ if (chartData.inflexionPointColor) {
+ pointLayer.strokeColor = [[chartData.inflexionPointColor
+ colorWithAlphaComponent:chartData.alpha] CGColor];
+ } else {
+ pointLayer.strokeColor = [PNGreen CGColor];
+ }
+ // setup the color of the chart line
+ NSArray<UIBezierPath *> *progressLines = _chartPath[lineIndex];
+ UIBezierPath *pointPath = _pointPath[lineIndex];
+
+ pointLayer.path = pointPath.CGPath;
+
+ [CATransaction begin];
+ for (NSUInteger index = 0; index < progressLines.count; index++) {
+ CAShapeLayer *chartLine = chartLines[index];
+ //chartLine strokeColor is already set. no need to override here
+ [chartLine addAnimation:self.pathAnimation forKey:@"strokeEndAnimation"];
+ chartLine.strokeEnd = 1.0;
+ }
+
+ // if you want cancel the point animation, comment this code, the point will show immediately
+ if (chartData.inflexionPointStyle != PNLineChartPointStyleNone) {
+ [pointLayer addAnimation:self.pathAnimation forKey:@"strokeEndAnimation"];
+ }
+
+ [CATransaction commit];
+
+ NSMutableArray *textLayerArray = self.gradeStringPaths[lineIndex];
+ for (CATextLayer *textLayer in textLayerArray) {
+ CABasicAnimation *fadeAnimation = [self fadeAnimation];
+ [textLayer addAnimation:fadeAnimation forKey:nil];
+ }
+
+ UIGraphicsEndImageContext();
+ }
+ [self setNeedsDisplay];
+}
+
+
+- (void)calculateChartPath:(NSMutableArray *)chartPath
+ andPointsPath:(NSMutableArray *)pointsPath
+ andPathKeyPoints:(NSMutableArray *)pathPoints
+ andPathStartEndPoints:(NSMutableArray *)pointsOfPath
+andProgressLinePathsColors:(NSMutableArray *)progressLinePathsColors {
+
+ // Draw each line
+
+ for (NSUInteger lineIndex = 0; lineIndex < self.chartData.count; lineIndex++) {
+ PNLineChartData *chartData = self.chartData[lineIndex];
+
+ CGFloat yValue;
+ NSMutableArray<UIBezierPath *> *progressLines = [NSMutableArray new];
+ NSMutableArray<UIColor *> *progressLineColors = [NSMutableArray new];
+
+ UIBezierPath *pointPath = [UIBezierPath bezierPath];
+
+
+ [chartPath insertObject:progressLines atIndex:lineIndex];
+ [pointsPath insertObject:pointPath atIndex:lineIndex];
+ [progressLinePathsColors insertObject:progressLineColors atIndex:lineIndex];
+
+
+ NSMutableArray *gradePathArray = [NSMutableArray array];
+ [self.gradeStringPaths addObject:gradePathArray];
+
+ NSMutableArray *linePointsArray = [[NSMutableArray alloc] init];
+ NSMutableArray *lineStartEndPointsArray = [[NSMutableArray alloc] init];
+ int last_x = 0;
+ int last_y = 0;
+ NSMutableArray<NSDictionary<NSString *, NSValue *> *> *progressLinePaths = [NSMutableArray new];
+ UIColor *defaultColor = chartData.color != nil ? chartData.color : [UIColor greenColor];
+ CGFloat inflexionWidth = chartData.inflexionPointWidth;
+
+ for (NSUInteger i = 0; i < chartData.itemCount; i++) {
+
+ NSValue *from = nil;
+ NSValue *to = nil;
+
+ yValue = chartData.getData(i).y;
+
+ int x = (int) (i * _xLabelWidth + _chartMarginLeft + _xLabelWidth / 2.0);
+ int y = (int)[self yValuePositionInLineChart:yValue];
+
+ // Circular point
+ if (chartData.inflexionPointStyle == PNLineChartPointStyleCircle) {
+
+ CGRect circleRect = CGRectMake(x - inflexionWidth / 2, y - inflexionWidth / 2, inflexionWidth, inflexionWidth);
+ CGPoint circleCenter = CGPointMake(circleRect.origin.x + (circleRect.size.width / 2), circleRect.origin.y + (circleRect.size.height / 2));
+
+ [pointPath moveToPoint:CGPointMake(circleCenter.x + (inflexionWidth / 2), circleCenter.y)];
+ [pointPath addArcWithCenter:circleCenter radius:inflexionWidth / 2 startAngle:0 endAngle:(CGFloat) (2 * M_PI) clockwise:YES];
+
+ //jet text display text
+ if (chartData.showPointLabel) {
+ [gradePathArray addObject:[self createPointLabelFor:chartData.getData(i).rawY pointCenter:circleCenter width:inflexionWidth withChartData:chartData]];
+ }
+
+ if (i > 0) {
+
+ // calculate the point for line
+ float distance = (float) sqrt(pow(x - last_x, 2) + pow(y - last_y, 2));
+ float last_x1 = last_x + (inflexionWidth / 2) / distance * (x - last_x);
+ float last_y1 = last_y + (inflexionWidth / 2) / distance * (y - last_y);
+ float x1 = x - (inflexionWidth / 2) / distance * (x - last_x);
+ float y1 = y - (inflexionWidth / 2) / distance * (y - last_y);
+ from = [NSValue valueWithCGPoint:CGPointMake(last_x1, last_y1)];
+ to = [NSValue valueWithCGPoint:CGPointMake(x1, y1)];
+ }
+ }
+ // Square point
+ else if (chartData.inflexionPointStyle == PNLineChartPointStyleSquare) {
+
+ CGRect squareRect = CGRectMake(x - inflexionWidth / 2, y - inflexionWidth / 2, inflexionWidth, inflexionWidth);
+ CGPoint squareCenter = CGPointMake(squareRect.origin.x + (squareRect.size.width / 2), squareRect.origin.y + (squareRect.size.height / 2));
+
+ [pointPath moveToPoint:CGPointMake(squareCenter.x - (inflexionWidth / 2), squareCenter.y - (inflexionWidth / 2))];
+ [pointPath addLineToPoint:CGPointMake(squareCenter.x + (inflexionWidth / 2), squareCenter.y - (inflexionWidth / 2))];
+ [pointPath addLineToPoint:CGPointMake(squareCenter.x + (inflexionWidth / 2), squareCenter.y + (inflexionWidth / 2))];
+ [pointPath addLineToPoint:CGPointMake(squareCenter.x - (inflexionWidth / 2), squareCenter.y + (inflexionWidth / 2))];
+ [pointPath closePath];
+
+ // text display text
+ if (chartData.showPointLabel) {
+ [gradePathArray addObject:[self createPointLabelFor:chartData.getData(i).rawY pointCenter:squareCenter width:inflexionWidth withChartData:chartData]];
+ }
+
+ if (i > 0) {
+
+ // calculate the point for line
+ float distance = (float) sqrt(pow(x - last_x, 2) + pow(y - last_y, 2));
+ float last_x1 = last_x + (inflexionWidth / 2);
+ float last_y1 = last_y + (inflexionWidth / 2) / distance * (y - last_y);
+ float x1 = x - (inflexionWidth / 2);
+ float y1 = y - (inflexionWidth / 2) / distance * (y - last_y);
+ from = [NSValue valueWithCGPoint:CGPointMake(last_x1, last_y1)];
+ to = [NSValue valueWithCGPoint:CGPointMake(x1, y1)];
+ }
+ }
+ // Triangle point
+ else if (chartData.inflexionPointStyle == PNLineChartPointStyleTriangle) {
+
+ CGRect squareRect = CGRectMake(x - inflexionWidth / 2, y - inflexionWidth / 2, inflexionWidth, inflexionWidth);
+
+ CGPoint startPoint = CGPointMake(squareRect.origin.x, squareRect.origin.y + squareRect.size.height);
+ CGPoint endPoint = CGPointMake(squareRect.origin.x + (squareRect.size.width / 2), squareRect.origin.y);
+ CGPoint middlePoint = CGPointMake(squareRect.origin.x + (squareRect.size.width), squareRect.origin.y + squareRect.size.height);
+
+ [pointPath moveToPoint:startPoint];
+ [pointPath addLineToPoint:middlePoint];
+ [pointPath addLineToPoint:endPoint];
+ [pointPath closePath];
+
+ // text display text
+ if (chartData.showPointLabel) {
+ [gradePathArray addObject:[self createPointLabelFor:chartData.getData(i).rawY pointCenter:middlePoint width:inflexionWidth withChartData:chartData]];
+ }
+
+ if (i > 0) {
+ // calculate the point for triangle
+ float distance = (float) (sqrt(pow(x - last_x, 2) + pow(y - last_y, 2)) * 1.4);
+ float last_x1 = last_x + (inflexionWidth / 2) / distance * (x - last_x);
+ float last_y1 = last_y + (inflexionWidth / 2) / distance * (y - last_y);
+ float x1 = x - (inflexionWidth / 2) / distance * (x - last_x);
+ float y1 = y - (inflexionWidth / 2) / distance * (y - last_y);
+ from = [NSValue valueWithCGPoint:CGPointMake(last_x1, last_y1)];
+ to = [NSValue valueWithCGPoint:CGPointMake(x1, y1)];
+ }
+ } else {
+
+ if (i > 0) {
+ from = [NSValue valueWithCGPoint:CGPointMake(last_x, last_y)];
+ to = [NSValue valueWithCGPoint:CGPointMake(x, y)];
+ }
+ }
+ if(from != nil && to != nil) {
+ [progressLinePaths addObject:@{@"from": from, @"to":to}];
+ [lineStartEndPointsArray addObject:from];
+ [lineStartEndPointsArray addObject:to];
+ }
+ [linePointsArray addObject:[NSValue valueWithCGPoint:CGPointMake(x, y)]];
+ last_x = x;
+ last_y = y;
+ }
+
+ [pointsOfPath addObject:[lineStartEndPointsArray copy]];
+ [pathPoints addObject:[linePointsArray copy]];
+ // if rangeColors is not nil then it means we need to draw the chart
+ // with different colors. colorRangesBetweenP1.. function takes care of
+ // partitioning the p1->p2 into segments from which we can create UIBezierPath
+ if (self.showSmoothLines && chartData.itemCount >= 4) {
+ for (NSDictionary<NSString *, NSValue *> *item in progressLinePaths) {
+ NSArray<NSDictionary *> *calculatedRanges =
+ [self colorRangesBetweenP1:[item[@"from"] CGPointValue]
+ P2:[item[@"to"] CGPointValue]
+ rangeColors:chartData.rangeColors
+ defaultColor:defaultColor];
+ for (NSDictionary *range in calculatedRanges) {
+// NSLog(@"range : %@ range: %@ color %@", range[@"from"], range[@"to"], range[@"color"]);
+ UIBezierPath *currentProgressLine = [UIBezierPath bezierPath];
+ CGPoint segmentP1 = [range[@"from"] CGPointValue];
+ CGPoint segmentP2 = [range[@"to"] CGPointValue];
+ [currentProgressLine moveToPoint:segmentP1];
+ CGPoint midPoint = [PNLineChart midPointBetweenPoint1:segmentP1 andPoint2:segmentP2];
+ [currentProgressLine addQuadCurveToPoint:midPoint
+ controlPoint:[PNLineChart controlPointBetweenPoint1:midPoint andPoint2:segmentP1]];
+ [currentProgressLine addQuadCurveToPoint:segmentP2
+ controlPoint:[PNLineChart controlPointBetweenPoint1:midPoint andPoint2:segmentP2]];
+ [progressLines addObject:currentProgressLine];
+ [progressLineColors addObject:range[@"color"]];
+ }
+ }
+ } else {
+ for (NSDictionary<NSString *, NSValue *> *item in progressLinePaths) {
+ NSArray<NSDictionary *> *calculatedRanges =
+ [self colorRangesBetweenP1:[item[@"from"] CGPointValue]
+ P2:[item[@"to"] CGPointValue]
+ rangeColors:chartData.rangeColors
+ defaultColor:defaultColor];
+ for (NSDictionary *range in calculatedRanges) {
+// NSLog(@"range : %@ range: %@ color %@", range[@"from"], range[@"to"], range[@"color"]);
+ UIBezierPath *currentProgressLine = [UIBezierPath bezierPath];
+ [currentProgressLine moveToPoint:[range[@"from"] CGPointValue]];
+ [currentProgressLine addLineToPoint:[range[@"to"] CGPointValue]];
+ [progressLines addObject:currentProgressLine];
+ [progressLineColors addObject:range[@"color"]];
+ }
+ }
+ }
+ }
+}
+
+#pragma mark - Set Chart Data
+
+- (void)setChartData:(NSArray *)data {
+ if (data != _chartData) {
+ _chartData = data;
+ }
+}
+
+
+- (void)removeLayers {
+ for (NSArray<CALayer *> *layers in self.chartLineArray) {
+ for (CALayer *layer in layers) {
+ [layer removeFromSuperlayer];
+ }
+ }
+ for (CALayer *layer in self.chartPointArray) {
+ [layer removeFromSuperlayer];
+ }
+ self.chartLineArray = [NSMutableArray arrayWithCapacity:_chartData.count];
+ self.chartPointArray = [NSMutableArray arrayWithCapacity:_chartData.count];
+}
+
+-(void) resetCavanHeight {
+ _chartCavanHeight = self.frame.size.height - _chartMarginBottom - _chartMarginTop;
+ if (!_showLabel) {
+ _chartCavanHeight = self.frame.size.height - 2 * _yLabelHeight;
+ _chartCavanWidth = self.frame.size.width;
+ //_chartMargin = chartData.inflexionPointWidth;
+ _xLabelWidth = (_chartCavanWidth / ([_xLabels count]));
+ }
+}
+
+- (void)recreatePointLayers {
+ for (PNLineChartData *chartData in _chartData) {
+ // create as many chart line layers as there are data-lines
+ [self.chartLineArray addObject:[NSMutableArray new]];
+
+ // create point
+ CAShapeLayer *pointLayer = [CAShapeLayer layer];
+ pointLayer.strokeColor = [[chartData.color colorWithAlphaComponent:chartData.alpha] CGColor];
+ pointLayer.lineCap = kCALineCapRound;
+ pointLayer.lineJoin = kCALineJoinBevel;
+ pointLayer.fillColor = nil;
+ pointLayer.lineWidth = chartData.lineWidth;
+ [self.layer addSublayer:pointLayer];
+ [self.chartPointArray addObject:pointLayer];
+ }
+}
+
+- (void)prepareYLabelsWithData:(NSArray *)data {
+ CGFloat yMax = 0.0f;
+ CGFloat yMin = MAXFLOAT;
+ NSMutableArray *yLabelsArray = [NSMutableArray new];
+
+ for (PNLineChartData *chartData in data) {
+ // create as many chart line layers as there are data-lines
+
+ for (NSUInteger i = 0; i < chartData.itemCount; i++) {
+ CGFloat yValue = chartData.getData(i).y;
+ [yLabelsArray addObject:[NSString stringWithFormat:@"%2f", yValue]];
+ yMax = fmaxf(yMax, yValue);
+ yMin = fminf(yMin, yValue);
+ }
+ }
+
+
+ if (_yValueMin == -FLT_MAX) {
+ _yValueMin = (_yFixedValueMin > -FLT_MAX) ? _yFixedValueMin : yMin;
+ }
+ if (_yValueMax == -FLT_MAX) {
+ _yValueMax = (CGFloat) ((_yFixedValueMax > -FLT_MAX) ? _yFixedValueMax : yMax + yMax / 10.0);
+ }
+
+ if (_showGenYLabels) {
+ [self setYLabels];
+ }
+
+}
+
+#pragma mark - Update Chart Data
+
+- (void)updateChartData:(NSArray *)data {
+ _chartData = data;
+
+ [self prepareYLabelsWithData:data];
+
+ [self calculateChartPath:_chartPath
+ andPointsPath:_pointPath
+ andPathKeyPoints:_pathPoints
+ andPathStartEndPoints:_endPointsOfPath
+ andProgressLinePathsColors:_progressLinePathsColors];
+
+ for (NSUInteger lineIndex = 0; lineIndex < self.chartData.count; lineIndex++) {
+
+ CAShapeLayer *chartLine = (CAShapeLayer *) self.chartLineArray[lineIndex];
+ CAShapeLayer *pointLayer = (CAShapeLayer *) self.chartPointArray[lineIndex];
+
+
+ NSArray<UIBezierPath *> *progressLines = _chartPath[lineIndex];
+ UIBezierPath *pointPath = _pointPath[lineIndex];
+
+ for(UIBezierPath *progressLine in progressLines) {
+ CABasicAnimation *pathAnimation = [CABasicAnimation animationWithKeyPath:@"path"];
+ pathAnimation.fromValue = (id) chartLine.path;
+ pathAnimation.toValue = (__bridge id) [progressLine CGPath];
+ pathAnimation.duration = 0.5f;
+ pathAnimation.autoreverses = NO;
+ pathAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
+ [chartLine addAnimation:pathAnimation forKey:@"animationKey"];
+ chartLine.path = progressLine.CGPath;
+ }
+
+ CABasicAnimation *pointPathAnimation = [CABasicAnimation animationWithKeyPath:@"path"];
+ pointPathAnimation.fromValue = (id) pointLayer.path;
+ pointPathAnimation.toValue = (__bridge id) [pointPath CGPath];
+ pointPathAnimation.duration = 0.5f;
+ pointPathAnimation.autoreverses = NO;
+ pointPathAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
+ [pointLayer addAnimation:pointPathAnimation forKey:@"animationKey"];
+
+ pointLayer.path = pointPath.CGPath;
+
+
+ }
+
+}
+
+#define IOS7_OR_LATER [[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0
+
+- (void)drawRect:(CGRect)rect {
+ if (self.isShowCoordinateAxis) {
+ CGFloat yAxisOffset = 10.f;
+
+ CGContextRef ctx = UIGraphicsGetCurrentContext();
+ UIGraphicsPopContext();
+ UIGraphicsPushContext(ctx);
+ CGContextSetLineWidth(ctx, self.axisWidth);
+ CGContextSetStrokeColorWithColor(ctx, [self.axisColor CGColor]);
+
+ CGFloat xAxisWidth = CGRectGetWidth(rect) - (_chartMarginLeft + _chartMarginRight) / 2;
+ CGFloat yAxisHeight = _chartMarginBottom + _chartCavanHeight;
+
+ // draw coordinate axis
+ CGContextMoveToPoint(ctx, _chartMarginBottom + yAxisOffset, 0);
+ CGContextAddLineToPoint(ctx, _chartMarginBottom + yAxisOffset, yAxisHeight);
+ CGContextAddLineToPoint(ctx, xAxisWidth, yAxisHeight);
+ CGContextStrokePath(ctx);
+
+ // draw y axis arrow
+ CGContextMoveToPoint(ctx, _chartMarginBottom + yAxisOffset - 3, 6);
+ CGContextAddLineToPoint(ctx, _chartMarginBottom + yAxisOffset, 0);
+ CGContextAddLineToPoint(ctx, _chartMarginBottom + yAxisOffset + 3, 6);
+ CGContextStrokePath(ctx);
+
+ // draw x axis arrow
+ CGContextMoveToPoint(ctx, xAxisWidth - 6, yAxisHeight - 3);
+ CGContextAddLineToPoint(ctx, xAxisWidth, yAxisHeight);
+ CGContextAddLineToPoint(ctx, xAxisWidth - 6, yAxisHeight + 3);
+ CGContextStrokePath(ctx);
+
+ if (self.showLabel) {
+
+ // draw x axis separator
+ CGPoint point;
+ for (NSUInteger i = 0; i < [self.xLabels count]; i++) {
+ point = CGPointMake(2 * _chartMarginLeft + (i * _xLabelWidth), _chartMarginBottom + _chartCavanHeight);
+ CGContextMoveToPoint(ctx, point.x, point.y - 2);
+ CGContextAddLineToPoint(ctx, point.x, point.y);
+ CGContextStrokePath(ctx);
+ }
+
+ // draw y axis separator
+ CGFloat yStepHeight = _chartCavanHeight / _yLabelNum;
+ for (NSUInteger i = 0; i < [self.xLabels count]; i++) {
+ point = CGPointMake(_chartMarginBottom + yAxisOffset, (_chartCavanHeight - i * yStepHeight + _yLabelHeight / 2));
+ CGContextMoveToPoint(ctx, point.x, point.y);
+ CGContextAddLineToPoint(ctx, point.x + 2, point.y);
+ CGContextStrokePath(ctx);
+ }
+ }
+
+ UIFont *font = [UIFont systemFontOfSize:11];
+
+ // draw y unit
+ if ([self.yUnit length]) {
+ CGFloat height = [PNLineChart sizeOfString:self.yUnit withWidth:30.f font:font].height;
+ CGRect drawRect = CGRectMake(_chartMarginLeft + 10 + 5, 0, 30.f, height);
+ [self drawTextInContext:ctx text:self.yUnit inRect:drawRect font:font color:self.yLabelColor];
+ }
+
+ // draw x unit
+ if ([self.xUnit length]) {
+ CGFloat height = [PNLineChart sizeOfString:self.xUnit withWidth:30.f font:font].height;
+ CGRect drawRect = CGRectMake(CGRectGetWidth(rect) - _chartMarginLeft + 5, _chartMarginBottom + _chartCavanHeight - height / 2, 25.f, height);
+ [self drawTextInContext:ctx text:self.xUnit inRect:drawRect font:font color:self.xLabelColor];
+ }
+ }
+ if (self.showYGridLines) {
+ CGContextRef ctx = UIGraphicsGetCurrentContext();
+ CGFloat yAxisOffset = _showLabel ? 10.f : 0.0f;
+ CGPoint point;
+ CGFloat yStepHeight = _chartCavanHeight / _yLabelNum;
+ if (self.yGridLinesColor) {
+ CGContextSetStrokeColorWithColor(ctx, self.yGridLinesColor.CGColor);
+ } else {
+ CGContextSetStrokeColorWithColor(ctx, [UIColor lightGrayColor].CGColor);
+ }
+ for (NSUInteger i = 0; i < _yLabelNum; i++) {
+ point = CGPointMake(_chartMarginLeft + yAxisOffset, (_chartCavanHeight - i * yStepHeight + _yLabelHeight / 2));
+ CGContextMoveToPoint(ctx, point.x, point.y);
+ // add dotted style grid
+ CGFloat dash[] = {6, 5};
+ // dot diameter is 20 points
+ CGContextSetLineWidth(ctx, 0.5);
+ CGContextSetLineCap(ctx, kCGLineCapRound);
+ CGContextSetLineDash(ctx, 0.0, dash, 2);
+ CGContextAddLineToPoint(ctx, CGRectGetWidth(rect) - _chartMarginLeft + 5, point.y);
+ CGContextStrokePath(ctx);
+ }
+ }
+
+ [super drawRect:rect];
+}
+
+#pragma mark private methods
+
+/*
+ * helper function that maps a y value ( from chartData) to
+ * a position in the chart ( between _yValueMin and _yValueMax)
+ */
+- (CGFloat)yValuePositionInLineChart:(CGFloat)y {
+ CGFloat innerGrade;
+ if (!(_yValueMax - _yValueMin)) {
+ innerGrade = 0.5;
+ } else {
+ innerGrade = ((CGFloat) y - _yValueMin) / (_yValueMax - _yValueMin);
+ }
+ return _chartCavanHeight - (innerGrade * _chartCavanHeight) - (_yLabelHeight / 2) + _chartMarginTop;
+}
+
+/**
+ * return array of segments which represents the color and path
+ * for each segments.
+ * for instance if p1.y=1 and p2.y=10
+ * and rangeColor = use blue for 2<y<3 and red for 4<y<6
+ * then this function divides the space between p1 and p2 into three segments
+ * segment #1 : 1-2 : default color
+ * segment #2 : 2-3 : blue
+ * segment #3 : 3-4 : default color
+ * segment #4 : 4-6 : red
+ * segment #5: 6-10 : default color
+ *
+ * keep in mind that the rangeColors values are based on the chartData so it needs to
+ * convert those values to coordinates which are valid between yValueMin and yValueMax
+ *
+ * in order to find whether there is an overlap between any of the rangeColors and the
+ * p1-p2 it uses NSIntersectionRange to intersect their yValues.
+ *
+ * @param p1
+ * @param p2
+ * @param rangeColors
+ * @param defaultColor
+ * @return
+ */
+- (NSArray *)colorRangesBetweenP1:(CGPoint)p1 P2:(CGPoint)p2
+ rangeColors:(NSArray<PNLineChartColorRange *> *)rangeColors
+ defaultColor:(UIColor *)defaultColor {
+ if (rangeColors && rangeColors.count > 0 && p2.x > p1.x) {
+ PNLineChartColorRange *colorForRangeInfo = [[rangeColors firstObject] copy];
+ NSArray *remainingRanges = nil;
+ if (rangeColors.count > 1) {
+ remainingRanges = [rangeColors subarrayWithRange:NSMakeRange(1, rangeColors.count - 1)];
+ }
+ // tRange : convert the rangeColors.range values to value between yValueMin and yValueMax
+ CGFloat transformedStart = [self yValuePositionInLineChart:(CGFloat)
+ colorForRangeInfo.range.location];
+ CGFloat transformedEnd = [self yValuePositionInLineChart:(CGFloat)
+ (colorForRangeInfo.range.location + colorForRangeInfo.range.length)];
+
+ NSRange pathRange = NSMakeRange((NSUInteger) fmin(p1.y, p2.y), (NSUInteger) fabs(p2.y - p1.y));
+ NSRange tRange = NSMakeRange((NSUInteger) fmin(transformedStart, transformedEnd),
+ (NSUInteger) fabs(transformedEnd - transformedStart));
+ if (NSIntersectionRange(tRange, pathRange).length > 0) {
+ CGPoint partition1EndPoint;
+ CGPoint partition2EndPoint;
+ NSArray *partition1 = @[];
+ NSDictionary *partition2 = nil;
+ NSArray *partition3 = @[];
+ if (p2.y >= p1.y) {
+ partition1EndPoint = CGPointMake([PNLineChart xOfY:(CGFloat) fmax(p1.y, tRange.location)
+ betweenPoint1:p1
+ andPoint2:p2], (CGFloat) fmax(p1.y, tRange.location));
+ partition2EndPoint = CGPointMake([PNLineChart xOfY:(CGFloat) fmin(p2.y, tRange.location + tRange.length)
+ betweenPoint1:p1
+ andPoint2:p2], (CGFloat) fmin(p2.y, tRange.location + tRange.length));
+ } else {
+ partition1EndPoint = CGPointMake([PNLineChart xOfY:(CGFloat) fmin(p1.y, tRange.location + tRange.length)
+ betweenPoint1:p1
+ andPoint2:p2], (CGFloat) fmin(p1.y, tRange.location + tRange.length));
+ partition2EndPoint = CGPointMake([PNLineChart xOfY:(CGFloat) fmax(p2.y, tRange.location)
+ betweenPoint1:p1
+ andPoint2:p2], (CGFloat) fmax(p2.y, tRange.location));
+ }
+ if (p1.y != partition1EndPoint.y) {
+ partition1 = [self colorRangesBetweenP1:p1
+ P2:partition1EndPoint
+ rangeColors:remainingRanges
+ defaultColor:defaultColor];
+ }
+ partition2 = @{
+ @"color": colorForRangeInfo.color,
+ @"from": [NSValue valueWithCGPoint:partition1EndPoint],
+ @"to": [NSValue valueWithCGPoint:partition2EndPoint]};
+ if (p2.y != partition2EndPoint.y) {
+ partition3 = [self colorRangesBetweenP1:partition2EndPoint
+ P2:p2
+ rangeColors:remainingRanges
+ defaultColor:defaultColor];
+ }
+ return [[partition1 arrayByAddingObject:partition2] arrayByAddingObjectsFromArray:partition3];
+ } else {
+
+ return [self colorRangesBetweenP1:p1
+ P2:p2
+ rangeColors:remainingRanges
+ defaultColor:defaultColor];
+ }
+ } else {
+ return @[@{
+ @"color": defaultColor,
+ @"from": [NSValue valueWithCGPoint:p1],
+ @"to": [NSValue valueWithCGPoint:p2]}];
+ }
+}
+
+
+- (void)setupDefaultValues {
+ [super setupDefaultValues];
+ // Initialization code
+ self.backgroundColor = [UIColor whiteColor];
+ self.clipsToBounds = YES;
+ self.chartLineArray = [NSMutableArray new];
+ _showLabel = YES;
+ _showGenYLabels = YES;
+ _pathPoints = [[NSMutableArray alloc] init];
+ _endPointsOfPath = [[NSMutableArray alloc] init];
+ self.userInteractionEnabled = YES;
+
+ _yFixedValueMin = -FLT_MAX;
+ _yFixedValueMax = -FLT_MAX;
+ _yValueMax = -FLT_MAX;
+ _yValueMin = -FLT_MAX;
+ _yLabelNum = 5;
+ _yLabelHeight = [[[[PNChartLabel alloc] init] font] pointSize];
+
+// _chartMargin = 40;
+
+ _chartMarginLeft = 25.0;
+ _chartMarginRight = 25.0;
+ _chartMarginTop = 25.0;
+ _chartMarginBottom = 25.0;
+
+ _yLabelFormat = @"%1.f";
+
+ _chartCavanWidth = self.frame.size.width - _chartMarginLeft - _chartMarginRight;
+ _chartCavanHeight = self.frame.size.height - _chartMarginBottom - _chartMarginTop;
+
+ // Coordinate Axis Default Values
+ _showCoordinateAxis = NO;
+ _axisColor = [UIColor colorWithRed:0.4f green:0.4f blue:0.4f alpha:1.f];
+ _axisWidth = 1.f;
+
+ // do not create curved line chart by default
+ _showSmoothLines = NO;
+
+}
+
+#pragma mark - tools
+
++ (CGSize)sizeOfString:(NSString *)text withWidth:(float)width font:(UIFont *)font {
+ CGSize size = CGSizeMake(width, MAXFLOAT);
+
+ if ([text respondsToSelector:@selector(boundingRectWithSize:options:attributes:context:)]) {
+ NSDictionary *tdic = @{NSFontAttributeName: font};
+ size = [text boundingRectWithSize:size
+ options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading
+ attributes:tdic
+ context:nil].size;
+ } else {
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+ size = [text sizeWithFont:font constrainedToSize:size lineBreakMode:NSLineBreakByCharWrapping];
+#pragma clang diagnostic pop
+ }
+
+ return size;
+}
+
++ (CGPoint)midPointBetweenPoint1:(CGPoint)point1 andPoint2:(CGPoint)point2 {
+ return CGPointMake((point1.x + point2.x) / 2, (point1.y + point2.y) / 2);
+}
+
++ (CGFloat)xOfY:(CGFloat)y betweenPoint1:(CGPoint)point1 andPoint2:(CGPoint)point2 {
+ CGFloat m = (point2.y - point1.y) / (point2.x - point1.x);
+ // formulate = y - y1 = m (x - x1) = mx - mx1 -> mx = y - y1 + mx1 ->
+ // x = (y - y1 + mx1) / m
+ return (y - point1.y + m * point1.x) / m;
+}
+
+
++ (CGPoint)controlPointBetweenPoint1:(CGPoint)point1 andPoint2:(CGPoint)point2 {
+ CGPoint controlPoint = [self midPointBetweenPoint1:point1 andPoint2:point2];
+ CGFloat diffY = abs((int) (point2.y - controlPoint.y));
+ if (point1.y < point2.y)
+ controlPoint.y += diffY;
+ else if (point1.y > point2.y)
+ controlPoint.y -= diffY;
+ return controlPoint;
+}
+
+- (void)drawTextInContext:(CGContextRef)ctx text:(NSString *)text inRect:(CGRect)rect font:(UIFont *)font color:(UIColor *)color {
+ if (IOS7_OR_LATER) {
+ NSMutableParagraphStyle *priceParagraphStyle = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
+ priceParagraphStyle.lineBreakMode = NSLineBreakByTruncatingTail;
+ priceParagraphStyle.alignment = NSTextAlignmentLeft;
+
+ if (color != nil) {
+ [text drawInRect:rect
+ withAttributes:@{NSParagraphStyleAttributeName: priceParagraphStyle, NSFontAttributeName: font,
+ NSForegroundColorAttributeName: color}];
+ } else {
+ [text drawInRect:rect
+ withAttributes:@{NSParagraphStyleAttributeName: priceParagraphStyle, NSFontAttributeName: font}];
+ }
+ } else {
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+ [text drawInRect:rect
+ withFont:font
+ lineBreakMode:NSLineBreakByTruncatingTail
+ alignment:NSTextAlignmentLeft];
+#pragma clang diagnostic pop
+ }
+}
+
+- (NSString *)formatYLabel:(double)value {
+
+ if (self.yLabelBlockFormatter) {
+ return self.yLabelBlockFormatter((CGFloat) value);
+ } else {
+ if (!self.thousandsSeparator) {
+ NSString *format = self.yLabelFormat ?: @"%1.f";
+ return [NSString stringWithFormat:format, value];
+ }
+
+ NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init];
+ [numberFormatter setFormatterBehavior:NSNumberFormatterBehavior10_4];
+ [numberFormatter setNumberStyle:NSNumberFormatterDecimalStyle];
+ return [numberFormatter stringFromNumber:@(value)];
+ }
+}
+
+- (UIView *)getLegendWithMaxWidth:(CGFloat)mWidth {
+ if ([self.chartData count] < 1) {
+ return nil;
+ }
+
+ /* This is a short line that refers to the chart data */
+ CGFloat legendLineWidth = 40;
+
+ /* x and y are the coordinates of the starting point of each legend item */
+ CGFloat x = 0;
+ CGFloat y = 0;
+
+ /* accumulated height */
+ CGFloat totalHeight = 0;
+ CGFloat totalWidth = 0;
+
+ NSMutableArray *legendViews = [[NSMutableArray alloc] init];
+
+ /* Determine the max width of each legend item */
+ CGFloat maxLabelWidth;
+ if (self.legendStyle == PNLegendItemStyleStacked) {
+ maxLabelWidth = mWidth - legendLineWidth;
+ } else {
+ maxLabelWidth = MAXFLOAT;
+ }
+
+ /* this is used when labels wrap text and the line
+ * should be in the middle of the first row */
+ CGFloat singleRowHeight = [PNLineChart sizeOfString:@"Test"
+ withWidth:MAXFLOAT
+ font:self.legendFont ? self.legendFont : [UIFont systemFontOfSize:12.0f]].height;
+
+ NSUInteger counter = 0;
+ NSUInteger rowWidth = 0;
+ NSUInteger rowMaxHeight = 0;
+
+ for (PNLineChartData *pdata in self.chartData) {
+ /* Expected label size*/
+ CGSize labelsize = [PNLineChart sizeOfString:pdata.dataTitle
+ withWidth:maxLabelWidth
+ font:self.legendFont ? self.legendFont : [UIFont systemFontOfSize:12.0f]];
+
+ /* draw lines */
+ if ((rowWidth + labelsize.width + legendLineWidth > mWidth) && (self.legendStyle == PNLegendItemStyleSerial)) {
+ rowWidth = 0;
+ x = 0;
+ y += rowMaxHeight;
+ rowMaxHeight = 0;
+ }
+ rowWidth += labelsize.width + legendLineWidth;
+ totalWidth = self.legendStyle == PNLegendItemStyleSerial ? fmaxf(rowWidth, totalWidth) : fmaxf(totalWidth, labelsize.width + legendLineWidth);
+
+ /* If there is inflection decorator, the line is composed of two lines
+ * and this is the space that separates two lines in order to put inflection
+ * decorator */
+
+ CGFloat inflexionWidthSpacer = pdata.inflexionPointStyle == PNLineChartPointStyleTriangle ? pdata.inflexionPointWidth / 2 : pdata.inflexionPointWidth;
+
+ CGFloat halfLineLength;
+
+ if (pdata.inflexionPointStyle != PNLineChartPointStyleNone) {
+ halfLineLength = (CGFloat) ((legendLineWidth * 0.8 - inflexionWidthSpacer) / 2);
+ } else {
+ halfLineLength = (CGFloat) (legendLineWidth * 0.8);
+ }
+
+ UIView *line = [[UIView alloc] initWithFrame:CGRectMake((CGFloat) (x + legendLineWidth * 0.1), y + (singleRowHeight - pdata.lineWidth) / 2, halfLineLength, pdata.lineWidth)];
+
+ line.backgroundColor = pdata.color;
+ line.alpha = pdata.alpha;
+ [legendViews addObject:line];
+
+ if (pdata.inflexionPointStyle != PNLineChartPointStyleNone) {
+ line = [[UIView alloc] initWithFrame:CGRectMake((CGFloat) (x + legendLineWidth * 0.1 + halfLineLength + inflexionWidthSpacer), y + (singleRowHeight - pdata.lineWidth) / 2, halfLineLength, pdata.lineWidth)];
+ line.backgroundColor = pdata.color;
+ line.alpha = pdata.alpha;
+ [legendViews addObject:line];
+ }
+
+ // Add inflexion type
+ UIColor *inflexionPointColor = pdata.inflexionPointColor;
+ if (!inflexionPointColor) {
+ inflexionPointColor = pdata.color;
+ }
+ [legendViews addObject:[self drawInflexion:pdata.inflexionPointWidth
+ center:CGPointMake(x + legendLineWidth / 2, y + singleRowHeight / 2)
+ strokeWidth:pdata.lineWidth
+ inflexionStyle:pdata.inflexionPointStyle
+ andColor:inflexionPointColor
+ andAlpha:pdata.alpha]];
+
+ UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(x + legendLineWidth, y, labelsize.width, labelsize.height)];
+ label.text = pdata.dataTitle;
+ label.textColor = self.legendFontColor ? self.legendFontColor : [UIColor blackColor];
+ label.font = self.legendFont ? self.legendFont : [UIFont systemFontOfSize:12.0f];
+ label.lineBreakMode = NSLineBreakByWordWrapping;
+ label.numberOfLines = 0;
+
+ rowMaxHeight = (NSUInteger) fmaxf(rowMaxHeight, labelsize.height);
+ x += self.legendStyle == PNLegendItemStyleStacked ? 0 : labelsize.width + legendLineWidth;
+ y += self.legendStyle == PNLegendItemStyleStacked ? labelsize.height : 0;
+
+
+ totalHeight = self.legendStyle == PNLegendItemStyleSerial ? fmaxf(totalHeight, rowMaxHeight + y) : totalHeight + labelsize.height;
+
+ [legendViews addObject:label];
+ counter++;
+ }
+
+ UIView *legend = [[UIView alloc] initWithFrame:CGRectMake(0, 0, mWidth, totalHeight)];
+
+ for (UIView *v in legendViews) {
+ [legend addSubview:v];
+ }
+ return legend;
+}
+
+
+- (UIImageView *)drawInflexion:(CGFloat)size center:(CGPoint)center strokeWidth:(CGFloat)sw inflexionStyle:(PNLineChartPointStyle)type andColor:(UIColor *)color andAlpha:(CGFloat)alfa {
+ //Make the size a little bigger so it includes also border stroke
+ CGSize aSize = CGSizeMake(size + sw, size + sw);
+
+
+ UIGraphicsBeginImageContextWithOptions(aSize, NO, 0.0);
+ CGContextRef context = UIGraphicsGetCurrentContext();
+
+
+ if (type == PNLineChartPointStyleCircle) {
+ CGContextAddArc(context, (size + sw) / 2, (size + sw) / 2, size / 2, 0, (CGFloat) (M_PI * 2), YES);
+ } else if (type == PNLineChartPointStyleSquare) {
+ CGContextAddRect(context, CGRectMake(sw / 2, sw / 2, size, size));
+ } else if (type == PNLineChartPointStyleTriangle) {
+ CGContextMoveToPoint(context, sw / 2, size + sw / 2);
+ CGContextAddLineToPoint(context, size + sw / 2, size + sw / 2);
+ CGContextAddLineToPoint(context, size / 2 + sw / 2, sw / 2);
+ CGContextAddLineToPoint(context, sw / 2, size + sw / 2);
+ CGContextClosePath(context);
+ }
+
+ //Set some stroke properties
+ CGContextSetLineWidth(context, sw);
+ CGContextSetAlpha(context, alfa);
+ CGContextSetStrokeColorWithColor(context, color.CGColor);
+
+ //Finally draw
+ CGContextDrawPath(context, kCGPathStroke);
+
+ //now get the image from the context
+ UIImage *squareImage = UIGraphicsGetImageFromCurrentImageContext();
+
+ UIGraphicsEndImageContext();
+
+ //// Translate origin
+ CGFloat originX = (CGFloat) (center.x - (size + sw) / 2.0);
+ CGFloat originY = (CGFloat) (center.y - (size + sw) / 2.0);
+
+ UIImageView *squareImageView = [[UIImageView alloc] initWithImage:squareImage];
+ [squareImageView setFrame:CGRectMake(originX, originY, size + sw, size + sw)];
+ return squareImageView;
+}
+
+#pragma mark setter and getter
+
+- (CATextLayer *)createPointLabelFor:(CGFloat)grade pointCenter:(CGPoint)pointCenter width:(CGFloat)width withChartData:(PNLineChartData *)chartData {
+ CATextLayer *textLayer = [[CATextLayer alloc] init];
+ [textLayer setAlignmentMode:kCAAlignmentCenter];
+ [textLayer setForegroundColor:[chartData.pointLabelColor CGColor]];
+ [textLayer setBackgroundColor:self.backgroundColor.CGColor];
+// [textLayer setBackgroundColor:[self.backgroundColor colorWithAlphaComponent:0.8].CGColor];
+// [textLayer setCornerRadius:(CGFloat) (textLayer.fontSize / 8.0)];
+
+ if (chartData.pointLabelFont != nil) {
+ [textLayer setFont:(__bridge CFTypeRef) (chartData.pointLabelFont)];
+ textLayer.fontSize = [chartData.pointLabelFont pointSize];
+ }
+
+ CGFloat textHeight = (CGFloat) (textLayer.fontSize * 1.1);
+ // FIXME: convert the grade to string and use its length instead of hardcoding 8
+ CGFloat textWidth = width * 8;
+ CGFloat textStartPosY;
+
+ textStartPosY = pointCenter.y - textLayer.fontSize;
+
+ [self.layer addSublayer:textLayer];
+
+ if (chartData.pointLabelFormat != nil) {
+ [textLayer setString:[[NSString alloc] initWithFormat:chartData.pointLabelFormat, grade]];
+ } else {
+ [textLayer setString:[[NSString alloc] initWithFormat:_yLabelFormat, grade]];
+ }
+
+ [textLayer setFrame:CGRectMake(0, 0, textWidth, textHeight)];
+ [textLayer setPosition:CGPointMake(pointCenter.x, textStartPosY)];
+ textLayer.contentsScale = [UIScreen mainScreen].scale;
+
+ return textLayer;
+}
+
+- (CABasicAnimation *)fadeAnimation {
+ CABasicAnimation *fadeAnimation = nil;
+ if (self.displayAnimated) {
+ fadeAnimation = [CABasicAnimation animationWithKeyPath:@"opacity"];
+ fadeAnimation.fromValue = @0.0F;
+ fadeAnimation.toValue = @1.0F;
+ fadeAnimation.duration = 2.0;
+ }
+ return fadeAnimation;
+}
+
+- (CABasicAnimation *)pathAnimation {
+ if (self.displayAnimated && !_pathAnimation) {
+ _pathAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
+ _pathAnimation.duration = 1.0;
+ _pathAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
+ _pathAnimation.fromValue = @0.0f;
+ _pathAnimation.toValue = @1.0f;
+ }
+ if(!self.displayAnimated) {
+ _pathAnimation = nil;
+ }
+ return _pathAnimation;
+}
+
+@end
diff --git a/PNChartdemo/PNChartdemo/PNChart/PNLineChartData.h b/PNChartdemo/PNChartdemo/PNChart/PNLineChartData.h
new file mode 100755
index 0000000..2158e8e
--- /dev/null
+++ b/PNChartdemo/PNChartdemo/PNChart/PNLineChartData.h
@@ -0,0 +1,61 @@
+//
+// Created by J��rg Polakowski on 14/12/13.
+// Copyright (c) 2013 kevinzhow. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+#import <UIKit/UIKit.h>
+
+typedef NS_ENUM(NSUInteger, PNLineChartPointStyle) {
+ PNLineChartPointStyleNone = 0,
+ PNLineChartPointStyleCircle = 1,
+ PNLineChartPointStyleSquare = 3,
+ PNLineChartPointStyleTriangle = 4
+};
+
+@class PNLineChartDataItem;
+
+typedef PNLineChartDataItem *(^LCLineChartDataGetter)(NSUInteger item);
+
+@interface PNLineChartColorRange : NSObject<NSCopying>
+
+@property(nonatomic) NSRange range;
+@property(nonatomic) BOOL inclusive;
+@property(nonatomic, retain) UIColor *color;
+
+- (id)initWithRange:(NSRange)range color:(UIColor *)color;
+
+@end
+
+@interface PNLineChartData : NSObject
+
+@property (strong) UIColor *color;
+@property (nonatomic) CGFloat alpha;
+@property NSUInteger itemCount;
+@property (copy) LCLineChartDataGetter getData;
+@property (strong, nonatomic) NSString *dataTitle;
+
+@property (nonatomic) BOOL showPointLabel;
+@property (nonatomic) UIColor *pointLabelColor;
+@property (nonatomic) UIFont *pointLabelFont;
+@property (nonatomic) NSString *pointLabelFormat;
+
+@property (nonatomic, assign) PNLineChartPointStyle inflexionPointStyle;
+@property (nonatomic) UIColor *inflexionPointColor;
+
+/**
+ * if rangeColor is set and the lineChartData values are within any
+ * of the given range then use the rangeColor.color otherwise use
+ * self.color for the rest of the graph
+ */
+@property(strong) NSArray<PNLineChartColorRange *> *rangeColors;
+
+/**
+ * If PNLineChartPointStyle is circle, this returns the circle's diameter.
+ * If PNLineChartPointStyle is square, each point is a square with each side equal in length to this value.
+ */
+@property (nonatomic, assign) CGFloat inflexionPointWidth;
+
+@property (nonatomic, assign) CGFloat lineWidth;
+
+@end
diff --git a/PNChartdemo/PNChartdemo/PNChart/PNLineChartData.m b/PNChartdemo/PNChartdemo/PNChart/PNLineChartData.m
new file mode 100755
index 0000000..bbf2647
--- /dev/null
+++ b/PNChartdemo/PNChartdemo/PNChart/PNLineChartData.m
@@ -0,0 +1,54 @@
+//
+// Created by J��rg Polakowski on 14/12/13.
+// Copyright (c) 2013 kevinzhow. All rights reserved.
+//
+
+#import "PNLineChartData.h"
+
+
+@implementation PNLineChartColorRange
+
+- (id)initWithRange:(NSRange)range color:(UIColor *)color {
+ self = [super init];
+ if (self) {
+ self.range = range;
+ self.color = color;
+ }
+ return self;
+}
+
+
+- (id)copyWithZone:(NSZone *)zone {
+ PNLineChartColorRange *copy = [[self class] allocWithZone:zone];
+ copy.color = self.color;
+ copy.range = self.range;
+ return copy;
+}
+
+@end
+
+@implementation PNLineChartData
+
+- (id)init
+{
+ self = [super init];
+ if (self) {
+ [self setupDefaultValues];
+ }
+
+ return self;
+}
+
+- (void)setupDefaultValues
+{
+ _inflexionPointStyle = PNLineChartPointStyleNone;
+ _inflexionPointWidth = 6.f;
+ _lineWidth = 2.f;
+ _alpha = 1.f;
+ _showPointLabel = NO;
+ _pointLabelColor = [UIColor blackColor];
+ _pointLabelFormat = @"%1.f";
+ _rangeColors = nil;
+}
+
+@end
diff --git a/PNChartdemo/PNChartdemo/PNChart/PNLineChartDataItem.h b/PNChartdemo/PNChartdemo/PNChart/PNLineChartDataItem.h
new file mode 100755
index 0000000..ad2d23d
--- /dev/null
+++ b/PNChartdemo/PNChartdemo/PNChart/PNLineChartDataItem.h
@@ -0,0 +1,17 @@
+//
+// Created by J��rg Polakowski on 14/12/13.
+// Copyright (c) 2013 kevinzhow. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+#import <UIKit/UIKit.h>
+
+@interface PNLineChartDataItem : NSObject
+
++ (PNLineChartDataItem *)dataItemWithY:(CGFloat)y;
++ (PNLineChartDataItem *)dataItemWithY:(CGFloat)y andRawY:(CGFloat)rawY;
+
+@property (readonly) CGFloat y; // should be within the y range
+@property (readonly) CGFloat rawY; // this is the raw value, used for point label.
+
+@end
diff --git a/PNChartdemo/PNChartdemo/PNChart/PNLineChartDataItem.m b/PNChartdemo/PNChartdemo/PNChart/PNLineChartDataItem.m
new file mode 100755
index 0000000..1beea91
--- /dev/null
+++ b/PNChartdemo/PNChartdemo/PNChart/PNLineChartDataItem.m
@@ -0,0 +1,38 @@
+//
+// Created by J��rg Polakowski on 14/12/13.
+// Copyright (c) 2013 kevinzhow. All rights reserved.
+//
+
+#import "PNLineChartDataItem.h"
+
+@interface PNLineChartDataItem ()
+
+- (id)initWithY:(CGFloat)y andRawY:(CGFloat)rawY;
+
+@property (readwrite) CGFloat y; // should be within the y range
+@property (readwrite) CGFloat rawY; // this is the raw value, used for point label.
+
+@end
+
+@implementation PNLineChartDataItem
+
++ (PNLineChartDataItem *)dataItemWithY:(CGFloat)y
+{
+ return [[PNLineChartDataItem alloc] initWithY:y andRawY:y];
+}
+
++ (PNLineChartDataItem *)dataItemWithY:(CGFloat)y andRawY:(CGFloat)rawY {
+ return [[PNLineChartDataItem alloc] initWithY:y andRawY:rawY];
+}
+
+- (id)initWithY:(CGFloat)y andRawY:(CGFloat)rawY
+{
+ if ((self = [super init])) {
+ self.y = y;
+ self.rawY = rawY;
+ }
+
+ return self;
+}
+
+@end
diff --git a/PNChartdemo/PNChartdemo/PNChart/PNPieChart.h b/PNChartdemo/PNChartdemo/PNChart/PNPieChart.h
new file mode 100755
index 0000000..204afb5
--- /dev/null
+++ b/PNChartdemo/PNChartdemo/PNChart/PNPieChart.h
@@ -0,0 +1,68 @@
+//
+// 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"
+#import "PNGenericChart.h"
+#import "PNChartDelegate.h"
+
+@interface PNPieChart : PNGenericChart
+
+- (id)initWithFrame:(CGRect)frame items:(NSArray *)items;
+
+@property (nonatomic, readonly) NSArray *items;
+
+/** Default is 18-point Avenir Medium. */
+@property (nonatomic) UIFont *descriptionTextFont;
+
+/** Default is white. */
+@property (nonatomic) UIColor *descriptionTextColor;
+
+/** Default is black, with an alpha of 0.4. */
+@property (nonatomic) UIColor *descriptionTextShadowColor;
+
+/** Default is CGSizeMake(0, 1). */
+@property (nonatomic) CGSize descriptionTextShadowOffset;
+
+/** Default is 1.0. */
+@property (nonatomic) NSTimeInterval duration;
+
+/** Show only values, this is useful when legend is present */
+@property (nonatomic) BOOL showOnlyValues;
+
+/** Show absolute values not relative i.e. percentages */
+@property (nonatomic) BOOL showAbsoluteValues;
+
+/** Hide percentage labels less than cutoff value */
+@property (nonatomic, assign) CGFloat labelPercentageCutoff;
+
+/** Default YES. */
+@property (nonatomic) BOOL shouldHighlightSectorOnTouch;
+
+/** Current outer radius. Override recompute() to change this. **/
+@property (nonatomic) CGFloat outerCircleRadius;
+
+/** Current inner radius. Override recompute() to change this. **/
+@property (nonatomic) CGFloat innerCircleRadius;
+
+@property (nonatomic, weak) id<PNChartDelegate> delegate;
+
+/** Update chart items. Does not update chart itself. */
+- (void)updateChartData:(NSArray *)data;
+
+/** Multiple selection */
+@property (nonatomic, assign) BOOL enableMultipleSelection;
+
+/** show only tiles, not values or percentage */
+@property (nonatomic) BOOL hideValues;
+
+- (void)strokeChart;
+
+- (void)recompute;
+
+@end
diff --git a/PNChartdemo/PNChartdemo/PNChart/PNPieChart.m b/PNChartdemo/PNChartdemo/PNChart/PNPieChart.m
new file mode 100755
index 0000000..ae9ab7a
--- /dev/null
+++ b/PNChartdemo/PNChartdemo/PNChart/PNPieChart.m
@@ -0,0 +1,508 @@
+//
+// PNPieChart.m
+// PNChartDemo
+//
+// Created by Hang Zhang on 14-5-5.
+// Copyright (c) 2014��� kevinzhow. All rights reserved.
+//
+
+#import "PNPieChart.h"
+//needed for the expected label size
+#import "PNLineChart.h"
+
+@interface PNPieChart()
+
+@property (nonatomic) NSArray *items;
+@property (nonatomic) NSArray *endPercentages;
+
+@property (nonatomic) UIView *contentView;
+@property (nonatomic) CAShapeLayer *pieLayer;
+@property (nonatomic) NSMutableArray *descriptionLabels;
+@property (strong, nonatomic) CAShapeLayer *sectorHighlight;
+
+@property (nonatomic, strong) NSMutableDictionary *selectedItems;
+
+- (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
+ 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];
+ [self baseInit];
+ }
+
+ return self;
+}
+
+- (void)awakeFromNib{
+ [super awakeFromNib];
+ [self baseInit];
+}
+
+- (void)baseInit{
+ _selectedItems = [NSMutableDictionary dictionary];
+ //������������������,���������������������������������������������,������������������,���������������,���������������view���������,���������������������������������
+
+ CGFloat minimal = (CGRectGetWidth(self.bounds) < CGRectGetHeight(self.bounds)) ? CGRectGetWidth(self.bounds) : CGRectGetHeight(self.bounds);
+
+ _outerCircleRadius = minimal / 2;
+ _innerCircleRadius = minimal / 6;
+// _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;
+ _shouldHighlightSectorOnTouch = YES;
+ _enableMultipleSelection = NO;
+ _hideValues = NO;
+
+ [super setupDefaultValues];
+ [self loadDefault];
+}
+
+- (void)loadDefault{
+ __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];
+
+}
+
+/** Override this to change how inner attributes are computed. **/
+- (void)recompute {
+
+ //������
+ CGFloat minimal = (CGRectGetWidth(self.bounds) < CGRectGetHeight(self.bounds)) ? CGRectGetWidth(self.bounds) : CGRectGetHeight(self.bounds);
+ self.outerCircleRadius = minimal / 2;
+ self.innerCircleRadius = minimal / 6;
+}
+
+#pragma mark -
+
+- (void)strokeChart{
+ [self loadDefault];
+ [self recompute];
+
+ PNPieChartDataItem *currentItem;
+ for (int i = 0; i < _items.count; i++) {
+ currentItem = [self dataItemForIndex:i];
+
+
+ CGFloat startPercentage = [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:startPercentage
+ endPercentage:endPercentage];
+ [_pieLayer addSublayer:currentPieLayer];
+ }
+
+ [self maskChart];
+
+ for (int i = 0; i < _items.count; i++) {
+ UILabel *descriptionLabel = [self descriptionLabelForItemAtIndex:i];
+ [_contentView addSubview:descriptionLabel];
+ [_descriptionLabels addObject:descriptionLabel];
+ }
+
+ [self addAnimationIfNeeded];
+}
+
+- (UILabel *)descriptionLabelForItemAtIndex:(NSUInteger)index{
+ PNPieChartDataItem *currentDataItem = [self dataItemForIndex:index];
+ CGFloat distance = _innerCircleRadius + (_outerCircleRadius - _innerCircleRadius) / 2;
+ CGFloat centerPercentage = ([self startPercentageForItemAtIndex:index] + [self endPercentageForItemAtIndex:index])/ 2;
+ CGFloat rad = centerPercentage * 2 * M_PI;
+
+ UILabel *descriptionLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 100, 80)];
+ NSString *titleText = currentDataItem.textDescription;
+
+ NSString *titleValue;
+
+ if (self.showAbsoluteValues) {
+ titleValue = [NSString stringWithFormat:@"%.0f",currentDataItem.value];
+ }else{
+ titleValue = [NSString stringWithFormat:@"%.0f%%",[self ratioForItemAtIndex:index] * 100];
+ }
+
+ if (self.hideValues)
+ descriptionLabel.text = titleText;
+ else if(!titleText || self.showOnlyValues)
+ descriptionLabel.text = titleValue;
+ else {
+ NSString* str = [titleValue stringByAppendingString:[NSString stringWithFormat:@"\n%@",titleText]];
+ descriptionLabel.text = str ;
+ }
+
+ //If value is less than cutoff, show no label
+ if ([self ratioForItemAtIndex:index] < self.labelPercentageCutoff )
+ {
+ descriptionLabel.text = nil;
+ }
+
+ CGPoint center = CGPointMake(_outerCircleRadius + distance * sin(rad),
+ _outerCircleRadius - distance * cos(rad));
+
+ 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.backgroundColor = [UIColor clearColor];
+ return descriptionLabel;
+}
+
+- (void)updateChartData:(NSArray *)items {
+ self.items = items;
+}
+
+- (PNPieChartDataItem *)dataItemForIndex:(NSUInteger)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
+
+- (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{
+ 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;
+}
+
+- (void)addAnimationIfNeeded{
+ if (self.displayAnimated) {
+ 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;
+ [_pieLayer.mask addAnimation:animation forKey:@"circleAnimation"];
+ }
+ else {
+ // Add description labels since no animation is required
+ [_descriptionLabels enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
+ [obj setAlpha:1];
+ }];
+ }
+}
+
+- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag{
+ [_descriptionLabels enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
+ [UIView animateWithDuration:0.2 animations:^(){
+ [obj setAlpha:1];
+ }];
+ }];
+}
+
+- (void)didTouchAt:(CGPoint)touchLocation
+{
+ CGPoint circleCenter = CGPointMake(_contentView.bounds.size.width/2, _contentView.bounds.size.height/2);
+
+ CGFloat distanceFromCenter = sqrtf(powf((touchLocation.y - circleCenter.y),2) + powf((touchLocation.x - circleCenter.x),2));
+
+ if (distanceFromCenter < _innerCircleRadius) {
+ if ([self.delegate respondsToSelector:@selector(didUnselectPieItem)]) {
+ [self.delegate didUnselectPieItem];
+ }
+ [self.sectorHighlight removeFromSuperlayer];
+ return;
+ }
+
+ CGFloat percentage = [self findPercentageOfAngleInCircle:circleCenter fromPoint:touchLocation];
+ int index = 0;
+ while (percentage > [self endPercentageForItemAtIndex:index]) {
+ index ++;
+ }
+
+ if ([self.delegate respondsToSelector:@selector(userClickedOnPieIndexItem:)]) {
+ [self.delegate userClickedOnPieIndexItem:index];
+ }
+
+ if (self.shouldHighlightSectorOnTouch)
+ {
+ if (!self.enableMultipleSelection)
+ {
+ if (self.sectorHighlight)
+ [self.sectorHighlight removeFromSuperlayer];
+ }
+
+ PNPieChartDataItem *currentItem = [self dataItemForIndex:index];
+
+ CGFloat red,green,blue,alpha;
+ UIColor *old = currentItem.color;
+ [old getRed:&red green:&green blue:&blue alpha:&alpha];
+ alpha /= 2;
+ UIColor *newColor = [UIColor colorWithRed:red green:green blue:blue alpha:alpha];
+
+ CGFloat startPercentage = [self startPercentageForItemAtIndex:index];
+ CGFloat endPercentage = [self endPercentageForItemAtIndex:index];
+
+ self.sectorHighlight = [self newCircleLayerWithRadius:_outerCircleRadius + 5
+ borderWidth:10
+ fillColor:[UIColor clearColor]
+ borderColor:newColor
+ startPercentage:startPercentage
+ endPercentage:endPercentage];
+
+ if (self.enableMultipleSelection)
+ {
+ NSString *dictIndex = [NSString stringWithFormat:@"%d", index];
+ CAShapeLayer *indexShape = [self.selectedItems valueForKey:dictIndex];
+ if (indexShape)
+ {
+ [indexShape removeFromSuperlayer];
+ [self.selectedItems removeObjectForKey:dictIndex];
+ }
+ else
+ {
+ [self.selectedItems setObject:self.sectorHighlight forKey:dictIndex];
+ [_contentView.layer addSublayer:self.sectorHighlight];
+ }
+ }
+ else
+ {
+ [_contentView.layer addSublayer:self.sectorHighlight];
+ }
+ }
+}
+
+- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
+{
+ for (UITouch *touch in touches) {
+ CGPoint touchLocation = [touch locationInView:_contentView];
+ [self didTouchAt:touchLocation];
+ }
+}
+
+- (CGFloat) findPercentageOfAngleInCircle:(CGPoint)center fromPoint:(CGPoint)reference{
+ //Find angle of line Passing In Reference And Center
+ CGFloat angleOfLine = atanf((reference.y - center.y) / (reference.x - center.x));
+ CGFloat percentage = (angleOfLine + M_PI/2)/(2 * M_PI);
+ return (reference.x - center.x) > 0 ? percentage : percentage + .5;
+}
+
+- (UIView*) getLegendWithMaxWidth:(CGFloat)mWidth{
+ if ([self.items count] < 1) {
+ return nil;
+ }
+
+ /* This is a small circle that refers to the chart data */
+ CGFloat legendCircle = 16;
+
+ CGFloat hSpacing = 0;
+
+ CGFloat beforeLabel = legendCircle + hSpacing;
+
+ /* x and y are the coordinates of the starting point of each legend item */
+ CGFloat x = 0;
+ CGFloat y = 0;
+
+ /* accumulated width and height */
+ CGFloat totalWidth = 0;
+ CGFloat totalHeight = 0;
+
+ NSMutableArray *legendViews = [[NSMutableArray alloc] init];
+
+ /* Determine the max width of each legend item */
+ CGFloat maxLabelWidth;
+ if (self.legendStyle == PNLegendItemStyleStacked) {
+ maxLabelWidth = mWidth - beforeLabel;
+ }else{
+ maxLabelWidth = MAXFLOAT;
+ }
+
+ /* this is used when labels wrap text and the line
+ * should be in the middle of the first row */
+ CGFloat singleRowHeight = [PNLineChart sizeOfString:@"Test"
+ withWidth:MAXFLOAT
+ font:self.legendFont ? self.legendFont : [UIFont systemFontOfSize:12.0f]].height;
+
+ NSUInteger counter = 0;
+ NSUInteger rowWidth = 0;
+ NSUInteger rowMaxHeight = 0;
+
+ for (PNPieChartDataItem *pdata in self.items) {
+ /* Expected label size*/
+ CGSize labelsize = [PNLineChart sizeOfString:pdata.textDescription
+ withWidth:maxLabelWidth
+ font:self.legendFont ? self.legendFont : [UIFont systemFontOfSize:12.0f]];
+
+ if ((rowWidth + labelsize.width + beforeLabel > mWidth)&&(self.legendStyle == PNLegendItemStyleSerial)) {
+ rowWidth = 0;
+ x = 0;
+ y += rowMaxHeight;
+ rowMaxHeight = 0;
+ }
+ rowWidth += labelsize.width + beforeLabel;
+ totalWidth = self.legendStyle == PNLegendItemStyleSerial ? fmaxf(rowWidth, totalWidth) : fmaxf(totalWidth, labelsize.width + beforeLabel);
+ // Add inflexion type
+ [legendViews addObject:[self drawInflexion:legendCircle * .6
+ center:CGPointMake(x + legendCircle / 2, y + singleRowHeight / 2)
+ andColor:pdata.color]];
+
+
+ UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(x + beforeLabel, y, labelsize.width, labelsize.height)];
+ label.text = pdata.textDescription;
+ label.textColor = self.legendFontColor ? self.legendFontColor : [UIColor blackColor];
+ label.font = self.legendFont ? self.legendFont : [UIFont systemFontOfSize:12.0f];
+ label.lineBreakMode = NSLineBreakByWordWrapping;
+ label.numberOfLines = 0;
+
+
+ rowMaxHeight = fmaxf(rowMaxHeight, labelsize.height);
+ x += self.legendStyle == PNLegendItemStyleStacked ? 0 : labelsize.width + beforeLabel;
+ y += self.legendStyle == PNLegendItemStyleStacked ? labelsize.height : 0;
+
+
+ totalHeight = self.legendStyle == PNLegendItemStyleSerial ? fmaxf(totalHeight, rowMaxHeight + y) : totalHeight + labelsize.height;
+ [legendViews addObject:label];
+ counter ++;
+ }
+
+ UIView *legend = [[UIView alloc] initWithFrame:CGRectMake(0, 0, totalWidth, totalHeight)];
+
+ for (UIView* v in legendViews) {
+ [legend addSubview:v];
+ }
+ return legend;
+}
+
+
+- (UIImageView*)drawInflexion:(CGFloat)size center:(CGPoint)center andColor:(UIColor*)color
+{
+ //Make the size a little bigger so it includes also border stroke
+ CGSize aSize = CGSizeMake(size, size);
+
+
+ UIGraphicsBeginImageContextWithOptions(aSize, NO, 0.0);
+ CGContextRef context = UIGraphicsGetCurrentContext();
+
+ CGContextAddArc(context, size/2, size/ 2, size/2, 0, M_PI*2, YES);
+
+
+ //Set some fill color
+ CGContextSetFillColorWithColor(context, color.CGColor);
+
+ //Finally draw
+ CGContextDrawPath(context, kCGPathFill);
+
+ //now get the image from the context
+ UIImage *squareImage = UIGraphicsGetImageFromCurrentImageContext();
+
+ UIGraphicsEndImageContext();
+
+ //// Translate origin
+ CGFloat originX = center.x - (size) / 2.0;
+ CGFloat originY = center.y - (size) / 2.0;
+
+ UIImageView *squareImageView = [[UIImageView alloc]initWithImage:squareImage];
+ [squareImageView setFrame:CGRectMake(originX, originY, size, size)];
+ return squareImageView;
+}
+
+/* Redraw the chart on autolayout */
+-(void)layoutSubviews {
+ [super layoutSubviews];
+ [self strokeChart];
+}
+
+@end
diff --git a/PNChartdemo/PNChartdemo/PNChart/PNPieChartDataItem.h b/PNChartdemo/PNChartdemo/PNChart/PNPieChartDataItem.h
new file mode 100755
index 0000000..08d48e9
--- /dev/null
+++ b/PNChartdemo/PNChartdemo/PNChart/PNPieChartDataItem.h
@@ -0,0 +1,25 @@
+//
+// PNPieChartDataItem.h
+// PNChartDemo
+//
+// Created by Hang Zhang on 14-5-5.
+// Copyright (c) 2014��� kevinzhow. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+#import <UIKit/UIKit.h>
+
+@interface PNPieChartDataItem : NSObject
+
++ (instancetype)dataItemWithValue:(CGFloat)value
+ color:(UIColor*)color;
+
++ (instancetype)dataItemWithValue:(CGFloat)value
+ color:(UIColor*)color
+ description:(NSString *)description;
+
+@property (nonatomic) CGFloat value;
+@property (nonatomic) UIColor *color;
+@property (nonatomic) NSString *textDescription;
+
+@end
diff --git a/PNChartdemo/PNChartdemo/PNChart/PNPieChartDataItem.m b/PNChartdemo/PNChartdemo/PNChart/PNPieChartDataItem.m
new file mode 100755
index 0000000..4bda818
--- /dev/null
+++ b/PNChartdemo/PNChartdemo/PNChart/PNPieChartDataItem.m
@@ -0,0 +1,38 @@
+//
+// PNPieChartDataItem.m
+// PNChartDemo
+//
+// Created by Hang Zhang on 14-5-5.
+// Copyright (c) 2014��� kevinzhow. All rights reserved.
+//
+
+#import "PNPieChartDataItem.h"
+#import <UIKit/UIKit.h>
+
+@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.textDescription = description;
+ return item;
+}
+
+- (void)setValue:(CGFloat)value{
+ NSAssert(value >= 0, @"value should >= 0");
+ if (value != _value){
+ _value = value;
+ }
+}
+
+@end
diff --git a/PNChartdemo/PNChartdemo/PNChart/PNRadarChart.h b/PNChartdemo/PNChartdemo/PNChart/PNRadarChart.h
new file mode 100755
index 0000000..87871d0
--- /dev/null
+++ b/PNChartdemo/PNChartdemo/PNChart/PNRadarChart.h
@@ -0,0 +1,52 @@
+//
+// PNRadarChart.h
+// PNChartDemo
+//
+// Created by Lei on 15/7/1.
+// Copyright (c) 2015��� kevinzhow. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+#import "PNGenericChart.h"
+#import "PNRadarChartDataItem.h"
+
+#define MAXCIRCLE 20
+
+typedef NS_ENUM(NSUInteger, PNRadarChartLabelStyle) {
+ PNRadarChartLabelStyleCircle = 0,
+ PNRadarChartLabelStyleHorizontal,
+ PNRadarChartLabelStyleHidden,
+};
+
+@interface PNRadarChart : PNGenericChart
+
+-(id)initWithFrame:(CGRect)frame items:(NSArray *)items valueDivider:(CGFloat)unitValue;
+/**
+ *Draws the chart in an animated fashion.
+ */
+-(void)strokeChart;
+
+/** Array of `RadarChartDataItem` objects, one for each corner. */
+@property (nonatomic) NSArray *chartData;
+/** The unit of this chart ,default is 1 */
+@property (nonatomic) CGFloat valueDivider;
+/** The maximum for the range of values to display on the chart */
+@property (nonatomic) CGFloat maxValue;
+/** Default is gray. */
+@property (nonatomic) UIColor *webColor;
+/** Default is green , with an alpha of 0.7 */
+@property (nonatomic) UIColor *plotColor;
+/** Default is black */
+@property (nonatomic) UIColor *fontColor;
+/** Default is orange */
+@property (nonatomic) UIColor *graduationColor;
+/** Default is 15 */
+@property (nonatomic) CGFloat fontSize;
+/** Controls the labels display style that around chart */
+@property (nonatomic, assign) PNRadarChartLabelStyle labelStyle;
+/** Tap the label will display detail value ,default is YES. */
+@property (nonatomic, assign) BOOL isLabelTouchable;
+/** is show graduation on the chart ,default is NO. */
+@property (nonatomic, assign) BOOL isShowGraduation;
+
+@end
diff --git a/PNChartdemo/PNChartdemo/PNChart/PNRadarChart.m b/PNChartdemo/PNChartdemo/PNChart/PNRadarChart.m
new file mode 100755
index 0000000..9dace2b
--- /dev/null
+++ b/PNChartdemo/PNChartdemo/PNChart/PNRadarChart.m
@@ -0,0 +1,373 @@
+//
+// PNRadarChart.m
+// PNChartDemo
+//
+// Created by Lei on 15/7/1.
+// Copyright (c) 2015��� kevinzhow. All rights reserved.
+//
+
+#import "PNRadarChart.h"
+
+@interface PNRadarChart()
+
+@property (nonatomic) CGFloat centerX;
+@property (nonatomic) CGFloat centerY;
+@property (nonatomic) NSMutableArray *pointsToWebArrayArray;
+@property (nonatomic) NSMutableArray *pointsToPlotArray;
+@property (nonatomic) UILabel *detailLabel;
+@property (nonatomic) CGFloat lengthUnit;
+@property (nonatomic) CAShapeLayer *chartPlot;
+
+@end
+
+
+@implementation PNRadarChart
+
+- (id)initWithFrame:(CGRect)frame items:(NSArray *)items valueDivider:(CGFloat)unitValue {
+ self=[super initWithFrame:frame];
+ if (self) {
+ self.backgroundColor = [UIColor clearColor];
+ self.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
+
+ //Public iVar
+ if ([items count]< 3)//At least three corners of A polygon ,If the count of items is less than 3 will add 3 default values
+ {
+ NSLog( @"At least three items!");
+ NSArray *defaultArray = @[[PNRadarChartDataItem dataItemWithValue:0 description:@"Default"],
+ [PNRadarChartDataItem dataItemWithValue:0 description:@"Default"],
+ [PNRadarChartDataItem dataItemWithValue:0 description:@"Default"],
+ ];
+ defaultArray = [defaultArray arrayByAddingObjectsFromArray:items];
+ _chartData = [NSArray arrayWithArray:defaultArray];
+ }else{
+ _chartData = [NSArray arrayWithArray:items];
+ }
+ _valueDivider = unitValue;
+ _maxValue = 1;
+ _webColor = [UIColor grayColor];
+ _plotColor = [UIColor colorWithRed:.4 green:.8 blue:.4 alpha:.7];
+ _fontColor = [UIColor blackColor];
+ _graduationColor = [UIColor orangeColor];
+ _fontSize = 15;
+ _labelStyle = PNRadarChartLabelStyleHorizontal;
+ _isLabelTouchable = YES;
+ _isShowGraduation = NO;
+
+ //Private iVar
+ _centerX = frame.size.width/2;
+ _centerY = frame.size.height/2;
+ _pointsToWebArrayArray = [NSMutableArray array];
+ _pointsToPlotArray = [NSMutableArray array];
+ _lengthUnit = 0;
+ _chartPlot = [CAShapeLayer layer];
+ _chartPlot.lineCap = kCALineCapButt;
+ _chartPlot.lineWidth = 1.0;
+ [self.layer addSublayer:_chartPlot];
+
+ [super setupDefaultValues];
+ //init detailLabel
+ _detailLabel = [[UILabel alloc] init];
+ _detailLabel.backgroundColor = [UIColor colorWithRed:.9 green:.9 blue:.1 alpha:.9];
+ _detailLabel.textAlignment = NSTextAlignmentCenter;
+ _detailLabel.textColor = [UIColor colorWithWhite:1 alpha:1];
+ _detailLabel.font = [UIFont systemFontOfSize:15];
+ [_detailLabel setHidden:YES];
+ [self addSubview:_detailLabel];
+
+ [self strokeChart];
+ }
+ return self;
+}
+
+#pragma mark - main
+- (void)calculateChartPoints {
+ [_pointsToPlotArray removeAllObjects];
+ [_pointsToWebArrayArray removeAllObjects];
+
+ //init Descriptions , Values and Angles.
+ NSMutableArray *descriptions = [NSMutableArray array];
+ NSMutableArray *values = [NSMutableArray array];
+ NSMutableArray *angles = [NSMutableArray array];
+ for (int i=0;i<_chartData.count;i++) {
+ PNRadarChartDataItem *item = (PNRadarChartDataItem *)[_chartData objectAtIndex:i];
+ [descriptions addObject:item.textDescription];
+ [values addObject:[NSNumber numberWithFloat:item.value]];
+ CGFloat angleValue = (float)i/(float)[_chartData count]*2*M_PI;
+ [angles addObject:[NSNumber numberWithFloat:angleValue]];
+ }
+
+ //calculate all the lengths
+ _maxValue = [self getMaxValueFromArray:values];
+ CGFloat margin = 0;
+ if (_labelStyle==PNRadarChartLabelStyleCircle) {
+ margin = MIN(_centerX , _centerY)*3/10;
+ }else if (_labelStyle==PNRadarChartLabelStyleHorizontal) {
+ margin = [self getMaxWidthLabelFromArray:descriptions withFontSize:_fontSize];
+ }
+ CGFloat maxLength = ceil(MIN(_centerX, _centerY) - margin);
+ int plotCircles = (_maxValue/_valueDivider);
+ if (plotCircles > MAXCIRCLE) {
+ NSLog(@"Circle number is higher than max");
+ plotCircles = MAXCIRCLE;
+ _valueDivider = _maxValue/plotCircles;
+ }
+ _lengthUnit = maxLength/plotCircles;
+ NSArray *lengthArray = [self getLengthArrayWithCircleNum:(int)plotCircles];
+
+ //get all the points and plot
+ for (NSNumber *lengthNumber in lengthArray) {
+ CGFloat length = [lengthNumber floatValue];
+ [_pointsToWebArrayArray addObject:[self getWebPointWithLength:length angleArray:angles]];
+ }
+ int section = 0;
+ for (id value in values) {
+ CGFloat valueFloat = [value floatValue];
+ if (valueFloat>_maxValue) {
+ NSString *reason = [NSString stringWithFormat:@"Value number is higher than max -value: %f - maxValue: %f",valueFloat,_maxValue];
+ @throw [NSException exceptionWithName:NSInvalidArgumentException reason:reason userInfo:nil];
+ return;
+ }
+
+ CGFloat length = valueFloat/_maxValue*maxLength;
+ CGFloat angle = [[angles objectAtIndex:section] floatValue];
+ CGFloat x = _centerX +length*cos(angle);
+ CGFloat y = _centerY +length*sin(angle);
+ NSValue* point = [NSValue valueWithCGPoint:CGPointMake(x, y)];
+ [_pointsToPlotArray addObject:point];
+ section++;
+ }
+ //set the labels
+ [self drawLabelWithMaxLength:maxLength labelArray:descriptions angleArray:angles];
+
+ }
+#pragma mark - Draw
+
+- (void)drawRect:(CGRect)rect {
+ // Drawing backgound
+ CGContextRef context = UIGraphicsGetCurrentContext();
+ CGContextClearRect(context, rect);
+ int section = 0;
+ //circles
+ for(NSArray *pointArray in _pointsToWebArrayArray){
+ //plot backgound
+ CGContextRef graphContext = UIGraphicsGetCurrentContext();
+ CGContextBeginPath(graphContext);
+ CGPoint beginPoint = [[pointArray objectAtIndex:0] CGPointValue];
+ CGContextMoveToPoint(graphContext, beginPoint.x, beginPoint.y);
+ for(NSValue* pointValue in pointArray){
+ CGPoint point = [pointValue CGPointValue];
+ CGContextAddLineToPoint(graphContext, point.x, point.y);
+ }
+ CGContextAddLineToPoint(graphContext, beginPoint.x, beginPoint.y);
+ CGContextSetStrokeColorWithColor(graphContext, _webColor.CGColor);
+ CGContextStrokePath(graphContext);
+
+ }
+ //cuts
+ NSArray *largestPointArray = [_pointsToWebArrayArray lastObject];
+ for (NSValue *pointValue in largestPointArray){
+ section++;
+ if (section==1&&_isShowGraduation)continue;
+
+ CGContextRef graphContext = UIGraphicsGetCurrentContext();
+ CGContextBeginPath(graphContext);
+ CGContextMoveToPoint(graphContext, _centerX, _centerY);
+ CGPoint point = [pointValue CGPointValue];
+ CGContextAddLineToPoint(graphContext, point.x, point.y);
+ CGContextSetStrokeColorWithColor(graphContext, _webColor.CGColor);
+ CGContextStrokePath(graphContext);
+ }
+
+
+}
+
+- (void)strokeChart {
+
+ [self calculateChartPoints];
+ [self setNeedsDisplay];
+ [_detailLabel setHidden:YES];
+
+ //Draw plot
+ [_chartPlot removeAllAnimations];
+ UIBezierPath *plotline = [UIBezierPath bezierPath];
+ CGPoint beginPoint = [[_pointsToPlotArray objectAtIndex:0] CGPointValue];
+ [plotline moveToPoint:CGPointMake(beginPoint.x, beginPoint.y)];
+ for(NSValue *pointValue in _pointsToPlotArray){
+ CGPoint point = [pointValue CGPointValue];
+ [plotline addLineToPoint:CGPointMake(point.x ,point.y)];
+
+ }
+ [plotline setLineWidth:1];
+ [plotline setLineCapStyle:kCGLineCapButt];
+
+ _chartPlot.path = plotline.CGPath;
+
+ _chartPlot.fillColor = _plotColor.CGColor;
+
+ [self addAnimationIfNeeded];
+ [self showGraduation];
+}
+
+#pragma mark - Helper
+
+- (void)drawLabelWithMaxLength:(CGFloat)maxLength labelArray:(NSArray *)labelArray angleArray:(NSArray *)angleArray {
+ //set labels
+ int labelTag = 121;
+ while (true) {
+ UIView *label = [self viewWithTag:labelTag];
+ if(!label)break;
+ [label removeFromSuperview];
+ }
+ int section = 0;
+ CGFloat labelLength = maxLength + maxLength/10;
+
+ for (NSString *labelString in labelArray) {
+ CGFloat angle = [[angleArray objectAtIndex:section] floatValue];
+ CGFloat x = _centerX + labelLength *cos(angle);
+ CGFloat y = _centerY + labelLength *sin(angle);
+
+ UILabel *label = [[UILabel alloc] init] ;
+ label.backgroundColor = [UIColor clearColor];
+ label.font = [UIFont systemFontOfSize:_fontSize];
+ label.text = labelString;
+ label.tag = labelTag;
+ CGSize detailSize = [labelString sizeWithAttributes:@{NSFontAttributeName:[UIFont systemFontOfSize:_fontSize]}];
+
+ switch (_labelStyle) {
+ case PNRadarChartLabelStyleCircle:
+ label.frame = CGRectMake(x-5*_fontSize/2, y-_fontSize/2, 5*_fontSize, _fontSize);
+ label.transform = CGAffineTransformMakeRotation(((float)section/[labelArray count])*(2*M_PI)+M_PI_2);
+ label.textAlignment = NSTextAlignmentCenter;
+
+ break;
+ case PNRadarChartLabelStyleHorizontal:
+ if (x<_centerX) {
+ label.frame = CGRectMake(x-detailSize.width, y-detailSize.height/2, detailSize.width, detailSize.height);
+ label.textAlignment = NSTextAlignmentRight;
+ }else{
+ label.frame = CGRectMake(x, y-detailSize.height/2, detailSize.width , detailSize.height);
+ label.textAlignment = NSTextAlignmentLeft;
+ }
+ break;
+ case PNRadarChartLabelStyleHidden:
+ [label setHidden:YES];
+ break;
+ default:
+ break;
+ }
+ [label sizeToFit];
+
+ label.userInteractionEnabled = YES;
+ UITapGestureRecognizer *tapLabelGesture = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(tapLabel:)];
+ [label addGestureRecognizer:tapLabelGesture];
+ [self addSubview:label];
+
+ section ++;
+ }
+
+}
+
+- (void)tapLabel:(UITapGestureRecognizer *)recognizer {
+ UILabel *label=(UILabel*)recognizer.view;
+ _detailLabel.frame = CGRectMake(label.frame.origin.x, label.frame.origin.y-30, 50, 25);
+ for (PNRadarChartDataItem *item in _chartData) {
+ if ([label.text isEqualToString:item.textDescription]) {
+ _detailLabel.text = [NSString stringWithFormat:@"%.2f", item.value];
+ break;
+ }
+ }
+ [_detailLabel setHidden:NO];
+
+}
+
+- (void)showGraduation {
+ int labelTag = 112;
+ while (true) {
+ UIView *label = [self viewWithTag:labelTag];
+ if(!label)break;
+ [label removeFromSuperview];
+ }
+ int section = 0;
+ for (NSArray *pointsArray in _pointsToWebArrayArray) {
+ section++;
+ CGPoint labelPoint = [[pointsArray objectAtIndex:0] CGPointValue];
+ UILabel *graduationLabel = [[UILabel alloc] initWithFrame:CGRectMake(labelPoint.x-_lengthUnit, labelPoint.y-_lengthUnit*5/8, _lengthUnit*5/8, _lengthUnit)];
+ graduationLabel.adjustsFontSizeToFitWidth = YES;
+ graduationLabel.tag = labelTag;
+ graduationLabel.font = [UIFont systemFontOfSize:ceil(_lengthUnit)];
+ graduationLabel.textColor = [UIColor orangeColor];
+ graduationLabel.text = [NSString stringWithFormat:@"%.0f",_valueDivider*section];
+ [self addSubview:graduationLabel];
+ if (_isShowGraduation) {
+ [graduationLabel setHidden:NO];
+ }else{
+ [graduationLabel setHidden:YES];}
+ }
+
+}
+
+- (NSArray *)getWebPointWithLength:(CGFloat)length angleArray:(NSArray *)angleArray {
+ NSMutableArray *pointArray = [NSMutableArray array];
+ for (NSNumber *angleNumber in angleArray) {
+ CGFloat angle = [angleNumber floatValue];
+ CGFloat x = _centerX + length*cos(angle);
+ CGFloat y = _centerY + length*sin(angle);
+ [pointArray addObject:[NSValue valueWithCGPoint:CGPointMake(x,y)]];
+ }
+ return pointArray;
+
+}
+
+- (NSArray *)getLengthArrayWithCircleNum:(int)plotCircles {
+ NSMutableArray *lengthArray = [NSMutableArray array];
+ CGFloat length = 0;
+ for (int i = 0; i < plotCircles; i++) {
+ length += _lengthUnit;
+ [lengthArray addObject:[NSNumber numberWithFloat:length]];
+ }
+ return lengthArray;
+}
+
+- (CGFloat)getMaxWidthLabelFromArray:(NSArray *)keyArray withFontSize:(CGFloat)size {
+ CGFloat maxWidth = 0;
+ for (NSString *str in keyArray) {
+ CGSize detailSize = [str sizeWithAttributes:@{NSFontAttributeName:[UIFont systemFontOfSize:_fontSize]}];
+ maxWidth = MAX(maxWidth, detailSize.width);
+ }
+ return maxWidth;
+}
+
+- (CGFloat)getMaxValueFromArray:(NSArray *)valueArray {
+ CGFloat max = _maxValue;
+ for (NSNumber *valueNum in valueArray) {
+ CGFloat valueFloat = [valueNum floatValue];
+ max = MAX(valueFloat, max);
+ }
+ return ceil(max);
+}
+
+- (void)addAnimationIfNeeded
+{
+ if (self.displayAnimated) {
+ CABasicAnimation *animateScale = [CABasicAnimation animationWithKeyPath:@"transform.scale"];
+ animateScale.fromValue = [NSNumber numberWithFloat:0.f];
+ animateScale.toValue = [NSNumber numberWithFloat:1.0f];
+
+ CABasicAnimation *animateMove = [CABasicAnimation animationWithKeyPath:@"position"];
+ animateMove.fromValue = [NSValue valueWithCGPoint:CGPointMake(_centerX, _centerY)];
+ animateMove.toValue = [NSValue valueWithCGPoint:CGPointMake(0, 0)];
+
+ CABasicAnimation *animateAlpha = [CABasicAnimation animationWithKeyPath:@"opacity"];
+ animateAlpha.fromValue = [NSNumber numberWithFloat:0.f];
+
+ CAAnimationGroup *aniGroup = [CAAnimationGroup animation];
+ aniGroup.duration = 1.f;
+ aniGroup.repeatCount = 1;
+ aniGroup.animations = [NSArray arrayWithObjects:animateScale,animateMove,animateAlpha, nil];
+ aniGroup.removedOnCompletion = YES;
+
+ [_chartPlot addAnimation:aniGroup forKey:nil];
+ }
+}
+
+@end
diff --git a/PNChartdemo/PNChartdemo/PNChart/PNRadarChartDataItem.h b/PNChartdemo/PNChartdemo/PNChart/PNRadarChartDataItem.h
new file mode 100755
index 0000000..e67429c
--- /dev/null
+++ b/PNChartdemo/PNChartdemo/PNChart/PNRadarChartDataItem.h
@@ -0,0 +1,19 @@
+//
+// PNRadarChartDataItem.h
+// PNChartDemo
+//
+// Created by Lei on 15/7/1.
+// Copyright (c) 2015��� kevinzhow. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+
+@interface PNRadarChartDataItem : NSObject
+
++ (instancetype)dataItemWithValue:(CGFloat)value
+ description:(NSString *)description;
+
+@property (nonatomic) CGFloat value;
+@property (nonatomic,copy) NSString *textDescription;
+
+@end
diff --git a/PNChartdemo/PNChartdemo/PNChart/PNRadarChartDataItem.m b/PNChartdemo/PNChartdemo/PNChart/PNRadarChartDataItem.m
new file mode 100755
index 0000000..218ef6e
--- /dev/null
+++ b/PNChartdemo/PNChartdemo/PNChart/PNRadarChartDataItem.m
@@ -0,0 +1,29 @@
+//
+// PNRadarChartDataItem.m
+// PNChartDemo
+//
+// Created by Lei on 15/7/1.
+// Copyright (c) 2015��� kevinzhow. All rights reserved.
+//
+
+#import "PNRadarChartDataItem.h"
+
+@implementation PNRadarChartDataItem
+
++ (instancetype)dataItemWithValue:(CGFloat)value
+ description:(NSString *)description {
+ PNRadarChartDataItem *item = [PNRadarChartDataItem new];
+ item.value = value;
+ item.textDescription = description;
+ return item;
+}
+
+- (void)setValue:(CGFloat)value {
+ if (value < 0) {
+ value = 0;
+ NSLog(@"Value value can not be negative");
+ }
+ _value = value;
+}
+
+@end
diff --git a/PNChartdemo/PNChartdemo/PNChart/PNScatterChart.h b/PNChartdemo/PNChartdemo/PNChart/PNScatterChart.h
new file mode 100755
index 0000000..aa4eab8
--- /dev/null
+++ b/PNChartdemo/PNChartdemo/PNChart/PNScatterChart.h
@@ -0,0 +1,69 @@
+//
+// PNScatterChart.h
+// PNChartDemo
+//
+// Created by Alireza Arabi on 12/4/14.
+// Copyright (c) 2014 kevinzhow. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+#import <QuartzCore/QuartzCore.h>
+#import "PNChartDelegate.h"
+#import "PNGenericChart.h"
+#import "PNScatterChartData.h"
+#import "PNScatterChartDataItem.h"
+
+@interface PNScatterChart : PNGenericChart
+
+@property (nonatomic, retain) id<PNChartDelegate> delegate;
+
+/** Array of `ScatterChartData` objects, one for each line. */
+@property (nonatomic) NSArray *chartData;
+
+/** Controls whether to show the coordinate axis. Default is NO. */
+@property (nonatomic, getter = isShowCoordinateAxis) BOOL showCoordinateAxis;
+@property (nonatomic) UIColor *axisColor;
+@property (nonatomic) CGFloat axisWidth;
+
+/** String formatter for float values in x-axis/y-axis labels. If not set, defaults to @"%1.f" */
+@property (nonatomic, strong) NSString *xLabelFormat;
+@property (nonatomic, strong) NSString *yLabelFormat;
+
+/** Default is true. */
+@property (nonatomic) BOOL showLabel;
+
+/** Default is 18-point Avenir Medium. */
+@property (nonatomic) UIFont *descriptionTextFont;
+
+/** Default is white. */
+@property (nonatomic) UIColor *descriptionTextColor;
+
+/** Default is black, with an alpha of 0.4. */
+@property (nonatomic) UIColor *descriptionTextShadowColor;
+
+/** Default is CGSizeMake(0, 1). */
+@property (nonatomic) CGSize descriptionTextShadowOffset;
+
+/** Default is 1.0. */
+@property (nonatomic) NSTimeInterval duration;
+
+@property (nonatomic) CGFloat AxisX_minValue;
+@property (nonatomic) CGFloat AxisX_maxValue;
+
+@property (nonatomic) CGFloat AxisY_minValue;
+@property (nonatomic) CGFloat AxisY_maxValue;
+
+- (void) setAxisXWithMinimumValue:(CGFloat)minVal andMaxValue:(CGFloat)maxVal toTicks:(int)numberOfTicks;
+- (void) setAxisYWithMinimumValue:(CGFloat)minVal andMaxValue:(CGFloat)maxVal toTicks:(int)numberOfTicks;
+- (void) setAxisXLabel:(NSArray *)array;
+- (void) setAxisYLabel:(NSArray *)array;
+- (void) setup;
+- (void) drawLineFromPoint : (CGPoint) startPoint ToPoint : (CGPoint) endPoint WithLineWith : (CGFloat) lineWidth AndWithColor : (UIColor*) color;
+
+/**
+ * Update Chart Value
+ */
+
+- (void)updateChartData:(NSArray *)data;
+
+@end
diff --git a/PNChartdemo/PNChartdemo/PNChart/PNScatterChart.m b/PNChartdemo/PNChartdemo/PNChart/PNScatterChart.m
new file mode 100755
index 0000000..a16cf85
--- /dev/null
+++ b/PNChartdemo/PNChartdemo/PNChart/PNScatterChart.m
@@ -0,0 +1,445 @@
+//
+// PNScatterChart.m
+// PNChartDemo
+//
+// Created by Alireza Arabi on 12/4/14.
+// Copyright (c) 2014 kevinzhow. All rights reserved.
+//
+
+#import "PNScatterChart.h"
+#import "PNColor.h"
+#import "PNChartLabel.h"
+#import "PNScatterChartData.h"
+#import "PNScatterChartDataItem.h"
+
+@interface PNScatterChart ()
+
+@property (nonatomic, weak) CAShapeLayer *pathLayer;
+@property (nonatomic, weak) NSMutableArray *verticalLineLayer;
+@property (nonatomic, weak) NSMutableArray *horizentalLinepathLayer;
+
+@property (nonatomic) CGPoint startPoint;
+
+@property (nonatomic) CGPoint startPointVectorX;
+@property (nonatomic) CGPoint endPointVecotrX;
+
+@property (nonatomic) CGPoint startPointVectorY;
+@property (nonatomic) CGPoint endPointVecotrY;
+
+@property (nonatomic) CGFloat vectorX_Steps;
+@property (nonatomic) CGFloat vectorY_Steps;
+
+@property (nonatomic) CGFloat vectorX_Size;
+@property (nonatomic) CGFloat vectorY_Size;
+
+@property (nonatomic) NSMutableArray *axisX_labels;
+@property (nonatomic) NSMutableArray *axisY_labels;
+
+@property (nonatomic) int AxisX_partNumber ;
+@property (nonatomic) int AxisY_partNumber ;
+
+@property (nonatomic) CGFloat AxisX_step ;
+@property (nonatomic) CGFloat AxisY_step ;
+
+@property (nonatomic) CGFloat AxisX_Margin;
+@property (nonatomic) CGFloat AxisY_Margin;
+
+@property (nonatomic) BOOL isForUpdate;
+
+@end
+
+
+@implementation PNScatterChart
+
+#pragma mark initialization
+
+- (id)initWithCoder:(NSCoder *)coder
+{
+ self = [super initWithCoder:coder];
+
+ if (self) {
+ [self setupDefaultValues];
+ }
+ return self;
+}
+
+- (id)initWithFrame:(CGRect)frame
+{
+ self = [super initWithFrame:frame];
+
+ if (self) {
+ [self setupDefaultValues];
+ }
+ return self;
+}
+
+- (void) setup
+{
+ [self vectorXSetup];
+ [self vectorYSetup];
+}
+
+- (void)setupDefaultValues
+{
+ [super setupDefaultValues];
+
+ // Initialization code
+ self.backgroundColor = [UIColor whiteColor];
+ self.clipsToBounds = YES;
+ _showLabel = YES;
+ _isForUpdate = NO;
+ self.userInteractionEnabled = YES;
+
+ // Coordinate Axis Default Values
+ _showCoordinateAxis = YES;
+ _axisColor = [UIColor colorWithRed:0.4f green:0.4f blue:0.4f alpha:1.f];
+ _axisWidth = 1.f;
+
+ // Initialization code
+ _AxisX_Margin = 30 ;
+ _AxisY_Margin = 30 ;
+
+// self.frame = CGRectMake((SCREEN_WIDTH - self.frame.size.width) / 2, 200, self.frame.size.width, self.frame.size.height) ;
+ self.backgroundColor = [UIColor clearColor];
+
+ _startPoint.y = self.frame.size.height - self.AxisY_Margin ;
+ _startPoint.x = self.AxisX_Margin ;
+
+ _axisX_labels = [NSMutableArray array];
+ _axisY_labels = [NSMutableArray array];
+
+ _descriptionTextColor = [UIColor blackColor];
+ _descriptionTextFont = [UIFont fontWithName:@"Avenir-Medium" size:9.0];
+ _descriptionTextShadowColor = [[UIColor blackColor] colorWithAlphaComponent:0.4];
+ _descriptionTextShadowOffset = CGSizeMake(0, 1);
+ _duration = 1.0;
+
+}
+
+#pragma mark calculating axis
+
+- (void) setAxisXWithMinimumValue:(CGFloat)minVal andMaxValue:(CGFloat)maxVal toTicks:(int)numberOfTicks
+{
+ _AxisX_minValue = minVal ;
+ _AxisX_maxValue = maxVal ;
+ _AxisX_partNumber = numberOfTicks - 1;
+ _AxisX_step = (float)((maxVal - minVal)/_AxisX_partNumber);
+
+ NSString *LabelFormat = self.xLabelFormat ? : @"%1.f";
+ CGFloat tempValue = minVal ;
+ UILabel *label = [[UILabel alloc] init];
+ label.text = [NSString stringWithFormat:LabelFormat,minVal] ;
+ [_axisX_labels addObject:label];
+ for (int i = 0 ; i < _AxisX_partNumber; i++) {
+ tempValue = tempValue + _AxisX_step;
+ UILabel *tempLabel = [[UILabel alloc] init];
+ tempLabel.text = [NSString stringWithFormat:LabelFormat,tempValue] ;
+ [_axisX_labels addObject:tempLabel];
+ }
+}
+
+- (void) setAxisYWithMinimumValue:(CGFloat)minVal andMaxValue:(CGFloat)maxVal toTicks:(int)numberOfTicks
+{
+ _AxisY_minValue = minVal ;
+ _AxisY_maxValue = maxVal ;
+ _AxisY_partNumber = numberOfTicks - 1;
+ _AxisY_step = (float)((maxVal - minVal)/_AxisY_partNumber);
+
+ NSString *LabelFormat = self.yLabelFormat ? : @"%1.f";
+ CGFloat tempValue = minVal ;
+ UILabel *label = [[UILabel alloc] init];
+ label.text = [NSString stringWithFormat:LabelFormat,minVal] ;
+ [_axisY_labels addObject:label];
+ for (int i = 0 ; i < _AxisY_partNumber; i++) {
+ tempValue = tempValue + _AxisY_step;
+ UILabel *tempLabel = [[UILabel alloc] init];
+ tempLabel.text = [NSString stringWithFormat:LabelFormat,tempValue] ;
+ [_axisY_labels addObject:tempLabel];
+ }
+}
+
+- (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];
+ for(int i=0;i<array.count;i++){
+ UILabel *label = [[UILabel alloc] init];
+ label.text = [array objectAtIndex:i];
+ [_axisX_labels addObject:label];
+ }
+ }
+}
+
+- (void)setAxisYLabel:(NSArray *)array {
+ if(array.count == ++_AxisY_partNumber){
+ [_axisY_labels removeAllObjects];
+ for(int i=0;i<array.count;i++){
+ UILabel *label = [[UILabel alloc] init];
+ label.text = [array objectAtIndex:i];
+ [_axisY_labels addObject:label];
+ }
+ }
+}
+
+- (void) vectorXSetup
+{
+ _AxisX_partNumber += 1;
+ _vectorX_Size = self.frame.size.width - (_AxisX_Margin) - 15 ;
+ _vectorX_Steps = (_vectorX_Size) / (_AxisX_partNumber) ;
+ _endPointVecotrX = CGPointMake(_startPoint.x + _vectorX_Size, _startPoint.y) ;
+ _startPointVectorX = _startPoint ;
+}
+
+- (void) vectorYSetup
+{
+ _AxisY_partNumber += 1;
+ _vectorY_Size = self.frame.size.height - (_AxisY_Margin) - 15;
+ _vectorY_Steps = (_vectorY_Size) / (_AxisY_partNumber);
+ _endPointVecotrY = CGPointMake(_startPoint.x, _startPoint.y - _vectorY_Size) ;
+ _startPointVectorY = _startPoint ;
+}
+
+- (void) showXLabel : (UILabel *) descriptionLabel InPosition : (CGPoint) point
+{
+ CGRect frame = CGRectMake(point.x, point.y, 30, 10);
+ descriptionLabel.frame = frame;
+ descriptionLabel.font = _descriptionTextFont;
+ descriptionLabel.textColor = _descriptionTextColor;
+ descriptionLabel.shadowColor = _descriptionTextShadowColor;
+ descriptionLabel.shadowOffset = _descriptionTextShadowOffset;
+ descriptionLabel.textAlignment = NSTextAlignmentCenter;
+ descriptionLabel.backgroundColor = [UIColor clearColor];
+ [self addSubview:descriptionLabel];
+}
+
+- (void)setChartData:(NSArray *)data
+{
+ __block CGFloat yFinilizeValue , xFinilizeValue;
+ __block CGFloat yValue , xValue;
+
+ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
+ if (self.displayAnimated) {
+ [NSThread sleepForTimeInterval:1];
+ }
+ // update UI on the main thread
+ dispatch_async(dispatch_get_main_queue(), ^{
+ for (PNScatterChartData *chartData in data) {
+ for (NSUInteger i = 0; i < chartData.itemCount; i++) {
+ yValue = chartData.getData(i).y;
+ xValue = chartData.getData(i).x;
+ if (!(xValue >= _AxisX_minValue && xValue <= _AxisX_maxValue) || !(yValue >= _AxisY_minValue && yValue <= _AxisY_maxValue)) {
+ NSLog(@"input is not in correct range.");
+ exit(0);
+ }
+ xFinilizeValue = [self mappingIsForAxisX:true WithValue:xValue];
+ yFinilizeValue = [self mappingIsForAxisX:false WithValue:yValue];
+ CAShapeLayer *shape = [self drawingPointsForChartData:chartData AndWithX:xFinilizeValue AndWithY:yFinilizeValue];
+ self.pathLayer = shape ;
+ [self.layer addSublayer:self.pathLayer];
+
+ [self addAnimationIfNeeded];
+ }
+ }
+ });
+ });
+}
+
+- (void)addAnimationIfNeeded{
+
+ if (self.displayAnimated) {
+ CABasicAnimation *pathAnimation = [CABasicAnimation animationWithKeyPath:@"opacity"];
+ pathAnimation.duration = _duration;
+ pathAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
+ pathAnimation.fromValue = @(0.0f);
+ pathAnimation.toValue = @(1.0f);
+ pathAnimation.fillMode = kCAFillModeForwards;
+ self.layer.opacity = 1;
+ [self.pathLayer addAnimation:pathAnimation forKey:@"fade"];
+ }
+}
+
+- (CGFloat) mappingIsForAxisX : (BOOL) isForAxisX WithValue : (CGFloat) value{
+
+ if (isForAxisX) {
+ float temp = _startPointVectorX.x + (_vectorX_Steps / 2) ;
+ CGFloat xPos = temp + (((value - _AxisX_minValue)/_AxisX_step) * _vectorX_Steps) ;
+ return xPos;
+ }
+ else {
+ float temp = _startPointVectorY.y - (_vectorY_Steps / 2) ;
+ CGFloat yPos = temp - (((value - _AxisY_minValue) /_AxisY_step) * _vectorY_Steps);
+ return yPos;
+ }
+ return 0;
+}
+
+#pragma mark - Update Chart Data
+
+- (void)updateChartData:(NSArray *)data
+{
+ _chartData = data;
+
+ // will be work in future.
+}
+
+#pragma drawing methods
+
+- (void)drawRect:(CGRect)rect
+{
+ [super drawRect:rect];
+
+ CGContextRef context = UIGraphicsGetCurrentContext();
+ if (_showCoordinateAxis) {
+ CGContextSetStrokeColorWithColor(context, [_axisColor CGColor]);
+ CGContextSetLineWidth(context, _axisWidth);
+ //drawing x vector
+ CGContextMoveToPoint(context, _startPoint.x, _startPoint.y);
+ CGContextAddLineToPoint(context, _endPointVecotrX.x, _endPointVecotrX.y);
+ //drawing y vector
+ CGContextMoveToPoint(context, _startPoint.x, _startPoint.y);
+ CGContextAddLineToPoint(context, _endPointVecotrY.x, _endPointVecotrY.y);
+ //drawing x arrow vector
+ CGContextMoveToPoint(context, _endPointVecotrX.x, _endPointVecotrX.y);
+ CGContextAddLineToPoint(context, _endPointVecotrX.x - 5, _endPointVecotrX.y + 3);
+ CGContextMoveToPoint(context, _endPointVecotrX.x, _endPointVecotrX.y);
+ CGContextAddLineToPoint(context, _endPointVecotrX.x - 5, _endPointVecotrX.y - 3);
+ //drawing y arrow vector
+ CGContextMoveToPoint(context, _endPointVecotrY.x, _endPointVecotrY.y);
+ CGContextAddLineToPoint(context, _endPointVecotrY.x - 3, _endPointVecotrY.y + 5);
+ CGContextMoveToPoint(context, _endPointVecotrY.x, _endPointVecotrY.y);
+ CGContextAddLineToPoint(context, _endPointVecotrY.x + 3, _endPointVecotrY.y + 5);
+ }
+
+ if (_showLabel) {
+ //drawing x steps vector and putting axis x labels
+ float temp = _startPointVectorX.x + (_vectorX_Steps / 2) ;
+ for (int i = 0; i < _axisX_labels.count; i++) {
+ UIBezierPath *path = [UIBezierPath bezierPath];
+ [path moveToPoint:CGPointMake(temp, _startPointVectorX.y - 2)];
+ [path addLineToPoint:CGPointMake(temp, _startPointVectorX.y + 3)];
+ CAShapeLayer *shapeLayer = [CAShapeLayer layer];
+ shapeLayer.path = [path CGPath];
+ shapeLayer.strokeColor = [_axisColor CGColor];
+ shapeLayer.lineWidth = _axisWidth;
+ shapeLayer.fillColor = [_axisColor CGColor];
+ [self.horizentalLinepathLayer addObject:shapeLayer];
+ [self.layer addSublayer:shapeLayer];
+ UILabel *lb = [_axisX_labels objectAtIndex:i] ;
+ [self showXLabel:lb InPosition:CGPointMake(temp - 15, _startPointVectorX.y + 10 )];
+ temp = temp + _vectorX_Steps ;
+ }
+ //drawing y steps vector and putting axis x labels
+ temp = _startPointVectorY.y - (_vectorY_Steps / 2) ;
+ for (int i = 0; i < _axisY_labels.count; i++) {
+ UIBezierPath *path = [UIBezierPath bezierPath];
+ [path moveToPoint:CGPointMake(_startPointVectorY.x - 3, temp)];
+ [path addLineToPoint:CGPointMake( _startPointVectorY.x + 2, temp)];
+ CAShapeLayer *shapeLayer = [CAShapeLayer layer];
+ shapeLayer.path = [path CGPath];
+ shapeLayer.strokeColor = [_axisColor CGColor];
+ shapeLayer.lineWidth = _axisWidth;
+ shapeLayer.fillColor = [_axisColor CGColor];
+ [self.verticalLineLayer addObject:shapeLayer];
+ [self.layer addSublayer:shapeLayer];
+ UILabel *lb = [_axisY_labels objectAtIndex:i];
+ [self showXLabel:lb InPosition:CGPointMake(_startPointVectorY.x - 30, temp - 5)];
+ temp = temp - _vectorY_Steps ;
+ }
+ }
+ CGContextDrawPath(context, kCGPathStroke);
+}
+
+- (CAShapeLayer*) drawingPointsForChartData : (PNScatterChartData *) chartData AndWithX : (CGFloat) X AndWithY : (CGFloat) Y
+{
+ if (chartData.inflexionPointStyle == PNScatterChartPointStyleCircle) {
+ float radius = chartData.size;
+ CAShapeLayer *circle = [CAShapeLayer layer];
+ // Make a circular shape
+ circle.path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(X - radius, Y - radius, 2.0*radius, 2.0*radius)
+ cornerRadius:radius].CGPath;
+ // Configure the appearence of the circle
+ circle.fillColor = [chartData.fillColor CGColor];
+ circle.strokeColor = [chartData.strokeColor CGColor];
+ circle.lineWidth = 1;
+
+ // Add to parent layer
+ return circle;
+ }
+ else if (chartData.inflexionPointStyle == PNScatterChartPointStyleSquare) {
+ float side = chartData.size;
+ CAShapeLayer *square = [CAShapeLayer layer];
+ // Make a circular shape
+ square.path = [UIBezierPath bezierPathWithRect:CGRectMake(X - (side/2) , Y - (side/2), side, side)].CGPath ;
+ // Configure the apperence of the circle
+ square.fillColor = [chartData.fillColor CGColor];
+ square.strokeColor = [chartData.strokeColor CGColor];
+ square.lineWidth = 1;
+
+ // Add to parent layer
+ return square;
+ }
+ else {
+ // you cann add your own scatter chart point here
+ }
+ return nil ;
+}
+
+- (void) drawLineFromPoint : (CGPoint) startPoint ToPoint : (CGPoint) endPoint WithLineWith : (CGFloat) lineWidth AndWithColor : (UIColor*) color{
+
+ // call the same method on a background thread
+ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
+ if (self.displayAnimated) {
+ [NSThread sleepForTimeInterval:2];
+ }
+ // calculating start and end point
+ __block CGFloat startX = [self mappingIsForAxisX:true WithValue:startPoint.x];
+ __block CGFloat startY = [self mappingIsForAxisX:false WithValue:startPoint.y];
+ __block CGFloat endX = [self mappingIsForAxisX:true WithValue:endPoint.x];
+ __block CGFloat endY = [self mappingIsForAxisX:false WithValue:endPoint.y];
+ // update UI on the main thread
+ dispatch_async(dispatch_get_main_queue(), ^{
+ // drawing path between two points
+ UIBezierPath *path = [UIBezierPath bezierPath];
+ [path moveToPoint:CGPointMake(startX, startY)];
+ [path addLineToPoint:CGPointMake(endX, endY)];
+ CAShapeLayer *shapeLayer = [CAShapeLayer layer];
+ shapeLayer.path = [path CGPath];
+ shapeLayer.strokeColor = [color CGColor];
+ shapeLayer.lineWidth = lineWidth;
+ shapeLayer.fillColor = [color CGColor];
+ // adding animation to path
+ [self addStrokeEndAnimationIfNeededToLayer:shapeLayer];
+ [self.layer addSublayer:shapeLayer];
+ });
+ });
+}
+
+- (void)addStrokeEndAnimationIfNeededToLayer:(CAShapeLayer *)shapeLayer{
+
+ if (self.displayAnimated) {
+ CABasicAnimation *animateStrokeEnd = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
+ animateStrokeEnd.duration = _duration;
+ animateStrokeEnd.fromValue = [NSNumber numberWithFloat:0.0f];
+ animateStrokeEnd.toValue = [NSNumber numberWithFloat:1.0f];
+ [shapeLayer addAnimation:animateStrokeEnd forKey:nil];
+ }
+}
+
+@end
diff --git a/PNChartdemo/PNChartdemo/PNChart/PNScatterChartData.h b/PNChartdemo/PNChartdemo/PNChart/PNScatterChartData.h
new file mode 100755
index 0000000..40b7b0e
--- /dev/null
+++ b/PNChartdemo/PNChartdemo/PNChart/PNScatterChartData.h
@@ -0,0 +1,38 @@
+//
+// PNScatterChartData.h
+// PNChartDemo
+//
+// Created by Alireza Arabi on 12/4/14.
+// Copyright (c) 2014 kevinzhow. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+#import <UIKit/UIKit.h>
+
+typedef NS_ENUM(NSUInteger, PNScatterChartPointStyle) {
+ PNScatterChartPointStyleCircle = 0,
+ PNScatterChartPointStyleSquare = 1,
+};
+
+@class PNScatterChartDataItem;
+
+typedef PNScatterChartDataItem *(^LCScatterChartDataGetter)(NSUInteger item);
+
+@interface PNScatterChartData : NSObject
+
+@property (strong) UIColor *fillColor;
+@property (strong) UIColor *strokeColor;
+
+@property NSUInteger itemCount;
+@property (copy) LCScatterChartDataGetter getData;
+
+@property (nonatomic, assign) PNScatterChartPointStyle inflexionPointStyle;
+
+/**
+ * If PNLineChartPointStyle is circle, this returns the circle's diameter.
+ * If PNLineChartPointStyle is square, each point is a square with each side equal in length to this value.
+ */
+@property (nonatomic, assign) CGFloat size;
+
+
+@end
diff --git a/PNChartdemo/PNChartdemo/PNChart/PNScatterChartData.m b/PNChartdemo/PNChartdemo/PNChart/PNScatterChartData.m
new file mode 100755
index 0000000..a53a5c2
--- /dev/null
+++ b/PNChartdemo/PNChartdemo/PNChart/PNScatterChartData.m
@@ -0,0 +1,31 @@
+//
+// PNScatterChartData.m
+// PNChartDemo
+//
+// Created by Alireza Arabi on 12/4/14.
+// Copyright (c) 2014 kevinzhow. All rights reserved.
+//
+
+#import "PNScatterChartData.h"
+
+@implementation PNScatterChartData
+
+- (id)init
+{
+ self = [super init];
+ if (self) {
+ [self setupDefaultValues];
+ }
+
+ return self;
+}
+
+- (void)setupDefaultValues
+{
+ _inflexionPointStyle = PNScatterChartPointStyleCircle;
+ _fillColor = [UIColor grayColor];
+ _strokeColor = [UIColor clearColor];
+ _size = 3 ;
+}
+
+@end
diff --git a/PNChartdemo/PNChartdemo/PNChart/PNScatterChartDataItem.h b/PNChartdemo/PNChartdemo/PNChart/PNScatterChartDataItem.h
new file mode 100755
index 0000000..f38ee4e
--- /dev/null
+++ b/PNChartdemo/PNChartdemo/PNChart/PNScatterChartDataItem.h
@@ -0,0 +1,19 @@
+//
+// PNScatterChartDataItem.h
+// PNChartDemo
+//
+// Created by Alireza Arabi on 12/4/14.
+// Copyright (c) 2014 kevinzhow. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+#import <UIKit/UIKit.h>
+
+@interface PNScatterChartDataItem : NSObject
+
++ (PNScatterChartDataItem *)dataItemWithX:(CGFloat)x AndWithY:(CGFloat)y;
+
+@property (readonly) CGFloat x; // should be within the x range
+@property (readonly) CGFloat y; // should be within the y range
+
+@end
diff --git a/PNChartdemo/PNChartdemo/PNChart/PNScatterChartDataItem.m b/PNChartdemo/PNChartdemo/PNChart/PNScatterChartDataItem.m
new file mode 100755
index 0000000..a454459
--- /dev/null
+++ b/PNChartdemo/PNChartdemo/PNChart/PNScatterChartDataItem.m
@@ -0,0 +1,37 @@
+//
+// PNScatterChartDataItem.m
+// PNChartDemo
+//
+// Created by Alireza Arabi on 12/4/14.
+// Copyright (c) 2014 kevinzhow. All rights reserved.
+//
+
+#import "PNScatterChartDataItem.h"
+
+@interface PNScatterChartDataItem ()
+
+- (id)initWithX:(CGFloat)x AndWithY:(CGFloat)y;
+
+@property (readwrite) CGFloat x; // should be within the x range
+@property (readwrite) CGFloat y; // should be within the y range
+
+@end
+
+@implementation PNScatterChartDataItem
+
++ (PNScatterChartDataItem *)dataItemWithX:(CGFloat)x AndWithY:(CGFloat)y
+{
+ return [[PNScatterChartDataItem alloc] initWithX:x AndWithY:y];
+}
+
+- (id)initWithX:(CGFloat)x AndWithY:(CGFloat)y
+{
+ if ((self = [super init])) {
+ self.x = x;
+ self.y = y;
+ }
+
+ return self;
+}
+
+@end
diff --git a/PNChartdemo/PNChartdemo/PNChartDemo-Prefix.pch b/PNChartdemo/PNChartdemo/PNChartDemo-Prefix.pch
new file mode 100755
index 0000000..a0c6545
--- /dev/null
+++ b/PNChartdemo/PNChartdemo/PNChartDemo-Prefix.pch
@@ -0,0 +1,16 @@
+//
+// Prefix header
+//
+// The contents of this file are implicitly included at the beginning of every source file.
+//
+
+#import <Availability.h>
+
+#ifndef __IPHONE_5_0
+#warning "This project uses features only available in iOS SDK 5.0 and later."
+#endif
+
+#ifdef __OBJC__
+ #import <UIKit/UIKit.h>
+ #import <Foundation/Foundation.h>
+#endif
diff --git a/PNChartdemo/PNChartdemo/UICountingLabel/UICountingLabel.h b/PNChartdemo/PNChartdemo/UICountingLabel/UICountingLabel.h
new file mode 100755
index 0000000..3c59ee3
--- /dev/null
+++ b/PNChartdemo/PNChartdemo/UICountingLabel/UICountingLabel.h
@@ -0,0 +1,36 @@
+#import <Foundation/Foundation.h>
+#import <UIKit/UIKit.h>
+
+typedef NS_ENUM(NSInteger, UILabelCountingMethod) {
+ UILabelCountingMethodEaseInOut,
+ UILabelCountingMethodEaseIn,
+ UILabelCountingMethodEaseOut,
+ UILabelCountingMethodLinear
+};
+
+typedef NSString* (^UICountingLabelFormatBlock)(CGFloat value);
+typedef NSAttributedString* (^UICountingLabelAttributedFormatBlock)(CGFloat value);
+
+@interface UICountingLabel : UILabel
+
+@property (nonatomic, strong) NSString *format;
+@property (nonatomic, assign) UILabelCountingMethod method;
+@property (nonatomic, assign) NSTimeInterval animationDuration;
+
+@property (nonatomic, copy) UICountingLabelFormatBlock formatBlock;
+@property (nonatomic, copy) UICountingLabelAttributedFormatBlock attributedFormatBlock;
+@property (nonatomic, copy) void (^completionBlock)();
+
+-(void)countFrom:(CGFloat)startValue to:(CGFloat)endValue;
+-(void)countFrom:(CGFloat)startValue to:(CGFloat)endValue withDuration:(NSTimeInterval)duration;
+
+-(void)countFromCurrentValueTo:(CGFloat)endValue;
+-(void)countFromCurrentValueTo:(CGFloat)endValue withDuration:(NSTimeInterval)duration;
+
+-(void)countFromZeroTo:(CGFloat)endValue;
+-(void)countFromZeroTo:(CGFloat)endValue withDuration:(NSTimeInterval)duration;
+
+- (CGFloat)currentValue;
+
+@end
+
diff --git a/PNChartdemo/PNChartdemo/UICountingLabel/UICountingLabel.m b/PNChartdemo/PNChartdemo/UICountingLabel/UICountingLabel.m
new file mode 100755
index 0000000..3a75a50
--- /dev/null
+++ b/PNChartdemo/PNChartdemo/UICountingLabel/UICountingLabel.m
@@ -0,0 +1,234 @@
+#import <QuartzCore/QuartzCore.h>
+
+#import "UICountingLabel.h"
+
+#if !__has_feature(objc_arc)
+#error UICountingLabel is ARC only. Either turn on ARC for the project or use -fobjc-arc flag
+#endif
+
+#pragma mark - UILabelCounter
+
+#ifndef kUILabelCounterRate
+#define kUILabelCounterRate 3.0
+#endif
+
+@protocol UILabelCounter<NSObject>
+
+-(CGFloat)update:(CGFloat)t;
+
+@end
+
+@interface UILabelCounterLinear : NSObject<UILabelCounter>
+
+@end
+
+@interface UILabelCounterEaseIn : NSObject<UILabelCounter>
+
+@end
+
+@interface UILabelCounterEaseOut : NSObject<UILabelCounter>
+
+@end
+
+@interface UILabelCounterEaseInOut : NSObject<UILabelCounter>
+
+@end
+
+@implementation UILabelCounterLinear
+
+-(CGFloat)update:(CGFloat)t
+{
+ return t;
+}
+
+@end
+
+@implementation UILabelCounterEaseIn
+
+-(CGFloat)update:(CGFloat)t
+{
+ return powf(t, kUILabelCounterRate);
+}
+
+@end
+
+@implementation UILabelCounterEaseOut
+
+-(CGFloat)update:(CGFloat)t{
+ return 1.0-powf((1.0-t), kUILabelCounterRate);
+}
+
+@end
+
+@implementation UILabelCounterEaseInOut
+
+-(CGFloat) update: (CGFloat) t
+{
+ t *= 2;
+ if (t < 1)
+ return 0.5f * powf (t, kUILabelCounterRate);
+ else
+ return 0.5f * (2.0f - powf(2.0 - t, kUILabelCounterRate));
+}
+
+@end
+
+#pragma mark - UICountingLabel
+
+@interface UICountingLabel ()
+
+@property CGFloat startingValue;
+@property CGFloat destinationValue;
+@property NSTimeInterval progress;
+@property NSTimeInterval lastUpdate;
+@property NSTimeInterval totalTime;
+@property CGFloat easingRate;
+
+@property (nonatomic, strong) CADisplayLink *timer;
+@property (nonatomic, strong) id<UILabelCounter> counter;
+
+@end
+
+@implementation UICountingLabel
+
+-(void)countFrom:(CGFloat)value to:(CGFloat)endValue {
+
+ if (self.animationDuration == 0.0f) {
+ self.animationDuration = 2.0f;
+ }
+
+ [self countFrom:value to:endValue withDuration:self.animationDuration];
+}
+
+-(void)countFrom:(CGFloat)startValue to:(CGFloat)endValue withDuration:(NSTimeInterval)duration {
+
+ self.startingValue = startValue;
+ self.destinationValue = endValue;
+
+ // remove any (possible) old timers
+ [self.timer invalidate];
+ self.timer = nil;
+
+ if (duration == 0.0) {
+ // No animation
+ [self setTextValue:endValue];
+ [self runCompletionBlock];
+ return;
+ }
+
+ self.easingRate = 3.0f;
+ self.progress = 0;
+ self.totalTime = duration;
+ self.lastUpdate = [NSDate timeIntervalSinceReferenceDate];
+
+ if(self.format == nil)
+ self.format = @"%f";
+
+ switch(self.method)
+ {
+ case UILabelCountingMethodLinear:
+ self.counter = [[UILabelCounterLinear alloc] init];
+ break;
+ case UILabelCountingMethodEaseIn:
+ self.counter = [[UILabelCounterEaseIn alloc] init];
+ break;
+ case UILabelCountingMethodEaseOut:
+ self.counter = [[UILabelCounterEaseOut alloc] init];
+ break;
+ case UILabelCountingMethodEaseInOut:
+ self.counter = [[UILabelCounterEaseInOut alloc] init];
+ break;
+ }
+
+ CADisplayLink *timer = [CADisplayLink displayLinkWithTarget:self selector:@selector(updateValue:)];
+ timer.frameInterval = 2;
+ [timer addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
+ [timer addToRunLoop:[NSRunLoop mainRunLoop] forMode:UITrackingRunLoopMode];
+ self.timer = timer;
+}
+
+- (void)countFromCurrentValueTo:(CGFloat)endValue {
+ [self countFrom:[self currentValue] to:endValue];
+}
+
+- (void)countFromCurrentValueTo:(CGFloat)endValue withDuration:(NSTimeInterval)duration {
+ [self countFrom:[self currentValue] to:endValue withDuration:duration];
+}
+
+- (void)countFromZeroTo:(CGFloat)endValue {
+ [self countFrom:0.0f to:endValue];
+}
+
+- (void)countFromZeroTo:(CGFloat)endValue withDuration:(NSTimeInterval)duration {
+ [self countFrom:0.0f to:endValue withDuration:duration];
+}
+
+- (void)updateValue:(NSTimer *)timer {
+
+ // update progress
+ NSTimeInterval now = [NSDate timeIntervalSinceReferenceDate];
+ self.progress += now - self.lastUpdate;
+ self.lastUpdate = now;
+
+ if (self.progress >= self.totalTime) {
+ [self.timer invalidate];
+ self.timer = nil;
+ self.progress = self.totalTime;
+ }
+
+ [self setTextValue:[self currentValue]];
+
+ if (self.progress == self.totalTime) {
+ [self runCompletionBlock];
+ }
+}
+
+- (void)setTextValue:(CGFloat)value
+{
+ if (self.attributedFormatBlock != nil) {
+ self.attributedText = self.attributedFormatBlock(value);
+ }
+ else if(self.formatBlock != nil)
+ {
+ self.text = self.formatBlock(value);
+ }
+ else
+ {
+ // check if counting with ints - cast to int
+ if([self.format rangeOfString:@"%(.*)d" options:NSRegularExpressionSearch].location != NSNotFound || [self.format rangeOfString:@"%(.*)i"].location != NSNotFound )
+ {
+ self.text = [NSString stringWithFormat:self.format,(int)value];
+ }
+ else
+ {
+ self.text = [NSString stringWithFormat:self.format,value];
+ }
+ }
+}
+
+- (void)setFormat:(NSString *)format {
+ _format = format;
+ // update label with new format
+ [self setTextValue:self.currentValue];
+}
+
+- (void)runCompletionBlock {
+
+ if (self.completionBlock) {
+ self.completionBlock();
+ self.completionBlock = nil;
+ }
+}
+
+- (CGFloat)currentValue {
+
+ if (self.progress >= self.totalTime) {
+ return self.destinationValue;
+ }
+
+ CGFloat percent = self.progress / self.totalTime;
+ CGFloat updateVal = [self.counter update:percent];
+ return self.startingValue + (updateVal * (self.destinationValue - self.startingValue));
+}
+
+@end
diff --git a/camerademo/camerademo/ViewController.h b/PNChartdemo/PNChartdemo/ViewController.h
similarity index 75%
rename from camerademo/camerademo/ViewController.h
rename to PNChartdemo/PNChartdemo/ViewController.h
index ca96e2d..fbaa548 100644
--- a/camerademo/camerademo/ViewController.h
+++ b/PNChartdemo/PNChartdemo/ViewController.h
@@ -1,8 +1,8 @@
//
// ViewController.h
-// camerademo
+// PNChartdemo
//
-// Created by WindShan on 2017/2/21.
+// Created by WindShan on 2017/3/3.
// Copyright �� 2017��� WindShan. All rights reserved.
//
diff --git a/camerademo/camerademo/ViewController.m b/PNChartdemo/PNChartdemo/ViewController.m
similarity index 89%
rename from camerademo/camerademo/ViewController.m
rename to PNChartdemo/PNChartdemo/ViewController.m
index d49c4e7..93fbcb3 100644
--- a/camerademo/camerademo/ViewController.m
+++ b/PNChartdemo/PNChartdemo/ViewController.m
@@ -1,8 +1,8 @@
//
// ViewController.m
-// camerademo
+// PNChartdemo
//
-// Created by WindShan on 2017/2/21.
+// Created by WindShan on 2017/3/3.
// Copyright �� 2017��� WindShan. All rights reserved.
//
diff --git a/camerademo/camerademo/main.m b/PNChartdemo/PNChartdemo/main.m
similarity index 83%
rename from camerademo/camerademo/main.m
rename to PNChartdemo/PNChartdemo/main.m
index 27a8a02..c92139f 100644
--- a/camerademo/camerademo/main.m
+++ b/PNChartdemo/PNChartdemo/main.m
@@ -1,8 +1,8 @@
//
// main.m
-// camerademo
+// PNChartdemo
//
-// Created by WindShan on 2017/2/21.
+// Created by WindShan on 2017/3/3.
// Copyright �� 2017��� WindShan. All rights reserved.
//
diff --git a/camerademo/camerademo.xcodeproj/project.pbxproj b/camerademo/camerademo.xcodeproj/project.pbxproj
deleted file mode 100644
index a75fd57..0000000
--- a/camerademo/camerademo.xcodeproj/project.pbxproj
+++ /dev/null
@@ -1,317 +0,0 @@
-// !$*UTF8*$!
-{
- archiveVersion = 1;
- classes = {
- };
- objectVersion = 46;
- objects = {
-
-/* Begin PBXBuildFile section */
- E52F59F01E5C21890084B3E2 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = E52F59EF1E5C21890084B3E2 /* main.m */; };
- E52F59F31E5C21890084B3E2 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = E52F59F21E5C21890084B3E2 /* AppDelegate.m */; };
- E52F59F61E5C21890084B3E2 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = E52F59F51E5C21890084B3E2 /* ViewController.m */; };
- E52F59F91E5C21890084B3E2 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = E52F59F71E5C21890084B3E2 /* Main.storyboard */; };
- E52F59FB1E5C21890084B3E2 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = E52F59FA1E5C21890084B3E2 /* Assets.xcassets */; };
- E52F59FE1E5C21890084B3E2 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = E52F59FC1E5C21890084B3E2 /* LaunchScreen.storyboard */; };
-/* End PBXBuildFile section */
-
-/* Begin PBXFileReference section */
- E52F59EB1E5C21890084B3E2 /* camerademo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = camerademo.app; sourceTree = BUILT_PRODUCTS_DIR; };
- E52F59EF1E5C21890084B3E2 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
- E52F59F11E5C21890084B3E2 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
- E52F59F21E5C21890084B3E2 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
- E52F59F41E5C21890084B3E2 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = "<group>"; };
- E52F59F51E5C21890084B3E2 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = "<group>"; };
- E52F59F81E5C21890084B3E2 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
- E52F59FA1E5C21890084B3E2 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
- E52F59FD1E5C21890084B3E2 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
- E52F59FF1E5C21890084B3E2 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
-/* End PBXFileReference section */
-
-/* Begin PBXFrameworksBuildPhase section */
- E52F59E81E5C21890084B3E2 /* Frameworks */ = {
- isa = PBXFrameworksBuildPhase;
- buildActionMask = 2147483647;
- files = (
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
-/* End PBXFrameworksBuildPhase section */
-
-/* Begin PBXGroup section */
- E52F59E21E5C21890084B3E2 = {
- isa = PBXGroup;
- children = (
- E52F59ED1E5C21890084B3E2 /* camerademo */,
- E52F59EC1E5C21890084B3E2 /* Products */,
- );
- sourceTree = "<group>";
- };
- E52F59EC1E5C21890084B3E2 /* Products */ = {
- isa = PBXGroup;
- children = (
- E52F59EB1E5C21890084B3E2 /* camerademo.app */,
- );
- name = Products;
- sourceTree = "<group>";
- };
- E52F59ED1E5C21890084B3E2 /* camerademo */ = {
- isa = PBXGroup;
- children = (
- E52F59F11E5C21890084B3E2 /* AppDelegate.h */,
- E52F59F21E5C21890084B3E2 /* AppDelegate.m */,
- E52F59F41E5C21890084B3E2 /* ViewController.h */,
- E52F59F51E5C21890084B3E2 /* ViewController.m */,
- E52F59F71E5C21890084B3E2 /* Main.storyboard */,
- E52F59FA1E5C21890084B3E2 /* Assets.xcassets */,
- E52F59FC1E5C21890084B3E2 /* LaunchScreen.storyboard */,
- E52F59FF1E5C21890084B3E2 /* Info.plist */,
- E52F59EE1E5C21890084B3E2 /* Supporting Files */,
- );
- path = camerademo;
- sourceTree = "<group>";
- };
- E52F59EE1E5C21890084B3E2 /* Supporting Files */ = {
- isa = PBXGroup;
- children = (
- E52F59EF1E5C21890084B3E2 /* main.m */,
- );
- name = "Supporting Files";
- sourceTree = "<group>";
- };
-/* End PBXGroup section */
-
-/* Begin PBXNativeTarget section */
- E52F59EA1E5C21890084B3E2 /* camerademo */ = {
- isa = PBXNativeTarget;
- buildConfigurationList = E52F5A021E5C21890084B3E2 /* Build configuration list for PBXNativeTarget "camerademo" */;
- buildPhases = (
- E52F59E71E5C21890084B3E2 /* Sources */,
- E52F59E81E5C21890084B3E2 /* Frameworks */,
- E52F59E91E5C21890084B3E2 /* Resources */,
- );
- buildRules = (
- );
- dependencies = (
- );
- name = camerademo;
- productName = camerademo;
- productReference = E52F59EB1E5C21890084B3E2 /* camerademo.app */;
- productType = "com.apple.product-type.application";
- };
-/* End PBXNativeTarget section */
-
-/* Begin PBXProject section */
- E52F59E31E5C21890084B3E2 /* Project object */ = {
- isa = PBXProject;
- attributes = {
- LastUpgradeCheck = 0820;
- ORGANIZATIONNAME = WindShan;
- TargetAttributes = {
- E52F59EA1E5C21890084B3E2 = {
- CreatedOnToolsVersion = 8.2.1;
- DevelopmentTeam = VGXA77XL6T;
- ProvisioningStyle = Automatic;
- };
- };
- };
- buildConfigurationList = E52F59E61E5C21890084B3E2 /* Build configuration list for PBXProject "camerademo" */;
- compatibilityVersion = "Xcode 3.2";
- developmentRegion = English;
- hasScannedForEncodings = 0;
- knownRegions = (
- en,
- Base,
- );
- mainGroup = E52F59E21E5C21890084B3E2;
- productRefGroup = E52F59EC1E5C21890084B3E2 /* Products */;
- projectDirPath = "";
- projectRoot = "";
- targets = (
- E52F59EA1E5C21890084B3E2 /* camerademo */,
- );
- };
-/* End PBXProject section */
-
-/* Begin PBXResourcesBuildPhase section */
- E52F59E91E5C21890084B3E2 /* Resources */ = {
- isa = PBXResourcesBuildPhase;
- buildActionMask = 2147483647;
- files = (
- E52F59FE1E5C21890084B3E2 /* LaunchScreen.storyboard in Resources */,
- E52F59FB1E5C21890084B3E2 /* Assets.xcassets in Resources */,
- E52F59F91E5C21890084B3E2 /* Main.storyboard in Resources */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
-/* End PBXResourcesBuildPhase section */
-
-/* Begin PBXSourcesBuildPhase section */
- E52F59E71E5C21890084B3E2 /* Sources */ = {
- isa = PBXSourcesBuildPhase;
- buildActionMask = 2147483647;
- files = (
- E52F59F61E5C21890084B3E2 /* ViewController.m in Sources */,
- E52F59F31E5C21890084B3E2 /* AppDelegate.m in Sources */,
- E52F59F01E5C21890084B3E2 /* main.m in Sources */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
-/* End PBXSourcesBuildPhase section */
-
-/* Begin PBXVariantGroup section */
- E52F59F71E5C21890084B3E2 /* Main.storyboard */ = {
- isa = PBXVariantGroup;
- children = (
- E52F59F81E5C21890084B3E2 /* Base */,
- );
- name = Main.storyboard;
- sourceTree = "<group>";
- };
- E52F59FC1E5C21890084B3E2 /* LaunchScreen.storyboard */ = {
- isa = PBXVariantGroup;
- children = (
- E52F59FD1E5C21890084B3E2 /* Base */,
- );
- name = LaunchScreen.storyboard;
- sourceTree = "<group>";
- };
-/* End PBXVariantGroup section */
-
-/* Begin XCBuildConfiguration section */
- E52F5A001E5C21890084B3E2 /* Debug */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- ALWAYS_SEARCH_USER_PATHS = NO;
- CLANG_ANALYZER_NONNULL = YES;
- CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
- CLANG_CXX_LIBRARY = "libc++";
- CLANG_ENABLE_MODULES = YES;
- CLANG_ENABLE_OBJC_ARC = YES;
- CLANG_WARN_BOOL_CONVERSION = YES;
- CLANG_WARN_CONSTANT_CONVERSION = YES;
- CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
- CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
- CLANG_WARN_EMPTY_BODY = YES;
- CLANG_WARN_ENUM_CONVERSION = YES;
- CLANG_WARN_INFINITE_RECURSION = YES;
- CLANG_WARN_INT_CONVERSION = YES;
- CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
- CLANG_WARN_SUSPICIOUS_MOVE = YES;
- CLANG_WARN_UNREACHABLE_CODE = YES;
- CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
- "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
- COPY_PHASE_STRIP = NO;
- DEBUG_INFORMATION_FORMAT = dwarf;
- ENABLE_STRICT_OBJC_MSGSEND = YES;
- ENABLE_TESTABILITY = YES;
- GCC_C_LANGUAGE_STANDARD = gnu99;
- GCC_DYNAMIC_NO_PIC = NO;
- GCC_NO_COMMON_BLOCKS = YES;
- GCC_OPTIMIZATION_LEVEL = 0;
- GCC_PREPROCESSOR_DEFINITIONS = (
- "DEBUG=1",
- "$(inherited)",
- );
- GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
- GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
- GCC_WARN_UNDECLARED_SELECTOR = YES;
- GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
- GCC_WARN_UNUSED_FUNCTION = YES;
- GCC_WARN_UNUSED_VARIABLE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 10.2;
- MTL_ENABLE_DEBUG_INFO = YES;
- ONLY_ACTIVE_ARCH = YES;
- SDKROOT = iphoneos;
- };
- name = Debug;
- };
- E52F5A011E5C21890084B3E2 /* Release */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- ALWAYS_SEARCH_USER_PATHS = NO;
- CLANG_ANALYZER_NONNULL = YES;
- CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
- CLANG_CXX_LIBRARY = "libc++";
- CLANG_ENABLE_MODULES = YES;
- CLANG_ENABLE_OBJC_ARC = YES;
- CLANG_WARN_BOOL_CONVERSION = YES;
- CLANG_WARN_CONSTANT_CONVERSION = YES;
- CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
- CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
- CLANG_WARN_EMPTY_BODY = YES;
- CLANG_WARN_ENUM_CONVERSION = YES;
- CLANG_WARN_INFINITE_RECURSION = YES;
- CLANG_WARN_INT_CONVERSION = YES;
- CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
- CLANG_WARN_SUSPICIOUS_MOVE = YES;
- CLANG_WARN_UNREACHABLE_CODE = YES;
- CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
- "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
- COPY_PHASE_STRIP = NO;
- DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
- ENABLE_NS_ASSERTIONS = NO;
- ENABLE_STRICT_OBJC_MSGSEND = YES;
- GCC_C_LANGUAGE_STANDARD = gnu99;
- GCC_NO_COMMON_BLOCKS = YES;
- GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
- GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
- GCC_WARN_UNDECLARED_SELECTOR = YES;
- GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
- GCC_WARN_UNUSED_FUNCTION = YES;
- GCC_WARN_UNUSED_VARIABLE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 10.2;
- MTL_ENABLE_DEBUG_INFO = NO;
- SDKROOT = iphoneos;
- VALIDATE_PRODUCT = YES;
- };
- name = Release;
- };
- E52F5A031E5C21890084B3E2 /* Debug */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
- DEVELOPMENT_TEAM = VGXA77XL6T;
- INFOPLIST_FILE = camerademo/Info.plist;
- LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
- PRODUCT_BUNDLE_IDENTIFIER = com.moral.camerademo.camerademo;
- PRODUCT_NAME = "$(TARGET_NAME)";
- };
- name = Debug;
- };
- E52F5A041E5C21890084B3E2 /* Release */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
- DEVELOPMENT_TEAM = VGXA77XL6T;
- INFOPLIST_FILE = camerademo/Info.plist;
- LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
- PRODUCT_BUNDLE_IDENTIFIER = com.moral.camerademo.camerademo;
- PRODUCT_NAME = "$(TARGET_NAME)";
- };
- name = Release;
- };
-/* End XCBuildConfiguration section */
-
-/* Begin XCConfigurationList section */
- E52F59E61E5C21890084B3E2 /* Build configuration list for PBXProject "camerademo" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- E52F5A001E5C21890084B3E2 /* Debug */,
- E52F5A011E5C21890084B3E2 /* Release */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Release;
- };
- E52F5A021E5C21890084B3E2 /* Build configuration list for PBXNativeTarget "camerademo" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- E52F5A031E5C21890084B3E2 /* Debug */,
- E52F5A041E5C21890084B3E2 /* Release */,
- );
- defaultConfigurationIsVisible = 0;
- };
-/* End XCConfigurationList section */
- };
- rootObject = E52F59E31E5C21890084B3E2 /* Project object */;
-}
diff --git a/camerademo/camerademo.xcodeproj/project.xcworkspace/xcuserdata/WindShan.xcuserdatad/UserInterfaceState.xcuserstate b/camerademo/camerademo.xcodeproj/project.xcworkspace/xcuserdata/WindShan.xcuserdatad/UserInterfaceState.xcuserstate
deleted file mode 100644
index 3f97b50..0000000
--- a/camerademo/camerademo.xcodeproj/project.xcworkspace/xcuserdata/WindShan.xcuserdatad/UserInterfaceState.xcuserstate
+++ /dev/null
Binary files differ
diff --git a/camerademo/camerademo.xcodeproj/xcuserdata/WindShan.xcuserdatad/xcschemes/camerademo.xcscheme b/camerademo/camerademo.xcodeproj/xcuserdata/WindShan.xcuserdatad/xcschemes/camerademo.xcscheme
deleted file mode 100644
index b422b1d..0000000
--- a/camerademo/camerademo.xcodeproj/xcuserdata/WindShan.xcuserdatad/xcschemes/camerademo.xcscheme
+++ /dev/null
@@ -1,46 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<Scheme
- LastUpgradeVersion = "0820"
- version = "1.3">
- <BuildAction
- parallelizeBuildables = "YES"
- buildImplicitDependencies = "YES">
- </BuildAction>
- <TestAction
- buildConfiguration = "Debug"
- selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
- selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
- shouldUseLaunchSchemeArgsEnv = "YES">
- <Testables>
- </Testables>
- <AdditionalOptions>
- </AdditionalOptions>
- </TestAction>
- <LaunchAction
- buildConfiguration = "Debug"
- selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
- selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
- launchStyle = "0"
- useCustomWorkingDirectory = "NO"
- ignoresPersistentStateOnLaunch = "NO"
- debugDocumentVersioning = "YES"
- debugServiceExtension = "internal"
- allowLocationSimulation = "YES">
- <AdditionalOptions>
- </AdditionalOptions>
- </LaunchAction>
- <ProfileAction
- buildConfiguration = "Release"
- shouldUseLaunchSchemeArgsEnv = "YES"
- savedToolIdentifier = ""
- useCustomWorkingDirectory = "NO"
- debugDocumentVersioning = "YES">
- </ProfileAction>
- <AnalyzeAction
- buildConfiguration = "Debug">
- </AnalyzeAction>
- <ArchiveAction
- buildConfiguration = "Release"
- revealArchiveInOrganizer = "YES">
- </ArchiveAction>
-</Scheme>
diff --git a/camerademo/camerademo/Base.lproj/Main.storyboard b/camerademo/camerademo/Base.lproj/Main.storyboard
deleted file mode 100644
index 4529698..0000000
--- a/camerademo/camerademo/Base.lproj/Main.storyboard
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="11134" systemVersion="15F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
- <dependencies>
- <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11106"/>
- <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
- </dependencies>
- <scenes>
- <!--View Controller-->
- <scene sceneID="tne-QT-ifu">
- <objects>
- <viewController id="BYZ-38-t0r" customClass="ViewController" customModuleProvider="" sceneMemberID="viewController">
- <layoutGuides>
- <viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/>
- <viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
- </layoutGuides>
- <view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
- <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
- <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
- <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
- </view>
- </viewController>
- <placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
- </objects>
- </scene>
- </scenes>
-</document>
diff --git a/camerademo/camerademo/demo/FileManager/MPFileManager.h b/camerademo/camerademo/demo/FileManager/MPFileManager.h
deleted file mode 100755
index 15562d4..0000000
--- a/camerademo/camerademo/demo/FileManager/MPFileManager.h
+++ /dev/null
@@ -1,31 +0,0 @@
-//
-// MPFileManager.h
-// MobileProject ���������������
-//
-// Created by wujunyang on 16/7/22.
-// Copyright �� 2016��� wujunyang. All rights reserved.
-//
-
-#import <Foundation/Foundation.h>
-#import <AssetsLibrary/ALAsset.h>
-#import <AssetsLibrary/ALAssetsLibrary.h>
-#import <AssetsLibrary/ALAssetsGroup.h>
-#import <AssetsLibrary/ALAssetRepresentation.h>
-
-@interface MPFileManager : NSObject
-
-+ (MPFileManager *)sharedManager;
-
-//������������������
-+ (NSString *)downloadPath;
-//������������������
-+ (NSString *)uploadPath;
-
-//���������������������APP������������
-+ (BOOL)writeUploadDataWithName:(NSString *)fileName andAsset:(ALAsset *)asset;
-//���������������������APP������������
-+ (BOOL)writeUploadDataWithName:(NSString *)fileName andImage:(UIImage *)image;
-//������APP���������������������
-+ (BOOL)deleteUploadDataWithName:(NSString *)fileName;
-
-@end
diff --git a/camerademo/camerademo/demo/FileManager/MPFileManager.m b/camerademo/camerademo/demo/FileManager/MPFileManager.m
deleted file mode 100755
index f514428..0000000
--- a/camerademo/camerademo/demo/FileManager/MPFileManager.m
+++ /dev/null
@@ -1,133 +0,0 @@
-//
-// MPFileManager.m
-// MobileProject
-//
-// Created by wujunyang on 16/7/22.
-// Copyright �� 2016��� wujunyang. All rights reserved.
-//
-
-#import "MPFileManager.h"
-
-@implementation MPFileManager
-
-+ (MPFileManager *)sharedManager {
- static MPFileManager *_sharedManager = nil;
- static dispatch_once_t onceToken;
- dispatch_once(&onceToken, ^{
- _sharedManager = [[MPFileManager alloc] init];
- });
- return _sharedManager;
-}
-
-- (instancetype)init
-{
- self = [super init];
- if (self) {
- [[self class] createFolder:[[self class] downloadPath]];
- [[self class] createFolder:[[self class] uploadPath]];
- }
- return self;
-}
-
-/**
- * @author wujunyang, 16-07-22 11:07:41
- *
- * @brief ������������������
- *
- * @return <#return value description#>
- */
-+ (NSString *)downloadPath{
- NSString *documentPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
- NSString *downloadPath = [documentPath stringByAppendingPathComponent:@"MobileProject_Download"];
- return downloadPath;
-}
-
-/**
- * @author wujunyang, 16-07-22 11:07:58
- *
- * @brief ������������������
- *
- * @return <#return value description#>
- */
-+ (NSString *)uploadPath{
- NSString *documentPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
- NSString *uploadPath = [documentPath stringByAppendingPathComponent:@"MobileProject_Upload"];
- return uploadPath;
-}
-
-/**
- * @author wujunyang, 16-07-22 11:07:50
- *
- * @brief ���������������������
- *
- * @param path <#path description#>
- *
- * @return <#return value description#>
- */
-+ (BOOL)createFolder:(NSString *)path{
- BOOL isDir = NO;
- NSFileManager *fileManager = [NSFileManager defaultManager];
- BOOL existed = [fileManager fileExistsAtPath:path isDirectory:&isDir];
- BOOL isCreated = NO;
- if (!(isDir == YES && existed == YES)){
- isCreated = [fileManager createDirectoryAtPath:path withIntermediateDirectories:YES attributes:nil error:nil];
- }else{
- isCreated = YES;
- }
- return isCreated;
-}
-
-
-+ (BOOL)writeUploadDataWithName:(NSString *)fileName andAsset:(ALAsset *)asset{
- if (![self createFolder:[self uploadPath]]) {
- return NO;
- }
- NSString *filePath = [[self uploadPath] stringByAppendingPathComponent:fileName];
-
- [[NSFileManager defaultManager] createFileAtPath:filePath contents:nil attributes:nil];
- NSFileHandle *handle = [NSFileHandle fileHandleForWritingAtPath:filePath];
- if (!handle) {
- return NO;
- }
- static const NSUInteger BufferSize = 1024*1024;
-
- ALAssetRepresentation *rep = [asset defaultRepresentation];
- uint8_t *buffer = calloc(BufferSize, sizeof(*buffer));
- NSUInteger offset = 0, bytesRead = 0;
-
- do {
- @try {
- bytesRead = [rep getBytes:buffer fromOffset:offset length:BufferSize error:nil];
- [handle writeData:[NSData dataWithBytesNoCopy:buffer length:bytesRead freeWhenDone:NO]];
- offset += bytesRead;
- } @catch (NSException *exception) {
- free(buffer);
-
- return NO;
- }
- } while (bytesRead > 0);
-
- free(buffer);
- return YES;
-}
-
-+ (BOOL)writeUploadDataWithName:(NSString *)fileName andImage:(UIImage *)image{
- if (![self createFolder:[self uploadPath]]) {
- return NO;
- }
- NSString *filePath = [[self uploadPath] stringByAppendingPathComponent:fileName];
-
- return [UIImageJPEGRepresentation(image, 1.0) writeToFile:filePath options:NSAtomicWrite error:nil];
-}
-
-+ (BOOL)deleteUploadDataWithName:(NSString *)fileName{
- NSString *filePath = [[self uploadPath] stringByAppendingPathComponent:fileName];
- NSFileManager *fm = [NSFileManager defaultManager];
- if ([fm fileExistsAtPath:filePath]) {
- return [fm removeItemAtPath:filePath error:nil];
- }else{
- return YES;
- }
-}
-
-@end
diff --git a/camerademo/camerademo/demo/MPUploadImageHelper.h b/camerademo/camerademo/demo/MPUploadImageHelper.h
deleted file mode 100755
index e752fb2..0000000
--- a/camerademo/camerademo/demo/MPUploadImageHelper.h
+++ /dev/null
@@ -1,34 +0,0 @@
-//
-// MPUploadImageHelper.h
-// MobileProject
-//
-// Created by wujunyang on 16/7/20.
-// Copyright �� 2016��� wujunyang. All rights reserved.
-//
-
-#import <Foundation/Foundation.h>
-#import "MPImageItemModel.h"
-
-@interface MPUploadImageHelper : NSObject
-
-//������������������imagesArray ���������selectedAssetURLs������������KVO������������
-@property (readwrite, nonatomic, strong) NSMutableArray *imagesArray;
-@property (readwrite, nonatomic, strong) NSMutableArray *selectedAssetURLs;
-
-
-- (void)addASelectedAssetURL:(NSURL *)assetURL;
-- (void)deleteASelectedAssetURL:(NSURL *)assetURL;
-- (void)deleteAImage:(MPImageItemModel *)imageInfo;
-
-/**
- * @author wujunyang, 16-07-25 13:07:17
- *
- * @brief <#Description#>
- *
- * @param isUploadProcess ������������������������YES���������������������
- *
- * @return <#return value description#>
- */
-+(MPUploadImageHelper *)MPUploadImageForSend:(BOOL)isUploadProcess;
-
-@end
diff --git a/camerademo/camerademo/demo/MPUploadImageHelper.m b/camerademo/camerademo/demo/MPUploadImageHelper.m
deleted file mode 100755
index 8cd4d65..0000000
--- a/camerademo/camerademo/demo/MPUploadImageHelper.m
+++ /dev/null
@@ -1,82 +0,0 @@
-//
-// MPUploadImageHelper.m
-// MobileProject
-//
-// Created by wujunyang on 16/7/20.
-// Copyright �� 2016��� wujunyang. All rights reserved.
-//
-
-#import "MPUploadImageHelper.h"
-
-@interface MPUploadImageHelper()
-@property(nonatomic)BOOL isUploadProcess;
-@end
-
-static MPUploadImageHelper *_mpUploadImageHelper = nil;
-
-@implementation MPUploadImageHelper
-
-+(MPUploadImageHelper *)MPUploadImageForSend:(BOOL)isUploadProcess
-{
- _mpUploadImageHelper = [[MPUploadImageHelper alloc] init];
- _mpUploadImageHelper.isUploadProcess=isUploadProcess;
- return _mpUploadImageHelper;
-}
-
-- (void)setSelectedAssetURLs:(NSMutableArray *)selectedAssetURLs{
- NSMutableArray *needToAdd = [NSMutableArray new];
- NSMutableArray *needToDelete = [NSMutableArray new];
- [self.selectedAssetURLs enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
- if (![selectedAssetURLs containsObject:obj]) {
- [needToDelete addObject:obj];
- }
- }];
- [needToDelete enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
- [self deleteASelectedAssetURL:obj];
- }];
- [selectedAssetURLs enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
- if (![self.selectedAssetURLs containsObject:obj]) {
- [needToAdd addObject:obj];
- }
- }];
- [needToAdd enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
- [self addASelectedAssetURL:obj];
- }];
-}
-
-
-- (void)addASelectedAssetURL:(NSURL *)assetURL{
- if (!_selectedAssetURLs) {
- _selectedAssetURLs = [NSMutableArray new];
- }
- if (!_imagesArray) {
- _imagesArray = [NSMutableArray new];
- }
-
- [_selectedAssetURLs addObject:assetURL];
-
- NSMutableArray *imagesArray = [self mutableArrayValueForKey:@"imagesArray"];//������kvo
- MPImageItemModel *imageItem = [MPImageItemModel imageWithAssetURL:assetURL isUploadProcess:self.isUploadProcess];
- [imagesArray addObject:imageItem];
-}
-
-- (void)deleteASelectedAssetURL:(NSURL *)assetURL{
- [self.selectedAssetURLs removeObject:assetURL];
- NSMutableArray *imagesArray = [self mutableArrayValueForKey:@"imagesArray"];//������kvo
- [imagesArray enumerateObjectsUsingBlock:^(MPImageItemModel *obj, NSUInteger idx, BOOL *stop) {
- if (obj.assetURL == assetURL) {
- [imagesArray removeObject:obj];
- *stop = YES;
- }
- }];
-}
-
-- (void)deleteAImage:(MPImageItemModel *)imageInfo{
- NSMutableArray *imagesArray = [self mutableArrayValueForKey:@"imagesArray"];//������kvo
- [imagesArray removeObject:imageInfo];
- if (imageInfo.assetURL) {
- [self.selectedAssetURLs removeObject:imageInfo.assetURL];
- }
-}
-
-@end
diff --git a/camerademo/camerademo/demo/MPUploadImagesViewController.h b/camerademo/camerademo/demo/MPUploadImagesViewController.h
deleted file mode 100755
index 1ed9601..0000000
--- a/camerademo/camerademo/demo/MPUploadImagesViewController.h
+++ /dev/null
@@ -1,14 +0,0 @@
-//
-// MPUploadImagesViewController.h
-// MobileProject ������������
-//
-// Created by wujunyang on 16/7/20.
-// Copyright �� 2016��� wujunyang. All rights reserved.
-//
-
-#import <UIKit/UIKit.h>
-
-
-@interface MPUploadImagesViewController : UIViewController
-
-@end
diff --git a/camerademo/camerademo/demo/MPUploadImagesViewController.m b/camerademo/camerademo/demo/MPUploadImagesViewController.m
deleted file mode 100755
index 99c2a66..0000000
--- a/camerademo/camerademo/demo/MPUploadImagesViewController.m
+++ /dev/null
@@ -1,231 +0,0 @@
-//
-// MPUploadImagesViewController.m
-// MobileProject
-//
-// Created by wujunyang on 16/7/20.
-// Copyright �� 2016��� wujunyang. All rights reserved.
-//
-
-#import "MPUploadImagesViewController.h"
-
-@interface MPUploadImagesViewController()<UITableViewDataSource, UITableViewDelegate,UIActionSheetDelegate, UINavigationControllerDelegate, UIImagePickerControllerDelegate, QBImagePickerControllerDelegate>
-@property (nonatomic,strong) UITableView *myTableView;
-@property (strong, nonatomic) MPUploadImageHelper *curUploadImageHelper;
-@end
-
-
-@implementation MPUploadImagesViewController
-
-
-- (void)viewDidLoad {
- [super viewDidLoad];
- self.view.backgroundColor=[UIColor whiteColor];
- self.navigationItem.title=@"������������";
-
- //���������
- _curUploadImageHelper=[MPUploadImageHelper MPUploadImageForSend:NO];
-
- //���������������
- if (!_myTableView) {
- _myTableView = [[UITableView alloc] initWithFrame:CGRectMake(0,0, Main_Screen_Width, Main_Screen_Height) style:UITableViewStylePlain];
- _myTableView.tableFooterView=[UIView new];
- _myTableView.showsVerticalScrollIndicator = NO;
- _myTableView.showsHorizontalScrollIndicator = NO;
- _myTableView.dataSource = self;
- _myTableView.delegate = self;
- [_myTableView registerClass:[MPImageUploadCell class] forCellReuseIdentifier:NSStringFromClass([MPImageUploadCell class])];
- [self.view addSubview:_myTableView];
- [_myTableView mas_makeConstraints:^(MASConstraintMaker *make) {
- make.edges.equalTo(UIEdgeInsetsMake(0, 0, 0, 0));
- }];
- }
-
- //������������
- UIButton*rightButton = [[UIButton alloc]initWithFrame:CGRectMake(0,0,70,30)];
- [rightButton setTitleColor:[UIColor blueColor] forState:UIControlStateNormal];
- [rightButton setTitle:@"������" forState:UIControlStateNormal];
- [rightButton addTarget:self action:@selector(myAction)forControlEvents:UIControlEventTouchUpInside];
- UIBarButtonItem*rightItem = [[UIBarButtonItem alloc]initWithCustomView:rightButton];
- self.navigationItem.rightBarButtonItem= rightItem;
-}
-
-- (void)didReceiveMemoryWarning {
- [super didReceiveMemoryWarning];
-}
-
-
-- (void)dealloc
-{
- _myTableView.delegate = nil;
- _myTableView.dataSource = nil;
-}
-
-#pragma mark UITableViewDataSource, UITableViewDelegate������������
-
--(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
-{
- return 1;
-}
-
-- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
- return 1;
-}
-
-- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
-{
- MPImageUploadCell *cell = [tableView dequeueReusableCellWithIdentifier:NSStringFromClass([MPImageUploadCell class]) forIndexPath:indexPath];
- __weak typeof(self)weakSelf = self;
- cell.accessoryType = UITableViewCellAccessoryNone;
- cell.curUploadImageHelper=self.curUploadImageHelper;
- cell.addPicturesBlock = ^(){
- [weakSelf showActionForPhoto];
- };
- cell.deleteImageBlock = ^(MPImageItemModel *toDelete)
- {
- [weakSelf.curUploadImageHelper deleteAImage:toDelete];
- [weakSelf.myTableView reloadData];
- };
- return cell;
-}
-
-- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
- return [MPImageUploadCell cellHeightWithObj:self.curUploadImageHelper];
-}
-
-- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
- [tableView deselectRowAtIndexPath:indexPath animated:YES];
-}
-
-
-#pragma mark UIActionSheetDelegate
-
-- (void)actionSheet:(UIActionSheet *)modalView clickedButtonAtIndex:(NSInteger)buttonIndex
-{
- if (buttonIndex == 0)
- {
- //������
- if (![cameraHelper checkCameraAuthorizationStatus]) {
- return;
- }
- UIImagePickerController *picker = [[UIImagePickerController alloc] init];
- picker.delegate = self;
- picker.allowsEditing = NO;//���������������
- picker.sourceType = UIImagePickerControllerSourceTypeCamera;
- [self presentViewController:picker animated:YES completion:nil];//������������������
- }else if (buttonIndex == 1)
- {
- //������
- if (![cameraHelper checkPhotoLibraryAuthorizationStatus]) {
- return;
- }
- QBImagePickerController *imagePickerController = [[QBImagePickerController alloc] init];
- [imagePickerController.selectedAssetURLs removeAllObjects];
- [imagePickerController.selectedAssetURLs addObjectsFromArray:self.curUploadImageHelper.selectedAssetURLs];
- imagePickerController.filterType = QBImagePickerControllerFilterTypePhotos;
- imagePickerController.delegate = self;
- imagePickerController.maximumNumberOfSelection = kupdateMaximumNumberOfImage;
- imagePickerController.allowsMultipleSelection = YES;
- UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:imagePickerController];
- [self presentViewController:navigationController animated:YES completion:NULL];
- }
-}
-
-
-#pragma mark UIImagePickerControllerDelegate
-
-- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
-{
- UIImage *pickerImage = [info objectForKey:UIImagePickerControllerOriginalImage];
- ALAssetsLibrary *assetsLibrary = [[ALAssetsLibrary alloc] init];
- [assetsLibrary writeImageToSavedPhotosAlbum:[pickerImage CGImage] orientation:(ALAssetOrientation)pickerImage.imageOrientation completionBlock:^(NSURL *assetURL, NSError *error) {
- [self.curUploadImageHelper addASelectedAssetURL:assetURL];
- //������������ ������������������������
- [self partialTableViewRefresh];
- }];
- [picker dismissViewControllerAnimated:YES completion:^{}];
-}
-
-- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker
-{
- [picker dismissViewControllerAnimated:YES completion:nil];
-}
-
-
-#pragma mark UINavigationControllerDelegate, QBImagePickerControllerDelegate
-
-- (void)qb_imagePickerController:(QBImagePickerController *)imagePickerController didSelectAssets:(NSArray *)assets{
- NSMutableArray *selectedAssetURLs = [NSMutableArray new];
- [imagePickerController.selectedAssetURLs enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
- [selectedAssetURLs addObject:obj];
- }];
- MPWeakSelf(self)
- dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
- self.curUploadImageHelper.selectedAssetURLs = selectedAssetURLs;
- dispatch_async(dispatch_get_main_queue(), ^{
- MPStrongSelf(self)
- //������������ ������������������������
- [self partialTableViewRefresh];
- });
- });
- [self dismissViewControllerAnimated:YES completion:nil];
-}
-- (void)qb_imagePickerControllerDidCancel:(QBImagePickerController *)imagePickerController{
- [self dismissViewControllerAnimated:YES completion:nil];
-}
-
-#pragma mark ���������������
-
-//���������������
--(void)showActionForPhoto
-{
- UIActionSheet *actionSheet = [[UIActionSheet alloc]
- initWithTitle:nil
- delegate:self
- cancelButtonTitle:@"������"
- destructiveButtonTitle:nil
- otherButtonTitles:@"������",@"���������������",nil];
- actionSheet.actionSheetStyle = UIActionSheetStyleBlackOpaque;
- [actionSheet showInView:self.view];
-}
-
-//��������������������������������� ������������������������
--(void)partialTableViewRefresh
-{
- [self.myTableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:0 inSection:0]] withRowAnimation:UITableViewRowAnimationFade];
-}
-
-//������������
--(void)myAction
-{
- if (self.curUploadImageHelper.selectedAssetURLs.count==0) {
- [MBProgressHUD showAutoMessage:@"���������������������������" ToView:nil];
- return;
- }
-
- MPUploadImageService *req=[[MPUploadImageService alloc]initWithUploadImages:self.curUploadImageHelper];
-
- [req startWithCompletionBlockWithSuccess:^(__kindof YTKBaseRequest *request) {
- //������������������������������
-
- } failure:^(__kindof YTKBaseRequest *request) {
- [MPRequstFailedHelper requstFailed:request];
- }];
-
- //������������
- MPWeakSelf(self)
- req.uploadPropressBlock = ^(NSUInteger __unused bytesWritten,
- long long totalBytesWritten,
- long long totalBytesExpectedToWrite)
- {
-
- MPStrongSelf(self);
- CGFloat propress = totalBytesWritten*1.0/totalBytesExpectedToWrite;
- NSLog(@"���������������%lld/%lld___%2f",totalBytesWritten,totalBytesExpectedToWrite,propress);
- dispatch_async(dispatch_get_main_queue(), ^{
- //������UI
- });
-
-
- };
-}
-@end
diff --git a/camerademo/camerademo/demo/Model/MPImageItemModel.h b/camerademo/camerademo/demo/Model/MPImageItemModel.h
deleted file mode 100755
index a23da37..0000000
--- a/camerademo/camerademo/demo/Model/MPImageItemModel.h
+++ /dev/null
@@ -1,46 +0,0 @@
-//
-// MPImageItemModel.h
-// MobileProject ������������������������
-//
-// Created by wujunyang on 16/7/20.
-// Copyright �� 2016��� wujunyang. All rights reserved.
-//
-
-#import <Foundation/Foundation.h>
-#import "MPFileManager.h"
-#import "imageCompressHelper.h"
-#import "dateTimeHelper.h"
-#import "UIImage+Resize.h"
-#import "UIImage+FX.h"
-
-typedef NS_ENUM(NSInteger, MPImageUploadState)
-{
- MPImageUploadStateInit = 0,
- MPImageUploadStateIng,
- MPImageUploadStateSuccess,
- MPImageUploadStateFail
-};
-
-
-@interface MPImageItemModel : NSObject
-
-//������ ���������
-@property (readwrite, nonatomic, strong) UIImage *image, *thumbnailImage;
-//������������asstURL
-@property (strong, nonatomic) NSURL *assetURL;
-//������������
-@property (assign, nonatomic) MPImageUploadState uploadState;
-//���������������������[���������������������������������������������������������������������������������������������������,������������]
-@property(nonatomic,copy)NSString *httpUrl;
-@property(nonatomic,copy)NSString *upServicePath;
-//������������������ ������������ ��������� ������������
-@property (readwrite, nonatomic, strong) NSString *photoName;
-@property (readwrite, nonatomic, strong) NSString *photoLatitude;
-@property (readwrite, nonatomic, strong) NSString *photoLongitude;
-@property (readwrite, nonatomic, strong) NSString *photoTime;
-
-//������������
-+ (instancetype)imageWithAssetURL:(NSURL *)assetURL isUploadProcess:(BOOL)isUploadProcess;
-+ (instancetype)imageWithAssetURL:(NSURL *)assetURL andImage:(UIImage *)image;
-
-@end
diff --git a/camerademo/camerademo/demo/Model/MPImageItemModel.m b/camerademo/camerademo/demo/Model/MPImageItemModel.m
deleted file mode 100755
index 2d0bc80..0000000
--- a/camerademo/camerademo/demo/Model/MPImageItemModel.m
+++ /dev/null
@@ -1,100 +0,0 @@
-//
-// MPImageItemModel.m
-// MobileProject
-//
-// Created by wujunyang on 16/7/20.
-// Copyright �� 2016��� wujunyang. All rights reserved.
-//
-
-#import "MPImageItemModel.h"
-#import <CoreLocation/CoreLocation.h>
-
-@implementation MPImageItemModel
-
-+ (instancetype)imageWithAssetURL:(NSURL *)assetURL isUploadProcess:(BOOL)isUploadProcess{
- MPImageItemModel *imageItem = [[MPImageItemModel alloc] init];
- imageItem.uploadState = MPImageUploadStateInit;
- imageItem.assetURL = assetURL;
-
- MPWeakSelf(self);
-
- void (^selectAsset)(ALAsset *) = ^(ALAsset *asset){
- if (asset) {
- UIImage *highQualityImage = [imageCompressHelper fullScreenImageALAsset:asset];
- UIImage *thumbnailImage = [UIImage imageWithCGImage:[asset thumbnail]];
-
- //������������
- MPStrongSelf(self);
- [self imageInfoWithALAsset:asset imageItem:imageItem];
-
- dispatch_async(dispatch_get_main_queue(), ^{
- imageItem.image = [imageCompressHelper compressedImageToLimitSizeOfKB:100 image:highQualityImage];;
- imageItem.thumbnailImage = thumbnailImage;
-
- if (isUploadProcess) {
- //��������������� ���������������������������������
- [MPFileManager writeUploadDataWithName:imageItem.photoName andImage:imageItem.image];
- }
- });
- }
- };
-
- ALAssetsLibrary *assetsLibrary = [[ALAssetsLibrary alloc] init];
- MPWeakSelf(assetsLibrary);
- [assetsLibrary assetForURL:assetURL resultBlock:^(ALAsset *asset) {
- if (asset) {
- selectAsset(asset);
- }else{
- MPStrongSelf(assetsLibrary);
- [assetsLibrary enumerateGroupsWithTypes:ALAssetsGroupPhotoStream usingBlock:^(ALAssetsGroup *group, BOOL *stop) {
- [group enumerateAssetsUsingBlock:^(ALAsset *result, NSUInteger index, BOOL *stopG) {
- if([result.defaultRepresentation.url isEqual:assetURL]) {
- selectAsset(result);
- *stop = YES;
- *stopG = YES;
- }
- }];
- } failureBlock:^(NSError *error) {
- NSLog(@"������������������");
- }];
- }
- }failureBlock:^(NSError *error) {
- NSLog(@"������������������");
- }];
- return imageItem;
-
-}
-
-//������������������������
-+(void)imageInfoWithALAsset:(ALAsset *)asset imageItem:(MPImageItemModel *)imageItem
-{
- //������������
- NSDate * nsALAssetPropertyDate = [ asset valueForProperty:ALAssetPropertyDate ];
- if (nsALAssetPropertyDate!=nil) {
- imageItem.photoTime=[dateTimeHelper htcTimeToLocationStr:nsALAssetPropertyDate];
- }
-
- //GPS������
- CLLocation *location = [asset valueForProperty:ALAssetPropertyLocation];
- if (location) {
- CLLocationCoordinate2D curCoordinate=location.coordinate;
- imageItem.photoLatitude=[NSString stringWithFormat:@"%f",curCoordinate.latitude];
- imageItem.photoLongitude=[NSString stringWithFormat:@"%f",curCoordinate.longitude];
- }
-
- //������������
- ALAssetRepresentation *representation = [asset defaultRepresentation];
- imageItem.photoName = [representation filename];
-}
-
-
-+ (instancetype)imageWithAssetURL:(NSURL *)assetURL andImage:(UIImage *)image{
- MPImageItemModel *imageItem = [[MPImageItemModel alloc] init];
- imageItem.uploadState = MPImageUploadStateInit;
- imageItem.assetURL = assetURL;
- imageItem.image = image;
- imageItem.thumbnailImage = [image imageScaledToSize:CGSizeMake(AdaptedWidth(70), AdaptedWidth(70))];
- return imageItem;
-}
-
-@end
diff --git a/camerademo/camerademo/demo/OtherHelper/UITapImageView.h b/camerademo/camerademo/demo/OtherHelper/UITapImageView.h
deleted file mode 100755
index 3d3233b..0000000
--- a/camerademo/camerademo/demo/OtherHelper/UITapImageView.h
+++ /dev/null
@@ -1,17 +0,0 @@
-//
-// UITapImageView.h
-// zxptUser
-//
-// Created by wujunyang on 16/6/8.
-// Copyright �� 2016��� qijia. All rights reserved.
-//
-
-#import <UIKit/UIKit.h>
-
-@interface UITapImageView : UIImageView
-
-- (void)addTapBlock:(void(^)(id obj))tapAction;
-
--(void)setImageWithUrl:(NSURL *)imgUrl placeholderImage:(UIImage *)placeholderImage tapBlock:(void(^)(id obj))tapAction;
-
-@end
diff --git a/camerademo/camerademo/demo/OtherHelper/UITapImageView.m b/camerademo/camerademo/demo/OtherHelper/UITapImageView.m
deleted file mode 100755
index 4193a43..0000000
--- a/camerademo/camerademo/demo/OtherHelper/UITapImageView.m
+++ /dev/null
@@ -1,53 +0,0 @@
-//
-// UITapImageView.m
-// zxptUser
-//
-// Created by wujunyang on 16/6/8.
-// Copyright �� 2016��� qijia. All rights reserved.
-//
-
-#import "UITapImageView.h"
-
-@interface UITapImageView ()
-
-@property (nonatomic, copy) void(^tapAction)(id);
-
-@end
-
-@implementation UITapImageView
-
-- (id)initWithFrame:(CGRect)frame
-{
- self = [super initWithFrame:frame];
- if (self) {
- // Initialization code
- }
- return self;
-}
-
-- (instancetype)init
-{
- return [self initWithFrame:CGRectZero];
-}
-
-- (void)tap{
- if (self.tapAction) {
- self.tapAction(self);
- }
-}
-- (void)addTapBlock:(void(^)(id obj))tapAction{
- self.tapAction = tapAction;
- if (![self gestureRecognizers]) {
- self.userInteractionEnabled = YES;
- UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tap)];
- [self addGestureRecognizer:tap];
- }
-}
-
--(void)setImageWithUrl:(NSURL *)imgUrl placeholderImage:(UIImage *)placeholderImage tapBlock:(void(^)(id obj))tapAction{
- [self sd_setImageWithURL:imgUrl placeholderImage:placeholderImage];
- [self addTapBlock:tapAction];
-}
-
-
-@end
diff --git a/camerademo/camerademo/demo/OtherHelper/cameraHelper.h b/camerademo/camerademo/demo/OtherHelper/cameraHelper.h
deleted file mode 100755
index 609027f..0000000
--- a/camerademo/camerademo/demo/OtherHelper/cameraHelper.h
+++ /dev/null
@@ -1,23 +0,0 @@
-//
-// cameraHelper.h
-// MobileProject
-//
-// Created by wujunyang on 16/7/20.
-// Copyright �� 2016��� wujunyang. All rights reserved.
-//
-
-#import <Foundation/Foundation.h>
-
-@interface cameraHelper : NSObject
-
-/**
- * ������������"������"������������, ���������������������, ������������������������������������.
- */
-+ (BOOL)checkPhotoLibraryAuthorizationStatus;
-
-/**
- * ������������"������"������������, ���������������������, ������������������������������������.
- */
-+ (BOOL)checkCameraAuthorizationStatus;
-
-@end
diff --git a/camerademo/camerademo/demo/OtherHelper/cameraHelper.m b/camerademo/camerademo/demo/OtherHelper/cameraHelper.m
deleted file mode 100755
index 73a9a94..0000000
--- a/camerademo/camerademo/demo/OtherHelper/cameraHelper.m
+++ /dev/null
@@ -1,50 +0,0 @@
-//
-// cameraHelper.m
-// MobileProject
-//
-// Created by wujunyang on 16/7/20.
-// Copyright �� 2016��� wujunyang. All rights reserved.
-//
-
-#import "cameraHelper.h"
-#import <AssetsLibrary/ALAsset.h>
-#import <AssetsLibrary/ALAssetsLibrary.h>
-#import <AssetsLibrary/ALAssetsGroup.h>
-#import <AssetsLibrary/ALAssetRepresentation.h>
-
-@import AVFoundation;
-
-@implementation cameraHelper
-
-+ (BOOL)checkPhotoLibraryAuthorizationStatus
-{
- //if ([ALAssetsLibrary respondsToSelector:@selector(authorizationStatus)]) {
- ALAuthorizationStatus authStatus = [ALAssetsLibrary authorizationStatus];
- if (ALAuthorizationStatusDenied == authStatus ||
- ALAuthorizationStatusRestricted == authStatus) {
- [MBProgressHUD showAutoMessage:@"������iPhone������������->������->������������������������������������������" ToView:nil];
- return NO;
- // }
- }
- return YES;
-}
-
-+ (BOOL)checkCameraAuthorizationStatus
-{
- if (![UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
- [MBProgressHUD showAutoMessage:@"������������������������" ToView:nil];
- return NO;
- }
-
- if ([AVCaptureDevice respondsToSelector:@selector(authorizationStatusForMediaType:)]) {
- AVAuthorizationStatus authStatus = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
- if (AVAuthorizationStatusDenied == authStatus ||
- AVAuthorizationStatusRestricted == authStatus) {
- [MBProgressHUD showAutoMessage:@"������iPhone������������->������->������������������������������������������" ToView:nil];
- return NO;
- }
- }
- return YES;
-}
-
-@end
diff --git a/camerademo/camerademo/demo/OtherHelper/dateTimeHelper.h b/camerademo/camerademo/demo/OtherHelper/dateTimeHelper.h
deleted file mode 100755
index 7e25da9..0000000
--- a/camerademo/camerademo/demo/OtherHelper/dateTimeHelper.h
+++ /dev/null
@@ -1,16 +0,0 @@
-//
-// dateTimeHelper.h
-// MobileProject
-//
-// Created by wujunyang on 16/7/20.
-// Copyright �� 2016��� wujunyang. All rights reserved.
-//
-
-#import <Foundation/Foundation.h>
-
-@interface dateTimeHelper : NSObject
-
-//������������������������������
-+ (NSString *)htcTimeToLocationStr:(NSDate*)curDate;
-
-@end
diff --git a/camerademo/camerademo/demo/OtherHelper/dateTimeHelper.m b/camerademo/camerademo/demo/OtherHelper/dateTimeHelper.m
deleted file mode 100755
index 0cb4e18..0000000
--- a/camerademo/camerademo/demo/OtherHelper/dateTimeHelper.m
+++ /dev/null
@@ -1,24 +0,0 @@
-//
-// dateTimeHelper.m
-// MobileProject
-//
-// Created by wujunyang on 16/7/20.
-// Copyright �� 2016��� wujunyang. All rights reserved.
-//
-
-#import "dateTimeHelper.h"
-
-@implementation dateTimeHelper
-
-+ (NSString *)htcTimeToLocationStr:(NSDate*)curDate
-{
- if (curDate==nil) {
- return @"";
- }
- NSDateFormatter* dateFormatter = [[NSDateFormatter alloc]init];
- [dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
- NSString *fixString = [dateFormatter stringFromDate:curDate];
- return fixString;
-}
-
-@end
diff --git a/camerademo/camerademo/demo/OtherHelper/imageCompressHelper.h b/camerademo/camerademo/demo/OtherHelper/imageCompressHelper.h
deleted file mode 100755
index e94a550..0000000
--- a/camerademo/camerademo/demo/OtherHelper/imageCompressHelper.h
+++ /dev/null
@@ -1,42 +0,0 @@
-//
-// imageCompressHelper.h
-// zxptUser ������������
-//
-// Created by wujunyang on 16/4/14.
-// Copyright �� 2016��� qijia. All rights reserved.
-//
-
-#import <Foundation/Foundation.h>
-#import <AssetsLibrary/ALAsset.h>
-#import <AssetsLibrary/ALAssetsLibrary.h>
-#import <AssetsLibrary/ALAssetsGroup.h>
-#import <AssetsLibrary/ALAssetRepresentation.h>
-
-@interface imageCompressHelper : NSObject
-
-/**
- * @author wujunyang, 16-04-14 15:04:54
- *
- * @brief ������������������KB���������������
- *
- * @param kb <#kb description#>
- * @param image <#image description#>
- *
- * @return <#return value description#>
- */
-+(UIImage*)compressedImageToLimitSizeOfKB:(CGFloat)kb image:(UIImage*)image;
-
-+(NSData*)returnDataCompressedImageToLimitSizeOfKB:(CGFloat)kb image:(UIImage*)image;
-
-//��������������������� ���������������������
-+(UIImage*) circleImage:(UIImage*) image withParam:(CGFloat) inset;
-
-//���������������������������
-+(UIImage *) imageCompressForWidth:(UIImage *)sourceImage targetWidth:(CGFloat)defineWidth;
-
-//���������������,size ������������������������ ������������ CGSizeMake(300, 140)
-+(UIImage *)compressImage:(UIImage *)sourceImage toTargetWidth:(CGFloat)targetWidth;
-
-//������������������
-+ (UIImage *)fullScreenImageALAsset:(ALAsset *)asset;
-@end
diff --git a/camerademo/camerademo/demo/OtherHelper/imageCompressHelper.m b/camerademo/camerademo/demo/OtherHelper/imageCompressHelper.m
deleted file mode 100755
index 2852c6a..0000000
--- a/camerademo/camerademo/demo/OtherHelper/imageCompressHelper.m
+++ /dev/null
@@ -1,163 +0,0 @@
-//
-// imageCompressHelper.m
-// zxptUser
-//
-// Created by wujunyang on 16/4/14.
-// Copyright �� 2016��� qijia. All rights reserved.
-//
-
-#import "imageCompressHelper.h"
-
-@implementation imageCompressHelper
-
-+(UIImage*)compressedImageToLimitSizeOfKB:(CGFloat)kb image:(UIImage*)image
-{
- //������������kb���������������������
- long imagePixel = CGImageGetWidth(image.CGImage)*CGImageGetHeight(image.CGImage);
- long imageKB = imagePixel * CGImageGetBitsPerPixel(image.CGImage) / (8 * 1024);
- if (imageKB > kb){
- float compressedParam = kb / imageKB;
- return [UIImage imageWithData:UIImageJPEGRepresentation(image, compressedParam)];
- }
- //������������
- else{
- return image;
- }
-}
-
-+(NSData*)returnDataCompressedImageToLimitSizeOfKB:(CGFloat)kb image:(UIImage*)image
-{
- //������������kb���������������������
- long imagePixel = CGImageGetWidth(image.CGImage)*CGImageGetHeight(image.CGImage);
- long imageKB = imagePixel * CGImageGetBitsPerPixel(image.CGImage) / (8 * 1024);
- if (imageKB > kb){
- float compressedParam = kb / imageKB;
- return UIImageJPEGRepresentation(image, compressedParam);
- }
- //������������
- else{
- return UIImageJPEGRepresentation(image, 1);
- }
-}
-
-
-+(UIImage*) circleImage:(UIImage*) image withParam:(CGFloat) inset
-{
- //UIGraphicsBeginImageContext(image.size);
- //������������ ���������������
- UIGraphicsBeginImageContextWithOptions(image.size, NO, [[UIScreen mainScreen] scale]);
- CGContextRef context =UIGraphicsGetCurrentContext();
-
- //���������������������2������������������
-
- CGContextSetLineWidth(context,2);
-
- CGContextSetStrokeColorWithColor(context, [UIColor whiteColor].CGColor);
-
- CGRect rect = CGRectMake(inset, inset, image.size.width - inset *2.0f, image.size.height - inset *2.0f);
-
- CGContextAddEllipseInRect(context, rect);
-
- CGContextClip(context);
-
- //���������������������image������
-
- [image drawInRect:rect];
-
- CGContextAddEllipseInRect(context, rect);
-
- CGContextStrokePath(context);
-
- //������������image
-
- UIImage *newimg = UIGraphicsGetImageFromCurrentImageContext();
-
- UIGraphicsEndImageContext();
-
- return newimg;
-}
-
-+(UIImage *) imageCompressForWidth:(UIImage *)sourceImage targetWidth:(CGFloat)defineWidth
-{
- UIImage *newImage = nil;
- CGSize imageSize = sourceImage.size;
- CGFloat width = imageSize.width;
- CGFloat height = imageSize.height;
- CGFloat targetWidth = defineWidth;
- CGFloat targetHeight = height / (width / targetWidth);
- CGSize size = CGSizeMake(targetWidth, targetHeight);
- CGFloat scaleFactor = 0.0;
- CGFloat scaledWidth = targetWidth;
- CGFloat scaledHeight = targetHeight;
- CGPoint thumbnailPoint = CGPointMake(0.0, 0.0);
-
- if(CGSizeEqualToSize(imageSize, size) == NO){
-
- CGFloat widthFactor = targetWidth / width;
- CGFloat heightFactor = targetHeight / height;
-
- if(widthFactor > heightFactor){
- scaleFactor = widthFactor;
- }
- else{
- scaleFactor = heightFactor;
- }
- scaledWidth = width * scaleFactor;
- scaledHeight = height * scaleFactor;
-
- if(widthFactor > heightFactor){
-
- thumbnailPoint.y = (targetHeight - scaledHeight) * 0.5;
-
- }else if(widthFactor < heightFactor){
-
- thumbnailPoint.x = (targetWidth - scaledWidth) * 0.5;
- }
- }
-
- UIGraphicsBeginImageContext(size);
-
- CGRect thumbnailRect = CGRectZero;
- thumbnailRect.origin = thumbnailPoint;
- thumbnailRect.size.width = scaledWidth;
- thumbnailRect.size.height = scaledHeight;
-
- [sourceImage drawInRect:thumbnailRect];
-
- newImage = UIGraphicsGetImageFromCurrentImageContext();
-
- if(newImage == nil){
-
- NSLog(@"scale image fail");
- }
- UIGraphicsEndImageContext();
- return newImage;
-}
-
-
-+(UIImage *)compressImage:(UIImage *)sourceImage toTargetWidth:(CGFloat)targetWidth
-{
- CGSize imageSize = sourceImage.size;
-
- CGFloat width = imageSize.width;
- CGFloat height = imageSize.height;
-
- CGFloat targetHeight = (targetWidth / width) * height;
-
- UIGraphicsBeginImageContext(CGSizeMake(targetWidth, targetHeight));
- [sourceImage drawInRect:CGRectMake(0, 0, targetWidth, targetHeight)];
-
- UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
- UIGraphicsEndImageContext();
-
- return newImage;
-}
-
-
-+ (UIImage *)fullScreenImageALAsset:(ALAsset *)asset{
- ALAssetRepresentation *assetRep = [asset defaultRepresentation];
- CGImageRef imgRef = [assetRep fullScreenImage];//fullScreenImage������������������������
- UIImage *img = [UIImage imageWithCGImage:imgRef];
- return img;
-}
-@end
diff --git a/camerademo/camerademo/demo/QBImagePickerController/QBAssetsCollectionCheckmarkView.h b/camerademo/camerademo/demo/QBImagePickerController/QBAssetsCollectionCheckmarkView.h
deleted file mode 100755
index 161379c..0000000
--- a/camerademo/camerademo/demo/QBImagePickerController/QBAssetsCollectionCheckmarkView.h
+++ /dev/null
@@ -1,13 +0,0 @@
-//
-// QBAssetsCollectionCheckmarkView.h
-// QBImagePickerController
-//
-// Created by Tanaka Katsuma on 2014/01/01.
-// Copyright (c) 2014��� Katsuma Tanaka. All rights reserved.
-//
-
-#import <UIKit/UIKit.h>
-
-@interface QBAssetsCollectionCheckmarkView : UIView
-
-@end
diff --git a/camerademo/camerademo/demo/QBImagePickerController/QBAssetsCollectionCheckmarkView.m b/camerademo/camerademo/demo/QBImagePickerController/QBAssetsCollectionCheckmarkView.m
deleted file mode 100755
index 82ee42d..0000000
--- a/camerademo/camerademo/demo/QBImagePickerController/QBAssetsCollectionCheckmarkView.m
+++ /dev/null
@@ -1,53 +0,0 @@
-//
-// QBAssetsCollectionCheckmarkView.m
-// QBImagePickerController
-//
-// Created by Tanaka Katsuma on 2014/01/01.
-// Copyright (c) 2014��� Katsuma Tanaka. All rights reserved.
-//
-
-#import "QBAssetsCollectionCheckmarkView.h"
-
-@implementation QBAssetsCollectionCheckmarkView
-
-- (instancetype)initWithFrame:(CGRect)frame
-{
- self = [super initWithFrame:frame];
-
- if (self) {
- // View settings
- self.backgroundColor = [UIColor clearColor];
- }
-
- return self;
-}
-
-- (CGSize)sizeThatFits:(CGSize)size
-{
- return CGSizeMake(24.0, 24.0);
-}
-
-- (void)drawRect:(CGRect)rect
-{
- CGContextRef context = UIGraphicsGetCurrentContext();
-
- // Border
- CGContextSetRGBFillColor(context, 1.0, 1.0, 1.0, 1.0);
- CGContextFillEllipseInRect(context, self.bounds);
-
- // Body
- CGContextSetRGBFillColor(context, 20.0/255.0, 111.0/255.0, 223.0/255.0, 1.0);
- CGContextFillEllipseInRect(context, CGRectInset(self.bounds, 1.0, 1.0));
-
- // Checkmark
- CGContextSetRGBStrokeColor(context, 1.0, 1.0, 1.0, 1.0);
- CGContextSetLineWidth(context, 1.2);
-
- CGContextMoveToPoint(context, 6.0, 12.0);
- CGContextAddLineToPoint(context, 10.0, 16.0);
- CGContextAddLineToPoint(context, 18.0, 8.0);
-
- CGContextStrokePath(context);
-}
-
-@end
diff --git a/camerademo/camerademo/demo/QBImagePickerController/QBAssetsCollectionFooterView.h b/camerademo/camerademo/demo/QBImagePickerController/QBAssetsCollectionFooterView.h
deleted file mode 100755
index 630307c..0000000
--- a/camerademo/camerademo/demo/QBImagePickerController/QBAssetsCollectionFooterView.h
+++ /dev/null
@@ -1,15 +0,0 @@
-//
-// QBAssetsCollectionFooterView.h
-// QBImagePickerController
-//
-// Created by Tanaka Katsuma on 2013/12/31.
-// Copyright (c) 2013��� Katsuma Tanaka. All rights reserved.
-//
-
-#import <UIKit/UIKit.h>
-
-@interface QBAssetsCollectionFooterView : UICollectionReusableView
-
-@property (nonatomic, strong, readonly) UILabel *textLabel;
-
-@end
diff --git a/camerademo/camerademo/demo/QBImagePickerController/QBAssetsCollectionFooterView.m b/camerademo/camerademo/demo/QBImagePickerController/QBAssetsCollectionFooterView.m
deleted file mode 100755
index 3d23af8..0000000
--- a/camerademo/camerademo/demo/QBImagePickerController/QBAssetsCollectionFooterView.m
+++ /dev/null
@@ -1,48 +0,0 @@
-//
-// QBAssetsCollectionFooterView.m
-// QBImagePickerController
-//
-// Created by Tanaka Katsuma on 2013/12/31.
-// Copyright (c) 2013��� Katsuma Tanaka. All rights reserved.
-//
-
-#import "QBAssetsCollectionFooterView.h"
-
-@interface QBAssetsCollectionFooterView ()
-
-@property (nonatomic, strong, readwrite) UILabel *textLabel;
-
-@end
-
-@implementation QBAssetsCollectionFooterView
-
-- (instancetype)initWithFrame:(CGRect)frame
-{
- self = [super initWithFrame:frame];
-
- if (self) {
- // Create a label
- UILabel *textLabel = [[UILabel alloc] initWithFrame:CGRectZero];
- textLabel.font = [UIFont systemFontOfSize:17];
- textLabel.textColor = [UIColor blackColor];
- textLabel.textAlignment = NSTextAlignmentCenter;
-
- [self addSubview:textLabel];
- self.textLabel = textLabel;
- }
-
- return self;
-}
-
-- (void)layoutSubviews
-{
- [super layoutSubviews];
-
- // Layout text label
- self.textLabel.frame = CGRectMake(0,
- (self.bounds.size.height - 21.0) / 2.0,
- self.bounds.size.width,
- 21.0);
-}
-
-@end
diff --git a/camerademo/camerademo/demo/QBImagePickerController/QBAssetsCollectionOverlayView.h b/camerademo/camerademo/demo/QBImagePickerController/QBAssetsCollectionOverlayView.h
deleted file mode 100755
index b4b5b39..0000000
--- a/camerademo/camerademo/demo/QBImagePickerController/QBAssetsCollectionOverlayView.h
+++ /dev/null
@@ -1,13 +0,0 @@
-//
-// QBAssetsCollectionOverlayView.h
-// QBImagePickerController
-//
-// Created by Tanaka Katsuma on 2014/01/01.
-// Copyright (c) 2014��� Katsuma Tanaka. All rights reserved.
-//
-
-#import <UIKit/UIKit.h>
-
-@interface QBAssetsCollectionOverlayView : UIView
-
-@end
diff --git a/camerademo/camerademo/demo/QBImagePickerController/QBAssetsCollectionOverlayView.m b/camerademo/camerademo/demo/QBImagePickerController/QBAssetsCollectionOverlayView.m
deleted file mode 100755
index caa7ae6..0000000
--- a/camerademo/camerademo/demo/QBImagePickerController/QBAssetsCollectionOverlayView.m
+++ /dev/null
@@ -1,47 +0,0 @@
-//
-// QBAssetsCollectionOverlayView.m
-// QBImagePickerController
-//
-// Created by Tanaka Katsuma on 2014/01/01.
-// Copyright (c) 2014��� Katsuma Tanaka. All rights reserved.
-//
-
-#import "QBAssetsCollectionOverlayView.h"
-#import <QuartzCore/QuartzCore.h>
-
-// Views
-#import "QBAssetsCollectionCheckmarkView.h"
-
-@interface QBAssetsCollectionOverlayView ()
-
-@property (nonatomic, strong) QBAssetsCollectionCheckmarkView *checkmarkView;
-
-@end
-
-@implementation QBAssetsCollectionOverlayView
-
-- (instancetype)initWithFrame:(CGRect)frame
-{
- self = [super initWithFrame:frame];
-
- if (self) {
- // View settings
- self.backgroundColor = [UIColor colorWithWhite:1.0 alpha:0.4];
-
- // Create a checkmark view
- QBAssetsCollectionCheckmarkView *checkmarkView = [[QBAssetsCollectionCheckmarkView alloc] initWithFrame:CGRectMake(self.bounds.size.width - (4.0 + 24.0), self.bounds.size.height - (4.0 + 24.0), 24.0, 24.0)];
- checkmarkView.autoresizingMask = UIViewAutoresizingNone;
-
- checkmarkView.layer.shadowColor = [[UIColor grayColor] CGColor];
- checkmarkView.layer.shadowOffset = CGSizeMake(0, 0);
- checkmarkView.layer.shadowOpacity = 0.6;
- checkmarkView.layer.shadowRadius = 2.0;
-
- [self addSubview:checkmarkView];
- self.checkmarkView = checkmarkView;
- }
-
- return self;
-}
-
-@end
diff --git a/camerademo/camerademo/demo/QBImagePickerController/QBAssetsCollectionVideoIndicatorView.h b/camerademo/camerademo/demo/QBImagePickerController/QBAssetsCollectionVideoIndicatorView.h
deleted file mode 100755
index 58a78dc..0000000
--- a/camerademo/camerademo/demo/QBImagePickerController/QBAssetsCollectionVideoIndicatorView.h
+++ /dev/null
@@ -1,15 +0,0 @@
-//
-// QBAssetsCollectionVideoIndicatorView.h
-// QBImagePickerControllerDemo
-//
-// Created by Katsuma Tanaka on 2014/08/07.
-// Copyright (c) 2014��� Katsuma Tanaka. All rights reserved.
-//
-
-#import <UIKit/UIKit.h>
-
-@interface QBAssetsCollectionVideoIndicatorView : UIView
-
-@property (nonatomic, assign) NSTimeInterval duration;
-
-@end
diff --git a/camerademo/camerademo/demo/QBImagePickerController/QBAssetsCollectionVideoIndicatorView.m b/camerademo/camerademo/demo/QBImagePickerController/QBAssetsCollectionVideoIndicatorView.m
deleted file mode 100755
index 4aba36c..0000000
--- a/camerademo/camerademo/demo/QBImagePickerController/QBAssetsCollectionVideoIndicatorView.m
+++ /dev/null
@@ -1,107 +0,0 @@
-//
-// QBAssetsCollectionVideoIndicatorView.m
-// QBImagePickerControllerDemo
-//
-// Created by Katsuma Tanaka on 2014/08/07.
-// Copyright (c) 2014��� Katsuma Tanaka. All rights reserved.
-//
-
-#import "QBAssetsCollectionVideoIndicatorView.h"
-#import <QuartzCore/QuartzCore.h>
-
-@implementation QBAssetsCollectionVideoIndicatorView
-
-- (instancetype)initWithFrame:(CGRect)frame
-{
- self = [super initWithFrame:frame];
-
- if (self) {
- self.backgroundColor = [UIColor clearColor];
- self.clipsToBounds = YES;
- }
-
- return self;
-}
-
-
-#pragma mark - Accessors
-
-- (void)setDuration:(NSTimeInterval)duration
-{
- _duration = duration;
-
- [self setNeedsDisplay];
-}
-
-
-#pragma mark - Drawing the View
-
-- (void)drawRect:(CGRect)rect
-{
- // Draw linear gradient
- CGContextRef context = UIGraphicsGetCurrentContext();
-
- CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
- CGFloat colors[12] = {
- 0.0, 0.0, 0.0, 0.9,
- 0.0, 0.0, 0.0, 0.45,
- 0.0, 0.0, 0.0, 0.0
- };
- const CGFloat locations[] = { 0.0, 0.55, 1.0 };
- CGGradientRef gradient = CGGradientCreateWithColorComponents(colorSpace, colors, locations, 3);
- CGColorSpaceRelease(colorSpace);
-
- CGPoint startPoint = CGPointMake(0, CGRectGetHeight(self.bounds));
- CGPoint endPoint = CGPointMake(0, 0);
- CGContextDrawLinearGradient(context, gradient, startPoint, endPoint, kCGGradientDrawsBeforeStartLocation);
-
- CGGradientRelease(gradient);
-
- // Draw camera icon
- CGSize cameraIconSize = CGSizeMake(14.0, 8.0);
- CGRect cameraIconRect = CGRectMake(5.0, (CGRectGetHeight(self.bounds) - cameraIconSize.height) / 2.0, cameraIconSize.width, cameraIconSize.height);
- [self drawCameraIconInRect:cameraIconRect];
-
- // Draw duration
- NSInteger minutes = (NSInteger)(self.duration / 60.0);
- NSInteger seconds = (NSInteger)ceil(self.duration - 60.0 * (double)minutes);
- NSString *durationString = [NSString stringWithFormat:@"%02ld:%02ld", (long)minutes, (long)seconds];
-
- NSMutableParagraphStyle *paragraphStyle = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
- paragraphStyle.alignment = NSTextAlignmentRight;
-
- UIFont *durationFont = [UIFont systemFontOfSize:12.0];
-
- CGRect durationRect = CGRectMake(CGRectGetMaxX(cameraIconRect), 0, CGRectGetWidth(self.bounds) - CGRectGetMaxX(cameraIconRect), CGRectGetHeight(self.bounds));
- durationRect = CGRectInset(durationRect, 5.0, (CGRectGetHeight(self.bounds) - durationFont.lineHeight) / 2.0);
-
- [durationString drawInRect:durationRect
- withAttributes:@{
- NSParagraphStyleAttributeName: [paragraphStyle copy],
- NSFontAttributeName: durationFont,
- NSForegroundColorAttributeName: [UIColor whiteColor]
- }];
-}
-
-- (void)drawCameraIconInRect:(CGRect)rect
-{
- [[UIColor whiteColor] setFill];
-
- // Draw triangle
- CGRect triangleRect = CGRectMake(0, CGRectGetMinY(rect), ceil(CGRectGetHeight(rect) / 2.0), CGRectGetHeight(rect));
- triangleRect.origin.x = CGRectGetMinX(rect) + CGRectGetWidth(rect) - CGRectGetWidth(triangleRect);
-
- UIBezierPath *trianglePath = [UIBezierPath bezierPath];
- [trianglePath moveToPoint:CGPointMake(CGRectGetMinX(triangleRect) + CGRectGetWidth(triangleRect), CGRectGetMinY(triangleRect))];
- [trianglePath addLineToPoint:CGPointMake(CGRectGetMinX(triangleRect) + CGRectGetWidth(triangleRect), CGRectGetMaxY(triangleRect))];
- [trianglePath addLineToPoint:CGPointMake(CGRectGetMinX(triangleRect), CGRectGetMidY(triangleRect))];
- [trianglePath closePath];
- [trianglePath fill];
-
- // Draw rounded square
- CGRect squareRect = CGRectMake(CGRectGetMinX(rect), CGRectGetMinY(rect), CGRectGetWidth(rect) - CGRectGetWidth(triangleRect) - 1.0, CGRectGetHeight(rect));
- UIBezierPath *squarePath = [UIBezierPath bezierPathWithRoundedRect:squareRect cornerRadius:2.0];
- [squarePath fill];
-}
-
-@end
diff --git a/camerademo/camerademo/demo/QBImagePickerController/QBAssetsCollectionViewCell.h b/camerademo/camerademo/demo/QBImagePickerController/QBAssetsCollectionViewCell.h
deleted file mode 100755
index caba987..0000000
--- a/camerademo/camerademo/demo/QBImagePickerController/QBAssetsCollectionViewCell.h
+++ /dev/null
@@ -1,17 +0,0 @@
-//
-// QBAssetsCollectionViewCell.h
-// QBImagePickerController
-//
-// Created by Tanaka Katsuma on 2013/12/31.
-// Copyright (c) 2013��� Katsuma Tanaka. All rights reserved.
-//
-
-#import <UIKit/UIKit.h>
-#import <AssetsLibrary/AssetsLibrary.h>
-
-@interface QBAssetsCollectionViewCell : UICollectionViewCell
-
-@property (nonatomic, strong) ALAsset *asset;
-@property (nonatomic, assign) BOOL showsOverlayViewWhenSelected;
-
-@end
diff --git a/camerademo/camerademo/demo/QBImagePickerController/QBAssetsCollectionViewCell.m b/camerademo/camerademo/demo/QBImagePickerController/QBAssetsCollectionViewCell.m
deleted file mode 100755
index 502dc93..0000000
--- a/camerademo/camerademo/demo/QBImagePickerController/QBAssetsCollectionViewCell.m
+++ /dev/null
@@ -1,143 +0,0 @@
-//
-// QBAssetsCollectionViewCell.m
-// QBImagePickerController
-//
-// Created by Tanaka Katsuma on 2013/12/31.
-// Copyright (c) 2013��� Katsuma Tanaka. All rights reserved.
-//
-
-#import "QBAssetsCollectionViewCell.h"
-
-// Views
-#import "QBAssetsCollectionOverlayView.h"
-#import "QBAssetsCollectionVideoIndicatorView.h"
-
-@interface QBAssetsCollectionViewCell ()
-
-@property (nonatomic, strong) UIImageView *imageView;
-@property (nonatomic, strong) QBAssetsCollectionOverlayView *overlayView;
-@property (nonatomic, strong) QBAssetsCollectionVideoIndicatorView *videoIndicatorView;
-
-@property (nonatomic, strong) UIImage *blankImage;
-
-@end
-
-@implementation QBAssetsCollectionViewCell
-
-- (instancetype)initWithFrame:(CGRect)frame
-{
- self = [super initWithFrame:frame];
-
- if (self) {
- self.showsOverlayViewWhenSelected = YES;
-
- // Create a image view
- UIImageView *imageView = [[UIImageView alloc] initWithFrame:self.contentView.bounds];
- imageView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
-
- [self.contentView addSubview:imageView];
- self.imageView = imageView;
- }
-
- return self;
-}
-
-- (void)setSelected:(BOOL)selected
-{
- [super setSelected:selected];
-
- // Show/hide overlay view
- if (selected && self.showsOverlayViewWhenSelected) {
- [self showOverlayView];
- } else {
- [self hideOverlayView];
- }
-}
-
-
-#pragma mark - Overlay View
-
-- (void)showOverlayView
-{
- [self hideOverlayView];
-
- QBAssetsCollectionOverlayView *overlayView = [[QBAssetsCollectionOverlayView alloc] initWithFrame:self.contentView.bounds];
- overlayView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
-
- [self.contentView addSubview:overlayView];
- self.overlayView = overlayView;
-}
-
-- (void)hideOverlayView
-{
- if (self.overlayView) {
- [self.overlayView removeFromSuperview];
- self.overlayView = nil;
- }
-}
-
-
-#pragma mark - Video Indicator View
-
-- (void)showVideoIndicatorView
-{
- CGFloat height = 19.0;
- CGRect frame = CGRectMake(0, CGRectGetHeight(self.bounds) - height, CGRectGetWidth(self.bounds), height);
- QBAssetsCollectionVideoIndicatorView *videoIndicatorView = [[QBAssetsCollectionVideoIndicatorView alloc] initWithFrame:frame];
- videoIndicatorView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
- videoIndicatorView.duration = [[self.asset valueForProperty:ALAssetPropertyDuration] doubleValue];
-
- [self.contentView addSubview:videoIndicatorView];
- self.videoIndicatorView = videoIndicatorView;
-}
-
-- (void)hideVideoIndicatorView
-{
- if (self.videoIndicatorView) {
- [self.videoIndicatorView removeFromSuperview];
- self.videoIndicatorView = nil;
- }
-}
-
-
-#pragma mark - Accessors
-
-- (void)setAsset:(ALAsset *)asset
-{
- _asset = asset;
-
- // Update view
- CGImageRef thumbnailImageRef = [asset thumbnail];
-
- if (thumbnailImageRef) {
- self.imageView.image = [UIImage imageWithCGImage:thumbnailImageRef];
- } else {
- self.imageView.image = [self blankImage];
- }
-
- // Show video indicator if the asset is video
- if ([[asset valueForProperty:ALAssetPropertyType] isEqualToString:ALAssetTypeVideo]) {
- [self showVideoIndicatorView];
- } else {
- [self hideVideoIndicatorView];
- }
-}
-
-- (UIImage *)blankImage
-{
- if (_blankImage == nil) {
- CGSize size = CGSizeMake(100.0, 100.0);
- UIGraphicsBeginImageContextWithOptions(size, NO, 0.0);
-
- [[UIColor colorWithWhite:(240.0 / 255.0) alpha:1.0] setFill];
- UIRectFill(CGRectMake(0, 0, size.width, size.height));
-
- _blankImage = UIGraphicsGetImageFromCurrentImageContext();
-
- UIGraphicsEndImageContext();
- }
-
- return _blankImage;
-}
-
-@end
diff --git a/camerademo/camerademo/demo/QBImagePickerController/QBAssetsCollectionViewController.h b/camerademo/camerademo/demo/QBImagePickerController/QBAssetsCollectionViewController.h
deleted file mode 100755
index 036e7f6..0000000
--- a/camerademo/camerademo/demo/QBImagePickerController/QBAssetsCollectionViewController.h
+++ /dev/null
@@ -1,39 +0,0 @@
-//
-// QBAssetsCollectionViewController.h
-// QBImagePickerController
-//
-// Created by Tanaka Katsuma on 2013/12/31.
-// Copyright (c) 2013��� Katsuma Tanaka. All rights reserved.
-//
-
-#import <UIKit/UIKit.h>
-#import <AssetsLibrary/AssetsLibrary.h>
-
-// ViewControllers
-#import "QBImagePickerController.h"
-
-@class QBAssetsCollectionViewController;
-
-@protocol QBAssetsCollectionViewControllerDelegate <NSObject>
-
-@optional
-- (void)assetsCollectionViewController:(QBAssetsCollectionViewController *)assetsCollectionViewController didSelectAsset:(ALAsset *)asset;
-- (void)assetsCollectionViewController:(QBAssetsCollectionViewController *)assetsCollectionViewController didDeselectAsset:(ALAsset *)asset;
-- (void)assetsCollectionViewControllerDidFinishSelection:(QBAssetsCollectionViewController *)assetsCollectionViewController;
-
-@end
-
-@interface QBAssetsCollectionViewController : UICollectionViewController <UICollectionViewDelegateFlowLayout>
-
-@property (nonatomic, weak) QBImagePickerController *imagePickerController;
-
-@property (nonatomic, weak) id<QBAssetsCollectionViewControllerDelegate> delegate;
-@property (nonatomic, strong) ALAssetsGroup *assetsGroup;
-@property (nonatomic, assign) QBImagePickerControllerFilterType filterType;
-@property (nonatomic, assign) BOOL allowsMultipleSelection;
-@property (nonatomic, assign) NSUInteger minimumNumberOfSelection;
-@property (nonatomic, assign) NSUInteger maximumNumberOfSelection;
-
-- (void)selectAssetHavingURL:(NSURL *)URL;
-
-@end
diff --git a/camerademo/camerademo/demo/QBImagePickerController/QBAssetsCollectionViewController.m b/camerademo/camerademo/demo/QBImagePickerController/QBAssetsCollectionViewController.m
deleted file mode 100755
index b3fc9c3..0000000
--- a/camerademo/camerademo/demo/QBImagePickerController/QBAssetsCollectionViewController.m
+++ /dev/null
@@ -1,344 +0,0 @@
-//
-// QBAssetsCollectionViewController.m
-// QBImagePickerController
-//
-// Created by Tanaka Katsuma on 2013/12/31.
-// Copyright (c) 2013��� Katsuma Tanaka. All rights reserved.
-//
-
-#import "QBAssetsCollectionViewController.h"
-
-// Views
-#import "QBAssetsCollectionViewCell.h"
-#import "QBAssetsCollectionFooterView.h"
-
-@interface QBAssetsCollectionViewController ()
-
-@property (nonatomic, strong) NSMutableArray *assets;
-
-@property (nonatomic, assign) NSUInteger numberOfAssets;
-@property (nonatomic, assign) NSUInteger numberOfPhotos;
-@property (nonatomic, assign) NSUInteger numberOfVideos;
-
-@property (nonatomic, assign) BOOL disableScrollToBottom;
-
-@end
-
-@implementation QBAssetsCollectionViewController
-
-- (instancetype)initWithCollectionViewLayout:(UICollectionViewLayout *)layout
-{
- self = [super initWithCollectionViewLayout:layout];
-
- if (self) {
- // View settings
- self.collectionView.backgroundColor = [UIColor whiteColor];
-
- // Register cell class
- [self.collectionView registerClass:[QBAssetsCollectionViewCell class]
- forCellWithReuseIdentifier:@"AssetsCell"];
- [self.collectionView registerClass:[QBAssetsCollectionFooterView class]
- forSupplementaryViewOfKind:UICollectionElementKindSectionFooter
- withReuseIdentifier:@"FooterView"];
- }
-
- return self;
-}
-
-- (void)viewWillAppear:(BOOL)animated
-{
- [super viewWillAppear:animated];
-
- // Scroll to bottom
- if (self.isMovingToParentViewController && !self.disableScrollToBottom) {
- CGFloat topInset;
- if ([self respondsToSelector:@selector(setEdgesForExtendedLayout:)]) { // iOS7 or later
- topInset = ((self.edgesForExtendedLayout && UIRectEdgeTop) && (self.collectionView.contentInset.top == 0)) ? (20.0 + 44.0) : 0.0;
- } else {
- topInset = (self.collectionView.contentInset.top == 0) ? (20.0 + 44.0) : 0.0;
- }
-
- [self.collectionView setContentOffset:CGPointMake(0, self.collectionView.collectionViewLayout.collectionViewContentSize.height - self.collectionView.frame.size.height + topInset)
- animated:NO];
- }
-
- // Validation
- if (self.allowsMultipleSelection) {
- self.navigationItem.rightBarButtonItem.enabled = [self validateNumberOfSelections:self.imagePickerController.selectedAssetURLs.count];
- }
-}
-
-- (void)viewWillDisappear:(BOOL)animated
-{
- [super viewWillDisappear:animated];
-
- self.disableScrollToBottom = YES;
-}
-
-- (void)viewDidDisappear:(BOOL)animated
-{
- [super viewDidDisappear:animated];
-
- self.disableScrollToBottom = NO;
-}
-
-
-#pragma mark - Accessors
-
-- (void)setFilterType:(QBImagePickerControllerFilterType)filterType
-{
- _filterType = filterType;
-
- // Set assets filter
- [self.assetsGroup setAssetsFilter:ALAssetsFilterFromQBImagePickerControllerFilterType(self.filterType)];
-}
-
-- (void)setAssetsGroup:(ALAssetsGroup *)assetsGroup
-{
- _assetsGroup = assetsGroup;
-
- // Set title
- self.title = [self.assetsGroup valueForProperty:ALAssetsGroupPropertyName];
-
- // Set assets filter
- [self.assetsGroup setAssetsFilter:ALAssetsFilterFromQBImagePickerControllerFilterType(self.filterType)];
-
- // Load assets
- NSMutableArray *assets = [NSMutableArray array];
- __block NSUInteger numberOfAssets = 0;
- __block NSUInteger numberOfPhotos = 0;
- __block NSUInteger numberOfVideos = 0;
-
- [self.assetsGroup enumerateAssetsUsingBlock:^(ALAsset *result, NSUInteger index, BOOL *stop) {
- if (result) {
- numberOfAssets++;
-
- NSString *type = [result valueForProperty:ALAssetPropertyType];
- if ([type isEqualToString:ALAssetTypePhoto]) numberOfPhotos++;
- else if ([type isEqualToString:ALAssetTypeVideo]) numberOfVideos++;
-
- [assets addObject:result];
- }
- }];
-
- self.assets = assets;
- self.numberOfAssets = numberOfAssets;
- self.numberOfPhotos = numberOfPhotos;
- self.numberOfVideos = numberOfVideos;
-
- // Update view
- [self.collectionView reloadData];
-}
-
-- (void)setAllowsMultipleSelection:(BOOL)allowsMultipleSelection
-{
- self.collectionView.allowsMultipleSelection = allowsMultipleSelection;
-
- // Show/hide done button
- if (allowsMultipleSelection) {
- UIBarButtonItem *doneButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(done:)];
- [self.navigationItem setRightBarButtonItem:doneButton animated:NO];
- } else {
- [self.navigationItem setRightBarButtonItem:nil animated:NO];
- }
-}
-
-- (BOOL)allowsMultipleSelection
-{
- return self.collectionView.allowsMultipleSelection;
-}
-
-
-#pragma mark - Actions
-
-- (void)done:(id)sender
-{
- // Delegate
- if (self.delegate && [self.delegate respondsToSelector:@selector(assetsCollectionViewControllerDidFinishSelection:)]) {
- [self.delegate assetsCollectionViewControllerDidFinishSelection:self];
- }
-}
-
-
-#pragma mark - Managing Selection
-
-- (void)selectAssetHavingURL:(NSURL *)URL
-{
- for (NSInteger i = 0; i < self.assets.count; i++) {
- ALAsset *asset = self.assets[i];
- NSURL *assetURL = [asset valueForProperty:ALAssetPropertyAssetURL];
-
- if ([assetURL isEqual:URL]) {
- NSIndexPath *indexPath = [NSIndexPath indexPathForRow:i inSection:0];
- [self.collectionView selectItemAtIndexPath:indexPath animated:NO scrollPosition:UICollectionViewScrollPositionNone];
-
- return;
- }
- }
-}
-
-
-#pragma mark - Validating Selections
-
-- (BOOL)validateNumberOfSelections:(NSUInteger)numberOfSelections
-{
- NSUInteger minimumNumberOfSelection = MAX(1, self.minimumNumberOfSelection);
- BOOL qualifiesMinimumNumberOfSelection = (numberOfSelections >= minimumNumberOfSelection);
-
- BOOL qualifiesMaximumNumberOfSelection = YES;
- if (minimumNumberOfSelection <= self.maximumNumberOfSelection) {
- qualifiesMaximumNumberOfSelection = (numberOfSelections <= self.maximumNumberOfSelection);
- }
-
- return (qualifiesMinimumNumberOfSelection && qualifiesMaximumNumberOfSelection);
-}
-
-- (BOOL)validateMaximumNumberOfSelections:(NSUInteger)numberOfSelections
-{
- NSUInteger minimumNumberOfSelection = MAX(1, self.minimumNumberOfSelection);
-
- if (minimumNumberOfSelection <= self.maximumNumberOfSelection) {
- if (numberOfSelections > self.maximumNumberOfSelection) {
- [MBProgressHUD showAutoMessage:[NSString stringWithFormat:@"������������������%lu���������", (unsigned long)self.maximumNumberOfSelection]];
- }
- return (numberOfSelections <= self.maximumNumberOfSelection);
- }
-
- return YES;
-}
-
-
-#pragma mark - UICollectionViewDataSource
-
-- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
-{
- return 1;
-}
-
-- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
-{
- return self.numberOfAssets;
-}
-
-- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
-{
- QBAssetsCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"AssetsCell" forIndexPath:indexPath];
- cell.showsOverlayViewWhenSelected = self.allowsMultipleSelection;
-
- ALAsset *asset = self.assets[indexPath.row];
- cell.asset = asset;
-
- return cell;
-}
-
-- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout referenceSizeForFooterInSection:(NSInteger)section
-{
- return CGSizeMake(collectionView.bounds.size.width, 46.0);
-}
-
-- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath
-{
- if (kind == UICollectionElementKindSectionFooter) {
- QBAssetsCollectionFooterView *footerView = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionFooter
- withReuseIdentifier:@"FooterView"
- forIndexPath:indexPath];
-
- switch (self.filterType) {
- case QBImagePickerControllerFilterTypeNone:{
- NSString *format;
- if (self.numberOfPhotos == 1) {
- if (self.numberOfVideos == 1) {
- format = @"format_photo_and_video";
- } else {
- format = @"format_photo_and_videos";
- }
- } else if (self.numberOfVideos == 1) {
- format = @"format_photos_and_video";
- } else {
- format = @"format_photos_and_videos";
- }
- footerView.textLabel.text = [NSString stringWithFormat:NSLocalizedStringFromTable(format,
- @"QBImagePickerController",
- nil),
- self.numberOfPhotos,
- self.numberOfVideos
- ];
- break;
- }
-
- case QBImagePickerControllerFilterTypePhotos:{
- NSString *format = (self.numberOfPhotos == 1) ? @"format_photo" : @"format_photos";
- footerView.textLabel.text = [NSString stringWithFormat:NSLocalizedStringFromTable(format,
- @"QBImagePickerController",
- nil),
- self.numberOfPhotos
- ];
- break;
- }
-
- case QBImagePickerControllerFilterTypeVideos:{
- NSString *format = (self.numberOfVideos == 1) ? @"format_video" : @"format_videos";
- footerView.textLabel.text = [NSString stringWithFormat:NSLocalizedStringFromTable(format,
- @"QBImagePickerController",
- nil),
- self.numberOfVideos
- ];
- break;
- }
- }
-
- return footerView;
- }
-
- return nil;
-}
-
-
-#pragma mark - UICollectionViewDelegateFlowLayout
-
-- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
-{
- return CGSizeMake(77.5, 77.5);
-}
-
-- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section
-{
- return UIEdgeInsetsMake(2, 2, 2, 2);
-}
-
-- (BOOL)collectionView:(UICollectionView *)collectionView shouldSelectItemAtIndexPath:(NSIndexPath *)indexPath
-{
- return [self validateMaximumNumberOfSelections:(self.imagePickerController.selectedAssetURLs.count + 1)];
-}
-
-- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
-{
- ALAsset *asset = self.assets[indexPath.row];
-
- // Validation
- if (self.allowsMultipleSelection) {
- self.navigationItem.rightBarButtonItem.enabled = [self validateNumberOfSelections:(self.imagePickerController.selectedAssetURLs.count + 1)];
- }
-
- // Delegate
- if (self.delegate && [self.delegate respondsToSelector:@selector(assetsCollectionViewController:didSelectAsset:)]) {
- [self.delegate assetsCollectionViewController:self didSelectAsset:asset];
- }
-}
-
-- (void)collectionView:(UICollectionView *)collectionView didDeselectItemAtIndexPath:(NSIndexPath *)indexPath
-{
- ALAsset *asset = self.assets[indexPath.row];
-
- // Validation
- if (self.allowsMultipleSelection) {
- self.navigationItem.rightBarButtonItem.enabled = [self validateNumberOfSelections:(self.imagePickerController.selectedAssetURLs.count - 1)];
- }
-
- // Delegate
- if (self.delegate && [self.delegate respondsToSelector:@selector(assetsCollectionViewController:didDeselectAsset:)]) {
- [self.delegate assetsCollectionViewController:self didDeselectAsset:asset];
- }
-}
-
-@end
diff --git a/camerademo/camerademo/demo/QBImagePickerController/QBAssetsCollectionViewLayout.h b/camerademo/camerademo/demo/QBImagePickerController/QBAssetsCollectionViewLayout.h
deleted file mode 100755
index f75811e..0000000
--- a/camerademo/camerademo/demo/QBImagePickerController/QBAssetsCollectionViewLayout.h
+++ /dev/null
@@ -1,15 +0,0 @@
-//
-// QBAssetsCollectionViewLayout.h
-// QBImagePickerController
-//
-// Created by Tanaka Katsuma on 2013/12/31.
-// Copyright (c) 2013��� Katsuma Tanaka. All rights reserved.
-//
-
-#import <UIKit/UIKit.h>
-
-@interface QBAssetsCollectionViewLayout : UICollectionViewFlowLayout
-
-+ (instancetype)layout;
-
-@end
diff --git a/camerademo/camerademo/demo/QBImagePickerController/QBAssetsCollectionViewLayout.m b/camerademo/camerademo/demo/QBImagePickerController/QBAssetsCollectionViewLayout.m
deleted file mode 100755
index 4d6f452..0000000
--- a/camerademo/camerademo/demo/QBImagePickerController/QBAssetsCollectionViewLayout.m
+++ /dev/null
@@ -1,30 +0,0 @@
-//
-// QBAssetsCollectionViewLayout.m
-// QBImagePickerController
-//
-// Created by Tanaka Katsuma on 2013/12/31.
-// Copyright (c) 2013��� Katsuma Tanaka. All rights reserved.
-//
-
-#import "QBAssetsCollectionViewLayout.h"
-
-@implementation QBAssetsCollectionViewLayout
-
-+ (instancetype)layout
-{
- return [[self alloc] init];
-}
-
-- (instancetype)init
-{
- self = [super init];
-
- if (self) {
- self.minimumLineSpacing = 2.0;
- self.minimumInteritemSpacing = 2.0;
- }
-
- return self;
-}
-
-@end
diff --git a/camerademo/camerademo/demo/QBImagePickerController/QBImagePickerController.h b/camerademo/camerademo/demo/QBImagePickerController/QBImagePickerController.h
deleted file mode 100755
index 006bf6f..0000000
--- a/camerademo/camerademo/demo/QBImagePickerController/QBImagePickerController.h
+++ /dev/null
@@ -1,47 +0,0 @@
-//
-// QBImagePickerController.h
-// QBImagePickerController
-//
-// Created by Tanaka Katsuma on 2013/12/30.
-// Copyright (c) 2013��� Katsuma Tanaka. All rights reserved.
-//
-
-#import <UIKit/UIKit.h>
-#import <AssetsLibrary/AssetsLibrary.h>
-
-typedef NS_ENUM(NSUInteger, QBImagePickerControllerFilterType) {
- QBImagePickerControllerFilterTypeNone,
- QBImagePickerControllerFilterTypePhotos,
- QBImagePickerControllerFilterTypeVideos
-};
-
-UIKIT_EXTERN ALAssetsFilter * ALAssetsFilterFromQBImagePickerControllerFilterType(QBImagePickerControllerFilterType type);
-
-@class QBImagePickerController;
-
-@protocol QBImagePickerControllerDelegate <NSObject>
-
-@optional
-- (void)qb_imagePickerController:(QBImagePickerController *)imagePickerController didSelectAsset:(ALAsset *)asset;
-- (void)qb_imagePickerController:(QBImagePickerController *)imagePickerController didSelectAssets:(NSArray *)assets;
-- (void)qb_imagePickerControllerDidCancel:(QBImagePickerController *)imagePickerController;
-
-@end
-
-@interface QBImagePickerController : UITableViewController
-
-@property (nonatomic, strong, readonly) ALAssetsLibrary *assetsLibrary;
-@property (nonatomic, copy, readonly) NSArray *assetsGroups;
-@property (nonatomic, strong, readonly) NSMutableOrderedSet *selectedAssetURLs;
-
-@property (nonatomic, weak) id<QBImagePickerControllerDelegate> delegate;
-@property (nonatomic, copy) NSArray *groupTypes;
-@property (nonatomic, assign) QBImagePickerControllerFilterType filterType;
-@property (nonatomic, assign) BOOL showsCancelButton;
-@property (nonatomic, assign) BOOL allowsMultipleSelection;
-@property (nonatomic, assign) NSUInteger minimumNumberOfSelection;
-@property (nonatomic, assign) NSUInteger maximumNumberOfSelection;
-
-+ (BOOL)isAccessible;
-
-@end
diff --git a/camerademo/camerademo/demo/QBImagePickerController/QBImagePickerController.m b/camerademo/camerademo/demo/QBImagePickerController/QBImagePickerController.m
deleted file mode 100755
index 11ec6eb..0000000
--- a/camerademo/camerademo/demo/QBImagePickerController/QBImagePickerController.m
+++ /dev/null
@@ -1,405 +0,0 @@
-//
-// QBImagePickerController.m
-// QBImagePickerController
-//
-// Created by Tanaka Katsuma on 2013/12/30.
-// Copyright (c) 2013��� Katsuma Tanaka. All rights reserved.
-//
-
-#import "QBImagePickerController.h"
-#import <AssetsLibrary/AssetsLibrary.h>
-
-// Views
-#import "QBImagePickerGroupCell.h"
-#import "QBAssetsCollectionViewLayout.h"
-
-// ViewControllers
-#import "QBAssetsCollectionViewController.h"
-
-ALAssetsFilter * ALAssetsFilterFromQBImagePickerControllerFilterType(QBImagePickerControllerFilterType type) {
- switch (type) {
- case QBImagePickerControllerFilterTypeNone:
- return [ALAssetsFilter allAssets];
- break;
-
- case QBImagePickerControllerFilterTypePhotos:
- return [ALAssetsFilter allPhotos];
- break;
-
- case QBImagePickerControllerFilterTypeVideos:
- return [ALAssetsFilter allVideos];
- break;
- }
-}
-
-@interface QBImagePickerController () <QBAssetsCollectionViewControllerDelegate>
-
-@property (nonatomic, strong, readwrite) ALAssetsLibrary *assetsLibrary;
-@property (nonatomic, copy, readwrite) NSArray *assetsGroups;
-@property (nonatomic, strong, readwrite) NSMutableOrderedSet *selectedAssetURLs;
-@property (nonatomic, assign) BOOL firstShow;
-
-@end
-
-@implementation QBImagePickerController
-
-+ (BOOL)isAccessible
-{
- return ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypePhotoLibrary] &&
- [UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeSavedPhotosAlbum]);
-}
-
-- (instancetype)initWithStyle:(UITableViewStyle)style
-{
- self = [super initWithStyle:UITableViewStylePlain];
-
- if (self) {
- [self setUpProperties];
- }
-
- return self;
-}
-
-- (void)awakeFromNib
-{
- [super awakeFromNib];
-
- [self setUpProperties];
-}
-
-- (void)setUpProperties
-{
- // Property settings
- self.selectedAssetURLs = [NSMutableOrderedSet orderedSet];
-
- self.groupTypes = @[
- @(ALAssetsGroupSavedPhotos),
- @(ALAssetsGroupPhotoStream),
- @(ALAssetsGroupAlbum)
- ];
- self.filterType = QBImagePickerControllerFilterTypeNone;
- self.showsCancelButton = YES;
-
- // View settings
- self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
-
- // Create assets library instance
- ALAssetsLibrary *assetsLibrary = [[ALAssetsLibrary alloc] init];
- self.assetsLibrary = assetsLibrary;
-
- // Register cell classes
- [self.tableView registerClass:[QBImagePickerGroupCell class] forCellReuseIdentifier:@"GroupCell"];
-}
-
-- (void)viewDidLoad
-{
- [super viewDidLoad];
-
- // View controller settings
- self.title = NSLocalizedStringFromTable(@"title", @"QBImagePickerController", nil);
- self.firstShow = YES;
-}
-
-- (void)viewWillAppear:(BOOL)animated
-{
- [super viewWillAppear:animated];
-
- // Load assets groups
- [self loadAssetsGroupsWithTypes:self.groupTypes
- completion:^(NSArray *assetsGroups) {
- self.assetsGroups = assetsGroups;
- [self.tableView reloadData];
- if (self.firstShow) {
- self.firstShow = NO;
-// [self pushToCollectionVCWithIndex:0];
- }
- }];
-
- // Validation
- self.navigationItem.rightBarButtonItem.enabled = [self validateNumberOfSelections:self.selectedAssetURLs.count];
-}
-
-
-#pragma mark - Accessors
-
-- (void)setShowsCancelButton:(BOOL)showsCancelButton
-{
- _showsCancelButton = showsCancelButton;
-
- // Show/hide cancel button
- if (showsCancelButton) {
- UIBarButtonItem *cancelButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:@selector(cancel:)];
- [self.navigationItem setLeftBarButtonItem:cancelButton animated:NO];
- } else {
- [self.navigationItem setLeftBarButtonItem:nil animated:NO];
- }
-}
-
-- (void)setAllowsMultipleSelection:(BOOL)allowsMultipleSelection
-{
- _allowsMultipleSelection = allowsMultipleSelection;
-
- // Show/hide done button
- if (allowsMultipleSelection) {
- UIBarButtonItem *doneButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(done:)];
- [self.navigationItem setRightBarButtonItem:doneButton animated:NO];
- } else {
- [self.navigationItem setRightBarButtonItem:nil animated:NO];
- }
-}
-
-
-#pragma mark - Actions
-
-- (void)done:(id)sender
-{
- [self passSelectedAssetsToDelegate];
-}
-
-- (void)cancel:(id)sender
-{
- // Delegate
- if (self.delegate && [self.delegate respondsToSelector:@selector(qb_imagePickerControllerDidCancel:)]) {
- [self.delegate qb_imagePickerControllerDidCancel:self];
- }
-}
-
-
-#pragma mark - Validating Selections
-
-- (BOOL)validateNumberOfSelections:(NSUInteger)numberOfSelections
-{
- // Check the number of selected assets
- NSUInteger minimumNumberOfSelection = MAX(1, self.minimumNumberOfSelection);
- BOOL qualifiesMinimumNumberOfSelection = (numberOfSelections >= minimumNumberOfSelection);
-
- BOOL qualifiesMaximumNumberOfSelection = YES;
- if (minimumNumberOfSelection <= self.maximumNumberOfSelection) {
- qualifiesMaximumNumberOfSelection = (numberOfSelections <= self.maximumNumberOfSelection);
- }
-
- return (qualifiesMinimumNumberOfSelection && qualifiesMaximumNumberOfSelection);
-}
-
-
-#pragma mark - Managing Assets
-
-- (void)loadAssetsGroupsWithTypes:(NSArray *)types completion:(void (^)(NSArray *assetsGroups))completion
-{
- __block NSMutableArray *assetsGroups = [NSMutableArray array];
- __block NSUInteger numberOfFinishedTypes = 0;
-
- for (NSNumber *type in types) {
- __weak typeof(self) weakSelf = self;
-
- [self.assetsLibrary enumerateGroupsWithTypes:[type unsignedIntegerValue]
- usingBlock:^(ALAssetsGroup *assetsGroup, BOOL *stop) {
- if (assetsGroup) {
- // Filter the assets group
- [assetsGroup setAssetsFilter:ALAssetsFilterFromQBImagePickerControllerFilterType(weakSelf.filterType)];
-
- if (assetsGroup.numberOfAssets > 0) {
- // Add assets group
- [assetsGroups addObject:assetsGroup];
- }
- } else {
- numberOfFinishedTypes++;
- }
-
- // Check if the loading finished
- if (numberOfFinishedTypes == types.count) {
- // Sort assets groups
- NSArray *sortedAssetsGroups = [self sortAssetsGroups:(NSArray *)assetsGroups typesOrder:types];
-
- // Call completion block
- if (completion) {
- completion(sortedAssetsGroups);
- }
- }
- } failureBlock:^(NSError *error) {
- NSLog(@"Error: %@", [error localizedDescription]);
- }];
- }
-}
-
-- (NSArray *)sortAssetsGroups:(NSArray *)assetsGroups typesOrder:(NSArray *)typesOrder
-{
- NSMutableArray *sortedAssetsGroups = [NSMutableArray array];
-
- for (ALAssetsGroup *assetsGroup in assetsGroups) {
- if (sortedAssetsGroups.count == 0) {
- [sortedAssetsGroups addObject:assetsGroup];
- continue;
- }
-
- ALAssetsGroupType assetsGroupType = [[assetsGroup valueForProperty:ALAssetsGroupPropertyType] unsignedIntegerValue];
- NSUInteger indexOfAssetsGroupType = [typesOrder indexOfObject:@(assetsGroupType)];
-
- for (NSInteger i = 0; i <= sortedAssetsGroups.count; i++) {
- if (i == sortedAssetsGroups.count) {
- [sortedAssetsGroups addObject:assetsGroup];
- break;
- }
-
- ALAssetsGroup *sortedAssetsGroup = sortedAssetsGroups[i];
- ALAssetsGroupType sortedAssetsGroupType = [[sortedAssetsGroup valueForProperty:ALAssetsGroupPropertyType] unsignedIntegerValue];
- NSUInteger indexOfSortedAssetsGroupType = [typesOrder indexOfObject:@(sortedAssetsGroupType)];
-
- if (indexOfAssetsGroupType < indexOfSortedAssetsGroupType) {
- [sortedAssetsGroups insertObject:assetsGroup atIndex:i];
- break;
- }
- }
- }
-
- return [sortedAssetsGroups copy];
-}
-
-- (void)passSelectedAssetsToDelegate
-{
- // Load assets from URLs
- __block NSMutableArray *assets = [NSMutableArray array];
- __block NSUInteger tryCount = 0;
-
- for (NSURL *selectedAssetURL in self.selectedAssetURLs) {
- __weak typeof(self) weakSelf = self;
-
- // Success block
- void (^selectAsset)(ALAsset *) = ^(ALAsset *asset) {
- if (asset) {
- [assets addObject:asset];
- }
- // Check if the loading finished
- if (tryCount == weakSelf.selectedAssetURLs.count) {
- //NSLog(@"���������������������������%lu", (long)(tryCount - assets.count));
- // Delegate
- if (weakSelf.delegate && [weakSelf.delegate respondsToSelector:@selector(qb_imagePickerController:didSelectAssets:)]) {
- [weakSelf.delegate qb_imagePickerController:weakSelf didSelectAssets:[assets copy]];
- }
- }
- };
-
- [self.assetsLibrary assetForURL:selectedAssetURL resultBlock:^(ALAsset *asset) {
- if (asset) {
- tryCount++;
- selectAsset(asset);
- }else{
- // Search in the Photo Stream Album
- [weakSelf.assetsLibrary enumerateGroupsWithTypes:ALAssetsGroupPhotoStream usingBlock:^(ALAssetsGroup *group, BOOL *stop) {
- [group enumerateAssetsWithOptions:NSEnumerationReverse usingBlock:^(ALAsset *result, NSUInteger index, BOOL *stopG) {
- if([result.defaultRepresentation.url isEqual:selectedAssetURL]) {
- *stopG = YES;
- *stop = YES;
- tryCount++;
- selectAsset(result);
- }else if (index == 0){
- NSLog(@"���������");
- tryCount++;//���������������������
- selectAsset(nil);
- }
- }];
- } failureBlock:^(NSError *error) {
- NSLog(@"Error: %@", [error localizedDescription]);
- }];
- }
- } failureBlock:^(NSError *error) {
- NSLog(@"Error: %@", [error localizedDescription]);
- }];
- }
-}
-
-
-#pragma mark - UITableViewDataSource
-
-- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
-{
- return 1;
-}
-
-- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
-{
- return self.assetsGroups.count;
-}
-
-- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
-{
- QBImagePickerGroupCell *cell = [tableView dequeueReusableCellWithIdentifier:@"GroupCell" forIndexPath:indexPath];
-
- ALAssetsGroup *assetsGroup = self.assetsGroups[indexPath.row];
- cell.assetsGroup = assetsGroup;
-
- return cell;
-}
-
-
-#pragma mark - UITableViewDelegate
-
-- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
-{
- return 86.0;
-}
-
-- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
-{
- [self pushToCollectionVCWithIndex:indexPath.row];
-}
-
-- (void)pushToCollectionVCWithIndex:(NSInteger)index{
- if (index >= 0 && index < self.assetsGroups.count) {
- QBAssetsCollectionViewController *assetsCollectionViewController = [[QBAssetsCollectionViewController alloc] initWithCollectionViewLayout:[QBAssetsCollectionViewLayout layout]];
- assetsCollectionViewController.imagePickerController = self;
- assetsCollectionViewController.filterType = self.filterType;
- assetsCollectionViewController.allowsMultipleSelection = self.allowsMultipleSelection;
- assetsCollectionViewController.minimumNumberOfSelection = self.minimumNumberOfSelection;
- assetsCollectionViewController.maximumNumberOfSelection = self.maximumNumberOfSelection;
-
- ALAssetsGroup *assetsGroup = self.assetsGroups[index];
- assetsCollectionViewController.delegate = self;
- assetsCollectionViewController.assetsGroup = assetsGroup;
-
- for (NSURL *assetURL in self.selectedAssetURLs) {
- [assetsCollectionViewController selectAssetHavingURL:assetURL];
- }
-
- [self.navigationController pushViewController:assetsCollectionViewController animated:YES];
- }
-}
-
-
-#pragma mark - QBAssetsCollectionViewControllerDelegate
-
-- (void)assetsCollectionViewController:(QBAssetsCollectionViewController *)assetsCollectionViewController didSelectAsset:(ALAsset *)asset
-{
- if (self.allowsMultipleSelection) {
- // Add asset URL
- NSURL *assetURL = [asset valueForProperty:ALAssetPropertyAssetURL];
- [self.selectedAssetURLs addObject:assetURL];
-
- // Validation
- self.navigationItem.rightBarButtonItem.enabled = [self validateNumberOfSelections:self.selectedAssetURLs.count];
- } else {
- // Delegate
- if (self.delegate && [self.delegate respondsToSelector:@selector(qb_imagePickerController:didSelectAsset:)]) {
- [self.delegate qb_imagePickerController:self didSelectAsset:asset];
- }
- }
-}
-
-- (void)assetsCollectionViewController:(QBAssetsCollectionViewController *)assetsCollectionViewController didDeselectAsset:(ALAsset *)asset
-{
- if (self.allowsMultipleSelection) {
- // Remove asset URL
- NSURL *assetURL = [asset valueForProperty:ALAssetPropertyAssetURL];
- [self.selectedAssetURLs removeObject:assetURL];
-
- // Validation
- self.navigationItem.rightBarButtonItem.enabled = [self validateNumberOfSelections:self.selectedAssetURLs.count];
- }
-}
-
-- (void)assetsCollectionViewControllerDidFinishSelection:(QBAssetsCollectionViewController *)assetsCollectionViewController
-{
- [self passSelectedAssetsToDelegate];
-}
-
-@end
diff --git a/camerademo/camerademo/demo/QBImagePickerController/QBImagePickerController.strings b/camerademo/camerademo/demo/QBImagePickerController/QBImagePickerController.strings
deleted file mode 100755
index dfc7cce..0000000
--- a/camerademo/camerademo/demo/QBImagePickerController/QBImagePickerController.strings
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- QBImagePickerController.strings
- QBImagePickerControllerDemo
-
- Created by Tanaka Katsuma on 2014/01/01.
- Copyright (c) 2014��� Katsuma Tanaka. All rights reserved.
-*/
-
-"title" = "������";
-
-"format_photo" = "���%ld���������";
-"format_photos" = "���%ld���������";
-"format_video" = "%���ld���������";
-"format_videos" = "���%ld���������";
-"format_photo_and_video" = "%���ld���������, %ld���������";
-"format_photos_and_video" = "%���ld���������, %ld���������";
-"format_photo_and_videos" = "%���ld���������, %ld���������";
-"format_photos_and_videos" = "%���ld���������, %ld���������";
diff --git a/camerademo/camerademo/demo/QBImagePickerController/QBImagePickerGroupCell.h b/camerademo/camerademo/demo/QBImagePickerController/QBImagePickerGroupCell.h
deleted file mode 100755
index a6480ae..0000000
--- a/camerademo/camerademo/demo/QBImagePickerController/QBImagePickerGroupCell.h
+++ /dev/null
@@ -1,16 +0,0 @@
-//
-// QBImagePickerGroupCell.h
-// QBImagePickerController
-//
-// Created by Tanaka Katsuma on 2013/12/30.
-// Copyright (c) 2013��� Katsuma Tanaka. All rights reserved.
-//
-
-#import <UIKit/UIKit.h>
-#import <AssetsLibrary/AssetsLibrary.h>
-
-@interface QBImagePickerGroupCell : UITableViewCell
-
-@property (nonatomic, strong) ALAssetsGroup *assetsGroup;
-
-@end
diff --git a/camerademo/camerademo/demo/QBImagePickerController/QBImagePickerGroupCell.m b/camerademo/camerademo/demo/QBImagePickerController/QBImagePickerGroupCell.m
deleted file mode 100755
index c5bdac5..0000000
--- a/camerademo/camerademo/demo/QBImagePickerController/QBImagePickerGroupCell.m
+++ /dev/null
@@ -1,76 +0,0 @@
-//
-// QBImagePickerGroupCell.m
-// QBImagePickerController
-//
-// Created by Tanaka Katsuma on 2013/12/30.
-// Copyright (c) 2013��� Katsuma Tanaka. All rights reserved.
-//
-
-#import "QBImagePickerGroupCell.h"
-
-// Views
-#import "QBImagePickerThumbnailView.h"
-
-@interface QBImagePickerGroupCell ()
-
-@property (nonatomic, strong) QBImagePickerThumbnailView *thumbnailView;
-@property (nonatomic, strong) UILabel *nameLabel;
-@property (nonatomic, strong) UILabel *countLabel;
-
-@end
-
-@implementation QBImagePickerGroupCell
-
-- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
-{
- self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
-
- if (self) {
- // Cell settings
- self.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
-
- // Create thumbnail view
- QBImagePickerThumbnailView *thumbnailView = [[QBImagePickerThumbnailView alloc] initWithFrame:CGRectMake(8, 4, 70, 74)];
- thumbnailView.autoresizingMask = UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleBottomMargin;
-
- [self.contentView addSubview:thumbnailView];
- self.thumbnailView = thumbnailView;
-
- // Create name label
- UILabel *nameLabel = [[UILabel alloc] initWithFrame:CGRectMake(8 + 70 + 18, 22, 180, 21)];
- nameLabel.font = [UIFont systemFontOfSize:17];
- nameLabel.textColor = [UIColor blackColor];
- nameLabel.autoresizingMask = UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleWidth;
-
- [self.contentView addSubview:nameLabel];
- self.nameLabel = nameLabel;
-
- // Create count label
- UILabel *countLabel = [[UILabel alloc] initWithFrame:CGRectMake(8 + 70 + 18, 46, 180, 15)];
- countLabel.font = [UIFont systemFontOfSize:12];
- countLabel.textColor = [UIColor blackColor];
- countLabel.autoresizingMask = UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleWidth;
-
- [self.contentView addSubview:countLabel];
- self.countLabel = countLabel;
- }
-
- return self;
-}
-
-
-#pragma mark - Accessors
-
-- (void)setAssetsGroup:(ALAssetsGroup *)assetsGroup
-{
- _assetsGroup = assetsGroup;
-
- // Update thumbnail view
- self.thumbnailView.assetsGroup = self.assetsGroup;
-
- // Update label
- self.nameLabel.text = [self.assetsGroup valueForProperty:ALAssetsGroupPropertyName];
- self.countLabel.text = [NSString stringWithFormat:@"%ld", (long)self.assetsGroup.numberOfAssets];
-}
-
-@end
diff --git a/camerademo/camerademo/demo/QBImagePickerController/QBImagePickerThumbnailView.h b/camerademo/camerademo/demo/QBImagePickerController/QBImagePickerThumbnailView.h
deleted file mode 100755
index 2b5eeaa..0000000
--- a/camerademo/camerademo/demo/QBImagePickerController/QBImagePickerThumbnailView.h
+++ /dev/null
@@ -1,16 +0,0 @@
-//
-// QBImagePickerThumbnailView.h
-// QBImagePickerController
-//
-// Created by Tanaka Katsuma on 2013/12/31.
-// Copyright (c) 2013��� Katsuma Tanaka. All rights reserved.
-//
-
-#import <UIKit/UIKit.h>
-#import <AssetsLibrary/AssetsLibrary.h>
-
-@interface QBImagePickerThumbnailView : UIView
-
-@property (nonatomic, strong) ALAssetsGroup *assetsGroup;
-
-@end
diff --git a/camerademo/camerademo/demo/QBImagePickerController/QBImagePickerThumbnailView.m b/camerademo/camerademo/demo/QBImagePickerController/QBImagePickerThumbnailView.m
deleted file mode 100755
index ea05a6c..0000000
--- a/camerademo/camerademo/demo/QBImagePickerController/QBImagePickerThumbnailView.m
+++ /dev/null
@@ -1,112 +0,0 @@
-//
-// QBImagePickerThumbnailView.m
-// QBImagePickerController
-//
-// Created by Tanaka Katsuma on 2013/12/31.
-// Copyright (c) 2013��� Katsuma Tanaka. All rights reserved.
-//
-
-#import "QBImagePickerThumbnailView.h"
-
-@interface QBImagePickerThumbnailView ()
-
-@property (nonatomic, copy) NSArray *thumbnailImages;
-@property (nonatomic, strong) UIImage *blankImage;
-
-@end
-
-@implementation QBImagePickerThumbnailView
-
-- (instancetype)initWithFrame:(CGRect)frame
-{
- self = [super initWithFrame:frame];
-
- if (self) {
- self.backgroundColor = [UIColor clearColor];
- }
-
- return self;
-}
-
-- (CGSize)sizeThatFits:(CGSize)size
-{
- return CGSizeMake(70.0, 74.0);
-}
-
-- (void)drawRect:(CGRect)rect
-{
- [super drawRect:rect];
-
- CGContextRef context = UIGraphicsGetCurrentContext();
- CGContextSetRGBFillColor(context, 1.0, 1.0, 1.0, 1.0);
-
- if (self.thumbnailImages.count == 3) {
- UIImage *thumbnailImage = [self.thumbnailImages firstObject];
-
- CGRect thumbnailImageRect = CGRectMake(4.0, 0, 62.0, 62.0);
- CGContextFillRect(context, thumbnailImageRect);
- [thumbnailImage drawInRect:CGRectInset(thumbnailImageRect, 0.5, 0.5)];
- }
- if (self.thumbnailImages.count >= 2) {
- UIImage *thumbnailImage = self.thumbnailImages[1];
-
- CGRect thumbnailImageRect = CGRectMake(2.0, 2.0, 66.0, 66.0);
- CGContextFillRect(context, thumbnailImageRect);
- [thumbnailImage drawInRect:CGRectInset(thumbnailImageRect, 0.5, 0.5)];
- }
- if (self.thumbnailImages.count >= 1) {
- UIImage *thumbnailImage = [self.thumbnailImages lastObject];
-
- CGRect thumbnailImageRect = CGRectMake(0, 4.0, 70.0, 70.0);
- CGContextFillRect(context, thumbnailImageRect);
- [thumbnailImage drawInRect:CGRectInset(thumbnailImageRect, 0.5, 0.5)];
- }
-}
-
-
-#pragma mark - Accessors
-
-- (void)setAssetsGroup:(ALAssetsGroup *)assetsGroup
-{
- _assetsGroup = assetsGroup;
-
- // Extract three thumbnail images
- NSInteger thumbnailImagesCount = MIN(3, assetsGroup.numberOfAssets);
- NSIndexSet *indexes = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(assetsGroup.numberOfAssets-thumbnailImagesCount, thumbnailImagesCount)];
- NSMutableArray *thumbnailImages = [NSMutableArray array];
- [assetsGroup enumerateAssetsAtIndexes:indexes
- options:0
- usingBlock:^(ALAsset *result, NSUInteger index, BOOL *stop) {
- if (result) {
- CGImageRef thumbnailImageRef = [result thumbnail];
-
- if (thumbnailImageRef) {
- [thumbnailImages addObject:[UIImage imageWithCGImage:thumbnailImageRef]];
- } else {
- [thumbnailImages addObject:[self blankImage]];
- }
- }
- }];
- self.thumbnailImages = [thumbnailImages copy];
-
- [self setNeedsDisplay];
-}
-
-- (UIImage *)blankImage
-{
- if (_blankImage == nil) {
- CGSize size = CGSizeMake(100.0, 100.0);
- UIGraphicsBeginImageContextWithOptions(size, NO, 0.0);
-
- [[UIColor colorWithWhite:(240.0 / 255.0) alpha:1.0] setFill];
- UIRectFill(CGRectMake(0, 0, size.width, size.height));
-
- _blankImage = UIGraphicsGetImageFromCurrentImageContext();
-
- UIGraphicsEndImageContext();
- }
-
- return _blankImage;
-}
-
-@end
diff --git a/camerademo/camerademo/demo/UIImage/UIImage+Alpha.h b/camerademo/camerademo/demo/UIImage/UIImage+Alpha.h
deleted file mode 100755
index ba09684..0000000
--- a/camerademo/camerademo/demo/UIImage/UIImage+Alpha.h
+++ /dev/null
@@ -1,40 +0,0 @@
-// UIImage+Alpha.h
-// Created by Trevor Harmon on 9/20/09.
-// Free for personal or commercial use, with or without modification.
-// No warranty is expressed or implied.
-
-// Helper methods for adding an alpha layer to an image
-#import <UIKit/UIKit.h>
-
-@interface UIImage (Alpha)
-/**
- * @brief ���������alpha������
- *
- * @return ���������alpha������
- */
-- (BOOL)hasAlpha;
-/**
- * @brief ������������alpha������ ������alpha������
- *
- * @return ������������alpha������ ������alpha������
- */
-- (UIImage *)imageWithAlpha;
-/**
- * @brief ������������������
- *
- * @param borderSize ������������
- *
- * @return ������������������������������
- */
-- (UIImage *)transparentBorderImage:(NSUInteger)borderSize;
-
-
-//http://stackoverflow.com/questions/6521987/crop-uiimage-to-alpha?answertab=oldest#tab-top
-/**
- * @brief ������������������������������������
- *
- * @return ������������������
- */
-- (UIImage *)trimmedBetterSize;
-
-@end
diff --git a/camerademo/camerademo/demo/UIImage/UIImage+Alpha.m b/camerademo/camerademo/demo/UIImage/UIImage+Alpha.m
deleted file mode 100755
index fba6259..0000000
--- a/camerademo/camerademo/demo/UIImage/UIImage+Alpha.m
+++ /dev/null
@@ -1,234 +0,0 @@
-// UIImage+Alpha.m
-// Created by Trevor Harmon on 9/20/09.
-// Free for personal or commercial use, with or without modification.
-// No warranty is expressed or implied.
-
-#import "UIImage+Alpha.h"
-
-// Private helper methods
-@interface UIImage (AlphaPrivateMethods)
-- (CGImageRef)newBorderMask:(NSUInteger)borderSize size:(CGSize)size;
-@end
-
-@implementation UIImage (Alpha)
-/**
- * @brief ���������alpha������
- *
- * @return ���������alpha������
- */
-- (BOOL)hasAlpha {
- CGImageAlphaInfo alpha = CGImageGetAlphaInfo(self.CGImage);
- return (alpha == kCGImageAlphaFirst ||
- alpha == kCGImageAlphaLast ||
- alpha == kCGImageAlphaPremultipliedFirst ||
- alpha == kCGImageAlphaPremultipliedLast);
-}
-/**
- * @brief ������������alpha������ ������alpha������
- *
- * @return ������������alpha������ ������alpha������
- */
-- (UIImage *)imageWithAlpha {
- if ([self hasAlpha]) {
- return self;
- }
-
- CGImageRef imageRef = self.CGImage;
- size_t width = CGImageGetWidth(imageRef);
- size_t height = CGImageGetHeight(imageRef);
-
- // The bitsPerComponent and bitmapInfo values are hard-coded to prevent an "unsupported parameter combination" error
- CGContextRef offscreenContext = CGBitmapContextCreate(NULL,
- width,
- height,
- 8,
- 0,
- CGImageGetColorSpace(imageRef),
- kCGBitmapByteOrderDefault | kCGImageAlphaPremultipliedFirst);
-
- // Draw the image into the context and retrieve the new image, which will now have an alpha layer
- CGContextDrawImage(offscreenContext, CGRectMake(0, 0, width, height), imageRef);
- CGImageRef imageRefWithAlpha = CGBitmapContextCreateImage(offscreenContext);
- UIImage *imageWithAlpha = [UIImage imageWithCGImage:imageRefWithAlpha];
-
- // Clean up
- CGContextRelease(offscreenContext);
- CGImageRelease(imageRefWithAlpha);
-
- return imageWithAlpha;
-}
-
-// Returns a copy of the image with a transparent border of the given size added around its edges.
-// If the image has no alpha layer, one will be added to it.
-/**
- * @brief ������������������
- *
- * @param borderSize ������������
- *
- * @return ������������������������������
- */
-- (UIImage *)transparentBorderImage:(NSUInteger)borderSize {
- // If the image does not have an alpha layer, add one
- UIImage *image = [self imageWithAlpha];
-
- CGRect newRect = CGRectMake(0, 0, image.size.width + borderSize * 2, image.size.height + borderSize * 2);
-
- // Build a context that's the same dimensions as the new size
- CGContextRef bitmap = CGBitmapContextCreate(NULL,
- newRect.size.width,
- newRect.size.height,
- CGImageGetBitsPerComponent(self.CGImage),
- 0,
- CGImageGetColorSpace(self.CGImage),
- CGImageGetBitmapInfo(self.CGImage));
-
- // Draw the image in the center of the context, leaving a gap around the edges
- CGRect imageLocation = CGRectMake(borderSize, borderSize, image.size.width, image.size.height);
- CGContextDrawImage(bitmap, imageLocation, self.CGImage);
- CGImageRef borderImageRef = CGBitmapContextCreateImage(bitmap);
-
- // Create a mask to make the border transparent, and combine it with the image
- CGImageRef maskImageRef = [self newBorderMask:borderSize size:newRect.size];
- CGImageRef transparentBorderImageRef = CGImageCreateWithMask(borderImageRef, maskImageRef);
- UIImage *transparentBorderImage = [UIImage imageWithCGImage:transparentBorderImageRef];
-
- // Clean up
- CGContextRelease(bitmap);
- CGImageRelease(borderImageRef);
- CGImageRelease(maskImageRef);
- CGImageRelease(transparentBorderImageRef);
-
- return transparentBorderImage;
-}
-/**
- * @brief ������������������������������������
- *
- * @return ������������������
- */
-- (UIImage *)trimmedBetterSize {
-
- CGImageRef inImage = self.CGImage;
- CFDataRef m_DataRef;
- m_DataRef = CGDataProviderCopyData(CGImageGetDataProvider(inImage));
-
- UInt8 * m_PixelBuf = (UInt8 *) CFDataGetBytePtr(m_DataRef);
-
-// size_t width = CGImageGetWidth(inImage);
-// size_t height = CGImageGetHeight(inImage);
- CGFloat width = CGImageGetWidth(inImage);
- CGFloat height = CGImageGetHeight(inImage);
- CGPoint top,left,right,bottom;
-
- BOOL breakOut = NO;
- for (int x = 0;breakOut==NO && x < width; x++) {
- for (int y = 0; y < height; y++) {
- int loc = x + (y * width);
- loc *= 4;
- if (m_PixelBuf[loc + 3] != 0) {
- left = CGPointMake(x, y);
- breakOut = YES;
- break;
- }
- }
- }
-
- breakOut = NO;
- for (int y = 0;breakOut==NO && y < height; y++) {
-
- for (int x = 0; x < width; x++) {
-
- int loc = x + (y * width);
- loc *= 4;
- if (m_PixelBuf[loc + 3] != 0) {
- top = CGPointMake(x, y);
- breakOut = YES;
- break;
- }
-
- }
- }
-
- breakOut = NO;
- for (int y = height-1;breakOut==NO && y >= 0; y--) {
-
- for (int x = width-1; x >= 0; x--) {
-
- int loc = x + (y * width);
- loc *= 4;
- if (m_PixelBuf[loc + 3] != 0) {
- bottom = CGPointMake(x, y);
- breakOut = YES;
- break;
- }
-
- }
- }
-
- breakOut = NO;
- for (int x = width-1;breakOut==NO && x >= 0; x--) {
-
- for (int y = height-1; y >= 0; y--) {
-
- int loc = x + (y * width);
- loc *= 4;
- if (m_PixelBuf[loc + 3] != 0) {
- right = CGPointMake(x, y);
- breakOut = YES;
- break;
- }
-
- }
- }
-
-
- CGFloat scale = self.scale;
-
- CGRect cropRect = CGRectMake(left.x / scale, top.y/scale, (right.x - left.x)/scale, (bottom.y - top.y) / scale);
- UIGraphicsBeginImageContextWithOptions( cropRect.size,
- NO,
- scale);
- [self drawAtPoint:CGPointMake(-cropRect.origin.x, -cropRect.origin.y)
- blendMode:kCGBlendModeCopy
- alpha:1.];
- UIImage *croppedImage = UIGraphicsGetImageFromCurrentImageContext();
- UIGraphicsEndImageContext();
- CFRelease(m_DataRef);
- return croppedImage;
-}
-#pragma mark -
-#pragma mark Private helper methods
-
-// Creates a mask that makes the outer edges transparent and everything else opaque
-// The size must include the entire mask (opaque part + transparent border)
-// The caller is responsible for releasing the returned reference by calling CGImageRelease
-- (CGImageRef)newBorderMask:(NSUInteger)borderSize size:(CGSize)size {
- CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceGray();
-
- // Build a context that's the same dimensions as the new size
- CGContextRef maskContext = CGBitmapContextCreate(NULL,
- size.width,
- size.height,
- 8, // 8-bit grayscale
- 0,
- colorSpace,
- kCGBitmapByteOrderDefault | kCGImageAlphaNone);
-
- // Start with a mask that's entirely transparent
- CGContextSetFillColorWithColor(maskContext, [UIColor blackColor].CGColor);
- CGContextFillRect(maskContext, CGRectMake(0, 0, size.width, size.height));
-
- // Make the inner part (within the border) opaque
- CGContextSetFillColorWithColor(maskContext, [UIColor whiteColor].CGColor);
- CGContextFillRect(maskContext, CGRectMake(borderSize, borderSize, size.width - borderSize * 2, size.height - borderSize * 2));
-
- // Get an image of the context
- CGImageRef maskImageRef = CGBitmapContextCreateImage(maskContext);
-
- // Clean up
- CGContextRelease(maskContext);
- CGColorSpaceRelease(colorSpace);
-
- return maskImageRef;
-}
-
-@end
diff --git a/camerademo/camerademo/demo/UIImage/UIImage+BetterFace.h b/camerademo/camerademo/demo/UIImage/UIImage+BetterFace.h
deleted file mode 100755
index 95fa0d6..0000000
--- a/camerademo/camerademo/demo/UIImage/UIImage+BetterFace.h
+++ /dev/null
@@ -1,23 +0,0 @@
-//
-// UIImage+BetterFace.h
-// bf
-//
-// Created by liuyan on 13-11-25.
-// Copyright (c) 2013��� Croath. All rights reserved.
-//
-// https://github.com/croath/UIImageView-BetterFace
-// a UIImageView category to let the picture-cutting with faces showing better
-
-#import <UIKit/UIKit.h>
-
-typedef NS_ENUM(NSUInteger, BFAccuracy) {
- kBFAccuracyLow = 0,
- kBFAccuracyHigh,
-};
-
-@interface UIImage (BetterFace)
-
-- (UIImage *)betterFaceImageForSize:(CGSize)size
- accuracy:(BFAccuracy)accurary;
-
-@end
diff --git a/camerademo/camerademo/demo/UIImage/UIImage+BetterFace.m b/camerademo/camerademo/demo/UIImage/UIImage+BetterFace.m
deleted file mode 100755
index f776f71..0000000
--- a/camerademo/camerademo/demo/UIImage/UIImage+BetterFace.m
+++ /dev/null
@@ -1,111 +0,0 @@
-//
-// UIImage+BetterFace.m
-// bf
-//
-// Created by liuyan on 13-11-25.
-// Copyright (c) 2013��� Croath. All rights reserved.
-//
-
-#import "UIImage+BetterFace.h"
-
-#define GOLDEN_RATIO (0.618)
-
-#ifdef BF_DEBUG
-#define BFLog(format...) NSLog(format)
-#else
-#define BFLog(format...)
-#endif
-
-@implementation UIImage (BetterFace)
-
-- (UIImage *)betterFaceImageForSize:(CGSize)size
- accuracy:(BFAccuracy)accurary;
-{
- NSArray *features = [UIImage _faceFeaturesInImage:self accuracy:accurary];
-
- if ([features count]==0) {
- BFLog(@"no faces");
- return nil;
- } else {
- BFLog(@"succeed %lu faces", (unsigned long)[features count]);
- return [self _subImageForFaceFeatures:features
- size:size];
- }
-}
-
-- (UIImage *)_subImageForFaceFeatures:(NSArray *)faceFeatures size:(CGSize)size
-{
- CGRect fixedRect = CGRectMake(MAXFLOAT, MAXFLOAT, 0, 0);
- CGFloat rightBorder = 0, bottomBorder = 0;
- for (CIFaceFeature *faceFeature in faceFeatures){
- CGRect oneRect = faceFeature.bounds;
- oneRect.origin.y = size.height - oneRect.origin.y - oneRect.size.height;
-
- fixedRect.origin.x = MIN(oneRect.origin.x, fixedRect.origin.x);
- fixedRect.origin.y = MIN(oneRect.origin.y, fixedRect.origin.y);
-
- rightBorder = MAX(oneRect.origin.x + oneRect.size.width, rightBorder);
- bottomBorder = MAX(oneRect.origin.y + oneRect.size.height, bottomBorder);
- }
-
- fixedRect.size.width = rightBorder - fixedRect.origin.x;
- fixedRect.size.height = bottomBorder - fixedRect.origin.y;
-
- CGPoint fixedCenter = CGPointMake(fixedRect.origin.x + fixedRect.size.width / 2.0,
- fixedRect.origin.y + fixedRect.size.height / 2.0);
- CGPoint offset = CGPointZero;
- CGSize finalSize = size;
- if (size.width / size.height > self.size.width / self.size.height) {
- //move horizonal
- finalSize.height = self.size.height;
- finalSize.width = size.width/size.height * finalSize.height;
- fixedCenter.x = finalSize.width / size.width * fixedCenter.x;
- fixedCenter.y = finalSize.width / size.width * fixedCenter.y;
-
- offset.x = fixedCenter.x - self.size.width * 0.5;
- if (offset.x < 0) {
- offset.x = 0;
- } else if (offset.x + self.size.width > finalSize.width) {
- offset.x = finalSize.width - self.size.width;
- }
- offset.x = - offset.x;
- } else {
- //move vertical
- finalSize.width = self.size.width;
- finalSize.height = size.height/size.width * finalSize.width;
- fixedCenter.x = finalSize.width / size.width * fixedCenter.x;
- fixedCenter.y = finalSize.width / size.width * fixedCenter.y;
-
- offset.y = fixedCenter.y - self.size.height * (1-GOLDEN_RATIO);
- if (offset.y < 0) {
- offset.y = 0;
- } else if (offset.y + self.size.height > finalSize.height){
- offset.y = finalSize.height = self.size.height;
- }
- offset.y = - offset.y;
- }
-
- CGRect finalRect = CGRectApplyAffineTransform(CGRectMake(offset.x, offset.y, finalSize.width, finalSize.height),
- CGAffineTransformMakeScale(self.scale, self.scale));
- CGImageRef imageRef = CGImageCreateWithImageInRect([self CGImage], finalRect);
- UIImage *subImage = [UIImage imageWithCGImage:imageRef scale:self.scale orientation:self.imageOrientation];
- CGImageRelease(imageRef);
-
- return subImage;
-}
-
-#pragma mark - Util
-
-+ (NSArray *)_faceFeaturesInImage:(UIImage *)image accuracy:(BFAccuracy)accurary
-{
- CIImage *ciImage = [CIImage imageWithCGImage:image.CGImage];
- NSString *accuraryStr = (accurary == kBFAccuracyLow) ? CIDetectorAccuracyLow : CIDetectorAccuracyHigh;
-
- CIDetector *detector = [CIDetector detectorOfType:CIDetectorTypeFace
- context:nil
- options:@{CIDetectorAccuracy: accuraryStr}];
-
- return [detector featuresInImage:ciImage];
-}
-
-@end
diff --git a/camerademo/camerademo/demo/UIImage/UIImage+Blur.h b/camerademo/camerademo/demo/UIImage/UIImage+Blur.h
deleted file mode 100755
index 4f5f82b..0000000
--- a/camerademo/camerademo/demo/UIImage/UIImage+Blur.h
+++ /dev/null
@@ -1,24 +0,0 @@
-//
-// UIImage+Blur.h
-// IOS-Categories (https://github.com/shaojiankui/iOS-Categories)
-//
-// Created by Jakey on 15/6/5.
-// Copyright (c) 2015��� www.skyfox.org. All rights reserved.
-//
-
-#import <UIKit/UIKit.h>
-FOUNDATION_EXPORT double ImageEffectsVersionNumber;
-FOUNDATION_EXPORT const unsigned char ImageEffectsVersionString[];
-@interface UIImage (Blur)
-- (UIImage *)lightImage;
-- (UIImage *)extraLightImage;
-- (UIImage *)darkImage;
-- (UIImage *)tintedImageWithColor:(UIColor *)tintColor;
-
-- (UIImage *)blurredImageWithRadius:(CGFloat)blurRadius;
-- (UIImage *)blurredImageWithSize:(CGSize)blurSize;
-- (UIImage *)blurredImageWithSize:(CGSize)blurSize
- tintColor:(UIColor *)tintColor
- saturationDeltaFactor:(CGFloat)saturationDeltaFactor
- maskImage:(UIImage *)maskImage;
-@end
diff --git a/camerademo/camerademo/demo/UIImage/UIImage+Blur.m b/camerademo/camerademo/demo/UIImage/UIImage+Blur.m
deleted file mode 100755
index 70f4461..0000000
--- a/camerademo/camerademo/demo/UIImage/UIImage+Blur.m
+++ /dev/null
@@ -1,281 +0,0 @@
-//
-// UIImage+Blur.m
-// IOS-Categories (https://github.com/shaojiankui/iOS-Categories)
-//
-// Created by Jakey on 15/6/5.
-// Copyright (c) 2015��� www.skyfox.org. All rights reserved.
-//
-
-#import "UIImage+Blur.h"
-@import Accelerate;
-@implementation UIImage (Blur)
-#pragma mark -
-#pragma mark - Effects
-
-//| ----------------------------------------------------------------------------
-- (UIImage *)lightImage
-{
- UIColor *tintColor = [UIColor colorWithWhite:1.0 alpha:0.3];
- return [self blurredImageWithSize:CGSizeMake(60, 60) tintColor:tintColor saturationDeltaFactor:1.8 maskImage:nil];
-}
-
-
-//| ----------------------------------------------------------------------------
-- (UIImage *)extraLightImage
-{
- UIColor *tintColor = [UIColor colorWithWhite:0.97 alpha:0.82];
- return [self blurredImageWithSize:CGSizeMake(40, 40) tintColor:tintColor saturationDeltaFactor:1.8 maskImage:nil];
-}
-
-
-//| ----------------------------------------------------------------------------
-- (UIImage *)darkImage
-{
- UIColor *tintColor = [UIColor colorWithWhite:0.11 alpha:0.73];
- return [self blurredImageWithSize:CGSizeMake(40, 40) tintColor:tintColor saturationDeltaFactor:1.8 maskImage:nil];
-}
-
-
-//| ----------------------------------------------------------------------------
-- (UIImage *)tintedImageWithColor:(UIColor *)tintColor
-{
- const CGFloat EffectColorAlpha = 0.6;
- UIColor *effectColor = tintColor;
- size_t componentCount = CGColorGetNumberOfComponents(tintColor.CGColor);
- if (componentCount == 2) {
- CGFloat b;
- if ([tintColor getWhite:&b alpha:NULL]) {
- effectColor = [UIColor colorWithWhite:b alpha:EffectColorAlpha];
- }
- }
- else {
- CGFloat r, g, b;
- if ([tintColor getRed:&r green:&g blue:&b alpha:NULL]) {
- effectColor = [UIColor colorWithRed:r green:g blue:b alpha:EffectColorAlpha];
- }
- }
- return [self blurredImageWithSize:CGSizeMake(20, 20) tintColor:effectColor saturationDeltaFactor:-1.0 maskImage:nil];
-}
-
-
-//| ----------------------------------------------------------------------------
-- (UIImage *)blurredImageWithRadius:(CGFloat)blurRadius
-{
- return [self blurredImageWithSize:CGSizeMake(blurRadius, blurRadius)];
-}
-
-
-//| ----------------------------------------------------------------------------
-- (UIImage *)blurredImageWithSize:(CGSize)blurSize
-{
- return [self blurredImageWithSize:blurSize tintColor:nil saturationDeltaFactor:1.0 maskImage:nil];
-}
-
-#pragma mark -
-#pragma mark - Implementation
-
-//| ----------------------------------------------------------------------------
-- (UIImage *)blurredImageWithSize:(CGSize)blurSize tintColor:(UIColor *)tintColor saturationDeltaFactor:(CGFloat)saturationDeltaFactor maskImage:(UIImage *)maskImage
-{
-#define ENABLE_BLUR 1
-#define ENABLE_SATURATION_ADJUSTMENT 1
-#define ENABLE_TINT 1
-
- // Check pre-conditions.
- if (self.size.width < 1 || self.size.height < 1)
- {
- NSLog(@"*** error: invalid size: (%.2f x %.2f). Both dimensions must be >= 1: %@", self.size.width, self.size.height, self);
- return nil;
- }
- if (!self.CGImage)
- {
- NSLog(@"*** error: inputImage must be backed by a CGImage: %@", self);
- return nil;
- }
- if (maskImage && !maskImage.CGImage)
- {
- NSLog(@"*** error: effectMaskImage must be backed by a CGImage: %@", maskImage);
- return nil;
- }
-
- BOOL hasBlur = blurSize.width > __FLT_EPSILON__ || blurSize.height > __FLT_EPSILON__;
- BOOL hasSaturationChange = fabs(saturationDeltaFactor - 1.) > __FLT_EPSILON__;
-
- CGImageRef inputCGImage = self.CGImage;
- CGFloat inputImageScale = self.scale;
- CGBitmapInfo inputImageBitmapInfo = CGImageGetBitmapInfo(inputCGImage);
- CGImageAlphaInfo inputImageAlphaInfo = (inputImageBitmapInfo & kCGBitmapAlphaInfoMask);
-
- CGSize outputImageSizeInPoints = self.size;
- CGRect outputImageRectInPoints = { CGPointZero, outputImageSizeInPoints };
-
- // Set up output context.
- BOOL useOpaqueContext;
- if (inputImageAlphaInfo == kCGImageAlphaNone || inputImageAlphaInfo == kCGImageAlphaNoneSkipLast || inputImageAlphaInfo == kCGImageAlphaNoneSkipFirst)
- useOpaqueContext = YES;
- else
- useOpaqueContext = NO;
- UIGraphicsBeginImageContextWithOptions(outputImageRectInPoints.size, useOpaqueContext, inputImageScale);
- CGContextRef outputContext = UIGraphicsGetCurrentContext();
- CGContextScaleCTM(outputContext, 1.0, -1.0);
- CGContextTranslateCTM(outputContext, 0, -outputImageRectInPoints.size.height);
-
- if (hasBlur || hasSaturationChange)
- {
- vImage_Buffer effectInBuffer;
- vImage_Buffer scratchBuffer1;
-
- vImage_Buffer *inputBuffer;
- vImage_Buffer *outputBuffer;
-
- vImage_CGImageFormat format = {
- .bitsPerComponent = 8,
- .bitsPerPixel = 32,
- .colorSpace = NULL,
- // (kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Little)
- // requests a BGRA buffer.
- .bitmapInfo = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Little,
- .version = 0,
- .decode = NULL,
- .renderingIntent = kCGRenderingIntentDefault
- };
-
- vImage_Error e = vImageBuffer_InitWithCGImage(&effectInBuffer, &format, NULL, self.CGImage, kvImagePrintDiagnosticsToConsole);
- if (e != kvImageNoError)
- {
- NSLog(@"*** error: vImageBuffer_InitWithCGImage returned error code %zi for inputImage: %@", e, self);
- UIGraphicsEndImageContext();
- return nil;
- }
-
- vImageBuffer_Init(&scratchBuffer1, effectInBuffer.height, effectInBuffer.width, format.bitsPerPixel, kvImageNoFlags);
- inputBuffer = &effectInBuffer;
- outputBuffer = &scratchBuffer1;
-
-#if ENABLE_BLUR
- if (hasBlur)
- {
- CGFloat radiusX = [self gaussianBlurRadiusWithBlurRadius:blurSize.width * inputImageScale];
- CGFloat radiusY = [self gaussianBlurRadiusWithBlurRadius:blurSize.height * inputImageScale];
-
- NSInteger tempBufferSize = vImageBoxConvolve_ARGB8888(inputBuffer, outputBuffer, NULL, 0, 0, radiusY, radiusX, NULL, kvImageGetTempBufferSize | kvImageEdgeExtend);
- void *tempBuffer = malloc(tempBufferSize);
-
- vImageBoxConvolve_ARGB8888(inputBuffer, outputBuffer, tempBuffer, 0, 0, radiusY, radiusX, NULL, kvImageEdgeExtend);
- vImageBoxConvolve_ARGB8888(outputBuffer, inputBuffer, tempBuffer, 0, 0, radiusY, radiusX, NULL, kvImageEdgeExtend);
- vImageBoxConvolve_ARGB8888(inputBuffer, outputBuffer, tempBuffer, 0, 0, radiusY, radiusX, NULL, kvImageEdgeExtend);
-
- free(tempBuffer);
-
- vImage_Buffer *temp = inputBuffer;
- inputBuffer = outputBuffer;
- outputBuffer = temp;
- }
-#endif
-
-#if ENABLE_SATURATION_ADJUSTMENT
- if (hasSaturationChange)
- {
- CGFloat s = saturationDeltaFactor;
- // These values appear in the W3C Filter Effects spec:
- // https://dvcs.w3.org/hg/FXTF/raw-file/default/filters/index.html#grayscaleEquivalent
- //
- CGFloat floatingPointSaturationMatrix[] = {
- 0.0722 + 0.9278 * s, 0.0722 - 0.0722 * s, 0.0722 - 0.0722 * s, 0,
- 0.7152 - 0.7152 * s, 0.7152 + 0.2848 * s, 0.7152 - 0.7152 * s, 0,
- 0.2126 - 0.2126 * s, 0.2126 - 0.2126 * s, 0.2126 + 0.7873 * s, 0,
- 0, 0, 0, 1,
- };
- const int32_t divisor = 256;
- NSUInteger matrixSize = sizeof(floatingPointSaturationMatrix)/sizeof(floatingPointSaturationMatrix[0]);
- int16_t saturationMatrix[matrixSize];
- for (NSUInteger i = 0; i < matrixSize; ++i) {
- saturationMatrix[i] = (int16_t)roundf(floatingPointSaturationMatrix[i] * divisor);
- }
- vImageMatrixMultiply_ARGB8888(inputBuffer, outputBuffer, saturationMatrix, divisor, NULL, NULL, kvImageNoFlags);
-
- vImage_Buffer *temp = inputBuffer;
- inputBuffer = outputBuffer;
- outputBuffer = temp;
- }
-#endif
-
- CGImageRef effectCGImage;
- if ( (effectCGImage = vImageCreateCGImageFromBuffer(inputBuffer, &format, &cleanupBuffer, NULL, kvImageNoAllocate, NULL)) == NULL ) {
- effectCGImage = vImageCreateCGImageFromBuffer(inputBuffer, &format, NULL, NULL, kvImageNoFlags, NULL);
- free(inputBuffer->data);
- }
- if (maskImage) {
- // Only need to draw the base image if the effect image will be masked.
- CGContextDrawImage(outputContext, outputImageRectInPoints, inputCGImage);
- }
-
- // draw effect image
- CGContextSaveGState(outputContext);
- if (maskImage)
- CGContextClipToMask(outputContext, outputImageRectInPoints, maskImage.CGImage);
- CGContextDrawImage(outputContext, outputImageRectInPoints, effectCGImage);
- CGContextRestoreGState(outputContext);
-
- // Cleanup
- CGImageRelease(effectCGImage);
- free(outputBuffer->data);
- }
- else
- {
- // draw base image
- CGContextDrawImage(outputContext, outputImageRectInPoints, inputCGImage);
- }
-
-#if ENABLE_TINT
- // Add in color tint.
- if (tintColor)
- {
- CGContextSaveGState(outputContext);
- CGContextSetFillColorWithColor(outputContext, tintColor.CGColor);
- CGContextFillRect(outputContext, outputImageRectInPoints);
- CGContextRestoreGState(outputContext);
- }
-#endif
-
- // Output image is ready.
- UIImage *outputImage = UIGraphicsGetImageFromCurrentImageContext();
- UIGraphicsEndImageContext();
-
- return outputImage;
-#undef ENABLE_BLUR
-#undef ENABLE_SATURATION_ADJUSTMENT
-#undef ENABLE_TINT
-}
-
-
-// A description of how to compute the box kernel width from the Gaussian
-// radius (aka standard deviation) appears in the SVG spec:
-// http://www.w3.org/TR/SVG/filters.html#feGaussianBlurElement
-//
-// For larger values of 's' (s >= 2.0), an approximation can be used: Three
-// successive box-blurs build a piece-wise quadratic convolution kernel, which
-// approximates the Gaussian kernel to within roughly 3%.
-//
-// let d = floor(s * 3*sqrt(2*pi)/4 + 0.5)
-//
-// ... if d is odd, use three box-blurs of size 'd', centered on the output pixel.
-//
-- (CGFloat)gaussianBlurRadiusWithBlurRadius:(CGFloat)blurRadius
-{
- if (blurRadius - 2. < __FLT_EPSILON__) {
- blurRadius = 2.;
- }
- uint32_t radius = floor((blurRadius * 3. * sqrt(2 * M_PI) / 4 + 0.5) / 2);
- radius |= 1; // force radius to be odd so that the three box-blur methodology works.
- return radius;
-}
-
-
-//| ----------------------------------------------------------------------------
-// Helper function to handle deferred cleanup of a buffer.
-//
-void cleanupBuffer(void *userData, void *buf_data)
-{ free(buf_data); }
-
-@end
diff --git a/camerademo/camerademo/demo/UIImage/UIImage+Capture.h b/camerademo/camerademo/demo/UIImage/UIImage+Capture.h
deleted file mode 100755
index 36ccac3..0000000
--- a/camerademo/camerademo/demo/UIImage/UIImage+Capture.h
+++ /dev/null
@@ -1,35 +0,0 @@
-//
-// UIImage+Capture.h
-// iOS-Categories (https://github.com/shaojiankui/iOS-Categories)
-//
-// Created by Jakey on 15/1/10.
-// Copyright (c) 2015��� www.skyfox.org. All rights reserved.
-//
-
-#import <UIKit/UIKit.h>
-
-@interface UIImage (Capture)
-/**
- * @brief ������������view���������
- *
- * @param view ������view
- *
- * @return ������
- */
-+ (UIImage *)captureWithView:(UIView *)view;
-
-///���������������������������������
-+ (UIImage *)getImageWithSize:(CGRect)myImageRect FromImage:(UIImage *)bigImage;
-
-/**
- * @author Jakey
- *
- * @brief ������������view��������������� ������������������������
- *
- * @param aView ���������view
- * @param maxWidth ������������ 0���view������������
- *
- * @return ������
- */
-+ (UIImage *)screenshotWithView:(UIView *)aView limitWidth:(CGFloat)maxWidth;
-@end
diff --git a/camerademo/camerademo/demo/UIImage/UIImage+Capture.m b/camerademo/camerademo/demo/UIImage/UIImage+Capture.m
deleted file mode 100755
index e376c89..0000000
--- a/camerademo/camerademo/demo/UIImage/UIImage+Capture.m
+++ /dev/null
@@ -1,105 +0,0 @@
-//
-// UIImage+Capture.m
-// iOS-Categories (https://github.com/shaojiankui/iOS-Categories)
-//
-// Created by Jakey on 15/1/10.
-// Copyright (c) 2015��� www.skyfox.org. All rights reserved.
-//
-
-#import "UIImage+Capture.h"
-#import <QuartzCore/QuartzCore.h>
-@implementation UIImage (Capture)
-/**
- * @brief ������������view���������
- *
- * @param view ������view
- *
- * @return ������
- */
-+ (UIImage *)captureWithView:(UIView *)view
-{
- UIGraphicsBeginImageContextWithOptions(view.bounds.size, view.opaque, [UIScreen mainScreen].scale);
- // IOS7������������������
- if ([view respondsToSelector:@selector(drawViewHierarchyInRect:afterScreenUpdates:)]) {
- [view drawViewHierarchyInRect:view.bounds afterScreenUpdates:NO];
- } else { // IOS7���������������
- [view.layer renderInContext:UIGraphicsGetCurrentContext()];
- }
-
- UIImage *screenshot = UIGraphicsGetImageFromCurrentImageContext();
- UIGraphicsEndImageContext();
- return screenshot;
-}
-
-+ (UIImage *)getImageWithSize:(CGRect)myImageRect FromImage:(UIImage *)bigImage
-{
- //������bigImage
- //������myImageRect������������������
- CGImageRef imageRef = bigImage.CGImage;
- CGImageRef subImageRef = CGImageCreateWithImageInRect(imageRef, myImageRect);
- CGSize size;
- size.width = CGRectGetWidth(myImageRect);
- size.height = CGRectGetHeight(myImageRect);
- UIGraphicsBeginImageContext(size);
- CGContextRef context = UIGraphicsGetCurrentContext();
- CGContextDrawImage(context, myImageRect, subImageRef);
- UIImage* smallImage = [UIImage imageWithCGImage:subImageRef];
- CGImageRelease(subImageRef);
- UIGraphicsEndImageContext();
- return smallImage;
-}
-
-/**
- * @author Jakey
- *
- * @brief ������������view��������������� ������������������������
- *
- * @param aView ���������view
- * @param maxWidth ������������ 0���view������������
- *
- * @return ������
- */
-+ (UIImage *)screenshotWithView:(UIView *)aView limitWidth:(CGFloat)maxWidth{
- CGAffineTransform oldTransform = aView.transform;
-
- CGAffineTransform scaleTransform = CGAffineTransformIdentity;
- if (!isnan(maxWidth) && maxWidth>0) {
- CGFloat maxScale = maxWidth/CGRectGetWidth(aView.frame);
- CGAffineTransform transformScale = CGAffineTransformMakeScale(maxScale, maxScale);
- scaleTransform = CGAffineTransformConcat(oldTransform, transformScale);
-
- }
- if(!CGAffineTransformEqualToTransform(scaleTransform, CGAffineTransformIdentity)){
- aView.transform = scaleTransform;
- }
-
- CGRect actureFrame = aView.frame; //���������������������frame
- CGRect actureBounds= aView.bounds;//CGRectApplyAffineTransform();
-
- //begin
- UIGraphicsBeginImageContextWithOptions(actureFrame.size, NO, 0.0);
- CGContextRef context = UIGraphicsGetCurrentContext();
- CGContextSaveGState(context);
- // CGContextScaleCTM(UIGraphicsGetCurrentContext(), 1, -1);
- CGContextTranslateCTM(context,actureFrame.size.width/2, actureFrame.size.height/2);
- CGContextConcatCTM(context, aView.transform);
- CGPoint anchorPoint = aView.layer.anchorPoint;
- CGContextTranslateCTM(context,
- -actureBounds.size.width * anchorPoint.x,
- -actureBounds.size.height * anchorPoint.y);
- if([aView respondsToSelector:@selector(drawViewHierarchyInRect:afterScreenUpdates:)])
- {
- [aView drawViewHierarchyInRect:aView.bounds afterScreenUpdates:NO];
- }
- else
- {
- [aView.layer renderInContext:UIGraphicsGetCurrentContext()];
- }
- UIImage *screenshot = UIGraphicsGetImageFromCurrentImageContext();
- UIGraphicsEndImageContext();
- //end
- aView.transform = oldTransform;
-
- return screenshot;
-}
-@end
diff --git a/camerademo/camerademo/demo/UIImage/UIImage+Color.h b/camerademo/camerademo/demo/UIImage/UIImage+Color.h
deleted file mode 100755
index 10fefa6..0000000
--- a/camerademo/camerademo/demo/UIImage/UIImage+Color.h
+++ /dev/null
@@ -1,53 +0,0 @@
-//
-// UIImage+Color.h
-// iOS-Categories (https://github.com/shaojiankui/iOS-Categories)
-//
-// Created by Jakey on 14/12/15.
-// Copyright (c) 2014��� www.skyfox.org. All rights reserved.
-//
-
-#import <UIKit/UIKit.h>
-
-@interface UIImage (Color)
-/**
- * @brief ������������������������������
- *
- * @param color ������
- *
- * @return ������������
- */
-+ (UIImage *)imageWithColor:(UIColor *)color;
-/**
- * @brief ���������������������������
- *
- * @param point ���������
- *
- * @return ������
- */
-- (UIColor *)colorAtPoint:(CGPoint )point;
-//more accurate method ,colorAtPixel 1x1 pixel
-/**
- * @brief ������������������������
- *
- * @param point ���������
- *
- * @return ������
- */
-- (UIColor *)colorAtPixel:(CGPoint)point;
-/**
- * @brief ���������������������������������������
- *
- * @return ������������������������
- */
-- (BOOL)hasAlphaChannel;
-
-/**
- * @brief ���������������
- *
- * @param sourceImage ������
- *
- * @return ������������������
- */
-+ (UIImage*)covertToGrayImageFromImage:(UIImage*)sourceImage;
-
-@end
diff --git a/camerademo/camerademo/demo/UIImage/UIImage+Color.m b/camerademo/camerademo/demo/UIImage/UIImage+Color.m
deleted file mode 100755
index e005574..0000000
--- a/camerademo/camerademo/demo/UIImage/UIImage+Color.m
+++ /dev/null
@@ -1,175 +0,0 @@
-//
-// UIImage+Color.m
-// iOS-Categories (https://github.com/shaojiankui/iOS-Categories)
-//
-// Created by Jakey on 14/12/15.
-// Copyright (c) 2014��� www.skyfox.org. All rights reserved.
-//
-
-#import "UIImage+Color.h"
-
-@implementation UIImage (Color)
-/**
- * @brief ������������������������������
- *
- * @param color ������
- *
- * @return ������������
- */
-+ (UIImage *)imageWithColor:(UIColor *)color {
- CGRect rect = CGRectMake(0.0f, 0.0f, 1.0f, 1.0f);
- UIGraphicsBeginImageContext(rect.size);
- CGContextRef context = UIGraphicsGetCurrentContext();
-
- CGContextSetFillColorWithColor(context, [color CGColor]);
- CGContextFillRect(context, rect);
-
- UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
- UIGraphicsEndImageContext();
-
- return image;
-}
-/**
- * @brief ���������������������������
- *
- * @param point ���������
- *
- * @return ������
- */
-- (UIColor *)colorAtPoint:(CGPoint )point
-{
- if (point.x < 0 || point.y < 0) return nil;
-
- CGImageRef imageRef = self.CGImage;
- NSUInteger width = CGImageGetWidth(imageRef);
- NSUInteger height = CGImageGetHeight(imageRef);
- if (point.x >= width || point.y >= height) return nil;
-
- unsigned char *rawData = malloc(height * width * 4);
- if (!rawData) return nil;
-
- CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
- NSUInteger bytesPerPixel = 4;
- NSUInteger bytesPerRow = bytesPerPixel * width;
- NSUInteger bitsPerComponent = 8;
- CGContextRef context = CGBitmapContextCreate(rawData,
- width,
- height,
- bitsPerComponent,
- bytesPerRow,
- colorSpace,
- kCGImageAlphaPremultipliedLast
- | kCGBitmapByteOrder32Big);
- if (!context) {
- free(rawData);
- return nil;
- }
- CGColorSpaceRelease(colorSpace);
- CGContextDrawImage(context, CGRectMake(0, 0, width, height), imageRef);
- CGContextRelease(context);
-
- int byteIndex = (bytesPerRow * point.y) + point.x * bytesPerPixel;
- CGFloat red = (rawData[byteIndex] * 1.0) / 255.0;
- CGFloat green = (rawData[byteIndex + 1] * 1.0) / 255.0;
- CGFloat blue = (rawData[byteIndex + 2] * 1.0) / 255.0;
- CGFloat alpha = (rawData[byteIndex + 3] * 1.0) / 255.0;
-
- UIColor *result = nil;
- result = [UIColor colorWithRed:red green:green blue:blue alpha:alpha];
- free(rawData);
- return result;
-}
-/**
- * @brief ������������������������
- *
- * @param point ���������
- *
- * @return ������
- */
-- (UIColor *)colorAtPixel:(CGPoint)point
-{
- // Cancel if point is outside image coordinates
- if (!CGRectContainsPoint(CGRectMake(0.0f, 0.0f, self.size.width, self.size.height), point)) {
- return nil;
- }
-
- // Create a 1x1 pixel byte array and bitmap context to draw the pixel into.
- // Reference: http://stackoverflow.com/questions/1042830/retrieving-a-pixel-alpha-value-for-a-uiimage
- NSInteger pointX = trunc(point.x);
- NSInteger pointY = trunc(point.y);
- CGImageRef cgImage = self.CGImage;
- NSUInteger width = self.size.width;
- NSUInteger height = self.size.height;
- CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
- int bytesPerPixel = 4;
- int bytesPerRow = bytesPerPixel * 1;
- NSUInteger bitsPerComponent = 8;
- unsigned char pixelData[4] = { 0, 0, 0, 0 };
- CGContextRef context = CGBitmapContextCreate(pixelData,
- 1,
- 1,
- bitsPerComponent,
- bytesPerRow,
- colorSpace,
- kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
- CGColorSpaceRelease(colorSpace);
- CGContextSetBlendMode(context, kCGBlendModeCopy);
-
- // Draw the pixel we are interested in onto the bitmap context
- CGContextTranslateCTM(context, -pointX, pointY-(CGFloat)height);
- CGContextDrawImage(context, CGRectMake(0.0f, 0.0f, (CGFloat)width, (CGFloat)height), cgImage);
- CGContextRelease(context);
-
- // Convert color values [0..255] to floats [0.0..1.0]
- CGFloat red = (CGFloat)pixelData[0] / 255.0f;
- CGFloat green = (CGFloat)pixelData[1] / 255.0f;
- CGFloat blue = (CGFloat)pixelData[2] / 255.0f;
- CGFloat alpha = (CGFloat)pixelData[3] / 255.0f;
- return [UIColor colorWithRed:red green:green blue:blue alpha:alpha];
-}
-/**
- * @brief ���������������������������������������
- *
- * @return ������������������������
- */
-- (BOOL)hasAlphaChannel
-{
- CGImageAlphaInfo alpha = CGImageGetAlphaInfo(self.CGImage);
- return (alpha == kCGImageAlphaFirst ||
- alpha == kCGImageAlphaLast ||
- alpha == kCGImageAlphaPremultipliedFirst ||
- alpha == kCGImageAlphaPremultipliedLast);
-}
-
-/**
- * @brief ���������������
- *
- * @param sourceImage ������
- *
- * @return ������������������
- */
-
-+ (UIImage*)covertToGrayImageFromImage:(UIImage*)sourceImage
-{
- int width = sourceImage.size.width;
- int height = sourceImage.size.height;
-
- CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceGray();
- CGContextRef context = CGBitmapContextCreate (nil,width,height,8,0,colorSpace,kCGImageAlphaNone);
- CGColorSpaceRelease(colorSpace);
-
- if (context == NULL) {
- return nil;
- }
-
- CGContextDrawImage(context,CGRectMake(0, 0, width, height), sourceImage.CGImage);
- CGImageRef contextRef = CGBitmapContextCreateImage(context);
- UIImage *grayImage = [UIImage imageWithCGImage:contextRef];
- CGContextRelease(context);
- CGImageRelease(contextRef);
-
- return grayImage;
-}
-
-
-@end
diff --git a/camerademo/camerademo/demo/UIImage/UIImage+FX.h b/camerademo/camerademo/demo/UIImage/UIImage+FX.h
deleted file mode 100755
index 1eacf3d..0000000
--- a/camerademo/camerademo/demo/UIImage/UIImage+FX.h
+++ /dev/null
@@ -1,56 +0,0 @@
-//
-// UIImage+FX.h
-//
-// Version 1.2.3
-//
-// Created by Nick Lockwood on 31/10/2011.
-// Copyright (c) 2011 Charcoal Design
-//
-// Distributed under the permissive zlib License
-// Get the latest version from here:
-//
-// https://github.com/nicklockwood/FXImageView
-//
-// This software is provided 'as-is', without any express or implied
-// warranty. In no event will the authors be held liable for any damages
-// arising from the use of this software.
-//
-// Permission is granted to anyone to use this software for any purpose,
-// including commercial applications, and to alter it and redistribute it
-// freely, subject to the following restrictions:
-//
-// 1. The origin of this software must not be misrepresented; you must not
-// claim that you wrote the original software. If you use this software
-// in a product, an acknowledgment in the product documentation would be
-// appreciated but is not required.
-//
-// 2. Altered source versions must be plainly marked as such, and must not be
-// misrepresented as being the original software.
-//
-// 3. This notice may not be removed or altered from any source distribution.
-//
-
-#import <UIKit/UIKit.h>
-
-
-@interface UIImage (FX)
-
-- (UIImage *)imageCroppedToRect:(CGRect)rect;
-- (UIImage *)imageScaledToSize:(CGSize)size;
-- (UIImage *)imageScaledToFitSize:(CGSize)size;
-- (UIImage *)imageScaledToFillSize:(CGSize)size;
-- (UIImage *)imageCroppedAndScaledToSize:(CGSize)size
- contentMode:(UIViewContentMode)contentMode
- padToFit:(BOOL)padToFit;
-
-- (UIImage *)reflectedImageWithScale:(CGFloat)scale;
-- (UIImage *)imageWithReflectionWithScale:(CGFloat)scale gap:(CGFloat)gap alpha:(CGFloat)alpha;
-- (UIImage *)imageWithShadowColor:(UIColor *)color offset:(CGSize)offset blur:(CGFloat)blur;
-- (UIImage *)imageWithCornerRadius:(CGFloat)radius;
-- (UIImage *)imageWithAlpha:(CGFloat)alpha;
-- (UIImage *)imageWithMask:(UIImage *)maskImage;
-
-- (UIImage *)maskImageFromImageAlpha;
-
-
-@end
diff --git a/camerademo/camerademo/demo/UIImage/UIImage+FX.m b/camerademo/camerademo/demo/UIImage/UIImage+FX.m
deleted file mode 100755
index 904a1f3..0000000
--- a/camerademo/camerademo/demo/UIImage/UIImage+FX.m
+++ /dev/null
@@ -1,426 +0,0 @@
-//
-// UIImage+FX.m
-//
-// Version 1.2.3
-//
-// Created by Nick Lockwood on 31/10/2011.
-// Copyright (c) 2011 Charcoal Design
-//
-// Distributed under the permissive zlib License
-// Get the latest version from here:
-//
-// https://github.com/nicklockwood/FXImageView
-//
-// This software is provided 'as-is', without any express or implied
-// warranty. In no event will the authors be held liable for any damages
-// arising from the use of this software.
-//
-// Permission is granted to anyone to use this software for any purpose,
-// including commercial applications, and to alter it and redistribute it
-// freely, subject to the following restrictions:
-//
-// 1. The origin of this software must not be misrepresented; you must not
-// claim that you wrote the original software. If you use this software
-// in a product, an acknowledgment in the product documentation would be
-// appreciated but is not required.
-//
-// 2. Altered source versions must be plainly marked as such, and must not be
-// misrepresented as being the original software.
-//
-// 3. This notice may not be removed or altered from any source distribution.
-//
-
-#import "UIImage+FX.h"
-
-@implementation UIImage (FX)
-
-- (UIImage *)imageCroppedToRect:(CGRect)rect
-{
- //create drawing context
- UIGraphicsBeginImageContextWithOptions(rect.size, NO, 0.0f);
-
- //draw
- [self drawAtPoint:CGPointMake(-rect.origin.x, -rect.origin.y)];
-
- //capture resultant image
- UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
- UIGraphicsEndImageContext();
-
- //return image
- return image;
-}
-
-- (UIImage *)imageScaledToSize:(CGSize)size
-{
- //avoid redundant drawing
- if (CGSizeEqualToSize(self.size, size))
- {
- return self;
- }
-
- //create drawing context
- UIGraphicsBeginImageContextWithOptions(size, NO, 0.0f);
-
- //draw
- [self drawInRect:CGRectMake(0.0f, 0.0f, size.width, size.height)];
-
- //capture resultant image
- UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
- UIGraphicsEndImageContext();
-
- //return image
- return image;
-}
-
-- (UIImage *)imageScaledToFitSize:(CGSize)size
-{
- //calculate rect
- CGFloat aspect = self.size.width / self.size.height;
- if (size.width / aspect <= size.height)
- {
- return [self imageScaledToSize:CGSizeMake(size.width, size.width / aspect)];
- }
- else
- {
- return [self imageScaledToSize:CGSizeMake(size.height * aspect, size.height)];
- }
-}
-
-- (UIImage *)imageScaledToFillSize:(CGSize)size
-{
- if (CGSizeEqualToSize(self.size, size))
- {
- return self;
- }
- //calculate rect
- CGFloat aspect = self.size.width / self.size.height;
- if (size.width / aspect >= size.height)
- {
- return [self imageScaledToSize:CGSizeMake(size.width, size.width / aspect)];
- }
- else
- {
- return [self imageScaledToSize:CGSizeMake(size.height * aspect, size.height)];
- }
-}
-
-- (UIImage *)imageCroppedAndScaledToSize:(CGSize)size
- contentMode:(UIViewContentMode)contentMode
- padToFit:(BOOL)padToFit;
-{
- //calculate rect
- CGRect rect = CGRectZero;
- switch (contentMode)
- {
- case UIViewContentModeScaleAspectFit:
- {
- CGFloat aspect = self.size.width / self.size.height;
- if (size.width / aspect <= size.height)
- {
- rect = CGRectMake(0.0f, (size.height - size.width / aspect) / 2.0f, size.width, size.width / aspect);
- }
- else
- {
- rect = CGRectMake((size.width - size.height * aspect) / 2.0f, 0.0f, size.height * aspect, size.height);
- }
- break;
- }
- case UIViewContentModeScaleAspectFill:
- {
- CGFloat aspect = self.size.width / self.size.height;
- if (size.width / aspect >= size.height)
- {
- rect = CGRectMake(0.0f, (size.height - size.width / aspect) / 2.0f, size.width, size.width / aspect);
- }
- else
- {
- rect = CGRectMake((size.width - size.height * aspect) / 2.0f, 0.0f, size.height * aspect, size.height);
- }
- break;
- }
- case UIViewContentModeCenter:
- {
- rect = CGRectMake((size.width - self.size.width) / 2.0f, (size.height - self.size.height) / 2.0f, self.size.width, self.size.height);
- break;
- }
- case UIViewContentModeTop:
- {
- rect = CGRectMake((size.width - self.size.width) / 2.0f, 0.0f, self.size.width, self.size.height);
- break;
- }
- case UIViewContentModeBottom:
- {
- rect = CGRectMake((size.width - self.size.width) / 2.0f, size.height - self.size.height, self.size.width, self.size.height);
- break;
- }
- case UIViewContentModeLeft:
- {
- rect = CGRectMake(0.0f, (size.height - self.size.height) / 2.0f, self.size.width, self.size.height);
- break;
- }
- case UIViewContentModeRight:
- {
- rect = CGRectMake(size.width - self.size.width, (size.height - self.size.height) / 2.0f, self.size.width, self.size.height);
- break;
- }
- case UIViewContentModeTopLeft:
- {
- rect = CGRectMake(0.0f, 0.0f, self.size.width, self.size.height);
- break;
- }
- case UIViewContentModeTopRight:
- {
- rect = CGRectMake(size.width - self.size.width, 0.0f, self.size.width, self.size.height);
- break;
- }
- case UIViewContentModeBottomLeft:
- {
- rect = CGRectMake(0.0f, size.height - self.size.height, self.size.width, self.size.height);
- break;
- }
- case UIViewContentModeBottomRight:
- {
- rect = CGRectMake(size.width - self.size.width, size.height - self.size.height, self.size.width, self.size.height);
- break;
- }
- default:
- {
- rect = CGRectMake(0.0f, 0.0f, size.width, size.height);
- break;
- }
- }
-
- if (!padToFit)
- {
- //remove padding
- if (rect.size.width < size.width)
- {
- size.width = rect.size.width;
- rect.origin.x = 0.0f;
- }
- if (rect.size.height < size.height)
- {
- size.height = rect.size.height;
- rect.origin.y = 0.0f;
- }
- }
-
- //avoid redundant drawing
- if (CGSizeEqualToSize(self.size, size))
- {
- return self;
- }
-
- //create drawing context
- UIGraphicsBeginImageContextWithOptions(size, NO, 0.0f);
-
- //draw
- [self drawInRect:rect];
-
- //capture resultant image
- UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
- UIGraphicsEndImageContext();
-
- //return image
- return image;
-}
-
-+ (CGImageRef)gradientMask
-{
- static CGImageRef sharedMask = NULL;
- if (sharedMask == NULL)
- {
- //create gradient mask
- UIGraphicsBeginImageContextWithOptions(CGSizeMake(1, 256), YES, 0.0);
- CGContextRef gradientContext = UIGraphicsGetCurrentContext();
- CGFloat colors[] = {0.0, 1.0, 1.0, 1.0};
- CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceGray();
- CGGradientRef gradient = CGGradientCreateWithColorComponents(colorSpace, colors, NULL, 2);
- CGPoint gradientStartPoint = CGPointMake(0, 0);
- CGPoint gradientEndPoint = CGPointMake(0, 256);
- CGContextDrawLinearGradient(gradientContext, gradient, gradientStartPoint,
- gradientEndPoint, kCGGradientDrawsAfterEndLocation);
- sharedMask = CGBitmapContextCreateImage(gradientContext);
- CGGradientRelease(gradient);
- CGColorSpaceRelease(colorSpace);
- UIGraphicsEndImageContext();
- }
- return sharedMask;
-}
-
-- (UIImage *)reflectedImageWithScale:(CGFloat)scale
-{
- //get reflection dimensions
- CGFloat height = ceil(self.size.height * scale);
- CGSize size = CGSizeMake(self.size.width, height);
- CGRect bounds = CGRectMake(0.0f, 0.0f, size.width, size.height);
-
- //create drawing context
- UIGraphicsBeginImageContextWithOptions(size, NO, 0.0f);
- CGContextRef context = UIGraphicsGetCurrentContext();
-
- //clip to gradient
- CGContextClipToMask(context, bounds, [[self class] gradientMask]);
-
- //draw reflected image
- CGContextScaleCTM(context, 1.0f, -1.0f);
- CGContextTranslateCTM(context, 0.0f, -self.size.height);
- [self drawInRect:CGRectMake(0.0f, 0.0f, self.size.width, self.size.height)];
-
- //capture resultant image
- UIImage *reflection = UIGraphicsGetImageFromCurrentImageContext();
- UIGraphicsEndImageContext();
-
- //return reflection image
- return reflection;
-}
-
-- (UIImage *)imageWithReflectionWithScale:(CGFloat)scale gap:(CGFloat)gap alpha:(CGFloat)alpha
-{
- //get reflected image
- UIImage *reflection = [self reflectedImageWithScale:scale];
- CGFloat reflectionOffset = reflection.size.height + gap;
-
- //create drawing context
- UIGraphicsBeginImageContextWithOptions(CGSizeMake(self.size.width, self.size.height + reflectionOffset * 2.0f), NO, 0.0f);
-
- //draw reflection
- [reflection drawAtPoint:CGPointMake(0.0f, reflectionOffset + self.size.height + gap) blendMode:kCGBlendModeNormal alpha:alpha];
-
- //draw image
- [self drawAtPoint:CGPointMake(0.0f, reflectionOffset)];
-
- //capture resultant image
- UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
- UIGraphicsEndImageContext();
-
- //return image
- return image;
-}
-
-- (UIImage *)imageWithShadowColor:(UIColor *)color offset:(CGSize)offset blur:(CGFloat)blur
-{
- //get size
- //CGSize border = CGSizeMake(fabsf(offset.width) + blur, fabsf(offset.height) + blur);
- CGSize border = CGSizeMake(fabs(offset.width) + blur, fabs(offset.height) + blur);
-
- CGSize size = CGSizeMake(self.size.width + border.width * 2.0f, self.size.height + border.height * 2.0f);
-
- //create drawing context
- UIGraphicsBeginImageContextWithOptions(size, NO, 0.0f);
- CGContextRef context = UIGraphicsGetCurrentContext();
-
- //set up shadow
- CGContextSetShadowWithColor(context, offset, blur, color.CGColor);
-
- //draw with shadow
- [self drawAtPoint:CGPointMake(border.width, border.height)];
-
- //capture resultant image
- UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
- UIGraphicsEndImageContext();
-
- //return image
- return image;
-}
-
-- (UIImage *)imageWithCornerRadius:(CGFloat)radius
-{
- //create drawing context
- UIGraphicsBeginImageContextWithOptions(self.size, NO, 0.0f);
- CGContextRef context = UIGraphicsGetCurrentContext();
-
- //clip image
- CGContextBeginPath(context);
- CGContextMoveToPoint(context, 0.0f, radius);
- CGContextAddLineToPoint(context, 0.0f, self.size.height - radius);
- CGContextAddArc(context, radius, self.size.height - radius, radius, M_PI, M_PI / 2.0f, 1);
- CGContextAddLineToPoint(context, self.size.width - radius, self.size.height);
- CGContextAddArc(context, self.size.width - radius, self.size.height - radius, radius, M_PI / 2.0f, 0.0f, 1);
- CGContextAddLineToPoint(context, self.size.width, radius);
- CGContextAddArc(context, self.size.width - radius, radius, radius, 0.0f, -M_PI / 2.0f, 1);
- CGContextAddLineToPoint(context, radius, 0.0f);
- CGContextAddArc(context, radius, radius, radius, -M_PI / 2.0f, M_PI, 1);
- CGContextClip(context);
-
- //draw image
- [self drawAtPoint:CGPointZero];
-
- //capture resultant image
- UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
- UIGraphicsEndImageContext();
-
- //return image
- return image;
-}
-
-- (UIImage *)imageWithAlpha:(CGFloat)alpha
-{
- //create drawing context
- UIGraphicsBeginImageContextWithOptions(self.size, NO, 0.0f);
-
- //draw with alpha
- [self drawAtPoint:CGPointZero blendMode:kCGBlendModeNormal alpha:alpha];
-
- //capture resultant image
- UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
- UIGraphicsEndImageContext();
-
- //return image
- return image;
-}
-
-- (UIImage *)imageWithMask:(UIImage *)maskImage;
-{
- //create drawing context
- UIGraphicsBeginImageContextWithOptions(self.size, NO, 0.0f);
- CGContextRef context = UIGraphicsGetCurrentContext();
-
- //apply mask
- CGContextClipToMask(context, CGRectMake(0.0f, 0.0f, self.size.width, self.size.height), maskImage.CGImage);
-
- //draw image
- [self drawAtPoint:CGPointZero];
-
- //capture resultant image
- UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
- UIGraphicsEndImageContext();
-
- //return image
- return image;
-}
-
-- (UIImage *)maskImageFromImageAlpha
-{
- //get dimensions
- NSInteger width = CGImageGetWidth(self.CGImage);
- NSInteger height = CGImageGetHeight(self.CGImage);
-
- //create alpha image
- NSInteger bytesPerRow = ((width + 3) / 4) * 4;
- void *data = calloc(bytesPerRow * height, sizeof(unsigned char *));
- CGContextRef context = CGBitmapContextCreate(data, width, height, 8, bytesPerRow, NULL, kCGImageAlphaOnly);
- CGContextDrawImage(context, CGRectMake(0.0f, 0.0f, width, height), self.CGImage);
-
- //invert alpha pixels
- for (int y = 0; y < height; y++)
- {
- for (int x = 0; x < width; x++)
- {
- NSInteger index = y * bytesPerRow + x;
- ((unsigned char *)data)[index] = 255 - ((unsigned char *)data)[index];
- }
- }
-
- //create mask image
- CGImageRef maskRef = CGBitmapContextCreateImage(context);
- CGContextRelease(context);
- UIImage *mask = [UIImage imageWithCGImage:maskRef];
- CGImageRelease(maskRef);
- free(data);
-
- //return image
- return mask;
-}
-
-@end
diff --git a/camerademo/camerademo/demo/UIImage/UIImage+FileName.h b/camerademo/camerademo/demo/UIImage/UIImage+FileName.h
deleted file mode 100755
index 6e881f3..0000000
--- a/camerademo/camerademo/demo/UIImage/UIImage+FileName.h
+++ /dev/null
@@ -1,21 +0,0 @@
-//
-// UIImage+FileName.h
-// iOS-Categories (https://github.com/shaojiankui/iOS-Categories)
-//
-// Created by Jakey on 14/12/15.
-// Copyright (c) 2014��� www.skyfox.org. All rights reserved.
-//
-
-#import <UIKit/UIKit.h>
-
-@interface UIImage (FileName)
-/**
- * @brief ������bundle���������������������������
- *
- * @param name ���������
- *
- * @return ������������������
- */
-+ (UIImage *)imageWithFileName:(NSString *)name;
-
-@end
diff --git a/camerademo/camerademo/demo/UIImage/UIImage+FileName.m b/camerademo/camerademo/demo/UIImage/UIImage+FileName.m
deleted file mode 100755
index 6a468ee..0000000
--- a/camerademo/camerademo/demo/UIImage/UIImage+FileName.m
+++ /dev/null
@@ -1,57 +0,0 @@
-//
-// UIImage+FileName.m
-// iOS-Categories (https://github.com/shaojiankui/iOS-Categories)
-//
-// Created by Jakey on 14/12/15.
-// Copyright (c) 2014��� www.skyfox.org. All rights reserved.
-//
-#import "UIImage+FileName.h"
-
-
-@implementation UIImage (FileName)
-/**
- * @brief ������bundle���������������������������
- *
- * @param name ���������
- *
- * @return ������������������
- */
-+ (UIImage *)imageWithFileName:(NSString *)name {
- NSString *extension = @"png";
-
- NSArray *components = [name componentsSeparatedByString:@"."];
- if ([components count] >= 2) {
- NSUInteger lastIndex = components.count - 1;
- extension = [components objectAtIndex:lastIndex];
-
- name = [name substringToIndex:(name.length-(extension.length+1))];
- }
-
- // ���������Retina���������������������������������������Retina���������������������������������
- if ([UIScreen mainScreen].scale == 2.0) {
- name = [name stringByAppendingString:@"@2x"];
-
- NSString *path = [[NSBundle mainBundle] pathForResource:name ofType:extension];
- if (path != nil) {
- return [UIImage imageWithContentsOfFile:path];
- }
- }
-
- if ([UIScreen mainScreen].scale == 3.0) {
- name = [name stringByAppendingString:@"@3x"];
-
- NSString *path = [[NSBundle mainBundle] pathForResource:name ofType:extension];
- if (path != nil) {
- return [UIImage imageWithContentsOfFile:path];
- }
- }
-
- NSString *path = [[NSBundle mainBundle] pathForResource:name ofType:extension];
- if (path) {
- return [UIImage imageWithContentsOfFile:path];
- }
-
- return nil;
-}
-
-@end
diff --git a/camerademo/camerademo/demo/UIImage/UIImage+GIF.h b/camerademo/camerademo/demo/UIImage/UIImage+GIF.h
deleted file mode 100755
index 084f424..0000000
--- a/camerademo/camerademo/demo/UIImage/UIImage+GIF.h
+++ /dev/null
@@ -1,19 +0,0 @@
-//
-// UIImage+GIF.h
-// LBGIFImage
-//
-// Created by Laurin Brandner on 06.01.12.
-// Copyright (c) 2012 __MyCompanyName__. All rights reserved.
-//
-
-#import <UIKit/UIKit.h>
-
-@interface UIImage (GIF)
-
-+ (UIImage *)sd_animatedGIFNamed:(NSString *)name;
-
-+ (UIImage *)sd_animatedGIFWithData:(NSData *)data;
-
-- (UIImage *)sd_animatedImageByScalingAndCroppingToSize:(CGSize)size;
-
-@end
diff --git a/camerademo/camerademo/demo/UIImage/UIImage+GIF.m b/camerademo/camerademo/demo/UIImage/UIImage+GIF.m
deleted file mode 100755
index a703637..0000000
--- a/camerademo/camerademo/demo/UIImage/UIImage+GIF.m
+++ /dev/null
@@ -1,158 +0,0 @@
-//
-// UIImage+GIF.m
-// LBGIFImage
-//
-// Created by Laurin Brandner on 06.01.12.
-// Copyright (c) 2012 __MyCompanyName__. All rights reserved.
-//
-
-#import "UIImage+GIF.h"
-#import <ImageIO/ImageIO.h>
-
-@implementation UIImage (GIF)
-
-+ (UIImage *)sd_animatedGIFWithData:(NSData *)data {
- if (!data) {
- return nil;
- }
-
- CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFDataRef)data, NULL);
-
- size_t count = CGImageSourceGetCount(source);
-
- UIImage *animatedImage;
-
- if (count <= 1) {
- animatedImage = [[UIImage alloc] initWithData:data];
- }
- else {
- NSMutableArray *images = [NSMutableArray array];
-
- NSTimeInterval duration = 0.0f;
-
- for (size_t i = 0; i < count; i++) {
- CGImageRef image = CGImageSourceCreateImageAtIndex(source, i, NULL);
-
- duration += [self sd_frameDurationAtIndex:i source:source];
-
- [images addObject:[UIImage imageWithCGImage:image scale:[UIScreen mainScreen].scale orientation:UIImageOrientationUp]];
-
- CGImageRelease(image);
- }
-
- if (!duration) {
- duration = (1.0f / 10.0f) * count;
- }
-
- animatedImage = [UIImage animatedImageWithImages:images duration:duration];
- }
-
- CFRelease(source);
-
- return animatedImage;
-}
-
-+ (float)sd_frameDurationAtIndex:(NSUInteger)index source:(CGImageSourceRef)source {
- float frameDuration = 0.1f;
- CFDictionaryRef cfFrameProperties = CGImageSourceCopyPropertiesAtIndex(source, index, nil);
- NSDictionary *frameProperties = (__bridge NSDictionary *)cfFrameProperties;
- NSDictionary *gifProperties = frameProperties[(NSString *)kCGImagePropertyGIFDictionary];
-
- NSNumber *delayTimeUnclampedProp = gifProperties[(NSString *)kCGImagePropertyGIFUnclampedDelayTime];
- if (delayTimeUnclampedProp) {
- frameDuration = [delayTimeUnclampedProp floatValue];
- }
- else {
-
- NSNumber *delayTimeProp = gifProperties[(NSString *)kCGImagePropertyGIFDelayTime];
- if (delayTimeProp) {
- frameDuration = [delayTimeProp floatValue];
- }
- }
-
- // Many annoying ads specify a 0 duration to make an image flash as quickly as possible.
- // We follow Firefox's behavior and use a duration of 100 ms for any frames that specify
- // a duration of <= 10 ms. See <rdar://problem/7689300> and <http://webkit.org/b/36082>
- // for more information.
-
- if (frameDuration < 0.011f) {
- frameDuration = 0.100f;
- }
-
- CFRelease(cfFrameProperties);
- return frameDuration;
-}
-
-+ (UIImage *)sd_animatedGIFNamed:(NSString *)name {
- CGFloat scale = [UIScreen mainScreen].scale;
-
- if (scale > 1.0f) {
- NSString *retinaPath = [[NSBundle mainBundle] pathForResource:[name stringByAppendingString:@"@2x"] ofType:@"gif"];
-
- NSData *data = [NSData dataWithContentsOfFile:retinaPath];
-
- if (data) {
- return [UIImage sd_animatedGIFWithData:data];
- }
-
- NSString *path = [[NSBundle mainBundle] pathForResource:name ofType:@"gif"];
-
- data = [NSData dataWithContentsOfFile:path];
-
- if (data) {
- return [UIImage sd_animatedGIFWithData:data];
- }
-
- return [UIImage imageNamed:name];
- }
- else {
- NSString *path = [[NSBundle mainBundle] pathForResource:name ofType:@"gif"];
-
- NSData *data = [NSData dataWithContentsOfFile:path];
-
- if (data) {
- return [UIImage sd_animatedGIFWithData:data];
- }
-
- return [UIImage imageNamed:name];
- }
-}
-
-- (UIImage *)sd_animatedImageByScalingAndCroppingToSize:(CGSize)size {
- if (CGSizeEqualToSize(self.size, size) || CGSizeEqualToSize(size, CGSizeZero)) {
- return self;
- }
-
- CGSize scaledSize = size;
- CGPoint thumbnailPoint = CGPointZero;
-
- CGFloat widthFactor = size.width / self.size.width;
- CGFloat heightFactor = size.height / self.size.height;
- CGFloat scaleFactor = (widthFactor > heightFactor) ? widthFactor : heightFactor;
- scaledSize.width = self.size.width * scaleFactor;
- scaledSize.height = self.size.height * scaleFactor;
-
- if (widthFactor > heightFactor) {
- thumbnailPoint.y = (size.height - scaledSize.height) * 0.5;
- }
- else if (widthFactor < heightFactor) {
- thumbnailPoint.x = (size.width - scaledSize.width) * 0.5;
- }
-
- NSMutableArray *scaledImages = [NSMutableArray array];
-
- UIGraphicsBeginImageContextWithOptions(size, NO, 0.0);
-
- for (UIImage *image in self.images) {
- [image drawInRect:CGRectMake(thumbnailPoint.x, thumbnailPoint.y, scaledSize.width, scaledSize.height)];
- UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
-
- [scaledImages addObject:newImage];
- }
-
- UIGraphicsEndImageContext();
-
- return [UIImage animatedImageWithImages:scaledImages duration:self.duration];
-}
-
-@end
diff --git a/camerademo/camerademo/demo/UIImage/UIImage+Merge.h b/camerademo/camerademo/demo/UIImage/UIImage+Merge.h
deleted file mode 100755
index a7eeb5c..0000000
--- a/camerademo/camerademo/demo/UIImage/UIImage+Merge.h
+++ /dev/null
@@ -1,21 +0,0 @@
-//
-// UIImage+Merge.h
-// iOS-Categories (https://github.com/shaojiankui/iOS-Categories)
-//
-// Created by Jakey on 14/12/30.
-// Copyright (c) 2014��� www.skyfox.org. All rights reserved.
-//
-
-#import <UIKit/UIKit.h>
-
-@interface UIImage (Merge)
-/**
- * @brief ������������������
- *
- * @param firstImage ������������
- * @param secondImage ������������
- *
- * @return ���������������
- */
-+ (UIImage*)mergeImage:(UIImage*)firstImage withImage:(UIImage*)secondImage;
-@end
diff --git a/camerademo/camerademo/demo/UIImage/UIImage+Merge.m b/camerademo/camerademo/demo/UIImage/UIImage+Merge.m
deleted file mode 100755
index b3dc743..0000000
--- a/camerademo/camerademo/demo/UIImage/UIImage+Merge.m
+++ /dev/null
@@ -1,35 +0,0 @@
-//
-// UIImage+Merge.m
-// iOS-Categories (https://github.com/shaojiankui/iOS-Categories)
-//
-// Created by Jakey on 14/12/30.
-// Copyright (c) 2014��� www.skyfox.org. All rights reserved.
-//
-
-#import "UIImage+Merge.h"
-
-@implementation UIImage (Merge)
-/**
- * @brief ������������������
- *
- * @param firstImage ������������
- * @param secondImage ������������
- *
- * @return ���������������
- */
-+ (UIImage*)mergeImage:(UIImage*)firstImage withImage:(UIImage*)secondImage {
- CGImageRef firstImageRef = firstImage.CGImage;
- CGFloat firstWidth = CGImageGetWidth(firstImageRef);
- CGFloat firstHeight = CGImageGetHeight(firstImageRef);
- CGImageRef secondImageRef = secondImage.CGImage;
- CGFloat secondWidth = CGImageGetWidth(secondImageRef);
- CGFloat secondHeight = CGImageGetHeight(secondImageRef);
- CGSize mergedSize = CGSizeMake(MAX(firstWidth, secondWidth), MAX(firstHeight, secondHeight));
- UIGraphicsBeginImageContext(mergedSize);
- [firstImage drawInRect:CGRectMake(0, 0, firstWidth, firstHeight)];
- [secondImage drawInRect:CGRectMake(0, 0, secondWidth, secondHeight)];
- UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
- UIGraphicsEndImageContext();
- return image;
-}
-@end
diff --git a/camerademo/camerademo/demo/UIImage/UIImage+Orientation.h b/camerademo/camerademo/demo/UIImage/UIImage+Orientation.h
deleted file mode 100755
index 89a3fd9..0000000
--- a/camerademo/camerademo/demo/UIImage/UIImage+Orientation.h
+++ /dev/null
@@ -1,69 +0,0 @@
-//
-// UIImage+Orientation.h
-// iOS-Categories (https://github.com/shaojiankui/iOS-Categories)
-//
-// Created by Jakey on 15/1/4.
-// Copyright (c) 2015��� www.skyfox.org. All rights reserved.
-//
-
-#import <UIKit/UIKit.h>
-//CGFloat DegreesToRadiansForOrientation(CGFloat degrees) {return degrees * M_PI / 180;};
-//CGFloat RadiansToDegreesForOrientation(CGFloat radians) {return radians * 180/M_PI;};
-@interface UIImage (Orientation)
-/**
- * @brief ���������������������
- *
- * @param srcImg ������
- *
- * @return ������������������������
- */
-+ (UIImage *)fixOrientation:(UIImage *)srcImg;
-/**
- * @brief ������������
- *
- * @param degrees ������
- *
- * @return ���������������
- */
-- (UIImage *)imageRotatedByDegrees:(CGFloat)degrees;
-
-/**
- * @brief ������������
- *
- * @param degrees ������
- *
- * @return ���������������
- */
-- (UIImage *)imageRotatedByRadians:(CGFloat)radians;
-
-/**
- * @brief ������������
- *
- * @return ������������������
- */
-- (UIImage *)flipVertical;
-/**
- * @brief ������������
- *
- * @return ������������������
- */
-- (UIImage *)flipHorizontal;
-
-/**
- * @brief ���������������
- *
- * @param degrees ������
- *
- * @return ������
- */
-+(CGFloat)degreesToRadians:(CGFloat)degrees;
-/**
- * @brief ���������������
- *
- * @param radians ������
- *
- * @return ������
- */
-+(CGFloat)radiansToDegrees:(CGFloat)radians;
-
-@end
diff --git a/camerademo/camerademo/demo/UIImage/UIImage+Orientation.m b/camerademo/camerademo/demo/UIImage/UIImage+Orientation.m
deleted file mode 100755
index 98a1a98..0000000
--- a/camerademo/camerademo/demo/UIImage/UIImage+Orientation.m
+++ /dev/null
@@ -1,181 +0,0 @@
-//
-// UIImage+Orientation.m
-// iOS-Categories (https://github.com/shaojiankui/iOS-Categories)
-//
-// Created by Jakey on 15/1/4.
-// Copyright (c) 2015��� www.skyfox.org. All rights reserved.
-//
-
-#import "UIImage+Orientation.h"
-
-@implementation UIImage (Orientation)
-/**
- * @brief ���������������������
- *
- * @param srcImg ������
- *
- * @return ������������������������
- */
-+ (UIImage *)fixOrientation:(UIImage *)srcImg {
- if (srcImg.imageOrientation == UIImageOrientationUp) return srcImg;
- CGAffineTransform transform = CGAffineTransformIdentity;
- switch (srcImg.imageOrientation) {
- case UIImageOrientationDown:
- case UIImageOrientationDownMirrored:
- transform = CGAffineTransformTranslate(transform, srcImg.size.width, srcImg.size.height);
- transform = CGAffineTransformRotate(transform, M_PI);
- break;
- case UIImageOrientationLeft:
- case UIImageOrientationLeftMirrored:
- transform = CGAffineTransformTranslate(transform, srcImg.size.width, 0);
- transform = CGAffineTransformRotate(transform, M_PI_2);
- break;
- case UIImageOrientationRight:
- case UIImageOrientationRightMirrored:
- transform = CGAffineTransformTranslate(transform, 0, srcImg.size.height);
- transform = CGAffineTransformRotate(transform, -M_PI_2);
- break;
- case UIImageOrientationUp:
- case UIImageOrientationUpMirrored:
- break;
- }
- switch (srcImg.imageOrientation) {
- case UIImageOrientationUpMirrored:
- case UIImageOrientationDownMirrored:
- transform = CGAffineTransformTranslate(transform, srcImg.size.width, 0);
- transform = CGAffineTransformScale(transform, -1, 1);
- break;
- case UIImageOrientationLeftMirrored:
- case UIImageOrientationRightMirrored:
- transform = CGAffineTransformTranslate(transform, srcImg.size.height, 0);
- transform = CGAffineTransformScale(transform, -1, 1);
- break;
- case UIImageOrientationUp:
- case UIImageOrientationDown:
- case UIImageOrientationLeft:
- case UIImageOrientationRight:
- break;
- }
- CGContextRef ctx = CGBitmapContextCreate(NULL, srcImg.size.width, srcImg.size.height,
- CGImageGetBitsPerComponent(srcImg.CGImage), 0,
- CGImageGetColorSpace(srcImg.CGImage),
- CGImageGetBitmapInfo(srcImg.CGImage));
- CGContextConcatCTM(ctx, transform);
- switch (srcImg.imageOrientation) {
- case UIImageOrientationLeft:
- case UIImageOrientationLeftMirrored:
- case UIImageOrientationRight:
- case UIImageOrientationRightMirrored:
- CGContextDrawImage(ctx, CGRectMake(0,0,srcImg.size.height,srcImg.size.width), srcImg.CGImage);
- break;
- default:
- CGContextDrawImage(ctx, CGRectMake(0,0,srcImg.size.width,srcImg.size.height), srcImg.CGImage);
- break;
- }
- CGImageRef cgimg = CGBitmapContextCreateImage(ctx);
- UIImage *img = [UIImage imageWithCGImage:cgimg];
- CGContextRelease(ctx);
- CGImageRelease(cgimg);
- return img;
-}
-
-- (UIImage *)flip:(BOOL)isHorizontal {
- CGRect rect = CGRectMake(0, 0, self.size.width, self.size.height);
- UIGraphicsBeginImageContextWithOptions(rect.size, NO, 0);
-
- CGContextRef ctx = UIGraphicsGetCurrentContext();
- CGContextClipToRect(ctx, rect);
- if (isHorizontal) {
- CGContextRotateCTM(ctx, M_PI);
- CGContextTranslateCTM(ctx, -rect.size.width, -rect.size.height);
- }
- CGContextDrawImage(ctx, rect, self.CGImage);
- UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
- UIGraphicsEndImageContext();
- return image;
-}
-/**
- * @brief ������������
- *
- * @return ������������������
- */
-- (UIImage *)flipVertical {
- return [self flip:NO];
-}
-/**
- * @brief ������������
- *
- * @return ������������������
- */
-- (UIImage *)flipHorizontal {
- return [self flip:YES];
-}
-/**
- * @brief ������������
- *
- * @param degrees ������
- *
- * @return ���������������
- */
-- (UIImage *)imageRotatedByRadians:(CGFloat)radians
-{
- return [self imageRotatedByDegrees:[UIImage radiansToDegrees:radians]];
-}
-/**
- * @brief ������������
- *
- * @param degrees ���
- *
- * @return ���������������
- */
-- (UIImage *)imageRotatedByDegrees:(CGFloat)degrees
-{
- // calculate the size of the rotated view's containing box for our drawing space
- UIView *rotatedViewBox = [[UIView alloc] initWithFrame:CGRectMake(0,0,self.size.width, self.size.height)];
- CGAffineTransform t = CGAffineTransformMakeRotation([UIImage degreesToRadians:degrees]);
- rotatedViewBox.transform = t;
- CGSize rotatedSize = rotatedViewBox.frame.size;
-
- // Create the bitmap context
- UIGraphicsBeginImageContext(rotatedSize);
- CGContextRef bitmap = UIGraphicsGetCurrentContext();
-
- // Move the origin to the middle of the image so we will rotate and scale around the center.
- CGContextTranslateCTM(bitmap, rotatedSize.width/2, rotatedSize.height/2);
-
- // // Rotate the image context
- CGContextRotateCTM(bitmap, [UIImage degreesToRadians:degrees]);
-
- // Now, draw the rotated/scaled image into the context
- CGContextScaleCTM(bitmap, 1.0, -1.0);
- CGContextDrawImage(bitmap, CGRectMake(-self.size.width / 2, -self.size.height / 2, self.size.width, self.size.height), [self CGImage]);
-
- UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
- UIGraphicsEndImageContext();
- return newImage;
-
-}
-
-/**
- * @brief ���������������
- *
- * @param degrees ������
- *
- * @return ������
- */
-+(CGFloat)degreesToRadians:(CGFloat)degrees
-{
- return degrees * M_PI / 180;
-}
-/**
- * @brief ���������������
- *
- * @param radians ������
- *
- * @return ������
- */
-+(CGFloat)radiansToDegrees:(CGFloat)radians
-{
- return radians * 180/M_PI;
-}
-@end
diff --git a/camerademo/camerademo/demo/UIImage/UIImage+PDF.h b/camerademo/camerademo/demo/UIImage/UIImage+PDF.h
deleted file mode 100755
index 27db567..0000000
--- a/camerademo/camerademo/demo/UIImage/UIImage+PDF.h
+++ /dev/null
@@ -1,13 +0,0 @@
-//
-// UIImage+PDF.h
-// iOS-Categories (https://github.com/shaojiankui/iOS-Categories)
-//
-// Created by Jakey on 15/5/22.
-// Copyright (c) 2015��� www.skyfox.org. All rights reserved.
-//
-
-#import <UIKit/UIKit.h>
-
-@interface UIImage (PDF)
-
-@end
diff --git a/camerademo/camerademo/demo/UIImage/UIImage+PDF.m b/camerademo/camerademo/demo/UIImage/UIImage+PDF.m
deleted file mode 100755
index e6ca42f..0000000
--- a/camerademo/camerademo/demo/UIImage/UIImage+PDF.m
+++ /dev/null
@@ -1,13 +0,0 @@
-//
-// UIImage+PDF.m
-// iOS-Categories (https://github.com/shaojiankui/iOS-Categories)
-//
-// Created by Jakey on 15/5/22.
-// Copyright (c) 2015��� www.skyfox.org. All rights reserved.
-//
-
-#import "UIImage+PDF.h"
-
-@implementation UIImage (PDF)
-
-@end
diff --git a/camerademo/camerademo/demo/UIImage/UIImage+RemoteSize.h b/camerademo/camerademo/demo/UIImage/UIImage+RemoteSize.h
deleted file mode 100755
index 8d4d1f2..0000000
--- a/camerademo/camerademo/demo/UIImage/UIImage+RemoteSize.h
+++ /dev/null
@@ -1,29 +0,0 @@
-//
-// UIImage+RemoteSize.h
-// iOS-Categories (https://github.com/shaojiankui/iOS-Categories)
-//
-// Created by Jakey on 15/1/27.
-// Copyright (c) 2015��� www.skyfox.org. All rights reserved.
-//
-
-#import <UIKit/UIKit.h>
-
-typedef void (^UIImageSizeRequestCompleted) (NSURL* imgURL, CGSize size);
-
-@interface UIImage (RemoteSize)
-/**
- * @brief ���������������������������
- *
- * @param imgURL ������url
- * @param completion ������������
- */
-+ (void)requestSizeNoHeader:(NSURL*)imgURL completion:(UIImageSizeRequestCompleted)completion;
-/**
- * @brief ���header������������������������������ (���������������������)
- *
- * @param imgURL ������url
- * @param completion ������������
- */
-//+ (void)requestSizeWithHeader:(NSURL*)imgURL completion:(UIImageSizeRequestCompleted)completion;
-
-@end
\ No newline at end of file
diff --git a/camerademo/camerademo/demo/UIImage/UIImage+RemoteSize.m b/camerademo/camerademo/demo/UIImage/UIImage+RemoteSize.m
deleted file mode 100755
index 82d4085..0000000
--- a/camerademo/camerademo/demo/UIImage/UIImage+RemoteSize.m
+++ /dev/null
@@ -1,270 +0,0 @@
-//
-// UIImage+RemoteSize.m
-// iOS-Categories (https://github.com/shaojiankui/iOS-Categories)
-//
-// Created by Jakey on 15/1/27.
-// Copyright (c) 2015��� www.skyfox.org. All rights reserved.
-//
-
-#import "UIImage+RemoteSize.h"
-
-#import <objc/runtime.h>
-
-static char *kSizeRequestDataKey = "NSURL.sizeRequestData";
-static char *kSizeRequestTypeKey = "NSURL.sizeRequestType";
-static char *kSizeRequestCompletionKey = "NSURL.sizeRequestCompletion";
-
-typedef uint32_t dword;
-
-@interface NSURL (RemoteSize)
-@property (nonatomic, strong) NSMutableData* sizeRequestData;
-@property (nonatomic, strong) NSString* sizeRequestType;
-@property (nonatomic, copy) UIImageSizeRequestCompleted sizeRequestCompletion;
-@end
-
-@implementation NSURL (RemoteSize)
-
-- (void)setSizeRequestCompletion: (UIImageSizeRequestCompleted) block {
- objc_setAssociatedObject(self, &kSizeRequestCompletionKey, block, OBJC_ASSOCIATION_COPY);
-}
-
-- (UIImageSizeRequestCompleted)sizeRequestCompletion {
- return objc_getAssociatedObject(self, &kSizeRequestCompletionKey);
-}
-
-- (void)setSizeRequestData:(NSMutableData *)sizeRequestData {
- objc_setAssociatedObject(self, &kSizeRequestDataKey, sizeRequestData, OBJC_ASSOCIATION_RETAIN);
-}
-
-- (NSMutableData*)sizeRequestData {
- return objc_getAssociatedObject(self, &kSizeRequestDataKey);
-}
-
-- (void)setSizeRequestType:(NSString *)sizeRequestType {
- objc_setAssociatedObject(self, &kSizeRequestTypeKey, sizeRequestType, OBJC_ASSOCIATION_RETAIN);
-}
-
-- (NSString*)sizeRequestType {
- return objc_getAssociatedObject(self, &kSizeRequestTypeKey);
-}
-
-#pragma mark - NSURLConnectionDelegate
-- (void)connection:(NSURLConnection*)connection didReceiveResponse:(NSURLResponse *)response {
- [self.sizeRequestData setLength: 0]; //Redirected => reset data
-}
-
-- (void)connection:(NSURLConnection*)connection didReceiveData:(NSData *)data {
- NSMutableData* receivedData = self.sizeRequestData;
-
- if( !receivedData ) {
- receivedData = [NSMutableData data];
- self.sizeRequestData = receivedData;
- }
-
- [receivedData appendData: data];
-
- //Parse metadata
- const unsigned char* cString = [receivedData bytes];
- const NSInteger length = [receivedData length];
-
- const char pngSignature[8] = {137, 80, 78, 71, 13, 10, 26, 10};
- const char bmpSignature[2] = {66, 77};
- const char gifSignature[2] = {71, 73};
- const char jpgSignature[2] = {255, 216};
-
- if(!self.sizeRequestType ) {
- if( memcmp(pngSignature, cString, 8) == 0 ) {
- self.sizeRequestType = @"PNG";
- }
- else if( memcmp(bmpSignature, cString, 2) == 0 ) {
- self.sizeRequestType = @"BMP";
- }
- else if( memcmp(jpgSignature, cString, 2) == 0 ) {
- self.sizeRequestType = @"JPG";
- }
- else if( memcmp(gifSignature, cString, 2) == 0 ) {
- self.sizeRequestType = @"GIF";
- }
- }
-
- if( [self.sizeRequestType isEqualToString: @"PNG"] ) {
- char type[5];
- int offset = 8;
-
- dword chunkSize = 0;
- int chunkSizeSize = sizeof(chunkSize);
-
- if( offset+chunkSizeSize > length )
- return;
-
- memcpy(&chunkSize, cString+offset, chunkSizeSize);
- chunkSize = OSSwapInt32(chunkSize);
- offset += chunkSizeSize;
-
- if( offset + chunkSize > length )
- return;
-
- memcpy(&type, cString+offset, 4); type[4]='\0';
- offset += 4;
-
- if( strcmp(type, "IHDR") == 0 ) { //Should always be first
- dword width = 0, height = 0;
- memcpy(&width, cString+offset, 4);
- offset += 4;
- width = OSSwapInt32(width);
-
- memcpy(&height, cString+offset, 4);
- offset += 4;
- height = OSSwapInt32(height);
-
- if( self.sizeRequestCompletion ) {
- self.sizeRequestCompletion(self, CGSizeMake(width, height));
- }
-
- self.sizeRequestCompletion = nil;
-
- [connection cancel];
- }
- }
- else if( [self.sizeRequestType isEqualToString: @"BMP"] ) {
- int offset = 18;
- dword width = 0, height = 0;
- memcpy(&width, cString+offset, 4);
- offset += 4;
-
- memcpy(&height, cString+offset, 4);
- offset += 4;
-
- if( self.sizeRequestCompletion ) {
- self.sizeRequestCompletion(self, CGSizeMake(width, height));
- }
-
- self.sizeRequestCompletion = nil;
-
- [connection cancel];
- }
- else if( [self.sizeRequestType isEqualToString: @"JPG"] ) {
- int offset = 4;
- dword block_length = cString[offset]*256 + cString[offset+1];
-
- while (offset<length) {
- offset += block_length;
-
- if( offset >= length )
- break;
- if( cString[offset] != 0xFF )
- break;
- if( cString[offset+1] == 0xC0 ||
- cString[offset+1] == 0xC1 ||
- cString[offset+1] == 0xC2 ||
- cString[offset+1] == 0xC3 ||
- cString[offset+1] == 0xC5 ||
- cString[offset+1] == 0xC6 ||
- cString[offset+1] == 0xC7 ||
- cString[offset+1] == 0xC9 ||
- cString[offset+1] == 0xCA ||
- cString[offset+1] == 0xCB ||
- cString[offset+1] == 0xCD ||
- cString[offset+1] == 0xCE ||
- cString[offset+1] == 0xCF ) {
-
- dword width = 0, height = 0;
-
- height = cString[offset+5]*256 + cString[offset+6];
- width = cString[offset+7]*256 + cString[offset+8];
-
- if( self.sizeRequestCompletion ) {
- self.sizeRequestCompletion(self, CGSizeMake(width, height));
- }
-
- self.sizeRequestCompletion = nil;
-
- [connection cancel];
-
- }
- else {
- offset += 2;
- block_length = cString[offset]*256 + cString[offset+1];
- }
-
- }
- }
- else if( [self.sizeRequestType isEqualToString: @"GIF"] ) {
- int offset = 6;
- dword width = 0, height = 0;
- memcpy(&width, cString+offset, 2);
- offset += 2;
-
- memcpy(&height, cString+offset, 2);
- offset += 2;
-
- if( self.sizeRequestCompletion ) {
- self.sizeRequestCompletion(self, CGSizeMake(width, height));
- }
-
- self.sizeRequestCompletion = nil;
-
- [connection cancel];
- }
-}
-
--(void)connection:(NSURLConnection*)connection didFailWithError:(NSError *)error {
- if( self.sizeRequestCompletion )
- self.sizeRequestCompletion(self, CGSizeZero);
-}
-
--(NSCachedURLResponse*)connection:(NSURLConnection *)connection willCacheResponse:(NSCachedURLResponse *)cachedResponse {
- return cachedResponse;
-}
-
-- (void)connectionDidFinishLoading: (NSURLConnection *)connection {
- // Basically, we failed to obtain the image size using metadata and the
- // entire image was downloaded...
-
- if(!self.sizeRequestData.length) {
- self.sizeRequestData = nil;
- }
- else {
- //Try parse to UIImage
- UIImage* image = [UIImage imageWithData: self.sizeRequestData];
-
- if( self.sizeRequestCompletion && image) {
- self.sizeRequestCompletion(self, [image size]);
- return;
- }
- }
-
- self.sizeRequestCompletion(self, CGSizeZero);
-}
-
-@end
-
-@implementation UIImage (RemoteSize)
-
-+ (void)requestSizeNoHeader:(NSURL*)imgURL completion:(UIImageSizeRequestCompleted)completion{
-
- if([imgURL isFileURL] ) {
- //Load from file stream
- }
- else {
- imgURL.sizeRequestCompletion = completion;
-
- NSURLRequest* request = [NSURLRequest requestWithURL:imgURL];
- NSURLConnection* conn = [NSURLConnection connectionWithRequest: request delegate: imgURL];
- [conn scheduleInRunLoop: [NSRunLoop mainRunLoop] forMode: NSDefaultRunLoopMode];
- [conn start];
- }
-}
-
-
-+ (void)requestSizeWithHeader:(NSURL*)imgURL completion:(UIImageSizeRequestCompleted)completion{
-// NSURLRequest* request = [NSURLRequest requestWithURL:imgURL];
-//
-// [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *resp, NSData *d, NSError *e) {
-// NSLog(@"respone%@", [(NSHTTPURLResponse*)resp allHeaderFields]);
-//
-//
-// }];
-}
-
-@end
diff --git a/camerademo/camerademo/demo/UIImage/UIImage+Resize.h b/camerademo/camerademo/demo/UIImage/UIImage+Resize.h
deleted file mode 100755
index 64610b1..0000000
--- a/camerademo/camerademo/demo/UIImage/UIImage+Resize.h
+++ /dev/null
@@ -1,21 +0,0 @@
-// UIImage+Resize.h
-// Created by Trevor Harmon on 8/5/09.
-// Free for personal or commercial use, with or without modification.
-// No warranty is expressed or implied.
-
-// Extends the UIImage class to support resizing/cropping
-#import <UIKit/UIKit.h>
-
-@interface UIImage (Resize)
-
-- (UIImage *)croppedImage:(CGRect)bounds;
-- (UIImage *)thumbnailImage:(NSInteger)thumbnailSize
- transparentBorder:(NSUInteger)borderSize
- cornerRadius:(NSUInteger)cornerRadius
- interpolationQuality:(CGInterpolationQuality)quality;
-- (UIImage *)resizedImage:(CGSize)newSize
- interpolationQuality:(CGInterpolationQuality)quality;
-- (UIImage *)resizedImageWithContentMode:(UIViewContentMode)contentMode
- bounds:(CGSize)bounds
- interpolationQuality:(CGInterpolationQuality)quality;
-@end
diff --git a/camerademo/camerademo/demo/UIImage/UIImage+Resize.m b/camerademo/camerademo/demo/UIImage/UIImage+Resize.m
deleted file mode 100755
index affbf31..0000000
--- a/camerademo/camerademo/demo/UIImage/UIImage+Resize.m
+++ /dev/null
@@ -1,200 +0,0 @@
-// UIImage+Resize.m
-// Created by Trevor Harmon on 8/5/09.
-// Free for personal or commercial use, with or without modification.
-// No warranty is expressed or implied.
-
-#import "UIImage+Resize.h"
-#import "UIImage+RoundedCorner.h"
-#import "UIImage+Alpha.h"
-
-// Private helper methods
-@interface UIImage (ResizePrivateMethods)
-- (UIImage *)resizedImage:(CGSize)newSize
- transform:(CGAffineTransform)transform
- drawTransposed:(BOOL)transpose
- interpolationQuality:(CGInterpolationQuality)quality;
-- (CGAffineTransform)transformForOrientation:(CGSize)newSize;
-@end
-
-@implementation UIImage (Resize)
-
-// Returns a copy of this image that is cropped to the given bounds.
-// The bounds will be adjusted using CGRectIntegral.
-// This method ignores the image's imageOrientation setting.
-- (UIImage *)croppedImage:(CGRect)bounds {
- CGImageRef imageRef = CGImageCreateWithImageInRect([self CGImage], bounds);
- UIImage *croppedImage = [UIImage imageWithCGImage:imageRef];
- CGImageRelease(imageRef);
- return croppedImage;
-}
-
-// Returns a copy of this image that is squared to the thumbnail size.
-// If transparentBorder is non-zero, a transparent border of the given size will be added around the edges of the thumbnail. (Adding a transparent border of at least one pixel in size has the side-effect of antialiasing the edges of the image when rotating it using Core Animation.)
-- (UIImage *)thumbnailImage:(NSInteger)thumbnailSize
- transparentBorder:(NSUInteger)borderSize
- cornerRadius:(NSUInteger)cornerRadius
- interpolationQuality:(CGInterpolationQuality)quality {
- UIImage *resizedImage = [self resizedImageWithContentMode:UIViewContentModeScaleAspectFill
- bounds:CGSizeMake(thumbnailSize, thumbnailSize)
- interpolationQuality:quality];
-
- // Crop out any part of the image that's larger than the thumbnail size
- // The cropped rect must be centered on the resized image
- // Round the origin points so that the size isn't altered when CGRectIntegral is later invoked
- CGRect cropRect = CGRectMake(round((resizedImage.size.width - thumbnailSize) / 2),
- round((resizedImage.size.height - thumbnailSize) / 2),
- thumbnailSize,
- thumbnailSize);
- UIImage *croppedImage = [resizedImage croppedImage:cropRect];
-
- UIImage *transparentBorderImage = borderSize ? [croppedImage transparentBorderImage:borderSize] : croppedImage;
-
- return [transparentBorderImage roundedCornerImage:cornerRadius borderSize:borderSize];
-}
-
-// Returns a rescaled copy of the image, taking into account its orientation
-// The image will be scaled disproportionately if necessary to fit the bounds specified by the parameter
-- (UIImage *)resizedImage:(CGSize)newSize interpolationQuality:(CGInterpolationQuality)quality {
- BOOL drawTransposed;
-
- switch (self.imageOrientation) {
- case UIImageOrientationLeft:
- case UIImageOrientationLeftMirrored:
- case UIImageOrientationRight:
- case UIImageOrientationRightMirrored:
- drawTransposed = YES;
- break;
-
- default:
- drawTransposed = NO;
- }
-
- return [self resizedImage:newSize
- transform:[self transformForOrientation:newSize]
- drawTransposed:drawTransposed
- interpolationQuality:quality];
-}
-
-// Resizes the image according to the given content mode, taking into account the image's orientation
-- (UIImage *)resizedImageWithContentMode:(UIViewContentMode)contentMode
- bounds:(CGSize)bounds
- interpolationQuality:(CGInterpolationQuality)quality {
- CGFloat horizontalRatio = bounds.width / self.size.width;
- CGFloat verticalRatio = bounds.height / self.size.height;
- CGFloat ratio;
-
- switch (contentMode) {
- case UIViewContentModeScaleAspectFill:
- ratio = MAX(horizontalRatio, verticalRatio);
- break;
-
- case UIViewContentModeScaleAspectFit:
- ratio = MIN(horizontalRatio, verticalRatio);
- break;
-
- default:
- [NSException raise:NSInvalidArgumentException format:@"Unsupported content mode: %@", @(contentMode)];
- }
-
- CGSize newSize = CGSizeMake(round(self.size.width * ratio), round(self.size.height * ratio));
-
- return [self resizedImage:newSize interpolationQuality:quality];
-}
-
-#pragma mark -
-#pragma mark Private helper methods
-
-// Returns a copy of the image that has been transformed using the given affine transform and scaled to the new size
-// The new image's orientation will be UIImageOrientationUp, regardless of the current image's orientation
-// If the new size is not integral, it will be rounded up
-- (UIImage *)resizedImage:(CGSize)newSize
- transform:(CGAffineTransform)transform
- drawTransposed:(BOOL)transpose
- interpolationQuality:(CGInterpolationQuality)quality {
- CGRect newRect = CGRectIntegral(CGRectMake(0, 0, newSize.width, newSize.height));
- CGRect transposedRect = CGRectMake(0, 0, newRect.size.height, newRect.size.width);
- CGImageRef imageRef = self.CGImage;
-
- // Build a context that's the same dimensions as the new size
- uint32_t bitmapInfo = CGImageGetBitmapInfo(imageRef);
- if((bitmapInfo == kCGImageAlphaLast) || (bitmapInfo == kCGImageAlphaNone))
- bitmapInfo = kCGImageAlphaNoneSkipLast;
-
-
-
- CGContextRef bitmap = CGBitmapContextCreate(NULL,
- newRect.size.width,
- newRect.size.height,
- CGImageGetBitsPerComponent(imageRef),
- 0,
- CGImageGetColorSpace(imageRef),
- bitmapInfo);
-
- // Rotate and/or flip the image if required by its orientation
- CGContextConcatCTM(bitmap, transform);
-
- // Set the quality level to use when rescaling
- CGContextSetInterpolationQuality(bitmap, quality);
-
- // Draw into the context; this scales the image
- CGContextDrawImage(bitmap, transpose ? transposedRect : newRect, imageRef);
-
- // Get the resized image from the context and a UIImage
- CGImageRef newImageRef = CGBitmapContextCreateImage(bitmap);
- UIImage *newImage = [UIImage imageWithCGImage:newImageRef];
-
- // Clean up
- CGContextRelease(bitmap);
- CGImageRelease(newImageRef);
-
- return newImage;
-}
-
-// Returns an affine transform that takes into account the image orientation when drawing a scaled image
-- (CGAffineTransform)transformForOrientation:(CGSize)newSize {
- CGAffineTransform transform = CGAffineTransformIdentity;
-
- switch (self.imageOrientation) {
- case UIImageOrientationDown: // EXIF = 3
- case UIImageOrientationDownMirrored: // EXIF = 4
- transform = CGAffineTransformTranslate(transform, newSize.width, newSize.height);
- transform = CGAffineTransformRotate(transform, M_PI);
- break;
-
- case UIImageOrientationLeft: // EXIF = 6
- case UIImageOrientationLeftMirrored: // EXIF = 5
- transform = CGAffineTransformTranslate(transform, newSize.width, 0);
- transform = CGAffineTransformRotate(transform, M_PI_2);
- break;
-
- case UIImageOrientationRight: // EXIF = 8
- case UIImageOrientationRightMirrored: // EXIF = 7
- transform = CGAffineTransformTranslate(transform, 0, newSize.height);
- transform = CGAffineTransformRotate(transform, -M_PI_2);
- break;
-
- default:
- break;
- }
-
- switch (self.imageOrientation) {
- case UIImageOrientationUpMirrored: // EXIF = 2
- case UIImageOrientationDownMirrored: // EXIF = 4
- transform = CGAffineTransformTranslate(transform, newSize.width, 0);
- transform = CGAffineTransformScale(transform, -1, 1);
- break;
-
- case UIImageOrientationLeftMirrored: // EXIF = 5
- case UIImageOrientationRightMirrored: // EXIF = 7
- transform = CGAffineTransformTranslate(transform, newSize.height, 0);
- transform = CGAffineTransformScale(transform, -1, 1);
- break;
-
- default:
- break;
- }
-
- return transform;
-}
-
-@end
diff --git a/camerademo/camerademo/demo/UIImage/UIImage+RoundedCorner.h b/camerademo/camerademo/demo/UIImage/UIImage+RoundedCorner.h
deleted file mode 100755
index f9d9803..0000000
--- a/camerademo/camerademo/demo/UIImage/UIImage+RoundedCorner.h
+++ /dev/null
@@ -1,10 +0,0 @@
-// UIImage+RoundedCorner.h
-// Created by Trevor Harmon on 9/20/09.
-// Free for personal or commercial use, with or without modification.
-// No warranty is expressed or implied.
-
-// Extends the UIImage class to support making rounded corners
-#import <UIKit/UIKit.h>
-@interface UIImage (RoundedCorner)
-- (UIImage *)roundedCornerImage:(NSInteger)cornerSize borderSize:(NSInteger)borderSize;
-@end
diff --git a/camerademo/camerademo/demo/UIImage/UIImage+RoundedCorner.m b/camerademo/camerademo/demo/UIImage/UIImage+RoundedCorner.m
deleted file mode 100755
index f917f2c..0000000
--- a/camerademo/camerademo/demo/UIImage/UIImage+RoundedCorner.m
+++ /dev/null
@@ -1,79 +0,0 @@
-// UIImage+RoundedCorner.m
-// Created by Trevor Harmon on 9/20/09.
-// Free for personal or commercial use, with or without modification.
-// No warranty is expressed or implied.
-
-#import "UIImage+RoundedCorner.h"
-#import "UIImage+Alpha.h"
-
-// Private helper methods
-@interface UIImage (RoundedCornerPrivateMethods)
-- (void)addRoundedRectToPath:(CGRect)rect context:(CGContextRef)context ovalWidth:(CGFloat)ovalWidth ovalHeight:(CGFloat)ovalHeight;
-@end
-
-@implementation UIImage (RoundedCorner)
-
-// Creates a copy of this image with rounded corners
-// If borderSize is non-zero, a transparent border of the given size will also be added
-// Original author: Bj��rn S��llarp. Used with permission. See: http://blog.sallarp.com/iphone-uiimage-round-corners/
-- (UIImage *)roundedCornerImage:(NSInteger)cornerSize borderSize:(NSInteger)borderSize {
- // If the image does not have an alpha layer, add one
- UIImage *image = [self imageWithAlpha];
-
- // Build a context that's the same dimensions as the new size
- CGContextRef context = CGBitmapContextCreate(NULL,
- image.size.width,
- image.size.height,
- CGImageGetBitsPerComponent(image.CGImage),
- 0,
- CGImageGetColorSpace(image.CGImage),
- CGImageGetBitmapInfo(image.CGImage));
-
- // Create a clipping path with rounded corners
- CGContextBeginPath(context);
- [self addRoundedRectToPath:CGRectMake(borderSize, borderSize, image.size.width - borderSize * 2, image.size.height - borderSize * 2)
- context:context
- ovalWidth:cornerSize
- ovalHeight:cornerSize];
- CGContextClosePath(context);
- CGContextClip(context);
-
- // Draw the image to the context; the clipping path will make anything outside the rounded rect transparent
- CGContextDrawImage(context, CGRectMake(0, 0, image.size.width, image.size.height), image.CGImage);
-
- // Create a CGImage from the context
- CGImageRef clippedImage = CGBitmapContextCreateImage(context);
- CGContextRelease(context);
-
- // Create a UIImage from the CGImage
- UIImage *roundedImage = [UIImage imageWithCGImage:clippedImage];
- CGImageRelease(clippedImage);
-
- return roundedImage;
-}
-
-#pragma mark -
-#pragma mark Private helper methods
-
-// Adds a rectangular path to the given context and rounds its corners by the given extents
-// Original author: Bj��rn S��llarp. Used with permission. See: http://blog.sallarp.com/iphone-uiimage-round-corners/
-- (void)addRoundedRectToPath:(CGRect)rect context:(CGContextRef)context ovalWidth:(CGFloat)ovalWidth ovalHeight:(CGFloat)ovalHeight {
- if (ovalWidth == 0 || ovalHeight == 0) {
- CGContextAddRect(context, rect);
- return;
- }
- CGContextSaveGState(context);
- CGContextTranslateCTM(context, CGRectGetMinX(rect), CGRectGetMinY(rect));
- CGContextScaleCTM(context, ovalWidth, ovalHeight);
- CGFloat fw = CGRectGetWidth(rect) / ovalWidth;
- CGFloat fh = CGRectGetHeight(rect) / ovalHeight;
- CGContextMoveToPoint(context, fw, fh/2);
- CGContextAddArcToPoint(context, fw, fh, fw/2, fh, 1);
- CGContextAddArcToPoint(context, 0, fh, 0, fh/2, 1);
- CGContextAddArcToPoint(context, 0, 0, fw/2, 0, 1);
- CGContextAddArcToPoint(context, fw, 0, fw, fh/2, 1);
- CGContextClosePath(context);
- CGContextRestoreGState(context);
-}
-
-@end
diff --git a/camerademo/camerademo/demo/UIImage/UIImage+Vector.h b/camerademo/camerademo/demo/UIImage/UIImage+Vector.h
deleted file mode 100755
index 9f93d41..0000000
--- a/camerademo/camerademo/demo/UIImage/UIImage+Vector.h
+++ /dev/null
@@ -1,65 +0,0 @@
-//
-// UIImage+Vector.h
-// UIImage+Vector
-//
-// Created by David Keegan on 8/7/13.
-// Copyright (c) 2013 David Keegan All rights reserved.
-//
-
-
-/**
- * @Author(������) David Keegan
- *
- * @URL(������) https://github.com/kgn/UIImage-Vector
- *
- * @Version(������) 20150620
- *
- * @Requirements(������������)
- *
- * @Description(������) UIImage category for dealing with vector formats like PDF and icon fonts.
- * @Usage(������) ..
- */
-
-#import <UIKit/UIKit.h>
-
-@interface UIImage(Vector)
-
-/**
- Create a UIImage from an icon font.
- @param font The icon font.
- @param iconNamed The name of the icon in the font.
- @param tintColor The tint color to use for the icon. Defaults to black.
- @param clipToBounds If YES the image will be clipped to the pixel bounds of the icon.
- @param fontSize The font size to draw the icon at.
- @return The resulting image.
- */
-+ (UIImage *)iconWithFont:(UIFont *)font named:(NSString *)iconNamed
- withTintColor:(UIColor *)tintColor clipToBounds:(BOOL)clipToBounds forSize:(CGFloat)fontSize;
-
-/**
- Create a UIImage from a PDF icon.
- @param pdfNamed The name of the PDF file in the application's resources directory.
- @param height The height of the resulting image, the width will be based on the aspect ratio of the PDF.
- @return The resulting image.
- */
-+ (UIImage *)imageWithPDFNamed:(NSString *)pdfNamed forHeight:(CGFloat)height;
-
-/**
- Create a UIImage from a PDF icon.
- @param pdfNamed The name of the PDF file in the application's resources directory.
- @param tintColor The tint color to use for the icon. If nil no tint color will be used.
- @param height The height of the resulting image, the width will be based on the aspect ratio of the PDF.
- @return The resulting image.
- */
-+ (UIImage *)imageWithPDFNamed:(NSString *)pdfNamed withTintColor:(UIColor *)tintColor forHeight:(CGFloat)height;
-
-/**
- Create a UIImage from a PDF icon.
- @param pdfFile The path of the PDF file.
- @param tintColor The tint color to use for the icon. If nil no tint color will be used.
- @param maxSize The maximum size the resulting image can be. The image will maintain it's aspect ratio and may not encumpas the full size.
- @return The resulting image.
- */
-+ (UIImage *)imageWithPDFFile:(NSString *)pdfFile withTintColor:(UIColor *)tintColor forSize:(CGSize)size;
-
-@end
diff --git a/camerademo/camerademo/demo/UIImage/UIImage+Vector.m b/camerademo/camerademo/demo/UIImage/UIImage+Vector.m
deleted file mode 100755
index e2d4af0..0000000
--- a/camerademo/camerademo/demo/UIImage/UIImage+Vector.m
+++ /dev/null
@@ -1,140 +0,0 @@
-//
-// UIImage+Vector.m
-// UIImage+Vector
-//
-// Created by David Keegan on 8/7/13.
-// Copyright (c) 2013 David Keegan All rights reserved.
-//
-
-#import "UIImage+Vector.h"
-#import <CoreText/CoreText.h>
-
-@implementation UIImage(Vector)
-
-+ (NSCache *)cache{
- static NSCache *cache = nil;
- static dispatch_once_t onceToken;
- dispatch_once(&onceToken, ^{
- cache = [[NSCache alloc] init];
- });
- return cache;
-}
-
-+ (UIImage *)iconWithFont:(UIFont *)font named:(NSString *)iconNamed withTintColor:(UIColor *)tintColor clipToBounds:(BOOL)clipToBounds forSize:(CGFloat)fontSize{
- NSString *identifier = [NSString stringWithFormat:@"%@%@%@%@%d%f", NSStringFromSelector(_cmd), font.fontName, tintColor, iconNamed, clipToBounds, fontSize];
- UIImage *image = [[self cache] objectForKey:identifier];
- if(image == nil){
- NSMutableAttributedString *ligature = [[NSMutableAttributedString alloc] initWithString:iconNamed];
- [ligature setAttributes:@{(NSString *)kCTLigatureAttributeName: @(2),
- (NSString *)kCTFontAttributeName: font}
- range:NSMakeRange(0, [ligature length])];
-
- CGSize imageSize = [ligature size];
- imageSize.width = ceil(imageSize.width);
- imageSize.height = ceil(imageSize.height);
- if(!CGSizeEqualToSize(CGSizeZero, imageSize)){
- UIGraphicsBeginImageContextWithOptions(imageSize, NO, 0);
- [ligature drawAtPoint:CGPointZero];
- image = UIGraphicsGetImageFromCurrentImageContext();
- UIGraphicsEndImageContext();
-
- if(tintColor){
- UIGraphicsBeginImageContextWithOptions(imageSize, NO, 0);
- CGContextRef context = UIGraphicsGetCurrentContext();
- CGContextScaleCTM(context, 1, -1);
- CGContextTranslateCTM(context, 0, -imageSize.height);
- CGContextClipToMask(context, (CGRect){.size=imageSize}, [image CGImage]);
- [tintColor setFill];
- CGContextFillRect(context, (CGRect){.size=imageSize});
- image = UIGraphicsGetImageFromCurrentImageContext();
- UIGraphicsEndImageContext();
- }
-
- #pragma clang diagnostic push
- #pragma clang diagnostic ignored "-Wundeclared-selector"
- if(clipToBounds && [image respondsToSelector:@selector(imageClippedToPixelBounds)]){
- image = [image performSelector:@selector(imageClippedToPixelBounds)];
- }
- #pragma clang diagnostic pop
-
- [[self cache] setObject:image forKey:identifier];
- }
- }
- return image;
-}
-
-+ (UIImage *)imageWithPDFNamed:(NSString *)pdfNamed forHeight:(CGFloat)height{
- return [self imageWithPDFNamed:pdfNamed withTintColor:nil forHeight:height];
-}
-
-+ (UIImage *)imageWithPDFNamed:(NSString *)pdfNamed withTintColor:(UIColor *)tintColor forHeight:(CGFloat)height{
- NSString *pdfFile = [[NSBundle mainBundle] pathForResource:pdfNamed ofType:@"pdf"];
- return [self imageWithPDFFile:pdfFile withTintColor:tintColor forSize:CGSizeMake(MAXFLOAT, height)];
-}
-
-+ (UIImage *)imageWithPDFFile:(NSString *)pdfFile withTintColor:(UIColor *)tintColor forSize:(CGSize)size{
- if(!pdfFile || CGSizeEqualToSize(size, CGSizeZero)){
- return nil;
- }
-
- NSString *identifier = [NSString stringWithFormat:@"%@%@%@%@", NSStringFromSelector(_cmd), pdfFile, tintColor, NSStringFromCGSize(size)];
- UIImage *image = [[self cache] objectForKey:identifier];
- if(image){
- return image;
- }
-
- NSURL *url = [NSURL fileURLWithPath:pdfFile];
- CGPDFDocumentRef pdf = CGPDFDocumentCreateWithURL((__bridge CFURLRef)url);
- if(!pdf){
- return nil;
- }
-
- CGPDFPageRef page1 = CGPDFDocumentGetPage(pdf, 1);
- CGRect mediaRect = CGPDFPageGetBoxRect(page1, kCGPDFCropBox);
-
- CGSize imageSize = mediaRect.size;
- if(imageSize.height < size.height && size.height != MAXFLOAT){
- imageSize.width = round(size.height/imageSize.height*imageSize.width);
- imageSize.height = size.height;
- }
- if(imageSize.width < size.width && size.width != MAXFLOAT){
- imageSize.height = round(size.width/imageSize.width*imageSize.height);
- imageSize.width = size.width;
- }
-
- if(imageSize.height > size.height){
- imageSize.width = round(size.height/imageSize.height*imageSize.width);
- imageSize.height = size.height;
- }
- if(imageSize.width > size.width){
- imageSize.height = round(size.width/imageSize.width*imageSize.height);
- imageSize.width = size.width;
- }
-
- UIGraphicsBeginImageContextWithOptions(imageSize, NO, 0);
- CGFloat scale = MIN(imageSize.width/mediaRect.size.width, imageSize.height/mediaRect.size.height);
- CGContextRef context = UIGraphicsGetCurrentContext();
- CGContextScaleCTM(context, 1, -1);
- CGContextTranslateCTM(context, 0, -imageSize.height);
- CGContextScaleCTM(context, scale, scale);
- CGContextDrawPDFPage(context, page1);
- CGPDFDocumentRelease(pdf);
- image = UIGraphicsGetImageFromCurrentImageContext();
- UIGraphicsEndImageContext();
-
- if(tintColor){
- UIGraphicsBeginImageContextWithOptions(imageSize, NO, 0);
- CGContextRef context = UIGraphicsGetCurrentContext();
- CGContextScaleCTM(context, 1, -1);
- CGContextTranslateCTM(context, 0, -imageSize.height);
- CGContextClipToMask(context, (CGRect){.size=imageSize}, [image CGImage]);
- [tintColor setFill];
- CGContextFillRect(context, (CGRect){.size=imageSize});
- image = UIGraphicsGetImageFromCurrentImageContext();
- UIGraphicsEndImageContext();
- }
-
- return image;
-}
-
-@end
diff --git a/camerademo/camerademo/demo/UIImage/UIImage+animatedGIF.h b/camerademo/camerademo/demo/UIImage/UIImage+animatedGIF.h
deleted file mode 100755
index 324d814..0000000
--- a/camerademo/camerademo/demo/UIImage/UIImage+animatedGIF.h
+++ /dev/null
@@ -1,32 +0,0 @@
-#import <UIKit/UIKit.h>
-
-/**
- UIImage (animatedGIF)
-
- This category adds class methods to `UIImage` to create an animated `UIImage` from an animated GIF.
-*/
-@interface UIImage (animatedGIF)
-
-/*
- UIImage *animation = [UIImage animatedImageWithAnimatedGIFData:theData];
-
- I interpret `theData` as a GIF. I create an animated `UIImage` using the source images in the GIF.
-
- The GIF stores a separate duration for each frame, in units of centiseconds (hundredths of a second). However, a `UIImage` only has a single, total `duration` property, which is a floating-point number.
-
- To handle this mismatch, I add each source image (from the GIF) to `animation` a varying number of times to match the ratios between the frame durations in the GIF.
-
- For example, suppose the GIF contains three frames. Frame 0 has duration 3. Frame 1 has duration 9. Frame 2 has duration 15. I divide each duration by the greatest common denominator of all the durations, which is 3, and add each frame the resulting number of times. Thus `animation` will contain frame 0 3/3 = 1 time, then frame 1 9/3 = 3 times, then frame 2 15/3 = 5 times. I set `animation.duration` to (3+9+15)/100 = 0.27 seconds.
-*/
-+ (UIImage *)animatedImageWithAnimatedGIFData:(NSData *)theData;
-
-/*
- UIImage *image = [UIImage animatedImageWithAnimatedGIFURL:theURL];
-
- I interpret the contents of `theURL` as a GIF. I create an animated `UIImage` using the source images in the GIF.
-
- I operate exactly like `+[UIImage animatedImageWithAnimatedGIFData:]`, except that I read the data from `theURL`. If `theURL` is not a `file:` URL, you probably want to call me on a background thread or GCD queue to avoid blocking the main thread.
-*/
-+ (UIImage *)animatedImageWithAnimatedGIFURL:(NSURL *)theURL;
-
-@end
diff --git a/camerademo/camerademo/demo/UIImage/UIImage+animatedGIF.m b/camerademo/camerademo/demo/UIImage/UIImage+animatedGIF.m
deleted file mode 100755
index f6bdf5f..0000000
--- a/camerademo/camerademo/demo/UIImage/UIImage+animatedGIF.m
+++ /dev/null
@@ -1,114 +0,0 @@
-#import "UIImage+animatedGIF.h"
-#import <ImageIO/ImageIO.h>
-
-#if __has_feature(objc_arc)
-#define toCF (__bridge CFTypeRef)
-#define fromCF (__bridge id)
-#else
-#define toCF (CFTypeRef)
-#define fromCF (id)
-#endif
-
-@implementation UIImage (animatedGIF)
-
-static int delayCentisecondsForImageAtIndex(CGImageSourceRef const source, size_t const i) {
- int delayCentiseconds = 1;
- CFDictionaryRef const properties = CGImageSourceCopyPropertiesAtIndex(source, i, NULL);
- if (properties) {
- CFDictionaryRef const gifProperties = CFDictionaryGetValue(properties, kCGImagePropertyGIFDictionary);
- CFRelease(properties);
- if (gifProperties) {
- CFNumberRef const number = CFDictionaryGetValue(gifProperties, kCGImagePropertyGIFDelayTime);
- // Even though the GIF stores the delay as an integer number of centiseconds, ImageIO ���helpfully��� converts that to seconds for us.
- delayCentiseconds = (int)lrint([fromCF number doubleValue] * 100);
- }
- }
- return delayCentiseconds;
-}
-
-static void createImagesAndDelays(CGImageSourceRef source, size_t count, CGImageRef imagesOut[count], int delayCentisecondsOut[count]) {
- for (size_t i = 0; i < count; ++i) {
- imagesOut[i] = CGImageSourceCreateImageAtIndex(source, i, NULL);
- delayCentisecondsOut[i] = delayCentisecondsForImageAtIndex(source, i);
- }
-}
-
-static int sum(size_t const count, int const *const values) {
- int theSum = 0;
- for (size_t i = 0; i < count; ++i) {
- theSum += values[i];
- }
- return theSum;
-}
-
-static int pairGCD(int a, int b) {
- if (a < b)
- return pairGCD(b, a);
- while (true) {
- int const r = a % b;
- if (r == 0)
- return b;
- a = b;
- b = r;
- }
-}
-
-static int vectorGCD(size_t const count, int const *const values) {
- int gcd = values[0];
- for (size_t i = 1; i < count; ++i) {
- // Note that after I process the first few elements of the vector, `gcd` will probably be smaller than any remaining element. By passing the smaller value as the second argument to `pairGCD`, I avoid making it swap the arguments.
- gcd = pairGCD(values[i], gcd);
- }
- return gcd;
-}
-
-static NSArray *frameArray(size_t const count, CGImageRef const images[count], int const delayCentiseconds[count], int const totalDurationCentiseconds) {
- int const gcd = vectorGCD(count, delayCentiseconds);
- size_t const frameCount = totalDurationCentiseconds / gcd;
- UIImage *frames[frameCount];
- for (size_t i = 0, f = 0; i < count; ++i) {
- UIImage *const frame = [UIImage imageWithCGImage:images[i]];
- for (size_t j = delayCentiseconds[i] / gcd; j > 0; --j) {
- frames[f++] = frame;
- }
- }
- return [NSArray arrayWithObjects:frames count:frameCount];
-}
-
-static void releaseImages(size_t const count, CGImageRef const images[count]) {
- for (size_t i = 0; i < count; ++i) {
- CGImageRelease(images[i]);
- }
-}
-
-static UIImage *animatedImageWithAnimatedGIFImageSource(CGImageSourceRef const source) {
- size_t const count = CGImageSourceGetCount(source);
- CGImageRef images[count];
- int delayCentiseconds[count]; // in centiseconds
- createImagesAndDelays(source, count, images, delayCentiseconds);
- int const totalDurationCentiseconds = sum(count, delayCentiseconds);
- NSArray *const frames = frameArray(count, images, delayCentiseconds, totalDurationCentiseconds);
- UIImage *const animation = [UIImage animatedImageWithImages:frames duration:(NSTimeInterval)totalDurationCentiseconds / 100.0];
- releaseImages(count, images);
- return animation;
-}
-
-static UIImage *animatedImageWithAnimatedGIFReleasingImageSource(CGImageSourceRef source) {
- if (source) {
- UIImage *const image = animatedImageWithAnimatedGIFImageSource(source);
- CFRelease(source);
- return image;
- } else {
- return nil;
- }
-}
-
-+ (UIImage *)animatedImageWithAnimatedGIFData:(NSData *)data {
- return animatedImageWithAnimatedGIFReleasingImageSource(CGImageSourceCreateWithData(toCF data, NULL));
-}
-
-+ (UIImage *)animatedImageWithAnimatedGIFURL:(NSURL *)url {
- return animatedImageWithAnimatedGIFReleasingImageSource(CGImageSourceCreateWithURL(toCF url, NULL));
-}
-
-@end
--
Gitblit v1.8.0