From d08627d135786715cc6cec2e29649e2de9f77d28 Mon Sep 17 00:00:00 2001 From: runningOtter Date: Tue, 22 Apr 2014 12:41:43 +0200 Subject: [PATCH 01/11] before creating own class for area diagramm --- Classes/JBLineChartView.h | 57 ++- Classes/JBLineChartView.m | 355 +++++++++++++++++- .../JBChartViewDemo.xcodeproj/project.pbxproj | 6 + .../Controllers/JBAreaChartViewController.h | 13 + .../Controllers/JBAreaChartViewController.m | 270 +++++++++++++ .../Controllers/JBChartListViewController.m | 33 +- 6 files changed, 726 insertions(+), 8 deletions(-) create mode 100644 JBChartViewDemo/JBChartViewDemo/Controllers/JBAreaChartViewController.h create mode 100644 JBChartViewDemo/JBChartViewDemo/Controllers/JBAreaChartViewController.m diff --git a/Classes/JBLineChartView.h b/Classes/JBLineChartView.h index f6742633f..9a147fb98 100755 --- a/Classes/JBLineChartView.h +++ b/Classes/JBLineChartView.h @@ -27,8 +27,8 @@ typedef NS_ENUM(NSInteger, JBLineChartViewLineStyle){ @interface JBLineChartView : JBChartView -@property (nonatomic, weak) id delegate; -@property (nonatomic, weak) id dataSource; +@property (nonatomic, weak) IBOutlet id delegate; +@property (nonatomic, weak) IBOutlet id dataSource; /** * Vertical highlight overlayed on a line graph during touch events. @@ -46,6 +46,22 @@ typedef NS_ENUM(NSInteger, JBLineChartViewLineStyle){ */ @property (nonatomic, assign) BOOL showsLineSelection; +/** + * A highlight shown on a area under a line within the graph during touch events. The highlighted area + * is the on under the closest line to the touch point and corresponds to the lineIndex delegatd back via + * didSelectChartAtHorizontalIndex:atLineIndex: and didUnSlectChartAtHorizontalIndex:atLineIndex: + * + * Default: NO. + */ +@property (nonatomic, assign) BOOL showsAreaSelection; + +/** + * Fills the area under the lines till the next lane below or the bottom. + * + * Default: NO. + */ +@property (nonatomic, assign) BOOL fillsAreaBelowLine; + @end @protocol JBLineChartViewDelegate @@ -127,6 +143,18 @@ typedef NS_ENUM(NSInteger, JBLineChartViewLineStyle){ */ - (UIColor *)lineChartView:(JBLineChartView *)lineChartView colorForLineAtLineIndex:(NSUInteger)lineIndex; +/** + * Returns the color of particular area under the line at lineIndex within the chart. + * + * Default: black color. + * + * @param lineChartView The line chart object requesting this information. + * @param lineIndex An index number identifying a line in the chart. + * + * @return The color to be used to shade a line in the chart. + */ +- (UIColor *)lineChartView:(JBLineChartView *)lineChartView colorForAreaUnderLineAtLineIndex:(NSUInteger)lineIndex; + /** * Returns the color of a particular dot in a line at lineIndex within the chart. * For this value to apply, showsDotsForLineAtLineIndex: must return YES for the line at lineIndex. @@ -207,6 +235,19 @@ typedef NS_ENUM(NSInteger, JBLineChartViewLineStyle){ */ - (UIColor *)lineChartView:(JBLineChartView *)lineChartView selectionColorForLineAtLineIndex:(NSUInteger)lineIndex; +/** + * Returns the selection color to be overlayed on a area under a line within the chart during touch events. + * The property showsAreaSelection must be YES for the color to apply. + * + * Default: white color. + * + * @param lineChartView The line chart object requesting this information. + * @param lineIndex An index number identifying a line in the chart. + * + * @return The color to be used to highlight a line during chart selections. + */ +- (UIColor *)lineChartView:(JBLineChartView *)lineChartView selectionColorForAreaUnderLineAtLineIndex:(NSUInteger)lineIndex; + /** * Returns the selection color to be overlayed on a line within the chart during touch events. * The property showsLineSelection must be YES for the color to apply. @@ -260,4 +301,16 @@ typedef NS_ENUM(NSInteger, JBLineChartViewLineStyle){ */ - (BOOL)lineChartView:(JBLineChartView *)lineChartView smoothLineAtLineIndex:(NSUInteger)lineIndex; +/** + * Returns whether or not the area under the line should be filled + * + * Default: NO + * + * @param lineChartView The line chart object requesting this information. + * @param lineIndex An index number identifying a line in the chart. + * + * @return Whether or not the area under the line should be filled + */ +- (BOOL)lineChartView:(JBLineChartView *)lineChartView fillsAreaUnderLineWithIndex:(NSUInteger)lineIndex; + @end diff --git a/Classes/JBLineChartView.m b/Classes/JBLineChartView.m index ab069f682..93ed28a02 100755 --- a/Classes/JBLineChartView.m +++ b/Classes/JBLineChartView.m @@ -44,8 +44,10 @@ typedef NS_ENUM(NSUInteger, JBLineChartHorizontalIndexClamp){ // Colors (JBLineChartView) static UIColor *kJBLineChartViewDefaultLineColor = nil; +static UIColor *kJBLineChartViewDefaultAreaColor = nil; static UIColor *kJBLineChartViewDefaultDotColor = nil; static UIColor *kJBLineChartViewDefaultLineSelectionColor = nil; +static UIColor *kJBLineChartViewDefaultAreaSelectionColor = nil; static UIColor *kJBLineChartViewDefaultDotSelectionColor = nil; @interface JBLineLayer : CAShapeLayer @@ -55,6 +57,12 @@ @interface JBLineLayer : CAShapeLayer @end +@interface JBAreaLayer : CAShapeLayer + +@property (nonatomic, assign) NSUInteger tag; + +@end + @interface JBLineChartPoint : NSObject @property (nonatomic, assign) CGPoint position; @@ -131,11 +139,45 @@ - (id)initWithRadius:(CGFloat)radius; @end -@interface JBLineChartView () +@protocol JBLineChartAreasViewDelegate; + +@interface JBLineChartAreasView : UIView + +@property (nonatomic, assign) id delegate; +@property (nonatomic, assign) NSInteger selectedLineIndex; // -1 to unselect +@property (nonatomic, assign) BOOL animated; + +// Data +- (void)reloadData; + +// Setters +- (void)setSelectedLineIndex:(NSInteger)selectedLineIndex animated:(BOOL)animated; + +// Callback helpers +- (void)fireCallback:(void (^)())callback; + +// View helpers +- (JBAreaLayer *)areaLayerForLineIndex:(NSUInteger)lineIndex; + + +@end + + +@protocol JBLineChartAreasViewDelegate + +- (NSArray *)chartDataForLineChartAreasView:(JBLineChartAreasView*)lineChartAreasView; +- (UIColor *)lineChartAreasView:(JBLineChartAreasView *)lineChartAreasView colorForAreaUnderLineAtLineIndex:(NSUInteger)lineIndex; +- (UIColor *)lineChartAreasView:(JBLineChartAreasView *)lineChartAreasView selectedColorForAreaUnderLineAtLineIndex:(NSUInteger)lineIndex; +- (CGFloat)paddingForLineChartAreasView:(JBLineChartAreasView *)lineChartAreasView; + +@end + +@interface JBLineChartView () @property (nonatomic, strong) NSArray *chartData; @property (nonatomic, strong) JBLineChartLinesView *linesView; @property (nonatomic, strong) JBLineChartDotsView *dotsView; +@property (nonatomic, strong) JBLineChartAreasView *areasView; @property (nonatomic, strong) JBChartVerticalSelectionView *verticalSelectionView; @property (nonatomic, assign) CGFloat cachedMaxHeight; @property (nonatomic, assign) CGFloat cachedMinHeight; @@ -175,8 +217,10 @@ + (void)initialize if (self == [JBLineChartView class]) { kJBLineChartViewDefaultLineColor = [UIColor blackColor]; + kJBLineChartViewDefaultAreaColor = [[UIColor blackColor] colorWithAlphaComponent:0.5]; kJBLineChartViewDefaultDotColor = [UIColor blackColor]; kJBLineChartViewDefaultLineSelectionColor = [UIColor whiteColor]; + kJBLineChartViewDefaultAreaSelectionColor = [[UIColor whiteColor] colorWithAlphaComponent:0.5]; kJBLineChartViewDefaultDotSelectionColor = [UIColor whiteColor]; } } @@ -215,6 +259,8 @@ - (void)construct { _showsVerticalSelection = YES; _showsLineSelection = YES; + _showsAreaSelection = NO; + _fillsAreaBelowLine = NO; _cachedMinHeight = kJBBarChartViewUndefinedCachedHeight; _cachedMaxHeight = kJBBarChartViewUndefinedCachedHeight; } @@ -326,6 +372,38 @@ - (void)reloadData [self addSubview:self.dotsView]; } }; + + /* + * Creates a new areas view using the previously calculated data model + */ + dispatch_block_t createAreaView = ^{ + + // Remove old areas view + if (self.areasView) + { + [self.areasView removeFromSuperview]; + self.areasView = nil; + } + + + // Create new areas and overlay subviews + self.areasView = [[JBLineChartAreasView alloc] initWithFrame:CGRectOffset(mainViewRect, 0, self.headerView.frame.size.height + self.headerPadding)]; + self.areasView.delegate = self; + //hide when not needed + self.areasView.hidden = !self.fillsAreaBelowLine; + + + // Add new areas view + if (self.footerView) + { + [self insertSubview:self.areasView belowSubview:self.footerView]; + } + else + { + [self addSubview:self.areasView]; + } + }; + /* * Creates a vertical selection view for touch events @@ -362,6 +440,7 @@ - (void)reloadData }; createChartData(); + createAreaView(); createLineGraphView(); createDotGraphView(); createSelectionView(); @@ -604,6 +683,49 @@ - (BOOL)lineChartDotsView:(JBLineChartDotsView *)lineChartDotsView showsDotsForL return NO; } +#pragma mark - JBLineChartAreasViewDelegate + +- (NSArray *)chartDataForLineChartAreasView:(JBLineChartAreasView*)lineChartAreasView +{ + return self.chartData; +} + +- (UIColor *)lineChartAreasView:(JBLineChartAreasView *)lineChartAreasView colorForAreaUnderLineAtLineIndex:(NSUInteger)lineIndex +{ + if ([self.dataSource respondsToSelector:@selector(lineChartView:colorForAreaUnderLineAtLineIndex:)]) + { + return [self.dataSource lineChartView:self colorForAreaUnderLineAtLineIndex:lineIndex]; + } + + if ([self.dataSource respondsToSelector:@selector(lineChartView:colorForLineAtLineIndex:)]) + { + return [[self.dataSource lineChartView:self colorForLineAtLineIndex:lineIndex] colorWithAlphaComponent:0.5]; + } + + return kJBLineChartViewDefaultAreaColor; +} + +- (UIColor *)lineChartAreasView:(JBLineChartAreasView *)lineChartAreasView selectedColorForAreaUnderLineAtLineIndex:(NSUInteger)lineIndex +{ + if ([self.dataSource respondsToSelector:@selector(lineChartView:selectionColorForAreaUnderLineAtLineIndex:)]) + { + return [self.dataSource lineChartView:self selectionColorForAreaUnderLineAtLineIndex:lineIndex]; + } + + if ([self.dataSource respondsToSelector:@selector(lineChartView:selectionColorForLineAtLineIndex:)]) + { + return [[self.dataSource lineChartView:self selectionColorForLineAtLineIndex:lineIndex] colorWithAlphaComponent:0.5]; + } + + return kJBLineChartViewDefaultAreaSelectionColor; +} + +- (CGFloat)paddingForLineChartAreasView:(JBLineChartAreasView *)lineChartAreasView +{ + return [self padding]; +} + + #pragma mark - Setters - (void)setState:(JBChartViewState)state animated:(BOOL)animated callback:(void (^)())callback force:(BOOL)force @@ -618,11 +740,13 @@ - (void)setState:(JBChartViewState)state animated:(BOOL)animated callback:(void dispatch_block_t adjustViewFrames = ^{ self.linesView.frame = CGRectMake(self.linesView.frame.origin.x, yOffset + ((self.state == JBChartViewStateCollapsed) ? (self.linesView.frame.size.height + self.footerView.frame.size.height) : 0.0), self.linesView.frame.size.width, self.linesView.frame.size.height); self.dotsView.frame = CGRectMake(self.dotsView.frame.origin.x, yOffset + ((self.state == JBChartViewStateCollapsed) ? (self.dotsView.frame.size.height + self.footerView.frame.size.height) : 0.0), self.dotsView.frame.size.width, self.dotsView.frame.size.height); + self.areasView.frame = CGRectMake(self.areasView.frame.origin.x, yOffset + ((self.state == JBChartViewStateCollapsed) ? (self.areasView.frame.size.height + self.footerView.frame.size.height) : 0.0), self.areasView.frame.size.width, self.areasView.frame.size.height); }; dispatch_block_t adjustViewAlphas = ^{ self.linesView.alpha = (self.state == JBChartViewStateExpanded) ? 1.0 : 0.0; self.dotsView.alpha = (self.state == JBChartViewStateExpanded) ? 1.0 : 0.0; + self.areasView.alpha = (self.state == JBChartViewStateExpanded) ? 1.0 : 0.0; }; if (animated) @@ -630,6 +754,7 @@ - (void)setState:(JBChartViewState)state animated:(BOOL)animated callback:(void [UIView animateWithDuration:(kJBLineChartViewStateAnimationDuration * 0.5) delay:0.0 options:UIViewAnimationOptionBeginFromCurrentState animations:^{ self.linesView.frame = CGRectOffset(mainViewRect, 0, yOffset - kJBLineChartViewStateBounceOffset); // bounce self.dotsView.frame = CGRectOffset(mainViewRect, 0, yOffset - kJBLineChartViewStateBounceOffset); + self.areasView.frame = CGRectOffset(mainViewRect, 0, yOffset - kJBLineChartViewStateBounceOffset); } completion:^(BOOL finished) { [UIView animateWithDuration:kJBLineChartViewStateAnimationDuration delay:0.0 options:UIViewAnimationOptionBeginFromCurrentState animations:^{ adjustViewFrames(); @@ -881,6 +1006,7 @@ - (void)touchesEndedOrCancelledWithTouches:(NSSet *)touches { [self.linesView setSelectedLineIndex:kJBLineChartLinesViewUnselectedLineIndex animated:YES]; [self.dotsView setSelectedLineIndex:kJBLineChartDotsViewUnselectedLineIndex animated:YES]; + [self.areasView setSelectedLineIndex:kJBLineChartLinesViewUnselectedLineIndex animated:YES]; } } @@ -925,6 +1051,7 @@ - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { [self.linesView setSelectedLineIndex:[self lineIndexForPoint:touchPoint] animated:YES]; [self.dotsView setSelectedLineIndex:[self lineIndexForPoint:touchPoint] animated:YES]; + [self.areasView setSelectedLineIndex:[self lineIndexForPoint:touchPoint] animated:YES]; } [self touchesBeganOrMovedWithTouches:touches]; } @@ -1065,6 +1192,7 @@ - (void)drawRect:(CGRect)rect index++; } + JBLineLayer *shapeLayer = [self lineLayerForLineIndex:lineIndex]; if (shapeLayer == nil) @@ -1075,10 +1203,10 @@ - (void)drawRect:(CGRect)rect shapeLayer.tag = lineIndex; NSAssert([self.delegate respondsToSelector:@selector(lineChartLinesView:lineStyleForLineAtLineIndex:)], @"JBLineChartLinesView // delegate must implement - (JBLineChartViewLineStyle)lineChartLineView:(JBLineChartLinesView *)lineChartLinesView lineStyleForLineAtLineIndex:(NSUInteger)lineIndex"); shapeLayer.lineStyle = [self.delegate lineChartLinesView:self lineStyleForLineAtLineIndex:lineIndex]; - + NSAssert([self.delegate respondsToSelector:@selector(lineChartLinesView:colorForLineAtLineIndex:)], @"JBLineChartLinesView // delegate must implement - (UIColor *)lineChartLinesView:(JBLineChartLinesView *)lineChartLinesView colorForLineAtLineIndex:(NSUInteger)lineIndex"); shapeLayer.strokeColor = [self.delegate lineChartLinesView:self colorForLineAtLineIndex:lineIndex].CGColor; - + NSAssert([self.delegate respondsToSelector:@selector(lineChartLinesView:smoothLineAtLineIndex:)], @"JBLineChartLinesView // delegate must implement - (UIColor *)lineChartLinesView:(JBLineChartLinesView *)lineChartLinesView colorForLineAtLineIndex:(NSUInteger)lineIndex"); BOOL smoothLine = [self.delegate lineChartLinesView:self smoothLineAtLineIndex:lineIndex]; if (smoothLine) @@ -1094,11 +1222,13 @@ - (void)drawRect:(CGRect)rect NSAssert([self.delegate respondsToSelector:@selector(lineChartLinesView:widthForLineAtLineIndex:)], @"JBLineChartLinesView // delegate must implement - (CGFloat)lineChartLinesView:(JBLineChartLinesView *)lineChartLinesView widthForLineAtLineIndex:(NSUInteger)lineIndex"); shapeLayer.lineWidth = [self.delegate lineChartLinesView:self widthForLineAtLineIndex:lineIndex]; + shapeLayer.path = path.CGPath; shapeLayer.frame = self.bounds; [self.layer addSublayer:shapeLayer]; lineIndex++; + } self.animated = NO; @@ -1183,6 +1313,21 @@ - (JBLineLayer *)lineLayerForLineIndex:(NSUInteger)lineIndex return nil; } +- (JBLineLayer *)fillLayerForAreaIndex:(NSUInteger)areaIndex +{ + for (CALayer *layer in [self.layer sublayers]) + { + if ([layer isKindOfClass:[JBLineLayer class]]) + { + if (((JBLineLayer *)layer).tag == areaIndex) + { + return (JBLineLayer *)layer; + } + } + } + return nil; +} + @end @implementation JBLineChartDotsView @@ -1317,3 +1462,207 @@ - (id)initWithRadius:(CGFloat)radius } @end + + +@implementation JBAreaLayer + +#pragma mark - Alloc/Init + ++ (void)initialize +{ + if (self == [JBAreaLayer class]) + { + + } +} + +- (id)init +{ + self = [super init]; + if (self) + { + self.zPosition = 0.0f; + self.strokeColor = [UIColor clearColor].CGColor; + } + return self; +} +@end + +@implementation JBLineChartAreasView + +#pragma mark - Alloc/Init + +- (id)initWithFrame:(CGRect)frame +{ + self = [super initWithFrame:frame]; + if (self) + { + self.backgroundColor = [UIColor clearColor]; + } + return self; +} + +#pragma mark - Memory Management + +- (void)dealloc +{ + [NSObject cancelPreviousPerformRequestsWithTarget:self]; +} + +#pragma mark - Drawing + +- (void)drawRect:(CGRect)rect +{ + [super drawRect:rect]; + + NSAssert([self.delegate respondsToSelector:@selector(chartDataForLineChartAreasView:)], @"JBLineChartAreasView // delegate must implement - (NSArray *)chartDataForLineChartAreasView:(JBLineChartAreasView *)lineChartAreasView"); + NSArray *chartData = [self.delegate chartDataForLineChartAreasView:self]; + + NSAssert([self.delegate respondsToSelector:@selector(paddingForLineChartAreasView:)], @"JBLineChartAreasView // delegate must implement - (CGFloat)paddingForLineChartAreasView:(JBLineChartAreasView *)lineChartAreasView"); + CGFloat padding = [self.delegate paddingForLineChartAreasView:self]; + + NSUInteger lineIndex = 0; + NSArray *previousLineData = nil; + for (NSArray *lineData in chartData) + { + UIBezierPath *path = [UIBezierPath bezierPath]; + path.miterLimit = kJBLineChartLinesViewMiterLimit; + + if (!previousLineData) { + JBLineChartPoint *lowerRightCornor = [[JBLineChartPoint alloc] init]; + lowerRightCornor.position = CGPointMake(self.bounds.size.width - padding, self.bounds.size.height - padding); + JBLineChartPoint *lowerLeftCornor = [[JBLineChartPoint alloc] init]; + lowerLeftCornor.position = CGPointMake(padding, self.bounds.size.height); + previousLineData = @[lowerLeftCornor, lowerRightCornor]; + } + + //add the previous line in inversed order at the beginning of the path to create a polygon + NSUInteger index = 0; + for (JBLineChartPoint *lineChartPoint in [[previousLineData reverseObjectEnumerator] allObjects]) + { + if (index == 0) + { + [path moveToPoint:CGPointMake(lineChartPoint.position.x, fmin(self.bounds.size.height - padding, fmax(padding, lineChartPoint.position.y)))]; + } + else + { + [path addLineToPoint:CGPointMake(lineChartPoint.position.x, fmin(self.bounds.size.height - padding, fmax(padding, lineChartPoint.position.y)))]; + } + index ++; + } + + for (JBLineChartPoint *lineChartPoint in [lineData sortedArrayUsingSelector:@selector(compare:)]) + { + + [path addLineToPoint:CGPointMake(lineChartPoint.position.x, fmin(self.bounds.size.height - padding, fmax(padding, lineChartPoint.position.y)))]; + } + + [path closePath]; + + + + JBAreaLayer *areaLayer = [self areaLayerForLineIndex:lineIndex]; + if (areaLayer == nil) { + areaLayer = [JBAreaLayer layer]; + } + + areaLayer.tag = lineIndex; + NSAssert([self.delegate respondsToSelector:@selector(lineChartAreasView:colorForAreaUnderLineAtLineIndex:)], @"JBLineChartAreasView // delegate must implement - (UIColor *)lineChartAreasView:(JBLineChartAreasView *)lineChartAreasView colorForAreaUnderLineAtLineIndex:(NSUInteger)lineIndex"); + areaLayer.fillColor = [self.delegate lineChartAreasView:self colorForAreaUnderLineAtLineIndex:lineIndex].CGColor; + + + areaLayer.path = path.CGPath; + areaLayer.frame = self.bounds; + [self.layer addSublayer:areaLayer]; + + previousLineData = lineData; + + lineIndex++; + } + + self.animated = NO; +} + + +#pragma mark - Data + +- (void)reloadData +{ + // Drawing is all done with CG (no subviews here) + [self setNeedsDisplay]; +} + + +#pragma mark - Setters + +- (void)setSelectedLineIndex:(NSInteger)selectedLineIndex animated:(BOOL)animated +{ + _selectedLineIndex = selectedLineIndex; + + dispatch_block_t adjustLines = ^{ + for (CALayer *layer in [self.layer sublayers]) + { + if ([layer isKindOfClass:[JBAreaLayer class]]) + { + if (((JBAreaLayer *)layer).tag == _selectedLineIndex) + { + NSAssert([self.delegate respondsToSelector:@selector(lineChartAreasView:selectedColorForAreaUnderLineAtLineIndex:)], @"JBLineChartAreasView // delegate must implement - (UIColor *)lineChartAreasView:(JBLineChartAreasView *)lineChartAreasView selectedColorForAreaUnderLineAtLineIndex:(NSUInteger)lineIndex"); + ((JBLineLayer *)layer).fillColor = [self.delegate lineChartAreasView:self selectedColorForAreaUnderLineAtLineIndex:((JBAreaLayer *)layer).tag].CGColor; + ((JBAreaLayer *)layer).opacity = 1.0f; + } + else + { + NSAssert([self.delegate respondsToSelector:@selector(lineChartAreasView:colorForAreaUnderLineAtLineIndex:)], @"JBLineChartAreasView // delegate must implement - (UIColor *)lineChartAreasView:(JBLineChartAreasView *)lineChartAreasView colorForAreaUnderLineAtLineIndex:(NSUInteger)lineIndex"); + ((JBAreaLayer *)layer).fillColor = [self.delegate lineChartAreasView:self colorForAreaUnderLineAtLineIndex:((JBLineLayer *)layer).tag].CGColor; + ((JBAreaLayer *)layer).opacity = (_selectedLineIndex == kJBLineChartLinesViewUnselectedLineIndex) ? 1.0f : kJBLineChartLinesViewDefaultDimmedOpacity; + } + } + } + }; + + if (animated) + { + [UIView animateWithDuration:kJBChartViewDefaultAnimationDuration animations:^{ + adjustLines(); + }]; + } + else + { + adjustLines(); + } +} + +- (void)setSelectedLineIndex:(NSInteger)selectedLineIndex +{ + [self setSelectedLineIndex:selectedLineIndex animated:NO]; +} + + +#pragma mark - Callback Helpers + +- (void)fireCallback:(void (^)())callback +{ + dispatch_block_t callbackCopy = [callback copy]; + + if (callbackCopy != nil) + { + callbackCopy(); + } +} + +- (JBAreaLayer *)areaLayerForLineIndex:(NSUInteger)areaIndex +{ + for (CALayer *layer in [self.layer sublayers]) + { + if ([layer isKindOfClass:[JBAreaLayer class]]) + { + if (((JBAreaLayer *)layer).tag == areaIndex) + { + return (JBAreaLayer *)layer; + } + } + } + return nil; +} + +@end \ No newline at end of file diff --git a/JBChartViewDemo/JBChartViewDemo.xcodeproj/project.pbxproj b/JBChartViewDemo/JBChartViewDemo.xcodeproj/project.pbxproj index 95e6977cf..f0a9eda6d 100644 --- a/JBChartViewDemo/JBChartViewDemo.xcodeproj/project.pbxproj +++ b/JBChartViewDemo/JBChartViewDemo.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 44EB67A11905B47800FABB5D /* JBAreaChartViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 44EB67A01905B47800FABB5D /* JBAreaChartViewController.m */; }; 9B0725211829822A0052109B /* JBChartListViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 9B0725201829822A0052109B /* JBChartListViewController.m */; }; 9B2E530518218CF20079B9D2 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9B2E530418218CF20079B9D2 /* Foundation.framework */; }; 9B2E530718218CF20079B9D2 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9B2E530618218CF20079B9D2 /* CoreGraphics.framework */; }; @@ -42,6 +43,8 @@ /* End PBXBuildFile section */ /* Begin PBXFileReference section */ + 44EB679F1905B47800FABB5D /* JBAreaChartViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JBAreaChartViewController.h; sourceTree = ""; }; + 44EB67A01905B47800FABB5D /* JBAreaChartViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JBAreaChartViewController.m; sourceTree = ""; }; 9B07251F1829822A0052109B /* JBChartListViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JBChartListViewController.h; sourceTree = ""; }; 9B0725201829822A0052109B /* JBChartListViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JBChartListViewController.m; sourceTree = ""; }; 9B2E530118218CF20079B9D2 /* JBChartViewDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = JBChartViewDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -189,6 +192,8 @@ 9B0725201829822A0052109B /* JBChartListViewController.m */, 9B6A68DF1829BED5006DB3BF /* JBLineChartViewController.h */, 9B6A68E01829BED5006DB3BF /* JBLineChartViewController.m */, + 44EB679F1905B47800FABB5D /* JBAreaChartViewController.h */, + 44EB67A01905B47800FABB5D /* JBAreaChartViewController.m */, ); path = Controllers; sourceTree = ""; @@ -398,6 +403,7 @@ 9BEE694618D2789E005D9BA7 /* JBBaseChartViewController.m in Sources */, 9B6A68E11829BED5006DB3BF /* JBLineChartViewController.m in Sources */, 9B2E533F18218D310079B9D2 /* AppDelegate.m in Sources */, + 44EB67A11905B47800FABB5D /* JBAreaChartViewController.m in Sources */, 9BD57BBC18D13D1A00ACFA52 /* JBChartTooltipView.m in Sources */, 9B603D4B182C7117000A76D0 /* JBBaseViewController.m in Sources */, 9B0725211829822A0052109B /* JBChartListViewController.m in Sources */, diff --git a/JBChartViewDemo/JBChartViewDemo/Controllers/JBAreaChartViewController.h b/JBChartViewDemo/JBChartViewDemo/Controllers/JBAreaChartViewController.h new file mode 100644 index 000000000..159da8b2b --- /dev/null +++ b/JBChartViewDemo/JBChartViewDemo/Controllers/JBAreaChartViewController.h @@ -0,0 +1,13 @@ +// +// JBAreaChartViewController.h +// JBChartViewDemo +// +// Created by Lars Ott on 21.04.14. +// Copyright (c) 2014 Jawbone. All rights reserved. +// + +#import "JBBaseChartViewController.h" + +@interface JBAreaChartViewController : JBBaseChartViewController + +@end diff --git a/JBChartViewDemo/JBChartViewDemo/Controllers/JBAreaChartViewController.m b/JBChartViewDemo/JBChartViewDemo/Controllers/JBAreaChartViewController.m new file mode 100644 index 000000000..75e21765a --- /dev/null +++ b/JBChartViewDemo/JBChartViewDemo/Controllers/JBAreaChartViewController.m @@ -0,0 +1,270 @@ +// +// JBAreaChartViewController.m +// JBChartViewDemo +// +// Created by Lars Ott on 21.04.14. +// Copyright (c) 2014 Jawbone. All rights reserved. +// + +#import "JBAreaChartViewController.h" + +// Views +#import "JBLineChartView.h" +#import "JBChartHeaderView.h" +#import "JBLineChartFooterView.h" +#import "JBChartInformationView.h" + +#define ARC4RANDOM_MAX 0x100000000 + +typedef NS_ENUM(NSInteger, JBLineChartLine){ + JBLineChartLineBottom, + JBLineChartLineTop, + JBLineChartLineCount +}; + +// Numerics +CGFloat const kJBAreaChartViewControllerChartHeight = 250.0f; +CGFloat const kJBAreaChartViewControllerChartPadding = 10.0f; +CGFloat const kJBAreaChartViewControllerChartHeaderHeight = 75.0f; +CGFloat const kJBAreaChartViewControllerChartHeaderPadding = 20.0f; +CGFloat const kJBAreaChartViewControllerChartFooterHeight = 20.0f; +CGFloat const kJBAreaChartViewControllerChartSolidLineWidth = 6.0f; +CGFloat const kJBAreaChartViewControllerChartDashedLineWidth = 2.0f; +NSInteger const kJBAreaChartViewControllerMaxNumChartPoints = 7; + +// Strings +NSString * const kJBAreaChartViewControllerNavButtonViewKey = @"view"; + +@interface JBAreaChartViewController () + +@property (nonatomic, strong) JBLineChartView *lineChartView; +@property (nonatomic, strong) JBChartInformationView *informationView; +@property (nonatomic, strong) NSArray *lineData; +@property (nonatomic, strong) NSArray *weekDays; + +// Buttons +- (void)chartToggleButtonPressed:(id)sender; + +// Helpers +- (void)initFakeData; + +@end + +@implementation JBAreaChartViewController + +#pragma mark - Alloc/Init + +- (id)init +{ + self = [super init]; + if (self) + { + [self initFakeData]; + } + return self; +} + +- (id)initWithCoder:(NSCoder *)aDecoder +{ + self = [super initWithCoder:aDecoder]; + if (self) + { + [self initFakeData]; + } + return self; +} + +- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil +{ + self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; + if (self) + { + [self initFakeData]; + } + return self; +} + +#pragma mark - Data + +- (void)initFakeData +{ + + NSMutableArray *mutableLineData = [NSMutableArray array]; + for (int i=0; i Date: Tue, 22 Apr 2014 15:37:07 +0200 Subject: [PATCH 02/11] area filling for line chart now Working; Implemented in example --- Classes/JBLineChartView.h | 10 ++ Classes/JBLineChartView.m | 62 ++++++++--- .../Constants/JBColorConstants.h | 15 +++ .../Constants/JBStringConstants.h | 9 ++ .../Controllers/JBAreaChartViewController.m | 101 +++++++++++------- .../Controllers/JBChartListViewController.m | 6 +- 6 files changed, 146 insertions(+), 57 deletions(-) diff --git a/Classes/JBLineChartView.h b/Classes/JBLineChartView.h index 9a147fb98..119fd4746 100755 --- a/Classes/JBLineChartView.h +++ b/Classes/JBLineChartView.h @@ -57,11 +57,21 @@ typedef NS_ENUM(NSInteger, JBLineChartViewLineStyle){ /** * Fills the area under the lines till the next lane below or the bottom. + * For best results the lines should not intersect each other. One way to achive this is + * makeing the diagramm cumulative by setting the BOOL isCumulative to YES * * Default: NO. */ @property (nonatomic, assign) BOOL fillsAreaBelowLine; +/** + * If YES the chart adds the value of the next line to the previous. The distance of a line to the one below + * represents the upper lines real value. For best results you should also set the BOOL fillsAreaBelowLine to YES + * + * Default: NO. + */ +@property (nonatomic, assign) BOOL isCumulative; + @end @protocol JBLineChartViewDelegate diff --git a/Classes/JBLineChartView.m b/Classes/JBLineChartView.m index 93ed28a02..560799d75 100755 --- a/Classes/JBLineChartView.m +++ b/Classes/JBLineChartView.m @@ -261,6 +261,7 @@ - (void)construct _showsLineSelection = YES; _showsAreaSelection = NO; _fillsAreaBelowLine = NO; + _isCumulative = NO; _cachedMinHeight = kJBBarChartViewUndefinedCachedHeight; _cachedMaxHeight = kJBBarChartViewUndefinedCachedHeight; } @@ -305,8 +306,20 @@ - (void)reloadData NSAssert(rawHeight >= 0, @"JBLineChartView // delegate function - (CGFloat)lineChartView:(JBLineChartView *)lineChartView verticalValueForHorizontalIndex:(NSUInteger)horizontalIndex atLineIndex:(NSUInteger)lineIndex must return a CGFloat >= 0"); CGFloat normalizedHeight = [self normalizedHeightForRawHeight:rawHeight]; - yOffset = mainViewRect.size.height - normalizedHeight; - + + //TODO: heigt of line below if no point direct below + if (_isCumulative) { + CGFloat normalizedHeightOfLineBelow = mainViewRect.size.height; + if (lineIndex > 0) { + CGFloat rawHeightOfLineBelow = [self.delegate lineChartView:self verticalValueForHorizontalIndex:horizontalIndex atLineIndex:lineIndex - 1]; + normalizedHeightOfLineBelow -= [self normalizedHeightForRawHeight:rawHeightOfLineBelow]; + } + + yOffset = normalizedHeightOfLineBelow - normalizedHeight; + } else { + yOffset = mainViewRect.size.height - normalizedHeight; + } + JBLineChartPoint *chartPoint = [[JBLineChartPoint alloc] init]; chartPoint.position = CGPointMake(xOffset, yOffset); @@ -826,21 +839,44 @@ - (CGFloat)cachedMaxHeight if (_cachedMaxHeight == kJBBarChartViewUndefinedCachedHeight) { CGFloat maxHeight = 0; - NSAssert([self.dataSource respondsToSelector:@selector(numberOfLinesInLineChartView:)], @"JBLineChartView // dataSource must implement - (NSUInteger)numberOfLinesInLineChartView:(JBLineChartView *)lineChartView"); - for (NSUInteger lineIndex=0; lineIndex<[self.dataSource numberOfLinesInLineChartView:self]; lineIndex++) - { - NSAssert([self.dataSource respondsToSelector:@selector(lineChartView:numberOfVerticalValuesAtLineIndex:)], @"JBLineChartView // dataSource must implement - (NSUInteger)lineChartView:(JBLineChartView *)lineChartView numberOfVerticalValuesAtLineIndex:(NSUInteger)lineIndex"); - NSUInteger dataCount = [self.dataSource lineChartView:self numberOfVerticalValuesAtLineIndex:lineIndex]; - for (NSUInteger horizontalIndex=0; horizontalIndex= 0, @"JBLineChartView // delegate function - (CGFloat)lineChartView:(JBLineChartView *)lineChartView verticalValueForHorizontalIndex:(NSUInteger)horizontalIndex atLineIndex:(NSUInteger)lineIndex must return a CGFloat >= 0"); - if (height > maxHeight) + NSAssert([self.dataSource respondsToSelector:@selector(lineChartView:numberOfVerticalValuesAtLineIndex:)], @"JBLineChartView // dataSource must implement - (NSUInteger)lineChartView:(JBLineChartView *)lineChartView numberOfVerticalValuesAtLineIndex:(NSUInteger)lineIndex"); + NSUInteger dataCount = [self.dataSource lineChartView:self numberOfVerticalValuesAtLineIndex:lineIndex]; + for (NSUInteger horizontalIndex=0; horizontalIndex= 0, @"JBLineChartView // delegate function - (CGFloat)lineChartView:(JBLineChartView *)lineChartView verticalValueForHorizontalIndex:(NSUInteger)horizontalIndex atLineIndex:(NSUInteger)lineIndex must return a CGFloat >= 0"); + if (height > maxHeight) + { + maxHeight = height; + } + } + } + } else { + NSAssert([self.dataSource respondsToSelector:@selector(numberOfLinesInLineChartView:)], @"JBLineChartView // dataSource must implement - (NSUInteger)numberOfLinesInLineChartView:(JBLineChartView *)lineChartView"); + for (NSUInteger lineIndex=0; lineIndex<[self.dataSource numberOfLinesInLineChartView:self]; lineIndex++) + { + CGFloat maxHeightInLine = 0; + NSAssert([self.dataSource respondsToSelector:@selector(lineChartView:numberOfVerticalValuesAtLineIndex:)], @"JBLineChartView // dataSource must implement - (NSUInteger)lineChartView:(JBLineChartView *)lineChartView numberOfVerticalValuesAtLineIndex:(NSUInteger)lineIndex"); + NSUInteger dataCount = [self.dataSource lineChartView:self numberOfVerticalValuesAtLineIndex:lineIndex]; + for (NSUInteger horizontalIndex=0; horizontalIndex= 0, @"JBLineChartView // delegate function - (CGFloat)lineChartView:(JBLineChartView *)lineChartView verticalValueForHorizontalIndex:(NSUInteger)horizontalIndex atLineIndex:(NSUInteger)lineIndex must return a CGFloat >= 0"); + if (height > maxHeightInLine) + { + maxHeightInLine = height; + } } + maxHeight += maxHeightInLine; } + } _cachedMaxHeight = maxHeight; } diff --git a/JBChartViewDemo/JBChartViewDemo/Constants/JBColorConstants.h b/JBChartViewDemo/JBChartViewDemo/Constants/JBColorConstants.h index 8fbe99968..2d9b7180b 100644 --- a/JBChartViewDemo/JBChartViewDemo/Constants/JBColorConstants.h +++ b/JBChartViewDemo/JBChartViewDemo/Constants/JBColorConstants.h @@ -32,6 +32,21 @@ #define kJBColorLineChartDefaultDashedLineColor [UIColor colorWithRed:1.0 green:0.0 blue:0.0 alpha:1.0] #define kJBColorLineChartDefaultDashedSelectedLineColor [UIColor colorWithWhite:1.0 alpha:1.0] +#define mark - Area Chart + +#define kJBColorAreaChartControllerBackground UIColorFromHex(0xb7e3e4) +#define kJBColorAreaChartBackground UIColorFromHex(0xb7e3e4) +#define kJBColorAreaChartHeader UIColorFromHex(0x1c474e) +#define kJBColorAreaChartHeaderSeparatorColor UIColorFromHex(0x8eb6b7) +#define kJBColorAreaChartDefaultSunLineColor [UIColor clearColor] +#define kJBColorAreaChartDefaultSunAreaColor [UIColorFromHex(0xfcfb3a) colorWithAlphaComponent:0.5] +#define kJBColorAreaChartDefaultSunSelectedLineColor [UIColor clearColor] +#define kJBColorAreaChartDefaultSunSelectedAreaColor UIColorFromHex(0xfcfb3a) +#define kJBColorAreaChartDefaultMoonLineColor [UIColor clearColor] +#define kJBColorAreaChartDefaultMoonAreaColor [[UIColor blackColor] colorWithAlphaComponent:0.5] +#define kJBColorAreaChartDefaultMoonSelectedLineColor [UIColor clearColor] +#define kJBColorAreaChartDefaultMoonSelectedAreaColor [UIColor blackColor] + #pragma mark - Tooltips #define kJBColorTooltipColor [UIColor colorWithWhite:1.0 alpha:0.9] diff --git a/JBChartViewDemo/JBChartViewDemo/Constants/JBStringConstants.h b/JBChartViewDemo/JBChartViewDemo/Constants/JBStringConstants.h index 4cd6a1314..1d6c02143 100644 --- a/JBChartViewDemo/JBChartViewDemo/Constants/JBStringConstants.h +++ b/JBChartViewDemo/JBChartViewDemo/Constants/JBStringConstants.h @@ -27,3 +27,12 @@ #define kJBStringLabelMm localize(@"label.mm", @"mm") #define kJBStringLabelMetropolitanAverage localize(@"label.metropolitan.average", @"Metropolitan Average") #define kJBStringLabelNationalAverage localize(@"label.national.average", @"National Average") + +#pragma mark - Labels (Area Chart) + +#define kJBStringLabel2014 localize(@"label.2014", @"2014") +#define kJBStringLabelSeattle2014 localize(@"label.seattle.2014", @"Seattle - 2014") +#define kJBStringLabelAverageShineHours localize(@"label.average.shine.hours", @"Average Shine Hours of Sun/Moon") +#define kJBStringLabelHours localize(@"label.hours", @"h") +#define kJBStringLabelMoon localize(@"label.moon", @"Moon") +#define kJBStringLabelSun localize(@"label.sun", @"Sun") \ No newline at end of file diff --git a/JBChartViewDemo/JBChartViewDemo/Controllers/JBAreaChartViewController.m b/JBChartViewDemo/JBChartViewDemo/Controllers/JBAreaChartViewController.m index 75e21765a..08a7f5c45 100644 --- a/JBChartViewDemo/JBChartViewDemo/Controllers/JBAreaChartViewController.m +++ b/JBChartViewDemo/JBChartViewDemo/Controllers/JBAreaChartViewController.m @@ -17,8 +17,8 @@ #define ARC4RANDOM_MAX 0x100000000 typedef NS_ENUM(NSInteger, JBLineChartLine){ - JBLineChartLineBottom, - JBLineChartLineTop, + JBLineChartLineSun, + JBLineChartLineMoon, JBLineChartLineCount }; @@ -28,8 +28,7 @@ typedef NS_ENUM(NSInteger, JBLineChartLine){ CGFloat const kJBAreaChartViewControllerChartHeaderHeight = 75.0f; CGFloat const kJBAreaChartViewControllerChartHeaderPadding = 20.0f; CGFloat const kJBAreaChartViewControllerChartFooterHeight = 20.0f; -CGFloat const kJBAreaChartViewControllerChartSolidLineWidth = 6.0f; -CGFloat const kJBAreaChartViewControllerChartDashedLineWidth = 2.0f; +CGFloat const kJBAreaChartViewControllerChartLineWidth = 2.0f; NSInteger const kJBAreaChartViewControllerMaxNumChartPoints = 7; // Strings @@ -39,14 +38,15 @@ @interface JBAreaChartViewController () [largestLineData count]) + { + largestLineData = lineData; + } + } + return largestLineData; +} #pragma mark - View Lifecycle @@ -117,13 +132,14 @@ - (void)loadView self.lineChartView.headerPadding =kJBAreaChartViewControllerChartHeaderPadding; self.lineChartView.backgroundColor = kJBColorLineChartBackground; self.lineChartView.fillsAreaBelowLine = YES; + self.lineChartView.isCumulative = YES; JBChartHeaderView *headerView = [[JBChartHeaderView alloc] initWithFrame:CGRectMake(kJBAreaChartViewControllerChartPadding, ceil(self.view.bounds.size.height * 0.5) - ceil(kJBAreaChartViewControllerChartHeaderHeight * 0.5), self.view.bounds.size.width - (kJBAreaChartViewControllerChartPadding * 2), kJBAreaChartViewControllerChartHeaderHeight)]; - headerView.titleLabel.text = [kJBStringLabelAverageDailyRainfall uppercaseString]; + headerView.titleLabel.text = [kJBStringLabelAverageShineHours uppercaseString]; headerView.titleLabel.textColor = kJBColorLineChartHeader; headerView.titleLabel.shadowColor = [UIColor colorWithWhite:1.0 alpha:0.25]; headerView.titleLabel.shadowOffset = CGSizeMake(0, 1); - headerView.subtitleLabel.text = kJBStringLabel2013; + headerView.subtitleLabel.text = kJBStringLabel2014; headerView.subtitleLabel.textColor = kJBColorLineChartHeader; headerView.subtitleLabel.shadowColor = [UIColor colorWithWhite:1.0 alpha:0.25]; headerView.subtitleLabel.shadowOffset = CGSizeMake(0, 1); @@ -132,11 +148,11 @@ - (void)loadView JBLineChartFooterView *footerView = [[JBLineChartFooterView alloc] initWithFrame:CGRectMake(kJBAreaChartViewControllerChartPadding, ceil(self.view.bounds.size.height * 0.5) - ceil(kJBAreaChartViewControllerChartFooterHeight * 0.5), self.view.bounds.size.width - (kJBAreaChartViewControllerChartPadding * 2), kJBAreaChartViewControllerChartFooterHeight)]; footerView.backgroundColor = [UIColor clearColor]; - footerView.leftLabel.text = [[self.weekDays firstObject] uppercaseString]; + footerView.leftLabel.text = [[self.daysOfWeek firstObject] uppercaseString]; footerView.leftLabel.textColor = [UIColor whiteColor]; - footerView.rightLabel.text = [[self.weekDays lastObject] uppercaseString];; + footerView.rightLabel.text = [[self.daysOfWeek lastObject] uppercaseString];; footerView.rightLabel.textColor = [UIColor whiteColor]; - footerView.sectionCount = [[self lineData] count]; + footerView.sectionCount = [[self chartData] count]; self.lineChartView.footerView = footerView; [self.view addSubview:self.lineChartView]; @@ -161,20 +177,18 @@ - (void)viewWillAppear:(BOOL)animated - (CGFloat)lineChartView:(JBLineChartView *)lineChartView verticalValueForHorizontalIndex:(NSUInteger)horizontalIndex atLineIndex:(NSUInteger)lineIndex { - if (lineIndex == JBLineChartLineTop) { - return 1; - } - return [[self.lineData objectAtIndex:horizontalIndex] floatValue]; + return [[[self.chartData objectAtIndex:lineIndex] objectAtIndex:horizontalIndex] floatValue]; } - (void)lineChartView:(JBLineChartView *)lineChartView didSelectLineAtIndex:(NSUInteger)lineIndex horizontalIndex:(NSUInteger)horizontalIndex touchPoint:(CGPoint)touchPoint { - NSNumber *valueNumber = [[self.lineData objectAtIndex:lineIndex] objectAtIndex:horizontalIndex]; - [self.informationView setValueText:[NSString stringWithFormat:@"%.2f", [valueNumber floatValue]] unitText:kJBStringLabelMm]; - [self.informationView setTitleText:lineIndex == JBLineChartLineBottom ? kJBStringLabelMetropolitanAverage : kJBStringLabelNationalAverage]; + NSNumber *valueNumber = [[self.chartData objectAtIndex:lineIndex] objectAtIndex:horizontalIndex]; + [self.informationView setValueText:[NSString stringWithFormat:@"%.1f", [valueNumber floatValue]] unitText:kJBStringLabelHours]; + [self.informationView setTitleText:lineIndex == JBLineChartLineSun ? kJBStringLabelSun : kJBStringLabelMoon]; [self.informationView setHidden:NO animated:YES]; [self setTooltipVisible:YES animated:YES atTouchPoint:touchPoint]; - [self.tooltipView setText:[[self.weekDays objectAtIndex:horizontalIndex] uppercaseString]]; + [self.tooltipView setText:[[self.daysOfWeek objectAtIndex:horizontalIndex] uppercaseString]]; + //FIXME: hh } - (void)didUnselectLineInLineChartView:(JBLineChartView *)lineChartView @@ -187,32 +201,28 @@ - (void)didUnselectLineInLineChartView:(JBLineChartView *)lineChartView - (NSUInteger)numberOfLinesInLineChartView:(JBLineChartView *)lineChartView { - return JBLineChartLineCount; + return [self.chartData count]; } - (NSUInteger)lineChartView:(JBLineChartView *)lineChartView numberOfVerticalValuesAtLineIndex:(NSUInteger)lineIndex { - return [self.lineData count]; + return [[self.chartData objectAtIndex:lineIndex] count]; } + - (UIColor *)lineChartView:(JBLineChartView *)lineChartView colorForLineAtLineIndex:(NSUInteger)lineIndex { - return (lineIndex == JBLineChartLineBottom) ? kJBColorLineChartDefaultSolidLineColor: kJBColorLineChartDefaultDashedLineColor; + return (lineIndex == JBLineChartLineSun) ? kJBColorAreaChartDefaultSunLineColor: kJBColorAreaChartDefaultMoonLineColor; } - (UIColor *)lineChartView:(JBLineChartView *)lineChartView colorForDotAtHorizontalIndex:(NSUInteger)horizontalIndex atLineIndex:(NSUInteger)lineIndex { - return (lineIndex == JBLineChartLineBottom) ? kJBColorLineChartDefaultSolidLineColor: kJBColorLineChartDefaultDashedLineColor; + return (lineIndex == JBLineChartLineSun) ? kJBColorAreaChartDefaultSunLineColor: kJBColorAreaChartDefaultMoonLineColor; } - (CGFloat)lineChartView:(JBLineChartView *)lineChartView widthForLineAtLineIndex:(NSUInteger)lineIndex { - return (lineIndex == JBLineChartLineBottom) ? kJBAreaChartViewControllerChartSolidLineWidth: kJBAreaChartViewControllerChartDashedLineWidth; -} - -- (CGFloat)lineChartView:(JBLineChartView *)lineChartView dotRadiusForLineAtLineIndex:(NSUInteger)lineIndex -{ - return (lineIndex == JBLineChartLineBottom) ? 0.0: (kJBAreaChartViewControllerChartDashedLineWidth * 4); + return kJBAreaChartViewControllerChartLineWidth; } - (UIColor *)verticalSelectionColorForLineChartView:(JBLineChartView *)lineChartView @@ -222,27 +232,36 @@ - (UIColor *)verticalSelectionColorForLineChartView:(JBLineChartView *)lineChart - (UIColor *)lineChartView:(JBLineChartView *)lineChartView selectionColorForLineAtLineIndex:(NSUInteger)lineIndex { - return (lineIndex == JBLineChartLineBottom) ? kJBColorLineChartDefaultSolidSelectedLineColor: kJBColorLineChartDefaultDashedSelectedLineColor; + return (lineIndex == JBLineChartLineSun) ? kJBColorAreaChartDefaultSunSelectedLineColor: kJBColorAreaChartDefaultMoonSelectedLineColor; } - (UIColor *)lineChartView:(JBLineChartView *)lineChartView selectionColorForDotAtHorizontalIndex:(NSUInteger)horizontalIndex atLineIndex:(NSUInteger)lineIndex { - return (lineIndex == JBLineChartLineBottom) ? kJBColorLineChartDefaultSolidSelectedLineColor: kJBColorLineChartDefaultDashedSelectedLineColor; + return (lineIndex == JBLineChartLineSun) ? kJBColorAreaChartDefaultSunSelectedLineColor: kJBColorAreaChartDefaultMoonSelectedLineColor; +} + +- (UIColor *)lineChartView:(JBLineChartView *)lineChartView colorForAreaUnderLineAtLineIndex:(NSUInteger)lineIndex{ + return (lineIndex == JBLineChartLineSun) ? kJBColorAreaChartDefaultSunAreaColor : kJBColorAreaChartDefaultMoonAreaColor; +} + +-(UIColor *)lineChartView:(JBLineChartView *)lineChartView selectionColorForAreaUnderLineAtLineIndex:(NSUInteger)lineIndex +{ + return (lineIndex == JBLineChartLineSun) ? kJBColorAreaChartDefaultSunSelectedAreaColor : kJBColorAreaChartDefaultMoonSelectedAreaColor; } - (JBLineChartViewLineStyle)lineChartView:(JBLineChartView *)lineChartView lineStyleForLineAtLineIndex:(NSUInteger)lineIndex { - return (lineIndex == JBLineChartLineBottom) ? JBLineChartViewLineStyleSolid : JBLineChartViewLineStyleDashed; + return JBLineChartViewLineStyleSolid; } - (BOOL)lineChartView:(JBLineChartView *)lineChartView showsDotsForLineAtLineIndex:(NSUInteger)lineIndex { - return lineIndex == JBLineChartViewLineStyleDashed; + return NO; } - (BOOL)lineChartView:(JBLineChartView *)lineChartView smoothLineAtLineIndex:(NSUInteger)lineIndex { - return lineIndex == JBLineChartViewLineStyleSolid; + return YES; } #pragma mark - Buttons diff --git a/JBChartViewDemo/JBChartViewDemo/Controllers/JBChartListViewController.m b/JBChartViewDemo/JBChartViewDemo/Controllers/JBChartListViewController.m index 0b395e792..e3eaf9da8 100644 --- a/JBChartViewDemo/JBChartViewDemo/Controllers/JBChartListViewController.m +++ b/JBChartViewDemo/JBChartViewDemo/Controllers/JBChartListViewController.m @@ -66,15 +66,15 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N detailText = kJBStringLabelWorldwide2012; break; case JBChartListViewControllerRowAreaChart: - text = @"Text missing"; - detailText = @"detailText missing"; + text = kJBStringLabelAverageShineHours; + detailText = kJBStringLabelSeattle2014; break; default: break; } cell.textLabel.text = text; cell.detailTextLabel.text = detailText; - cell.type = indexPath.row == JBChartListViewControllerRowLineChart ? JBChartTableCellTypeLineChart : JBChartTableCellTypeBarChart; + cell.type = indexPath.row == JBChartListViewControllerRowBarChart ? JBChartTableCellTypeBarChart : JBChartTableCellTypeLineChart; //TODO: area chart type return cell; } From e141e92685e20b08e6597da406fe7533f3cd9655 Mon Sep 17 00:00:00 2001 From: runningOtter Date: Tue, 22 Apr 2014 15:54:42 +0200 Subject: [PATCH 03/11] added icon for area chart in the table --- .../JBChartViewDemo.xcodeproj/project.pbxproj | 8 ++++++++ .../JBChartViewDemo/Cells/JBChartTableCell.h | 1 + .../JBChartViewDemo/Cells/JBChartTableCell.m | 16 +++++++++++++++- .../JBChartViewDemo/Constants/JBUIConstants.h | 1 + .../Controllers/JBAreaChartViewController.m | 1 - .../Controllers/JBChartListViewController.m | 8 ++++++-- .../Resources/Images/icon-area-chart.png | Bin 0 -> 650 bytes .../Resources/Images/icon-area-chart@2x.png | Bin 0 -> 1089 bytes 8 files changed, 31 insertions(+), 4 deletions(-) create mode 100644 JBChartViewDemo/JBChartViewDemo/Resources/Images/icon-area-chart.png create mode 100644 JBChartViewDemo/JBChartViewDemo/Resources/Images/icon-area-chart@2x.png diff --git a/JBChartViewDemo/JBChartViewDemo.xcodeproj/project.pbxproj b/JBChartViewDemo/JBChartViewDemo.xcodeproj/project.pbxproj index f0a9eda6d..6a8a05867 100644 --- a/JBChartViewDemo/JBChartViewDemo.xcodeproj/project.pbxproj +++ b/JBChartViewDemo/JBChartViewDemo.xcodeproj/project.pbxproj @@ -8,6 +8,8 @@ /* Begin PBXBuildFile section */ 44EB67A11905B47800FABB5D /* JBAreaChartViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 44EB67A01905B47800FABB5D /* JBAreaChartViewController.m */; }; + 44EB67A71906AA9200FABB5D /* icon-area-chart.png in Resources */ = {isa = PBXBuildFile; fileRef = 44EB67A51906AA9200FABB5D /* icon-area-chart.png */; }; + 44EB67A81906AA9200FABB5D /* icon-area-chart@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 44EB67A61906AA9200FABB5D /* icon-area-chart@2x.png */; }; 9B0725211829822A0052109B /* JBChartListViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 9B0725201829822A0052109B /* JBChartListViewController.m */; }; 9B2E530518218CF20079B9D2 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9B2E530418218CF20079B9D2 /* Foundation.framework */; }; 9B2E530718218CF20079B9D2 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9B2E530618218CF20079B9D2 /* CoreGraphics.framework */; }; @@ -45,6 +47,8 @@ /* Begin PBXFileReference section */ 44EB679F1905B47800FABB5D /* JBAreaChartViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JBAreaChartViewController.h; sourceTree = ""; }; 44EB67A01905B47800FABB5D /* JBAreaChartViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JBAreaChartViewController.m; sourceTree = ""; }; + 44EB67A51906AA9200FABB5D /* icon-area-chart.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "icon-area-chart.png"; sourceTree = ""; }; + 44EB67A61906AA9200FABB5D /* icon-area-chart@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "icon-area-chart@2x.png"; sourceTree = ""; }; 9B07251F1829822A0052109B /* JBChartListViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JBChartListViewController.h; sourceTree = ""; }; 9B0725201829822A0052109B /* JBChartListViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JBChartListViewController.m; sourceTree = ""; }; 9B2E530118218CF20079B9D2 /* JBChartViewDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = JBChartViewDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -230,6 +234,8 @@ 9B698F13182D7DAE003C135F /* icon-bar-chart@2x.png */, 9B698F14182D7DAE003C135F /* icon-line-chart.png */, 9B698F15182D7DAE003C135F /* icon-line-chart@2x.png */, + 44EB67A51906AA9200FABB5D /* icon-area-chart.png */, + 44EB67A61906AA9200FABB5D /* icon-area-chart@2x.png */, 9B603D45182C7002000A76D0 /* icon-jawbone-logo.png */, 9B603D46182C7002000A76D0 /* icon-jawbone-logo@2x.png */, ); @@ -373,8 +379,10 @@ 9B698F18182D7DAE003C135F /* icon-line-chart.png in Resources */, 9B2E530F18218CF20079B9D2 /* InfoPlist.strings in Resources */, 9B698F17182D7DAE003C135F /* icon-bar-chart@2x.png in Resources */, + 44EB67A71906AA9200FABB5D /* icon-area-chart.png in Resources */, 9B603D47182C7002000A76D0 /* icon-jawbone-logo.png in Resources */, 9B603D48182C7002000A76D0 /* icon-jawbone-logo@2x.png in Resources */, + 44EB67A81906AA9200FABB5D /* icon-area-chart@2x.png in Resources */, 9B698F19182D7DAE003C135F /* icon-line-chart@2x.png in Resources */, 9B698F0A182D720E003C135F /* icon-arrow@2x.png in Resources */, ); diff --git a/JBChartViewDemo/JBChartViewDemo/Cells/JBChartTableCell.h b/JBChartViewDemo/JBChartViewDemo/Cells/JBChartTableCell.h index 788ceb67e..e2cae790c 100644 --- a/JBChartViewDemo/JBChartViewDemo/Cells/JBChartTableCell.h +++ b/JBChartViewDemo/JBChartViewDemo/Cells/JBChartTableCell.h @@ -10,6 +10,7 @@ typedef NS_ENUM(NSInteger, JBChartTableCellType){ JBChartTableCellTypeLineChart, + JBChartTableCellTypeAreaChart, JBChartTableCellTypeBarChart }; diff --git a/JBChartViewDemo/JBChartViewDemo/Cells/JBChartTableCell.m b/JBChartViewDemo/JBChartViewDemo/Cells/JBChartTableCell.m index b817e8879..19be35554 100644 --- a/JBChartViewDemo/JBChartViewDemo/Cells/JBChartTableCell.m +++ b/JBChartViewDemo/JBChartViewDemo/Cells/JBChartTableCell.m @@ -22,7 +22,21 @@ - (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reus - (void)setType:(JBChartTableCellType)type { _type = type; - self.accessoryView = [[UIImageView alloc] initWithImage:_type == JBChartTableCellTypeBarChart ? [UIImage imageNamed:kJBImageIconBarChart] : [UIImage imageNamed:kJBImageIconLineChart]]; + UIImage *image = nil; + switch (type) { + case JBChartTableCellTypeBarChart: + image = [UIImage imageNamed:kJBImageIconBarChart]; + break; + case JBChartTableCellTypeLineChart: + image = [UIImage imageNamed:kJBImageIconLineChart]; + break; + case JBChartTableCellTypeAreaChart: + image = [UIImage imageNamed:kJBImageIconAreaChart]; + break; + default: + break; + } + self.accessoryView = [[UIImageView alloc] initWithImage:image]; } @end diff --git a/JBChartViewDemo/JBChartViewDemo/Constants/JBUIConstants.h b/JBChartViewDemo/JBChartViewDemo/Constants/JBUIConstants.h index 4515d6911..c09d16fa8 100644 --- a/JBChartViewDemo/JBChartViewDemo/Constants/JBUIConstants.h +++ b/JBChartViewDemo/JBChartViewDemo/Constants/JBUIConstants.h @@ -12,3 +12,4 @@ #define kJBImageIconArrow @"icon-arrow.png" #define kJBImageIconLineChart @"icon-line-chart.png" #define kJBImageIconBarChart @"icon-bar-chart.png" +#define kJBImageIconAreaChart @"icon-area-chart.png" diff --git a/JBChartViewDemo/JBChartViewDemo/Controllers/JBAreaChartViewController.m b/JBChartViewDemo/JBChartViewDemo/Controllers/JBAreaChartViewController.m index 08a7f5c45..4b2f505f1 100644 --- a/JBChartViewDemo/JBChartViewDemo/Controllers/JBAreaChartViewController.m +++ b/JBChartViewDemo/JBChartViewDemo/Controllers/JBAreaChartViewController.m @@ -188,7 +188,6 @@ - (void)lineChartView:(JBLineChartView *)lineChartView didSelectLineAtIndex:(NSU [self.informationView setHidden:NO animated:YES]; [self setTooltipVisible:YES animated:YES atTouchPoint:touchPoint]; [self.tooltipView setText:[[self.daysOfWeek objectAtIndex:horizontalIndex] uppercaseString]]; - //FIXME: hh } - (void)didUnselectLineInLineChartView:(JBLineChartView *)lineChartView diff --git a/JBChartViewDemo/JBChartViewDemo/Controllers/JBChartListViewController.m b/JBChartViewDemo/JBChartViewDemo/Controllers/JBChartListViewController.m index e3eaf9da8..11ee5b006 100644 --- a/JBChartViewDemo/JBChartViewDemo/Controllers/JBChartListViewController.m +++ b/JBChartViewDemo/JBChartViewDemo/Controllers/JBChartListViewController.m @@ -56,26 +56,30 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N NSString *text = nil; NSString *detailText = nil; + JBChartTableCellType type = -1; switch (indexPath.row) { case JBChartListViewControllerRowLineChart: text = kJBStringLabelAverageDailyRainfall; detailText = kJBStringLabelSanFrancisco2013; + type = JBChartTableCellTypeLineChart; break; case JBChartListViewControllerRowBarChart: text = kJBStringLabelAverageMonthlyTemperature; detailText = kJBStringLabelWorldwide2012; + type = JBChartTableCellTypeBarChart; break; case JBChartListViewControllerRowAreaChart: text = kJBStringLabelAverageShineHours; detailText = kJBStringLabelSeattle2014; + type = JBChartTableCellTypeAreaChart; break; default: break; } cell.textLabel.text = text; cell.detailTextLabel.text = detailText; - cell.type = indexPath.row == JBChartListViewControllerRowBarChart ? JBChartTableCellTypeBarChart : JBChartTableCellTypeLineChart; - //TODO: area chart type + cell.type = type; + return cell; } diff --git a/JBChartViewDemo/JBChartViewDemo/Resources/Images/icon-area-chart.png b/JBChartViewDemo/JBChartViewDemo/Resources/Images/icon-area-chart.png new file mode 100644 index 0000000000000000000000000000000000000000..0f267ba19a5a6b9e1d233c9d3ef9611e9a1bd7ca GIT binary patch literal 650 zcmV;50(Jd~P)()fa0!;Mq5Rt*4#1VV<_Hwlhy{J1s)f?f_mZ%%O(yO* z&*mk>4>8hDaU93`JQ+`-3BVjU6)J%PGPNyW2iW%dcP3zovKg>Y`kTKE5^FP{m>MF* zW>W*C+JE4Y?KPNG)_8h5AymkoW0S!q06)cWRggdMOIofA$Q#&&fmF7@E)1kTL7u=G z?9wVb;1>!{WmQ97z^IDpq=OzcOS}ROfqM~SwbXTD zVO`vgn%16)c~(Komx9w5j8}coQGlN)a~%SED;DN-1e^sx2M5;T(CGtkcLnSmIPaNb z&`s9|>+~MD1w0PGmg0O#HzaD>jkh+i275wxXFGkwe8Bi&Ap6dhdw&cCti|jpt%o#d zZG-ubU21{J!==?918biBig_c2Qj*j~#DXqqD*{Zjec+APHwUg_Y8_R?99JU743Z`G zmGMWwF_%4BD}C!K3HXsR_Lw#u`H#33s=T&T^g>fZ;(>R*0Cs7MF^xDDbc-~hwr0WW zslaEVUDJ)jnzn2ZTTOBcYkIEBcCv?eMZ2%25d+}&`Ec5zi&WqnJ=f#{LLOebj+X*F z!@OR%fjby4l$bD)X{_*$a?`ltqm*xj7}tnCNDPSrc!+t6-L{~mJ@>~+kWNYx7OI^3 zz;eDM;0pL|+wT(Y8`L(f82Il1`*E3#g<|+RaG$)MKmpVR=3C<0#4yp8lLupLxoN=7 krv3K%{Vk#WT+GqxU+J~nR@h_u{r~^~07*qoM6N<$f`2$HssI20 literal 0 HcmV?d00001 diff --git a/JBChartViewDemo/JBChartViewDemo/Resources/Images/icon-area-chart@2x.png b/JBChartViewDemo/JBChartViewDemo/Resources/Images/icon-area-chart@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..174b96fe6ce28c6b9625ddab70126c5f0dcffe93 GIT binary patch literal 1089 zcmV-H1it%;P)?YJJwK)ouvn? zc=jDpJjayKf@ncxD73OBxK!357BL|QPxCEO<5 z%r(JNNM`P)pl_!H-v^#5jO$alsUx>jg0D}+@+9E6lERH|TIihMiv{sK3@~o!1+9~U ztG20+=NPx@n}`rIw-bV|dBjyGT}Wnb)h43Tg3k$V;*MZkN#Uk$T4=rC$py`~`OIX= zg0@y8hE52+JjcyEsu*_>3tH<1OC*%FqNj^cg_}+bu9FtZ+GM(r6mCMxZH?e%g&Vs7 zoDuX7nHE|lSTb|p06rXqJ9!NUplzWkDbzXIN5lyzr*^Q`$?wbI-ot zfqen59hDp}98JN`Jp26u_A18FD4K#ldGtwuor*Cuj;7$a;p?{o%^TeI@_f*e5CMIq zu{(vPV4K0{N|=5;N)@lwS{Av;HTpc-5Sv;Y{~9? zH1S&U!4&nc`@u^7(xQ^L8D{MZFqg}cFDjKBGCEam5?x6RSSF^p>!N&epCHB*X(r(}hxUBDK9r^AHtzX47o zvSQD{88>C`#*+I_%9eT!zOdoRx8ODg)IHG^Y-_t`hWKa{S~3G7)_8569G30B4g zD`SF{F~Q21U}dC&zp6yBjgf9N_LFUI|HsOhln6*Ag8RS=vR#@9o=pU-OKK5D4Q!Fq zWz7UDV}g}2!OECmWlXR#CRmxG?~;sw41m|b0ZepgB4F(gO_nR-6hOHk00000NkvXX Hu0mjfb}$9h literal 0 HcmV?d00001 From 6b7af10fc8c4cc08a05344722917029634ec00e8 Mon Sep 17 00:00:00 2001 From: runningOtter Date: Tue, 29 Apr 2014 17:27:13 +0200 Subject: [PATCH 04/11] made area filling compatible to smoothed curves --- Classes/JBLineChartView.h | 0 Classes/JBLineChartView.m | 124 +++++++++++++++++++++++++++++--------- 2 files changed, 96 insertions(+), 28 deletions(-) mode change 100755 => 100644 Classes/JBLineChartView.h mode change 100755 => 100644 Classes/JBLineChartView.m diff --git a/Classes/JBLineChartView.h b/Classes/JBLineChartView.h old mode 100755 new mode 100644 diff --git a/Classes/JBLineChartView.m b/Classes/JBLineChartView.m old mode 100755 new mode 100644 index 9c8eb993f..9da34f8c3 --- a/Classes/JBLineChartView.m +++ b/Classes/JBLineChartView.m @@ -170,6 +170,7 @@ - (NSArray *)chartDataForLineChartAreasView:(JBLineChartAreasView*)lineChartArea - (UIColor *)lineChartAreasView:(JBLineChartAreasView *)lineChartAreasView colorForAreaUnderLineAtLineIndex:(NSUInteger)lineIndex; - (UIColor *)lineChartAreasView:(JBLineChartAreasView *)lineChartAreasView selectedColorForAreaUnderLineAtLineIndex:(NSUInteger)lineIndex; - (CGFloat)paddingForLineChartAreasView:(JBLineChartAreasView *)lineChartAreasView; +- (BOOL)lineChartAreasView:(JBLineChartAreasView *)lineChartAreasView smoothLineAtLineIndex:(NSUInteger)lineIndex; @end @@ -739,6 +740,16 @@ - (CGFloat)paddingForLineChartAreasView:(JBLineChartAreasView *)lineChartAreasVi return [self padding]; } +- (BOOL)lineChartAreasView:(JBLineChartAreasView *)lineChartAreasView smoothLineAtLineIndex:(NSUInteger)lineIndex; +{ + { + if ([self.dataSource respondsToSelector:@selector(lineChartView:smoothLineAtLineIndex:)]) + { + return [self.dataSource lineChartView:self smoothLineAtLineIndex:lineIndex]; + } + return NO; + } +} #pragma mark - Setters @@ -856,6 +867,7 @@ - (CGFloat)cachedMaxHeight { maxHeight = height; } + } } } else { @@ -1265,7 +1277,6 @@ - (void)drawRect:(CGRect)rect previousLineChartPoint = lineChartPoint; index++; } - JBLineLayer *shapeLayer = [self lineLayerForLineIndex:lineIndex]; if (shapeLayer == nil) @@ -1276,13 +1287,11 @@ - (void)drawRect:(CGRect)rect shapeLayer.tag = lineIndex; NSAssert([self.delegate respondsToSelector:@selector(lineChartLinesView:lineStyleForLineAtLineIndex:)], @"JBLineChartLinesView // delegate must implement - (JBLineChartViewLineStyle)lineChartLineView:(JBLineChartLinesView *)lineChartLinesView lineStyleForLineAtLineIndex:(NSUInteger)lineIndex"); shapeLayer.lineStyle = [self.delegate lineChartLinesView:self lineStyleForLineAtLineIndex:lineIndex]; - + NSAssert([self.delegate respondsToSelector:@selector(lineChartLinesView:colorForLineAtLineIndex:)], @"JBLineChartLinesView // delegate must implement - (UIColor *)lineChartLinesView:(JBLineChartLinesView *)lineChartLinesView colorForLineAtLineIndex:(NSUInteger)lineIndex"); shapeLayer.strokeColor = [self.delegate lineChartLinesView:self colorForLineAtLineIndex:lineIndex].CGColor; - - NSAssert([self.delegate respondsToSelector:@selector(lineChartLinesView:smoothLineAtLineIndex:)], @"JBLineChartLinesView // delegate must implement - (UIColor *)lineChartLinesView:(JBLineChartLinesView *)lineChartLinesView colorForLineAtLineIndex:(NSUInteger)lineIndex"); - BOOL smoothLine = [self.delegate lineChartLinesView:self smoothLineAtLineIndex:lineIndex]; - if (smoothLine) + + if (smoothLine == YES) { shapeLayer.lineCap = kCALineCapRound; shapeLayer.lineJoin = kCALineJoinRound; @@ -1295,13 +1304,11 @@ - (void)drawRect:(CGRect)rect NSAssert([self.delegate respondsToSelector:@selector(lineChartLinesView:widthForLineAtLineIndex:)], @"JBLineChartLinesView // delegate must implement - (CGFloat)lineChartLinesView:(JBLineChartLinesView *)lineChartLinesView widthForLineAtLineIndex:(NSUInteger)lineIndex"); shapeLayer.lineWidth = [self.delegate lineChartLinesView:self widthForLineAtLineIndex:lineIndex]; - shapeLayer.path = path.CGPath; shapeLayer.frame = self.bounds; [self.layer addSublayer:shapeLayer]; lineIndex++; - } self.animated = NO; @@ -1386,21 +1393,6 @@ - (JBLineLayer *)lineLayerForLineIndex:(NSUInteger)lineIndex return nil; } -- (JBLineLayer *)fillLayerForAreaIndex:(NSUInteger)areaIndex -{ - for (CALayer *layer in [self.layer sublayers]) - { - if ([layer isKindOfClass:[JBLineLayer class]]) - { - if (((JBLineLayer *)layer).tag == areaIndex) - { - return (JBLineLayer *)layer; - } - } - } - return nil; -} - @end @implementation JBLineChartDotsView @@ -1601,6 +1593,17 @@ - (void)drawRect:(CGRect)rect UIBezierPath *path = [UIBezierPath bezierPath]; path.miterLimit = kJBLineChartLinesViewMiterLimit; + JBLineChartPoint *previousLineChartPoint = nil; + CGFloat previousSlope; + + NSAssert([self.delegate respondsToSelector:@selector(lineChartAreasView:smoothLineAtLineIndex:)], @"JBLineChartAreasView // delegate must implement - (BOOL)lineChartAreasView:(JBLineChartAreasView *)lineChartAreasView smoothLineAtLineIndex:(NSUInteger)lineIndex"); + BOOL smoothLine = [self.delegate lineChartAreasView:self smoothLineAtLineIndex:lineIndex]; + + CGFloat nextSlope = 0; + CGFloat currentSlope = 0; + NSUInteger index = 0; + NSArray *sortedLineData = [lineData sortedArrayUsingSelector:@selector(compare:)]; + if (!previousLineData) { JBLineChartPoint *lowerRightCornor = [[JBLineChartPoint alloc] init]; lowerRightCornor.position = CGPointMake(self.bounds.size.width - padding, self.bounds.size.height - padding); @@ -1610,7 +1613,6 @@ - (void)drawRect:(CGRect)rect } //add the previous line in inversed order at the beginning of the path to create a polygon - NSUInteger index = 0; for (JBLineChartPoint *lineChartPoint in [[previousLineData reverseObjectEnumerator] allObjects]) { if (index == 0) @@ -1619,15 +1621,81 @@ - (void)drawRect:(CGRect)rect } else { - [path addLineToPoint:CGPointMake(lineChartPoint.position.x, fmin(self.bounds.size.height - padding, fmax(padding, lineChartPoint.position.y)))]; + if (smoothLine == YES) + { + JBLineChartPoint *nextLineChartPoint = nil; + if (index != ([lineData count] - 1)) + { + nextLineChartPoint = [sortedLineData objectAtIndex:(index + 1)]; + } + + nextSlope = (nextLineChartPoint != nil) ? ((nextLineChartPoint.position.y - lineChartPoint.position.y)) / ((nextLineChartPoint.position.x - lineChartPoint.position.x)) : previousSlope; + currentSlope = ((lineChartPoint.position.y - previousLineChartPoint.position.y)) / (lineChartPoint.position.x-previousLineChartPoint.position.x); + } + + if (smoothLine && ((currentSlope >= (nextSlope + kJBLineChartLinesViewSlopeThreshold)) || (currentSlope <= (nextSlope - kJBLineChartLinesViewSlopeThreshold)))) + { + CGFloat deltaX = lineChartPoint.position.x - previousLineChartPoint.position.x; + CGFloat controlPointX = previousLineChartPoint.position.x + (deltaX / 2); + + CGPoint controlPoint1 = CGPointMake(controlPointX, previousLineChartPoint.position.y); + CGPoint controlPoint2 = CGPointMake(controlPointX, lineChartPoint.position.y); + + [path addCurveToPoint:CGPointMake(lineChartPoint.position.x, fmin(self.bounds.size.height - padding, fmax(padding, lineChartPoint.position.y))) controlPoint1:controlPoint1 controlPoint2:controlPoint2]; + } + else + { + [path addLineToPoint:CGPointMake(lineChartPoint.position.x, fmin(self.bounds.size.height - padding, fmax(padding, lineChartPoint.position.y)))]; + } + + previousSlope = currentSlope; } - index ++; + previousLineChartPoint = lineChartPoint; + index++; } + index = 0; for (JBLineChartPoint *lineChartPoint in [lineData sortedArrayUsingSelector:@selector(compare:)]) { - [path addLineToPoint:CGPointMake(lineChartPoint.position.x, fmin(self.bounds.size.height - padding, fmax(padding, lineChartPoint.position.y)))]; + if (index == 0) + { + [path addLineToPoint:CGPointMake(lineChartPoint.position.x, fmin(self.bounds.size.height - padding, fmax(padding, lineChartPoint.position.y)))]; + } + else + { + if (smoothLine == YES) + { + JBLineChartPoint *nextLineChartPoint = nil; + if (index != ([lineData count] - 1)) + { + nextLineChartPoint = [sortedLineData objectAtIndex:(index + 1)]; + } + + nextSlope = (nextLineChartPoint != nil) ? ((nextLineChartPoint.position.y - lineChartPoint.position.y)) / ((nextLineChartPoint.position.x - lineChartPoint.position.x)) : previousSlope; + currentSlope = ((lineChartPoint.position.y - previousLineChartPoint.position.y)) / (lineChartPoint.position.x-previousLineChartPoint.position.x); + } + + if (smoothLine && ((currentSlope >= (nextSlope + kJBLineChartLinesViewSlopeThreshold)) || (currentSlope <= (nextSlope - kJBLineChartLinesViewSlopeThreshold)))) + { + CGFloat deltaX = lineChartPoint.position.x - previousLineChartPoint.position.x; + CGFloat controlPointX = previousLineChartPoint.position.x + (deltaX / 2); + + CGPoint controlPoint1 = CGPointMake(controlPointX, previousLineChartPoint.position.y); + CGPoint controlPoint2 = CGPointMake(controlPointX, lineChartPoint.position.y); + + [path addCurveToPoint:CGPointMake(lineChartPoint.position.x, fmin(self.bounds.size.height - padding, fmax(padding, lineChartPoint.position.y))) controlPoint1:controlPoint1 controlPoint2:controlPoint2]; + } + else + { + [path addLineToPoint:CGPointMake(lineChartPoint.position.x, fmin(self.bounds.size.height - padding, fmax(padding, lineChartPoint.position.y)))]; + } + + previousSlope = currentSlope; + } + previousLineChartPoint = lineChartPoint; + index++; + } [path closePath]; @@ -1738,4 +1806,4 @@ - (JBAreaLayer *)areaLayerForLineIndex:(NSUInteger)areaIndex return nil; } -@end +@end \ No newline at end of file From 311be6bf654af85feb330003bfed7ae2aeac7541 Mon Sep 17 00:00:00 2001 From: hackingotter Date: Tue, 29 Apr 2014 18:57:18 +0200 Subject: [PATCH 05/11] fixed bug with mixture of smooth and linear lines --- Classes/JBLineChartView.m | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Classes/JBLineChartView.m b/Classes/JBLineChartView.m index 9da34f8c3..c423fd92a 100644 --- a/Classes/JBLineChartView.m +++ b/Classes/JBLineChartView.m @@ -1598,6 +1598,10 @@ - (void)drawRect:(CGRect)rect NSAssert([self.delegate respondsToSelector:@selector(lineChartAreasView:smoothLineAtLineIndex:)], @"JBLineChartAreasView // delegate must implement - (BOOL)lineChartAreasView:(JBLineChartAreasView *)lineChartAreasView smoothLineAtLineIndex:(NSUInteger)lineIndex"); BOOL smoothLine = [self.delegate lineChartAreasView:self smoothLineAtLineIndex:lineIndex]; + BOOL previousSmoothLine = NO; + if (lineIndex > 0) { + previousSmoothLine = [self.delegate lineChartAreasView:self smoothLineAtLineIndex:lineIndex - 1]; + } CGFloat nextSlope = 0; CGFloat currentSlope = 0; @@ -1621,7 +1625,7 @@ - (void)drawRect:(CGRect)rect } else { - if (smoothLine == YES) + if (previousSmoothLine == YES) { JBLineChartPoint *nextLineChartPoint = nil; if (index != ([lineData count] - 1)) From cd3d28a6a3b22cff433840139547856f90048ecc Mon Sep 17 00:00:00 2001 From: hackingotter Date: Tue, 29 Apr 2014 19:26:04 +0200 Subject: [PATCH 06/11] solve wobble issue with bottom line --- Classes/JBLineChartView.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Classes/JBLineChartView.m b/Classes/JBLineChartView.m index c423fd92a..11f12c359 100644 --- a/Classes/JBLineChartView.m +++ b/Classes/JBLineChartView.m @@ -1630,7 +1630,7 @@ - (void)drawRect:(CGRect)rect JBLineChartPoint *nextLineChartPoint = nil; if (index != ([lineData count] - 1)) { - nextLineChartPoint = [sortedLineData objectAtIndex:(index + 1)]; + nextLineChartPoint = [[[previousLineData reverseObjectEnumerator] allObjects] objectAtIndex:(index + 1)]; } nextSlope = (nextLineChartPoint != nil) ? ((nextLineChartPoint.position.y - lineChartPoint.position.y)) / ((nextLineChartPoint.position.x - lineChartPoint.position.x)) : previousSlope; From f5262292ea1e42873daba62ec16ef5ca89e2780d Mon Sep 17 00:00:00 2001 From: hackingotter Date: Thu, 1 May 2014 17:54:17 +0200 Subject: [PATCH 07/11] integrated changes of version 2.4.1 into area filling --- Classes/JBLineChartView.m | 52 +++++++++++++++++++-------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/Classes/JBLineChartView.m b/Classes/JBLineChartView.m index 7a6d0483f..ac800f3bf 100644 --- a/Classes/JBLineChartView.m +++ b/Classes/JBLineChartView.m @@ -1603,11 +1603,6 @@ - (void)drawRect:(CGRect)rect previousSmoothLine = [self.delegate lineChartAreasView:self smoothLineAtLineIndex:lineIndex - 1]; } - CGFloat nextSlope = 0; - CGFloat currentSlope = 0; - NSUInteger index = 0; - NSArray *sortedLineData = [lineData sortedArrayUsingSelector:@selector(compare:)]; - if (!previousLineData) { JBLineChartPoint *lowerRightCornor = [[JBLineChartPoint alloc] init]; lowerRightCornor.position = CGPointMake(self.bounds.size.width - padding, self.bounds.size.height - padding); @@ -1617,7 +1612,9 @@ - (void)drawRect:(CGRect)rect } //add the previous line in inversed order at the beginning of the path to create a polygon - for (JBLineChartPoint *lineChartPoint in [[previousLineData reverseObjectEnumerator] allObjects]) + NSUInteger index = 0; + NSArray *sortedPreviousLineData = [[previousLineData reverseObjectEnumerator] allObjects]; + for (JBLineChartPoint *lineChartPoint in sortedPreviousLineData) { if (index == 0) { @@ -1625,19 +1622,20 @@ - (void)drawRect:(CGRect)rect } else { - if (previousSmoothLine == YES) + JBLineChartPoint *nextLineChartPoint = nil; + if (index != ([lineData count] - 1)) { - JBLineChartPoint *nextLineChartPoint = nil; - if (index != ([lineData count] - 1)) - { - nextLineChartPoint = [[[previousLineData reverseObjectEnumerator] allObjects] objectAtIndex:(index + 1)]; - } - - nextSlope = (nextLineChartPoint != nil) ? ((nextLineChartPoint.position.y - lineChartPoint.position.y)) / ((nextLineChartPoint.position.x - lineChartPoint.position.x)) : previousSlope; - currentSlope = ((lineChartPoint.position.y - previousLineChartPoint.position.y)) / (lineChartPoint.position.x-previousLineChartPoint.position.x); + nextLineChartPoint = [sortedPreviousLineData objectAtIndex:(index + 1)]; } - if (smoothLine && ((currentSlope >= (nextSlope + kJBLineChartLinesViewSlopeThreshold)) || (currentSlope <= (nextSlope - kJBLineChartLinesViewSlopeThreshold)))) + CGFloat nextSlope = (nextLineChartPoint != nil) ? ((nextLineChartPoint.position.y - lineChartPoint.position.y)) / ((nextLineChartPoint.position.x - lineChartPoint.position.x)) : previousSlope; + CGFloat currentSlope = ((lineChartPoint.position.y - previousLineChartPoint.position.y)) / (lineChartPoint.position.x-previousLineChartPoint.position.x); + + BOOL deltaFromNextSlope = ((currentSlope >= (nextSlope + kJBLineChartLinesViewSmoothThresholdSlope)) || (currentSlope <= (nextSlope - kJBLineChartLinesViewSmoothThresholdSlope))); + BOOL deltaFromPreviousSlope = ((currentSlope >= (previousSlope + kJBLineChartLinesViewSmoothThresholdSlope)) || (currentSlope <= (previousSlope - kJBLineChartLinesViewSmoothThresholdSlope))); + BOOL deltaFromPreviousY = (lineChartPoint.position.y >= previousLineChartPoint.position.y + kJBLineChartLinesViewSmoothThresholdVertical) || (lineChartPoint.position.y <= previousLineChartPoint.position.y - kJBLineChartLinesViewSmoothThresholdVertical); + + if (previousSmoothLine && deltaFromNextSlope && deltaFromPreviousSlope && deltaFromPreviousY) { CGFloat deltaX = lineChartPoint.position.x - previousLineChartPoint.position.x; CGFloat controlPointX = previousLineChartPoint.position.x + (deltaX / 2); @@ -1659,6 +1657,7 @@ - (void)drawRect:(CGRect)rect } index = 0; + NSArray *sortedLineData = [lineData sortedArrayUsingSelector:@selector(compare:)]; for (JBLineChartPoint *lineChartPoint in [lineData sortedArrayUsingSelector:@selector(compare:)]) { @@ -1668,19 +1667,20 @@ - (void)drawRect:(CGRect)rect } else { - if (smoothLine == YES) + JBLineChartPoint *nextLineChartPoint = nil; + if (index != ([lineData count] - 1)) { - JBLineChartPoint *nextLineChartPoint = nil; - if (index != ([lineData count] - 1)) - { - nextLineChartPoint = [sortedLineData objectAtIndex:(index + 1)]; - } - - nextSlope = (nextLineChartPoint != nil) ? ((nextLineChartPoint.position.y - lineChartPoint.position.y)) / ((nextLineChartPoint.position.x - lineChartPoint.position.x)) : previousSlope; - currentSlope = ((lineChartPoint.position.y - previousLineChartPoint.position.y)) / (lineChartPoint.position.x-previousLineChartPoint.position.x); + nextLineChartPoint = [sortedLineData objectAtIndex:(index + 1)]; } - if (smoothLine && ((currentSlope >= (nextSlope + kJBLineChartLinesViewSlopeThreshold)) || (currentSlope <= (nextSlope - kJBLineChartLinesViewSlopeThreshold)))) + CGFloat nextSlope = (nextLineChartPoint != nil) ? ((nextLineChartPoint.position.y - lineChartPoint.position.y)) / ((nextLineChartPoint.position.x - lineChartPoint.position.x)) : previousSlope; + CGFloat currentSlope = ((lineChartPoint.position.y - previousLineChartPoint.position.y)) / (lineChartPoint.position.x-previousLineChartPoint.position.x); + + BOOL deltaFromNextSlope = ((currentSlope >= (nextSlope + kJBLineChartLinesViewSmoothThresholdSlope)) || (currentSlope <= (nextSlope - kJBLineChartLinesViewSmoothThresholdSlope))); + BOOL deltaFromPreviousSlope = ((currentSlope >= (previousSlope + kJBLineChartLinesViewSmoothThresholdSlope)) || (currentSlope <= (previousSlope - kJBLineChartLinesViewSmoothThresholdSlope))); + BOOL deltaFromPreviousY = (lineChartPoint.position.y >= previousLineChartPoint.position.y + kJBLineChartLinesViewSmoothThresholdVertical) || (lineChartPoint.position.y <= previousLineChartPoint.position.y - kJBLineChartLinesViewSmoothThresholdVertical); + + if (smoothLine && deltaFromNextSlope && deltaFromPreviousSlope && deltaFromPreviousY) { CGFloat deltaX = lineChartPoint.position.x - previousLineChartPoint.position.x; CGFloat controlPointX = previousLineChartPoint.position.x + (deltaX / 2); From 59540828e2dc39e451c92aabb278a8c89be16591 Mon Sep 17 00:00:00 2001 From: hackingotter Date: Thu, 1 May 2014 20:06:23 +0200 Subject: [PATCH 08/11] set delegate and dataSource as IBOutlets to link them in interface builder --- Classes/JBBarChartView.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Classes/JBBarChartView.h b/Classes/JBBarChartView.h index b8620ef99..37a25a142 100644 --- a/Classes/JBBarChartView.h +++ b/Classes/JBBarChartView.h @@ -14,8 +14,8 @@ @interface JBBarChartView : JBChartView -@property (nonatomic, weak) id delegate; -@property (nonatomic, weak) id dataSource; +@property (nonatomic, weak) IBOutlet id delegate; +@property (nonatomic, weak) IBOutlet id dataSource; /** * Vertical highlight overlayed on bar during touch events. From 07880a58e0236ca9b7e2ce3a692ee7f4e2c23674 Mon Sep 17 00:00:00 2001 From: hackingotter Date: Thu, 1 May 2014 22:04:02 +0200 Subject: [PATCH 09/11] fixed some bugs --- Classes/JBLineChartView.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Classes/JBLineChartView.m b/Classes/JBLineChartView.m index ac800f3bf..9e9dd3434 100644 --- a/Classes/JBLineChartView.m +++ b/Classes/JBLineChartView.m @@ -1623,7 +1623,7 @@ - (void)drawRect:(CGRect)rect else { JBLineChartPoint *nextLineChartPoint = nil; - if (index != ([lineData count] - 1)) + if (index != ([sortedPreviousLineData count] - 1)) { nextLineChartPoint = [sortedPreviousLineData objectAtIndex:(index + 1)]; } @@ -1632,7 +1632,7 @@ - (void)drawRect:(CGRect)rect CGFloat currentSlope = ((lineChartPoint.position.y - previousLineChartPoint.position.y)) / (lineChartPoint.position.x-previousLineChartPoint.position.x); BOOL deltaFromNextSlope = ((currentSlope >= (nextSlope + kJBLineChartLinesViewSmoothThresholdSlope)) || (currentSlope <= (nextSlope - kJBLineChartLinesViewSmoothThresholdSlope))); - BOOL deltaFromPreviousSlope = ((currentSlope >= (previousSlope + kJBLineChartLinesViewSmoothThresholdSlope)) || (currentSlope <= (previousSlope - kJBLineChartLinesViewSmoothThresholdSlope))); + BOOL deltaFromPreviousSlope = ((currentSlope <= (previousSlope + kJBLineChartLinesViewSmoothThresholdSlope)) || (currentSlope >= (previousSlope - kJBLineChartLinesViewSmoothThresholdSlope))); BOOL deltaFromPreviousY = (lineChartPoint.position.y >= previousLineChartPoint.position.y + kJBLineChartLinesViewSmoothThresholdVertical) || (lineChartPoint.position.y <= previousLineChartPoint.position.y - kJBLineChartLinesViewSmoothThresholdVertical); if (previousSmoothLine && deltaFromNextSlope && deltaFromPreviousSlope && deltaFromPreviousY) From 287d9b410da594822e22cf4298f9841a281d4d17 Mon Sep 17 00:00:00 2001 From: hackingotter Date: Mon, 5 May 2014 13:36:19 +0200 Subject: [PATCH 10/11] code cleanup --- Classes/JBLineChartView.h | 34 - Classes/JBLineChartView.m | 729 ++++++++---------- .../JBChartViewDemo.xcodeproj/project.pbxproj | 14 - .../JBChartViewDemo/Cells/JBChartTableCell.m | 16 +- .../Constants/JBColorConstants.h | 15 - .../Constants/JBStringConstants.h | 11 +- .../JBChartViewDemo/Constants/JBUIConstants.h | 1 - .../Controllers/JBAreaChartViewController.h | 13 - .../Controllers/JBAreaChartViewController.m | 288 ------- .../Controllers/JBChartListViewController.m | 39 +- .../Controllers/JBLineChartViewController.m | 8 +- .../Resources/Images/icon-area-chart.png | Bin 650 -> 0 bytes .../Resources/Images/icon-area-chart@2x.png | Bin 1089 -> 0 bytes 13 files changed, 317 insertions(+), 851 deletions(-) delete mode 100644 JBChartViewDemo/JBChartViewDemo/Controllers/JBAreaChartViewController.h delete mode 100644 JBChartViewDemo/JBChartViewDemo/Controllers/JBAreaChartViewController.m delete mode 100644 JBChartViewDemo/JBChartViewDemo/Resources/Images/icon-area-chart.png delete mode 100644 JBChartViewDemo/JBChartViewDemo/Resources/Images/icon-area-chart@2x.png diff --git a/Classes/JBLineChartView.h b/Classes/JBLineChartView.h index 58e7eb711..9aed87603 100644 --- a/Classes/JBLineChartView.h +++ b/Classes/JBLineChartView.h @@ -55,15 +55,6 @@ typedef NS_ENUM(NSInteger, JBLineChartViewLineStyle){ */ @property (nonatomic, assign) BOOL showsAreaSelection; -/** - * Fills the area under the lines till the next lane below or the bottom. - * For best results the lines should not intersect each other. One way to achive this is - * makeing the diagramm cumulative by setting the BOOL isCumulative to YES - * - * Default: NO. - */ -@property (nonatomic, assign) BOOL fillsAreaBelowLine; - /** * If YES the chart adds the value of the next line to the previous. The distance of a line to the one below * represents the upper lines real value. For best results you should also set the BOOL fillsAreaBelowLine to YES @@ -153,18 +144,6 @@ typedef NS_ENUM(NSInteger, JBLineChartViewLineStyle){ */ - (UIColor *)lineChartView:(JBLineChartView *)lineChartView colorForLineAtLineIndex:(NSUInteger)lineIndex; -/** - * Returns the color of particular area under the line at lineIndex within the chart. - * - * Default: black color. - * - * @param lineChartView The line chart object requesting this information. - * @param lineIndex An index number identifying a line in the chart. - * - * @return The color to be used to shade a line in the chart. - */ -- (UIColor *)lineChartView:(JBLineChartView *)lineChartView colorForAreaUnderLineAtLineIndex:(NSUInteger)lineIndex; - /** * Returns the color of a particular dot in a line at lineIndex within the chart. * For this value to apply, showsDotsForLineAtLineIndex: must return YES for the line at lineIndex. @@ -245,19 +224,6 @@ typedef NS_ENUM(NSInteger, JBLineChartViewLineStyle){ */ - (UIColor *)lineChartView:(JBLineChartView *)lineChartView selectionColorForLineAtLineIndex:(NSUInteger)lineIndex; -/** - * Returns the selection color to be overlayed on a area under a line within the chart during touch events. - * The property showsAreaSelection must be YES for the color to apply. - * - * Default: white color. - * - * @param lineChartView The line chart object requesting this information. - * @param lineIndex An index number identifying a line in the chart. - * - * @return The color to be used to highlight a line during chart selections. - */ -- (UIColor *)lineChartView:(JBLineChartView *)lineChartView selectionColorForAreaUnderLineAtLineIndex:(NSUInteger)lineIndex; - /** * Returns the selection color to be overlayed on a line within the chart during touch events. * The property showsLineSelection must be YES for the color to apply. diff --git a/Classes/JBLineChartView.m b/Classes/JBLineChartView.m index 9e9dd3434..3119d6407 100644 --- a/Classes/JBLineChartView.m +++ b/Classes/JBLineChartView.m @@ -46,10 +46,8 @@ typedef NS_ENUM(NSUInteger, JBLineChartHorizontalIndexClamp){ // Colors (JBLineChartView) static UIColor *kJBLineChartViewDefaultLineColor = nil; -static UIColor *kJBLineChartViewDefaultAreaColor = nil; static UIColor *kJBLineChartViewDefaultDotColor = nil; static UIColor *kJBLineChartViewDefaultLineSelectionColor = nil; -static UIColor *kJBLineChartViewDefaultAreaSelectionColor = nil; static UIColor *kJBLineChartViewDefaultDotSelectionColor = nil; @interface JBLineLayer : CAShapeLayer @@ -59,9 +57,7 @@ @interface JBLineLayer : CAShapeLayer @end -@interface JBAreaLayer : CAShapeLayer - -@property (nonatomic, assign) NSUInteger tag; +@interface JBAreaLayer : JBLineLayer @end @@ -90,6 +86,7 @@ - (void)fireCallback:(void (^)())callback; // View helpers - (JBLineLayer *)lineLayerForLineIndex:(NSUInteger)lineIndex; +- (JBAreaLayer *)areaLayerForLineIndex:(NSUInteger)lineIndex; @end @@ -102,6 +99,7 @@ - (CGFloat)lineChartLinesView:(JBLineChartLinesView *)lineChartLinesView widthFo - (CGFloat)paddingForLineChartLinesView:(JBLineChartLinesView *)lineChartLinesView; - (JBLineChartViewLineStyle)lineChartLinesView:(JBLineChartLinesView *)lineChartLinesView lineStyleForLineAtLineIndex:(NSUInteger)lineIndex; - (BOOL)lineChartLinesView:(JBLineChartLinesView *)lineChartLinesView smoothLineAtLineIndex:(NSUInteger)lineIndex; +- (BOOL)lineChartLinesView:(JBLineChartLinesView *)lineChartLinesView fillsAreaUnderLineWithIndex:(NSUInteger)lineIndex; @end @@ -141,46 +139,12 @@ - (id)initWithRadius:(CGFloat)radius; @end -@protocol JBLineChartAreasViewDelegate; - -@interface JBLineChartAreasView : UIView - -@property (nonatomic, assign) id delegate; -@property (nonatomic, assign) NSInteger selectedLineIndex; // -1 to unselect -@property (nonatomic, assign) BOOL animated; - -// Data -- (void)reloadData; - -// Setters -- (void)setSelectedLineIndex:(NSInteger)selectedLineIndex animated:(BOOL)animated; - -// Callback helpers -- (void)fireCallback:(void (^)())callback; - -// View helpers -- (JBAreaLayer *)areaLayerForLineIndex:(NSUInteger)lineIndex; - - -@end - - -@protocol JBLineChartAreasViewDelegate - -- (NSArray *)chartDataForLineChartAreasView:(JBLineChartAreasView*)lineChartAreasView; -- (UIColor *)lineChartAreasView:(JBLineChartAreasView *)lineChartAreasView colorForAreaUnderLineAtLineIndex:(NSUInteger)lineIndex; -- (UIColor *)lineChartAreasView:(JBLineChartAreasView *)lineChartAreasView selectedColorForAreaUnderLineAtLineIndex:(NSUInteger)lineIndex; -- (CGFloat)paddingForLineChartAreasView:(JBLineChartAreasView *)lineChartAreasView; -- (BOOL)lineChartAreasView:(JBLineChartAreasView *)lineChartAreasView smoothLineAtLineIndex:(NSUInteger)lineIndex; - -@end -@interface JBLineChartView () +@interface JBLineChartView () @property (nonatomic, strong) NSArray *chartData; @property (nonatomic, strong) JBLineChartLinesView *linesView; @property (nonatomic, strong) JBLineChartDotsView *dotsView; -@property (nonatomic, strong) JBLineChartAreasView *areasView; @property (nonatomic, strong) JBChartVerticalSelectionView *verticalSelectionView; @property (nonatomic, assign) CGFloat cachedMaxHeight; @property (nonatomic, assign) CGFloat cachedMinHeight; @@ -220,10 +184,8 @@ + (void)initialize if (self == [JBLineChartView class]) { kJBLineChartViewDefaultLineColor = [UIColor blackColor]; - kJBLineChartViewDefaultAreaColor = [[UIColor blackColor] colorWithAlphaComponent:0.5]; kJBLineChartViewDefaultDotColor = [UIColor blackColor]; kJBLineChartViewDefaultLineSelectionColor = [UIColor whiteColor]; - kJBLineChartViewDefaultAreaSelectionColor = [[UIColor whiteColor] colorWithAlphaComponent:0.5]; kJBLineChartViewDefaultDotSelectionColor = [UIColor whiteColor]; } } @@ -263,7 +225,6 @@ - (void)construct _showsVerticalSelection = YES; _showsLineSelection = YES; _showsAreaSelection = NO; - _fillsAreaBelowLine = NO; _isCumulative = NO; _cachedMinHeight = kJBBarChartViewUndefinedCachedHeight; _cachedMaxHeight = kJBBarChartViewUndefinedCachedHeight; @@ -389,37 +350,6 @@ - (void)reloadData } }; - /* - * Creates a new areas view using the previously calculated data model - */ - dispatch_block_t createAreaView = ^{ - - // Remove old areas view - if (self.areasView) - { - [self.areasView removeFromSuperview]; - self.areasView = nil; - } - - - // Create new areas and overlay subviews - self.areasView = [[JBLineChartAreasView alloc] initWithFrame:CGRectOffset(mainViewRect, 0, self.headerView.frame.size.height + self.headerPadding)]; - self.areasView.delegate = self; - //hide when not needed - self.areasView.hidden = !self.fillsAreaBelowLine; - - - // Add new areas view - if (self.footerView) - { - [self insertSubview:self.areasView belowSubview:self.footerView]; - } - else - { - [self addSubview:self.areasView]; - } - }; - /* * Creates a vertical selection view for touch events @@ -456,7 +386,6 @@ - (void)reloadData }; createChartData(); - createAreaView(); createLineGraphView(); createDotGraphView(); createSelectionView(); @@ -699,58 +628,14 @@ - (BOOL)lineChartDotsView:(JBLineChartDotsView *)lineChartDotsView showsDotsForL return NO; } -#pragma mark - JBLineChartAreasViewDelegate - -- (NSArray *)chartDataForLineChartAreasView:(JBLineChartAreasView*)lineChartAreasView +- (BOOL)lineChartLinesView:(JBLineChartLinesView *)lineChartLinesView fillsAreaUnderLineWithIndex:(NSUInteger)lineIndex { - return self.chartData; -} - -- (UIColor *)lineChartAreasView:(JBLineChartAreasView *)lineChartAreasView colorForAreaUnderLineAtLineIndex:(NSUInteger)lineIndex -{ - if ([self.dataSource respondsToSelector:@selector(lineChartView:colorForAreaUnderLineAtLineIndex:)]) - { - return [self.dataSource lineChartView:self colorForAreaUnderLineAtLineIndex:lineIndex]; + if ([self.dataSource respondsToSelector:@selector(lineChartView:fillsAreaUnderLineWithIndex:)]) { + return [self.dataSource lineChartView:self fillsAreaUnderLineWithIndex:lineIndex]; } - - if ([self.dataSource respondsToSelector:@selector(lineChartView:colorForLineAtLineIndex:)]) - { - return [[self.dataSource lineChartView:self colorForLineAtLineIndex:lineIndex] colorWithAlphaComponent:0.5]; - } - - return kJBLineChartViewDefaultAreaColor; -} - -- (UIColor *)lineChartAreasView:(JBLineChartAreasView *)lineChartAreasView selectedColorForAreaUnderLineAtLineIndex:(NSUInteger)lineIndex -{ - if ([self.dataSource respondsToSelector:@selector(lineChartView:selectionColorForAreaUnderLineAtLineIndex:)]) - { - return [self.dataSource lineChartView:self selectionColorForAreaUnderLineAtLineIndex:lineIndex]; - } - - if ([self.dataSource respondsToSelector:@selector(lineChartView:selectionColorForLineAtLineIndex:)]) - { - return [[self.dataSource lineChartView:self selectionColorForLineAtLineIndex:lineIndex] colorWithAlphaComponent:0.5]; - } - - return kJBLineChartViewDefaultAreaSelectionColor; -} - -- (CGFloat)paddingForLineChartAreasView:(JBLineChartAreasView *)lineChartAreasView -{ - return [self padding]; + return NO; } -- (BOOL)lineChartAreasView:(JBLineChartAreasView *)lineChartAreasView smoothLineAtLineIndex:(NSUInteger)lineIndex; -{ - { - if ([self.dataSource respondsToSelector:@selector(lineChartView:smoothLineAtLineIndex:)]) - { - return [self.dataSource lineChartView:self smoothLineAtLineIndex:lineIndex]; - } - return NO; - } -} #pragma mark - Setters @@ -766,13 +651,11 @@ - (void)setState:(JBChartViewState)state animated:(BOOL)animated callback:(void dispatch_block_t adjustViewFrames = ^{ self.linesView.frame = CGRectMake(self.linesView.frame.origin.x, yOffset + ((self.state == JBChartViewStateCollapsed) ? (self.linesView.frame.size.height + self.footerView.frame.size.height) : 0.0), self.linesView.frame.size.width, self.linesView.frame.size.height); self.dotsView.frame = CGRectMake(self.dotsView.frame.origin.x, yOffset + ((self.state == JBChartViewStateCollapsed) ? (self.dotsView.frame.size.height + self.footerView.frame.size.height) : 0.0), self.dotsView.frame.size.width, self.dotsView.frame.size.height); - self.areasView.frame = CGRectMake(self.areasView.frame.origin.x, yOffset + ((self.state == JBChartViewStateCollapsed) ? (self.areasView.frame.size.height + self.footerView.frame.size.height) : 0.0), self.areasView.frame.size.width, self.areasView.frame.size.height); }; dispatch_block_t adjustViewAlphas = ^{ self.linesView.alpha = (self.state == JBChartViewStateExpanded) ? 1.0 : 0.0; self.dotsView.alpha = (self.state == JBChartViewStateExpanded) ? 1.0 : 0.0; - self.areasView.alpha = (self.state == JBChartViewStateExpanded) ? 1.0 : 0.0; }; if (animated) @@ -780,7 +663,6 @@ - (void)setState:(JBChartViewState)state animated:(BOOL)animated callback:(void [UIView animateWithDuration:(kJBLineChartViewStateAnimationDuration * 0.5) delay:0.0 options:UIViewAnimationOptionBeginFromCurrentState animations:^{ self.linesView.frame = CGRectOffset(mainViewRect, 0, yOffset - kJBLineChartViewStateBounceOffset); // bounce self.dotsView.frame = CGRectOffset(mainViewRect, 0, yOffset - kJBLineChartViewStateBounceOffset); - self.areasView.frame = CGRectOffset(mainViewRect, 0, yOffset - kJBLineChartViewStateBounceOffset); } completion:^(BOOL finished) { [UIView animateWithDuration:kJBLineChartViewStateAnimationDuration delay:0.0 options:UIViewAnimationOptionBeginFromCurrentState animations:^{ adjustViewFrames(); @@ -1056,7 +938,6 @@ - (void)touchesEndedOrCancelledWithTouches:(NSSet *)touches { [self.linesView setSelectedLineIndex:kJBLineChartLinesViewUnselectedLineIndex animated:YES]; [self.dotsView setSelectedLineIndex:kJBLineChartDotsViewUnselectedLineIndex animated:YES]; - [self.areasView setSelectedLineIndex:kJBLineChartLinesViewUnselectedLineIndex animated:YES]; } } @@ -1101,7 +982,6 @@ - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { [self.linesView setSelectedLineIndex:[self lineIndexForPoint:touchPoint] animated:YES]; [self.dotsView setSelectedLineIndex:[self lineIndexForPoint:touchPoint] animated:YES]; - [self.areasView setSelectedLineIndex:[self lineIndexForPoint:touchPoint] animated:YES]; } [self touchesBeganOrMovedWithTouches:touches]; } @@ -1166,6 +1046,20 @@ - (void)setLineStyle:(JBLineChartViewLineStyle)lineStyle @end + +@implementation JBAreaLayer + +-(id)init +{ + self = [super init]; + if (self) { + self.strokeColor = [UIColor clearColor].CGColor; + } + return self; +} + +@end + @implementation JBLineChartPoint #pragma mark - Alloc/Init @@ -1223,9 +1117,11 @@ - (void)drawRect:(CGRect)rect CGFloat padding = [self.delegate paddingForLineChartLinesView:self]; NSUInteger lineIndex = 0; + NSInteger fillingBottomLineIndex = -1; //-1 is x-axis for (NSArray *lineData in chartData) { UIBezierPath *path = [UIBezierPath bezierPath]; + UIBezierPath *fillingPath = [UIBezierPath bezierPath]; path.miterLimit = kJBLineChartLinesViewMiterLimit; JBLineChartPoint *previousLineChartPoint = nil; @@ -1277,36 +1173,123 @@ - (void)drawRect:(CGRect)rect previousLineChartPoint = lineChartPoint; index++; } + + + NSAssert([self.delegate respondsToSelector:@selector(lineChartLinesView:fillsAreaUnderLineWithIndex:)], @"JBLineChartLinesView // delegate must implement - (BOOL)lineChartLineView:(JBLineChartLinesView *)lineChartLinesView fillsAreaUnderLineWithIndex:(NSUInteger)lineIndex"); + BOOL fillAreUnderLine = [self.delegate lineChartLinesView:self fillsAreaUnderLineWithIndex:lineIndex]; + if (fillAreUnderLine) { + NSArray *bottomLineData = nil; + if (fillingBottomLineIndex == -1) { + //x-axis is bottom line + JBLineChartPoint *lowerRightCornor = [[JBLineChartPoint alloc] init]; + lowerRightCornor.position = CGPointMake(self.bounds.size.width - padding, self.bounds.size.height - padding); + JBLineChartPoint *lowerLeftCornor = [[JBLineChartPoint alloc] init]; + lowerLeftCornor.position = CGPointMake(padding, self.bounds.size.height); + bottomLineData = @[lowerLeftCornor, lowerRightCornor]; + } else { + bottomLineData = chartData[fillingBottomLineIndex]; + } + + //FIXME: I don't know how to avoid this code copy. + previousSlope = 0; + NSAssert([self.delegate respondsToSelector:@selector(lineChartLinesView:smoothLineAtLineIndex:)], @"JBLineChartLinesView // delegate must implement - (BOOL)lineChartLinesView:(JBLineChartLinesView *)lineChartLinesView smoothLineAtLineIndex:(NSUInteger)lineIndex"); + BOOL smoothBottomLine = fillingBottomLineIndex == -1 ? NO : [self.delegate lineChartLinesView:self smoothLineAtLineIndex:fillingBottomLineIndex]; + NSArray *inversedLineData = [[bottomLineData reverseObjectEnumerator] allObjects]; + NSArray *fillingLineData = [sortedLineData arrayByAddingObjectsFromArray:inversedLineData]; + NSUInteger index = 0; + for (JBLineChartPoint *lineChartPoint in fillingLineData) + { + if (index == 0) + { + [fillingPath moveToPoint:CGPointMake(lineChartPoint.position.x, fmin(self.bounds.size.height - padding, fmax(padding, lineChartPoint.position.y)))]; + } + else + { + JBLineChartPoint *nextLineChartPoint = nil; + if (index != ([fillingLineData count] - 1)) + { + nextLineChartPoint = [fillingLineData objectAtIndex:(index + 1)]; + } + + CGFloat nextSlope = (nextLineChartPoint != nil) ? ((nextLineChartPoint.position.y - lineChartPoint.position.y)) / ((nextLineChartPoint.position.x - lineChartPoint.position.x)) : previousSlope; + CGFloat currentSlope = ((lineChartPoint.position.y - previousLineChartPoint.position.y)) / (lineChartPoint.position.x-previousLineChartPoint.position.x); + + BOOL deltaFromNextSlope = ((currentSlope >= (nextSlope + kJBLineChartLinesViewSmoothThresholdSlope)) || (currentSlope <= (nextSlope - kJBLineChartLinesViewSmoothThresholdSlope))); + BOOL deltaFromPreviousSlope = ((currentSlope <= (previousSlope + kJBLineChartLinesViewSmoothThresholdSlope)) || (currentSlope >= (previousSlope - kJBLineChartLinesViewSmoothThresholdSlope))); + BOOL deltaFromPreviousY = (lineChartPoint.position.y >= previousLineChartPoint.position.y + kJBLineChartLinesViewSmoothThresholdVertical) || (lineChartPoint.position.y <= previousLineChartPoint.position.y - kJBLineChartLinesViewSmoothThresholdVertical); + + if ((index < lineData.count ? smoothLine : smoothBottomLine) && deltaFromNextSlope && deltaFromPreviousSlope && deltaFromPreviousY) + { + CGFloat deltaX = lineChartPoint.position.x - previousLineChartPoint.position.x; + CGFloat controlPointX = previousLineChartPoint.position.x + (deltaX / 2); + + CGPoint controlPoint1 = CGPointMake(controlPointX, previousLineChartPoint.position.y); + CGPoint controlPoint2 = CGPointMake(controlPointX, lineChartPoint.position.y); + + [fillingPath addCurveToPoint:CGPointMake(lineChartPoint.position.x, fmin(self.bounds.size.height - padding, fmax(padding, lineChartPoint.position.y))) controlPoint1:controlPoint1 controlPoint2:controlPoint2]; + } + else + { + [fillingPath addLineToPoint:CGPointMake(lineChartPoint.position.x, fmin(self.bounds.size.height - padding, fmax(padding, lineChartPoint.position.y)))]; + } + + previousSlope = currentSlope; + } + previousLineChartPoint = lineChartPoint; + index++; + } + + [fillingPath closePath]; + + fillingBottomLineIndex = lineIndex; + } - JBLineLayer *shapeLayer = [self lineLayerForLineIndex:lineIndex]; - if (shapeLayer == nil) + JBLineLayer *lineLayer = [self lineLayerForLineIndex:lineIndex]; + if (lineLayer == nil) { - shapeLayer = [JBLineLayer layer]; + lineLayer = [JBLineLayer layer]; + } + JBAreaLayer *areaLayer = [self areaLayerForLineIndex:lineIndex]; + if (areaLayer == nil) + { + areaLayer = [JBAreaLayer layer]; } + - shapeLayer.tag = lineIndex; + lineLayer.tag = lineIndex; + areaLayer.tag = lineIndex; NSAssert([self.delegate respondsToSelector:@selector(lineChartLinesView:lineStyleForLineAtLineIndex:)], @"JBLineChartLinesView // delegate must implement - (JBLineChartViewLineStyle)lineChartLineView:(JBLineChartLinesView *)lineChartLinesView lineStyleForLineAtLineIndex:(NSUInteger)lineIndex"); - shapeLayer.lineStyle = [self.delegate lineChartLinesView:self lineStyleForLineAtLineIndex:lineIndex]; + lineLayer.lineStyle = [self.delegate lineChartLinesView:self lineStyleForLineAtLineIndex:lineIndex]; NSAssert([self.delegate respondsToSelector:@selector(lineChartLinesView:colorForLineAtLineIndex:)], @"JBLineChartLinesView // delegate must implement - (UIColor *)lineChartLinesView:(JBLineChartLinesView *)lineChartLinesView colorForLineAtLineIndex:(NSUInteger)lineIndex"); - shapeLayer.strokeColor = [self.delegate lineChartLinesView:self colorForLineAtLineIndex:lineIndex].CGColor; - + UIColor *color = [self.delegate lineChartLinesView:self colorForLineAtLineIndex:lineIndex]; + lineLayer.strokeColor = color.CGColor; + areaLayer.fillColor = [color colorWithAlphaComponent:CGColorGetAlpha(color.CGColor)/2.0].CGColor; + if (smoothLine == YES) { - shapeLayer.lineCap = kCALineCapRound; - shapeLayer.lineJoin = kCALineJoinRound; + lineLayer.lineCap = kCALineCapRound; + lineLayer.lineJoin = kCALineJoinRound; + areaLayer.lineCap = kCALineCapRound; + areaLayer.lineJoin = kCALineJoinRound; } else { - shapeLayer.lineCap = kCALineCapButt; - shapeLayer.lineJoin = kCALineJoinMiter; + lineLayer.lineCap = kCALineCapButt; + lineLayer.lineJoin = kCALineJoinMiter; + areaLayer.lineCap = kCALineCapButt; + areaLayer.lineJoin = kCALineJoinMiter; } NSAssert([self.delegate respondsToSelector:@selector(lineChartLinesView:widthForLineAtLineIndex:)], @"JBLineChartLinesView // delegate must implement - (CGFloat)lineChartLinesView:(JBLineChartLinesView *)lineChartLinesView widthForLineAtLineIndex:(NSUInteger)lineIndex"); - shapeLayer.lineWidth = [self.delegate lineChartLinesView:self widthForLineAtLineIndex:lineIndex]; - shapeLayer.path = path.CGPath; - shapeLayer.frame = self.bounds; - [self.layer addSublayer:shapeLayer]; + lineLayer.lineWidth = [self.delegate lineChartLinesView:self widthForLineAtLineIndex:lineIndex]; + areaLayer.lineWidth = [self.delegate lineChartLinesView:self widthForLineAtLineIndex:lineIndex]; + lineLayer.path = path.CGPath; + areaLayer.path = fillingPath.CGPath; + lineLayer.frame = self.bounds; + areaLayer.frame = self.bounds; + [self.layer addSublayer:lineLayer]; + [self.layer insertSublayer:areaLayer atIndex:0]; lineIndex++; } @@ -1331,7 +1314,7 @@ - (void)setSelectedLineIndex:(NSInteger)selectedLineIndex animated:(BOOL)animate dispatch_block_t adjustLines = ^{ for (CALayer *layer in [self.layer sublayers]) { - if ([layer isKindOfClass:[JBLineLayer class]]) + if ([layer isMemberOfClass:[JBLineLayer class]]) { if (((JBLineLayer *)layer).tag == _selectedLineIndex) { @@ -1346,6 +1329,23 @@ - (void)setSelectedLineIndex:(NSInteger)selectedLineIndex animated:(BOOL)animate ((JBLineLayer *)layer).opacity = (_selectedLineIndex == kJBLineChartLinesViewUnselectedLineIndex) ? 1.0f : kJBLineChartLinesViewDefaultDimmedOpacity; } } + else if ([layer isMemberOfClass:[JBAreaLayer class]]) + { + if (((JBAreaLayer *)layer).tag == _selectedLineIndex) + { + NSAssert([self.delegate respondsToSelector:@selector(lineChartLinesView:selectedColorForLineAtLineIndex:)], @"JBLineChartLinesView // delegate must implement - (UIColor *)lineChartLinesView:(JBLineChartLinesView *)lineChartLinesView selectedColorForLineAtLineIndex:(NSUInteger)lineIndex"); + UIColor *lineColor = [self.delegate lineChartLinesView:self selectedColorForLineAtLineIndex:((JBAreaLayer *)layer).tag]; + ((JBAreaLayer *)layer).fillColor = [lineColor colorWithAlphaComponent:CGColorGetAlpha(lineColor.CGColor)/2.0].CGColor; + ((JBAreaLayer *)layer).opacity = 1.0f; + } + else + { + NSAssert([self.delegate respondsToSelector:@selector(lineChartLinesView:selectedColorForLineAtLineIndex:)], @"JBLineChartLinesView // delegate must implement - (UIColor *)lineChartLinesView:(JBLineChartLinesView *)lineChartLinesView selectedColorForLineAtLineIndex:(NSUInteger)lineIndex"); + UIColor *lineColor = [self.delegate lineChartLinesView:self colorForLineAtLineIndex:((JBAreaLayer *)layer).tag]; + ((JBAreaLayer *)layer).fillColor = [lineColor colorWithAlphaComponent:CGColorGetAlpha(lineColor.CGColor)/2.0].CGColor; + ((JBAreaLayer *)layer).opacity = (_selectedLineIndex == kJBLineChartLinesViewUnselectedLineIndex) ? 1.0f : kJBLineChartLinesViewDefaultDimmedOpacity; + } + } } }; @@ -1393,6 +1393,21 @@ - (JBLineLayer *)lineLayerForLineIndex:(NSUInteger)lineIndex return nil; } +- (JBAreaLayer *)areaLayerForLineIndex:(NSUInteger)areaIndex +{ + for (CALayer *layer in [self.layer sublayers]) + { + if ([layer isKindOfClass:[JBAreaLayer class]]) + { + if (((JBAreaLayer *)layer).tag == areaIndex) + { + return (JBAreaLayer *)layer; + } + } + } + return nil; +} + @end @implementation JBLineChartDotsView @@ -1529,285 +1544,149 @@ - (id)initWithRadius:(CGFloat)radius @end -@implementation JBAreaLayer - -#pragma mark - Alloc/Init - -+ (void)initialize -{ - if (self == [JBAreaLayer class]) - { - - } -} - -- (id)init -{ - self = [super init]; - if (self) - { - self.zPosition = 0.0f; - self.strokeColor = [UIColor clearColor].CGColor; - } - return self; -} -@end - -@implementation JBLineChartAreasView - -#pragma mark - Alloc/Init - -- (id)initWithFrame:(CGRect)frame -{ - self = [super initWithFrame:frame]; - if (self) - { - self.backgroundColor = [UIColor clearColor]; - } - return self; -} - -#pragma mark - Memory Management - -- (void)dealloc -{ - [NSObject cancelPreviousPerformRequestsWithTarget:self]; -} - -#pragma mark - Drawing - -- (void)drawRect:(CGRect)rect -{ - [super drawRect:rect]; - - NSAssert([self.delegate respondsToSelector:@selector(chartDataForLineChartAreasView:)], @"JBLineChartAreasView // delegate must implement - (NSArray *)chartDataForLineChartAreasView:(JBLineChartAreasView *)lineChartAreasView"); - NSArray *chartData = [self.delegate chartDataForLineChartAreasView:self]; - - NSAssert([self.delegate respondsToSelector:@selector(paddingForLineChartAreasView:)], @"JBLineChartAreasView // delegate must implement - (CGFloat)paddingForLineChartAreasView:(JBLineChartAreasView *)lineChartAreasView"); - CGFloat padding = [self.delegate paddingForLineChartAreasView:self]; - - NSUInteger lineIndex = 0; - NSArray *previousLineData = nil; - for (NSArray *lineData in chartData) - { - UIBezierPath *path = [UIBezierPath bezierPath]; - path.miterLimit = kJBLineChartLinesViewMiterLimit; - - JBLineChartPoint *previousLineChartPoint = nil; - CGFloat previousSlope; - NSAssert([self.delegate respondsToSelector:@selector(lineChartAreasView:smoothLineAtLineIndex:)], @"JBLineChartAreasView // delegate must implement - (BOOL)lineChartAreasView:(JBLineChartAreasView *)lineChartAreasView smoothLineAtLineIndex:(NSUInteger)lineIndex"); - BOOL smoothLine = [self.delegate lineChartAreasView:self smoothLineAtLineIndex:lineIndex]; - BOOL previousSmoothLine = NO; - if (lineIndex > 0) { - previousSmoothLine = [self.delegate lineChartAreasView:self smoothLineAtLineIndex:lineIndex - 1]; - } - - if (!previousLineData) { - JBLineChartPoint *lowerRightCornor = [[JBLineChartPoint alloc] init]; - lowerRightCornor.position = CGPointMake(self.bounds.size.width - padding, self.bounds.size.height - padding); - JBLineChartPoint *lowerLeftCornor = [[JBLineChartPoint alloc] init]; - lowerLeftCornor.position = CGPointMake(padding, self.bounds.size.height); - previousLineData = @[lowerLeftCornor, lowerRightCornor]; - } - - //add the previous line in inversed order at the beginning of the path to create a polygon - NSUInteger index = 0; - NSArray *sortedPreviousLineData = [[previousLineData reverseObjectEnumerator] allObjects]; - for (JBLineChartPoint *lineChartPoint in sortedPreviousLineData) - { - if (index == 0) - { - [path moveToPoint:CGPointMake(lineChartPoint.position.x, fmin(self.bounds.size.height - padding, fmax(padding, lineChartPoint.position.y)))]; - } - else - { - JBLineChartPoint *nextLineChartPoint = nil; - if (index != ([sortedPreviousLineData count] - 1)) - { - nextLineChartPoint = [sortedPreviousLineData objectAtIndex:(index + 1)]; - } - - CGFloat nextSlope = (nextLineChartPoint != nil) ? ((nextLineChartPoint.position.y - lineChartPoint.position.y)) / ((nextLineChartPoint.position.x - lineChartPoint.position.x)) : previousSlope; - CGFloat currentSlope = ((lineChartPoint.position.y - previousLineChartPoint.position.y)) / (lineChartPoint.position.x-previousLineChartPoint.position.x); - - BOOL deltaFromNextSlope = ((currentSlope >= (nextSlope + kJBLineChartLinesViewSmoothThresholdSlope)) || (currentSlope <= (nextSlope - kJBLineChartLinesViewSmoothThresholdSlope))); - BOOL deltaFromPreviousSlope = ((currentSlope <= (previousSlope + kJBLineChartLinesViewSmoothThresholdSlope)) || (currentSlope >= (previousSlope - kJBLineChartLinesViewSmoothThresholdSlope))); - BOOL deltaFromPreviousY = (lineChartPoint.position.y >= previousLineChartPoint.position.y + kJBLineChartLinesViewSmoothThresholdVertical) || (lineChartPoint.position.y <= previousLineChartPoint.position.y - kJBLineChartLinesViewSmoothThresholdVertical); - - if (previousSmoothLine && deltaFromNextSlope && deltaFromPreviousSlope && deltaFromPreviousY) - { - CGFloat deltaX = lineChartPoint.position.x - previousLineChartPoint.position.x; - CGFloat controlPointX = previousLineChartPoint.position.x + (deltaX / 2); - - CGPoint controlPoint1 = CGPointMake(controlPointX, previousLineChartPoint.position.y); - CGPoint controlPoint2 = CGPointMake(controlPointX, lineChartPoint.position.y); - - [path addCurveToPoint:CGPointMake(lineChartPoint.position.x, fmin(self.bounds.size.height - padding, fmax(padding, lineChartPoint.position.y))) controlPoint1:controlPoint1 controlPoint2:controlPoint2]; - } - else - { - [path addLineToPoint:CGPointMake(lineChartPoint.position.x, fmin(self.bounds.size.height - padding, fmax(padding, lineChartPoint.position.y)))]; - } - - previousSlope = currentSlope; - } - previousLineChartPoint = lineChartPoint; - index++; - } - - index = 0; - NSArray *sortedLineData = [lineData sortedArrayUsingSelector:@selector(compare:)]; - for (JBLineChartPoint *lineChartPoint in [lineData sortedArrayUsingSelector:@selector(compare:)]) - { - - if (index == 0) - { - [path addLineToPoint:CGPointMake(lineChartPoint.position.x, fmin(self.bounds.size.height - padding, fmax(padding, lineChartPoint.position.y)))]; - } - else - { - JBLineChartPoint *nextLineChartPoint = nil; - if (index != ([lineData count] - 1)) - { - nextLineChartPoint = [sortedLineData objectAtIndex:(index + 1)]; - } - - CGFloat nextSlope = (nextLineChartPoint != nil) ? ((nextLineChartPoint.position.y - lineChartPoint.position.y)) / ((nextLineChartPoint.position.x - lineChartPoint.position.x)) : previousSlope; - CGFloat currentSlope = ((lineChartPoint.position.y - previousLineChartPoint.position.y)) / (lineChartPoint.position.x-previousLineChartPoint.position.x); - - BOOL deltaFromNextSlope = ((currentSlope >= (nextSlope + kJBLineChartLinesViewSmoothThresholdSlope)) || (currentSlope <= (nextSlope - kJBLineChartLinesViewSmoothThresholdSlope))); - BOOL deltaFromPreviousSlope = ((currentSlope >= (previousSlope + kJBLineChartLinesViewSmoothThresholdSlope)) || (currentSlope <= (previousSlope - kJBLineChartLinesViewSmoothThresholdSlope))); - BOOL deltaFromPreviousY = (lineChartPoint.position.y >= previousLineChartPoint.position.y + kJBLineChartLinesViewSmoothThresholdVertical) || (lineChartPoint.position.y <= previousLineChartPoint.position.y - kJBLineChartLinesViewSmoothThresholdVertical); - - if (smoothLine && deltaFromNextSlope && deltaFromPreviousSlope && deltaFromPreviousY) - { - CGFloat deltaX = lineChartPoint.position.x - previousLineChartPoint.position.x; - CGFloat controlPointX = previousLineChartPoint.position.x + (deltaX / 2); - - CGPoint controlPoint1 = CGPointMake(controlPointX, previousLineChartPoint.position.y); - CGPoint controlPoint2 = CGPointMake(controlPointX, lineChartPoint.position.y); - - [path addCurveToPoint:CGPointMake(lineChartPoint.position.x, fmin(self.bounds.size.height - padding, fmax(padding, lineChartPoint.position.y))) controlPoint1:controlPoint1 controlPoint2:controlPoint2]; - } - else - { - [path addLineToPoint:CGPointMake(lineChartPoint.position.x, fmin(self.bounds.size.height - padding, fmax(padding, lineChartPoint.position.y)))]; - } - - previousSlope = currentSlope; - } - previousLineChartPoint = lineChartPoint; - index++; - - } - - [path closePath]; - - - - JBAreaLayer *areaLayer = [self areaLayerForLineIndex:lineIndex]; - if (areaLayer == nil) { - areaLayer = [JBAreaLayer layer]; - } - - areaLayer.tag = lineIndex; - NSAssert([self.delegate respondsToSelector:@selector(lineChartAreasView:colorForAreaUnderLineAtLineIndex:)], @"JBLineChartAreasView // delegate must implement - (UIColor *)lineChartAreasView:(JBLineChartAreasView *)lineChartAreasView colorForAreaUnderLineAtLineIndex:(NSUInteger)lineIndex"); - areaLayer.fillColor = [self.delegate lineChartAreasView:self colorForAreaUnderLineAtLineIndex:lineIndex].CGColor; - - - areaLayer.path = path.CGPath; - areaLayer.frame = self.bounds; - [self.layer addSublayer:areaLayer]; - - previousLineData = lineData; - - lineIndex++; - } - - self.animated = NO; -} - - -#pragma mark - Data - -- (void)reloadData -{ - // Drawing is all done with CG (no subviews here) - [self setNeedsDisplay]; -} - - -#pragma mark - Setters - -- (void)setSelectedLineIndex:(NSInteger)selectedLineIndex animated:(BOOL)animated -{ - _selectedLineIndex = selectedLineIndex; - - dispatch_block_t adjustLines = ^{ - for (CALayer *layer in [self.layer sublayers]) - { - if ([layer isKindOfClass:[JBAreaLayer class]]) - { - if (((JBAreaLayer *)layer).tag == _selectedLineIndex) - { - NSAssert([self.delegate respondsToSelector:@selector(lineChartAreasView:selectedColorForAreaUnderLineAtLineIndex:)], @"JBLineChartAreasView // delegate must implement - (UIColor *)lineChartAreasView:(JBLineChartAreasView *)lineChartAreasView selectedColorForAreaUnderLineAtLineIndex:(NSUInteger)lineIndex"); - ((JBLineLayer *)layer).fillColor = [self.delegate lineChartAreasView:self selectedColorForAreaUnderLineAtLineIndex:((JBAreaLayer *)layer).tag].CGColor; - ((JBAreaLayer *)layer).opacity = 1.0f; - } - else - { - NSAssert([self.delegate respondsToSelector:@selector(lineChartAreasView:colorForAreaUnderLineAtLineIndex:)], @"JBLineChartAreasView // delegate must implement - (UIColor *)lineChartAreasView:(JBLineChartAreasView *)lineChartAreasView colorForAreaUnderLineAtLineIndex:(NSUInteger)lineIndex"); - ((JBAreaLayer *)layer).fillColor = [self.delegate lineChartAreasView:self colorForAreaUnderLineAtLineIndex:((JBLineLayer *)layer).tag].CGColor; - ((JBAreaLayer *)layer).opacity = (_selectedLineIndex == kJBLineChartLinesViewUnselectedLineIndex) ? 1.0f : kJBLineChartLinesViewDefaultDimmedOpacity; - } - } - } - }; - - if (animated) - { - [UIView animateWithDuration:kJBChartViewDefaultAnimationDuration animations:^{ - adjustLines(); - }]; - } - else - { - adjustLines(); - } -} - -- (void)setSelectedLineIndex:(NSInteger)selectedLineIndex -{ - [self setSelectedLineIndex:selectedLineIndex animated:NO]; -} - - -#pragma mark - Callback Helpers - -- (void)fireCallback:(void (^)())callback -{ - dispatch_block_t callbackCopy = [callback copy]; - - if (callbackCopy != nil) - { - callbackCopy(); - } -} - -- (JBAreaLayer *)areaLayerForLineIndex:(NSUInteger)areaIndex -{ - for (CALayer *layer in [self.layer sublayers]) - { - if ([layer isKindOfClass:[JBAreaLayer class]]) - { - if (((JBAreaLayer *)layer).tag == areaIndex) - { - return (JBAreaLayer *)layer; - } - } - } - return nil; -} - -@end +//#pragma mark - Drawing +// +//- (void)drawRect:(CGRect)rect +//{ +// NSUInteger lineIndex = 0; +// NSArray *previousLineData = nil; +// for (NSArray *lineData in chartData) +// { +// UIBezierPath *path = [UIBezierPath bezierPath]; +// path.miterLimit = kJBLineChartLinesViewMiterLimit; +// +// JBLineChartPoint *previousLineChartPoint = nil; +// CGFloat previousSlope; +// +// NSAssert([self.delegate respondsToSelector:@selector(lineChartAreasView:smoothLineAtLineIndex:)], @"JBLineChartAreasView // delegate must implement - (BOOL)lineChartAreasView:(JBLineChartAreasView *)lineChartAreasView smoothLineAtLineIndex:(NSUInteger)lineIndex"); +// BOOL smoothLine = [self.delegate lineChartAreasView:self smoothLineAtLineIndex:lineIndex]; +// BOOL previousSmoothLine = NO; +// if (lineIndex > 0) { +// previousSmoothLine = [self.delegate lineChartAreasView:self smoothLineAtLineIndex:lineIndex - 1]; +// } +// +// if (!previousLineData) { +// JBLineChartPoint *lowerRightCornor = [[JBLineChartPoint alloc] init]; +// lowerRightCornor.position = CGPointMake(self.bounds.size.width - padding, self.bounds.size.height - padding); +// JBLineChartPoint *lowerLeftCornor = [[JBLineChartPoint alloc] init]; +// lowerLeftCornor.position = CGPointMake(padding, self.bounds.size.height); +// previousLineData = @[lowerLeftCornor, lowerRightCornor]; +// } +// +// //add the previous line in inversed order at the beginning of the path to create a polygon +// NSUInteger index = 0; +// NSArray *sortedPreviousLineData = [[previousLineData reverseObjectEnumerator] allObjects]; +// for (JBLineChartPoint *lineChartPoint in sortedPreviousLineData) +// { +// if (index == 0) +// { +// [path moveToPoint:CGPointMake(lineChartPoint.position.x, fmin(self.bounds.size.height - padding, fmax(padding, lineChartPoint.position.y)))]; +// } +// else +// { +// JBLineChartPoint *nextLineChartPoint = nil; +// if (index != ([sortedPreviousLineData count] - 1)) +// { +// nextLineChartPoint = [sortedPreviousLineData objectAtIndex:(index + 1)]; +// } +// +// CGFloat nextSlope = (nextLineChartPoint != nil) ? ((nextLineChartPoint.position.y - lineChartPoint.position.y)) / ((nextLineChartPoint.position.x - lineChartPoint.position.x)) : previousSlope; +// CGFloat currentSlope = ((lineChartPoint.position.y - previousLineChartPoint.position.y)) / (lineChartPoint.position.x-previousLineChartPoint.position.x); +// +// BOOL deltaFromNextSlope = ((currentSlope >= (nextSlope + kJBLineChartLinesViewSmoothThresholdSlope)) || (currentSlope <= (nextSlope - kJBLineChartLinesViewSmoothThresholdSlope))); +// BOOL deltaFromPreviousSlope = ((currentSlope <= (previousSlope + kJBLineChartLinesViewSmoothThresholdSlope)) || (currentSlope >= (previousSlope - kJBLineChartLinesViewSmoothThresholdSlope))); +// BOOL deltaFromPreviousY = (lineChartPoint.position.y >= previousLineChartPoint.position.y + kJBLineChartLinesViewSmoothThresholdVertical) || (lineChartPoint.position.y <= previousLineChartPoint.position.y - kJBLineChartLinesViewSmoothThresholdVertical); +// +// if (previousSmoothLine && deltaFromNextSlope && deltaFromPreviousSlope && deltaFromPreviousY) +// { +// CGFloat deltaX = lineChartPoint.position.x - previousLineChartPoint.position.x; +// CGFloat controlPointX = previousLineChartPoint.position.x + (deltaX / 2); +// +// CGPoint controlPoint1 = CGPointMake(controlPointX, previousLineChartPoint.position.y); +// CGPoint controlPoint2 = CGPointMake(controlPointX, lineChartPoint.position.y); +// +// [path addCurveToPoint:CGPointMake(lineChartPoint.position.x, fmin(self.bounds.size.height - padding, fmax(padding, lineChartPoint.position.y))) controlPoint1:controlPoint1 controlPoint2:controlPoint2]; +// } +// else +// { +// [path addLineToPoint:CGPointMake(lineChartPoint.position.x, fmin(self.bounds.size.height - padding, fmax(padding, lineChartPoint.position.y)))]; +// } +// +// previousSlope = currentSlope; +// } +// previousLineChartPoint = lineChartPoint; +// index++; +// } +// +// index = 0; +// NSArray *sortedLineData = [lineData sortedArrayUsingSelector:@selector(compare:)]; +// for (JBLineChartPoint *lineChartPoint in [lineData sortedArrayUsingSelector:@selector(compare:)]) +// { +// +// if (index == 0) +// { +// [path addLineToPoint:CGPointMake(lineChartPoint.position.x, fmin(self.bounds.size.height - padding, fmax(padding, lineChartPoint.position.y)))]; +// } +// else +// { +// JBLineChartPoint *nextLineChartPoint = nil; +// if (index != ([lineData count] - 1)) +// { +// nextLineChartPoint = [sortedLineData objectAtIndex:(index + 1)]; +// } +// +// CGFloat nextSlope = (nextLineChartPoint != nil) ? ((nextLineChartPoint.position.y - lineChartPoint.position.y)) / ((nextLineChartPoint.position.x - lineChartPoint.position.x)) : previousSlope; +// CGFloat currentSlope = ((lineChartPoint.position.y - previousLineChartPoint.position.y)) / (lineChartPoint.position.x-previousLineChartPoint.position.x); +// +// BOOL deltaFromNextSlope = ((currentSlope >= (nextSlope + kJBLineChartLinesViewSmoothThresholdSlope)) || (currentSlope <= (nextSlope - kJBLineChartLinesViewSmoothThresholdSlope))); +// BOOL deltaFromPreviousSlope = ((currentSlope >= (previousSlope + kJBLineChartLinesViewSmoothThresholdSlope)) || (currentSlope <= (previousSlope - kJBLineChartLinesViewSmoothThresholdSlope))); +// BOOL deltaFromPreviousY = (lineChartPoint.position.y >= previousLineChartPoint.position.y + kJBLineChartLinesViewSmoothThresholdVertical) || (lineChartPoint.position.y <= previousLineChartPoint.position.y - kJBLineChartLinesViewSmoothThresholdVertical); +// +// if (smoothLine && deltaFromNextSlope && deltaFromPreviousSlope && deltaFromPreviousY) +// { +// CGFloat deltaX = lineChartPoint.position.x - previousLineChartPoint.position.x; +// CGFloat controlPointX = previousLineChartPoint.position.x + (deltaX / 2); +// +// CGPoint controlPoint1 = CGPointMake(controlPointX, previousLineChartPoint.position.y); +// CGPoint controlPoint2 = CGPointMake(controlPointX, lineChartPoint.position.y); +// +// [path addCurveToPoint:CGPointMake(lineChartPoint.position.x, fmin(self.bounds.size.height - padding, fmax(padding, lineChartPoint.position.y))) controlPoint1:controlPoint1 controlPoint2:controlPoint2]; +// } +// else +// { +// [path addLineToPoint:CGPointMake(lineChartPoint.position.x, fmin(self.bounds.size.height - padding, fmax(padding, lineChartPoint.position.y)))]; +// } +// +// previousSlope = currentSlope; +// } +// previousLineChartPoint = lineChartPoint; +// index++; +// +// } +// +// [path closePath]; +// +// +// +// JBAreaLayer *areaLayer = [self areaLayerForLineIndex:lineIndex]; +// if (areaLayer == nil) { +// areaLayer = [JBAreaLayer layer]; +// } +// +// areaLayer.tag = lineIndex; +// NSAssert([self.delegate respondsToSelector:@selector(lineChartAreasView:colorForAreaUnderLineAtLineIndex:)], @"JBLineChartAreasView // delegate must implement - (UIColor *)lineChartAreasView:(JBLineChartAreasView *)lineChartAreasView colorForAreaUnderLineAtLineIndex:(NSUInteger)lineIndex"); +// areaLayer.fillColor = [self.delegate lineChartAreasView:self colorForAreaUnderLineAtLineIndex:lineIndex].CGColor; +// +// +// areaLayer.path = path.CGPath; +// areaLayer.frame = self.bounds; +// [self.layer addSublayer:areaLayer]; +// +// previousLineData = lineData; +// +// lineIndex++; +// } +// +// self.animated = NO; +//} diff --git a/JBChartViewDemo/JBChartViewDemo.xcodeproj/project.pbxproj b/JBChartViewDemo/JBChartViewDemo.xcodeproj/project.pbxproj index 6a8a05867..95e6977cf 100644 --- a/JBChartViewDemo/JBChartViewDemo.xcodeproj/project.pbxproj +++ b/JBChartViewDemo/JBChartViewDemo.xcodeproj/project.pbxproj @@ -7,9 +7,6 @@ objects = { /* Begin PBXBuildFile section */ - 44EB67A11905B47800FABB5D /* JBAreaChartViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 44EB67A01905B47800FABB5D /* JBAreaChartViewController.m */; }; - 44EB67A71906AA9200FABB5D /* icon-area-chart.png in Resources */ = {isa = PBXBuildFile; fileRef = 44EB67A51906AA9200FABB5D /* icon-area-chart.png */; }; - 44EB67A81906AA9200FABB5D /* icon-area-chart@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 44EB67A61906AA9200FABB5D /* icon-area-chart@2x.png */; }; 9B0725211829822A0052109B /* JBChartListViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 9B0725201829822A0052109B /* JBChartListViewController.m */; }; 9B2E530518218CF20079B9D2 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9B2E530418218CF20079B9D2 /* Foundation.framework */; }; 9B2E530718218CF20079B9D2 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9B2E530618218CF20079B9D2 /* CoreGraphics.framework */; }; @@ -45,10 +42,6 @@ /* End PBXBuildFile section */ /* Begin PBXFileReference section */ - 44EB679F1905B47800FABB5D /* JBAreaChartViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JBAreaChartViewController.h; sourceTree = ""; }; - 44EB67A01905B47800FABB5D /* JBAreaChartViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JBAreaChartViewController.m; sourceTree = ""; }; - 44EB67A51906AA9200FABB5D /* icon-area-chart.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "icon-area-chart.png"; sourceTree = ""; }; - 44EB67A61906AA9200FABB5D /* icon-area-chart@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "icon-area-chart@2x.png"; sourceTree = ""; }; 9B07251F1829822A0052109B /* JBChartListViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JBChartListViewController.h; sourceTree = ""; }; 9B0725201829822A0052109B /* JBChartListViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JBChartListViewController.m; sourceTree = ""; }; 9B2E530118218CF20079B9D2 /* JBChartViewDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = JBChartViewDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -196,8 +189,6 @@ 9B0725201829822A0052109B /* JBChartListViewController.m */, 9B6A68DF1829BED5006DB3BF /* JBLineChartViewController.h */, 9B6A68E01829BED5006DB3BF /* JBLineChartViewController.m */, - 44EB679F1905B47800FABB5D /* JBAreaChartViewController.h */, - 44EB67A01905B47800FABB5D /* JBAreaChartViewController.m */, ); path = Controllers; sourceTree = ""; @@ -234,8 +225,6 @@ 9B698F13182D7DAE003C135F /* icon-bar-chart@2x.png */, 9B698F14182D7DAE003C135F /* icon-line-chart.png */, 9B698F15182D7DAE003C135F /* icon-line-chart@2x.png */, - 44EB67A51906AA9200FABB5D /* icon-area-chart.png */, - 44EB67A61906AA9200FABB5D /* icon-area-chart@2x.png */, 9B603D45182C7002000A76D0 /* icon-jawbone-logo.png */, 9B603D46182C7002000A76D0 /* icon-jawbone-logo@2x.png */, ); @@ -379,10 +368,8 @@ 9B698F18182D7DAE003C135F /* icon-line-chart.png in Resources */, 9B2E530F18218CF20079B9D2 /* InfoPlist.strings in Resources */, 9B698F17182D7DAE003C135F /* icon-bar-chart@2x.png in Resources */, - 44EB67A71906AA9200FABB5D /* icon-area-chart.png in Resources */, 9B603D47182C7002000A76D0 /* icon-jawbone-logo.png in Resources */, 9B603D48182C7002000A76D0 /* icon-jawbone-logo@2x.png in Resources */, - 44EB67A81906AA9200FABB5D /* icon-area-chart@2x.png in Resources */, 9B698F19182D7DAE003C135F /* icon-line-chart@2x.png in Resources */, 9B698F0A182D720E003C135F /* icon-arrow@2x.png in Resources */, ); @@ -411,7 +398,6 @@ 9BEE694618D2789E005D9BA7 /* JBBaseChartViewController.m in Sources */, 9B6A68E11829BED5006DB3BF /* JBLineChartViewController.m in Sources */, 9B2E533F18218D310079B9D2 /* AppDelegate.m in Sources */, - 44EB67A11905B47800FABB5D /* JBAreaChartViewController.m in Sources */, 9BD57BBC18D13D1A00ACFA52 /* JBChartTooltipView.m in Sources */, 9B603D4B182C7117000A76D0 /* JBBaseViewController.m in Sources */, 9B0725211829822A0052109B /* JBChartListViewController.m in Sources */, diff --git a/JBChartViewDemo/JBChartViewDemo/Cells/JBChartTableCell.m b/JBChartViewDemo/JBChartViewDemo/Cells/JBChartTableCell.m index 19be35554..b817e8879 100644 --- a/JBChartViewDemo/JBChartViewDemo/Cells/JBChartTableCell.m +++ b/JBChartViewDemo/JBChartViewDemo/Cells/JBChartTableCell.m @@ -22,21 +22,7 @@ - (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reus - (void)setType:(JBChartTableCellType)type { _type = type; - UIImage *image = nil; - switch (type) { - case JBChartTableCellTypeBarChart: - image = [UIImage imageNamed:kJBImageIconBarChart]; - break; - case JBChartTableCellTypeLineChart: - image = [UIImage imageNamed:kJBImageIconLineChart]; - break; - case JBChartTableCellTypeAreaChart: - image = [UIImage imageNamed:kJBImageIconAreaChart]; - break; - default: - break; - } - self.accessoryView = [[UIImageView alloc] initWithImage:image]; + self.accessoryView = [[UIImageView alloc] initWithImage:_type == JBChartTableCellTypeBarChart ? [UIImage imageNamed:kJBImageIconBarChart] : [UIImage imageNamed:kJBImageIconLineChart]]; } @end diff --git a/JBChartViewDemo/JBChartViewDemo/Constants/JBColorConstants.h b/JBChartViewDemo/JBChartViewDemo/Constants/JBColorConstants.h index 2d9b7180b..8fbe99968 100644 --- a/JBChartViewDemo/JBChartViewDemo/Constants/JBColorConstants.h +++ b/JBChartViewDemo/JBChartViewDemo/Constants/JBColorConstants.h @@ -32,21 +32,6 @@ #define kJBColorLineChartDefaultDashedLineColor [UIColor colorWithRed:1.0 green:0.0 blue:0.0 alpha:1.0] #define kJBColorLineChartDefaultDashedSelectedLineColor [UIColor colorWithWhite:1.0 alpha:1.0] -#define mark - Area Chart - -#define kJBColorAreaChartControllerBackground UIColorFromHex(0xb7e3e4) -#define kJBColorAreaChartBackground UIColorFromHex(0xb7e3e4) -#define kJBColorAreaChartHeader UIColorFromHex(0x1c474e) -#define kJBColorAreaChartHeaderSeparatorColor UIColorFromHex(0x8eb6b7) -#define kJBColorAreaChartDefaultSunLineColor [UIColor clearColor] -#define kJBColorAreaChartDefaultSunAreaColor [UIColorFromHex(0xfcfb3a) colorWithAlphaComponent:0.5] -#define kJBColorAreaChartDefaultSunSelectedLineColor [UIColor clearColor] -#define kJBColorAreaChartDefaultSunSelectedAreaColor UIColorFromHex(0xfcfb3a) -#define kJBColorAreaChartDefaultMoonLineColor [UIColor clearColor] -#define kJBColorAreaChartDefaultMoonAreaColor [[UIColor blackColor] colorWithAlphaComponent:0.5] -#define kJBColorAreaChartDefaultMoonSelectedLineColor [UIColor clearColor] -#define kJBColorAreaChartDefaultMoonSelectedAreaColor [UIColor blackColor] - #pragma mark - Tooltips #define kJBColorTooltipColor [UIColor colorWithWhite:1.0 alpha:0.9] diff --git a/JBChartViewDemo/JBChartViewDemo/Constants/JBStringConstants.h b/JBChartViewDemo/JBChartViewDemo/Constants/JBStringConstants.h index 1d6c02143..62acff4a5 100644 --- a/JBChartViewDemo/JBChartViewDemo/Constants/JBStringConstants.h +++ b/JBChartViewDemo/JBChartViewDemo/Constants/JBStringConstants.h @@ -26,13 +26,4 @@ #define kJBStringLabelAverageDailyRainfall localize(@"label.average.daily.rainfall", @"Average Daily Rainfall") #define kJBStringLabelMm localize(@"label.mm", @"mm") #define kJBStringLabelMetropolitanAverage localize(@"label.metropolitan.average", @"Metropolitan Average") -#define kJBStringLabelNationalAverage localize(@"label.national.average", @"National Average") - -#pragma mark - Labels (Area Chart) - -#define kJBStringLabel2014 localize(@"label.2014", @"2014") -#define kJBStringLabelSeattle2014 localize(@"label.seattle.2014", @"Seattle - 2014") -#define kJBStringLabelAverageShineHours localize(@"label.average.shine.hours", @"Average Shine Hours of Sun/Moon") -#define kJBStringLabelHours localize(@"label.hours", @"h") -#define kJBStringLabelMoon localize(@"label.moon", @"Moon") -#define kJBStringLabelSun localize(@"label.sun", @"Sun") \ No newline at end of file +#define kJBStringLabelNationalAverage localize(@"label.national.average", @"National Average") \ No newline at end of file diff --git a/JBChartViewDemo/JBChartViewDemo/Constants/JBUIConstants.h b/JBChartViewDemo/JBChartViewDemo/Constants/JBUIConstants.h index c09d16fa8..4515d6911 100644 --- a/JBChartViewDemo/JBChartViewDemo/Constants/JBUIConstants.h +++ b/JBChartViewDemo/JBChartViewDemo/Constants/JBUIConstants.h @@ -12,4 +12,3 @@ #define kJBImageIconArrow @"icon-arrow.png" #define kJBImageIconLineChart @"icon-line-chart.png" #define kJBImageIconBarChart @"icon-bar-chart.png" -#define kJBImageIconAreaChart @"icon-area-chart.png" diff --git a/JBChartViewDemo/JBChartViewDemo/Controllers/JBAreaChartViewController.h b/JBChartViewDemo/JBChartViewDemo/Controllers/JBAreaChartViewController.h deleted file mode 100644 index 159da8b2b..000000000 --- a/JBChartViewDemo/JBChartViewDemo/Controllers/JBAreaChartViewController.h +++ /dev/null @@ -1,13 +0,0 @@ -// -// JBAreaChartViewController.h -// JBChartViewDemo -// -// Created by Lars Ott on 21.04.14. -// Copyright (c) 2014 Jawbone. All rights reserved. -// - -#import "JBBaseChartViewController.h" - -@interface JBAreaChartViewController : JBBaseChartViewController - -@end diff --git a/JBChartViewDemo/JBChartViewDemo/Controllers/JBAreaChartViewController.m b/JBChartViewDemo/JBChartViewDemo/Controllers/JBAreaChartViewController.m deleted file mode 100644 index 4b2f505f1..000000000 --- a/JBChartViewDemo/JBChartViewDemo/Controllers/JBAreaChartViewController.m +++ /dev/null @@ -1,288 +0,0 @@ -// -// JBAreaChartViewController.m -// JBChartViewDemo -// -// Created by Lars Ott on 21.04.14. -// Copyright (c) 2014 Jawbone. All rights reserved. -// - -#import "JBAreaChartViewController.h" - -// Views -#import "JBLineChartView.h" -#import "JBChartHeaderView.h" -#import "JBLineChartFooterView.h" -#import "JBChartInformationView.h" - -#define ARC4RANDOM_MAX 0x100000000 - -typedef NS_ENUM(NSInteger, JBLineChartLine){ - JBLineChartLineSun, - JBLineChartLineMoon, - JBLineChartLineCount -}; - -// Numerics -CGFloat const kJBAreaChartViewControllerChartHeight = 250.0f; -CGFloat const kJBAreaChartViewControllerChartPadding = 10.0f; -CGFloat const kJBAreaChartViewControllerChartHeaderHeight = 75.0f; -CGFloat const kJBAreaChartViewControllerChartHeaderPadding = 20.0f; -CGFloat const kJBAreaChartViewControllerChartFooterHeight = 20.0f; -CGFloat const kJBAreaChartViewControllerChartLineWidth = 2.0f; -NSInteger const kJBAreaChartViewControllerMaxNumChartPoints = 7; - -// Strings -NSString * const kJBAreaChartViewControllerNavButtonViewKey = @"view"; - -@interface JBAreaChartViewController () - -@property (nonatomic, strong) JBLineChartView *lineChartView; -@property (nonatomic, strong) JBChartInformationView *informationView; -@property (nonatomic, strong) NSArray *chartData; -@property (nonatomic, strong) NSArray *daysOfWeek; - -// Buttons -- (void)chartToggleButtonPressed:(id)sender; - -// Helpers -- (void)initFakeData; -- (NSArray *)largestLineData; // largest collection of fake line data - -@end - -@implementation JBAreaChartViewController - -#pragma mark - Alloc/Init - -- (id)init -{ - self = [super init]; - if (self) - { - [self initFakeData]; - } - return self; -} - -- (id)initWithCoder:(NSCoder *)aDecoder -{ - self = [super initWithCoder:aDecoder]; - if (self) - { - [self initFakeData]; - } - return self; -} - -- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil -{ - self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; - if (self) - { - [self initFakeData]; - } - return self; -} - -#pragma mark - Data - -- (void)initFakeData -{ - NSMutableArray *mutableLineCharts = [NSMutableArray array]; - for (int lineIndex=0; lineIndex [largestLineData count]) - { - largestLineData = lineData; - } - } - return largestLineData; -} - -#pragma mark - View Lifecycle - -- (void)loadView -{ - [super loadView]; - - self.view.backgroundColor = kJBColorLineChartControllerBackground; - self.navigationItem.rightBarButtonItem = [self chartToggleButtonWithTarget:self action:@selector(chartToggleButtonPressed:)]; - - self.lineChartView = [[JBLineChartView alloc] init]; - self.lineChartView.frame = CGRectMake(kJBAreaChartViewControllerChartPadding, kJBAreaChartViewControllerChartPadding - , self.view.bounds.size.width - (kJBAreaChartViewControllerChartPadding * 2), kJBAreaChartViewControllerChartHeight); - self.lineChartView.delegate = self; - self.lineChartView.dataSource = self; - self.lineChartView.headerPadding =kJBAreaChartViewControllerChartHeaderPadding; - self.lineChartView.backgroundColor = kJBColorLineChartBackground; - self.lineChartView.fillsAreaBelowLine = YES; - self.lineChartView.isCumulative = YES; - - JBChartHeaderView *headerView = [[JBChartHeaderView alloc] initWithFrame:CGRectMake(kJBAreaChartViewControllerChartPadding, ceil(self.view.bounds.size.height * 0.5) - ceil(kJBAreaChartViewControllerChartHeaderHeight * 0.5), self.view.bounds.size.width - (kJBAreaChartViewControllerChartPadding * 2), kJBAreaChartViewControllerChartHeaderHeight)]; - headerView.titleLabel.text = [kJBStringLabelAverageShineHours uppercaseString]; - headerView.titleLabel.textColor = kJBColorLineChartHeader; - headerView.titleLabel.shadowColor = [UIColor colorWithWhite:1.0 alpha:0.25]; - headerView.titleLabel.shadowOffset = CGSizeMake(0, 1); - headerView.subtitleLabel.text = kJBStringLabel2014; - headerView.subtitleLabel.textColor = kJBColorLineChartHeader; - headerView.subtitleLabel.shadowColor = [UIColor colorWithWhite:1.0 alpha:0.25]; - headerView.subtitleLabel.shadowOffset = CGSizeMake(0, 1); - headerView.separatorColor = kJBColorLineChartHeaderSeparatorColor; - self.lineChartView.headerView = headerView; - - JBLineChartFooterView *footerView = [[JBLineChartFooterView alloc] initWithFrame:CGRectMake(kJBAreaChartViewControllerChartPadding, ceil(self.view.bounds.size.height * 0.5) - ceil(kJBAreaChartViewControllerChartFooterHeight * 0.5), self.view.bounds.size.width - (kJBAreaChartViewControllerChartPadding * 2), kJBAreaChartViewControllerChartFooterHeight)]; - footerView.backgroundColor = [UIColor clearColor]; - footerView.leftLabel.text = [[self.daysOfWeek firstObject] uppercaseString]; - footerView.leftLabel.textColor = [UIColor whiteColor]; - footerView.rightLabel.text = [[self.daysOfWeek lastObject] uppercaseString];; - footerView.rightLabel.textColor = [UIColor whiteColor]; - footerView.sectionCount = [[self chartData] count]; - self.lineChartView.footerView = footerView; - - [self.view addSubview:self.lineChartView]; - - self.informationView = [[JBChartInformationView alloc] initWithFrame:CGRectMake(self.view.bounds.origin.x, CGRectGetMaxY(self.lineChartView.frame), self.view.bounds.size.width, self.view.bounds.size.height - CGRectGetMaxY(self.lineChartView.frame) - CGRectGetMaxY(self.navigationController.navigationBar.frame))]; - [self.informationView setValueAndUnitTextColor:[UIColor colorWithWhite:1.0 alpha:0.75]]; - [self.informationView setTitleTextColor:kJBColorLineChartHeader]; - [self.informationView setTextShadowColor:nil]; - [self.informationView setSeparatorColor:kJBColorLineChartHeaderSeparatorColor]; - [self.view addSubview:self.informationView]; - - [self.lineChartView reloadData]; -} - -- (void)viewWillAppear:(BOOL)animated -{ - [super viewWillAppear:animated]; - [self.lineChartView setState:JBChartViewStateExpanded]; -} - -#pragma mark - JBLineChartViewDelegate - -- (CGFloat)lineChartView:(JBLineChartView *)lineChartView verticalValueForHorizontalIndex:(NSUInteger)horizontalIndex atLineIndex:(NSUInteger)lineIndex -{ - return [[[self.chartData objectAtIndex:lineIndex] objectAtIndex:horizontalIndex] floatValue]; -} - -- (void)lineChartView:(JBLineChartView *)lineChartView didSelectLineAtIndex:(NSUInteger)lineIndex horizontalIndex:(NSUInteger)horizontalIndex touchPoint:(CGPoint)touchPoint -{ - NSNumber *valueNumber = [[self.chartData objectAtIndex:lineIndex] objectAtIndex:horizontalIndex]; - [self.informationView setValueText:[NSString stringWithFormat:@"%.1f", [valueNumber floatValue]] unitText:kJBStringLabelHours]; - [self.informationView setTitleText:lineIndex == JBLineChartLineSun ? kJBStringLabelSun : kJBStringLabelMoon]; - [self.informationView setHidden:NO animated:YES]; - [self setTooltipVisible:YES animated:YES atTouchPoint:touchPoint]; - [self.tooltipView setText:[[self.daysOfWeek objectAtIndex:horizontalIndex] uppercaseString]]; -} - -- (void)didUnselectLineInLineChartView:(JBLineChartView *)lineChartView -{ - [self.informationView setHidden:YES animated:YES]; - [self setTooltipVisible:NO animated:YES]; -} - -#pragma mark - JBLineChartViewDataSource - -- (NSUInteger)numberOfLinesInLineChartView:(JBLineChartView *)lineChartView -{ - return [self.chartData count]; -} - -- (NSUInteger)lineChartView:(JBLineChartView *)lineChartView numberOfVerticalValuesAtLineIndex:(NSUInteger)lineIndex -{ - return [[self.chartData objectAtIndex:lineIndex] count]; -} - - -- (UIColor *)lineChartView:(JBLineChartView *)lineChartView colorForLineAtLineIndex:(NSUInteger)lineIndex -{ - return (lineIndex == JBLineChartLineSun) ? kJBColorAreaChartDefaultSunLineColor: kJBColorAreaChartDefaultMoonLineColor; -} - -- (UIColor *)lineChartView:(JBLineChartView *)lineChartView colorForDotAtHorizontalIndex:(NSUInteger)horizontalIndex atLineIndex:(NSUInteger)lineIndex -{ - return (lineIndex == JBLineChartLineSun) ? kJBColorAreaChartDefaultSunLineColor: kJBColorAreaChartDefaultMoonLineColor; -} - -- (CGFloat)lineChartView:(JBLineChartView *)lineChartView widthForLineAtLineIndex:(NSUInteger)lineIndex -{ - return kJBAreaChartViewControllerChartLineWidth; -} - -- (UIColor *)verticalSelectionColorForLineChartView:(JBLineChartView *)lineChartView -{ - return [UIColor whiteColor]; -} - -- (UIColor *)lineChartView:(JBLineChartView *)lineChartView selectionColorForLineAtLineIndex:(NSUInteger)lineIndex -{ - return (lineIndex == JBLineChartLineSun) ? kJBColorAreaChartDefaultSunSelectedLineColor: kJBColorAreaChartDefaultMoonSelectedLineColor; -} - -- (UIColor *)lineChartView:(JBLineChartView *)lineChartView selectionColorForDotAtHorizontalIndex:(NSUInteger)horizontalIndex atLineIndex:(NSUInteger)lineIndex -{ - return (lineIndex == JBLineChartLineSun) ? kJBColorAreaChartDefaultSunSelectedLineColor: kJBColorAreaChartDefaultMoonSelectedLineColor; -} - -- (UIColor *)lineChartView:(JBLineChartView *)lineChartView colorForAreaUnderLineAtLineIndex:(NSUInteger)lineIndex{ - return (lineIndex == JBLineChartLineSun) ? kJBColorAreaChartDefaultSunAreaColor : kJBColorAreaChartDefaultMoonAreaColor; -} - --(UIColor *)lineChartView:(JBLineChartView *)lineChartView selectionColorForAreaUnderLineAtLineIndex:(NSUInteger)lineIndex -{ - return (lineIndex == JBLineChartLineSun) ? kJBColorAreaChartDefaultSunSelectedAreaColor : kJBColorAreaChartDefaultMoonSelectedAreaColor; -} - -- (JBLineChartViewLineStyle)lineChartView:(JBLineChartView *)lineChartView lineStyleForLineAtLineIndex:(NSUInteger)lineIndex -{ - return JBLineChartViewLineStyleSolid; -} - -- (BOOL)lineChartView:(JBLineChartView *)lineChartView showsDotsForLineAtLineIndex:(NSUInteger)lineIndex -{ - return NO; -} - -- (BOOL)lineChartView:(JBLineChartView *)lineChartView smoothLineAtLineIndex:(NSUInteger)lineIndex -{ - return YES; -} - -#pragma mark - Buttons - -- (void)chartToggleButtonPressed:(id)sender -{ - UIView *buttonImageView = [self.navigationItem.rightBarButtonItem valueForKey:kJBAreaChartViewControllerNavButtonViewKey]; - buttonImageView.userInteractionEnabled = NO; - - CGAffineTransform transform = self.lineChartView.state == JBChartViewStateExpanded ? CGAffineTransformMakeRotation(M_PI) : CGAffineTransformMakeRotation(0); - buttonImageView.transform = transform; - - [self.lineChartView setState:self.lineChartView.state == JBChartViewStateExpanded ? JBChartViewStateCollapsed : JBChartViewStateExpanded animated:YES callback:^{ - buttonImageView.userInteractionEnabled = YES; - }]; -} - -#pragma mark - Overrides - -- (JBChartView *)chartView -{ - return self.lineChartView; -} - -@end \ No newline at end of file diff --git a/JBChartViewDemo/JBChartViewDemo/Controllers/JBChartListViewController.m b/JBChartViewDemo/JBChartViewDemo/Controllers/JBChartListViewController.m index 11ee5b006..f66a11000 100644 --- a/JBChartViewDemo/JBChartViewDemo/Controllers/JBChartListViewController.m +++ b/JBChartViewDemo/JBChartViewDemo/Controllers/JBChartListViewController.m @@ -11,7 +11,6 @@ // Controllers #import "JBBarChartViewController.h" #import "JBLineChartViewController.h" -#import "JBAreaChartViewController.h" // Views #import "JBChartTableCell.h" @@ -19,7 +18,6 @@ typedef NS_ENUM(NSInteger, JBChartListViewControllerRow){ JBChartListViewControllerRowLineChart, JBChartListViewControllerRowBarChart, - JBChartListViewControllerRowAreaChart, JBChartListViewControllerRowCount }; @@ -53,33 +51,9 @@ - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { JBChartTableCell *cell = [tableView dequeueReusableCellWithIdentifier:kJBChartListViewControllerCellIdentifier forIndexPath:indexPath]; - - NSString *text = nil; - NSString *detailText = nil; - JBChartTableCellType type = -1; - switch (indexPath.row) { - case JBChartListViewControllerRowLineChart: - text = kJBStringLabelAverageDailyRainfall; - detailText = kJBStringLabelSanFrancisco2013; - type = JBChartTableCellTypeLineChart; - break; - case JBChartListViewControllerRowBarChart: - text = kJBStringLabelAverageMonthlyTemperature; - detailText = kJBStringLabelWorldwide2012; - type = JBChartTableCellTypeBarChart; - break; - case JBChartListViewControllerRowAreaChart: - text = kJBStringLabelAverageShineHours; - detailText = kJBStringLabelSeattle2014; - type = JBChartTableCellTypeAreaChart; - break; - default: - break; - } - cell.textLabel.text = text; - cell.detailTextLabel.text = detailText; - cell.type = type; - + cell.textLabel.text = indexPath.row == JBChartListViewControllerRowLineChart ? kJBStringLabelAverageDailyRainfall : kJBStringLabelAverageMonthlyTemperature; + cell.detailTextLabel.text = indexPath.row == JBChartListViewControllerRowLineChart ? kJBStringLabelSanFrancisco2013 : kJBStringLabelWorldwide2012; + cell.type = indexPath.row == JBChartListViewControllerRowLineChart ? JBChartTableCellTypeLineChart : JBChartTableCellTypeBarChart; return cell; } @@ -93,7 +67,7 @@ - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPa - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { [tableView deselectRowAtIndexPath:indexPath animated:YES]; - + if (indexPath.row == JBChartListViewControllerRowLineChart) { JBLineChartViewController *lineChartController = [[JBLineChartViewController alloc] init]; @@ -104,11 +78,6 @@ - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath JBBarChartViewController *barChartController = [[JBBarChartViewController alloc] init]; [self.navigationController pushViewController:barChartController animated:YES]; } - else if (indexPath.row == JBChartListViewControllerRowAreaChart) - { - JBAreaChartViewController *areaChartController = [[JBAreaChartViewController alloc] init]; - [self.navigationController pushViewController:areaChartController animated:YES]; - } } @end diff --git a/JBChartViewDemo/JBChartViewDemo/Controllers/JBLineChartViewController.m b/JBChartViewDemo/JBChartViewDemo/Controllers/JBLineChartViewController.m index f42fb4ec9..9a60e7c36 100644 --- a/JBChartViewDemo/JBChartViewDemo/Controllers/JBLineChartViewController.m +++ b/JBChartViewDemo/JBChartViewDemo/Controllers/JBLineChartViewController.m @@ -161,7 +161,7 @@ - (void)loadView [self.informationView setTextShadowColor:nil]; [self.informationView setSeparatorColor:kJBColorLineChartHeaderSeparatorColor]; [self.view addSubview:self.informationView]; - + [self.lineChartView reloadData]; } @@ -256,6 +256,12 @@ - (BOOL)lineChartView:(JBLineChartView *)lineChartView smoothLineAtLineIndex:(NS return lineIndex == JBLineChartViewLineStyleSolid; } +-(BOOL)lineChartView:(JBLineChartView *)lineChartView fillsAreaUnderLineWithIndex:(NSUInteger)lineIndex +{ + return lineIndex == JBLineChartLineSolid; +} + + #pragma mark - Buttons - (void)chartToggleButtonPressed:(id)sender diff --git a/JBChartViewDemo/JBChartViewDemo/Resources/Images/icon-area-chart.png b/JBChartViewDemo/JBChartViewDemo/Resources/Images/icon-area-chart.png deleted file mode 100644 index 0f267ba19a5a6b9e1d233c9d3ef9611e9a1bd7ca..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 650 zcmV;50(Jd~P)()fa0!;Mq5Rt*4#1VV<_Hwlhy{J1s)f?f_mZ%%O(yO* z&*mk>4>8hDaU93`JQ+`-3BVjU6)J%PGPNyW2iW%dcP3zovKg>Y`kTKE5^FP{m>MF* zW>W*C+JE4Y?KPNG)_8h5AymkoW0S!q06)cWRggdMOIofA$Q#&&fmF7@E)1kTL7u=G z?9wVb;1>!{WmQ97z^IDpq=OzcOS}ROfqM~SwbXTD zVO`vgn%16)c~(Komx9w5j8}coQGlN)a~%SED;DN-1e^sx2M5;T(CGtkcLnSmIPaNb z&`s9|>+~MD1w0PGmg0O#HzaD>jkh+i275wxXFGkwe8Bi&Ap6dhdw&cCti|jpt%o#d zZG-ubU21{J!==?918biBig_c2Qj*j~#DXqqD*{Zjec+APHwUg_Y8_R?99JU743Z`G zmGMWwF_%4BD}C!K3HXsR_Lw#u`H#33s=T&T^g>fZ;(>R*0Cs7MF^xDDbc-~hwr0WW zslaEVUDJ)jnzn2ZTTOBcYkIEBcCv?eMZ2%25d+}&`Ec5zi&WqnJ=f#{LLOebj+X*F z!@OR%fjby4l$bD)X{_*$a?`ltqm*xj7}tnCNDPSrc!+t6-L{~mJ@>~+kWNYx7OI^3 zz;eDM;0pL|+wT(Y8`L(f82Il1`*E3#g<|+RaG$)MKmpVR=3C<0#4yp8lLupLxoN=7 krv3K%{Vk#WT+GqxU+J~nR@h_u{r~^~07*qoM6N<$f`2$HssI20 diff --git a/JBChartViewDemo/JBChartViewDemo/Resources/Images/icon-area-chart@2x.png b/JBChartViewDemo/JBChartViewDemo/Resources/Images/icon-area-chart@2x.png deleted file mode 100644 index 174b96fe6ce28c6b9625ddab70126c5f0dcffe93..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1089 zcmV-H1it%;P)?YJJwK)ouvn? zc=jDpJjayKf@ncxD73OBxK!357BL|QPxCEO<5 z%r(JNNM`P)pl_!H-v^#5jO$alsUx>jg0D}+@+9E6lERH|TIihMiv{sK3@~o!1+9~U ztG20+=NPx@n}`rIw-bV|dBjyGT}Wnb)h43Tg3k$V;*MZkN#Uk$T4=rC$py`~`OIX= zg0@y8hE52+JjcyEsu*_>3tH<1OC*%FqNj^cg_}+bu9FtZ+GM(r6mCMxZH?e%g&Vs7 zoDuX7nHE|lSTb|p06rXqJ9!NUplzWkDbzXIN5lyzr*^Q`$?wbI-ot zfqen59hDp}98JN`Jp26u_A18FD4K#ldGtwuor*Cuj;7$a;p?{o%^TeI@_f*e5CMIq zu{(vPV4K0{N|=5;N)@lwS{Av;HTpc-5Sv;Y{~9? zH1S&U!4&nc`@u^7(xQ^L8D{MZFqg}cFDjKBGCEam5?x6RSSF^p>!N&epCHB*X(r(}hxUBDK9r^AHtzX47o zvSQD{88>C`#*+I_%9eT!zOdoRx8ODg)IHG^Y-_t`hWKa{S~3G7)_8569G30B4g zD`SF{F~Q21U}dC&zp6yBjgf9N_LFUI|HsOhln6*Ag8RS=vR#@9o=pU-OKK5D4Q!Fq zWz7UDV}g}2!OECmWlXR#CRmxG?~;sw41m|b0ZepgB4F(gO_nR-6hOHk00000NkvXX Hu0mjfb}$9h From e2b436a631c7cc411ca500fe67d9ada8dce5fc0b Mon Sep 17 00:00:00 2001 From: hackingotter Date: Mon, 5 May 2014 13:43:30 +0200 Subject: [PATCH 11/11] deleted outcommented code --- Classes/JBLineChartView.m | 148 -------------------------------------- 1 file changed, 148 deletions(-) diff --git a/Classes/JBLineChartView.m b/Classes/JBLineChartView.m index 3119d6407..bcc627ba3 100644 --- a/Classes/JBLineChartView.m +++ b/Classes/JBLineChartView.m @@ -1542,151 +1542,3 @@ - (id)initWithRadius:(CGFloat)radius } @end - - - -//#pragma mark - Drawing -// -//- (void)drawRect:(CGRect)rect -//{ -// NSUInteger lineIndex = 0; -// NSArray *previousLineData = nil; -// for (NSArray *lineData in chartData) -// { -// UIBezierPath *path = [UIBezierPath bezierPath]; -// path.miterLimit = kJBLineChartLinesViewMiterLimit; -// -// JBLineChartPoint *previousLineChartPoint = nil; -// CGFloat previousSlope; -// -// NSAssert([self.delegate respondsToSelector:@selector(lineChartAreasView:smoothLineAtLineIndex:)], @"JBLineChartAreasView // delegate must implement - (BOOL)lineChartAreasView:(JBLineChartAreasView *)lineChartAreasView smoothLineAtLineIndex:(NSUInteger)lineIndex"); -// BOOL smoothLine = [self.delegate lineChartAreasView:self smoothLineAtLineIndex:lineIndex]; -// BOOL previousSmoothLine = NO; -// if (lineIndex > 0) { -// previousSmoothLine = [self.delegate lineChartAreasView:self smoothLineAtLineIndex:lineIndex - 1]; -// } -// -// if (!previousLineData) { -// JBLineChartPoint *lowerRightCornor = [[JBLineChartPoint alloc] init]; -// lowerRightCornor.position = CGPointMake(self.bounds.size.width - padding, self.bounds.size.height - padding); -// JBLineChartPoint *lowerLeftCornor = [[JBLineChartPoint alloc] init]; -// lowerLeftCornor.position = CGPointMake(padding, self.bounds.size.height); -// previousLineData = @[lowerLeftCornor, lowerRightCornor]; -// } -// -// //add the previous line in inversed order at the beginning of the path to create a polygon -// NSUInteger index = 0; -// NSArray *sortedPreviousLineData = [[previousLineData reverseObjectEnumerator] allObjects]; -// for (JBLineChartPoint *lineChartPoint in sortedPreviousLineData) -// { -// if (index == 0) -// { -// [path moveToPoint:CGPointMake(lineChartPoint.position.x, fmin(self.bounds.size.height - padding, fmax(padding, lineChartPoint.position.y)))]; -// } -// else -// { -// JBLineChartPoint *nextLineChartPoint = nil; -// if (index != ([sortedPreviousLineData count] - 1)) -// { -// nextLineChartPoint = [sortedPreviousLineData objectAtIndex:(index + 1)]; -// } -// -// CGFloat nextSlope = (nextLineChartPoint != nil) ? ((nextLineChartPoint.position.y - lineChartPoint.position.y)) / ((nextLineChartPoint.position.x - lineChartPoint.position.x)) : previousSlope; -// CGFloat currentSlope = ((lineChartPoint.position.y - previousLineChartPoint.position.y)) / (lineChartPoint.position.x-previousLineChartPoint.position.x); -// -// BOOL deltaFromNextSlope = ((currentSlope >= (nextSlope + kJBLineChartLinesViewSmoothThresholdSlope)) || (currentSlope <= (nextSlope - kJBLineChartLinesViewSmoothThresholdSlope))); -// BOOL deltaFromPreviousSlope = ((currentSlope <= (previousSlope + kJBLineChartLinesViewSmoothThresholdSlope)) || (currentSlope >= (previousSlope - kJBLineChartLinesViewSmoothThresholdSlope))); -// BOOL deltaFromPreviousY = (lineChartPoint.position.y >= previousLineChartPoint.position.y + kJBLineChartLinesViewSmoothThresholdVertical) || (lineChartPoint.position.y <= previousLineChartPoint.position.y - kJBLineChartLinesViewSmoothThresholdVertical); -// -// if (previousSmoothLine && deltaFromNextSlope && deltaFromPreviousSlope && deltaFromPreviousY) -// { -// CGFloat deltaX = lineChartPoint.position.x - previousLineChartPoint.position.x; -// CGFloat controlPointX = previousLineChartPoint.position.x + (deltaX / 2); -// -// CGPoint controlPoint1 = CGPointMake(controlPointX, previousLineChartPoint.position.y); -// CGPoint controlPoint2 = CGPointMake(controlPointX, lineChartPoint.position.y); -// -// [path addCurveToPoint:CGPointMake(lineChartPoint.position.x, fmin(self.bounds.size.height - padding, fmax(padding, lineChartPoint.position.y))) controlPoint1:controlPoint1 controlPoint2:controlPoint2]; -// } -// else -// { -// [path addLineToPoint:CGPointMake(lineChartPoint.position.x, fmin(self.bounds.size.height - padding, fmax(padding, lineChartPoint.position.y)))]; -// } -// -// previousSlope = currentSlope; -// } -// previousLineChartPoint = lineChartPoint; -// index++; -// } -// -// index = 0; -// NSArray *sortedLineData = [lineData sortedArrayUsingSelector:@selector(compare:)]; -// for (JBLineChartPoint *lineChartPoint in [lineData sortedArrayUsingSelector:@selector(compare:)]) -// { -// -// if (index == 0) -// { -// [path addLineToPoint:CGPointMake(lineChartPoint.position.x, fmin(self.bounds.size.height - padding, fmax(padding, lineChartPoint.position.y)))]; -// } -// else -// { -// JBLineChartPoint *nextLineChartPoint = nil; -// if (index != ([lineData count] - 1)) -// { -// nextLineChartPoint = [sortedLineData objectAtIndex:(index + 1)]; -// } -// -// CGFloat nextSlope = (nextLineChartPoint != nil) ? ((nextLineChartPoint.position.y - lineChartPoint.position.y)) / ((nextLineChartPoint.position.x - lineChartPoint.position.x)) : previousSlope; -// CGFloat currentSlope = ((lineChartPoint.position.y - previousLineChartPoint.position.y)) / (lineChartPoint.position.x-previousLineChartPoint.position.x); -// -// BOOL deltaFromNextSlope = ((currentSlope >= (nextSlope + kJBLineChartLinesViewSmoothThresholdSlope)) || (currentSlope <= (nextSlope - kJBLineChartLinesViewSmoothThresholdSlope))); -// BOOL deltaFromPreviousSlope = ((currentSlope >= (previousSlope + kJBLineChartLinesViewSmoothThresholdSlope)) || (currentSlope <= (previousSlope - kJBLineChartLinesViewSmoothThresholdSlope))); -// BOOL deltaFromPreviousY = (lineChartPoint.position.y >= previousLineChartPoint.position.y + kJBLineChartLinesViewSmoothThresholdVertical) || (lineChartPoint.position.y <= previousLineChartPoint.position.y - kJBLineChartLinesViewSmoothThresholdVertical); -// -// if (smoothLine && deltaFromNextSlope && deltaFromPreviousSlope && deltaFromPreviousY) -// { -// CGFloat deltaX = lineChartPoint.position.x - previousLineChartPoint.position.x; -// CGFloat controlPointX = previousLineChartPoint.position.x + (deltaX / 2); -// -// CGPoint controlPoint1 = CGPointMake(controlPointX, previousLineChartPoint.position.y); -// CGPoint controlPoint2 = CGPointMake(controlPointX, lineChartPoint.position.y); -// -// [path addCurveToPoint:CGPointMake(lineChartPoint.position.x, fmin(self.bounds.size.height - padding, fmax(padding, lineChartPoint.position.y))) controlPoint1:controlPoint1 controlPoint2:controlPoint2]; -// } -// else -// { -// [path addLineToPoint:CGPointMake(lineChartPoint.position.x, fmin(self.bounds.size.height - padding, fmax(padding, lineChartPoint.position.y)))]; -// } -// -// previousSlope = currentSlope; -// } -// previousLineChartPoint = lineChartPoint; -// index++; -// -// } -// -// [path closePath]; -// -// -// -// JBAreaLayer *areaLayer = [self areaLayerForLineIndex:lineIndex]; -// if (areaLayer == nil) { -// areaLayer = [JBAreaLayer layer]; -// } -// -// areaLayer.tag = lineIndex; -// NSAssert([self.delegate respondsToSelector:@selector(lineChartAreasView:colorForAreaUnderLineAtLineIndex:)], @"JBLineChartAreasView // delegate must implement - (UIColor *)lineChartAreasView:(JBLineChartAreasView *)lineChartAreasView colorForAreaUnderLineAtLineIndex:(NSUInteger)lineIndex"); -// areaLayer.fillColor = [self.delegate lineChartAreasView:self colorForAreaUnderLineAtLineIndex:lineIndex].CGColor; -// -// -// areaLayer.path = path.CGPath; -// areaLayer.frame = self.bounds; -// [self.layer addSublayer:areaLayer]; -// -// previousLineData = lineData; -// -// lineIndex++; -// } -// -// self.animated = NO; -//}