├── LICENSE ├── README.md ├── YzcChart.podspec ├── YzcChart ├── Model │ ├── BarChartModel.h │ ├── BarChartModel.m │ ├── YzcConfigModel.h │ └── YzcConfigModel.m ├── UIView+Extension.h ├── UIView+Extension.m ├── YzcBar.h ├── YzcBar.m ├── YzcBarChart.h ├── YzcBarChart.m ├── YzcChartView.h ├── YzcChartView.m ├── YzcCommonMacros.h ├── YzcLabel.h ├── YzcLabel.m ├── YzcLineChart.h └── YzcLineChart.m ├── YzcChartExample.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ └── contents.xcworkspacedata └── xcuserdata │ └── yezhicheng.xcuserdatad │ └── xcschemes │ └── YzcChartExample.xcscheme ├── YzcChartExample ├── Assets.xcassets │ └── AppIcon.appiconset │ │ └── Contents.json ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard ├── Classes │ ├── AppDelegate.h │ ├── AppDelegate.m │ ├── ViewController.h │ ├── ViewController.m │ └── YzcChart │ │ ├── Model │ │ ├── BarChartModel.h │ │ ├── BarChartModel.m │ │ ├── YzcConfigModel.h │ │ └── YzcConfigModel.m │ │ ├── UIView+Extension.h │ │ ├── UIView+Extension.m │ │ ├── YzcBar.h │ │ ├── YzcBar.m │ │ ├── YzcBarChart.h │ │ ├── YzcBarChart.m │ │ ├── YzcChartView.h │ │ ├── YzcChartView.m │ │ ├── YzcCommonMacros.h │ │ ├── YzcLabel.h │ │ ├── YzcLabel.m │ │ ├── YzcLineChart.h │ │ └── YzcLineChart.m ├── Info.plist └── main.m ├── YzcChartTests ├── Info.plist └── YzcChartExampleTests.m ├── YzcChartUITests ├── Info.plist └── YzcChartUIExampleTests.m └── chartGIf.gif /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # YzcChart 2 | ![img](https://github.com/Yzc-jason/YzcChart/blob/master/chartGIf.gif) 3 | 4 | ## From CocoaPods【使用CocoaPods】 5 | 6 | ```ruby 7 | pod 'YzcChart' 8 | ``` 9 | ## Manually 【手动导入】 10 | - Drag all source files under floder YzcChart to your project.【将YzcChart文件夹中的所有源代码拽入项目中】 11 | - Import the main header file:#import "YzcChartView.h"【导入主头文件:#import "YzcChartView.h"】 12 | 13 | ## Examples【示例】 14 | #### lineChart 15 | ```objc 16 | YzcChartView *chartView = [[YzcChartView alloc] initWithFrame:CGRectMake(10, 100, 350, 200) dataSource:self style:YzcChartStyleLine]; 17 | [chartView showInView:self.scrollView]; 18 | 19 | ``` 20 | #### barChart 21 | ```objc 22 | YzcChartView *chartView2 = [[YzcChartView alloc] initWithFrame:CGRectMake(10, 300, self.view.frame.size.width-30, 200) dataSource:self style:YzcChartStyleBar]; 23 | [chartView2 showInView:self.scrollView]; 24 | ``` 25 | #### Must be achieved delegate void【必须实现的代理方法】 26 | ```objc 27 | ///横坐标标题数组 28 | - (NSMutableArray *)chartConfigAxisXValue:(YzcChartView *)chart; 29 | 30 | ///数值数组 31 | - (NSMutableArray *)chartConfigAxisYValue:(YzcChartView *)chart; 32 | 33 | ``` 34 | 35 | #### optional delegate method 【可配置的代理方法】 36 | ```objc 37 | ///显示数值范围 38 | - (CGRange)chartRange:(YzcChartView *)chart; 39 | 40 | 41 | /** 42 | 图表效果配置 43 | 44 | @param chart chart 45 | @return 配置model 46 | */ 47 | - (YzcConfigModel *)chartEffectConfig:(YzcChartView *)chart; 48 | 49 | #pragma mark - 柱状图功能 50 | 51 | - (NSInteger)barChartTargetValue:(YzcChartView *)chart; 52 | 53 | /** 54 | 柱状图样式 55 | 56 | @param chart chart 57 | @return bool 58 | */ 59 | - (BarChartStyle)barChartStyle:(YzcChartView *)chart; 60 | ``` 61 | 62 | #### optional Attributes 【可选属性】 63 | ```objc 64 | ///左上角显示单位(未国际化) 65 | @property (copy, nonatomic) NSString *unitString; 66 | ///是否显示左上角单位,默认隐藏 67 | @property (nonatomic, assign) BOOL isHiddenUnit; 68 | ///最后一个数值是否显示在柱状上面,默认隐藏 69 | @property (nonatomic, assign) BOOL isShowLastValue; 70 | ///横坐标显示间隔数 71 | @property (nonatomic, assign) NSInteger intervalValue; 72 | 73 | @property (nonatomic, strong) UIFont *textFont; 74 | 75 | ``` 76 | 77 | 78 | -------------------------------------------------------------------------------- /YzcChart.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = "YzcChart" 3 | s.version = "1.0" 4 | s.summary = "Some simple charts" 5 | s.homepage = "https://github.com/Yzc-jason/YzcChart" 6 | s.license = "MIT" 7 | s.authors = { 'jasonye' => 'yzc0253@gmail.com'} 8 | s.platform = :ios, "8.0" 9 | s.source = { :git => "https://github.com/Yzc-jason/YzcChart.git", :tag => s.version } 10 | s.source_files = 'YzcChart/**/*.{h,m}' 11 | s.requires_arc = true 12 | end 13 | -------------------------------------------------------------------------------- /YzcChart/Model/BarChartModel.h: -------------------------------------------------------------------------------- 1 | // 2 | // SleepModel.h 3 | // YzcChart 4 | // 5 | // Created by zs-pace on 2017/3/17. 6 | // Copyright © 2017年 yzc. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | @interface BarChartModel : NSObject 13 | ///睡眠总时长 14 | @property (nonatomic, assign) CGFloat SleepTimeLong; 15 | ///深睡时长 16 | @property (nonatomic, assign) CGFloat deepTimeLong; 17 | 18 | //-------------心率范围------------------------------- 19 | ///平均心率最低值 20 | @property (nonatomic, assign) CGFloat minValue; 21 | ///心率最高值 22 | @property (nonatomic, assign) CGFloat maxlValue; 23 | 24 | @end 25 | -------------------------------------------------------------------------------- /YzcChart/Model/BarChartModel.m: -------------------------------------------------------------------------------- 1 | // 2 | // SleepModel.m 3 | // YzcChart 4 | // 5 | // Created by zs-pace on 2017/3/17. 6 | // Copyright © 2017年 yzc. All rights reserved. 7 | // 8 | 9 | #import "BarChartModel.h" 10 | 11 | @implementation BarChartModel 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /YzcChart/Model/YzcConfigModel.h: -------------------------------------------------------------------------------- 1 | // 2 | // YzcConfigModel.h 3 | // YzcChart 4 | // 5 | // Created by zs-pace on 2017/3/21. 6 | // Copyright © 2017年 yzc. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | @interface YzcConfigModel : NSObject 13 | 14 | ///折线是否显示数值点 15 | @property (nonatomic, assign) BOOL lineChartIsDrawPoint; 16 | ///涉嫌是否显示渐变色 17 | @property (nonatomic, assign) BOOL lineChartIsShadow; 18 | ///是否显示最大最小值,默认不显示 19 | @property (nonatomic, assign) BOOL lineChartIsShowMaxMinVlaue; 20 | ///折线的颜色 21 | @property (nonatomic, strong) UIColor *lineChartLineColor; 22 | ///折线 横线的颜色 23 | @property (nonatomic, strong) UIColor *lineChartHorizontalLinecColor; 24 | ///折线 数值点的颜色 25 | @property (nonatomic, strong) UIColor *lineChartValuePointColor; 26 | ///是否显示虚线 27 | @property (nonatomic, assign) BOOL isHiddenDashedline; 28 | ///是否要分段 29 | @property (nonatomic, assign) BOOL isSegment; 30 | 31 | 32 | ///柱状条的颜色 33 | @property (nonatomic, strong) UIColor *barColor; 34 | ///柱状超过目标值的颜色 35 | @property (nonatomic, strong) UIColor *barChartAchieveTargetColor; 36 | ///柱状条空数据时的颜色 37 | @property (nonatomic, strong) UIColor *barChartEmptyDataBarColor; 38 | ///深睡柱状条颜色 39 | @property (nonatomic, strong) UIColor *barChartLessBarColor; 40 | ///横线的颜色 41 | @property (nonatomic, strong) UIColor *barChartHorizontalLinecColor; 42 | 43 | 44 | @end 45 | -------------------------------------------------------------------------------- /YzcChart/Model/YzcConfigModel.m: -------------------------------------------------------------------------------- 1 | // 2 | // YzcConfigModel.m 3 | // YzcChart 4 | // 5 | // Created by zs-pace on 2017/3/21. 6 | // Copyright © 2017年 yzc. All rights reserved. 7 | // 8 | 9 | #import "YzcConfigModel.h" 10 | 11 | @implementation YzcConfigModel 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /YzcChart/UIView+Extension.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+Extension.h 3 | // YzcChart 4 | // 5 | // Created by zs-pace on 2017/3/17. 6 | // Copyright © 2017年 yzc. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface UIView (Extension) 12 | 13 | /** 14 | 绘制实线 15 | 16 | @param point 开始绘制点 17 | @param lineToPoint 结束绘制点 18 | @param lineColor 实线颜色 19 | */ 20 | - (void)drawSolideLineWithMoveToPoint:(CGPoint)point lineToPoint:(CGPoint)lineToPoint lineColor:(UIColor *)lineColor; 21 | 22 | /** 23 | 绘制虚线 24 | 25 | @param startPoint 绘制位置 26 | @param lineLength 虚线的宽度 27 | @param lineSpacing 虚线的间距 28 | @param lineColor 虚线的颜色 29 | */ 30 | - (void)drawDashLineWithStartPoint:(CGPoint)startPoint 31 | endPoint:(CGPoint)endPoint 32 | lineLength:(int)lineLength 33 | lineSpacing:(int)lineSpacing 34 | lineColor:(UIColor *)lineColor; 35 | 36 | - (void)drawTipsViewWithFrame:(CGRect)frame; 37 | 38 | - (void)setWidth:(CGFloat)width; 39 | 40 | @end 41 | -------------------------------------------------------------------------------- /YzcChart/UIView+Extension.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+Extension.m 3 | // YzcChart 4 | // 5 | // Created by zs-pace on 2017/3/17. 6 | // Copyright © 2017年 yzc. All rights reserved. 7 | // 8 | 9 | #import "UIView+Extension.h" 10 | 11 | @implementation UIView (Extension) 12 | 13 | /** 14 | 绘制虚线 15 | 16 | @param startPoint 绘制位置 17 | @param lineLength 虚线的宽度 18 | @param lineSpacing 虚线的间距 19 | @param lineColor 虚线的颜色 20 | */ 21 | - (void)drawDashLineWithStartPoint:(CGPoint)startPoint endPoint:(CGPoint)endPoint lineLength:(int)lineLength 22 | lineSpacing:(int)lineSpacing lineColor:(UIColor *)lineColor { 23 | 24 | CAShapeLayer *shapeLayer = [CAShapeLayer layer]; 25 | [shapeLayer setPosition:startPoint]; 26 | [shapeLayer setFillColor:[UIColor clearColor].CGColor]; 27 | [shapeLayer setStrokeColor:lineColor.CGColor]; 28 | [shapeLayer setLineWidth:0.5]; 29 | [shapeLayer setLineJoin:kCALineJoinRound]; 30 | [shapeLayer setLineDashPattern:[NSArray arrayWithObjects:[NSNumber numberWithInt:lineLength], [NSNumber numberWithInt:lineSpacing], nil]]; 31 | 32 | CGMutablePathRef path = CGPathCreateMutable(); 33 | CGPathMoveToPoint(path, NULL, 0, 0); 34 | CGPathAddLineToPoint(path, NULL, endPoint.x, 0); 35 | [shapeLayer setPath:path]; 36 | CGPathRelease(path); 37 | 38 | [self.layer insertSublayer:shapeLayer atIndex:0]; 39 | } 40 | 41 | /** 42 | 绘制实线 43 | 44 | @param point 开始绘制点 45 | @param lineToPoint 结束绘制点 46 | @param lineColor 实线颜色 47 | */ 48 | - (void)drawSolideLineWithMoveToPoint:(CGPoint)point lineToPoint:(CGPoint)lineToPoint lineColor:(UIColor *)lineColor { 49 | CAShapeLayer *shapeLayer = [CAShapeLayer layer]; 50 | UIBezierPath *path = [UIBezierPath bezierPath]; 51 | 52 | [path moveToPoint:point]; 53 | [path addLineToPoint:lineToPoint]; 54 | [path closePath]; 55 | shapeLayer.path = path.CGPath; 56 | shapeLayer.strokeColor = lineColor.CGColor; 57 | shapeLayer.fillColor = [[UIColor whiteColor] CGColor]; 58 | shapeLayer.lineWidth = 0.5; 59 | [self.layer insertSublayer:shapeLayer atIndex:0]; 60 | } 61 | 62 | - (void)drawTipsViewWithFrame:(CGRect)frame { 63 | NSInteger triangleH = 3; 64 | UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:frame cornerRadius:1]; 65 | 66 | [path moveToPoint:CGPointMake(frame.origin.x + frame.size.width * 0.5 - triangleH, frame.origin.y + frame.size.height)]; 67 | [path addLineToPoint:CGPointMake(frame.origin.x + frame.size.width * 0.5 + triangleH, frame.origin.y + frame.size.height)]; 68 | [path addLineToPoint:CGPointMake(frame.origin.x + frame.size.width * 0.5, frame.origin.y + frame.size.height + triangleH)]; 69 | 70 | CAShapeLayer *shapeLayer = [[CAShapeLayer alloc] init]; 71 | shapeLayer.fillColor = [[UIColor blackColor] colorWithAlphaComponent:0.7].CGColor; 72 | shapeLayer.path = path.CGPath; 73 | [self.layer insertSublayer:shapeLayer atIndex:(int)(self.subviews.count - 2)]; 74 | } 75 | 76 | - (void)setWidth:(CGFloat)width { 77 | CGRect frame = self.frame; 78 | frame.size.width = width; 79 | self.frame = frame; 80 | } 81 | @end 82 | -------------------------------------------------------------------------------- /YzcChart/YzcBar.h: -------------------------------------------------------------------------------- 1 | // 2 | // YzcBar.h 3 | // YzcChart 4 | // 5 | // Created by 叶志成 on 2016/11/26. 6 | // Copyright © 2016年 yzc. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface YzcBar : UIView 12 | 13 | @property (nonatomic,assign) CGFloat percent; 14 | 15 | @property (nonatomic, assign) CGFloat leesPercent; 16 | 17 | @property (nonatomic, assign) CGFloat startPercent; 18 | 19 | ///柱状条空数据时的颜色 20 | @property (nonatomic, strong) UIColor * emptyDataBarColor; 21 | ///柱状条颜色 22 | @property (nonatomic, strong) UIColor * barColor; 23 | ///矮柱状条颜色 24 | @property (nonatomic, strong) UIColor * lessBarColor; 25 | 26 | @property (nonatomic, assign) BOOL isSvgRate; 27 | 28 | @end 29 | -------------------------------------------------------------------------------- /YzcChart/YzcBar.m: -------------------------------------------------------------------------------- 1 | // 2 | // YzcBar.m 3 | // YzcChart 4 | // 5 | // Created by 叶志成 on 2016/11/26. 6 | // Copyright © 2016年 yzc. All rights reserved. 7 | // 8 | 9 | #import "YzcBar.h" 10 | #import "YzcCommonMacros.h" 11 | 12 | @interface YzcBar () 13 | 14 | @property (nonatomic, strong) CAShapeLayer *progressLayer; 15 | @property (nonatomic, strong) CAGradientLayer *gradientLayer; 16 | 17 | @end 18 | 19 | @implementation YzcBar 20 | 21 | - (id)initWithFrame:(CGRect)frame { 22 | self = [super initWithFrame:frame]; 23 | if (self) { 24 | self.clipsToBounds = YES; 25 | 26 | //填充色层 27 | self.progressLayer = [CAShapeLayer layer]; 28 | self.progressLayer.frame = self.bounds; 29 | self.progressLayer.fillColor = [[UIColor clearColor] CGColor]; 30 | self.progressLayer.lineCap = kCALineCapSquare; 31 | self.progressLayer.lineWidth = self.frame.size.width; 32 | 33 | [self.layer addSublayer:self.progressLayer]; 34 | } 35 | return self; 36 | } 37 | 38 | - (void)setPercent:(CGFloat)percent { 39 | if (percent > 0 && percent < 0.1) { 40 | percent = 0.1; 41 | } 42 | // if (percent == 0.1) { 43 | // if (IS_IPHONE5S) { 44 | // percent = 0.13; 45 | // }else if (IS_IPHONE4S) { 46 | // percent = 0.16; 47 | // } 48 | // } 49 | 50 | _percent = percent; 51 | self.progressLayer.strokeColor = self.barColor.CGColor; 52 | 53 | UIBezierPath *path = [UIBezierPath bezierPath]; 54 | if (self.isSvgRate) { 55 | if (self.startPercent == percent) { //两个值一样情况,为了效果只显示一条线 56 | [path moveToPoint:CGPointMake(self.frame.size.width/2.0, (1 - percent) * self.frame.size.height)]; 57 | [path addLineToPoint:CGPointMake(self.frame.size.width/2.0, (1 - percent) * self.frame.size.height + 0.5 )]; 58 | self.progressLayer.lineCap = kCALineCapButt; 59 | }else { 60 | [path moveToPoint:CGPointMake(self.frame.size.width/2.0, (1-self.startPercent) * self.frame.size.height-5)]; 61 | [path addLineToPoint:CGPointMake(self.frame.size.width/2.0, (1 - percent) * self.frame.size.height+5 )]; 62 | } 63 | }else{ 64 | [path moveToPoint:CGPointMake(self.frame.size.width/2.0, self.frame.size.height+30)]; 65 | [path addLineToPoint:CGPointMake(self.frame.size.width/2.0, (1 - percent) * self.frame.size.height+15)]; 66 | } 67 | 68 | [path setLineWidth:1]; 69 | [path setLineCapStyle:kCGLineCapSquare]; 70 | 71 | //增加动画 72 | CABasicAnimation *pathAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"]; 73 | pathAnimation.duration = 0.5; 74 | pathAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; 75 | pathAnimation.fromValue = [NSNumber numberWithFloat:0.0f]; 76 | pathAnimation.toValue = [NSNumber numberWithFloat:1.0f]; 77 | pathAnimation.autoreverses = NO; 78 | self.progressLayer.path = path.CGPath; 79 | 80 | [self.progressLayer addAnimation:pathAnimation forKey:@"strokeEndAnimation"]; 81 | 82 | } 83 | 84 | - (void)setLeesPercent:(CGFloat)leesPercent { 85 | //深睡 86 | UIBezierPath *deepSleepPath = [UIBezierPath bezierPath]; 87 | [deepSleepPath moveToPoint:CGPointMake(self.frame.size.width/2.0, self.frame.size.height+30)]; 88 | [deepSleepPath addLineToPoint:CGPointMake(self.frame.size.width/2.0, (1 - leesPercent) * self.frame.size.height+15)]; 89 | [deepSleepPath setLineWidth:1]; 90 | [deepSleepPath setLineCapStyle:kCGLineCapSquare]; 91 | 92 | CAShapeLayer *shapeLayer = [CAShapeLayer layer]; 93 | shapeLayer.frame = self.bounds; 94 | shapeLayer.fillColor = [UIColor clearColor].CGColor; 95 | shapeLayer.lineWidth = self.frame.size.width; 96 | shapeLayer.strokeColor = self.lessBarColor.CGColor; 97 | shapeLayer.path = deepSleepPath.CGPath; 98 | [self.layer addSublayer:shapeLayer]; 99 | 100 | } 101 | 102 | @end 103 | -------------------------------------------------------------------------------- /YzcChart/YzcBarChart.h: -------------------------------------------------------------------------------- 1 | // 2 | // YzcBarChart.h 3 | // YzcChart 4 | // 5 | // Created by 叶志成 on 2016/11/26. 6 | // Copyright © 2016年 yzc. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "YzcCommonMacros.h" 11 | 12 | typedef NS_ENUM (NSInteger, BarChartStyle) { 13 | BarChartStyleNormal = 0, 14 | BarChartStyleSleep, 15 | BarChartStyleRateRange 16 | }; 17 | 18 | @interface YzcBarChart : UIView 19 | 20 | @property (nonatomic, copy) NSMutableArray *xLabels; 21 | @property (nonatomic, copy) NSMutableArray *yLabels; 22 | 23 | @property (nonatomic, strong) UIColor *barColor;/**柱装条的颜色*/ 24 | @property (nonatomic, strong) UIColor *achieveTargetColor;/**柱装超过目标值的颜色*/ 25 | @property (nonatomic, strong) UIColor *emptyDataBarColor; ///柱状条空数据时的颜色 26 | @property (nonatomic, strong) UIColor *lessBarColor; ///矮柱状条颜色 27 | @property (nonatomic, strong) UIColor *HorizontalLinecColor; /**横线的颜色*/ 28 | 29 | @property (copy, nonatomic) NSString *unitString; 30 | @property (nonatomic, assign) NSInteger intervalValue; /** x值间隔数 */ 31 | @property (nonatomic, assign) NSInteger targetValue; /**设置目标值,并且绘制目标虚线*/ 32 | 33 | @property (nonatomic, assign) BOOL isHiddenUnit; /**是否显示左上角单位,默认隐藏*/ 34 | @property (nonatomic, assign) BOOL isShowLastValue; /**最后一个数值是否显示在柱状上面,默认隐藏*/ 35 | 36 | @property (nonatomic, assign) CGRange chooseRange; 37 | 38 | @property (nonatomic, assign) BarChartStyle style; 39 | 40 | @property (nonatomic, strong) UIFont *textFont; 41 | 42 | - (void)strokeChart; 43 | 44 | @end 45 | -------------------------------------------------------------------------------- /YzcChart/YzcBarChart.m: -------------------------------------------------------------------------------- 1 | // 2 | // YzcBarChart.m 3 | // YzcChart 4 | // 5 | // Created by 叶志成 on 2016/11/26. 6 | // Copyright © 2016年 yzc. All rights reserved. 7 | // 8 | 9 | #import "YzcBarChart.h" 10 | #import "YzcLabel.h" 11 | #import "YzcBar.h" 12 | #import "UIView+Extension.h" 13 | #import "BarChartModel.h" 14 | 15 | #define marginLeft 10 16 | #define barWidth 8 17 | 18 | @interface YzcBarChart () 19 | 20 | @property (nonatomic) CGFloat xLabelWidth; 21 | @property (nonatomic, strong) UIScrollView *myScrollView; 22 | @property (nonatomic, assign) CGPoint lastPoint;; 23 | @property (nonatomic, assign) CGPoint originPoint; 24 | @property (nonatomic, strong) UILabel *unitLabel; 25 | @property (nonatomic, assign) CGFloat yValueMax; 26 | @property (nonatomic, assign) CGFloat yValueMin; 27 | @property (nonatomic, assign) CGFloat targetPercent; 28 | 29 | @end 30 | 31 | @implementation YzcBarChart 32 | 33 | #pragma mark - lazy 34 | - (UILabel *)unitLabel { 35 | if (_unitLabel == nil) { 36 | UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(YZCLabelwidth, 0, 100, 40)]; 37 | label.text = self.unitString; 38 | label.textColor = [[UIColor grayColor] colorWithAlphaComponent:0.5]; 39 | [label sizeToFit]; 40 | label.textAlignment = NSTextAlignmentCenter; 41 | [label setFont:[UIFont systemFontOfSize:10]]; 42 | [self addSubview:label]; 43 | _unitLabel = label; 44 | } 45 | return _unitLabel; 46 | } 47 | 48 | #pragma mark - init 49 | 50 | - (instancetype)initWithFrame:(CGRect)frame { 51 | self = [super initWithFrame:frame]; 52 | if (self) { 53 | self.myScrollView = [[UIScrollView alloc]initWithFrame:CGRectMake(YZCLabelwidth, 0, frame.size.width-YZCLabelwidth-10, frame.size.height)]; 54 | self.myScrollView.bounces = NO; 55 | [self addSubview:self.myScrollView]; 56 | self.isHiddenUnit = YES; 57 | self.intervalValue = 1; 58 | } 59 | return self; 60 | } 61 | 62 | #pragma mark - setter 63 | - (void)setUnitString:(NSString *)unitString { 64 | _unitString = unitString; 65 | } 66 | 67 | - (void)setIsHiddenUnit:(BOOL)isHiddenUnit { 68 | _isHiddenUnit = isHiddenUnit; 69 | if (!self.isHiddenUnit) { 70 | [self unitLabel]; 71 | } 72 | } 73 | 74 | - (void)setIntervalValue:(NSInteger)intervalValue { 75 | _intervalValue = intervalValue; 76 | } 77 | 78 | - (void)setIsShowLastValue:(BOOL)isShowLastValue { 79 | _isShowLastValue = isShowLastValue; 80 | } 81 | 82 | - (void)setXLabels:(NSMutableArray *)xLabels { 83 | _xLabels = xLabels; 84 | 85 | for (int i = 0; i < xLabels.count; i++) { 86 | if (i%self.intervalValue == 0 || i == xLabels.count - 1) { 87 | NSString *labelText = xLabels[i]; 88 | UIFont *font = self.textFont != nil ? self.textFont : [UIFont systemFontOfSize:10]; 89 | NSDictionary *attrs = @{NSFontAttributeName : font}; 90 | CGSize size = [labelText sizeWithAttributes:attrs]; 91 | CGFloat labelW = size.width; 92 | CGFloat labelH = size.height; 93 | CGFloat labelX = marginLeft + i * self.xLabelWidth + YZCLabelwidth + barWidth * 0.5 - labelW * 0.5; 94 | 95 | YzcLabel *label = [[YzcLabel alloc] initWithFrame:CGRectMake(labelX, self.frame.size.height - YZCLabelHeight - 5, self.xLabelWidth+10, labelH)]; 96 | label.text = labelText; 97 | if (self.textFont) { 98 | label.font = self.textFont; 99 | } 100 | [label sizeToFit]; 101 | [self addSubview:label]; 102 | if (self.isShowLastValue && i == xLabels.count - 1) { 103 | label.textColor = [[UIColor blackColor] colorWithAlphaComponent:0.5]; 104 | } 105 | } 106 | } 107 | 108 | if (self.targetValue) { //如果设置了目标值就绘制目标虚线 109 | CGFloat chartCavanHeight = self.frame.size.height - YZCLabelHeight * 3 + 8; 110 | float percent = ((float)self.targetValue-_yValueMin) / ((float)_yValueMax-_yValueMin); 111 | self.targetPercent = percent >= 1 ? 1 : percent; 112 | [self.myScrollView drawDashLineWithStartPoint:CGPointMake(marginLeft, (1 - percent) * chartCavanHeight+30) 113 | endPoint:CGPointMake(self.xLabelWidth * (self.yLabels.count - 1) + marginLeft, (1 - percent) * chartCavanHeight+30) 114 | lineLength:2 115 | lineSpacing:1 116 | lineColor:[[UIColor blackColor] colorWithAlphaComponent:0.2]]; 117 | } 118 | } 119 | 120 | - (void)setYLabels:(NSMutableArray *)yLabels { 121 | _yLabels = yLabels; 122 | self.xLabelWidth = (self.myScrollView.frame.size.width - YZCLabelwidth * 0.5)/self.yLabels.count; 123 | if (self.style == BarChartStyleNormal) { 124 | _yValueMax = [[self.yLabels valueForKeyPath:@"@max.floatValue"] floatValue]; 125 | _yValueMin = 0;//[[self.yLabels valueForKeyPath:@"@min.floatValue"] floatValue]; 126 | if (_yValueMax == _yValueMin) { 127 | _yValueMin = 0; 128 | } 129 | } 130 | 131 | if (_chooseRange.max != _chooseRange.min) { 132 | _yValueMax = _chooseRange.max; 133 | _yValueMin = _chooseRange.min; 134 | } 135 | 136 | if (_yValueMax < self.targetValue) { 137 | _yValueMax = self.targetValue; 138 | } 139 | 140 | if (self.targetValue) { //目标值 141 | CGFloat chartCavanHeight = self.frame.size.height - YZCLabelHeight * 3 + 8; 142 | float percent = ((float)self.targetValue-_yValueMin) / ((float)_yValueMax-_yValueMin); 143 | CGFloat labelH = percent >= 1 ? 22 : (1 - percent) * chartCavanHeight+22; 144 | YzcLabel *label = [[YzcLabel alloc] initWithFrame:CGRectMake(0, labelH, YZCLabelwidth+20, YZCLabelHeight)]; 145 | NSString *targetString; 146 | if (self.targetValue >= 1000) { 147 | targetString = [NSString stringWithFormat:@"%.1fk", (float)self.targetValue/1000]; 148 | NSString *lastNum = [targetString componentsSeparatedByString:@"."][1]; 149 | if (![lastNum integerValue]) { //没有小数 150 | NSString *firstNum = [targetString componentsSeparatedByString:@"."][0]; 151 | targetString = [NSString stringWithFormat:@"%@k", firstNum]; 152 | } 153 | } else { 154 | targetString = [NSString stringWithFormat:@"%zd", self.targetValue]; 155 | } 156 | label.text = targetString; 157 | 158 | if (self.textFont) { 159 | label.font = self.textFont; 160 | } 161 | [label sizeToFit]; 162 | [self addSubview:label]; 163 | } 164 | 165 | UIColor *lineColor = self.HorizontalLinecColor ? self.HorizontalLinecColor : [[UIColor blackColor] colorWithAlphaComponent:0.1]; 166 | CGFloat endPointX = self.xLabelWidth * (self.yLabels.count - 1) + marginLeft; 167 | 168 | if (self.style == BarChartStyleRateRange) { 169 | float level = (_yValueMax-_yValueMin) / LINE_COUNT; 170 | CGFloat chartCavanHeight = self.frame.size.height - YZCLabelHeight * LINE_COUNT + 8; 171 | CGFloat levelHeight = chartCavanHeight / LINE_COUNT; 172 | 173 | for (int i = 1; i < LINE_COUNT+1; i++) { 174 | YzcLabel *label = [[YzcLabel alloc] initWithFrame:CGRectMake(0, chartCavanHeight - i * levelHeight + 13, YZCLabelwidth+20, YZCLabelHeight)]; 175 | label.text = [NSString stringWithFormat:@"%d", (int)(level * i+_yValueMin)]; 176 | if (self.textFont) { 177 | label.font = self.textFont; 178 | } 179 | [label sizeToFit]; 180 | [self addSubview:label]; 181 | } 182 | 183 | //画中间虚线横线 184 | for (int i = 0; i < LINE_COUNT+1; i++) { 185 | if (i < LINE_COUNT) { 186 | [self.myScrollView drawDashLineWithStartPoint:CGPointMake(marginLeft, YZCLabelHeight + i * levelHeight) 187 | endPoint:CGPointMake(endPointX, YZCLabelHeight + i * levelHeight) 188 | lineLength:2 189 | lineSpacing:1 190 | lineColor:lineColor]; 191 | } 192 | } 193 | } 194 | 195 | //最底下一条线 196 | [self.myScrollView drawSolideLineWithMoveToPoint:CGPointMake(marginLeft, self.myScrollView.frame.size.height-YZCLabelHeight-10) 197 | lineToPoint:CGPointMake(endPointX + barWidth, self.myScrollView.frame.size.height-YZCLabelHeight-10) 198 | lineColor:lineColor]; 199 | } 200 | 201 | #pragma mark - draw 202 | 203 | - (void)strokeChart { 204 | CGFloat chartCavanHeight = self.frame.size.height - YZCLabelHeight * LINE_COUNT + 8; 205 | 206 | for (int i = 0; i < self.yLabels.count; i++) { 207 | YzcBar *bar = [[YzcBar alloc] initWithFrame:CGRectMake(i * _xLabelWidth + marginLeft, YZCLabelHeight + 2, barWidth, chartCavanHeight)]; 208 | bar.emptyDataBarColor = self.emptyDataBarColor ? self.emptyDataBarColor : [[UIColor grayColor] colorWithAlphaComponent:0.5]; 209 | 210 | if (self.style == BarChartStyleNormal) { 211 | NSString *valueString = self.yLabels[i]; 212 | float value = [valueString floatValue]; 213 | float percent = ((float)value-_yValueMin) / ((float)_yValueMax-_yValueMin); 214 | if (percent < 0 || isnan(percent)) { 215 | percent = 0; 216 | } 217 | if (percent >= self.targetPercent && self.targetValue) { 218 | bar.barColor = self.achieveTargetColor ? self.achieveTargetColor : [UIColor redColor]; 219 | } else { 220 | bar.barColor = self.barColor ? self.barColor : [UIColor greenColor]; 221 | } 222 | bar.percent = percent; 223 | 224 | //最后一个点显示数值在上面 225 | if ((i == self.self.yLabels.count - 1) && self.isShowLastValue && percent) { 226 | [self setupLastValueLabelWithView:bar value:[NSString stringWithFormat:@"%@", valueString] percent:percent chartCavanHeight:chartCavanHeight]; 227 | } 228 | } else { 229 | BarChartModel *barModel = self.yLabels[i]; 230 | 231 | float totalValue = 0.0; 232 | float totalPercent = 0.0; 233 | 234 | if (self.style == BarChartStyleSleep) { 235 | totalValue = barModel.SleepTimeLong; 236 | float deepValue = barModel.deepTimeLong; 237 | float deepPercent = ((float)deepValue-_yValueMin) / ((float)_yValueMax-_yValueMin); 238 | totalPercent = ((float)totalValue-_yValueMin) / ((float)_yValueMax-_yValueMin); 239 | 240 | if (isnan(totalPercent) || totalPercent < 0) { 241 | totalPercent = 0; 242 | } 243 | if (totalPercent >= self.targetPercent && self.targetValue) { 244 | bar.barColor = self.achieveTargetColor ? self.achieveTargetColor : [UIColor clearColor]; 245 | } else { 246 | bar.barColor = self.barColor ? self.barColor : [UIColor greenColor]; 247 | } 248 | 249 | bar.lessBarColor = self.lessBarColor ? self.lessBarColor : [UIColor blueColor]; 250 | bar.percent = totalPercent; 251 | bar.leesPercent = deepPercent; 252 | 253 | //最后一个点显示数值在上面 254 | if ((i == self.self.yLabels.count - 1) && self.isShowLastValue && (NSInteger)totalValue) { 255 | [self setupLastValueLabelWithView:bar value:[NSString stringWithFormat:@"%.0f", totalValue] percent:totalPercent chartCavanHeight:bar.frame.size.height + 10]; 256 | } 257 | } else if (self.style == BarChartStyleRateRange) { 258 | totalValue = barModel.maxlValue; 259 | totalPercent = ((float)totalValue-_yValueMin) / ((float)_yValueMax-_yValueMin); 260 | float startValue = barModel.minValue; 261 | float startPercent = ((float)startValue-_yValueMin) / ((float)_yValueMax-_yValueMin); 262 | 263 | bar.barColor = self.barColor ? self.barColor : [UIColor greenColor]; 264 | bar.isSvgRate = YES; 265 | bar.startPercent = startPercent; 266 | bar.percent = totalPercent; 267 | } 268 | } 269 | 270 | [self.myScrollView addSubview:bar]; 271 | } 272 | } 273 | 274 | - (void)setupLastValueLabelWithView:(YzcBar *)barView value:(NSString *)value percent:(CGFloat)percent chartCavanHeight:(CGFloat)chartCavanHeight { 275 | NSString *valueString = [NSString stringWithFormat:@"%@%@", value, self.unitString.length ? self.unitString : @""]; 276 | UIFont *font = self.textFont != nil ? self.textFont : [UIFont systemFontOfSize:10]; 277 | NSDictionary *attrs = @{NSFontAttributeName : font}; 278 | CGSize size = [valueString sizeWithAttributes:attrs]; 279 | CGFloat labelW = size.width; 280 | CGFloat labelH = size.height; 281 | CGFloat labelX = marginLeft + (self.yLabels.count - 1) * self.xLabelWidth + YZCLabelwidth + barWidth * 0.5 - labelW * 0.5; 282 | 283 | if (percent > 0 && percent < 0.1) { 284 | percent = 0.1; 285 | } 286 | CGFloat labelY = (1 - percent) * barView.frame.size.height + 15; 287 | 288 | UILabel *valueLabel = [[UILabel alloc] initWithFrame:CGRectMake(labelX, labelY, labelW, labelH)]; 289 | valueLabel.text = valueString; 290 | valueLabel.textColor = [UIColor whiteColor]; 291 | valueLabel.font = font; 292 | valueLabel.textAlignment = NSTextAlignmentCenter; 293 | 294 | [self addSubview:valueLabel]; 295 | [self drawTipsViewWithFrame:CGRectMake(labelX - marginLeft * 0.5, labelY, valueLabel.frame.size.width + marginLeft, valueLabel.frame.size.height)]; 296 | } 297 | 298 | @end 299 | -------------------------------------------------------------------------------- /YzcChart/YzcChartView.h: -------------------------------------------------------------------------------- 1 | // 2 | // YzcChartView.h 3 | // YzcChart 4 | // 5 | // Created by zs-pace on 2017/3/16. 6 | // Copyright © 2017年 yzc. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "YzcBarChart.h" 11 | #import "YzcLineChart.h" 12 | #import "BarChartModel.h" 13 | #import "YzcConfigModel.h" 14 | 15 | typedef NS_ENUM (NSInteger, YzcChartStyle){ 16 | YzcChartStyleLine = 0, 17 | YzcChartStyleBar 18 | }; 19 | 20 | @class YzcChartView; 21 | 22 | @protocol YzcChartDataSource 23 | 24 | @required 25 | ///横坐标标题数组 26 | - (NSMutableArray *)chartConfigAxisXValue:(YzcChartView *)chart; 27 | 28 | ///数值数组 29 | - (NSMutableArray *)chartConfigAxisYValue:(YzcChartView *)chart; 30 | 31 | @optional 32 | ///显示数值范围 33 | - (CGRange)chartRange:(YzcChartView *)chart; 34 | 35 | 36 | /** 37 | 图表效果配置 38 | 39 | @param chart chart 40 | @return 配置model 41 | */ 42 | - (YzcConfigModel *)chartEffectConfig:(YzcChartView *)chart; 43 | 44 | #pragma mark - 柱状图功能 45 | 46 | - (NSInteger)barChartTargetValue:(YzcChartView *)chart; 47 | 48 | /** 49 | 柱状图样式 50 | 51 | @param chart chart 52 | @return bool 53 | */ 54 | - (BarChartStyle)barChartStyle:(YzcChartView *)chart; 55 | 56 | @end 57 | 58 | 59 | @interface YzcChartView : UIView 60 | 61 | @property (nonatomic, assign) YzcChartStyle chartStyle; 62 | ///左上角显示单位(未国际化) 63 | @property (copy, nonatomic) NSString *unitString; 64 | ///是否显示左上角单位,默认隐藏 65 | @property (nonatomic, assign) BOOL isHiddenUnit; 66 | ///最后一个数值是否显示在柱状上面,默认隐藏 67 | @property (nonatomic, assign) BOOL isShowLastValue; 68 | ///横坐标显示间隔数 69 | @property (nonatomic, assign) NSInteger intervalValue; 70 | 71 | @property (nonatomic, strong) UIFont *textFont; 72 | 73 | - (id)initWithFrame:(CGRect)rect dataSource:(id)dataSource style:(YzcChartStyle)style; 74 | 75 | - (void)showInView:(UIView *)view; 76 | 77 | @end 78 | -------------------------------------------------------------------------------- /YzcChart/YzcChartView.m: -------------------------------------------------------------------------------- 1 | // 2 | // YzcChartView.m 3 | // YzcChart 4 | // 5 | // Created by zs-pace on 2017/3/16. 6 | // Copyright © 2017年 yzc. All rights reserved. 7 | // 8 | 9 | #import "YzcChartView.h" 10 | 11 | @interface YzcChartView () 12 | 13 | @property (weak, nonatomic) id dataSource; 14 | @property (strong, nonatomic) YzcLineChart *lineChart; 15 | @property (strong, nonatomic) YzcBarChart *barChart; 16 | 17 | @end 18 | 19 | @implementation YzcChartView 20 | 21 | 22 | - (id)initWithFrame:(CGRect)rect dataSource:(id)dataSource style:(YzcChartStyle)style { 23 | self.dataSource = dataSource; 24 | self.chartStyle = style; 25 | return [self initWithFrame:rect]; 26 | } 27 | 28 | - (id)initWithFrame:(CGRect)frame { 29 | self = [super initWithFrame:frame]; 30 | if (self) { 31 | self.clipsToBounds = NO; 32 | } 33 | return self; 34 | } 35 | 36 | - (void)setUpChart { 37 | if (self.chartStyle == YzcChartStyleLine) { 38 | if (!self.lineChart) { 39 | self.lineChart = [[YzcLineChart alloc] initWithFrame:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)]; 40 | [self addSubview:self.lineChart]; 41 | } 42 | 43 | //选择显示范围 44 | if ([self.dataSource respondsToSelector:@selector(chartRange:)]) { 45 | [self.lineChart setChooseRange:[self.dataSource chartRange:self]]; 46 | } 47 | 48 | BOOL isSegment = NO; 49 | if ([self.dataSource respondsToSelector:@selector(chartEffectConfig:)]) { 50 | YzcConfigModel *model = [self.dataSource chartEffectConfig:self]; 51 | self.lineChart.lineColor = model.lineChartLineColor; 52 | self.lineChart.HorizontalLinecColor = model.lineChartHorizontalLinecColor; 53 | self.lineChart.pointColor = model.lineChartValuePointColor; 54 | self.lineChart.isDrawPoint = model.lineChartIsDrawPoint; 55 | self.lineChart.isShadow = model.lineChartIsShadow; 56 | self.lineChart.isShowMaxMinValue = model.lineChartIsShowMaxMinVlaue; 57 | self.lineChart.isHiddenDashedLine = model.isHiddenDashedline; 58 | if (model.isSegment) { 59 | isSegment = model.isSegment; 60 | } 61 | } 62 | 63 | self.lineChart.textFont = self.textFont; 64 | self.lineChart.isHiddenLastValue = self.isShowLastValue; 65 | self.lineChart.isHiddenUnit = self.isHiddenUnit ? self.isHiddenUnit : YES; 66 | self.lineChart.unitString = self.unitString; 67 | self.lineChart.intervalValue = self.intervalValue ? self.intervalValue : 1; 68 | [self.lineChart setYLabels:[self.dataSource chartConfigAxisYValue:self]]; 69 | [self.lineChart setXLabels:[self.dataSource chartConfigAxisXValue:self]]; 70 | 71 | if (isSegment) { 72 | [self.lineChart segmentedStrokeChart]; 73 | }else{ 74 | [self.lineChart strokeChart]; 75 | } 76 | } else if (self.chartStyle == YzcChartStyleBar) { 77 | if (!self.barChart) { 78 | self.barChart = [[YzcBarChart alloc] initWithFrame:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)]; 79 | [self addSubview:self.barChart]; 80 | } 81 | if ([self.dataSource respondsToSelector:@selector(chartRange:)]) { 82 | [self.barChart setChooseRange:[self.dataSource chartRange:self]]; 83 | } 84 | 85 | if ([self.dataSource respondsToSelector:@selector(chartEffectConfig:)]) { 86 | YzcConfigModel *model = [self.dataSource chartEffectConfig:self]; 87 | self.barChart.barColor = model.barColor; 88 | self.barChart.achieveTargetColor = model.barChartAchieveTargetColor; 89 | self.barChart.emptyDataBarColor = model.barChartEmptyDataBarColor; 90 | self.barChart.lessBarColor = model.barChartLessBarColor; 91 | self.barChart.HorizontalLinecColor = model.barChartHorizontalLinecColor; 92 | } 93 | 94 | if ([self.dataSource respondsToSelector:@selector(barChartTargetValue:)]) { 95 | self.barChart.targetValue = [self.dataSource barChartTargetValue:self]; 96 | } 97 | if ([self.dataSource respondsToSelector:@selector(barChartStyle:)]) { 98 | self.barChart.style = [self.dataSource barChartStyle:self]; 99 | } 100 | 101 | self.barChart.textFont = self.textFont; 102 | self.barChart.isShowLastValue = self.isShowLastValue; 103 | self.barChart.isHiddenUnit = self.isHiddenUnit ? self.isHiddenUnit : YES; 104 | self.barChart.unitString = self.unitString; 105 | self.barChart.intervalValue = self.intervalValue? self.intervalValue : 1; 106 | [self.barChart setYLabels:[self.dataSource chartConfigAxisYValue:self]]; 107 | [self.barChart setXLabels:[self.dataSource chartConfigAxisXValue:self]]; 108 | 109 | [self.barChart strokeChart]; 110 | } 111 | } 112 | 113 | - (void)showInView:(UIView *)view { 114 | [self setUpChart]; 115 | [view addSubview:self]; 116 | } 117 | 118 | - (void)strokeChart { 119 | [self setUpChart]; 120 | } 121 | 122 | @end 123 | -------------------------------------------------------------------------------- /YzcChart/YzcCommonMacros.h: -------------------------------------------------------------------------------- 1 | // 2 | // YzcCommonMacros.h 3 | // YzcChart 4 | // 5 | // Created by 叶志成 on 2016/11/26. 6 | // Copyright © 2017年 yzc. All rights reserved. 7 | // 8 | 9 | #ifndef YzcCommonMacros_h 10 | #define YzcCommonMacros_h 11 | 12 | #define chartMargin 10 13 | #define xLabelMargin 15 14 | #define yLabelMargin 15 15 | #define YZCLabelHeight 20 16 | #define YZCLabelwidth 20 17 | #define YZCTagLabelwidth 80 18 | #define LINE_COUNT 3 19 | 20 | #define IS_IPHONE4S ([UIScreen mainScreen].bounds.size.height <= 480) 21 | #define IS_IPHONE5S ([UIScreen mainScreen].bounds.size.height == 568) 22 | 23 | //范围 24 | struct Range { 25 | CGFloat max; 26 | CGFloat min; 27 | }; 28 | typedef struct Range CGRange; 29 | CG_INLINE CGRange CGRangeMake(CGFloat max, CGFloat min); 30 | 31 | CG_INLINE CGRange 32 | CGRangeMake(CGFloat max, CGFloat min){ 33 | CGRange p; 34 | 35 | p.max = max; 36 | p.min = min; 37 | return p; 38 | } 39 | 40 | static const CGRange CGRangeZero = {0, 0}; 41 | 42 | #endif /* YzcCommonMacros_h */ 43 | -------------------------------------------------------------------------------- /YzcChart/YzcLabel.h: -------------------------------------------------------------------------------- 1 | // 2 | // YzcLabel.h 3 | // YzcChart 4 | // 5 | // Created by mac on 16/11/11. 6 | // Copyright © 2016年 yzc. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface YzcLabel : UILabel 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /YzcChart/YzcLabel.m: -------------------------------------------------------------------------------- 1 | // 2 | // YzcLabel.m 3 | // YzcChart 4 | // 5 | // Created by mac on 16/11/11. 6 | // Copyright © 2016年 yzc. All rights reserved. 7 | // 8 | 9 | #import "YzcLabel.h" 10 | 11 | @implementation YzcLabel 12 | 13 | - (id)initWithFrame:(CGRect)frame 14 | { 15 | self = [super initWithFrame:frame]; 16 | if (self) { 17 | 18 | [self setMinimumScaleFactor:5.0f]; 19 | [self setNumberOfLines:1]; 20 | [self setFont:[UIFont systemFontOfSize:10.0f]]; 21 | [self setTextColor: [[UIColor blackColor] colorWithAlphaComponent:0.2]]; 22 | [self setTextAlignment:NSTextAlignmentCenter]; 23 | self.userInteractionEnabled = YES; 24 | } 25 | return self; 26 | } 27 | 28 | 29 | 30 | @end 31 | -------------------------------------------------------------------------------- /YzcChart/YzcLineChart.h: -------------------------------------------------------------------------------- 1 | // 2 | // YzcChartView.h 3 | // YzcChart 4 | // 5 | // Created by mac on 16/11/10. 6 | // Copyright © 2016年 yzc. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "YzcCommonMacros.h" 11 | 12 | @interface YzcLineChart : UIView 13 | 14 | @property (copy, nonatomic) NSMutableArray *xLabels; 15 | @property (copy, nonatomic) NSMutableArray *yLabels; 16 | 17 | @property (nonatomic, assign) BOOL isDrawPoint; //是否数值点 18 | @property (nonatomic, assign) BOOL isShadow; //是否显示渐变 19 | @property (nonatomic, assign) BOOL isHiddenLastValue; //最后一个数值是否显示在柱状上面,默认隐藏 20 | @property (nonatomic, assign) BOOL isHiddenUnit; //是否显示左上角单位,默认隐藏 21 | @property (nonatomic, assign) BOOL isShowMaxMinValue; //是否显示最大最小值,默认不显示 22 | @property (nonatomic, assign) BOOL isHiddenDashedLine; 23 | 24 | @property (nonatomic, assign) NSInteger intervalValue;// x值显示间隔数 25 | @property (nonatomic, copy) NSString *unitString; 26 | 27 | @property (nonatomic, strong) UIColor *lineColor; //折线的颜色 28 | @property (nonatomic, strong) UIColor *HorizontalLinecColor; //横线的颜色 29 | @property (nonatomic, strong) UIColor *pointColor; //点的颜色 30 | 31 | @property (nonatomic, assign) CGRange chooseRange; 32 | 33 | @property (nonatomic, strong) UIFont *textFont; 34 | 35 | - (void)strokeChart; 36 | - (void)segmentedStrokeChart; 37 | 38 | @end 39 | -------------------------------------------------------------------------------- /YzcChart/YzcLineChart.m: -------------------------------------------------------------------------------- 1 | // 2 | // YzcChartView.m 3 | // YzcChart 4 | // 5 | // Created by mac on 16/11/10. 6 | // Copyright © 2016年 yzc. All rights reserved. 7 | // 8 | 9 | #import "YzcLineChart.h" 10 | #import "YzcLabel.h" 11 | #import "UIView+Extension.h" 12 | 13 | #define marginLeft 10 14 | 15 | @interface YzcLineChart () 16 | 17 | @property (nonatomic) CGFloat xLabelWidth; 18 | @property (nonatomic, strong) UIScrollView *myScrollView; 19 | @property (nonatomic, strong) UILabel *unitLabel; 20 | @property (nonatomic, assign) CGPoint lastPoint;; 21 | @property (nonatomic, assign) CGPoint originPoint; 22 | @property (nonatomic, assign) CGFloat yValueMin; 23 | @property (nonatomic, assign) CGFloat yValueMax; 24 | @property (nonatomic, assign) BOOL isLastIndex; 25 | @property (nonatomic, strong) CAShapeLayer *chartLine; 26 | @property (nonatomic, strong) UIBezierPath *progressline; 27 | 28 | @end 29 | 30 | @implementation YzcLineChart 31 | 32 | #pragma mark - init 33 | - (instancetype)initWithFrame:(CGRect)frame { 34 | self = [super initWithFrame:frame]; 35 | if (self) { 36 | self.myScrollView = [[UIScrollView alloc]initWithFrame:CGRectMake(YZCLabelwidth, 0, frame.size.width-YZCLabelwidth, frame.size.height)]; 37 | self.myScrollView.bounces = NO; 38 | [self addSubview:self.myScrollView]; 39 | self.isDrawPoint = YES; 40 | self.isShadow = YES; 41 | self.isHiddenUnit = YES; 42 | self.isShowMaxMinValue = NO; 43 | self.intervalValue = 1; 44 | } 45 | return self; 46 | } 47 | 48 | #pragma mark - Draw points 49 | - (void)strokeChart { 50 | float maxValue = [[self.yLabels valueForKeyPath:@"@max.floatValue"] floatValue]; 51 | 52 | if (!maxValue || !_yValueMax) { 53 | return; 54 | } 55 | 56 | BOOL isShowMaxAndMinPoint = YES; 57 | CGFloat firstValue = [[self.yLabels objectAtIndex:0] floatValue]; 58 | CGFloat xPosition = 10; 59 | CGFloat chartCavanHeight = self.myScrollView.frame.size.height - YZCLabelHeight*(LINE_COUNT-1); 60 | [self.myScrollView.layer addSublayer:self.chartLine]; 61 | 62 | float grade = ((float)firstValue-_yValueMin) / ((float)_yValueMax-_yValueMin); 63 | if (isnan(grade)) { 64 | grade = 0; 65 | } 66 | CGPoint firstPoint = CGPointMake(xPosition, chartCavanHeight - grade * chartCavanHeight+YZCLabelHeight); 67 | 68 | //线路径 69 | UIBezierPath *progressline = [UIBezierPath bezierPath]; 70 | [progressline moveToPoint:firstPoint]; //设置起点 71 | [progressline setLineWidth:2.0]; 72 | [progressline setLineCapStyle:kCGLineCapRound]; 73 | [progressline setLineJoinStyle:kCGLineJoinRound]; 74 | 75 | //遮罩层形状 76 | UIBezierPath *bezier1 = [UIBezierPath bezierPath]; 77 | bezier1.lineCapStyle = kCGLineCapRound; 78 | bezier1.lineJoinStyle = kCGLineJoinMiter; 79 | [bezier1 moveToPoint:firstPoint]; 80 | self.originPoint = firstPoint; //记录原点 81 | 82 | NSInteger index = 0; 83 | for (NSString *valueString in self.yLabels) { 84 | float grade = ([valueString floatValue] - _yValueMin) / ((float)_yValueMax-_yValueMin); 85 | if (isnan(grade)) { 86 | grade = 0; 87 | } 88 | 89 | CGPoint point = CGPointMake(xPosition+index*self.xLabelWidth, chartCavanHeight - grade * chartCavanHeight+YZCLabelHeight); 90 | if (index != 0) { 91 | [progressline addLineToPoint:point]; 92 | [bezier1 addLineToPoint:point]; 93 | } 94 | if (index == _yLabels.count-1) { 95 | self.lastPoint = point; //记录最后一个点 96 | self.isLastIndex = YES; 97 | } 98 | if (self.isDrawPoint) { //画点 99 | [self addPoint:point 100 | index:index 101 | isShow:isShowMaxAndMinPoint 102 | value:valueString]; 103 | } 104 | 105 | //显示最大值或最小值 106 | if (self.isShowMaxMinValue && ([valueString floatValue] == [[self.yLabels valueForKeyPath:@"@max.floatValue"] floatValue] || [valueString floatValue] == [[self.yLabels valueForKeyPath:@"@min.floatValue"] floatValue])) { 107 | [self setupLastValueLabelWithView:point 108 | value:[valueString integerValue] 109 | grade:grade 110 | chartCavanHeight:chartCavanHeight]; 111 | 112 | if (!self.isDrawPoint) { //如果没有画点才画最大最小的点,不然就不重复画点 113 | [self addPoint:point 114 | index:index 115 | isShow:isShowMaxAndMinPoint 116 | value:valueString]; 117 | } 118 | } 119 | index += 1; 120 | } 121 | 122 | self.chartLine.path = progressline.CGPath; 123 | self.chartLine.strokeColor = self.lineColor ? self.lineColor.CGColor : [UIColor greenColor].CGColor; 124 | self.chartLine.strokeEnd = 1.0; 125 | [self addAnimationWithLine:self.chartLine duration:self.yLabels.count * 0.03]; 126 | 127 | if (self.isShadow) { 128 | [bezier1 addLineToPoint:CGPointMake(self.lastPoint.x, self.myScrollView.frame.size.height - YZCLabelHeight)]; 129 | [bezier1 addLineToPoint:CGPointMake(self.originPoint.x, self.myScrollView.frame.size.height - YZCLabelHeight)]; 130 | [bezier1 addLineToPoint:self.originPoint]; 131 | [self addGradientLayer:bezier1]; 132 | } 133 | } 134 | 135 | - (void)segmentedStrokeChart { 136 | float maxValue = [[self.yLabels valueForKeyPath:@"@max.floatValue"] floatValue]; 137 | 138 | if (!maxValue || !_yValueMax) { 139 | return; 140 | } 141 | 142 | BOOL isShowMaxAndMinPoint = YES; 143 | CGFloat xPosition = 10; 144 | CGFloat chartCavanHeight = self.myScrollView.frame.size.height - YZCLabelHeight*(LINE_COUNT-1); 145 | 146 | NSInteger kAnimationTimeCount = 0; 147 | for (int i = 0; i < self.yLabels.count; i++) { 148 | NSString *valueString = self.yLabels[i]; 149 | float grade = ([valueString floatValue] - _yValueMin) / ((float)_yValueMax-_yValueMin); 150 | if (isnan(grade)) { 151 | grade = 0; 152 | } 153 | 154 | if ([valueString floatValue]) { 155 | kAnimationTimeCount += 1; 156 | CGPoint point = CGPointMake(xPosition+i*self.xLabelWidth, chartCavanHeight - grade * chartCavanHeight+YZCLabelHeight); 157 | [self.myScrollView.layer addSublayer:self.chartLine]; 158 | if (!self.progressline) { 159 | self.progressline = [UIBezierPath bezierPath]; 160 | [self.progressline setLineWidth:2.0]; 161 | [self.progressline setLineCapStyle:kCGLineCapRound]; 162 | [self.progressline setLineJoinStyle:kCGLineJoinRound]; 163 | [self.progressline moveToPoint:point]; 164 | } else { 165 | [self.progressline addLineToPoint:point]; 166 | } 167 | 168 | if (i == _yLabels.count-1) { 169 | self.lastPoint = point; //记录最后一个点 170 | self.isLastIndex = YES; 171 | } 172 | if (self.isDrawPoint) { //画点 173 | [self addPoint:point 174 | index:i 175 | isShow:isShowMaxAndMinPoint 176 | value:valueString]; 177 | } 178 | 179 | //显示最大值或最小值 180 | if (self.isShowMaxMinValue && ([valueString floatValue] == [[self.yLabels valueForKeyPath:@"@max.floatValue"] floatValue] || [valueString floatValue] == [[self.yLabels valueForKeyPath:@"@min.floatValue"] floatValue])) { 181 | [self setupLastValueLabelWithView:point 182 | value:[valueString integerValue] 183 | grade:grade 184 | chartCavanHeight:chartCavanHeight]; 185 | 186 | if (!self.isDrawPoint) { //如果没有画点才画最大最小的点,不然就不重复画点 187 | [self addPoint:point 188 | index:i 189 | isShow:isShowMaxAndMinPoint 190 | value:valueString]; 191 | } 192 | } 193 | 194 | self.chartLine.path = self.progressline.CGPath; 195 | self.chartLine.strokeColor = self.lineColor ? self.lineColor.CGColor : [UIColor greenColor].CGColor; 196 | self.chartLine.strokeEnd = 1.0; 197 | [self addAnimationWithLine:self.chartLine duration:kAnimationTimeCount * 0.1]; 198 | } else { 199 | self.progressline = nil; 200 | self.chartLine = nil; 201 | kAnimationTimeCount = 0; 202 | } 203 | } 204 | } 205 | 206 | - (void)addAnimationWithLine:(CAShapeLayer *)chartLine duration:(CGFloat)duration { 207 | CABasicAnimation *pathAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"]; 208 | 209 | pathAnimation.duration = duration; 210 | pathAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; 211 | pathAnimation.fromValue = [NSNumber numberWithFloat:0.0f]; 212 | pathAnimation.toValue = [NSNumber numberWithFloat:1.0f]; 213 | pathAnimation.autoreverses = NO; 214 | [chartLine addAnimation:pathAnimation forKey:@"strokeEndAnimation"]; 215 | } 216 | 217 | - (void)addPoint:(CGPoint)point index:(NSInteger)index isShow:(BOOL)isHollow value:(NSString *)value { 218 | CGFloat viewWH = 5; 219 | UIView *view = [[UIView alloc]initWithFrame:CGRectMake(5, 5, viewWH, viewWH)]; 220 | 221 | view.center = point; 222 | view.layer.masksToBounds = YES; 223 | view.layer.cornerRadius = viewWH*0.5; 224 | view.layer.borderWidth = 2; 225 | if (value) { 226 | view.layer.borderColor = self.pointColor ? self.pointColor.CGColor : [UIColor greenColor].CGColor; 227 | } else { 228 | view.layer.borderColor = [UIColor clearColor].CGColor; 229 | } 230 | view.backgroundColor = self.pointColor; 231 | [self.myScrollView addSubview:view]; 232 | 233 | 234 | NSString *valueString = [NSString stringWithFormat:@"%@%@", value, self.unitString.length ? self.unitString : @""]; 235 | //最后一个点显示数值在上面 236 | if (self.isLastIndex && self.isHiddenLastValue && valueString.length) { 237 | UIFont *font = self.textFont != nil ? self.textFont : [UIFont systemFontOfSize:10]; 238 | 239 | NSDictionary *attrs = @{NSFontAttributeName : font}; 240 | CGSize size = [valueString sizeWithAttributes:attrs]; 241 | CGFloat labelW = size.width; 242 | CGFloat labelH = size.height; 243 | CGFloat labelX = point.x + marginLeft * 0.5; 244 | if ([value integerValue] < 10) { 245 | labelX += viewWH * 0.5; 246 | } 247 | CGFloat labelY = point.y - 20; 248 | 249 | UILabel *valueLabel = [[UILabel alloc] initWithFrame:CGRectMake(labelX, labelY, labelW, labelH)]; 250 | valueLabel.text = valueString; 251 | valueLabel.textColor = [UIColor whiteColor]; 252 | valueLabel.font = font; 253 | valueLabel.textAlignment = NSTextAlignmentCenter; 254 | [self addSubview:valueLabel]; 255 | [self drawTipsViewWithFrame:CGRectMake(labelX - marginLeft * 0.5, labelY, valueLabel.frame.size.width + marginLeft, valueLabel.frame.size.height)]; 256 | } 257 | } 258 | 259 | /** 260 | 添加渐变图层 261 | */ 262 | - (void)addGradientLayer:(UIBezierPath *)bezier1 { 263 | CAShapeLayer *shadeLayer = [CAShapeLayer layer]; 264 | 265 | shadeLayer.path = bezier1.CGPath; 266 | shadeLayer.fillColor = [UIColor greenColor].CGColor; 267 | 268 | UIColor *color = self.lineColor ? self.lineColor : [UIColor greenColor]; 269 | CAGradientLayer *gradientLayer = [CAGradientLayer layer]; 270 | gradientLayer.frame = CGRectMake(5, 0, 0, self.myScrollView.bounds.size.height-20); 271 | gradientLayer.cornerRadius = 5; 272 | gradientLayer.masksToBounds = YES; 273 | gradientLayer.colors = @[(__bridge id)[color colorWithAlphaComponent:0.4].CGColor, (__bridge id)[color colorWithAlphaComponent:0.0].CGColor]; 274 | gradientLayer.locations = @[@(0.1f), @(1.0f)]; 275 | gradientLayer.startPoint = CGPointMake(0, 0); 276 | gradientLayer.endPoint = CGPointMake(1, 1); 277 | 278 | CALayer *baseLayer = [CALayer layer]; 279 | [baseLayer addSublayer:gradientLayer]; 280 | //截取渐变层 281 | [baseLayer setMask:shadeLayer]; 282 | [self.myScrollView.layer insertSublayer:baseLayer atIndex:0]; 283 | 284 | CABasicAnimation *anmi1 = [CABasicAnimation animation]; 285 | anmi1.keyPath = @"bounds"; 286 | anmi1.duration = self.yLabels.count*0.1; 287 | anmi1.toValue = [NSValue valueWithCGRect:CGRectMake(5, 0, 2*self.lastPoint.x, self.myScrollView.bounds.size.height-20)]; 288 | anmi1.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; 289 | anmi1.fillMode = kCAFillModeForwards; 290 | anmi1.autoreverses = NO; 291 | anmi1.removedOnCompletion = NO; 292 | 293 | [gradientLayer addAnimation:anmi1 forKey:@"bounds"]; 294 | } 295 | 296 | - (void)setupLastValueLabelWithView:(CGPoint)point value:(NSInteger)value grade:(CGFloat)grade chartCavanHeight:(CGFloat)chartCavanHeight { 297 | UIFont *font = self.textFont != nil ? self.textFont : [UIFont systemFontOfSize:10]; 298 | UILabel *valueLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 70, 31)]; 299 | 300 | valueLabel.text = [NSString stringWithFormat:@"%zd", value]; 301 | valueLabel.textColor = [UIColor blackColor]; 302 | valueLabel.font = font; 303 | [valueLabel sizeToFit]; 304 | CGPoint labelPoint = CGPointMake(valueLabel.text.length > 3 ? point.x - 3 : point.x, chartCavanHeight - grade * chartCavanHeight+YZCLabelHeight - 15); 305 | valueLabel.center = CGPointMake(labelPoint.x + 20, labelPoint.y); 306 | valueLabel.textAlignment = NSTextAlignmentCenter; 307 | [self addSubview:valueLabel]; 308 | } 309 | 310 | #pragma mark - setter && getter 311 | - (void)setIsHiddenUnit:(BOOL)isHiddenUnit { 312 | _isHiddenUnit = isHiddenUnit; 313 | if (!self.isHiddenUnit) { 314 | [self unitLabel]; 315 | } 316 | } 317 | 318 | - (void)setIsHiddenLastValue:(BOOL)isHiddenLastValue { 319 | _isHiddenLastValue = isHiddenLastValue; 320 | } 321 | 322 | - (void)setUnitString:(NSString *)unitString { 323 | _unitString = unitString; 324 | } 325 | 326 | - (void)setIntervalValue:(NSInteger)intervalValue { 327 | _intervalValue = intervalValue; 328 | } 329 | 330 | - (UILabel *)unitLabel { 331 | if (_unitLabel == nil) { 332 | UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(YZCLabelwidth-10, -10, 100, 40)]; 333 | label.text = self.unitString; 334 | label.textColor = [[UIColor grayColor] colorWithAlphaComponent:0.5]; 335 | [label sizeToFit]; 336 | label.textAlignment = NSTextAlignmentCenter; 337 | [label setFont:[UIFont systemFontOfSize:10]]; 338 | [self addSubview:label]; 339 | _unitLabel = label; 340 | } 341 | return _unitLabel; 342 | } 343 | 344 | - (CAShapeLayer *)chartLine { 345 | if (_chartLine == nil) { 346 | CAShapeLayer *chartLine = [CAShapeLayer layer]; 347 | chartLine.lineCap = kCALineCapRound; //设置线条拐角帽的样式 348 | chartLine.lineJoin = kCALineJoinRound; //设置两条线连结点的样式 349 | chartLine.fillColor = [[UIColor clearColor] CGColor]; 350 | chartLine.lineWidth = 2.0; 351 | chartLine.strokeEnd = 0.0; 352 | _chartLine = chartLine; 353 | } 354 | return _chartLine; 355 | } 356 | 357 | - (void)setXLabels:(NSMutableArray *)xLabels { 358 | _xLabels = xLabels; 359 | NSInteger count = xLabels.count; 360 | self.xLabelWidth = (self.myScrollView.frame.size.width - YZCLabelwidth * 0.5)/self.yLabels.count; 361 | 362 | for (int i = 0; i < count; i++) { 363 | if (i%self.intervalValue == 0 || i == count - 1) { 364 | NSString *labelText = xLabels[i]; 365 | 366 | UIFont *font = self.textFont != nil ? self.textFont : [UIFont systemFontOfSize:10]; 367 | 368 | NSDictionary *attrs = @{NSFontAttributeName : font}; 369 | CGSize size = [labelText sizeWithAttributes:attrs]; 370 | CGFloat labelW = size.width; 371 | CGFloat labelH = size.height; 372 | CGFloat labelX = marginLeft + i * self.xLabelWidth + YZCLabelwidth - labelW * 0.5; 373 | YzcLabel *label = [[YzcLabel alloc] initWithFrame:CGRectMake(labelX, self.frame.size.height - YZCLabelHeight + 5, labelW, labelH)]; 374 | label.text = labelText; 375 | if (self.textFont) { 376 | label.font = self.textFont; 377 | } 378 | [label sizeToFit]; 379 | [self addSubview:label]; 380 | 381 | if (self.isHiddenLastValue && i == count - 1) { 382 | label.textColor = [[UIColor blackColor] colorWithAlphaComponent:0.5]; 383 | } 384 | } 385 | } 386 | } 387 | 388 | - (void)setYLabels:(NSMutableArray *)yLabels { 389 | _yLabels = yLabels; 390 | self.xLabelWidth = (self.myScrollView.frame.size.width - YZCLabelwidth * 0.5)/self.yLabels.count; 391 | 392 | _yValueMax = [[self.yLabels valueForKeyPath:@"@max.floatValue"] floatValue]; 393 | _yValueMin = [[self.yLabels valueForKeyPath:@"@min.floatValue"] floatValue]; 394 | 395 | if (_chooseRange.max != _chooseRange.min) { 396 | _yValueMax = _chooseRange.max; 397 | _yValueMin = _chooseRange.min; 398 | } 399 | 400 | float level = (_yValueMax-_yValueMin) / (LINE_COUNT - 1); 401 | CGFloat chartCavanHeight = self.frame.size.height - YZCLabelHeight*(LINE_COUNT - 1); 402 | CGFloat levelHeight = chartCavanHeight / (LINE_COUNT - 1); 403 | 404 | for (int i = 0; i < LINE_COUNT; i++) { 405 | CGFloat labelValue = level * i+_yValueMin; 406 | if (labelValue >= 0 && i > 0 ) { 407 | YzcLabel *label = [[YzcLabel alloc] initWithFrame:CGRectMake(5, chartCavanHeight - i * levelHeight + 13, YZCLabelwidth+20, YZCLabelHeight)]; 408 | NSString *targetString; 409 | if (labelValue >= 1000) { 410 | targetString = [NSString stringWithFormat:@"%.1fk", (float)labelValue/1000]; 411 | } else { 412 | targetString = [NSString stringWithFormat:@"%.0f", labelValue]; 413 | } 414 | 415 | if (self.textFont) { 416 | label.font = self.textFont; 417 | } 418 | label.text = targetString; 419 | [label sizeToFit]; 420 | [self addSubview:label]; 421 | } 422 | } 423 | 424 | //画横线 425 | for (int i = 0; i < LINE_COUNT; i++) { 426 | UIColor *lineColor = self.HorizontalLinecColor ? self.HorizontalLinecColor : [[UIColor grayColor] colorWithAlphaComponent:0.5]; 427 | 428 | CGPoint startPoint = CGPointMake(marginLeft, YZCLabelHeight+i*levelHeight); 429 | CGPoint endPoint = CGPointMake(self.frame.size.width, YZCLabelHeight+i*levelHeight); 430 | if (i == LINE_COUNT - 1) { 431 | [self.myScrollView drawSolideLineWithMoveToPoint:startPoint 432 | lineToPoint:endPoint 433 | lineColor:lineColor]; 434 | } else { 435 | if (!self.isHiddenDashedLine) { 436 | [self.myScrollView drawDashLineWithStartPoint:startPoint 437 | endPoint:endPoint 438 | lineLength:2 439 | lineSpacing:1 440 | lineColor:lineColor]; 441 | } 442 | } 443 | } 444 | } 445 | 446 | @end 447 | -------------------------------------------------------------------------------- /YzcChartExample.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 045383101DD411A400BAF33D /* YzcChartExampleTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 0453830F1DD411A400BAF33D /* YzcChartExampleTests.m */; }; 11 | 0453831B1DD411A400BAF33D /* YzcChartUIExampleTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 0453831A1DD411A400BAF33D /* YzcChartUIExampleTests.m */; }; 12 | D71BCEA01E895F090044B4B9 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D71BCE801E895F090044B4B9 /* Assets.xcassets */; }; 13 | D71BCEA11E895F090044B4B9 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = D71BCE811E895F090044B4B9 /* LaunchScreen.storyboard */; }; 14 | D71BCEA21E895F090044B4B9 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = D71BCE831E895F090044B4B9 /* Main.storyboard */; }; 15 | D71BCEA41E895F090044B4B9 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = D71BCE871E895F090044B4B9 /* main.m */; }; 16 | D71BCEC81E8961A20044B4B9 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = D71BCEB01E8961A20044B4B9 /* AppDelegate.m */; }; 17 | D71BCEC91E8961A20044B4B9 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = D71BCEB21E8961A20044B4B9 /* ViewController.m */; }; 18 | D71BCECB1E8961A20044B4B9 /* BarChartModel.m in Sources */ = {isa = PBXBuildFile; fileRef = D71BCEB81E8961A20044B4B9 /* BarChartModel.m */; }; 19 | D71BCECC1E8961A20044B4B9 /* YzcConfigModel.m in Sources */ = {isa = PBXBuildFile; fileRef = D71BCEBA1E8961A20044B4B9 /* YzcConfigModel.m */; }; 20 | D71BCECD1E8961A20044B4B9 /* UIView+Extension.m in Sources */ = {isa = PBXBuildFile; fileRef = D71BCEBC1E8961A20044B4B9 /* UIView+Extension.m */; }; 21 | D71BCECE1E8961A20044B4B9 /* YzcBar.m in Sources */ = {isa = PBXBuildFile; fileRef = D71BCEBE1E8961A20044B4B9 /* YzcBar.m */; }; 22 | D71BCECF1E8961A20044B4B9 /* YzcBarChart.m in Sources */ = {isa = PBXBuildFile; fileRef = D71BCEC01E8961A20044B4B9 /* YzcBarChart.m */; }; 23 | D71BCED01E8961A20044B4B9 /* YzcChartView.m in Sources */ = {isa = PBXBuildFile; fileRef = D71BCEC21E8961A20044B4B9 /* YzcChartView.m */; }; 24 | D71BCED11E8961A20044B4B9 /* YzcLabel.m in Sources */ = {isa = PBXBuildFile; fileRef = D71BCEC51E8961A20044B4B9 /* YzcLabel.m */; }; 25 | D71BCED21E8961A20044B4B9 /* YzcLineChart.m in Sources */ = {isa = PBXBuildFile; fileRef = D71BCEC71E8961A20044B4B9 /* YzcLineChart.m */; }; 26 | /* End PBXBuildFile section */ 27 | 28 | /* Begin PBXContainerItemProxy section */ 29 | 0453830C1DD411A400BAF33D /* PBXContainerItemProxy */ = { 30 | isa = PBXContainerItemProxy; 31 | containerPortal = 045382EA1DD411A400BAF33D /* Project object */; 32 | proxyType = 1; 33 | remoteGlobalIDString = 045382F11DD411A400BAF33D; 34 | remoteInfo = YzcChart; 35 | }; 36 | 045383171DD411A400BAF33D /* PBXContainerItemProxy */ = { 37 | isa = PBXContainerItemProxy; 38 | containerPortal = 045382EA1DD411A400BAF33D /* Project object */; 39 | proxyType = 1; 40 | remoteGlobalIDString = 045382F11DD411A400BAF33D; 41 | remoteInfo = YzcChart; 42 | }; 43 | /* End PBXContainerItemProxy section */ 44 | 45 | /* Begin PBXFileReference section */ 46 | 045382F21DD411A400BAF33D /* YzcChartExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = YzcChartExample.app; sourceTree = BUILT_PRODUCTS_DIR; }; 47 | 0453830B1DD411A400BAF33D /* YzcChartExampleTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = YzcChartExampleTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 48 | 0453830F1DD411A400BAF33D /* YzcChartExampleTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = YzcChartExampleTests.m; sourceTree = ""; }; 49 | 045383111DD411A400BAF33D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 50 | 045383161DD411A400BAF33D /* YzcChartExampleUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = YzcChartExampleUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 51 | 0453831A1DD411A400BAF33D /* YzcChartUIExampleTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = YzcChartUIExampleTests.m; sourceTree = ""; }; 52 | 0453831C1DD411A400BAF33D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 53 | D71BCE801E895F090044B4B9 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 54 | D71BCE821E895F090044B4B9 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 55 | D71BCE841E895F090044B4B9 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 56 | D71BCE861E895F090044B4B9 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 57 | D71BCE871E895F090044B4B9 /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 58 | D71BCEAF1E8961A20044B4B9 /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 59 | D71BCEB01E8961A20044B4B9 /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 60 | D71BCEB11E8961A20044B4B9 /* ViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 61 | D71BCEB21E8961A20044B4B9 /* ViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 62 | D71BCEB71E8961A20044B4B9 /* BarChartModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BarChartModel.h; sourceTree = ""; }; 63 | D71BCEB81E8961A20044B4B9 /* BarChartModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BarChartModel.m; sourceTree = ""; }; 64 | D71BCEB91E8961A20044B4B9 /* YzcConfigModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YzcConfigModel.h; sourceTree = ""; }; 65 | D71BCEBA1E8961A20044B4B9 /* YzcConfigModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = YzcConfigModel.m; sourceTree = ""; }; 66 | D71BCEBB1E8961A20044B4B9 /* UIView+Extension.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIView+Extension.h"; sourceTree = ""; }; 67 | D71BCEBC1E8961A20044B4B9 /* UIView+Extension.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIView+Extension.m"; sourceTree = ""; }; 68 | D71BCEBD1E8961A20044B4B9 /* YzcBar.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YzcBar.h; sourceTree = ""; }; 69 | D71BCEBE1E8961A20044B4B9 /* YzcBar.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = YzcBar.m; sourceTree = ""; }; 70 | D71BCEBF1E8961A20044B4B9 /* YzcBarChart.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YzcBarChart.h; sourceTree = ""; }; 71 | D71BCEC01E8961A20044B4B9 /* YzcBarChart.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = YzcBarChart.m; sourceTree = ""; }; 72 | D71BCEC11E8961A20044B4B9 /* YzcChartView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YzcChartView.h; sourceTree = ""; }; 73 | D71BCEC21E8961A20044B4B9 /* YzcChartView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = YzcChartView.m; sourceTree = ""; }; 74 | D71BCEC31E8961A20044B4B9 /* YzcCommonMacros.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YzcCommonMacros.h; sourceTree = ""; }; 75 | D71BCEC41E8961A20044B4B9 /* YzcLabel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YzcLabel.h; sourceTree = ""; }; 76 | D71BCEC51E8961A20044B4B9 /* YzcLabel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = YzcLabel.m; sourceTree = ""; }; 77 | D71BCEC61E8961A20044B4B9 /* YzcLineChart.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YzcLineChart.h; sourceTree = ""; }; 78 | D71BCEC71E8961A20044B4B9 /* YzcLineChart.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = YzcLineChart.m; sourceTree = ""; }; 79 | /* End PBXFileReference section */ 80 | 81 | /* Begin PBXFrameworksBuildPhase section */ 82 | 045382EF1DD411A400BAF33D /* Frameworks */ = { 83 | isa = PBXFrameworksBuildPhase; 84 | buildActionMask = 2147483647; 85 | files = ( 86 | ); 87 | runOnlyForDeploymentPostprocessing = 0; 88 | }; 89 | 045383081DD411A400BAF33D /* Frameworks */ = { 90 | isa = PBXFrameworksBuildPhase; 91 | buildActionMask = 2147483647; 92 | files = ( 93 | ); 94 | runOnlyForDeploymentPostprocessing = 0; 95 | }; 96 | 045383131DD411A400BAF33D /* Frameworks */ = { 97 | isa = PBXFrameworksBuildPhase; 98 | buildActionMask = 2147483647; 99 | files = ( 100 | ); 101 | runOnlyForDeploymentPostprocessing = 0; 102 | }; 103 | /* End PBXFrameworksBuildPhase section */ 104 | 105 | /* Begin PBXGroup section */ 106 | 045382E91DD411A400BAF33D = { 107 | isa = PBXGroup; 108 | children = ( 109 | D71BCE7D1E895F090044B4B9 /* YzcChartExample */, 110 | 0453830E1DD411A400BAF33D /* YzcChartExampleTests */, 111 | 045383191DD411A400BAF33D /* YzcChartUIExampleTests */, 112 | 045382F31DD411A400BAF33D /* Products */, 113 | ); 114 | sourceTree = ""; 115 | }; 116 | 045382F31DD411A400BAF33D /* Products */ = { 117 | isa = PBXGroup; 118 | children = ( 119 | 045382F21DD411A400BAF33D /* YzcChartExample.app */, 120 | 0453830B1DD411A400BAF33D /* YzcChartExampleTests.xctest */, 121 | 045383161DD411A400BAF33D /* YzcChartExampleUITests.xctest */, 122 | ); 123 | name = Products; 124 | sourceTree = ""; 125 | }; 126 | 0453830E1DD411A400BAF33D /* YzcChartExampleTests */ = { 127 | isa = PBXGroup; 128 | children = ( 129 | 0453830F1DD411A400BAF33D /* YzcChartExampleTests.m */, 130 | 045383111DD411A400BAF33D /* Info.plist */, 131 | ); 132 | name = YzcChartExampleTests; 133 | path = YzcChartTests; 134 | sourceTree = ""; 135 | }; 136 | 045383191DD411A400BAF33D /* YzcChartUIExampleTests */ = { 137 | isa = PBXGroup; 138 | children = ( 139 | 0453831A1DD411A400BAF33D /* YzcChartUIExampleTests.m */, 140 | 0453831C1DD411A400BAF33D /* Info.plist */, 141 | ); 142 | name = YzcChartUIExampleTests; 143 | path = YzcChartUITests; 144 | sourceTree = ""; 145 | }; 146 | D71BCE7D1E895F090044B4B9 /* YzcChartExample */ = { 147 | isa = PBXGroup; 148 | children = ( 149 | D71BCE801E895F090044B4B9 /* Assets.xcassets */, 150 | D71BCE851E895F090044B4B9 /* Classes */, 151 | D71BCE861E895F090044B4B9 /* Info.plist */, 152 | D71BCE811E895F090044B4B9 /* LaunchScreen.storyboard */, 153 | D71BCE871E895F090044B4B9 /* main.m */, 154 | D71BCE831E895F090044B4B9 /* Main.storyboard */, 155 | ); 156 | path = YzcChartExample; 157 | sourceTree = ""; 158 | }; 159 | D71BCE851E895F090044B4B9 /* Classes */ = { 160 | isa = PBXGroup; 161 | children = ( 162 | D71BCEAF1E8961A20044B4B9 /* AppDelegate.h */, 163 | D71BCEB01E8961A20044B4B9 /* AppDelegate.m */, 164 | D71BCEB11E8961A20044B4B9 /* ViewController.h */, 165 | D71BCEB21E8961A20044B4B9 /* ViewController.m */, 166 | D71BCEB31E8961A20044B4B9 /* YzcChart */, 167 | ); 168 | path = Classes; 169 | sourceTree = ""; 170 | }; 171 | D71BCEB31E8961A20044B4B9 /* YzcChart */ = { 172 | isa = PBXGroup; 173 | children = ( 174 | D71BCEB61E8961A20044B4B9 /* Model */, 175 | D71BCEBB1E8961A20044B4B9 /* UIView+Extension.h */, 176 | D71BCEBC1E8961A20044B4B9 /* UIView+Extension.m */, 177 | D71BCEBD1E8961A20044B4B9 /* YzcBar.h */, 178 | D71BCEBE1E8961A20044B4B9 /* YzcBar.m */, 179 | D71BCEBF1E8961A20044B4B9 /* YzcBarChart.h */, 180 | D71BCEC01E8961A20044B4B9 /* YzcBarChart.m */, 181 | D71BCEC11E8961A20044B4B9 /* YzcChartView.h */, 182 | D71BCEC21E8961A20044B4B9 /* YzcChartView.m */, 183 | D71BCEC31E8961A20044B4B9 /* YzcCommonMacros.h */, 184 | D71BCEC41E8961A20044B4B9 /* YzcLabel.h */, 185 | D71BCEC51E8961A20044B4B9 /* YzcLabel.m */, 186 | D71BCEC61E8961A20044B4B9 /* YzcLineChart.h */, 187 | D71BCEC71E8961A20044B4B9 /* YzcLineChart.m */, 188 | ); 189 | path = YzcChart; 190 | sourceTree = ""; 191 | }; 192 | D71BCEB61E8961A20044B4B9 /* Model */ = { 193 | isa = PBXGroup; 194 | children = ( 195 | D71BCEB71E8961A20044B4B9 /* BarChartModel.h */, 196 | D71BCEB81E8961A20044B4B9 /* BarChartModel.m */, 197 | D71BCEB91E8961A20044B4B9 /* YzcConfigModel.h */, 198 | D71BCEBA1E8961A20044B4B9 /* YzcConfigModel.m */, 199 | ); 200 | path = Model; 201 | sourceTree = ""; 202 | }; 203 | /* End PBXGroup section */ 204 | 205 | /* Begin PBXNativeTarget section */ 206 | 045382F11DD411A400BAF33D /* YzcChartExample */ = { 207 | isa = PBXNativeTarget; 208 | buildConfigurationList = 0453831F1DD411A400BAF33D /* Build configuration list for PBXNativeTarget "YzcChartExample" */; 209 | buildPhases = ( 210 | 045382EE1DD411A400BAF33D /* Sources */, 211 | 045382EF1DD411A400BAF33D /* Frameworks */, 212 | 045382F01DD411A400BAF33D /* Resources */, 213 | ); 214 | buildRules = ( 215 | ); 216 | dependencies = ( 217 | ); 218 | name = YzcChartExample; 219 | productName = YzcChart; 220 | productReference = 045382F21DD411A400BAF33D /* YzcChartExample.app */; 221 | productType = "com.apple.product-type.application"; 222 | }; 223 | 0453830A1DD411A400BAF33D /* YzcChartExampleTests */ = { 224 | isa = PBXNativeTarget; 225 | buildConfigurationList = 045383221DD411A400BAF33D /* Build configuration list for PBXNativeTarget "YzcChartExampleTests" */; 226 | buildPhases = ( 227 | 045383071DD411A400BAF33D /* Sources */, 228 | 045383081DD411A400BAF33D /* Frameworks */, 229 | 045383091DD411A400BAF33D /* Resources */, 230 | ); 231 | buildRules = ( 232 | ); 233 | dependencies = ( 234 | 0453830D1DD411A400BAF33D /* PBXTargetDependency */, 235 | ); 236 | name = YzcChartExampleTests; 237 | productName = YzcChartTests; 238 | productReference = 0453830B1DD411A400BAF33D /* YzcChartExampleTests.xctest */; 239 | productType = "com.apple.product-type.bundle.unit-test"; 240 | }; 241 | 045383151DD411A400BAF33D /* YzcChartExampleUITests */ = { 242 | isa = PBXNativeTarget; 243 | buildConfigurationList = 045383251DD411A400BAF33D /* Build configuration list for PBXNativeTarget "YzcChartExampleUITests" */; 244 | buildPhases = ( 245 | 045383121DD411A400BAF33D /* Sources */, 246 | 045383131DD411A400BAF33D /* Frameworks */, 247 | 045383141DD411A400BAF33D /* Resources */, 248 | ); 249 | buildRules = ( 250 | ); 251 | dependencies = ( 252 | 045383181DD411A400BAF33D /* PBXTargetDependency */, 253 | ); 254 | name = YzcChartExampleUITests; 255 | productName = YzcChartUITests; 256 | productReference = 045383161DD411A400BAF33D /* YzcChartExampleUITests.xctest */; 257 | productType = "com.apple.product-type.bundle.ui-testing"; 258 | }; 259 | /* End PBXNativeTarget section */ 260 | 261 | /* Begin PBXProject section */ 262 | 045382EA1DD411A400BAF33D /* Project object */ = { 263 | isa = PBXProject; 264 | attributes = { 265 | LastUpgradeCheck = 0820; 266 | ORGANIZATIONNAME = yzc; 267 | TargetAttributes = { 268 | 045382F11DD411A400BAF33D = { 269 | CreatedOnToolsVersion = 8.1; 270 | ProvisioningStyle = Automatic; 271 | }; 272 | 0453830A1DD411A400BAF33D = { 273 | CreatedOnToolsVersion = 8.1; 274 | DevelopmentTeam = ZFHSP8SEMY; 275 | ProvisioningStyle = Automatic; 276 | TestTargetID = 045382F11DD411A400BAF33D; 277 | }; 278 | 045383151DD411A400BAF33D = { 279 | CreatedOnToolsVersion = 8.1; 280 | DevelopmentTeam = ZFHSP8SEMY; 281 | ProvisioningStyle = Automatic; 282 | TestTargetID = 045382F11DD411A400BAF33D; 283 | }; 284 | }; 285 | }; 286 | buildConfigurationList = 045382ED1DD411A400BAF33D /* Build configuration list for PBXProject "YzcChartExample" */; 287 | compatibilityVersion = "Xcode 3.2"; 288 | developmentRegion = English; 289 | hasScannedForEncodings = 0; 290 | knownRegions = ( 291 | en, 292 | Base, 293 | ); 294 | mainGroup = 045382E91DD411A400BAF33D; 295 | productRefGroup = 045382F31DD411A400BAF33D /* Products */; 296 | projectDirPath = ""; 297 | projectRoot = ""; 298 | targets = ( 299 | 045382F11DD411A400BAF33D /* YzcChartExample */, 300 | 0453830A1DD411A400BAF33D /* YzcChartExampleTests */, 301 | 045383151DD411A400BAF33D /* YzcChartExampleUITests */, 302 | ); 303 | }; 304 | /* End PBXProject section */ 305 | 306 | /* Begin PBXResourcesBuildPhase section */ 307 | 045382F01DD411A400BAF33D /* Resources */ = { 308 | isa = PBXResourcesBuildPhase; 309 | buildActionMask = 2147483647; 310 | files = ( 311 | D71BCEA21E895F090044B4B9 /* Main.storyboard in Resources */, 312 | D71BCEA01E895F090044B4B9 /* Assets.xcassets in Resources */, 313 | D71BCEA11E895F090044B4B9 /* LaunchScreen.storyboard in Resources */, 314 | ); 315 | runOnlyForDeploymentPostprocessing = 0; 316 | }; 317 | 045383091DD411A400BAF33D /* Resources */ = { 318 | isa = PBXResourcesBuildPhase; 319 | buildActionMask = 2147483647; 320 | files = ( 321 | ); 322 | runOnlyForDeploymentPostprocessing = 0; 323 | }; 324 | 045383141DD411A400BAF33D /* Resources */ = { 325 | isa = PBXResourcesBuildPhase; 326 | buildActionMask = 2147483647; 327 | files = ( 328 | ); 329 | runOnlyForDeploymentPostprocessing = 0; 330 | }; 331 | /* End PBXResourcesBuildPhase section */ 332 | 333 | /* Begin PBXSourcesBuildPhase section */ 334 | 045382EE1DD411A400BAF33D /* Sources */ = { 335 | isa = PBXSourcesBuildPhase; 336 | buildActionMask = 2147483647; 337 | files = ( 338 | D71BCEC91E8961A20044B4B9 /* ViewController.m in Sources */, 339 | D71BCED21E8961A20044B4B9 /* YzcLineChart.m in Sources */, 340 | D71BCEC81E8961A20044B4B9 /* AppDelegate.m in Sources */, 341 | D71BCECB1E8961A20044B4B9 /* BarChartModel.m in Sources */, 342 | D71BCECD1E8961A20044B4B9 /* UIView+Extension.m in Sources */, 343 | D71BCECC1E8961A20044B4B9 /* YzcConfigModel.m in Sources */, 344 | D71BCED01E8961A20044B4B9 /* YzcChartView.m in Sources */, 345 | D71BCECE1E8961A20044B4B9 /* YzcBar.m in Sources */, 346 | D71BCED11E8961A20044B4B9 /* YzcLabel.m in Sources */, 347 | D71BCEA41E895F090044B4B9 /* main.m in Sources */, 348 | D71BCECF1E8961A20044B4B9 /* YzcBarChart.m in Sources */, 349 | ); 350 | runOnlyForDeploymentPostprocessing = 0; 351 | }; 352 | 045383071DD411A400BAF33D /* Sources */ = { 353 | isa = PBXSourcesBuildPhase; 354 | buildActionMask = 2147483647; 355 | files = ( 356 | 045383101DD411A400BAF33D /* YzcChartExampleTests.m in Sources */, 357 | ); 358 | runOnlyForDeploymentPostprocessing = 0; 359 | }; 360 | 045383121DD411A400BAF33D /* Sources */ = { 361 | isa = PBXSourcesBuildPhase; 362 | buildActionMask = 2147483647; 363 | files = ( 364 | 0453831B1DD411A400BAF33D /* YzcChartUIExampleTests.m in Sources */, 365 | ); 366 | runOnlyForDeploymentPostprocessing = 0; 367 | }; 368 | /* End PBXSourcesBuildPhase section */ 369 | 370 | /* Begin PBXTargetDependency section */ 371 | 0453830D1DD411A400BAF33D /* PBXTargetDependency */ = { 372 | isa = PBXTargetDependency; 373 | target = 045382F11DD411A400BAF33D /* YzcChartExample */; 374 | targetProxy = 0453830C1DD411A400BAF33D /* PBXContainerItemProxy */; 375 | }; 376 | 045383181DD411A400BAF33D /* PBXTargetDependency */ = { 377 | isa = PBXTargetDependency; 378 | target = 045382F11DD411A400BAF33D /* YzcChartExample */; 379 | targetProxy = 045383171DD411A400BAF33D /* PBXContainerItemProxy */; 380 | }; 381 | /* End PBXTargetDependency section */ 382 | 383 | /* Begin PBXVariantGroup section */ 384 | D71BCE811E895F090044B4B9 /* LaunchScreen.storyboard */ = { 385 | isa = PBXVariantGroup; 386 | children = ( 387 | D71BCE821E895F090044B4B9 /* Base */, 388 | ); 389 | name = LaunchScreen.storyboard; 390 | sourceTree = ""; 391 | }; 392 | D71BCE831E895F090044B4B9 /* Main.storyboard */ = { 393 | isa = PBXVariantGroup; 394 | children = ( 395 | D71BCE841E895F090044B4B9 /* Base */, 396 | ); 397 | name = Main.storyboard; 398 | sourceTree = ""; 399 | }; 400 | /* End PBXVariantGroup section */ 401 | 402 | /* Begin XCBuildConfiguration section */ 403 | 0453831D1DD411A400BAF33D /* Debug */ = { 404 | isa = XCBuildConfiguration; 405 | buildSettings = { 406 | ALWAYS_SEARCH_USER_PATHS = NO; 407 | CLANG_ANALYZER_NONNULL = YES; 408 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 409 | CLANG_CXX_LIBRARY = "libc++"; 410 | CLANG_ENABLE_MODULES = YES; 411 | CLANG_ENABLE_OBJC_ARC = YES; 412 | CLANG_WARN_BOOL_CONVERSION = YES; 413 | CLANG_WARN_CONSTANT_CONVERSION = YES; 414 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 415 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 416 | CLANG_WARN_EMPTY_BODY = YES; 417 | CLANG_WARN_ENUM_CONVERSION = YES; 418 | CLANG_WARN_INFINITE_RECURSION = YES; 419 | CLANG_WARN_INT_CONVERSION = YES; 420 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 421 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 422 | CLANG_WARN_SUSPICIOUS_MOVES = YES; 423 | CLANG_WARN_UNREACHABLE_CODE = YES; 424 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 425 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 426 | COPY_PHASE_STRIP = NO; 427 | DEBUG_INFORMATION_FORMAT = dwarf; 428 | ENABLE_STRICT_OBJC_MSGSEND = YES; 429 | ENABLE_TESTABILITY = YES; 430 | GCC_C_LANGUAGE_STANDARD = gnu99; 431 | GCC_DYNAMIC_NO_PIC = NO; 432 | GCC_NO_COMMON_BLOCKS = YES; 433 | GCC_OPTIMIZATION_LEVEL = 0; 434 | GCC_PREPROCESSOR_DEFINITIONS = ( 435 | "DEBUG=1", 436 | "$(inherited)", 437 | ); 438 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 439 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 440 | GCC_WARN_UNDECLARED_SELECTOR = YES; 441 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 442 | GCC_WARN_UNUSED_FUNCTION = YES; 443 | GCC_WARN_UNUSED_VARIABLE = YES; 444 | IPHONEOS_DEPLOYMENT_TARGET = 10.1; 445 | MTL_ENABLE_DEBUG_INFO = YES; 446 | ONLY_ACTIVE_ARCH = YES; 447 | SDKROOT = iphoneos; 448 | }; 449 | name = Debug; 450 | }; 451 | 0453831E1DD411A400BAF33D /* Release */ = { 452 | isa = XCBuildConfiguration; 453 | buildSettings = { 454 | ALWAYS_SEARCH_USER_PATHS = NO; 455 | CLANG_ANALYZER_NONNULL = YES; 456 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 457 | CLANG_CXX_LIBRARY = "libc++"; 458 | CLANG_ENABLE_MODULES = YES; 459 | CLANG_ENABLE_OBJC_ARC = YES; 460 | CLANG_WARN_BOOL_CONVERSION = YES; 461 | CLANG_WARN_CONSTANT_CONVERSION = YES; 462 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 463 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 464 | CLANG_WARN_EMPTY_BODY = YES; 465 | CLANG_WARN_ENUM_CONVERSION = YES; 466 | CLANG_WARN_INFINITE_RECURSION = YES; 467 | CLANG_WARN_INT_CONVERSION = YES; 468 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 469 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 470 | CLANG_WARN_SUSPICIOUS_MOVES = YES; 471 | CLANG_WARN_UNREACHABLE_CODE = YES; 472 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 473 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 474 | COPY_PHASE_STRIP = NO; 475 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 476 | ENABLE_NS_ASSERTIONS = NO; 477 | ENABLE_STRICT_OBJC_MSGSEND = YES; 478 | GCC_C_LANGUAGE_STANDARD = gnu99; 479 | GCC_NO_COMMON_BLOCKS = YES; 480 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 481 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 482 | GCC_WARN_UNDECLARED_SELECTOR = YES; 483 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 484 | GCC_WARN_UNUSED_FUNCTION = YES; 485 | GCC_WARN_UNUSED_VARIABLE = YES; 486 | IPHONEOS_DEPLOYMENT_TARGET = 10.1; 487 | MTL_ENABLE_DEBUG_INFO = NO; 488 | SDKROOT = iphoneos; 489 | VALIDATE_PRODUCT = YES; 490 | }; 491 | name = Release; 492 | }; 493 | 045383201DD411A400BAF33D /* Debug */ = { 494 | isa = XCBuildConfiguration; 495 | buildSettings = { 496 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 497 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 498 | DEVELOPMENT_TEAM = ""; 499 | INFOPLIST_FILE = "$(SRCROOT)/YzcChartExample/Info.plist"; 500 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 501 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 502 | PRODUCT_BUNDLE_IDENTIFIER = com.yzc.YzcChartExample; 503 | PRODUCT_NAME = "$(TARGET_NAME)"; 504 | }; 505 | name = Debug; 506 | }; 507 | 045383211DD411A400BAF33D /* Release */ = { 508 | isa = XCBuildConfiguration; 509 | buildSettings = { 510 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 511 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 512 | DEVELOPMENT_TEAM = ""; 513 | INFOPLIST_FILE = "$(SRCROOT)/YzcChartExample/Info.plist"; 514 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 515 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 516 | PRODUCT_BUNDLE_IDENTIFIER = com.yzc.YzcChartExample; 517 | PRODUCT_NAME = "$(TARGET_NAME)"; 518 | }; 519 | name = Release; 520 | }; 521 | 045383231DD411A400BAF33D /* Debug */ = { 522 | isa = XCBuildConfiguration; 523 | buildSettings = { 524 | BUNDLE_LOADER = "$(TEST_HOST)"; 525 | DEVELOPMENT_TEAM = ZFHSP8SEMY; 526 | INFOPLIST_FILE = YzcChartExampleTests/Info.plist; 527 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 528 | PRODUCT_BUNDLE_IDENTIFIER = com.yzc.YzcChartTests; 529 | PRODUCT_NAME = "$(TARGET_NAME)"; 530 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/YzcChartExample.app/YzcChartExample"; 531 | }; 532 | name = Debug; 533 | }; 534 | 045383241DD411A400BAF33D /* Release */ = { 535 | isa = XCBuildConfiguration; 536 | buildSettings = { 537 | BUNDLE_LOADER = "$(TEST_HOST)"; 538 | DEVELOPMENT_TEAM = ZFHSP8SEMY; 539 | INFOPLIST_FILE = YzcChartExampleTests/Info.plist; 540 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 541 | PRODUCT_BUNDLE_IDENTIFIER = com.yzc.YzcChartTests; 542 | PRODUCT_NAME = "$(TARGET_NAME)"; 543 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/YzcChartExample.app/YzcChartExample"; 544 | }; 545 | name = Release; 546 | }; 547 | 045383261DD411A400BAF33D /* Debug */ = { 548 | isa = XCBuildConfiguration; 549 | buildSettings = { 550 | DEVELOPMENT_TEAM = ZFHSP8SEMY; 551 | INFOPLIST_FILE = YzcChartUIExampleTests/Info.plist; 552 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 553 | PRODUCT_BUNDLE_IDENTIFIER = com.yzc.YzcChartUITests; 554 | PRODUCT_NAME = "$(TARGET_NAME)"; 555 | TEST_TARGET_NAME = YzcChart; 556 | }; 557 | name = Debug; 558 | }; 559 | 045383271DD411A400BAF33D /* Release */ = { 560 | isa = XCBuildConfiguration; 561 | buildSettings = { 562 | DEVELOPMENT_TEAM = ZFHSP8SEMY; 563 | INFOPLIST_FILE = YzcChartUIExampleTests/Info.plist; 564 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 565 | PRODUCT_BUNDLE_IDENTIFIER = com.yzc.YzcChartUITests; 566 | PRODUCT_NAME = "$(TARGET_NAME)"; 567 | TEST_TARGET_NAME = YzcChart; 568 | }; 569 | name = Release; 570 | }; 571 | /* End XCBuildConfiguration section */ 572 | 573 | /* Begin XCConfigurationList section */ 574 | 045382ED1DD411A400BAF33D /* Build configuration list for PBXProject "YzcChartExample" */ = { 575 | isa = XCConfigurationList; 576 | buildConfigurations = ( 577 | 0453831D1DD411A400BAF33D /* Debug */, 578 | 0453831E1DD411A400BAF33D /* Release */, 579 | ); 580 | defaultConfigurationIsVisible = 0; 581 | defaultConfigurationName = Release; 582 | }; 583 | 0453831F1DD411A400BAF33D /* Build configuration list for PBXNativeTarget "YzcChartExample" */ = { 584 | isa = XCConfigurationList; 585 | buildConfigurations = ( 586 | 045383201DD411A400BAF33D /* Debug */, 587 | 045383211DD411A400BAF33D /* Release */, 588 | ); 589 | defaultConfigurationIsVisible = 0; 590 | defaultConfigurationName = Release; 591 | }; 592 | 045383221DD411A400BAF33D /* Build configuration list for PBXNativeTarget "YzcChartExampleTests" */ = { 593 | isa = XCConfigurationList; 594 | buildConfigurations = ( 595 | 045383231DD411A400BAF33D /* Debug */, 596 | 045383241DD411A400BAF33D /* Release */, 597 | ); 598 | defaultConfigurationIsVisible = 0; 599 | defaultConfigurationName = Release; 600 | }; 601 | 045383251DD411A400BAF33D /* Build configuration list for PBXNativeTarget "YzcChartExampleUITests" */ = { 602 | isa = XCConfigurationList; 603 | buildConfigurations = ( 604 | 045383261DD411A400BAF33D /* Debug */, 605 | 045383271DD411A400BAF33D /* Release */, 606 | ); 607 | defaultConfigurationIsVisible = 0; 608 | defaultConfigurationName = Release; 609 | }; 610 | /* End XCConfigurationList section */ 611 | }; 612 | rootObject = 045382EA1DD411A400BAF33D /* Project object */; 613 | } 614 | -------------------------------------------------------------------------------- /YzcChartExample.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /YzcChartExample.xcodeproj/xcuserdata/yezhicheng.xcuserdatad/xcschemes/YzcChartExample.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 43 | 49 | 50 | 51 | 52 | 53 | 59 | 60 | 61 | 62 | 63 | 64 | 74 | 76 | 82 | 83 | 84 | 85 | 86 | 87 | 93 | 95 | 101 | 102 | 103 | 104 | 106 | 107 | 110 | 111 | 112 | -------------------------------------------------------------------------------- /YzcChartExample/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | } 33 | ], 34 | "info" : { 35 | "version" : 1, 36 | "author" : "xcode" 37 | } 38 | } -------------------------------------------------------------------------------- /YzcChartExample/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /YzcChartExample/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /YzcChartExample/Classes/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // YzcChart 4 | // 5 | // Created by mac on 16/11/10. 6 | // Copyright © 2016年 yzc. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | 16 | @end 17 | 18 | -------------------------------------------------------------------------------- /YzcChartExample/Classes/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // YzcChart 4 | // 5 | // Created by mac on 16/11/10. 6 | // Copyright © 2016年 yzc. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | 11 | @interface AppDelegate () 12 | 13 | @end 14 | 15 | @implementation AppDelegate 16 | 17 | 18 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 19 | // Override point for customization after application launch. 20 | return YES; 21 | } 22 | 23 | 24 | - (void)applicationWillResignActive:(UIApplication *)application { 25 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 26 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 27 | } 28 | 29 | 30 | - (void)applicationDidEnterBackground:(UIApplication *)application { 31 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 32 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 33 | } 34 | 35 | 36 | - (void)applicationWillEnterForeground:(UIApplication *)application { 37 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 38 | } 39 | 40 | 41 | - (void)applicationDidBecomeActive:(UIApplication *)application { 42 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 43 | } 44 | 45 | 46 | - (void)applicationWillTerminate:(UIApplication *)application { 47 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 48 | } 49 | 50 | 51 | @end 52 | -------------------------------------------------------------------------------- /YzcChartExample/Classes/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // YzcChart 4 | // 5 | // Created by mac on 16/11/10. 6 | // Copyright © 2016年 yzc. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ViewController : UIViewController 12 | 13 | 14 | @end 15 | 16 | -------------------------------------------------------------------------------- /YzcChartExample/Classes/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // YzcChart 4 | // 5 | // Created by mac on 16/11/10. 6 | // Copyright © 2016年 yzc. All rights reserved. 7 | // 8 | 9 | #import "ViewController.h" 10 | #import "YzcLineChart.h" 11 | #import "YzcBarChart.h" 12 | #import "YzcChartView.h" 13 | 14 | @interface ViewController () 15 | 16 | @property (nonatomic, strong) UIScrollView *scrollView; 17 | 18 | @end 19 | 20 | @implementation ViewController 21 | 22 | - (void)viewDidLoad { 23 | [super viewDidLoad]; 24 | 25 | self.scrollView = [[UIScrollView alloc] initWithFrame:self.view.frame]; 26 | [self.view addSubview:self.scrollView]; 27 | 28 | YzcChartView *chartView = [[YzcChartView alloc] initWithFrame:CGRectMake(10, 100, self.view.frame.size.width-30, 200) dataSource:self style:YzcChartStyleLine]; 29 | chartView.tag = 100; 30 | chartView.intervalValue = 6; 31 | chartView.unitString = @"(步)"; 32 | chartView.isShowLastValue = YES; 33 | [chartView showInView:self.scrollView]; 34 | 35 | YzcChartView *chartView2 = [[YzcChartView alloc] initWithFrame:CGRectMake(10, 300, self.view.frame.size.width-30, 200) dataSource:self style:YzcChartStyleBar]; 36 | chartView2.intervalValue = 1; 37 | chartView2.tag = 200; 38 | chartView2.unitString = @"(步)"; 39 | chartView2.isShowLastValue = YES; 40 | [chartView2 showInView:self.scrollView]; 41 | 42 | 43 | YzcChartView *chartView3 = [[YzcChartView alloc] initWithFrame:CGRectMake(10, 500, self.view.frame.size.width-30, 200) dataSource:self style:YzcChartStyleBar]; 44 | chartView3.intervalValue = 6; 45 | chartView3.tag = 300; 46 | chartView3.isShowLastValue = YES; 47 | [chartView3 showInView:self.scrollView]; 48 | 49 | YzcChartView *chartView4 = [[YzcChartView alloc] initWithFrame:CGRectMake(10, 700, self.view.frame.size.width-30, 150) dataSource:self style:YzcChartStyleBar]; 50 | chartView4.tag = 400; 51 | chartView4.isShowLastValue = YES; 52 | [chartView4 showInView:self.scrollView]; 53 | 54 | 55 | self.scrollView.contentSize = CGSizeMake(0, CGRectGetMaxY(chartView4.frame)+40); 56 | } 57 | 58 | - (int)getRandomNumber:(int)from to:(int)to { 59 | return (int)(from + (arc4random() % (to - from + 1))); 60 | } 61 | 62 | #pragma mark - YzcChartDataSource 63 | - (NSMutableArray *)chartConfigAxisXValue:(YzcChartView *)chart { 64 | NSMutableArray *x = [NSMutableArray array]; 65 | 66 | switch (chart.tag) { 67 | case 100: 68 | for (int i = 0; i < 30; i++) { 69 | // if (i == 0) { 70 | // [x addObject:@"6月24日"]; 71 | // }else if ( i== 29){ 72 | // [x addObject:@"今日"]; 73 | // }else{ 74 | // 75 | [x addObject:[NSString stringWithFormat:@"%zd", i]]; 76 | // } 77 | } 78 | break; 79 | case 200: 80 | for (int i = 0; i <7; i++) { 81 | if (i%2 == 0) { 82 | [x addObject:[NSString stringWithFormat:@"%zd", i]]; 83 | }else{ 84 | 85 | [x addObject:[NSString stringWithFormat:@"%zd", i]]; 86 | } 87 | } 88 | break; 89 | 90 | case 300: 91 | for (int i = 0; i < 30; i++) { 92 | [x addObject:[NSString stringWithFormat:@"%zd", i]]; 93 | } 94 | break; 95 | 96 | case 400: 97 | for (int i = 0; i < 10; i++) { 98 | [x addObject:[NSString stringWithFormat:@"%zd", i]]; 99 | } 100 | break; 101 | 102 | default: 103 | break; 104 | } 105 | 106 | return x; 107 | } 108 | 109 | - (NSMutableArray *)chartConfigAxisYValue:(YzcChartView *)chart { 110 | NSMutableArray *y = [NSMutableArray array]; 111 | 112 | switch (chart.tag) { 113 | case 100: 114 | for (int i = 0; i < 30; i++) { 115 | [y addObject:[NSNumber numberWithInt:[self getRandomNumber:0 to:100]]]; 116 | } 117 | break; 118 | 119 | case 200: 120 | for (int i = 0; i < 7; i++) { 121 | [y addObject:[NSNumber numberWithInt:[self getRandomNumber:0 to:10000]]]; 122 | } 123 | break; 124 | 125 | case 300: 126 | for (int i = 0; i < 30; i++) { 127 | BarChartModel *model = [[BarChartModel alloc] init]; 128 | model.SleepTimeLong = 8; 129 | model.deepTimeLong = [self getRandomNumber:1 to:8]; 130 | [y addObject:model]; 131 | } 132 | break; 133 | 134 | case 400: 135 | for (int i = 0; i < 10; i++) { 136 | BarChartModel *model = [[BarChartModel alloc] init]; 137 | model.maxlValue = [self getRandomNumber:100 to:151]; 138 | model.minValue = [self getRandomNumber:0 to:70]; 139 | [y addObject:model]; 140 | } 141 | break; 142 | 143 | default: 144 | break; 145 | } 146 | 147 | return y; 148 | } 149 | 150 | - (CGRange)chartRange:(YzcChartView *)chart { 151 | CGRange rang = CGRangeMake(0, 0); 152 | 153 | switch (chart.tag) { 154 | case 100: 155 | rang = CGRangeMake(100, 0); 156 | break; 157 | case 200: 158 | rang = CGRangeMake(20000, 0); 159 | break; 160 | 161 | case 300: 162 | rang = CGRangeMake(12, 0); 163 | break; 164 | 165 | case 400: 166 | rang = CGRangeMake(150, 0); 167 | break; 168 | } 169 | return rang; 170 | } 171 | 172 | - (YzcConfigModel *)chartEffectConfig:(YzcChartView *)chart { 173 | YzcConfigModel *model = [[YzcConfigModel alloc] init]; 174 | 175 | if (chart.tag == 100) { 176 | UIColor *color = [UIColor colorWithRed:251/255.0 green:219/255.0 blue:92/255.0 alpha:1]; 177 | model.lineChartIsShadow = YES; 178 | model.lineChartIsDrawPoint = YES; 179 | model.lineChartValuePointColor = color; 180 | model.lineChartHorizontalLinecColor = color; 181 | model.lineChartLineColor = color; 182 | // model.lineChartIsShowMaxMinVlaue = YES; 183 | 184 | 185 | } else { 186 | model.barChartLessBarColor = [UIColor blueColor]; 187 | // model.barChartHorizontalLinecColor = [UIColor grayColor]; 188 | model.barChartAchieveTargetColor = [[UIColor blueColor] colorWithAlphaComponent: 0.5]; 189 | model.barChartEmptyDataBarColor = [[UIColor blueColor] colorWithAlphaComponent: 0.5]; 190 | model.barColor = [UIColor colorWithRed:251/255.0 green:219/255.0 blue:92/255.0 alpha:1]; 191 | 192 | } 193 | 194 | return model; 195 | } 196 | 197 | - (BarChartStyle)barChartStyle:(YzcChartView *)chart { 198 | if (chart.tag == 300) { 199 | return BarChartStyleSleep; 200 | } else if (chart.tag == 400) { 201 | return BarChartStyleRateRange; 202 | } 203 | return BarChartStyleNormal; 204 | } 205 | 206 | - (NSInteger)barChartTargetValue:(YzcChartView *)chart { 207 | if (chart.tag == 200) { 208 | return 8000; 209 | }else if (chart.tag == 300) { 210 | return 8; 211 | } 212 | return 0; 213 | } 214 | 215 | @end 216 | -------------------------------------------------------------------------------- /YzcChartExample/Classes/YzcChart/Model/BarChartModel.h: -------------------------------------------------------------------------------- 1 | // 2 | // SleepModel.h 3 | // YzcChart 4 | // 5 | // Created by zs-pace on 2017/3/17. 6 | // Copyright © 2017年 yzc. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | @interface BarChartModel : NSObject 13 | ///睡眠总时长 14 | @property (nonatomic, assign) CGFloat SleepTimeLong; 15 | ///深睡时长 16 | @property (nonatomic, assign) CGFloat deepTimeLong; 17 | 18 | //-------------心率范围------------------------------- 19 | ///平均心率最低值 20 | @property (nonatomic, assign) CGFloat minValue; 21 | ///心率最高值 22 | @property (nonatomic, assign) CGFloat maxlValue; 23 | 24 | @end 25 | -------------------------------------------------------------------------------- /YzcChartExample/Classes/YzcChart/Model/BarChartModel.m: -------------------------------------------------------------------------------- 1 | // 2 | // SleepModel.m 3 | // YzcChart 4 | // 5 | // Created by zs-pace on 2017/3/17. 6 | // Copyright © 2017年 yzc. All rights reserved. 7 | // 8 | 9 | #import "BarChartModel.h" 10 | 11 | @implementation BarChartModel 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /YzcChartExample/Classes/YzcChart/Model/YzcConfigModel.h: -------------------------------------------------------------------------------- 1 | // 2 | // YzcConfigModel.h 3 | // YzcChart 4 | // 5 | // Created by zs-pace on 2017/3/21. 6 | // Copyright © 2017年 yzc. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | @interface YzcConfigModel : NSObject 13 | 14 | ///折线是否显示数值点 15 | @property (nonatomic, assign) BOOL lineChartIsDrawPoint; 16 | ///涉嫌是否显示渐变色 17 | @property (nonatomic, assign) BOOL lineChartIsShadow; 18 | ///是否显示最大最小值,默认不显示 19 | @property (nonatomic, assign) BOOL lineChartIsShowMaxMinVlaue; 20 | ///折线的颜色 21 | @property (nonatomic, strong) UIColor *lineChartLineColor; 22 | ///折线 横线的颜色 23 | @property (nonatomic, strong) UIColor *lineChartHorizontalLinecColor; 24 | ///折线 数值点的颜色 25 | @property (nonatomic, strong) UIColor *lineChartValuePointColor; 26 | ///是否显示虚线 27 | @property (nonatomic, assign) BOOL isHiddenDashedline; 28 | ///是否要分段 29 | @property (nonatomic, assign) BOOL isSegment; 30 | 31 | 32 | ///柱状条的颜色 33 | @property (nonatomic, strong) UIColor *barColor; 34 | ///柱状超过目标值的颜色 35 | @property (nonatomic, strong) UIColor *barChartAchieveTargetColor; 36 | ///柱状条空数据时的颜色 37 | @property (nonatomic, strong) UIColor *barChartEmptyDataBarColor; 38 | ///深睡柱状条颜色 39 | @property (nonatomic, strong) UIColor *barChartLessBarColor; 40 | ///横线的颜色 41 | @property (nonatomic, strong) UIColor *barChartHorizontalLinecColor; 42 | 43 | 44 | @end 45 | -------------------------------------------------------------------------------- /YzcChartExample/Classes/YzcChart/Model/YzcConfigModel.m: -------------------------------------------------------------------------------- 1 | // 2 | // YzcConfigModel.m 3 | // YzcChart 4 | // 5 | // Created by zs-pace on 2017/3/21. 6 | // Copyright © 2017年 yzc. All rights reserved. 7 | // 8 | 9 | #import "YzcConfigModel.h" 10 | 11 | @implementation YzcConfigModel 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /YzcChartExample/Classes/YzcChart/UIView+Extension.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+Extension.h 3 | // YzcChart 4 | // 5 | // Created by zs-pace on 2017/3/17. 6 | // Copyright © 2017年 yzc. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface UIView (Extension) 12 | 13 | /** 14 | 绘制实线 15 | 16 | @param point 开始绘制点 17 | @param lineToPoint 结束绘制点 18 | @param lineColor 实线颜色 19 | */ 20 | - (void)drawSolideLineWithMoveToPoint:(CGPoint)point lineToPoint:(CGPoint)lineToPoint lineColor:(UIColor *)lineColor; 21 | 22 | /** 23 | 绘制虚线 24 | 25 | @param startPoint 绘制位置 26 | @param lineLength 虚线的宽度 27 | @param lineSpacing 虚线的间距 28 | @param lineColor 虚线的颜色 29 | */ 30 | - (void)drawDashLineWithStartPoint:(CGPoint)startPoint 31 | endPoint:(CGPoint)endPoint 32 | lineLength:(int)lineLength 33 | lineSpacing:(int)lineSpacing 34 | lineColor:(UIColor *)lineColor; 35 | 36 | - (void)drawTipsViewWithFrame:(CGRect)frame; 37 | 38 | - (void)setWidth:(CGFloat)width; 39 | 40 | @end 41 | -------------------------------------------------------------------------------- /YzcChartExample/Classes/YzcChart/UIView+Extension.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+Extension.m 3 | // YzcChart 4 | // 5 | // Created by zs-pace on 2017/3/17. 6 | // Copyright © 2017年 yzc. All rights reserved. 7 | // 8 | 9 | #import "UIView+Extension.h" 10 | 11 | @implementation UIView (Extension) 12 | 13 | /** 14 | 绘制虚线 15 | 16 | @param startPoint 绘制位置 17 | @param lineLength 虚线的宽度 18 | @param lineSpacing 虚线的间距 19 | @param lineColor 虚线的颜色 20 | */ 21 | - (void)drawDashLineWithStartPoint:(CGPoint)startPoint endPoint:(CGPoint)endPoint lineLength:(int)lineLength 22 | lineSpacing:(int)lineSpacing lineColor:(UIColor *)lineColor { 23 | 24 | CAShapeLayer *shapeLayer = [CAShapeLayer layer]; 25 | [shapeLayer setPosition:startPoint]; 26 | [shapeLayer setFillColor:[UIColor clearColor].CGColor]; 27 | [shapeLayer setStrokeColor:lineColor.CGColor]; 28 | [shapeLayer setLineWidth:0.5]; 29 | [shapeLayer setLineJoin:kCALineJoinRound]; 30 | [shapeLayer setLineDashPattern:[NSArray arrayWithObjects:[NSNumber numberWithInt:lineLength], [NSNumber numberWithInt:lineSpacing], nil]]; 31 | 32 | CGMutablePathRef path = CGPathCreateMutable(); 33 | CGPathMoveToPoint(path, NULL, 0, 0); 34 | CGPathAddLineToPoint(path, NULL, endPoint.x, 0); 35 | [shapeLayer setPath:path]; 36 | CGPathRelease(path); 37 | 38 | [self.layer insertSublayer:shapeLayer atIndex:0]; 39 | } 40 | 41 | /** 42 | 绘制实线 43 | 44 | @param point 开始绘制点 45 | @param lineToPoint 结束绘制点 46 | @param lineColor 实线颜色 47 | */ 48 | - (void)drawSolideLineWithMoveToPoint:(CGPoint)point lineToPoint:(CGPoint)lineToPoint lineColor:(UIColor *)lineColor { 49 | CAShapeLayer *shapeLayer = [CAShapeLayer layer]; 50 | UIBezierPath *path = [UIBezierPath bezierPath]; 51 | 52 | [path moveToPoint:point]; 53 | [path addLineToPoint:lineToPoint]; 54 | [path closePath]; 55 | shapeLayer.path = path.CGPath; 56 | shapeLayer.strokeColor = lineColor.CGColor; 57 | shapeLayer.fillColor = [[UIColor whiteColor] CGColor]; 58 | shapeLayer.lineWidth = 0.5; 59 | [self.layer insertSublayer:shapeLayer atIndex:0]; 60 | } 61 | 62 | - (void)drawTipsViewWithFrame:(CGRect)frame { 63 | NSInteger triangleH = 3; 64 | UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:frame cornerRadius:1]; 65 | 66 | [path moveToPoint:CGPointMake(frame.origin.x + frame.size.width * 0.5 - triangleH, frame.origin.y + frame.size.height)]; 67 | [path addLineToPoint:CGPointMake(frame.origin.x + frame.size.width * 0.5 + triangleH, frame.origin.y + frame.size.height)]; 68 | [path addLineToPoint:CGPointMake(frame.origin.x + frame.size.width * 0.5, frame.origin.y + frame.size.height + triangleH)]; 69 | 70 | CAShapeLayer *shapeLayer = [[CAShapeLayer alloc] init]; 71 | shapeLayer.fillColor = [[UIColor blackColor] colorWithAlphaComponent:0.7].CGColor; 72 | shapeLayer.path = path.CGPath; 73 | [self.layer insertSublayer:shapeLayer atIndex:(int)(self.subviews.count - 2)]; 74 | } 75 | 76 | - (void)setWidth:(CGFloat)width { 77 | CGRect frame = self.frame; 78 | frame.size.width = width; 79 | self.frame = frame; 80 | } 81 | @end 82 | -------------------------------------------------------------------------------- /YzcChartExample/Classes/YzcChart/YzcBar.h: -------------------------------------------------------------------------------- 1 | // 2 | // YzcBar.h 3 | // YzcChart 4 | // 5 | // Created by 叶志成 on 2016/11/26. 6 | // Copyright © 2016年 yzc. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface YzcBar : UIView 12 | 13 | @property (nonatomic,assign) CGFloat percent; 14 | 15 | @property (nonatomic, assign) CGFloat leesPercent; 16 | 17 | @property (nonatomic, assign) CGFloat startPercent; 18 | 19 | ///柱状条空数据时的颜色 20 | @property (nonatomic, strong) UIColor * emptyDataBarColor; 21 | ///柱状条颜色 22 | @property (nonatomic, strong) UIColor * barColor; 23 | ///矮柱状条颜色 24 | @property (nonatomic, strong) UIColor * lessBarColor; 25 | 26 | @property (nonatomic, assign) BOOL isSvgRate; 27 | 28 | @end 29 | -------------------------------------------------------------------------------- /YzcChartExample/Classes/YzcChart/YzcBar.m: -------------------------------------------------------------------------------- 1 | // 2 | // YzcBar.m 3 | // YzcChart 4 | // 5 | // Created by 叶志成 on 2016/11/26. 6 | // Copyright © 2016年 yzc. All rights reserved. 7 | // 8 | 9 | #import "YzcBar.h" 10 | #import "YzcCommonMacros.h" 11 | 12 | @interface YzcBar () 13 | 14 | @property (nonatomic, strong) CAShapeLayer *progressLayer; 15 | @property (nonatomic, strong) CAGradientLayer *gradientLayer; 16 | 17 | @end 18 | 19 | @implementation YzcBar 20 | 21 | - (id)initWithFrame:(CGRect)frame { 22 | self = [super initWithFrame:frame]; 23 | if (self) { 24 | self.clipsToBounds = YES; 25 | 26 | //填充色层 27 | self.progressLayer = [CAShapeLayer layer]; 28 | self.progressLayer.frame = self.bounds; 29 | self.progressLayer.fillColor = [[UIColor clearColor] CGColor]; 30 | self.progressLayer.lineCap = kCALineCapSquare; 31 | self.progressLayer.lineWidth = self.frame.size.width; 32 | 33 | [self.layer addSublayer:self.progressLayer]; 34 | } 35 | return self; 36 | } 37 | 38 | - (void)setPercent:(CGFloat)percent { 39 | if (percent > 0 && percent < 0.1) { 40 | percent = 0.1; 41 | } 42 | // if (percent == 0.1) { 43 | // if (IS_IPHONE5S) { 44 | // percent = 0.13; 45 | // }else if (IS_IPHONE4S) { 46 | // percent = 0.16; 47 | // } 48 | // } 49 | 50 | _percent = percent; 51 | self.progressLayer.strokeColor = self.barColor.CGColor; 52 | 53 | UIBezierPath *path = [UIBezierPath bezierPath]; 54 | if (self.isSvgRate) { 55 | if (self.startPercent == percent) { //两个值一样情况,为了效果只显示一条线 56 | [path moveToPoint:CGPointMake(self.frame.size.width/2.0, (1 - percent) * self.frame.size.height)]; 57 | [path addLineToPoint:CGPointMake(self.frame.size.width/2.0, (1 - percent) * self.frame.size.height + 0.5 )]; 58 | self.progressLayer.lineCap = kCALineCapButt; 59 | }else { 60 | [path moveToPoint:CGPointMake(self.frame.size.width/2.0, (1-self.startPercent) * self.frame.size.height-5)]; 61 | [path addLineToPoint:CGPointMake(self.frame.size.width/2.0, (1 - percent) * self.frame.size.height+5 )]; 62 | } 63 | }else{ 64 | [path moveToPoint:CGPointMake(self.frame.size.width/2.0, self.frame.size.height+30)]; 65 | [path addLineToPoint:CGPointMake(self.frame.size.width/2.0, (1 - percent) * self.frame.size.height+15)]; 66 | } 67 | 68 | [path setLineWidth:1]; 69 | [path setLineCapStyle:kCGLineCapSquare]; 70 | 71 | //增加动画 72 | CABasicAnimation *pathAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"]; 73 | pathAnimation.duration = 0.5; 74 | pathAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; 75 | pathAnimation.fromValue = [NSNumber numberWithFloat:0.0f]; 76 | pathAnimation.toValue = [NSNumber numberWithFloat:1.0f]; 77 | pathAnimation.autoreverses = NO; 78 | self.progressLayer.path = path.CGPath; 79 | 80 | [self.progressLayer addAnimation:pathAnimation forKey:@"strokeEndAnimation"]; 81 | 82 | } 83 | 84 | - (void)setLeesPercent:(CGFloat)leesPercent { 85 | //深睡 86 | UIBezierPath *deepSleepPath = [UIBezierPath bezierPath]; 87 | [deepSleepPath moveToPoint:CGPointMake(self.frame.size.width/2.0, self.frame.size.height+30)]; 88 | [deepSleepPath addLineToPoint:CGPointMake(self.frame.size.width/2.0, (1 - leesPercent) * self.frame.size.height+15)]; 89 | [deepSleepPath setLineWidth:1]; 90 | [deepSleepPath setLineCapStyle:kCGLineCapSquare]; 91 | 92 | CAShapeLayer *shapeLayer = [CAShapeLayer layer]; 93 | shapeLayer.frame = self.bounds; 94 | shapeLayer.fillColor = [UIColor clearColor].CGColor; 95 | shapeLayer.lineWidth = self.frame.size.width; 96 | shapeLayer.strokeColor = self.lessBarColor.CGColor; 97 | shapeLayer.path = deepSleepPath.CGPath; 98 | [self.layer addSublayer:shapeLayer]; 99 | 100 | } 101 | 102 | @end 103 | -------------------------------------------------------------------------------- /YzcChartExample/Classes/YzcChart/YzcBarChart.h: -------------------------------------------------------------------------------- 1 | // 2 | // YzcBarChart.h 3 | // YzcChart 4 | // 5 | // Created by 叶志成 on 2016/11/26. 6 | // Copyright © 2016年 yzc. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "YzcCommonMacros.h" 11 | 12 | typedef NS_ENUM (NSInteger, BarChartStyle) { 13 | BarChartStyleNormal = 0, 14 | BarChartStyleSleep, 15 | BarChartStyleRateRange 16 | }; 17 | 18 | @interface YzcBarChart : UIView 19 | 20 | @property (nonatomic, copy) NSMutableArray *xLabels; 21 | @property (nonatomic, copy) NSMutableArray *yLabels; 22 | 23 | @property (nonatomic, strong) UIColor *barColor;/**柱装条的颜色*/ 24 | @property (nonatomic, strong) UIColor *achieveTargetColor;/**柱装超过目标值的颜色*/ 25 | @property (nonatomic, strong) UIColor *emptyDataBarColor; ///柱状条空数据时的颜色 26 | @property (nonatomic, strong) UIColor *lessBarColor; ///矮柱状条颜色 27 | @property (nonatomic, strong) UIColor *HorizontalLinecColor; /**横线的颜色*/ 28 | 29 | @property (copy, nonatomic) NSString *unitString; 30 | @property (nonatomic, assign) NSInteger intervalValue; /** x值间隔数 */ 31 | @property (nonatomic, assign) NSInteger targetValue; /**设置目标值,并且绘制目标虚线*/ 32 | 33 | @property (nonatomic, assign) BOOL isHiddenUnit; /**是否显示左上角单位,默认隐藏*/ 34 | @property (nonatomic, assign) BOOL isShowLastValue; /**最后一个数值是否显示在柱状上面,默认隐藏*/ 35 | 36 | @property (nonatomic, assign) CGRange chooseRange; 37 | 38 | @property (nonatomic, assign) BarChartStyle style; 39 | 40 | @property (nonatomic, strong) UIFont *textFont; 41 | 42 | - (void)strokeChart; 43 | 44 | @end 45 | -------------------------------------------------------------------------------- /YzcChartExample/Classes/YzcChart/YzcBarChart.m: -------------------------------------------------------------------------------- 1 | // 2 | // YzcBarChart.m 3 | // YzcChart 4 | // 5 | // Created by 叶志成 on 2016/11/26. 6 | // Copyright © 2016年 yzc. All rights reserved. 7 | // 8 | 9 | #import "YzcBarChart.h" 10 | #import "YzcLabel.h" 11 | #import "YzcBar.h" 12 | #import "UIView+Extension.h" 13 | #import "BarChartModel.h" 14 | 15 | #define marginLeft 10 16 | #define barWidth 8 17 | 18 | @interface YzcBarChart () 19 | 20 | @property (nonatomic) CGFloat xLabelWidth; 21 | @property (nonatomic, strong) UIScrollView *myScrollView; 22 | @property (nonatomic, assign) CGPoint lastPoint;; 23 | @property (nonatomic, assign) CGPoint originPoint; 24 | @property (nonatomic, strong) UILabel *unitLabel; 25 | @property (nonatomic, assign) CGFloat yValueMax; 26 | @property (nonatomic, assign) CGFloat yValueMin; 27 | @property (nonatomic, assign) CGFloat targetPercent; 28 | 29 | @end 30 | 31 | @implementation YzcBarChart 32 | 33 | #pragma mark - lazy 34 | - (UILabel *)unitLabel { 35 | if (_unitLabel == nil) { 36 | UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(YZCLabelwidth, 0, 100, 40)]; 37 | label.text = self.unitString; 38 | label.textColor = [[UIColor grayColor] colorWithAlphaComponent:0.5]; 39 | [label sizeToFit]; 40 | label.textAlignment = NSTextAlignmentCenter; 41 | [label setFont:[UIFont systemFontOfSize:10]]; 42 | [self addSubview:label]; 43 | _unitLabel = label; 44 | } 45 | return _unitLabel; 46 | } 47 | 48 | #pragma mark - init 49 | 50 | - (instancetype)initWithFrame:(CGRect)frame { 51 | self = [super initWithFrame:frame]; 52 | if (self) { 53 | self.myScrollView = [[UIScrollView alloc]initWithFrame:CGRectMake(YZCLabelwidth, 0, frame.size.width-YZCLabelwidth-10, frame.size.height)]; 54 | self.myScrollView.bounces = NO; 55 | [self addSubview:self.myScrollView]; 56 | self.isHiddenUnit = YES; 57 | self.intervalValue = 1; 58 | } 59 | return self; 60 | } 61 | 62 | #pragma mark - setter 63 | - (void)setUnitString:(NSString *)unitString { 64 | _unitString = unitString; 65 | } 66 | 67 | - (void)setIsHiddenUnit:(BOOL)isHiddenUnit { 68 | _isHiddenUnit = isHiddenUnit; 69 | if (!self.isHiddenUnit) { 70 | [self unitLabel]; 71 | } 72 | } 73 | 74 | - (void)setIntervalValue:(NSInteger)intervalValue { 75 | _intervalValue = intervalValue; 76 | } 77 | 78 | - (void)setIsShowLastValue:(BOOL)isShowLastValue { 79 | _isShowLastValue = isShowLastValue; 80 | } 81 | 82 | - (void)setXLabels:(NSMutableArray *)xLabels { 83 | _xLabels = xLabels; 84 | 85 | for (int i = 0; i < xLabels.count; i++) { 86 | if (i%self.intervalValue == 0 || i == xLabels.count - 1) { 87 | NSString *labelText = xLabels[i]; 88 | UIFont *font = self.textFont != nil ? self.textFont : [UIFont systemFontOfSize:10]; 89 | NSDictionary *attrs = @{NSFontAttributeName : font}; 90 | CGSize size = [labelText sizeWithAttributes:attrs]; 91 | CGFloat labelW = size.width; 92 | CGFloat labelH = size.height; 93 | CGFloat labelX = marginLeft + i * self.xLabelWidth + YZCLabelwidth + barWidth * 0.5 - labelW * 0.5; 94 | 95 | YzcLabel *label = [[YzcLabel alloc] initWithFrame:CGRectMake(labelX, self.frame.size.height - YZCLabelHeight - 5, self.xLabelWidth+10, labelH)]; 96 | label.text = labelText; 97 | if (self.textFont) { 98 | label.font = self.textFont; 99 | } 100 | [label sizeToFit]; 101 | [self addSubview:label]; 102 | if (self.isShowLastValue && i == xLabels.count - 1) { 103 | label.textColor = [[UIColor blackColor] colorWithAlphaComponent:0.5]; 104 | } 105 | } 106 | } 107 | 108 | if (self.targetValue) { //如果设置了目标值就绘制目标虚线 109 | CGFloat chartCavanHeight = self.frame.size.height - YZCLabelHeight * 3 + 8; 110 | float percent = ((float)self.targetValue-_yValueMin) / ((float)_yValueMax-_yValueMin); 111 | self.targetPercent = percent >= 1 ? 1 : percent; 112 | [self.myScrollView drawDashLineWithStartPoint:CGPointMake(marginLeft, (1 - percent) * chartCavanHeight+30) 113 | endPoint:CGPointMake(self.xLabelWidth * (self.yLabels.count - 1) + marginLeft, (1 - percent) * chartCavanHeight+30) 114 | lineLength:2 115 | lineSpacing:1 116 | lineColor:[[UIColor blackColor] colorWithAlphaComponent:0.2]]; 117 | } 118 | } 119 | 120 | - (void)setYLabels:(NSMutableArray *)yLabels { 121 | _yLabels = yLabels; 122 | self.xLabelWidth = (self.myScrollView.frame.size.width - YZCLabelwidth * 0.5)/self.yLabels.count; 123 | if (self.style == BarChartStyleNormal) { 124 | _yValueMax = [[self.yLabels valueForKeyPath:@"@max.floatValue"] floatValue]; 125 | _yValueMin = 0;//[[self.yLabels valueForKeyPath:@"@min.floatValue"] floatValue]; 126 | if (_yValueMax == _yValueMin) { 127 | _yValueMin = 0; 128 | } 129 | } 130 | 131 | if (_chooseRange.max != _chooseRange.min) { 132 | _yValueMax = _chooseRange.max; 133 | _yValueMin = _chooseRange.min; 134 | } 135 | 136 | if (_yValueMax < self.targetValue) { 137 | _yValueMax = self.targetValue; 138 | } 139 | 140 | if (self.targetValue) { //目标值 141 | CGFloat chartCavanHeight = self.frame.size.height - YZCLabelHeight * 3 + 8; 142 | float percent = ((float)self.targetValue-_yValueMin) / ((float)_yValueMax-_yValueMin); 143 | CGFloat labelH = percent >= 1 ? 22 : (1 - percent) * chartCavanHeight+22; 144 | YzcLabel *label = [[YzcLabel alloc] initWithFrame:CGRectMake(0, labelH, YZCLabelwidth+20, YZCLabelHeight)]; 145 | NSString *targetString; 146 | if (self.targetValue >= 1000) { 147 | targetString = [NSString stringWithFormat:@"%.1fk", (float)self.targetValue/1000]; 148 | NSString *lastNum = [targetString componentsSeparatedByString:@"."][1]; 149 | if (![lastNum integerValue]) { //没有小数 150 | NSString *firstNum = [targetString componentsSeparatedByString:@"."][0]; 151 | targetString = [NSString stringWithFormat:@"%@k", firstNum]; 152 | } 153 | } else { 154 | targetString = [NSString stringWithFormat:@"%zd", self.targetValue]; 155 | } 156 | label.text = targetString; 157 | 158 | if (self.textFont) { 159 | label.font = self.textFont; 160 | } 161 | [label sizeToFit]; 162 | [self addSubview:label]; 163 | } 164 | 165 | UIColor *lineColor = self.HorizontalLinecColor ? self.HorizontalLinecColor : [[UIColor blackColor] colorWithAlphaComponent:0.1]; 166 | CGFloat endPointX = self.xLabelWidth * (self.yLabels.count - 1) + marginLeft; 167 | 168 | if (self.style == BarChartStyleRateRange) { 169 | float level = (_yValueMax-_yValueMin) / LINE_COUNT; 170 | CGFloat chartCavanHeight = self.frame.size.height - YZCLabelHeight * LINE_COUNT + 8; 171 | CGFloat levelHeight = chartCavanHeight / LINE_COUNT; 172 | 173 | for (int i = 1; i < LINE_COUNT+1; i++) { 174 | YzcLabel *label = [[YzcLabel alloc] initWithFrame:CGRectMake(0, chartCavanHeight - i * levelHeight + 13, YZCLabelwidth+20, YZCLabelHeight)]; 175 | label.text = [NSString stringWithFormat:@"%d", (int)(level * i+_yValueMin)]; 176 | if (self.textFont) { 177 | label.font = self.textFont; 178 | } 179 | [label sizeToFit]; 180 | [self addSubview:label]; 181 | } 182 | 183 | //画中间虚线横线 184 | for (int i = 0; i < LINE_COUNT+1; i++) { 185 | if (i < LINE_COUNT) { 186 | [self.myScrollView drawDashLineWithStartPoint:CGPointMake(marginLeft, YZCLabelHeight + i * levelHeight) 187 | endPoint:CGPointMake(endPointX, YZCLabelHeight + i * levelHeight) 188 | lineLength:2 189 | lineSpacing:1 190 | lineColor:lineColor]; 191 | } 192 | } 193 | } 194 | 195 | //最底下一条线 196 | [self.myScrollView drawSolideLineWithMoveToPoint:CGPointMake(marginLeft, self.myScrollView.frame.size.height-YZCLabelHeight-10) 197 | lineToPoint:CGPointMake(endPointX + barWidth, self.myScrollView.frame.size.height-YZCLabelHeight-10) 198 | lineColor:lineColor]; 199 | } 200 | 201 | #pragma mark - draw 202 | 203 | - (void)strokeChart { 204 | CGFloat chartCavanHeight = self.frame.size.height - YZCLabelHeight * LINE_COUNT + 8; 205 | 206 | for (int i = 0; i < self.yLabels.count; i++) { 207 | YzcBar *bar = [[YzcBar alloc] initWithFrame:CGRectMake(i * _xLabelWidth + marginLeft, YZCLabelHeight + 2, barWidth, chartCavanHeight)]; 208 | bar.emptyDataBarColor = self.emptyDataBarColor ? self.emptyDataBarColor : [[UIColor grayColor] colorWithAlphaComponent:0.5]; 209 | 210 | if (self.style == BarChartStyleNormal) { 211 | NSString *valueString = self.yLabels[i]; 212 | float value = [valueString floatValue]; 213 | float percent = ((float)value-_yValueMin) / ((float)_yValueMax-_yValueMin); 214 | if (percent < 0 || isnan(percent)) { 215 | percent = 0; 216 | } 217 | if (percent >= self.targetPercent && self.targetValue) { 218 | bar.barColor = self.achieveTargetColor ? self.achieveTargetColor : [UIColor redColor]; 219 | } else { 220 | bar.barColor = self.barColor ? self.barColor : [UIColor greenColor]; 221 | } 222 | bar.percent = percent; 223 | 224 | //最后一个点显示数值在上面 225 | if ((i == self.self.yLabels.count - 1) && self.isShowLastValue && percent) { 226 | [self setupLastValueLabelWithView:bar value:[NSString stringWithFormat:@"%@", valueString] percent:percent chartCavanHeight:chartCavanHeight]; 227 | } 228 | } else { 229 | BarChartModel *barModel = self.yLabels[i]; 230 | 231 | float totalValue = 0.0; 232 | float totalPercent = 0.0; 233 | 234 | if (self.style == BarChartStyleSleep) { 235 | totalValue = barModel.SleepTimeLong; 236 | float deepValue = barModel.deepTimeLong; 237 | float deepPercent = ((float)deepValue-_yValueMin) / ((float)_yValueMax-_yValueMin); 238 | totalPercent = ((float)totalValue-_yValueMin) / ((float)_yValueMax-_yValueMin); 239 | 240 | if (isnan(totalPercent) || totalPercent < 0) { 241 | totalPercent = 0; 242 | } 243 | if (totalPercent >= self.targetPercent && self.targetValue) { 244 | bar.barColor = self.achieveTargetColor ? self.achieveTargetColor : [UIColor clearColor]; 245 | } else { 246 | bar.barColor = self.barColor ? self.barColor : [UIColor greenColor]; 247 | } 248 | 249 | bar.lessBarColor = self.lessBarColor ? self.lessBarColor : [UIColor blueColor]; 250 | bar.percent = totalPercent; 251 | bar.leesPercent = deepPercent; 252 | 253 | //最后一个点显示数值在上面 254 | if ((i == self.self.yLabels.count - 1) && self.isShowLastValue && (NSInteger)totalValue) { 255 | [self setupLastValueLabelWithView:bar value:[NSString stringWithFormat:@"%.0f", totalValue] percent:totalPercent chartCavanHeight:bar.frame.size.height + 10]; 256 | } 257 | } else if (self.style == BarChartStyleRateRange) { 258 | totalValue = barModel.maxlValue; 259 | totalPercent = ((float)totalValue-_yValueMin) / ((float)_yValueMax-_yValueMin); 260 | float startValue = barModel.minValue; 261 | float startPercent = ((float)startValue-_yValueMin) / ((float)_yValueMax-_yValueMin); 262 | 263 | bar.barColor = self.barColor ? self.barColor : [UIColor greenColor]; 264 | bar.isSvgRate = YES; 265 | bar.startPercent = startPercent; 266 | bar.percent = totalPercent; 267 | } 268 | } 269 | 270 | [self.myScrollView addSubview:bar]; 271 | } 272 | } 273 | 274 | - (void)setupLastValueLabelWithView:(YzcBar *)barView value:(NSString *)value percent:(CGFloat)percent chartCavanHeight:(CGFloat)chartCavanHeight { 275 | NSString *valueString = [NSString stringWithFormat:@"%@%@", value, self.unitString.length ? self.unitString : @""]; 276 | UIFont *font = self.textFont != nil ? self.textFont : [UIFont systemFontOfSize:10]; 277 | NSDictionary *attrs = @{NSFontAttributeName : font}; 278 | CGSize size = [valueString sizeWithAttributes:attrs]; 279 | CGFloat labelW = size.width; 280 | CGFloat labelH = size.height; 281 | CGFloat labelX = marginLeft + (self.yLabels.count - 1) * self.xLabelWidth + YZCLabelwidth + barWidth * 0.5 - labelW * 0.5; 282 | 283 | if (percent > 0 && percent < 0.1) { 284 | percent = 0.1; 285 | } 286 | CGFloat labelY = (1 - percent) * barView.frame.size.height + 15; 287 | 288 | UILabel *valueLabel = [[UILabel alloc] initWithFrame:CGRectMake(labelX, labelY, labelW, labelH)]; 289 | valueLabel.text = valueString; 290 | valueLabel.textColor = [UIColor whiteColor]; 291 | valueLabel.font = font; 292 | valueLabel.textAlignment = NSTextAlignmentCenter; 293 | 294 | [self addSubview:valueLabel]; 295 | [self drawTipsViewWithFrame:CGRectMake(labelX - marginLeft * 0.5, labelY, valueLabel.frame.size.width + marginLeft, valueLabel.frame.size.height)]; 296 | } 297 | 298 | @end 299 | -------------------------------------------------------------------------------- /YzcChartExample/Classes/YzcChart/YzcChartView.h: -------------------------------------------------------------------------------- 1 | // 2 | // YzcChartView.h 3 | // YzcChart 4 | // 5 | // Created by zs-pace on 2017/3/16. 6 | // Copyright © 2017年 yzc. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "YzcBarChart.h" 11 | #import "YzcLineChart.h" 12 | #import "BarChartModel.h" 13 | #import "YzcConfigModel.h" 14 | 15 | typedef NS_ENUM (NSInteger, YzcChartStyle){ 16 | YzcChartStyleLine = 0, 17 | YzcChartStyleBar 18 | }; 19 | 20 | @class YzcChartView; 21 | 22 | @protocol YzcChartDataSource 23 | 24 | @required 25 | ///横坐标标题数组 26 | - (NSMutableArray *)chartConfigAxisXValue:(YzcChartView *)chart; 27 | 28 | ///数值数组 29 | - (NSMutableArray *)chartConfigAxisYValue:(YzcChartView *)chart; 30 | 31 | @optional 32 | ///显示数值范围 33 | - (CGRange)chartRange:(YzcChartView *)chart; 34 | 35 | 36 | /** 37 | 图表效果配置 38 | 39 | @param chart chart 40 | @return 配置model 41 | */ 42 | - (YzcConfigModel *)chartEffectConfig:(YzcChartView *)chart; 43 | 44 | #pragma mark - 柱状图功能 45 | 46 | - (NSInteger)barChartTargetValue:(YzcChartView *)chart; 47 | 48 | /** 49 | 柱状图样式 50 | 51 | @param chart chart 52 | @return bool 53 | */ 54 | - (BarChartStyle)barChartStyle:(YzcChartView *)chart; 55 | 56 | @end 57 | 58 | 59 | @interface YzcChartView : UIView 60 | 61 | @property (nonatomic, assign) YzcChartStyle chartStyle; 62 | ///左上角显示单位(未国际化) 63 | @property (copy, nonatomic) NSString *unitString; 64 | ///是否显示左上角单位,默认隐藏 65 | @property (nonatomic, assign) BOOL isHiddenUnit; 66 | ///最后一个数值是否显示在柱状上面,默认隐藏 67 | @property (nonatomic, assign) BOOL isShowLastValue; 68 | ///横坐标显示间隔数 69 | @property (nonatomic, assign) NSInteger intervalValue; 70 | 71 | @property (nonatomic, strong) UIFont *textFont; 72 | 73 | - (id)initWithFrame:(CGRect)rect dataSource:(id)dataSource style:(YzcChartStyle)style; 74 | 75 | - (void)showInView:(UIView *)view; 76 | 77 | @end 78 | -------------------------------------------------------------------------------- /YzcChartExample/Classes/YzcChart/YzcChartView.m: -------------------------------------------------------------------------------- 1 | // 2 | // YzcChartView.m 3 | // YzcChart 4 | // 5 | // Created by zs-pace on 2017/3/16. 6 | // Copyright © 2017年 yzc. All rights reserved. 7 | // 8 | 9 | #import "YzcChartView.h" 10 | 11 | @interface YzcChartView () 12 | 13 | @property (weak, nonatomic) id dataSource; 14 | @property (strong, nonatomic) YzcLineChart *lineChart; 15 | @property (strong, nonatomic) YzcBarChart *barChart; 16 | 17 | @end 18 | 19 | @implementation YzcChartView 20 | 21 | 22 | - (id)initWithFrame:(CGRect)rect dataSource:(id)dataSource style:(YzcChartStyle)style { 23 | self.dataSource = dataSource; 24 | self.chartStyle = style; 25 | return [self initWithFrame:rect]; 26 | } 27 | 28 | - (id)initWithFrame:(CGRect)frame { 29 | self = [super initWithFrame:frame]; 30 | if (self) { 31 | self.clipsToBounds = NO; 32 | } 33 | return self; 34 | } 35 | 36 | - (void)setUpChart { 37 | if (self.chartStyle == YzcChartStyleLine) { 38 | if (!self.lineChart) { 39 | self.lineChart = [[YzcLineChart alloc] initWithFrame:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)]; 40 | [self addSubview:self.lineChart]; 41 | } 42 | 43 | //选择显示范围 44 | if ([self.dataSource respondsToSelector:@selector(chartRange:)]) { 45 | [self.lineChart setChooseRange:[self.dataSource chartRange:self]]; 46 | } 47 | 48 | BOOL isSegment = NO; 49 | if ([self.dataSource respondsToSelector:@selector(chartEffectConfig:)]) { 50 | YzcConfigModel *model = [self.dataSource chartEffectConfig:self]; 51 | self.lineChart.lineColor = model.lineChartLineColor; 52 | self.lineChart.HorizontalLinecColor = model.lineChartHorizontalLinecColor; 53 | self.lineChart.pointColor = model.lineChartValuePointColor; 54 | self.lineChart.isDrawPoint = model.lineChartIsDrawPoint; 55 | self.lineChart.isShadow = model.lineChartIsShadow; 56 | self.lineChart.isShowMaxMinValue = model.lineChartIsShowMaxMinVlaue; 57 | self.lineChart.isHiddenDashedLine = model.isHiddenDashedline; 58 | if (model.isSegment) { 59 | isSegment = model.isSegment; 60 | } 61 | } 62 | 63 | self.lineChart.textFont = self.textFont; 64 | self.lineChart.isHiddenLastValue = self.isShowLastValue; 65 | self.lineChart.isHiddenUnit = self.isHiddenUnit ? self.isHiddenUnit : YES; 66 | self.lineChart.unitString = self.unitString; 67 | self.lineChart.intervalValue = self.intervalValue ? self.intervalValue : 1; 68 | [self.lineChart setYLabels:[self.dataSource chartConfigAxisYValue:self]]; 69 | [self.lineChart setXLabels:[self.dataSource chartConfigAxisXValue:self]]; 70 | 71 | if (isSegment) { 72 | [self.lineChart segmentedStrokeChart]; 73 | }else{ 74 | [self.lineChart strokeChart]; 75 | } 76 | } else if (self.chartStyle == YzcChartStyleBar) { 77 | if (!self.barChart) { 78 | self.barChart = [[YzcBarChart alloc] initWithFrame:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)]; 79 | [self addSubview:self.barChart]; 80 | } 81 | if ([self.dataSource respondsToSelector:@selector(chartRange:)]) { 82 | [self.barChart setChooseRange:[self.dataSource chartRange:self]]; 83 | } 84 | 85 | if ([self.dataSource respondsToSelector:@selector(chartEffectConfig:)]) { 86 | YzcConfigModel *model = [self.dataSource chartEffectConfig:self]; 87 | self.barChart.barColor = model.barColor; 88 | self.barChart.achieveTargetColor = model.barChartAchieveTargetColor; 89 | self.barChart.emptyDataBarColor = model.barChartEmptyDataBarColor; 90 | self.barChart.lessBarColor = model.barChartLessBarColor; 91 | self.barChart.HorizontalLinecColor = model.barChartHorizontalLinecColor; 92 | } 93 | 94 | if ([self.dataSource respondsToSelector:@selector(barChartTargetValue:)]) { 95 | self.barChart.targetValue = [self.dataSource barChartTargetValue:self]; 96 | } 97 | if ([self.dataSource respondsToSelector:@selector(barChartStyle:)]) { 98 | self.barChart.style = [self.dataSource barChartStyle:self]; 99 | } 100 | 101 | self.barChart.textFont = self.textFont; 102 | self.barChart.isShowLastValue = self.isShowLastValue; 103 | self.barChart.isHiddenUnit = self.isHiddenUnit ? self.isHiddenUnit : YES; 104 | self.barChart.unitString = self.unitString; 105 | self.barChart.intervalValue = self.intervalValue? self.intervalValue : 1; 106 | [self.barChart setYLabels:[self.dataSource chartConfigAxisYValue:self]]; 107 | [self.barChart setXLabels:[self.dataSource chartConfigAxisXValue:self]]; 108 | 109 | [self.barChart strokeChart]; 110 | } 111 | } 112 | 113 | - (void)showInView:(UIView *)view { 114 | [self setUpChart]; 115 | [view addSubview:self]; 116 | } 117 | 118 | - (void)strokeChart { 119 | [self setUpChart]; 120 | } 121 | 122 | @end 123 | -------------------------------------------------------------------------------- /YzcChartExample/Classes/YzcChart/YzcCommonMacros.h: -------------------------------------------------------------------------------- 1 | // 2 | // YzcCommonMacros.h 3 | // YzcChart 4 | // 5 | // Created by 叶志成 on 2016/11/26. 6 | // Copyright © 2017年 yzc. All rights reserved. 7 | // 8 | 9 | #ifndef YzcCommonMacros_h 10 | #define YzcCommonMacros_h 11 | 12 | #define chartMargin 10 13 | #define xLabelMargin 15 14 | #define yLabelMargin 15 15 | #define YZCLabelHeight 20 16 | #define YZCLabelwidth 20 17 | #define YZCTagLabelwidth 80 18 | #define LINE_COUNT 3 19 | 20 | #define IS_IPHONE4S ([UIScreen mainScreen].bounds.size.height <= 480) 21 | #define IS_IPHONE5S ([UIScreen mainScreen].bounds.size.height == 568) 22 | 23 | //范围 24 | struct Range { 25 | CGFloat max; 26 | CGFloat min; 27 | }; 28 | typedef struct Range CGRange; 29 | CG_INLINE CGRange CGRangeMake(CGFloat max, CGFloat min); 30 | 31 | CG_INLINE CGRange 32 | CGRangeMake(CGFloat max, CGFloat min){ 33 | CGRange p; 34 | 35 | p.max = max; 36 | p.min = min; 37 | return p; 38 | } 39 | 40 | static const CGRange CGRangeZero = {0, 0}; 41 | 42 | #endif /* YzcCommonMacros_h */ 43 | -------------------------------------------------------------------------------- /YzcChartExample/Classes/YzcChart/YzcLabel.h: -------------------------------------------------------------------------------- 1 | // 2 | // YzcLabel.h 3 | // YzcChart 4 | // 5 | // Created by mac on 16/11/11. 6 | // Copyright © 2016年 yzc. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface YzcLabel : UILabel 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /YzcChartExample/Classes/YzcChart/YzcLabel.m: -------------------------------------------------------------------------------- 1 | // 2 | // YzcLabel.m 3 | // YzcChart 4 | // 5 | // Created by mac on 16/11/11. 6 | // Copyright © 2016年 yzc. All rights reserved. 7 | // 8 | 9 | #import "YzcLabel.h" 10 | 11 | @implementation YzcLabel 12 | 13 | - (id)initWithFrame:(CGRect)frame 14 | { 15 | self = [super initWithFrame:frame]; 16 | if (self) { 17 | 18 | [self setMinimumScaleFactor:5.0f]; 19 | [self setNumberOfLines:1]; 20 | [self setFont:[UIFont systemFontOfSize:10.0f]]; 21 | [self setTextColor: [[UIColor blackColor] colorWithAlphaComponent:0.2]]; 22 | [self setTextAlignment:NSTextAlignmentCenter]; 23 | self.userInteractionEnabled = YES; 24 | } 25 | return self; 26 | } 27 | 28 | 29 | 30 | @end 31 | -------------------------------------------------------------------------------- /YzcChartExample/Classes/YzcChart/YzcLineChart.h: -------------------------------------------------------------------------------- 1 | // 2 | // YzcChartView.h 3 | // YzcChart 4 | // 5 | // Created by mac on 16/11/10. 6 | // Copyright © 2016年 yzc. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "YzcCommonMacros.h" 11 | 12 | @interface YzcLineChart : UIView 13 | 14 | @property (copy, nonatomic) NSMutableArray *xLabels; 15 | @property (copy, nonatomic) NSMutableArray *yLabels; 16 | 17 | @property (nonatomic, assign) BOOL isDrawPoint; //是否数值点 18 | @property (nonatomic, assign) BOOL isShadow; //是否显示渐变 19 | @property (nonatomic, assign) BOOL isHiddenLastValue; //最后一个数值是否显示在柱状上面,默认隐藏 20 | @property (nonatomic, assign) BOOL isHiddenUnit; //是否显示左上角单位,默认隐藏 21 | @property (nonatomic, assign) BOOL isShowMaxMinValue; //是否显示最大最小值,默认不显示 22 | @property (nonatomic, assign) BOOL isHiddenDashedLine; 23 | 24 | @property (nonatomic, assign) NSInteger intervalValue;// x值显示间隔数 25 | @property (nonatomic, copy) NSString *unitString; 26 | 27 | @property (nonatomic, strong) UIColor *lineColor; //折线的颜色 28 | @property (nonatomic, strong) UIColor *HorizontalLinecColor; //横线的颜色 29 | @property (nonatomic, strong) UIColor *pointColor; //点的颜色 30 | 31 | @property (nonatomic, assign) CGRange chooseRange; 32 | 33 | @property (nonatomic, strong) UIFont *textFont; 34 | 35 | - (void)strokeChart; 36 | - (void)segmentedStrokeChart; 37 | 38 | @end 39 | -------------------------------------------------------------------------------- /YzcChartExample/Classes/YzcChart/YzcLineChart.m: -------------------------------------------------------------------------------- 1 | // 2 | // YzcChartView.m 3 | // YzcChart 4 | // 5 | // Created by mac on 16/11/10. 6 | // Copyright © 2016年 yzc. All rights reserved. 7 | // 8 | 9 | #import "YzcLineChart.h" 10 | #import "YzcLabel.h" 11 | #import "UIView+Extension.h" 12 | 13 | #define marginLeft 10 14 | 15 | @interface YzcLineChart () 16 | 17 | @property (nonatomic) CGFloat xLabelWidth; 18 | @property (nonatomic, strong) UIScrollView *myScrollView; 19 | @property (nonatomic, strong) UILabel *unitLabel; 20 | @property (nonatomic, assign) CGPoint lastPoint;; 21 | @property (nonatomic, assign) CGPoint originPoint; 22 | @property (nonatomic, assign) CGFloat yValueMin; 23 | @property (nonatomic, assign) CGFloat yValueMax; 24 | @property (nonatomic, assign) BOOL isLastIndex; 25 | @property (nonatomic, strong) CAShapeLayer *chartLine; 26 | @property (nonatomic, strong) UIBezierPath *progressline; 27 | 28 | @end 29 | 30 | @implementation YzcLineChart 31 | 32 | #pragma mark - init 33 | - (instancetype)initWithFrame:(CGRect)frame { 34 | self = [super initWithFrame:frame]; 35 | if (self) { 36 | self.myScrollView = [[UIScrollView alloc]initWithFrame:CGRectMake(YZCLabelwidth, 0, frame.size.width-YZCLabelwidth, frame.size.height)]; 37 | self.myScrollView.bounces = NO; 38 | [self addSubview:self.myScrollView]; 39 | self.isDrawPoint = YES; 40 | self.isShadow = YES; 41 | self.isHiddenUnit = YES; 42 | self.isShowMaxMinValue = NO; 43 | self.intervalValue = 1; 44 | } 45 | return self; 46 | } 47 | 48 | #pragma mark - Draw points 49 | - (void)strokeChart { 50 | float maxValue = [[self.yLabels valueForKeyPath:@"@max.floatValue"] floatValue]; 51 | 52 | if (!maxValue || !_yValueMax) { 53 | return; 54 | } 55 | 56 | BOOL isShowMaxAndMinPoint = YES; 57 | CGFloat firstValue = [[self.yLabels objectAtIndex:0] floatValue]; 58 | CGFloat xPosition = 10; 59 | CGFloat chartCavanHeight = self.myScrollView.frame.size.height - YZCLabelHeight*(LINE_COUNT-1); 60 | [self.myScrollView.layer addSublayer:self.chartLine]; 61 | 62 | float grade = ((float)firstValue-_yValueMin) / ((float)_yValueMax-_yValueMin); 63 | if (isnan(grade)) { 64 | grade = 0; 65 | } 66 | CGPoint firstPoint = CGPointMake(xPosition, chartCavanHeight - grade * chartCavanHeight+YZCLabelHeight); 67 | 68 | //线路径 69 | UIBezierPath *progressline = [UIBezierPath bezierPath]; 70 | [progressline moveToPoint:firstPoint]; //设置起点 71 | [progressline setLineWidth:2.0]; 72 | [progressline setLineCapStyle:kCGLineCapRound]; 73 | [progressline setLineJoinStyle:kCGLineJoinRound]; 74 | 75 | //遮罩层形状 76 | UIBezierPath *bezier1 = [UIBezierPath bezierPath]; 77 | bezier1.lineCapStyle = kCGLineCapRound; 78 | bezier1.lineJoinStyle = kCGLineJoinMiter; 79 | [bezier1 moveToPoint:firstPoint]; 80 | self.originPoint = firstPoint; //记录原点 81 | 82 | NSInteger index = 0; 83 | for (NSString *valueString in self.yLabels) { 84 | float grade = ([valueString floatValue] - _yValueMin) / ((float)_yValueMax-_yValueMin); 85 | if (isnan(grade)) { 86 | grade = 0; 87 | } 88 | 89 | CGPoint point = CGPointMake(xPosition+index*self.xLabelWidth, chartCavanHeight - grade * chartCavanHeight+YZCLabelHeight); 90 | if (index != 0) { 91 | [progressline addLineToPoint:point]; 92 | [bezier1 addLineToPoint:point]; 93 | } 94 | if (index == _yLabels.count-1) { 95 | self.lastPoint = point; //记录最后一个点 96 | self.isLastIndex = YES; 97 | } 98 | if (self.isDrawPoint) { //画点 99 | [self addPoint:point 100 | index:index 101 | isShow:isShowMaxAndMinPoint 102 | value:valueString]; 103 | } 104 | 105 | //显示最大值或最小值 106 | if (self.isShowMaxMinValue && ([valueString floatValue] == [[self.yLabels valueForKeyPath:@"@max.floatValue"] floatValue] || [valueString floatValue] == [[self.yLabels valueForKeyPath:@"@min.floatValue"] floatValue])) { 107 | [self setupLastValueLabelWithView:point 108 | value:[valueString integerValue] 109 | grade:grade 110 | chartCavanHeight:chartCavanHeight]; 111 | 112 | if (!self.isDrawPoint) { //如果没有画点才画最大最小的点,不然就不重复画点 113 | [self addPoint:point 114 | index:index 115 | isShow:isShowMaxAndMinPoint 116 | value:valueString]; 117 | } 118 | } 119 | index += 1; 120 | } 121 | 122 | self.chartLine.path = progressline.CGPath; 123 | self.chartLine.strokeColor = self.lineColor ? self.lineColor.CGColor : [UIColor greenColor].CGColor; 124 | self.chartLine.strokeEnd = 1.0; 125 | [self addAnimationWithLine:self.chartLine duration:self.yLabels.count * 0.03]; 126 | 127 | if (self.isShadow) { 128 | [bezier1 addLineToPoint:CGPointMake(self.lastPoint.x, self.myScrollView.frame.size.height - YZCLabelHeight)]; 129 | [bezier1 addLineToPoint:CGPointMake(self.originPoint.x, self.myScrollView.frame.size.height - YZCLabelHeight)]; 130 | [bezier1 addLineToPoint:self.originPoint]; 131 | [self addGradientLayer:bezier1]; 132 | } 133 | } 134 | 135 | - (void)segmentedStrokeChart { 136 | float maxValue = [[self.yLabels valueForKeyPath:@"@max.floatValue"] floatValue]; 137 | 138 | if (!maxValue || !_yValueMax) { 139 | return; 140 | } 141 | 142 | BOOL isShowMaxAndMinPoint = YES; 143 | CGFloat xPosition = 10; 144 | CGFloat chartCavanHeight = self.myScrollView.frame.size.height - YZCLabelHeight*(LINE_COUNT-1); 145 | 146 | NSInteger kAnimationTimeCount = 0; 147 | for (int i = 0; i < self.yLabels.count; i++) { 148 | NSString *valueString = self.yLabels[i]; 149 | float grade = ([valueString floatValue] - _yValueMin) / ((float)_yValueMax-_yValueMin); 150 | if (isnan(grade)) { 151 | grade = 0; 152 | } 153 | 154 | if ([valueString floatValue]) { 155 | kAnimationTimeCount += 1; 156 | CGPoint point = CGPointMake(xPosition+i*self.xLabelWidth, chartCavanHeight - grade * chartCavanHeight+YZCLabelHeight); 157 | [self.myScrollView.layer addSublayer:self.chartLine]; 158 | if (!self.progressline) { 159 | self.progressline = [UIBezierPath bezierPath]; 160 | [self.progressline setLineWidth:2.0]; 161 | [self.progressline setLineCapStyle:kCGLineCapRound]; 162 | [self.progressline setLineJoinStyle:kCGLineJoinRound]; 163 | [self.progressline moveToPoint:point]; 164 | } else { 165 | [self.progressline addLineToPoint:point]; 166 | } 167 | 168 | if (i == _yLabels.count-1) { 169 | self.lastPoint = point; //记录最后一个点 170 | self.isLastIndex = YES; 171 | } 172 | if (self.isDrawPoint) { //画点 173 | [self addPoint:point 174 | index:i 175 | isShow:isShowMaxAndMinPoint 176 | value:valueString]; 177 | } 178 | 179 | //显示最大值或最小值 180 | if (self.isShowMaxMinValue && ([valueString floatValue] == [[self.yLabels valueForKeyPath:@"@max.floatValue"] floatValue] || [valueString floatValue] == [[self.yLabels valueForKeyPath:@"@min.floatValue"] floatValue])) { 181 | [self setupLastValueLabelWithView:point 182 | value:[valueString integerValue] 183 | grade:grade 184 | chartCavanHeight:chartCavanHeight]; 185 | 186 | if (!self.isDrawPoint) { //如果没有画点才画最大最小的点,不然就不重复画点 187 | [self addPoint:point 188 | index:i 189 | isShow:isShowMaxAndMinPoint 190 | value:valueString]; 191 | } 192 | } 193 | 194 | self.chartLine.path = self.progressline.CGPath; 195 | self.chartLine.strokeColor = self.lineColor ? self.lineColor.CGColor : [UIColor greenColor].CGColor; 196 | self.chartLine.strokeEnd = 1.0; 197 | [self addAnimationWithLine:self.chartLine duration:kAnimationTimeCount * 0.1]; 198 | } else { 199 | self.progressline = nil; 200 | self.chartLine = nil; 201 | kAnimationTimeCount = 0; 202 | } 203 | } 204 | } 205 | 206 | - (void)addAnimationWithLine:(CAShapeLayer *)chartLine duration:(CGFloat)duration { 207 | CABasicAnimation *pathAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"]; 208 | 209 | pathAnimation.duration = duration; 210 | pathAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; 211 | pathAnimation.fromValue = [NSNumber numberWithFloat:0.0f]; 212 | pathAnimation.toValue = [NSNumber numberWithFloat:1.0f]; 213 | pathAnimation.autoreverses = NO; 214 | [chartLine addAnimation:pathAnimation forKey:@"strokeEndAnimation"]; 215 | } 216 | 217 | - (void)addPoint:(CGPoint)point index:(NSInteger)index isShow:(BOOL)isHollow value:(NSString *)value { 218 | CGFloat viewWH = 5; 219 | UIView *view = [[UIView alloc]initWithFrame:CGRectMake(5, 5, viewWH, viewWH)]; 220 | 221 | view.center = point; 222 | view.layer.masksToBounds = YES; 223 | view.layer.cornerRadius = viewWH*0.5; 224 | view.layer.borderWidth = 2; 225 | if (value) { 226 | view.layer.borderColor = self.pointColor ? self.pointColor.CGColor : [UIColor greenColor].CGColor; 227 | } else { 228 | view.layer.borderColor = [UIColor clearColor].CGColor; 229 | } 230 | view.backgroundColor = self.pointColor; 231 | [self.myScrollView addSubview:view]; 232 | 233 | 234 | NSString *valueString = [NSString stringWithFormat:@"%@%@", value, self.unitString.length ? self.unitString : @""]; 235 | //最后一个点显示数值在上面 236 | if (self.isLastIndex && self.isHiddenLastValue && valueString.length) { 237 | UIFont *font = self.textFont != nil ? self.textFont : [UIFont systemFontOfSize:10]; 238 | 239 | NSDictionary *attrs = @{NSFontAttributeName : font}; 240 | CGSize size = [valueString sizeWithAttributes:attrs]; 241 | CGFloat labelW = size.width; 242 | CGFloat labelH = size.height; 243 | CGFloat labelX = point.x + marginLeft * 0.5; 244 | if ([value integerValue] < 10) { 245 | labelX += viewWH * 0.5; 246 | } 247 | CGFloat labelY = point.y - 20; 248 | 249 | UILabel *valueLabel = [[UILabel alloc] initWithFrame:CGRectMake(labelX, labelY, labelW, labelH)]; 250 | valueLabel.text = valueString; 251 | valueLabel.textColor = [UIColor whiteColor]; 252 | valueLabel.font = font; 253 | valueLabel.textAlignment = NSTextAlignmentCenter; 254 | [self addSubview:valueLabel]; 255 | [self drawTipsViewWithFrame:CGRectMake(labelX - marginLeft * 0.5, labelY, valueLabel.frame.size.width + marginLeft, valueLabel.frame.size.height)]; 256 | } 257 | } 258 | 259 | /** 260 | 添加渐变图层 261 | */ 262 | - (void)addGradientLayer:(UIBezierPath *)bezier1 { 263 | CAShapeLayer *shadeLayer = [CAShapeLayer layer]; 264 | 265 | shadeLayer.path = bezier1.CGPath; 266 | shadeLayer.fillColor = [UIColor greenColor].CGColor; 267 | 268 | UIColor *color = self.lineColor ? self.lineColor : [UIColor greenColor]; 269 | CAGradientLayer *gradientLayer = [CAGradientLayer layer]; 270 | gradientLayer.frame = CGRectMake(5, 0, 0, self.myScrollView.bounds.size.height-20); 271 | gradientLayer.cornerRadius = 5; 272 | gradientLayer.masksToBounds = YES; 273 | gradientLayer.colors = @[(__bridge id)[color colorWithAlphaComponent:0.4].CGColor, (__bridge id)[color colorWithAlphaComponent:0.0].CGColor]; 274 | gradientLayer.locations = @[@(0.1f), @(1.0f)]; 275 | gradientLayer.startPoint = CGPointMake(0, 0); 276 | gradientLayer.endPoint = CGPointMake(1, 1); 277 | 278 | CALayer *baseLayer = [CALayer layer]; 279 | [baseLayer addSublayer:gradientLayer]; 280 | //截取渐变层 281 | [baseLayer setMask:shadeLayer]; 282 | [self.myScrollView.layer insertSublayer:baseLayer atIndex:0]; 283 | 284 | CABasicAnimation *anmi1 = [CABasicAnimation animation]; 285 | anmi1.keyPath = @"bounds"; 286 | anmi1.duration = self.yLabels.count*0.1; 287 | anmi1.toValue = [NSValue valueWithCGRect:CGRectMake(5, 0, 2*self.lastPoint.x, self.myScrollView.bounds.size.height-20)]; 288 | anmi1.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; 289 | anmi1.fillMode = kCAFillModeForwards; 290 | anmi1.autoreverses = NO; 291 | anmi1.removedOnCompletion = NO; 292 | 293 | [gradientLayer addAnimation:anmi1 forKey:@"bounds"]; 294 | } 295 | 296 | - (void)setupLastValueLabelWithView:(CGPoint)point value:(NSInteger)value grade:(CGFloat)grade chartCavanHeight:(CGFloat)chartCavanHeight { 297 | UIFont *font = self.textFont != nil ? self.textFont : [UIFont systemFontOfSize:10]; 298 | UILabel *valueLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 70, 31)]; 299 | 300 | valueLabel.text = [NSString stringWithFormat:@"%zd", value]; 301 | valueLabel.textColor = [UIColor blackColor]; 302 | valueLabel.font = font; 303 | [valueLabel sizeToFit]; 304 | CGPoint labelPoint = CGPointMake(valueLabel.text.length > 3 ? point.x - 3 : point.x, chartCavanHeight - grade * chartCavanHeight+YZCLabelHeight - 15); 305 | valueLabel.center = CGPointMake(labelPoint.x + 20, labelPoint.y); 306 | valueLabel.textAlignment = NSTextAlignmentCenter; 307 | [self addSubview:valueLabel]; 308 | } 309 | 310 | #pragma mark - setter && getter 311 | - (void)setIsHiddenUnit:(BOOL)isHiddenUnit { 312 | _isHiddenUnit = isHiddenUnit; 313 | if (!self.isHiddenUnit) { 314 | [self unitLabel]; 315 | } 316 | } 317 | 318 | - (void)setIsHiddenLastValue:(BOOL)isHiddenLastValue { 319 | _isHiddenLastValue = isHiddenLastValue; 320 | } 321 | 322 | - (void)setUnitString:(NSString *)unitString { 323 | _unitString = unitString; 324 | } 325 | 326 | - (void)setIntervalValue:(NSInteger)intervalValue { 327 | _intervalValue = intervalValue; 328 | } 329 | 330 | - (UILabel *)unitLabel { 331 | if (_unitLabel == nil) { 332 | UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(YZCLabelwidth-10, -10, 100, 40)]; 333 | label.text = self.unitString; 334 | label.textColor = [[UIColor grayColor] colorWithAlphaComponent:0.5]; 335 | [label sizeToFit]; 336 | label.textAlignment = NSTextAlignmentCenter; 337 | [label setFont:[UIFont systemFontOfSize:10]]; 338 | [self addSubview:label]; 339 | _unitLabel = label; 340 | } 341 | return _unitLabel; 342 | } 343 | 344 | - (CAShapeLayer *)chartLine { 345 | if (_chartLine == nil) { 346 | CAShapeLayer *chartLine = [CAShapeLayer layer]; 347 | chartLine.lineCap = kCALineCapRound; //设置线条拐角帽的样式 348 | chartLine.lineJoin = kCALineJoinRound; //设置两条线连结点的样式 349 | chartLine.fillColor = [[UIColor clearColor] CGColor]; 350 | chartLine.lineWidth = 2.0; 351 | chartLine.strokeEnd = 0.0; 352 | _chartLine = chartLine; 353 | } 354 | return _chartLine; 355 | } 356 | 357 | - (void)setXLabels:(NSMutableArray *)xLabels { 358 | _xLabels = xLabels; 359 | NSInteger count = xLabels.count; 360 | self.xLabelWidth = (self.myScrollView.frame.size.width - YZCLabelwidth * 0.5)/self.yLabels.count; 361 | 362 | for (int i = 0; i < count; i++) { 363 | if (i%self.intervalValue == 0 || i == count - 1) { 364 | NSString *labelText = xLabels[i]; 365 | 366 | UIFont *font = self.textFont != nil ? self.textFont : [UIFont systemFontOfSize:10]; 367 | 368 | NSDictionary *attrs = @{NSFontAttributeName : font}; 369 | CGSize size = [labelText sizeWithAttributes:attrs]; 370 | CGFloat labelW = size.width; 371 | CGFloat labelH = size.height; 372 | CGFloat labelX = marginLeft + i * self.xLabelWidth + YZCLabelwidth - labelW * 0.5; 373 | YzcLabel *label = [[YzcLabel alloc] initWithFrame:CGRectMake(labelX, self.frame.size.height - YZCLabelHeight + 5, labelW, labelH)]; 374 | label.text = labelText; 375 | if (self.textFont) { 376 | label.font = self.textFont; 377 | } 378 | [label sizeToFit]; 379 | [self addSubview:label]; 380 | 381 | if (self.isHiddenLastValue && i == count - 1) { 382 | label.textColor = [[UIColor blackColor] colorWithAlphaComponent:0.5]; 383 | } 384 | } 385 | } 386 | } 387 | 388 | - (void)setYLabels:(NSMutableArray *)yLabels { 389 | _yLabels = yLabels; 390 | self.xLabelWidth = (self.myScrollView.frame.size.width - YZCLabelwidth * 0.5)/self.yLabels.count; 391 | 392 | _yValueMax = [[self.yLabels valueForKeyPath:@"@max.floatValue"] floatValue]; 393 | _yValueMin = [[self.yLabels valueForKeyPath:@"@min.floatValue"] floatValue]; 394 | 395 | if (_chooseRange.max != _chooseRange.min) { 396 | _yValueMax = _chooseRange.max; 397 | _yValueMin = _chooseRange.min; 398 | } 399 | 400 | float level = (_yValueMax-_yValueMin) / (LINE_COUNT - 1); 401 | CGFloat chartCavanHeight = self.frame.size.height - YZCLabelHeight*(LINE_COUNT - 1); 402 | CGFloat levelHeight = chartCavanHeight / (LINE_COUNT - 1); 403 | 404 | for (int i = 0; i < LINE_COUNT; i++) { 405 | CGFloat labelValue = level * i+_yValueMin; 406 | if (labelValue >= 0 && i > 0 ) { 407 | YzcLabel *label = [[YzcLabel alloc] initWithFrame:CGRectMake(5, chartCavanHeight - i * levelHeight + 13, YZCLabelwidth+20, YZCLabelHeight)]; 408 | NSString *targetString; 409 | if (labelValue >= 1000) { 410 | targetString = [NSString stringWithFormat:@"%.1fk", (float)labelValue/1000]; 411 | } else { 412 | targetString = [NSString stringWithFormat:@"%.0f", labelValue]; 413 | } 414 | 415 | if (self.textFont) { 416 | label.font = self.textFont; 417 | } 418 | label.text = targetString; 419 | [label sizeToFit]; 420 | [self addSubview:label]; 421 | } 422 | } 423 | 424 | //画横线 425 | for (int i = 0; i < LINE_COUNT; i++) { 426 | UIColor *lineColor = self.HorizontalLinecColor ? self.HorizontalLinecColor : [[UIColor grayColor] colorWithAlphaComponent:0.5]; 427 | 428 | CGPoint startPoint = CGPointMake(marginLeft, YZCLabelHeight+i*levelHeight); 429 | CGPoint endPoint = CGPointMake(self.frame.size.width, YZCLabelHeight+i*levelHeight); 430 | if (i == LINE_COUNT - 1) { 431 | [self.myScrollView drawSolideLineWithMoveToPoint:startPoint 432 | lineToPoint:endPoint 433 | lineColor:lineColor]; 434 | } else { 435 | if (!self.isHiddenDashedLine) { 436 | [self.myScrollView drawDashLineWithStartPoint:startPoint 437 | endPoint:endPoint 438 | lineLength:2 439 | lineSpacing:1 440 | lineColor:lineColor]; 441 | } 442 | } 443 | } 444 | } 445 | 446 | @end 447 | -------------------------------------------------------------------------------- /YzcChartExample/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UILaunchStoryboardName 24 | LaunchScreen 25 | UIMainStoryboardFile 26 | Main 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UIViewControllerBasedStatusBarAppearance 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /YzcChartExample/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // YzcChart 4 | // 5 | // Created by mac on 16/11/10. 6 | // Copyright © 2016年 yzc. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) { 13 | @autoreleasepool { 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /YzcChartTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /YzcChartTests/YzcChartExampleTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // YzcChartTests.m 3 | // YzcChartTests 4 | // 5 | // Created by mac on 16/11/10. 6 | // Copyright © 2016年 yzc. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface YzcChartExampleTests : XCTestCase 12 | 13 | @end 14 | 15 | @implementation YzcChartExampleTests 16 | 17 | - (void)setUp { 18 | [super setUp]; 19 | // Put setup code here. This method is called before the invocation of each test method in the class. 20 | } 21 | 22 | - (void)tearDown { 23 | // Put teardown code here. This method is called after the invocation of each test method in the class. 24 | [super tearDown]; 25 | } 26 | 27 | - (void)testExample { 28 | // This is an example of a functional test case. 29 | // Use XCTAssert and related functions to verify your tests produce the correct results. 30 | } 31 | 32 | - (void)testPerformanceExample { 33 | // This is an example of a performance test case. 34 | [self measureBlock:^{ 35 | // Put the code you want to measure the time of here. 36 | }]; 37 | } 38 | 39 | @end 40 | -------------------------------------------------------------------------------- /YzcChartUITests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /YzcChartUITests/YzcChartUIExampleTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // YzcChartUITests.m 3 | // YzcChartUITests 4 | // 5 | // Created by mac on 16/11/10. 6 | // Copyright © 2016年 yzc. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface YzcChartUIExampleTests : XCTestCase 12 | 13 | @end 14 | 15 | @implementation YzcChartUIExampleTests 16 | 17 | - (void)setUp { 18 | [super setUp]; 19 | 20 | // Put setup code here. This method is called before the invocation of each test method in the class. 21 | 22 | // In UI tests it is usually best to stop immediately when a failure occurs. 23 | self.continueAfterFailure = NO; 24 | // UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method. 25 | [[[XCUIApplication alloc] init] launch]; 26 | 27 | // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this. 28 | } 29 | 30 | - (void)tearDown { 31 | // Put teardown code here. This method is called after the invocation of each test method in the class. 32 | [super tearDown]; 33 | } 34 | 35 | - (void)testExample { 36 | // Use recording to get started writing UI tests. 37 | // Use XCTAssert and related functions to verify your tests produce the correct results. 38 | } 39 | 40 | @end 41 | -------------------------------------------------------------------------------- /chartGIf.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Yzc-jason/YzcChart/4da595b64a6e0db81c031b87c3dd4d6d10a6498d/chartGIf.gif --------------------------------------------------------------------------------