From 70cd5bde276ddf6cb32e057e6755cabfcc411944 Mon Sep 17 00:00:00 2001 From: Enrico Zamagni Date: Fri, 26 Feb 2016 11:36:25 +0100 Subject: [PATCH] Feature #539 Stepped line charts A new flag was added to ILineChartDataSet and relative implementations. The value of the flag is then used to slightly modify the behavior of drawLinear and generateFilledPath in LineChartRenderer. The appropriate demo viewControllers were also updated with the new flag. --- .../Standard/LineChartDataSet.swift | 7 ++++ .../Data/Interfaces/ILineChartDataSet.swift | 6 ++++ .../Classes/Renderers/LineChartRenderer.swift | 36 +++++++++++++------ .../Classes/Demos/LineChart1ViewController.m | 11 ++++++ .../Classes/Demos/LineChart2ViewController.m | 11 ++++++ .../Demos/MultipleLinesChartViewController.m | 11 ++++++ .../RealmDemos/RealmLineChartViewController.m | 11 ++++++ .../Classes/Data/RealmLineDataSet.swift | 7 ++++ 8 files changed, 90 insertions(+), 10 deletions(-) diff --git a/Charts/Classes/Data/Implementations/Standard/LineChartDataSet.swift b/Charts/Classes/Data/Implementations/Standard/LineChartDataSet.swift index 6886428701..05b7938040 100644 --- a/Charts/Classes/Data/Implementations/Standard/LineChartDataSet.swift +++ b/Charts/Classes/Data/Implementations/Standard/LineChartDataSet.swift @@ -67,8 +67,14 @@ public class LineChartDataSet: LineRadarChartDataSet, ILineChartDataSet /// If true, cubic lines are drawn instead of linear public var drawCubicEnabled = false + /// If true, stepped lines are drawn instead of linear + public var drawSteppedEnabled = false + /// - returns: true if drawing cubic lines is enabled, false if not. public var isDrawCubicEnabled: Bool { return drawCubicEnabled } + + /// - returns: true if drawing stepped lines is enabled, false if not. + public var isDrawSteppedEnabled: Bool { return drawSteppedEnabled } /// The radius of the drawn circles. public var circleRadius = CGFloat(8.0) @@ -160,6 +166,7 @@ public class LineChartDataSet: LineRadarChartDataSet, ILineChartDataSet copy.lineDashLengths = lineDashLengths copy.drawCirclesEnabled = drawCirclesEnabled copy.drawCubicEnabled = drawCubicEnabled + copy.drawSteppedEnabled = drawSteppedEnabled return copy } } diff --git a/Charts/Classes/Data/Interfaces/ILineChartDataSet.swift b/Charts/Classes/Data/Interfaces/ILineChartDataSet.swift index f6fb8312f1..4bb237f064 100644 --- a/Charts/Classes/Data/Interfaces/ILineChartDataSet.swift +++ b/Charts/Classes/Data/Interfaces/ILineChartDataSet.swift @@ -28,9 +28,15 @@ public protocol ILineChartDataSet: ILineRadarChartDataSet /// If true, cubic lines are drawn instead of linear var drawCubicEnabled: Bool { get set } + /// If true, stepped lines are drawn instead of linear + var drawSteppedEnabled: Bool { get set } + /// - returns: true if drawing cubic lines is enabled, false if not. var isDrawCubicEnabled: Bool { get } + /// - returns: true if drawing stepped lines is enabled, false if not. + var isDrawSteppedEnabled: Bool { get } + /// The radius of the drawn circles. var circleRadius: CGFloat { get set } diff --git a/Charts/Classes/Renderers/LineChartRenderer.swift b/Charts/Classes/Renderers/LineChartRenderer.swift index 2d685e2511..2884a03ab1 100644 --- a/Charts/Classes/Renderers/LineChartRenderer.swift +++ b/Charts/Classes/Renderers/LineChartRenderer.swift @@ -245,6 +245,7 @@ public class LineChartRenderer: LineRadarChartRenderer let valueToPixelMatrix = trans.valueToPixelMatrix let entryCount = dataSet.entryCount + let pointsPerEntryPair = dataSet.isDrawSteppedEnabled ? 4 : 2 let phaseX = animator.phaseX let phaseY = animator.phaseY @@ -263,9 +264,9 @@ public class LineChartRenderer: LineRadarChartRenderer // more than 1 color if (dataSet.colors.count > 1) { - if (_lineSegments.count != 2) + if (_lineSegments.count != pointsPerEntryPair) { - _lineSegments = [CGPoint](count: 2, repeatedValue: CGPoint()) + _lineSegments = [CGPoint](count: pointsPerEntryPair, repeatedValue: CGPoint()) } for (var j = minx, count = Int(ceil(CGFloat(maxx - minx) * phaseX + CGFloat(minx))); j < count; j++) @@ -281,21 +282,28 @@ public class LineChartRenderer: LineRadarChartRenderer _lineSegments[0].x = CGFloat(e.xIndex) _lineSegments[0].y = CGFloat(e.value) * phaseY - _lineSegments[0] = CGPointApplyAffineTransform(_lineSegments[0], valueToPixelMatrix) if (j + 1 < count) { e = dataSet.entryForIndex(j + 1) if e == nil { break } - _lineSegments[1].x = CGFloat(e.xIndex) - _lineSegments[1].y = CGFloat(e.value) * phaseY - _lineSegments[1] = CGPointApplyAffineTransform(_lineSegments[1], valueToPixelMatrix) + if dataSet.isDrawSteppedEnabled { + _lineSegments[1] = CGPoint(x: CGFloat(e.xIndex), y: _lineSegments[0].y) + _lineSegments[2] = _lineSegments[1] + _lineSegments[3] = CGPoint(x: CGFloat(e.xIndex), y: CGFloat(e.value) * phaseY) + } else { + _lineSegments[1] = CGPoint(x: CGFloat(e.xIndex), y: CGFloat(e.value) * phaseY) + } } else { _lineSegments[1] = _lineSegments[0] } + + for i in 0..<_lineSegments.count { + _lineSegments[i] = CGPointApplyAffineTransform(_lineSegments[i], valueToPixelMatrix) + } if (!viewPortHandler.isInBoundsRight(_lineSegments[0].x)) { @@ -312,7 +320,7 @@ public class LineChartRenderer: LineRadarChartRenderer // get the color that is set for this line-segment CGContextSetStrokeColorWithColor(context, dataSet.colorAt(j).CGColor) - CGContextStrokeLineSegments(context, _lineSegments, 2) + CGContextStrokeLineSegments(context, _lineSegments, pointsPerEntryPair) } } else @@ -321,9 +329,9 @@ public class LineChartRenderer: LineRadarChartRenderer var e1: ChartDataEntry! var e2: ChartDataEntry! - if (_lineSegments.count != max((entryCount - 1) * 2, 2)) + if (_lineSegments.count != max((entryCount - 1) * pointsPerEntryPair, pointsPerEntryPair)) { - _lineSegments = [CGPoint](count: max((entryCount - 1) * 2, 2), repeatedValue: CGPoint()) + _lineSegments = [CGPoint](count: max((entryCount - 1) * pointsPerEntryPair, pointsPerEntryPair), repeatedValue: CGPoint()) } e1 = dataSet.entryForIndex(minx) @@ -340,10 +348,14 @@ public class LineChartRenderer: LineRadarChartRenderer if e1 == nil || e2 == nil { continue } _lineSegments[j++] = CGPointApplyAffineTransform(CGPoint(x: CGFloat(e1.xIndex), y: CGFloat(e1.value) * phaseY), valueToPixelMatrix) + if dataSet.isDrawSteppedEnabled { + _lineSegments[j++] = CGPointApplyAffineTransform(CGPoint(x: CGFloat(e2.xIndex), y: CGFloat(e1.value) * phaseY), valueToPixelMatrix) + _lineSegments[j++] = CGPointApplyAffineTransform(CGPoint(x: CGFloat(e2.xIndex), y: CGFloat(e1.value) * phaseY), valueToPixelMatrix) + } _lineSegments[j++] = CGPointApplyAffineTransform(CGPoint(x: CGFloat(e2.xIndex), y: CGFloat(e2.value) * phaseY), valueToPixelMatrix) } - let size = max((count - minx - 1) * 2, 2) + let size = max((count - minx - 1) * pointsPerEntryPair, pointsPerEntryPair) CGContextSetStrokeColorWithColor(context, dataSet.colorAt(0).CGColor) CGContextStrokeLineSegments(context, _lineSegments, size) } @@ -400,6 +412,10 @@ public class LineChartRenderer: LineRadarChartRenderer for (var x = from + 1, count = Int(ceil(CGFloat(to - from) * phaseX + CGFloat(from))); x < count; x++) { guard let e = dataSet.entryForIndex(x) else { continue } + if dataSet.isDrawSteppedEnabled { + guard let ePrev = dataSet.entryForIndex(x-1) else { continue } + CGPathAddLineToPoint(filled, &matrix, CGFloat(e.xIndex), CGFloat(ePrev.value) * phaseY) + } CGPathAddLineToPoint(filled, &matrix, CGFloat(e.xIndex), CGFloat(e.value) * phaseY) } diff --git a/ChartsDemo/Classes/Demos/LineChart1ViewController.m b/ChartsDemo/Classes/Demos/LineChart1ViewController.m index 911c1a18b8..dd75095490 100644 --- a/ChartsDemo/Classes/Demos/LineChart1ViewController.m +++ b/ChartsDemo/Classes/Demos/LineChart1ViewController.m @@ -37,6 +37,7 @@ - (void)viewDidLoad @{@"key": @"toggleFilled", @"label": @"Toggle Filled"}, @{@"key": @"toggleCircles", @"label": @"Toggle Circles"}, @{@"key": @"toggleCubic", @"label": @"Toggle Cubic"}, + @{@"key": @"toggleStepped", @"label": @"Toggle Stepped"}, @{@"key": @"toggleHighlight", @"label": @"Toggle Highlight"}, @{@"key": @"animateX", @"label": @"Animate X"}, @{@"key": @"animateY", @"label": @"Animate Y"}, @@ -201,6 +202,16 @@ - (void)optionTapped:(NSString *)key [_chartView setNeedsDisplay]; } + + if ([key isEqualToString:@"toggleStepped"]) + { + for (id set in _chartView.data.dataSets) + { + set.drawSteppedEnabled = !set.isDrawSteppedEnabled; + } + + [_chartView setNeedsDisplay]; + } if ([key isEqualToString:@"toggleHighlight"]) { diff --git a/ChartsDemo/Classes/Demos/LineChart2ViewController.m b/ChartsDemo/Classes/Demos/LineChart2ViewController.m index 8cf162319d..3ca56add33 100644 --- a/ChartsDemo/Classes/Demos/LineChart2ViewController.m +++ b/ChartsDemo/Classes/Demos/LineChart2ViewController.m @@ -37,6 +37,7 @@ - (void)viewDidLoad @{@"key": @"toggleFilled", @"label": @"Toggle Filled"}, @{@"key": @"toggleCircles", @"label": @"Toggle Circles"}, @{@"key": @"toggleCubic", @"label": @"Toggle Cubic"}, + @{@"key": @"toggleStepped", @"label": @"Toggle Stepped"}, @{@"key": @"toggleHighlight", @"label": @"Toggle Highlight"}, @{@"key": @"animateX", @"label": @"Animate X"}, @{@"key": @"animateY", @"label": @"Animate Y"}, @@ -197,6 +198,16 @@ - (void)optionTapped:(NSString *)key [_chartView setNeedsDisplay]; } + + if ([key isEqualToString:@"toggleStepped"]) + { + for (id set in _chartView.data.dataSets) + { + set.drawSteppedEnabled = !set.isDrawSteppedEnabled; + } + + [_chartView setNeedsDisplay]; + } if ([key isEqualToString:@"toggleHighlight"]) { diff --git a/ChartsDemo/Classes/Demos/MultipleLinesChartViewController.m b/ChartsDemo/Classes/Demos/MultipleLinesChartViewController.m index 03fb8c980f..59ceffe802 100644 --- a/ChartsDemo/Classes/Demos/MultipleLinesChartViewController.m +++ b/ChartsDemo/Classes/Demos/MultipleLinesChartViewController.m @@ -37,6 +37,7 @@ - (void)viewDidLoad @{@"key": @"toggleFilled", @"label": @"Toggle Filled"}, @{@"key": @"toggleCircles", @"label": @"Toggle Circles"}, @{@"key": @"toggleCubic", @"label": @"Toggle Cubic"}, + @{@"key": @"toggleStepped", @"label": @"Toggle Stepped"}, @{@"key": @"toggleHighlight", @"label": @"Toggle Highlight"}, @{@"key": @"animateX", @"label": @"Animate X"}, @{@"key": @"animateY", @"label": @"Animate Y"}, @@ -161,6 +162,16 @@ - (void)optionTapped:(NSString *)key [_chartView setNeedsDisplay]; } + + if ([key isEqualToString:@"toggleStepped"]) + { + for (id set in _chartView.data.dataSets) + { + set.drawSteppedEnabled = !set.isDrawSteppedEnabled; + } + + [_chartView setNeedsDisplay]; + } if ([key isEqualToString:@"toggleHighlight"]) { diff --git a/ChartsDemo/Classes/RealmDemos/RealmLineChartViewController.m b/ChartsDemo/Classes/RealmDemos/RealmLineChartViewController.m index 78e45a5d39..7139465948 100644 --- a/ChartsDemo/Classes/RealmDemos/RealmLineChartViewController.m +++ b/ChartsDemo/Classes/RealmDemos/RealmLineChartViewController.m @@ -37,6 +37,7 @@ - (void)viewDidLoad @{@"key": @"toggleFilled", @"label": @"Toggle Filled"}, @{@"key": @"toggleCircles", @"label": @"Toggle Circles"}, @{@"key": @"toggleCubic", @"label": @"Toggle Cubic"}, + @{@"key": @"toggleStepped", @"label": @"Toggle Stepped"}, @{@"key": @"toggleHighlight", @"label": @"Toggle Highlight"}, @{@"key": @"animateX", @"label": @"Animate X"}, @{@"key": @"animateY", @"label": @"Animate Y"}, @@ -134,6 +135,16 @@ - (void)optionTapped:(NSString *)key [_chartView setNeedsDisplay]; } + if ([key isEqualToString:@"toggleStepped"]) + { + for (id set in _chartView.data.dataSets) + { + set.drawSteppedEnabled = !set.isDrawSteppedEnabled; + } + + [_chartView setNeedsDisplay]; + } + if ([key isEqualToString:@"toggleHighlight"]) { _chartView.data.highlightEnabled = !_chartView.data.isHighlightEnabled; diff --git a/ChartsRealm/Classes/Data/RealmLineDataSet.swift b/ChartsRealm/Classes/Data/RealmLineDataSet.swift index 055a801b9e..205e5b6cec 100644 --- a/ChartsRealm/Classes/Data/RealmLineDataSet.swift +++ b/ChartsRealm/Classes/Data/RealmLineDataSet.swift @@ -60,6 +60,12 @@ public class RealmLineDataSet: RealmLineRadarDataSet, ILineChartDataSet /// - returns: true if drawing cubic lines is enabled, false if not. public var isDrawCubicEnabled: Bool { return drawCubicEnabled } + /// If true, stepped lines are drawn instead of linear + public var drawSteppedEnabled = false + + /// - returns: true if drawing stepped lines is enabled, false if not. + public var isDrawSteppedEnabled: Bool { return drawSteppedEnabled } + /// The radius of the drawn circles. public var circleRadius = CGFloat(8.0) @@ -150,6 +156,7 @@ public class RealmLineDataSet: RealmLineRadarDataSet, ILineChartDataSet copy.lineDashLengths = lineDashLengths copy.drawCirclesEnabled = drawCirclesEnabled copy.drawCubicEnabled = drawCubicEnabled + copy.drawSteppedEnabled = drawSteppedEnabled return copy }