From ee4de2b77f25ae166c53342f983a38efe6e264b5 Mon Sep 17 00:00:00 2001 From: Daniel Cohen Gindi Date: Mon, 15 Aug 2016 15:27:03 +0300 Subject: [PATCH] autoScaleMinMax is working again (Fixes #1209) --- Charts/Classes/Charts/BarChartView.swift | 5 -- .../Classes/Charts/BarLineChartViewBase.swift | 42 +++++++------- .../Implementations/ChartBaseDataSet.swift | 5 ++ .../Standard/BarChartDataSet.swift | 56 +++++++------------ .../Standard/BubbleChartDataSet.swift | 28 +++------- .../Standard/CandleChartDataSet.swift | 38 +++---------- .../Implementations/Standard/ChartData.swift | 19 ++++++- .../Standard/ChartDataSet.swift | 48 +++++++++++++--- .../Standard/CombinedChartData.swift | 10 ++-- .../Standard/PieChartDataSet.swift | 9 +-- .../Data/Interfaces/IChartDataSet.swift | 4 ++ 11 files changed, 129 insertions(+), 135 deletions(-) diff --git a/Charts/Classes/Charts/BarChartView.swift b/Charts/Classes/Charts/BarChartView.swift index d9cead9dbc..0875d00bd8 100644 --- a/Charts/Classes/Charts/BarChartView.swift +++ b/Charts/Classes/Charts/BarChartView.swift @@ -35,11 +35,6 @@ public class BarChartView: BarLineChartViewBase, BarChartDataProvider guard let data = self.data as? BarChartData else { return } - if self.autoScaleMinMaxEnabled - { - data.calcMinMax() - } - if fitBars { _xAxis.calculate( diff --git a/Charts/Classes/Charts/BarLineChartViewBase.swift b/Charts/Classes/Charts/BarLineChartViewBase.swift index f04490f8e6..4a15d0dc8c 100644 --- a/Charts/Classes/Charts/BarLineChartViewBase.swift +++ b/Charts/Classes/Charts/BarLineChartViewBase.swift @@ -25,8 +25,6 @@ public class BarLineChartViewBase: ChartViewBase, BarLineScatterCandleBubbleChar /// flag that indicates if auto scaling on the y axis is enabled private var _autoScaleMinMaxEnabled = false - private var _autoScaleLastLowestVisibleX: Double? - private var _autoScaleLastHighestVisibleX: Double? private var _pinchZoomEnabled = false private var _doubleTapToZoomEnabled = true @@ -189,20 +187,9 @@ public class BarLineChartViewBase: ChartViewBase, BarLineScatterCandleBubbleChar _leftYAxisRenderer?.renderAxisLine(context: context) _rightYAxisRenderer?.renderAxisLine(context: context) - if (_autoScaleMinMaxEnabled) + if _autoScaleMinMaxEnabled { - let lowestVisibleX = self.lowestVisibleX, - highestVisibleX = self.highestVisibleX - - if (_autoScaleLastLowestVisibleX == nil || _autoScaleLastLowestVisibleX != lowestVisibleX || - _autoScaleLastHighestVisibleX == nil || _autoScaleLastHighestVisibleX != highestVisibleX) - { - calcMinMax() - calculateOffsets() - - _autoScaleLastLowestVisibleX = lowestVisibleX - _autoScaleLastHighestVisibleX = highestVisibleX - } + autoScale() } // The renderers are responsible for clipping, to account for line-width center etc. @@ -264,6 +251,26 @@ public class BarLineChartViewBase: ChartViewBase, BarLineScatterCandleBubbleChar drawDescription(context: context) } + private var _autoScaleLastLowestVisibleX: Double? + private var _autoScaleLastHighestVisibleX: Double? + + /// Performs auto scaling of the axis by recalculating the minimum and maximum y-values based on the entries currently in view. + internal func autoScale() + { + guard let data = _data + else { return } + + data.calcMinMaxY(fromX: self.lowestVisibleX, toX: self.highestVisibleX) + + _xAxis.calculate(min: data.xMin, max: data.xMax) + + // calculate axis range (min / max) according to provided data + _leftAxis.calculate(min: data.getYMin(.Left), max: data.getYMax(.Left)) + _rightAxis.calculate(min: data.getYMin(.Right), max: data.getYMax(.Right)) + + calculateOffsets(); + } + internal func prepareValuePxMatrix() { _rightAxisTransformer.prepareMatrixValuePx(chartXMin: _xAxis._axisMinimum, deltaX: CGFloat(xAxis.axisRange), deltaY: CGFloat(_rightAxis.axisRange), chartYMin: _rightAxis._axisMinimum) @@ -305,11 +312,6 @@ public class BarLineChartViewBase: ChartViewBase, BarLineScatterCandleBubbleChar internal override func calcMinMax() { - if _autoScaleMinMaxEnabled - { - _data?.calcMinMax() - } - // calculate / set x-axis range _xAxis.calculate(min: _data?.xMin ?? 0.0, max: _data?.xMax ?? 0.0) diff --git a/Charts/Classes/Data/Implementations/ChartBaseDataSet.swift b/Charts/Classes/Data/Implementations/ChartBaseDataSet.swift index f3daa0ae36..d42f1dd7eb 100644 --- a/Charts/Classes/Data/Implementations/ChartBaseDataSet.swift +++ b/Charts/Classes/Data/Implementations/ChartBaseDataSet.swift @@ -48,6 +48,11 @@ public class ChartBaseDataSet: NSObject, IChartDataSet fatalError("calcMinMax is not implemented in ChartBaseDataSet") } + public func calcMinMaxY(fromX fromX: Double, toX: Double) + { + fatalError("calcMinMaxY(fromX:, toX:) is not implemented in ChartBaseDataSet") + } + public var yMin: Double { fatalError("yMin is not implemented in ChartBaseDataSet") diff --git a/Charts/Classes/Data/Implementations/Standard/BarChartDataSet.swift b/Charts/Classes/Data/Implementations/Standard/BarChartDataSet.swift index 7cb15880fb..58bf3b5640 100644 --- a/Charts/Classes/Data/Implementations/Standard/BarChartDataSet.swift +++ b/Charts/Classes/Data/Implementations/Standard/BarChartDataSet.swift @@ -80,57 +80,39 @@ public class BarChartDataSet: BarLineScatterCandleBubbleChartDataSet, IBarChartD } } - public override func calcMinMax() + public override func calcMinMax(entry e: ChartDataEntry) { - if _values.count == 0 - { - return - } - - _yMax = -DBL_MAX - _yMin = DBL_MAX - _xMax = -DBL_MAX - _xMin = DBL_MAX + guard let e = e as? BarChartDataEntry + else { return } - for e in _values as! [BarChartDataEntry] + if !e.y.isNaN { - if !e.y.isNaN + if e.yValues == nil { - if e.yValues == nil + if e.y < _yMin { - if e.y < _yMin - { - _yMin = e.y - } - - if e.y > _yMax - { - _yMax = e.y - } + _yMin = e.y } - else + + if e.y > _yMax { - if -e.negativeSum < _yMin - { - _yMin = -e.negativeSum - } - - if e.positiveSum > _yMax - { - _yMax = e.positiveSum - } + _yMax = e.y } - - if e.x < _xMin + } + else + { + if -e.negativeSum < _yMin { - _xMin = e.x + _yMin = -e.negativeSum } - if e.x > _xMax + if e.positiveSum > _yMax { - _xMax = e.x + _yMax = e.positiveSum } } + + calcMinMaxX(entry: e) } } diff --git a/Charts/Classes/Data/Implementations/Standard/BubbleChartDataSet.swift b/Charts/Classes/Data/Implementations/Standard/BubbleChartDataSet.swift index e98645e533..245d132c59 100644 --- a/Charts/Classes/Data/Implementations/Standard/BubbleChartDataSet.swift +++ b/Charts/Classes/Data/Implementations/Standard/BubbleChartDataSet.swift @@ -23,30 +23,18 @@ public class BubbleChartDataSet: BarLineScatterCandleBubbleChartDataSet, IBubble public var normalizeSizeEnabled: Bool = true public var isNormalizeSizeEnabled: Bool { return normalizeSizeEnabled } - public override func calcMinMax() + public override func calcMinMax(entry e: ChartDataEntry) { - if self.entryCount == 0 - { - return - } - - // need chart width to guess this properly + guard let e = e as? BubbleChartDataEntry + else { return } + + super.calcMinMax(entry: e) - _yMax = -DBL_MAX - _yMin = DBL_MAX - _xMax = -DBL_MAX - _xMin = DBL_MAX + let size = e.size - for e in values as! [BubbleChartDataEntry] + if size > _maxSize { - calcMinMax(entry: e) - - let size = e.size - - if size > _maxSize - { - _maxSize = size - } + _maxSize = size } } diff --git a/Charts/Classes/Data/Implementations/Standard/CandleChartDataSet.swift b/Charts/Classes/Data/Implementations/Standard/CandleChartDataSet.swift index bd11afcee8..debbe65c5d 100644 --- a/Charts/Classes/Data/Implementations/Standard/CandleChartDataSet.swift +++ b/Charts/Classes/Data/Implementations/Standard/CandleChartDataSet.swift @@ -28,42 +28,22 @@ public class CandleChartDataSet: LineScatterCandleRadarChartDataSet, ICandleChar // MARK: - Data functions and accessors - public override func calcMinMax() + public override func calcMinMax(entry e: ChartDataEntry) { - let yValCount = self.entryCount + guard let e = e as? CandleChartDataEntry + else { return } - if yValCount == 0 + if (e.low < _yMin) { - return + _yMin = e.low } - _yMax = -DBL_MAX - _yMin = DBL_MAX - _xMax = -DBL_MAX - _xMin = DBL_MAX - - for e in _values as! [CandleChartDataEntry] + if (e.high > _yMax) { - if (e.low < _yMin) - { - _yMin = e.low - } - - if (e.high > _yMax) - { - _yMax = e.high - } - - if (e.x < _xMin) - { - _xMin = e.x - } - - if (e.x > _xMax) - { - _xMax = e.x - } + _yMax = e.high } + + calcMinMaxX(entry: e) } // MARK: - Styling functions and accessors diff --git a/Charts/Classes/Data/Implementations/Standard/ChartData.swift b/Charts/Classes/Data/Implementations/Standard/ChartData.swift index cd4d9fa721..ce23b5e090 100644 --- a/Charts/Classes/Data/Implementations/Standard/ChartData.swift +++ b/Charts/Classes/Data/Implementations/Standard/ChartData.swift @@ -47,14 +47,25 @@ public class ChartData: NSObject internal func initialize(dataSets: [IChartDataSet]) { - calcMinMax() + notifyDataChanged() } /// Call this method to let the ChartData know that the underlying data has changed. /// Calling this performs all necessary recalculations needed when the contained data has changed. public func notifyDataChanged() { - initialize(_dataSets) + calcMinMax() + } + + public func calcMinMaxY(fromX fromX: Double, toX: Double) + { + for set in _dataSets + { + set.calcMinMaxY(fromX: fromX, toX: toX) + } + + // apply the new data + calcMinMax() } /// calc minimum and maximum y value over all datasets @@ -126,6 +137,7 @@ public class ChartData: NSObject } } + /// Adjusts the current minimum and maximum values based on the provided Entry object. public func calcMinMax(entry e: ChartDataEntry, axis: YAxis.AxisDependency) { if _yMax < e.y @@ -174,6 +186,7 @@ public class ChartData: NSObject } } + /// Adjusts the minimum and maximum values based on the given DataSet. public func calcMinMax(dataSet d: IChartDataSet) { if _yMax < d.yMax @@ -325,7 +338,7 @@ public class ChartData: NSObject set { _dataSets = newValue - initialize(_dataSets) + notifyDataChanged() } } diff --git a/Charts/Classes/Data/Implementations/Standard/ChartDataSet.swift b/Charts/Classes/Data/Implementations/Standard/ChartDataSet.swift index 26ad456d36..6a3d042917 100644 --- a/Charts/Classes/Data/Implementations/Standard/ChartDataSet.swift +++ b/Charts/Classes/Data/Implementations/Standard/ChartDataSet.swift @@ -109,19 +109,30 @@ public class ChartDataSet: ChartBaseDataSet } } - /// Updates the min and max x and y value of this DataSet based on the given Entry. - /// - /// - parameter e: - internal func calcMinMax(entry e: ChartDataEntry) + public override func calcMinMaxY(fromX fromX: Double, toX: Double) { - if e.y < _yMin + if _values.count == 0 { - _yMin = e.y + return } - if e.y > _yMax + + _yMax = -DBL_MAX + _yMin = DBL_MAX + + let indexFrom = entryIndex(x: fromX, rounding: .Down) + let indexTo = entryIndex(x: toX, rounding: .Up) + + if indexTo <= indexFrom { return } + + for i in indexFrom.. _yMax + { + _yMax = e.y + } + } + + /// Updates the min and max x and y value of this DataSet based on the given Entry. + /// + /// - parameter e: + internal func calcMinMax(entry e: ChartDataEntry) + { + calcMinMaxX(entry: e) + calcMinMaxY(entry: e) + } + /// - returns: The minimum y-value this DataSet holds public override var yMin: Double { return _yMin } diff --git a/Charts/Classes/Data/Implementations/Standard/CombinedChartData.swift b/Charts/Classes/Data/Implementations/Standard/CombinedChartData.swift index 0a10fe9f71..dee3d3839f 100644 --- a/Charts/Classes/Data/Implementations/Standard/CombinedChartData.swift +++ b/Charts/Classes/Data/Implementations/Standard/CombinedChartData.swift @@ -38,7 +38,7 @@ public class CombinedChartData: BarLineScatterCandleBubbleChartData set { _lineData = newValue - calcMinMax() + notifyDataChanged() } } @@ -51,7 +51,7 @@ public class CombinedChartData: BarLineScatterCandleBubbleChartData set { _barData = newValue - calcMinMax() + notifyDataChanged() } } @@ -64,7 +64,7 @@ public class CombinedChartData: BarLineScatterCandleBubbleChartData set { _scatterData = newValue - calcMinMax() + notifyDataChanged() } } @@ -77,7 +77,7 @@ public class CombinedChartData: BarLineScatterCandleBubbleChartData set { _candleData = newValue - calcMinMax() + notifyDataChanged() } } @@ -90,7 +90,7 @@ public class CombinedChartData: BarLineScatterCandleBubbleChartData set { _bubbleData = newValue - calcMinMax() + notifyDataChanged() } } diff --git a/Charts/Classes/Data/Implementations/Standard/PieChartDataSet.swift b/Charts/Classes/Data/Implementations/Standard/PieChartDataSet.swift index 5e1d11844a..49d71b6e13 100644 --- a/Charts/Classes/Data/Implementations/Standard/PieChartDataSet.swift +++ b/Charts/Classes/Data/Implementations/Standard/PieChartDataSet.swift @@ -41,14 +41,7 @@ public class PieChartDataSet: ChartDataSet, IPieChartDataSet internal override func calcMinMax(entry e: ChartDataEntry) { - if e.y < _yMin - { - _yMin = e.y - } - if e.y > _yMax - { - _yMax = e.y - } + calcMinMaxY(entry: e) } // MARK: - Styling functions and accessors diff --git a/Charts/Classes/Data/Interfaces/IChartDataSet.swift b/Charts/Classes/Data/Interfaces/IChartDataSet.swift index 66cf2d8f6c..e64d3139b7 100644 --- a/Charts/Classes/Data/Interfaces/IChartDataSet.swift +++ b/Charts/Classes/Data/Interfaces/IChartDataSet.swift @@ -22,6 +22,10 @@ public protocol IChartDataSet /// Calculates the minimum and maximum x and y values (_xMin, _xMax, _yMin, _yMax). func calcMinMax() + /// Calculates the min and max y-values from the Entry closest to the given fromX to the Entry closest to the given toX value. + /// This is only needed for the autoScaleMinMax feature. + func calcMinMaxY(fromX fromX: Double, toX: Double) + /// - returns: The minimum y-value this DataSet holds var yMin: Double { get }