Преглед изворни кода

Update libraries for iOS 16

jonfawcett пре 3 година
родитељ
комит
cbafc08df9
100 измењених фајлова са 3580 додато и 4225 уклоњено
  1. 1 1
      LoopFollow.xcodeproj/xcuserdata/jon.xcuserdatad/xcschemes/xcschememanagement.plist
  2. BIN
      LoopFollow.xcworkspace/xcuserdata/jon.xcuserdatad/UserInterfaceState.xcuserstate
  3. 25 24
      LoopFollow/Controllers/Graphs.swift
  4. 8 8
      LoopFollow/helpers/Chart.swift
  5. 12 8
      Podfile.lock
  6. 21 9
      Pods/Charts/README.md
  7. 1 1
      Pods/Charts/Source/Charts/Animation/ChartAnimationEasing.swift
  8. 8 8
      Pods/Charts/Source/Charts/Charts/BarChartView.swift
  9. 142 153
      Pods/Charts/Source/Charts/Charts/BarLineChartViewBase.swift
  10. 2 2
      Pods/Charts/Source/Charts/Charts/BubbleChartView.swift
  11. 2 2
      Pods/Charts/Source/Charts/Charts/CandleStickChartView.swift
  12. 176 328
      Pods/Charts/Source/Charts/Charts/ChartViewBase.swift
  13. 10 10
      Pods/Charts/Source/Charts/Charts/CombinedChartView.swift
  14. 26 27
      Pods/Charts/Source/Charts/Charts/HorizontalBarChartView.swift
  15. 2 2
      Pods/Charts/Source/Charts/Charts/LineChartView.swift
  16. 31 46
      Pods/Charts/Source/Charts/Charts/PieChartView.swift
  17. 21 22
      Pods/Charts/Source/Charts/Charts/PieRadarChartViewBase.swift
  18. 20 21
      Pods/Charts/Source/Charts/Charts/RadarChartView.swift
  19. 2 2
      Pods/Charts/Source/Charts/Charts/ScatterChartView.swift
  20. 10 24
      Pods/Charts/Source/Charts/Components/AxisBase.swift
  21. 5 5
      Pods/Charts/Source/Charts/Components/ChartLimitLine.swift
  22. 1 1
      Pods/Charts/Source/Charts/Components/Description.swift
  23. 9 11
      Pods/Charts/Source/Charts/Components/Legend.swift
  24. 6 21
      Pods/Charts/Source/Charts/Components/LegendEntry.swift
  25. 1 1
      Pods/Charts/Source/Charts/Components/MarkerImage.swift
  26. 4 5
      Pods/Charts/Source/Charts/Components/MarkerView.swift
  27. 2 2
      Pods/Charts/Source/Charts/Components/YAxis.swift
  28. 10 32
      Pods/Charts/Source/Charts/Data/Implementations/ChartBaseDataSet.swift
  29. 13 12
      Pods/Charts/Source/Charts/Data/Implementations/Standard/BarChartData.swift
  30. 9 25
      Pods/Charts/Source/Charts/Data/Implementations/Standard/BarChartDataEntry.swift
  31. 21 54
      Pods/Charts/Source/Charts/Data/Implementations/Standard/BarChartDataSet.swift
  32. 7 2
      Pods/Charts/Source/Charts/Data/Implementations/Standard/BarLineScatterCandleBubbleChartData.swift
  33. 1 1
      Pods/Charts/Source/Charts/Data/Implementations/Standard/BarLineScatterCandleBubbleChartDataSet.swift
  34. 9 4
      Pods/Charts/Source/Charts/Data/Implementations/Standard/BubbleChartData.swift
  35. 2 7
      Pods/Charts/Source/Charts/Data/Implementations/Standard/BubbleChartDataSet.swift
  36. 7 2
      Pods/Charts/Source/Charts/Data/Implementations/Standard/CandleChartData.swift
  37. 14 33
      Pods/Charts/Source/Charts/Data/Implementations/Standard/CandleChartDataSet.swift
  38. 324 360
      Pods/Charts/Source/Charts/Data/Implementations/Standard/ChartData.swift
  39. 88 173
      Pods/Charts/Source/Charts/Data/Implementations/Standard/ChartDataSet.swift
  40. 74 83
      Pods/Charts/Source/Charts/Data/Implementations/Standard/CombinedChartData.swift
  41. 7 2
      Pods/Charts/Source/Charts/Data/Implementations/Standard/LineChartData.swift
  42. 10 6
      Pods/Charts/Source/Charts/Data/Implementations/Standard/LineChartDataSet.swift
  43. 1 1
      Pods/Charts/Source/Charts/Data/Implementations/Standard/LineRadarChartDataSet.swift
  44. 1 1
      Pods/Charts/Source/Charts/Data/Implementations/Standard/LineScatterCandleRadarChartDataSet.swift
  45. 27 44
      Pods/Charts/Source/Charts/Data/Implementations/Standard/PieChartData.swift
  46. 6 11
      Pods/Charts/Source/Charts/Data/Implementations/Standard/PieChartDataSet.swift
  47. 10 5
      Pods/Charts/Source/Charts/Data/Implementations/Standard/RadarChartData.swift
  48. 2 2
      Pods/Charts/Source/Charts/Data/Implementations/Standard/RadarChartDataSet.swift
  49. 8 3
      Pods/Charts/Source/Charts/Data/Implementations/Standard/ScatterChartData.swift
  50. 4 4
      Pods/Charts/Source/Charts/Data/Implementations/Standard/ScatterChartDataSet.swift
  51. 3 3
      Pods/Charts/Source/Charts/Filters/DataApproximator+N.swift
  52. 4 4
      Pods/Charts/Source/Charts/Filters/DataApproximator.swift
  53. 1 1
      Pods/Charts/Source/Charts/Formatters/DefaultAxisValueFormatter.swift
  54. 3 3
      Pods/Charts/Source/Charts/Formatters/DefaultFillFormatter.swift
  55. 38 30
      Pods/Charts/Source/Charts/Formatters/DefaultValueFormatter.swift
  56. 4 18
      Pods/Charts/Source/Charts/Formatters/IndexAxisValueFormatter.swift
  57. 5 4
      Pods/Charts/Source/Charts/Highlight/BarHighlighter.swift
  58. 6 11
      Pods/Charts/Source/Charts/Highlight/ChartHighlighter.swift
  59. 4 9
      Pods/Charts/Source/Charts/Highlight/CombinedHighlighter.swift
  60. 3 3
      Pods/Charts/Source/Charts/Highlight/HorizontalBarHighlighter.swift
  61. 1 1
      Pods/Charts/Source/Charts/Highlight/PieHighlighter.swift
  62. 7 18
      Pods/Charts/Source/Charts/Highlight/RadarHighlighter.swift
  63. 0 6
      Pods/Charts/Source/Charts/Jobs/AnimatedMoveViewJob.swift
  64. 5 5
      Pods/Charts/Source/Charts/Jobs/AnimatedViewPortJob.swift
  65. 12 18
      Pods/Charts/Source/Charts/Jobs/AnimatedZoomViewJob.swift
  66. 1 7
      Pods/Charts/Source/Charts/Jobs/MoveViewJob.swift
  67. 9 9
      Pods/Charts/Source/Charts/Jobs/ViewPortJob.swift
  68. 6 11
      Pods/Charts/Source/Charts/Jobs/ZoomViewJob.swift
  69. 224 293
      Pods/Charts/Source/Charts/Renderers/BarChartRenderer.swift
  70. 38 9
      Pods/Charts/Source/Charts/Renderers/BarLineScatterCandleBubbleRenderer.swift
  71. 29 28
      Pods/Charts/Source/Charts/Renderers/BubbleChartRenderer.swift
  72. 24 27
      Pods/Charts/Source/Charts/Renderers/CandleStickChartRenderer.swift
  73. 30 38
      Pods/Charts/Source/Charts/Renderers/CombinedChartRenderer.swift
  74. 46 51
      Pods/Charts/Source/Charts/Renderers/HorizontalBarChartRenderer.swift
  75. 82 107
      Pods/Charts/Source/Charts/Renderers/LegendRenderer.swift
  76. 260 143
      Pods/Charts/Source/Charts/Renderers/LineChartRenderer.swift
  77. 1 1
      Pods/Charts/Source/Charts/Renderers/LineScatterCandleRadarRenderer.swift
  78. 123 127
      Pods/Charts/Source/Charts/Renderers/PieChartRenderer.swift
  79. 36 42
      Pods/Charts/Source/Charts/Renderers/RadarChartRenderer.swift
  80. 3 9
      Pods/Charts/Source/Charts/Renderers/Renderer.swift
  81. 2 2
      Pods/Charts/Source/Charts/Renderers/Scatter/ChevronDownShapeRenderer.swift
  82. 2 2
      Pods/Charts/Source/Charts/Renderers/Scatter/ChevronUpShapeRenderer.swift
  83. 2 2
      Pods/Charts/Source/Charts/Renderers/Scatter/CircleShapeRenderer.swift
  84. 2 2
      Pods/Charts/Source/Charts/Renderers/Scatter/CrossShapeRenderer.swift
  85. 2 2
      Pods/Charts/Source/Charts/Renderers/Scatter/SquareShapeRenderer.swift
  86. 2 2
      Pods/Charts/Source/Charts/Renderers/Scatter/TriangleShapeRenderer.swift
  87. 2 2
      Pods/Charts/Source/Charts/Renderers/Scatter/XShapeRenderer.swift
  88. 29 38
      Pods/Charts/Source/Charts/Renderers/ScatterChartRenderer.swift
  89. 276 236
      Pods/Charts/Source/Charts/Renderers/XAxisRenderer.swift
  90. 120 186
      Pods/Charts/Source/Charts/Renderers/XAxisRendererHorizontalBarChart.swift
  91. 21 30
      Pods/Charts/Source/Charts/Renderers/XAxisRendererRadarChart.swift
  92. 238 178
      Pods/Charts/Source/Charts/Renderers/YAxisRenderer.swift
  93. 114 188
      Pods/Charts/Source/Charts/Renderers/YAxisRendererHorizontalBarChart.swift
  94. 60 121
      Pods/Charts/Source/Charts/Renderers/YAxisRendererRadarChart.swift
  95. 24 28
      Pods/Charts/Source/Charts/Utils/ChartColorTemplates.swift
  96. 83 96
      Pods/Charts/Source/Charts/Utils/ChartUtils.swift
  97. 159 272
      Pods/Charts/Source/Charts/Utils/Fill.swift
  98. 8 13
      Pods/Charts/Source/Charts/Utils/Platform+Accessibility.swift
  99. 223 178
      Pods/Charts/Source/Charts/Utils/Platform.swift
  100. 0 0
      Pods/Charts/Source/Charts/Utils/Transformer.swift

+ 1 - 1
LoopFollow.xcodeproj/xcuserdata/jon.xcuserdatad/xcschemes/xcschememanagement.plist

@@ -7,7 +7,7 @@
 		<key>LoopFollow.xcscheme_^#shared#^_</key>
 		<dict>
 			<key>orderHint</key>
-			<integer>4</integer>
+			<integer>5</integer>
 		</dict>
 	</dict>
 </dict>

BIN
LoopFollow.xcworkspace/xcuserdata/jon.xcuserdatad/UserInterfaceState.xcuserstate


+ 25 - 24
LoopFollow/Controllers/Graphs.swift

@@ -269,18 +269,19 @@ extension MainViewController {
         
         // Setup the chart data of all lines
         let data = LineChartData()
-        data.addDataSet(lineBG) // Dataset 0
-        data.addDataSet(linePrediction) // Dataset 1
-        data.addDataSet(lineBasal) // Dataset 2
-        data.addDataSet(lineBolus) // Dataset 3
-        data.addDataSet(lineCarbs) // Dataset 4
-        data.addDataSet(lineBasalScheduled) // Dataset 5
-        data.addDataSet(lineOverride) // Dataset 6
-        data.addDataSet(lineBGCheck) // Dataset 7
-        data.addDataSet(lineSuspend) // Dataset 8
-        data.addDataSet(lineResume) // Dataset 9
-        data.addDataSet(lineSensor) // Dataset 10
-        data.addDataSet(lineNote) // Dataset 11
+        
+        data.append(lineBG) // Dataset 0
+        data.append(linePrediction) // Dataset 1
+        data.append(lineBasal) // Dataset 2
+        data.append(lineBolus) // Dataset 3
+        data.append(lineCarbs) // Dataset 4
+        data.append(lineBasalScheduled) // Dataset 5
+        data.append(lineOverride) // Dataset 6
+        data.append(lineBGCheck) // Dataset 7
+        data.append(lineSuspend) // Dataset 8
+        data.append(lineResume) // Dataset 9
+        data.append(lineSensor) // Dataset 10
+        data.append(lineNote) // Dataset 11
         
         data.setValueFont(UIFont.systemFont(ofSize: 12))
         
@@ -1137,18 +1138,18 @@ extension MainViewController {
         
         // Setup the chart data of all lines
         let data = LineChartData()
-        data.addDataSet(lineBG) // Dataset 0
-        data.addDataSet(linePrediction) // Dataset 1
-        data.addDataSet(lineBasal) // Dataset 2
-        data.addDataSet(lineBolus) // Dataset 3
-        data.addDataSet(lineCarbs) // Dataset 4
-        data.addDataSet(lineBasalScheduled) // Dataset 5
-        data.addDataSet(lineOverride) // Dataset 6
-        data.addDataSet(lineBGCheck) // Dataset 7
-        data.addDataSet(lineSuspend) // Dataset 8
-        data.addDataSet(lineResume) // Dataset 9
-        data.addDataSet(lineSensor) // Dataset 10
-        data.addDataSet(lineNote) // Dataset 11
+        data.append(lineBG) // Dataset 0
+        data.append(linePrediction) // Dataset 1
+        data.append(lineBasal) // Dataset 2
+        data.append(lineBolus) // Dataset 3
+        data.append(lineCarbs) // Dataset 4
+        data.append(lineBasalScheduled) // Dataset 5
+        data.append(lineOverride) // Dataset 6
+        data.append(lineBGCheck) // Dataset 7
+        data.append(lineSuspend) // Dataset 8
+        data.append(lineResume) // Dataset 9
+        data.append(lineSensor) // Dataset 10
+        data.append(lineNote) // Dataset 11
         
         BGChartFull.highlightPerDragEnabled = true
         BGChartFull.leftAxis.enabled = false

+ 8 - 8
LoopFollow/helpers/Chart.swift

@@ -9,20 +9,20 @@
 import Foundation
 import Charts
 
-final class OverrideFillFormatter: IFillFormatter {
-    func getFillLinePosition(dataSet: ILineChartDataSet, dataProvider: LineChartDataProvider) -> CGFloat {
+final class OverrideFillFormatter: FillFormatter {
+    func getFillLinePosition(dataSet: Charts.LineChartDataSetProtocol, dataProvider: Charts.LineChartDataProvider) -> CGFloat {
         return CGFloat(dataSet.entryForIndex(0)!.y)
         //return 375
     }
 }
 
-final class basalFillFormatter: IFillFormatter {
-    func getFillLinePosition(dataSet: ILineChartDataSet, dataProvider: LineChartDataProvider) -> CGFloat {
+final class basalFillFormatter: FillFormatter {
+    func getFillLinePosition(dataSet: Charts.LineChartDataSetProtocol, dataProvider: Charts.LineChartDataProvider) -> CGFloat {
         return 0
     }
 }
 
-final class ChartXValueFormatter: IAxisValueFormatter {
+final class ChartXValueFormatter: AxisValueFormatter {
     
 
     func stringForValue(_ value: Double, axis: AxisBase?) -> String {
@@ -44,7 +44,7 @@ final class ChartXValueFormatter: IAxisValueFormatter {
     }
 }
 
-final class ChartYDataValueFormatter: IValueFormatter {
+final class ChartYDataValueFormatter: ValueFormatter {
     func stringForValue(_ value: Double, entry: ChartDataEntry, dataSetIndex: Int, viewPortHandler: ViewPortHandler?) -> String {
         if entry.data != nil {
             return entry.data as? String ?? ""
@@ -54,7 +54,7 @@ final class ChartYDataValueFormatter: IValueFormatter {
     }
 }
 
-final class ChartYOverrideValueFormatter: IValueFormatter {
+final class ChartYOverrideValueFormatter: ValueFormatter {
     func stringForValue(_ value: Double, entry: ChartDataEntry, dataSetIndex: Int, viewPortHandler: ViewPortHandler?) -> String {
         if entry.data != nil {
             return entry.data as? String ?? ""
@@ -64,7 +64,7 @@ final class ChartYOverrideValueFormatter: IValueFormatter {
     }
 }
 
-final class ChartYMMOLValueFormatter: IAxisValueFormatter {
+final class ChartYMMOLValueFormatter: AxisValueFormatter {
     func stringForValue(_ value: Double, axis: AxisBase?) -> String {
         return bgUnits.toDisplayUnits(String(value))
     }

+ 12 - 8
Podfile.lock

@@ -1,9 +1,11 @@
 PODS:
-  - Charts (3.6.0):
-    - Charts/Core (= 3.6.0)
-  - Charts/Core (3.6.0)
-  - Eureka (5.3.4)
+  - Charts (4.1.0):
+    - Charts/Core (= 4.1.0)
+  - Charts/Core (4.1.0):
+    - SwiftAlgorithms (~> 1.0)
+  - Eureka (5.3.6)
   - ShareClient (1.2)
+  - SwiftAlgorithms (1.0.0)
 
 DEPENDENCIES:
   - Charts
@@ -13,6 +15,7 @@ DEPENDENCIES:
 SPEC REPOS:
   trunk:
     - Charts
+    - SwiftAlgorithms
 
 EXTERNAL SOURCES:
   Eureka:
@@ -23,17 +26,18 @@ EXTERNAL SOURCES:
 
 CHECKOUT OPTIONS:
   Eureka:
-    :commit: 94475e83a6965320283b8b39986e7481ad675ab9
+    :commit: 044e31674d319c8edb19d993a5f8ea4e24641542
     :git: https://github.com/xmartlabs/Eureka.git
   ShareClient:
     :commit: 2dfaf101ed528e2a92f3791f5384ed368dc7144a
     :git: https://github.com/jonfawcett/dexcom-share-client-swift.git
 
 SPEC CHECKSUMS:
-  Charts: b1e3a1f5a1c9ba5394438ca3b91bd8c9076310af
-  Eureka: 60cf058f86a8fb3ed26165ba5292b9850361b0a6
+  Charts: 354f86803d11d9c35de280587fef50d1af063978
+  Eureka: 28ad9dec6286cd7cd601fdf8e8df39bb7356a8f4
   ShareClient: 08a3e6b9889b41172b98c4e386d23084bafbeec4
+  SwiftAlgorithms: 38dda4731d19027fdeee1125f973111bf3386b53
 
 PODFILE CHECKSUM: 084f5ab2f55c59ed2c2fa3cdaaa9590c99a95408
 
-COCOAPODS: 1.9.3
+COCOAPODS: 1.11.3

Разлика између датотеке није приказан због своје велике величине
+ 21 - 9
Pods/Charts/README.md


+ 1 - 1
Pods/Charts/Source/Charts/Animation/ChartAnimationEasing.swift

@@ -341,7 +341,7 @@ internal struct EasingFunctions
         let s: TimeInterval = 1.70158
         var position: TimeInterval = elapsed / duration
         position -= 1.0
-        return Double( position * position * ((s + 1.0) * position + s) + 1.0 )
+        return Double( position * position * ((s + Double(1.0)) * position + s) + Double(1.0) )
     }
     
     internal static let EaseInOutBack = { (elapsed: TimeInterval, duration: TimeInterval) -> Double in

+ 8 - 8
Pods/Charts/Source/Charts/Charts/BarChartView.swift

@@ -25,7 +25,7 @@ open class BarChartView: BarLineChartViewBase, BarChartDataProvider
     {
         super.initialize()
         
-        renderer = BarChartRenderer(dataProvider: self, animator: _animator, viewPortHandler: _viewPortHandler)
+        renderer = BarChartRenderer(dataProvider: self, animator: chartAnimator, viewPortHandler: viewPortHandler)
         
         self.highlighter = BarHighlighter(chart: self)
         
@@ -40,13 +40,13 @@ open class BarChartView: BarLineChartViewBase, BarChartDataProvider
         
         if fitBars
         {
-            _xAxis.calculate(
+            xAxis.calculate(
                 min: data.xMin - data.barWidth / 2.0,
                 max: data.xMax + data.barWidth / 2.0)
         }
         else
         {
-            _xAxis.calculate(min: data.xMin, max: data.xMax)
+            xAxis.calculate(min: data.xMin, max: data.xMax)
         }
         
         // calculate axis range (min / max) according to provided data
@@ -61,7 +61,7 @@ open class BarChartView: BarLineChartViewBase, BarChartDataProvider
     /// - Returns: The Highlight object (contains x-index and DataSet index) of the selected value at the given touch point inside the BarChart.
     open override func getHighlightByTouchPoint(_ pt: CGPoint) -> Highlight?
     {
-        if _data === nil
+        if data === nil
         {
             Swift.print("Can't select by touch. No data set.")
             return nil
@@ -86,9 +86,9 @@ open class BarChartView: BarLineChartViewBase, BarChartDataProvider
     @objc open func getBarBounds(entry e: BarChartDataEntry) -> CGRect
     {
         guard let
-            data = _data as? BarChartData,
-            let set = data.getDataSetForEntry(e) as? IBarChartDataSet
-            else { return CGRect.null }
+            data = data as? BarChartData,
+            let set = data.getDataSetForEntry(e) as? BarChartDataSetProtocol
+            else { return .null }
         
         let y = e.y
         let x = e.x
@@ -176,7 +176,7 @@ open class BarChartView: BarLineChartViewBase, BarChartDataProvider
     
     // MARK: - BarChartDataProvider
     
-    open var barData: BarChartData? { return _data as? BarChartData }
+    open var barData: BarChartData? { return data as? BarChartData }
     
     /// `true` if drawing values above bars is enabled, `false` ifnot
     open var isDrawValueAboveBarEnabled: Bool { return drawValueAboveBarEnabled }

+ 142 - 153
Pods/Charts/Source/Charts/Charts/BarLineChartViewBase.swift

@@ -9,15 +9,13 @@
 //  https://github.com/danielgindi/Charts
 //
 
-import Foundation
 import CoreGraphics
+import Foundation
 
 #if canImport(UIKit)
-    import UIKit
-#endif
-
-#if canImport(Cocoa)
-import Cocoa
+import UIKit
+#elseif canImport(AppKit)
+import AppKit
 #endif
 
 /// Base-class of LineChart, BarChart, ScatterChart and CandleStickChart.
@@ -76,19 +74,19 @@ open class BarLineChartViewBase: ChartViewBase, BarLineScatterCandleBubbleChartD
 
     /// The left Y axis renderer. This is a read-write property so you can set your own custom renderer here.
     /// **default**: An instance of YAxisRenderer
-    @objc open lazy var leftYAxisRenderer = YAxisRenderer(viewPortHandler: _viewPortHandler, yAxis: leftAxis, transformer: _leftAxisTransformer)
+    @objc open lazy var leftYAxisRenderer = YAxisRenderer(viewPortHandler: viewPortHandler, axis: leftAxis, transformer: _leftAxisTransformer)
 
     /// The right Y axis renderer. This is a read-write property so you can set your own custom renderer here.
     /// **default**: An instance of YAxisRenderer
-    @objc open lazy var rightYAxisRenderer = YAxisRenderer(viewPortHandler: _viewPortHandler, yAxis: rightAxis, transformer: _rightAxisTransformer)
-    
+    @objc open lazy var rightYAxisRenderer = YAxisRenderer(viewPortHandler: viewPortHandler, axis: rightAxis, transformer: _rightAxisTransformer)
+
     internal var _leftAxisTransformer: Transformer!
     internal var _rightAxisTransformer: Transformer!
     
     /// The X axis renderer. This is a read-write property so you can set your own custom renderer here.
     /// **default**: An instance of XAxisRenderer
-    @objc open lazy var xAxisRenderer = XAxisRenderer(viewPortHandler: _viewPortHandler, xAxis: _xAxis, transformer: _leftAxisTransformer)
-    
+    @objc open lazy var xAxisRenderer = XAxisRenderer(viewPortHandler: viewPortHandler, axis: xAxis, transformer: _leftAxisTransformer)
+
     internal var _tapGestureRecognizer: NSUITapGestureRecognizer!
     internal var _doubleTapGestureRecognizer: NSUITapGestureRecognizer!
     #if !os(tvOS)
@@ -118,9 +116,9 @@ open class BarLineChartViewBase: ChartViewBase, BarLineScatterCandleBubbleChartD
     {
         super.initialize()
 
-        _leftAxisTransformer = Transformer(viewPortHandler: _viewPortHandler)
-        _rightAxisTransformer = Transformer(viewPortHandler: _viewPortHandler)
-        
+        _leftAxisTransformer = Transformer(viewPortHandler: viewPortHandler)
+        _rightAxisTransformer = Transformer(viewPortHandler: viewPortHandler)
+
         self.highlighter = ChartHighlighter(chart: self)
         
         _tapGestureRecognizer = NSUITapGestureRecognizer(target: self, action: #selector(tapGestureRecognized(_:)))
@@ -138,10 +136,10 @@ open class BarLineChartViewBase: ChartViewBase, BarLineScatterCandleBubbleChartD
         _panGestureRecognizer.isEnabled = _dragXEnabled || _dragYEnabled
 
         #if !os(tvOS)
-        _pinchGestureRecognizer = NSUIPinchGestureRecognizer(target: self, action: #selector(BarLineChartViewBase.pinchGestureRecognized(_:)))
-        _pinchGestureRecognizer.delegate = self
-        self.addGestureRecognizer(_pinchGestureRecognizer)
-        _pinchGestureRecognizer.isEnabled = _pinchZoomEnabled || _scaleXEnabled || _scaleYEnabled
+            _pinchGestureRecognizer = NSUIPinchGestureRecognizer(target: self, action: #selector(BarLineChartViewBase.pinchGestureRecognized(_:)))
+            _pinchGestureRecognizer.delegate = self
+            self.addGestureRecognizer(_pinchGestureRecognizer)
+            _pinchGestureRecognizer.isEnabled = _pinchZoomEnabled || _scaleXEnabled || _scaleYEnabled
         #endif
     }
     
@@ -198,9 +196,9 @@ open class BarLineChartViewBase: ChartViewBase, BarLineScatterCandleBubbleChartD
             rightYAxisRenderer.computeAxis(min: rightAxis._axisMinimum, max: rightAxis._axisMaximum, inverted: rightAxis.isInverted)
         }
         
-        if _xAxis.isEnabled
+        if xAxis.isEnabled
         {
-            xAxisRenderer.computeAxis(min: _xAxis._axisMinimum, max: _xAxis._axisMaximum, inverted: false)
+            xAxisRenderer.computeAxis(min: xAxis._axisMinimum, max: xAxis._axisMaximum, inverted: false)
         }
         
         xAxisRenderer.renderAxisLine(context: context)
@@ -215,7 +213,7 @@ open class BarLineChartViewBase: ChartViewBase, BarLineScatterCandleBubbleChartD
             rightYAxisRenderer.renderGridLines(context: context)
         }
         
-        if _xAxis.isEnabled && _xAxis.isDrawLimitLinesBehindDataEnabled
+        if xAxis.isEnabled && xAxis.isDrawLimitLinesBehindDataEnabled
         {
             xAxisRenderer.renderLimitLines(context: context)
         }
@@ -231,10 +229,12 @@ open class BarLineChartViewBase: ChartViewBase, BarLineScatterCandleBubbleChartD
         }
         
         context.saveGState()
+
         // make sure the data cannot be drawn outside the content-rect
         if clipDataToContentEnabled {
-            context.clip(to: _viewPortHandler.contentRect)
+            context.clip(to: viewPortHandler.contentRect)
         }
+
         renderer.drawData(context: context)
         
         // The renderers are responsible for clipping, to account for line-width center etc.
@@ -248,14 +248,14 @@ open class BarLineChartViewBase: ChartViewBase, BarLineScatterCandleBubbleChartD
         // if highlighting is enabled
         if (valuesToHighlight())
         {
-            renderer.drawHighlighted(context: context, indices: _indicesToHighlight)
+            renderer.drawHighlighted(context: context, indices: highlighted)
         }
         
         context.restoreGState()
         
         renderer.drawExtras(context: context)
         
-        if _xAxis.isEnabled && !_xAxis.isDrawLimitLinesBehindDataEnabled
+        if xAxis.isEnabled && !xAxis.isDrawLimitLinesBehindDataEnabled
         {
             xAxisRenderer.renderLimitLines(context: context)
         }
@@ -277,7 +277,7 @@ open class BarLineChartViewBase: ChartViewBase, BarLineScatterCandleBubbleChartD
         if clipValuesToContentEnabled
         {
             context.saveGState()
-            context.clip(to: _viewPortHandler.contentRect)
+            context.clip(to: viewPortHandler.contentRect)
             
             renderer.drawValues(context: context)
             
@@ -288,9 +288,9 @@ open class BarLineChartViewBase: ChartViewBase, BarLineScatterCandleBubbleChartD
             renderer.drawValues(context: context)
         }
 
-        _legendRenderer.renderLegend(context: context)
+        legendRenderer.renderLegend(context: context)
 
-        drawDescription(context: context)
+        drawDescription(in: context)
         
         drawMarkers(context: context)
     }
@@ -301,12 +301,12 @@ open class BarLineChartViewBase: ChartViewBase, BarLineScatterCandleBubbleChartD
     /// 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
+        guard let data = data
             else { return }
         
         data.calcMinMaxY(fromX: self.lowestVisibleX, toX: self.highestVisibleX)
         
-        _xAxis.calculate(min: data.xMin, max: data.xMax)
+        xAxis.calculate(min: data.xMin, max: data.xMax)
         
         // calculate axis range (min / max) according to provided data
         
@@ -325,7 +325,7 @@ open class BarLineChartViewBase: ChartViewBase, BarLineScatterCandleBubbleChartD
     
     internal func prepareValuePxMatrix()
     {
-        _rightAxisTransformer.prepareMatrixValuePx(chartXMin: _xAxis._axisMinimum, deltaX: CGFloat(xAxis.axisRange), deltaY: CGFloat(rightAxis.axisRange), chartYMin: rightAxis._axisMinimum)
+        _rightAxisTransformer.prepareMatrixValuePx(chartXMin: xAxis._axisMinimum, deltaX: CGFloat(xAxis.axisRange), deltaY: CGFloat(rightAxis.axisRange), chartYMin: rightAxis._axisMinimum)
         _leftAxisTransformer.prepareMatrixValuePx(chartXMin: xAxis._axisMinimum, deltaX: CGFloat(xAxis.axisRange), deltaY: CGFloat(leftAxis.axisRange), chartYMin: leftAxis._axisMinimum)
     }
     
@@ -344,17 +344,14 @@ open class BarLineChartViewBase: ChartViewBase, BarLineScatterCandleBubbleChartD
         leftYAxisRenderer.computeAxis(min: leftAxis._axisMinimum, max: leftAxis._axisMaximum, inverted: leftAxis.isInverted)
         rightYAxisRenderer.computeAxis(min: rightAxis._axisMinimum, max: rightAxis._axisMaximum, inverted: rightAxis.isInverted)
         
-        if let data = _data
+        if let data = data
         {
             xAxisRenderer.computeAxis(
-                min: _xAxis._axisMinimum,
-                max: _xAxis._axisMaximum,
+                min: xAxis._axisMinimum,
+                max: xAxis._axisMaximum,
                 inverted: false)
 
-            if _legend !== nil
-            {
-                legendRenderer?.computeLegend(data: data)
-            }
+            legendRenderer.computeLegend(data: data)
         }
         
         calculateOffsets()
@@ -365,39 +362,39 @@ open class BarLineChartViewBase: ChartViewBase, BarLineScatterCandleBubbleChartD
     internal override func calcMinMax()
     {
         // calculate / set x-axis range
-        _xAxis.calculate(min: _data?.xMin ?? 0.0, max: _data?.xMax ?? 0.0)
+        xAxis.calculate(min: data?.xMin ?? 0.0, max: data?.xMax ?? 0.0)
         
         // calculate axis range (min / max) according to provided data
-        leftAxis.calculate(min: _data?.getYMin(axis: .left) ?? 0.0, max: _data?.getYMax(axis: .left) ?? 0.0)
-        rightAxis.calculate(min: _data?.getYMin(axis: .right) ?? 0.0, max: _data?.getYMax(axis: .right) ?? 0.0)
+        leftAxis.calculate(min: data?.getYMin(axis: .left) ?? 0.0, max: data?.getYMax(axis: .left) ?? 0.0)
+        rightAxis.calculate(min: data?.getYMin(axis: .right) ?? 0.0, max: data?.getYMax(axis: .right) ?? 0.0)
     }
     
     internal func calculateLegendOffsets(offsetLeft: inout CGFloat, offsetTop: inout CGFloat, offsetRight: inout CGFloat, offsetBottom: inout CGFloat)
     {
         // setup offsets for legend
-        if _legend !== nil && _legend.isEnabled && !_legend.drawInside
+        if legend.isEnabled, !legend.drawInside
         {
-            switch _legend.orientation
+            switch legend.orientation
             {
             case .vertical:
                 
-                switch _legend.horizontalAlignment
+                switch legend.horizontalAlignment
                 {
                 case .left:
-                    offsetLeft += min(_legend.neededWidth, _viewPortHandler.chartWidth * _legend.maxSizePercent) + _legend.xOffset
+                    offsetLeft += min(legend.neededWidth, viewPortHandler.chartWidth * legend.maxSizePercent) + legend.xOffset
                     
                 case .right:
-                    offsetRight += min(_legend.neededWidth, _viewPortHandler.chartWidth * _legend.maxSizePercent) + _legend.xOffset
+                    offsetRight += min(legend.neededWidth, viewPortHandler.chartWidth * legend.maxSizePercent) + legend.xOffset
                     
                 case .center:
                     
-                    switch _legend.verticalAlignment
+                    switch legend.verticalAlignment
                     {
                     case .top:
-                        offsetTop += min(_legend.neededHeight, _viewPortHandler.chartHeight * _legend.maxSizePercent) + _legend.yOffset
+                        offsetTop += min(legend.neededHeight, viewPortHandler.chartHeight * legend.maxSizePercent) + legend.yOffset
                         
                     case .bottom:
-                        offsetBottom += min(_legend.neededHeight, _viewPortHandler.chartHeight * _legend.maxSizePercent) + _legend.yOffset
+                        offsetBottom += min(legend.neededHeight, viewPortHandler.chartHeight * legend.maxSizePercent) + legend.yOffset
                         
                     default:
                         break
@@ -406,13 +403,13 @@ open class BarLineChartViewBase: ChartViewBase, BarLineScatterCandleBubbleChartD
                 
             case .horizontal:
                 
-                switch _legend.verticalAlignment
+                switch legend.verticalAlignment
                 {
                 case .top:
-                    offsetTop += min(_legend.neededHeight, _viewPortHandler.chartHeight * _legend.maxSizePercent) + _legend.yOffset
+                    offsetTop += min(legend.neededHeight, viewPortHandler.chartHeight * legend.maxSizePercent) + legend.yOffset
                     
                 case .bottom:
-                    offsetBottom += min(_legend.neededHeight, _viewPortHandler.chartHeight * _legend.maxSizePercent) + _legend.yOffset
+                    offsetBottom += min(legend.neededHeight, viewPortHandler.chartHeight * legend.maxSizePercent) + legend.yOffset
                     
                 default:
                     break
@@ -471,7 +468,7 @@ open class BarLineChartViewBase: ChartViewBase, BarLineScatterCandleBubbleChartD
             offsetBottom += self.extraBottomOffset
             offsetLeft += self.extraLeftOffset
 
-            _viewPortHandler.restrainViewPort(
+            viewPortHandler.restrainViewPort(
                 offsetLeft: max(self.minOffset, offsetLeft),
                 offsetTop: max(self.minOffset, offsetTop),
                 offsetRight: max(self.minOffset, offsetRight),
@@ -494,14 +491,14 @@ open class BarLineChartViewBase: ChartViewBase, BarLineScatterCandleBubbleChartD
         {
             // draw the grid background
             context.setFillColor(gridBackgroundColor.cgColor)
-            context.fill(_viewPortHandler.contentRect)
+            context.fill(viewPortHandler.contentRect)
         }
         
         if drawBordersEnabled
         {
             context.setLineWidth(borderLineWidth)
             context.setStrokeColor(borderColor.cgColor)
-            context.stroke(_viewPortHandler.contentRect)
+            context.stroke(viewPortHandler.contentRect)
         }
         
         if drawGridBackgroundEnabled || drawBordersEnabled
@@ -522,7 +519,7 @@ open class BarLineChartViewBase: ChartViewBase, BarLineScatterCandleBubbleChartD
     private var _isDragging = false
     private var _isScaling = false
     private var _gestureScaleAxis = GestureScaleAxis.both
-    private var _closestDataSetToTouch: IChartDataSet!
+    private var _closestDataSetToTouch: ChartDataSetProtocol!
     private var _panGestureReachedEdge: Bool = false
     private weak var _outerScrollView: NSUIScrollView?
     
@@ -534,7 +531,7 @@ open class BarLineChartViewBase: ChartViewBase, BarLineScatterCandleBubbleChartD
     
     @objc private func tapGestureRecognized(_ recognizer: NSUITapGestureRecognizer)
     {
-        if _data === nil
+        if data === nil
         {
             return
         }
@@ -560,31 +557,28 @@ open class BarLineChartViewBase: ChartViewBase, BarLineScatterCandleBubbleChartD
     
     @objc private func doubleTapGestureRecognized(_ recognizer: NSUITapGestureRecognizer)
     {
-        if _data === nil
+        if data === nil
         {
             return
         }
         
         if recognizer.state == NSUIGestureRecognizerState.ended
         {
-            if _data !== nil && _doubleTapToZoomEnabled && (data?.entryCount ?? 0) > 0
+            if data !== nil && _doubleTapToZoomEnabled && (data?.entryCount ?? 0) > 0
             {
                 var location = recognizer.location(in: self)
-                location.x = location.x - _viewPortHandler.offsetLeft
+                location.x = location.x - viewPortHandler.offsetLeft
                 
                 if isTouchInverted()
                 {
-                    location.y = -(location.y - _viewPortHandler.offsetTop)
+                    location.y = -(location.y - viewPortHandler.offsetTop)
                 }
                 else
                 {
-                    location.y = -(self.bounds.size.height - location.y - _viewPortHandler.offsetBottom)
+                    location.y = -(self.bounds.size.height - location.y - viewPortHandler.offsetBottom)
                 }
-
-                let scaleX: CGFloat = isScaleXEnabled ? 1.4 : 1.0
-                let scaleY: CGFloat = isScaleYEnabled ? 1.4 : 1.0
-
-                self.zoom(scaleX: scaleX, scaleY: scaleY, x: location.x, y: location.y)
+                
+                self.zoom(scaleX: isScaleXEnabled ? 1.4 : 1.0, scaleY: isScaleYEnabled ? 1.4 : 1.0, x: location.x, y: location.y)
                 delegate?.chartScaled?(self, scaleX: scaleX, scaleY: scaleY)
             }
         }
@@ -597,7 +591,7 @@ open class BarLineChartViewBase: ChartViewBase, BarLineScatterCandleBubbleChartD
         {
             stopDeceleration()
             
-            if _data !== nil &&
+            if data !== nil &&
                 (_pinchZoomEnabled || _scaleXEnabled || _scaleYEnabled)
             {
                 _isScaling = true
@@ -637,8 +631,8 @@ open class BarLineChartViewBase: ChartViewBase, BarLineScatterCandleBubbleChartD
         else if recognizer.state == NSUIGestureRecognizerState.changed
         {
             let isZoomingOut = (recognizer.nsuiScale < 1)
-            var canZoomMoreX = isZoomingOut ? _viewPortHandler.canZoomOutMoreX : _viewPortHandler.canZoomInMoreX
-            var canZoomMoreY = isZoomingOut ? _viewPortHandler.canZoomOutMoreY : _viewPortHandler.canZoomInMoreY
+            var canZoomMoreX = isZoomingOut ? viewPortHandler.canZoomOutMoreX : viewPortHandler.canZoomInMoreX
+            var canZoomMoreY = isZoomingOut ? viewPortHandler.canZoomOutMoreY : viewPortHandler.canZoomInMoreY
             
             if _isScaling
             {
@@ -647,15 +641,15 @@ open class BarLineChartViewBase: ChartViewBase, BarLineScatterCandleBubbleChartD
                 if canZoomMoreX || canZoomMoreY
                 {
                     var location = recognizer.location(in: self)
-                    location.x = location.x - _viewPortHandler.offsetLeft
+                    location.x = location.x - viewPortHandler.offsetLeft
                     
                     if isTouchInverted()
                     {
-                        location.y = -(location.y - _viewPortHandler.offsetTop)
+                        location.y = -(location.y - viewPortHandler.offsetTop)
                     }
                     else
                     {
-                        location.y = -(_viewPortHandler.chartHeight - location.y - _viewPortHandler.offsetBottom)
+                        location.y = -(viewPortHandler.chartHeight - location.y - viewPortHandler.offsetBottom)
                     }
                     
                     let scaleX = canZoomMoreX ? recognizer.nsuiScale : 1.0
@@ -665,10 +659,10 @@ open class BarLineChartViewBase: ChartViewBase, BarLineScatterCandleBubbleChartD
                     matrix = matrix.scaledBy(x: scaleX, y: scaleY)
                     matrix = matrix.translatedBy(x: -location.x, y: -location.y)
                     
-                    matrix = _viewPortHandler.touchMatrix.concatenating(matrix)
-                    
-                    _viewPortHandler.refresh(newMatrix: matrix, chart: self, invalidate: true)
+                    matrix = viewPortHandler.touchMatrix.concatenating(matrix)
                     
+                    viewPortHandler.refresh(newMatrix: matrix, chart: self, invalidate: true)
+
                     if delegate !== nil
                     {
                         delegate?.chartScaled?(self, scaleX: scaleX, scaleY: scaleY)
@@ -687,7 +681,7 @@ open class BarLineChartViewBase: ChartViewBase, BarLineScatterCandleBubbleChartD
         {
             stopDeceleration()
             
-            if _data === nil || !self.isDragEnabled
+            if data === nil || !self.isDragEnabled
             { // If we have no data, we have nothing to pan and no data to highlight
                 return
             }
@@ -739,6 +733,10 @@ open class BarLineChartViewBase: ChartViewBase, BarLineScatterCandleBubbleChartD
                 // We will only handle highlights on NSUIGestureRecognizerState.Changed
                 
                 _isDragging = false
+                
+                // Prevent the parent scroll view from scrolling
+                _outerScrollView?.nsuiIsScrollEnabled = false
+
             }
         }
         else if recognizer.state == NSUIGestureRecognizerState.changed
@@ -790,8 +788,6 @@ open class BarLineChartViewBase: ChartViewBase, BarLineScatterCandleBubbleChartD
                 }
                 
                 _isDragging = false
-                
-                delegate?.chartViewDidEndPanning?(self)
             }
             
             if _outerScrollView !== nil
@@ -799,6 +795,8 @@ open class BarLineChartViewBase: ChartViewBase, BarLineScatterCandleBubbleChartD
                 _outerScrollView?.nsuiIsScrollEnabled = true
                 _outerScrollView = nil
             }
+
+            delegate?.chartViewDidEndPanning?(self)
         }
     }
     
@@ -818,12 +816,12 @@ open class BarLineChartViewBase: ChartViewBase, BarLineScatterCandleBubbleChartD
             }
         }
         
-        let originalMatrix = _viewPortHandler.touchMatrix
+        let originalMatrix = viewPortHandler.touchMatrix
         
         var matrix = CGAffineTransform(translationX: translation.x, y: translation.y)
         matrix = originalMatrix.concatenating(matrix)
         
-        matrix = _viewPortHandler.refresh(newMatrix: matrix, chart: self, invalidate: true)
+        matrix = viewPortHandler.refresh(newMatrix: matrix, chart: self, invalidate: true)
         
         if matrix != originalMatrix
         {
@@ -888,7 +886,7 @@ open class BarLineChartViewBase: ChartViewBase, BarLineScatterCandleBubbleChartD
         if gestureRecognizer == _panGestureRecognizer
         {
             let velocity = _panGestureRecognizer.velocity(in: self)
-            if _data === nil || !isDragEnabled ||
+            if data === nil || !isDragEnabled ||
                 (self.hasNoDragOffset && self.isFullyZoomedOut && !self.isHighlightPerDragEnabled) ||
                 (!_dragYEnabled && abs(velocity.y) > abs(velocity.x)) ||
                 (!_dragXEnabled && abs(velocity.y) < abs(velocity.x))
@@ -899,13 +897,13 @@ open class BarLineChartViewBase: ChartViewBase, BarLineScatterCandleBubbleChartD
         else
         {
             #if !os(tvOS)
-            if gestureRecognizer == _pinchGestureRecognizer
-            {
-                if _data === nil || (!_pinchZoomEnabled && !_scaleXEnabled && !_scaleYEnabled)
+                if gestureRecognizer == _pinchGestureRecognizer
                 {
-                    return false
+                    if data === nil || (!_pinchZoomEnabled && !_scaleXEnabled && !_scaleYEnabled)
+                    {
+                        return false
+                    }
                 }
-            }
             #endif
         }
         
@@ -913,7 +911,7 @@ open class BarLineChartViewBase: ChartViewBase, BarLineScatterCandleBubbleChartD
     }
     
     #if !os(OSX)
-    open override func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool
+    open override func gestureRecognizerShouldBegin(_ gestureRecognizer: NSUIGestureRecognizer) -> Bool
     {
         if !super.gestureRecognizerShouldBegin(gestureRecognizer)
         {
@@ -925,7 +923,7 @@ open class BarLineChartViewBase: ChartViewBase, BarLineScatterCandleBubbleChartD
     #endif
     
     #if os(OSX)
-    public func gestureRecognizerShouldBegin(gestureRecognizer: NSGestureRecognizer) -> Bool
+    public func gestureRecognizerShouldBegin(gestureRecognizer: NSUIGestureRecognizer) -> Bool
     {
         return nsuiGestureRecognizerShouldBegin(gestureRecognizer)
     }
@@ -934,11 +932,11 @@ open class BarLineChartViewBase: ChartViewBase, BarLineScatterCandleBubbleChartD
     open func gestureRecognizer(_ gestureRecognizer: NSUIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: NSUIGestureRecognizer) -> Bool
     {
         #if !os(tvOS)
-        if ((gestureRecognizer is NSUIPinchGestureRecognizer && otherGestureRecognizer is NSUIPanGestureRecognizer) ||
-            (gestureRecognizer is NSUIPanGestureRecognizer && otherGestureRecognizer is NSUIPinchGestureRecognizer))
-        {
-            return true
-        }
+            if ((gestureRecognizer is NSUIPinchGestureRecognizer && otherGestureRecognizer is NSUIPanGestureRecognizer) ||
+                (gestureRecognizer is NSUIPanGestureRecognizer && otherGestureRecognizer is NSUIPinchGestureRecognizer))
+            {
+                return true
+            }
         #endif
         
         if gestureRecognizer is NSUIPanGestureRecognizer,
@@ -986,10 +984,10 @@ open class BarLineChartViewBase: ChartViewBase, BarLineScatterCandleBubbleChartD
     /// Zooms in by 1.4, into the charts center.
     @objc open func zoomIn()
     {
-        let center = _viewPortHandler.contentCenter
+        let center = viewPortHandler.contentCenter
         
-        let matrix = _viewPortHandler.zoomIn(x: center.x, y: -center.y)
-        _viewPortHandler.refresh(newMatrix: matrix, chart: self, invalidate: false)
+        let matrix = viewPortHandler.zoomIn(x: center.x, y: -center.y)
+        viewPortHandler.refresh(newMatrix: matrix, chart: self, invalidate: false)
         
         // Range might have changed, which means that Y-axis labels could have changed in size, affecting Y-axis size. So we need to recalculate offsets.
         calculateOffsets()
@@ -999,10 +997,10 @@ open class BarLineChartViewBase: ChartViewBase, BarLineScatterCandleBubbleChartD
     /// Zooms out by 0.7, from the charts center.
     @objc open func zoomOut()
     {
-        let center = _viewPortHandler.contentCenter
+        let center = viewPortHandler.contentCenter
         
-        let matrix = _viewPortHandler.zoomOut(x: center.x, y: -center.y)
-        _viewPortHandler.refresh(newMatrix: matrix, chart: self, invalidate: false)
+        let matrix = viewPortHandler.zoomOut(x: center.x, y: -center.y)
+        viewPortHandler.refresh(newMatrix: matrix, chart: self, invalidate: false)
 
         // Range might have changed, which means that Y-axis labels could have changed in size, affecting Y-axis size. So we need to recalculate offsets.
         calculateOffsets()
@@ -1012,9 +1010,9 @@ open class BarLineChartViewBase: ChartViewBase, BarLineScatterCandleBubbleChartD
     /// Zooms out to original size.
     @objc open func resetZoom()
     {
-        let matrix = _viewPortHandler.resetZoom()
-        _viewPortHandler.refresh(newMatrix: matrix, chart: self, invalidate: false)
-        
+        let matrix = viewPortHandler.resetZoom()
+        viewPortHandler.refresh(newMatrix: matrix, chart: self, invalidate: false)
+
         // Range might have changed, which means that Y-axis labels could have changed in size, affecting Y-axis size. So we need to recalculate offsets.
         calculateOffsets()
         setNeedsDisplay()
@@ -1034,9 +1032,9 @@ open class BarLineChartViewBase: ChartViewBase, BarLineScatterCandleBubbleChartD
                x: CGFloat,
                y: CGFloat)
     {
-        let matrix = _viewPortHandler.zoom(scaleX: scaleX, scaleY: scaleY, x: x, y: -y)
-        _viewPortHandler.refresh(newMatrix: matrix, chart: self, invalidate: false)
-        
+        let matrix = viewPortHandler.zoom(scaleX: scaleX, scaleY: scaleY, x: x, y: -y)
+        viewPortHandler.refresh(newMatrix: matrix, chart: self, invalidate: false)
+
         // Range might have changed, which means that Y-axis labels could have changed in size, affecting Y-axis size. So we need to recalculate offsets.
         calculateOffsets()
         setNeedsDisplay()
@@ -1119,7 +1117,7 @@ open class BarLineChartViewBase: ChartViewBase, BarLineScatterCandleBubbleChartD
             transformer: getTransformer(forAxis: axis),
             view: self,
             yAxis: getAxis(axis),
-            xAxisRange: _xAxis.axisRange,
+            xAxisRange: xAxis.axisRange,
             scaleX: scaleX,
             scaleY: scaleY,
             xOrigin: viewPortHandler.scaleX,
@@ -1180,8 +1178,8 @@ open class BarLineChartViewBase: ChartViewBase, BarLineScatterCandleBubbleChartD
     /// Resets all zooming and dragging and makes the chart fit exactly it's bounds.
     @objc open func fitScreen()
     {
-        let matrix = _viewPortHandler.fitScreen()
-        _viewPortHandler.refresh(newMatrix: matrix, chart: self, invalidate: false)
+        let matrix = viewPortHandler.fitScreen()
+        viewPortHandler.refresh(newMatrix: matrix, chart: self, invalidate: false)
         
         calculateOffsets()
         setNeedsDisplay()
@@ -1190,8 +1188,8 @@ open class BarLineChartViewBase: ChartViewBase, BarLineScatterCandleBubbleChartD
     /// Sets the minimum scale value to which can be zoomed out. 1 = fitScreen
     @objc open func setScaleMinima(_ scaleX: CGFloat, scaleY: CGFloat)
     {
-        _viewPortHandler.setMinimumScaleX(scaleX)
-        _viewPortHandler.setMinimumScaleY(scaleY)
+        viewPortHandler.setMinimumScaleX(scaleX)
+        viewPortHandler.setMinimumScaleY(scaleY)
     }
     
     @objc open var visibleXRange: Double
@@ -1206,8 +1204,8 @@ open class BarLineChartViewBase: ChartViewBase, BarLineScatterCandleBubbleChartD
     /// If you call this method, chart must have data or it has no effect.
     @objc open func setVisibleXRangeMaximum(_ maxXRange: Double)
     {
-        let xScale = _xAxis.axisRange / maxXRange
-        _viewPortHandler.setMinimumScaleX(CGFloat(xScale))
+        let xScale = xAxis.axisRange / maxXRange
+        viewPortHandler.setMinimumScaleX(CGFloat(xScale))
     }
     
     /// Sets the size of the area (range on the x-axis) that should be minimum visible at once (no further zooming in allowed).
@@ -1217,8 +1215,8 @@ open class BarLineChartViewBase: ChartViewBase, BarLineScatterCandleBubbleChartD
     /// If you call this method, chart must have data or it has no effect.
     @objc open func setVisibleXRangeMinimum(_ minXRange: Double)
     {
-        let xScale = _xAxis.axisRange / minXRange
-        _viewPortHandler.setMaximumScaleX(CGFloat(xScale))
+        let xScale = xAxis.axisRange / minXRange
+        viewPortHandler.setMaximumScaleX(CGFloat(xScale))
     }
 
     /// Limits the maximum and minimum value count that can be visible by pinching and zooming.
@@ -1229,9 +1227,9 @@ open class BarLineChartViewBase: ChartViewBase, BarLineScatterCandleBubbleChartD
     /// If you call this method, chart must have data or it has no effect.
     @objc open func setVisibleXRange(minXRange: Double, maxXRange: Double)
     {
-        let minScale = _xAxis.axisRange / maxXRange
-        let maxScale = _xAxis.axisRange / minXRange
-        _viewPortHandler.setMinMaxScaleX(
+        let minScale = xAxis.axisRange / maxXRange
+        let maxScale = xAxis.axisRange / minXRange
+        viewPortHandler.setMinMaxScaleX(
             minScaleX: CGFloat(minScale),
             maxScaleX: CGFloat(maxScale))
     }
@@ -1244,7 +1242,7 @@ open class BarLineChartViewBase: ChartViewBase, BarLineScatterCandleBubbleChartD
     @objc open func setVisibleYRangeMaximum(_ maxYRange: Double, axis: YAxis.AxisDependency)
     {
         let yScale = getAxisRange(axis: axis) / maxYRange
-        _viewPortHandler.setMinimumScaleY(CGFloat(yScale))
+        viewPortHandler.setMinimumScaleY(CGFloat(yScale))
     }
     
     /// Sets the size of the area (range on the y-axis) that should be minimum visible at once, no further zooming in possible.
@@ -1255,7 +1253,7 @@ open class BarLineChartViewBase: ChartViewBase, BarLineScatterCandleBubbleChartD
     @objc open func setVisibleYRangeMinimum(_ minYRange: Double, axis: YAxis.AxisDependency)
     {
         let yScale = getAxisRange(axis: axis) / minYRange
-        _viewPortHandler.setMaximumScaleY(CGFloat(yScale))
+        viewPortHandler.setMaximumScaleY(CGFloat(yScale))
     }
 
     /// Limits the maximum and minimum y range that can be visible by pinching and zooming.
@@ -1268,7 +1266,7 @@ open class BarLineChartViewBase: ChartViewBase, BarLineScatterCandleBubbleChartD
     {
         let minScale = getAxisRange(axis: axis) / minYRange
         let maxScale = getAxisRange(axis: axis) / maxYRange
-        _viewPortHandler.setMinMaxScaleY(minScaleY: CGFloat(minScale), maxScaleY: CGFloat(maxScale))
+        viewPortHandler.setMinMaxScaleY(minScaleY: CGFloat(minScale), maxScaleY: CGFloat(maxScale))
     }
     
     /// Moves the left side of the current viewport to the specified x-value.
@@ -1293,7 +1291,7 @@ open class BarLineChartViewBase: ChartViewBase, BarLineScatterCandleBubbleChartD
     ///   - axis: - which axis should be used as a reference for the y-axis
     @objc open func moveViewToY(_ yValue: Double, axis: YAxis.AxisDependency)
     {
-        let yInView = getAxisRange(axis: axis) / Double(_viewPortHandler.scaleY)
+        let yInView = getAxisRange(axis: axis) / Double(viewPortHandler.scaleY)
         
         let job = MoveViewJob(
             viewPortHandler: viewPortHandler,
@@ -1314,7 +1312,7 @@ open class BarLineChartViewBase: ChartViewBase, BarLineScatterCandleBubbleChartD
     ///   - axis: - which axis should be used as a reference for the y-axis
     @objc open func moveViewTo(xValue: Double, yValue: Double, axis: YAxis.AxisDependency)
     {
-        let yInView = getAxisRange(axis: axis) / Double(_viewPortHandler.scaleY)
+        let yInView = getAxisRange(axis: axis) / Double(viewPortHandler.scaleY)
         
         let job = MoveViewJob(
             viewPortHandler: viewPortHandler,
@@ -1346,7 +1344,7 @@ open class BarLineChartViewBase: ChartViewBase, BarLineScatterCandleBubbleChartD
             point: CGPoint(x: viewPortHandler.contentLeft, y: viewPortHandler.contentTop),
             axis: axis)
         
-        let yInView = getAxisRange(axis: axis) / Double(_viewPortHandler.scaleY)
+        let yInView = getAxisRange(axis: axis) / Double(viewPortHandler.scaleY)
         
         let job = AnimatedMoveViewJob(
             viewPortHandler: viewPortHandler,
@@ -1411,8 +1409,8 @@ open class BarLineChartViewBase: ChartViewBase, BarLineScatterCandleBubbleChartD
         yValue: Double,
         axis: YAxis.AxisDependency)
     {
-        let yInView = getAxisRange(axis: axis) / Double(_viewPortHandler.scaleY)
-        let xInView = xAxis.axisRange / Double(_viewPortHandler.scaleX)
+        let yInView = getAxisRange(axis: axis) / Double(viewPortHandler.scaleY)
+        let xInView = xAxis.axisRange / Double(viewPortHandler.scaleX)
         
         let job = MoveViewJob(
             viewPortHandler: viewPortHandler,
@@ -1443,8 +1441,8 @@ open class BarLineChartViewBase: ChartViewBase, BarLineScatterCandleBubbleChartD
             point: CGPoint(x: viewPortHandler.contentLeft, y: viewPortHandler.contentTop),
             axis: axis)
         
-        let yInView = getAxisRange(axis: axis) / Double(_viewPortHandler.scaleY)
-        let xInView = xAxis.axisRange / Double(_viewPortHandler.scaleX)
+        let yInView = getAxisRange(axis: axis) / Double(viewPortHandler.scaleY)
+        let xInView = xAxis.axisRange / Double(viewPortHandler.scaleX)
         
         let job = AnimatedMoveViewJob(
             viewPortHandler: viewPortHandler,
@@ -1503,7 +1501,7 @@ open class BarLineChartViewBase: ChartViewBase, BarLineScatterCandleBubbleChartD
         
         if Thread.isMainThread
         {
-            self._viewPortHandler.restrainViewPort(offsetLeft: left, offsetTop: top, offsetRight: right, offsetBottom: bottom)
+            self.viewPortHandler.restrainViewPort(offsetLeft: left, offsetTop: top, offsetRight: right, offsetBottom: bottom)
             prepareOffsetMatrix()
             prepareValuePxMatrix()
         }
@@ -1601,7 +1599,7 @@ open class BarLineChartViewBase: ChartViewBase, BarLineScatterCandleBubbleChartD
             _scaleXEnabled = enabled
             _scaleYEnabled = enabled
             #if !os(tvOS)
-            _pinchGestureRecognizer.isEnabled = _pinchZoomEnabled || _scaleXEnabled || _scaleYEnabled
+                _pinchGestureRecognizer.isEnabled = _pinchZoomEnabled || _scaleXEnabled || _scaleYEnabled
             #endif
         }
     }
@@ -1618,7 +1616,7 @@ open class BarLineChartViewBase: ChartViewBase, BarLineScatterCandleBubbleChartD
             {
                 _scaleXEnabled = newValue
                 #if !os(tvOS)
-                _pinchGestureRecognizer.isEnabled = _pinchZoomEnabled || _scaleXEnabled || _scaleYEnabled
+                    _pinchGestureRecognizer.isEnabled = _pinchZoomEnabled || _scaleXEnabled || _scaleYEnabled
                 #endif
             }
         }
@@ -1636,7 +1634,7 @@ open class BarLineChartViewBase: ChartViewBase, BarLineScatterCandleBubbleChartD
             {
                 _scaleYEnabled = newValue
                 #if !os(tvOS)
-                _pinchGestureRecognizer.isEnabled = _pinchZoomEnabled || _scaleXEnabled || _scaleYEnabled
+                    _pinchGestureRecognizer.isEnabled = _pinchZoomEnabled || _scaleXEnabled || _scaleYEnabled
                 #endif
             }
         }
@@ -1716,44 +1714,35 @@ open class BarLineChartViewBase: ChartViewBase, BarLineScatterCandleBubbleChartD
     {
         if let h = getHighlightByTouchPoint(pt)
         {
-            return _data!.entryForHighlight(h)
+            return data!.entry(for: h)
         }
         return nil
     }
     
     /// - Returns: The DataSet object displayed at the touched position of the chart
-    @objc open func getDataSetByTouchPoint(point pt: CGPoint) -> IBarLineScatterCandleBubbleChartDataSet?
+    @objc open func getDataSetByTouchPoint(point pt: CGPoint) -> BarLineScatterCandleBubbleChartDataSetProtocol?
     {
-        let h = getHighlightByTouchPoint(pt)
-        if h !== nil
-        {
-            return _data?.getDataSetByIndex(h!.dataSetIndex) as? IBarLineScatterCandleBubbleChartDataSet
+        guard let h = getHighlightByTouchPoint(pt) else {
+            return nil
         }
-        return nil
+
+        return data?[h.dataSetIndex] as? BarLineScatterCandleBubbleChartDataSetProtocol
     }
 
     /// The current x-scale factor
     @objc open var scaleX: CGFloat
     {
-        if _viewPortHandler === nil
-        {
-            return 1.0
-        }
-        return _viewPortHandler.scaleX
+        return viewPortHandler.scaleX
     }
 
     /// The current y-scale factor
     @objc open var scaleY: CGFloat
     {
-        if _viewPortHandler === nil
-        {
-            return 1.0
-        }
-        return _viewPortHandler.scaleY
+        return viewPortHandler.scaleY
     }
 
     /// if the chart is fully zoomed out, return true
-    @objc open var isFullyZoomedOut: Bool { return _viewPortHandler.isFullyZoomedOut }
+    @objc open var isFullyZoomedOut: Bool { return viewPortHandler.isFullyZoomedOut }
 
     /// - Returns: The y-axis object to the corresponding AxisDependency. In the
     /// horizontal bar-chart, LEFT == top, RIGHT == BOTTOM
@@ -1782,7 +1771,7 @@ open class BarLineChartViewBase: ChartViewBase, BarLineScatterCandleBubbleChartD
             {
                 _pinchZoomEnabled = newValue
                 #if !os(tvOS)
-                _pinchGestureRecognizer.isEnabled = _pinchZoomEnabled || _scaleXEnabled || _scaleYEnabled
+                    _pinchGestureRecognizer.isEnabled = _pinchZoomEnabled || _scaleXEnabled || _scaleYEnabled
                 #endif
             }
         }
@@ -1796,18 +1785,18 @@ open class BarLineChartViewBase: ChartViewBase, BarLineScatterCandleBubbleChartD
     /// bounds on the x-axis.
     @objc open func setDragOffsetX(_ offset: CGFloat)
     {
-        _viewPortHandler.setDragOffsetX(offset)
+        viewPortHandler.setDragOffsetX(offset)
     }
 
     /// Set an offset in dp that allows the user to drag the chart over it's
     /// bounds on the y-axis.
     @objc open func setDragOffsetY(_ offset: CGFloat)
     {
-        _viewPortHandler.setDragOffsetY(offset)
+        viewPortHandler.setDragOffsetY(offset)
     }
 
     /// `true` if both drag offsets (x and y) are zero or smaller.
-    @objc open var hasNoDragOffset: Bool { return _viewPortHandler.hasNoDragOffset }
+    @objc open var hasNoDragOffset: Bool { return viewPortHandler.hasNoDragOffset }
 
     open override var chartYMax: Double
     {

+ 2 - 2
Pods/Charts/Source/Charts/Charts/BubbleChartView.swift

@@ -18,10 +18,10 @@ open class BubbleChartView: BarLineChartViewBase, BubbleChartDataProvider
     {
         super.initialize()
         
-        renderer = BubbleChartRenderer(dataProvider: self, animator: _animator, viewPortHandler: _viewPortHandler)
+        renderer = BubbleChartRenderer(dataProvider: self, animator: chartAnimator, viewPortHandler: viewPortHandler)
     }
     
     // MARK: - BubbleChartDataProvider
     
-    open var bubbleData: BubbleChartData? { return _data as? BubbleChartData }
+    open var bubbleData: BubbleChartData? { return data as? BubbleChartData }
 }

+ 2 - 2
Pods/Charts/Source/Charts/Charts/CandleStickChartView.swift

@@ -19,7 +19,7 @@ open class CandleStickChartView: BarLineChartViewBase, CandleChartDataProvider
     {
         super.initialize()
         
-        renderer = CandleStickChartRenderer(dataProvider: self, animator: _animator, viewPortHandler: _viewPortHandler)
+        renderer = CandleStickChartRenderer(dataProvider: self, animator: chartAnimator, viewPortHandler: viewPortHandler)
         
         self.xAxis.spaceMin = 0.5
         self.xAxis.spaceMax = 0.5
@@ -29,6 +29,6 @@ open class CandleStickChartView: BarLineChartViewBase, CandleChartDataProvider
     
     open var candleData: CandleChartData?
     {
-        return _data as? CandleChartData
+        return data as? CandleChartData
     }
 }

+ 176 - 328
Pods/Charts/Source/Charts/Charts/ChartViewBase.swift

@@ -13,14 +13,10 @@
 import Foundation
 import CoreGraphics
 
-#if canImport(UIKit)
+#if !os(OSX)
     import UIKit
 #endif
 
-#if canImport(Cocoa)
-import Cocoa
-#endif
-
 @objc
 public protocol ChartViewDelegate
 {
@@ -51,43 +47,43 @@ open class ChartViewBase: NSUIView, ChartDataProvider, AnimatorDelegate
 {
     // MARK: - Properties
     
-    /// - Returns: The object representing all x-labels, this method can be used to
-    /// acquire the XAxis object and modify it (e.g. change the position of the
-    /// labels)
-    @objc open var xAxis: XAxis
-    {
-        return _xAxis
-    }
-    
     /// The default IValueFormatter that has been determined by the chart considering the provided minimum and maximum values.
-    internal var _defaultValueFormatter: IValueFormatter? = DefaultValueFormatter(decimals: 0)
-    
+    internal lazy var defaultValueFormatter: ValueFormatter = DefaultValueFormatter(decimals: 0)
+
     /// object that holds all data that was originally set for the chart, before it was modified or any filtering algorithms had been applied
-    internal var _data: ChartData?
-    
-    /// Flag that indicates if highlighting per tap (touch) is enabled
-    private var _highlightPerTapEnabled = true
-    
+    @objc open var data: ChartData?
+        {
+        didSet
+        {
+            offsetsCalculated = false
+
+            guard let data = data else { return }
+
+            // calculate how many digits are needed
+            setupDefaultFormatter(min: data.yMin, max: data.yMax)
+
+            for set in data where set.valueFormatter is DefaultValueFormatter
+            {
+                set.valueFormatter = defaultValueFormatter
+            }
+
+            // let the chart know there is new data
+            notifyDataSetChanged()
+        }
+    }
+
     /// If set to true, chart continues to scroll after touch up
     @objc open var dragDecelerationEnabled = true
-    
-    /// Deceleration friction coefficient in [0 ; 1] interval, higher values indicate that speed will decrease slowly, for example if it set to 0, it will stop immediately.
-    /// 1 is an invalid value, and will be converted to 0.999 automatically.
-    private var _dragDecelerationFrictionCoef: CGFloat = 0.9
-    
-    /// if true, units are drawn next to the values in the chart
-    internal var _drawUnitInChart = false
-    
+
     /// The object representing the labels on the x-axis
-    internal var _xAxis: XAxis!
+    @objc open internal(set) lazy var xAxis = XAxis()
     
     /// The `Description` object of the chart.
-    /// This should have been called just "description", but
-    @objc open var chartDescription: Description?
-        
+    @objc open lazy var chartDescription = Description()
+
     /// The legend object containing all data associated with the legend
-    internal var _legend: Legend!
-    
+    @objc open internal(set) lazy var legend = Legend()
+
     /// delegate to receive chart events
     @objc open weak var delegate: ChartViewDelegate?
     
@@ -101,26 +97,32 @@ open class ChartViewBase: NSUIView, ChartDataProvider, AnimatorDelegate
     @objc open var noDataTextColor: NSUIColor = .labelOrBlack
 
     /// alignment of the no data text
-    @objc open var noDataTextAlignment: NSTextAlignment = .left
+    @objc open var noDataTextAlignment: TextAlignment = .left
+
+    /// The renderer object responsible for rendering / drawing the Legend.
+    @objc open lazy var legendRenderer = LegendRenderer(viewPortHandler: viewPortHandler, legend: legend)
 
-    internal var _legendRenderer: LegendRenderer!
-    
     /// object responsible for rendering the data
     @objc open var renderer: DataRenderer?
     
-    @objc open var highlighter: IHighlighter?
-    
-    /// object that manages the bounds and drawing constraints of the chart
-    internal var _viewPortHandler: ViewPortHandler!
-    
-    /// object responsible for animations
-    internal var _animator: Animator!
-    
+    @objc open var highlighter: Highlighter?
+
+    /// The ViewPortHandler of the chart that is responsible for the
+    /// content area of the chart and its offsets and dimensions.
+    @objc open internal(set) lazy var viewPortHandler = ViewPortHandler(width: bounds.size.width, height: bounds.size.height)
+
+    /// The animator responsible for animating chart values.
+    @objc open internal(set) lazy var chartAnimator: Animator = {
+        let animator = Animator()
+        animator.delegate = self
+        return animator
+    }()
+
     /// flag that indicates if offsets calculation has already been done or not
-    private var _offsetsCalculated = false
-    
-    /// array of Highlight objects that reference the highlighted slices in the chart
-    internal var _indicesToHighlight = [Highlight]()
+    private var offsetsCalculated = false
+
+    /// The array of currently highlighted values. This might an empty if nothing is highlighted.
+    @objc open internal(set) var highlighted = [Highlight]()
     
     /// `true` if drawing the marker is enabled when tapping on values
     /// (use the `marker` property to specify a marker)
@@ -131,10 +133,8 @@ open class ChartViewBase: NSUIView, ChartDataProvider, AnimatorDelegate
     @objc open var isDrawMarkersEnabled: Bool { return drawMarkers }
     
     /// The marker that is displayed when a value is clicked on the chart
-    @objc open var marker: IMarker?
-    
-    private var _interceptTouchEvents = false
-    
+    @objc open var marker: Marker?
+
     /// An extra offset to be appended to the viewport's top
     @objc open var extraTopOffset: CGFloat = 0.0
     
@@ -146,7 +146,7 @@ open class ChartViewBase: NSUIView, ChartDataProvider, AnimatorDelegate
     
     /// An extra offset to be appended to the viewport's left
     @objc open var extraLeftOffset: CGFloat = 0.0
-    
+
     @objc open func setExtraOffsets(left: CGFloat, top: CGFloat, right: CGFloat, bottom: CGFloat)
     {
         extraLeftOffset = left
@@ -171,74 +171,28 @@ open class ChartViewBase: NSUIView, ChartDataProvider, AnimatorDelegate
     
     deinit
     {
-        self.removeObserver(self, forKeyPath: "bounds")
-        self.removeObserver(self, forKeyPath: "frame")
+        removeObserver(self, forKeyPath: "bounds")
+        removeObserver(self, forKeyPath: "frame")
     }
     
     internal func initialize()
     {
         #if os(iOS)
-        self.backgroundColor = NSUIColor.clear
+            self.backgroundColor = .clear
         #endif
 
-        _animator = Animator()
-        _animator.delegate = self
-
-        _viewPortHandler = ViewPortHandler(width: bounds.size.width, height: bounds.size.height)
-        
-        chartDescription = Description()
-        
-        _legend = Legend()
-        _legendRenderer = LegendRenderer(viewPortHandler: _viewPortHandler, legend: _legend)
-        
-        _xAxis = XAxis()
-        
-        self.addObserver(self, forKeyPath: "bounds", options: .new, context: nil)
-        self.addObserver(self, forKeyPath: "frame", options: .new, context: nil)
+        addObserver(self, forKeyPath: "bounds", options: .new, context: nil)
+        addObserver(self, forKeyPath: "frame", options: .new, context: nil)
     }
     
     // MARK: - ChartViewBase
     
-    /// The data for the chart
-    open var data: ChartData?
-    {
-        get
-        {
-            return _data
-        }
-        set
-        {
-            _data = newValue
-            _offsetsCalculated = false
-            
-            guard let _data = _data else
-            {
-                setNeedsDisplay()
-                return
-            }
-            
-            // calculate how many digits are needed
-            setupDefaultFormatter(min: _data.getYMin(), max: _data.getYMax())
-            
-            for set in _data.dataSets
-            {
-                if set.needsFormatter || set.valueFormatter === _defaultValueFormatter
-                {
-                    set.valueFormatter = _defaultValueFormatter
-                }
-            }
-            
-            // let the chart know there is new data
-            notifyDataSetChanged()
-        }
-    }
-    
     /// Clears the chart from all data (sets it to null) and refreshes it (by calling setNeedsDisplay()).
     @objc open func clear()
     {
-        _data = nil
-        _offsetsCalculated = false
-        _indicesToHighlight.removeAll()
+        data = nil
+        offsetsCalculated = false
+        highlighted.removeAll()
         lastHighlighted = nil
     
         setNeedsDisplay()
@@ -247,23 +201,14 @@ open class ChartViewBase: NSUIView, ChartDataProvider, AnimatorDelegate
     /// Removes all DataSets (and thereby Entries) from the chart. Does not set the data object to nil. Also refreshes the chart by calling setNeedsDisplay().
     @objc open func clearValues()
     {
-        _data?.clearValues()
+        data?.clearValues()
         setNeedsDisplay()
     }
 
     /// - Returns: `true` if the chart is empty (meaning it's data object is either null or contains no entries).
     @objc open func isEmpty() -> Bool
     {
-        guard let data = _data else { return true }
-
-        if data.entryCount <= 0
-        {
-            return true
-        }
-        else
-        {
-            return false
-        }
+        return data?.isEmpty ?? true
     }
     
     /// Lets the chart know its underlying data has changed and should perform all necessary recalculations.
@@ -289,94 +234,83 @@ open class ChartViewBase: NSUIView, ChartDataProvider, AnimatorDelegate
     internal func setupDefaultFormatter(min: Double, max: Double)
     {
         // check if a custom formatter is set or not
-        var reference = Double(0.0)
+        var reference = 0.0
         
-        if let data = _data , data.entryCount >= 2
+        if let data = data , data.entryCount >= 2
         {
-            reference = fabs(max - min)
+            reference = abs(max - min)
         }
         else
         {
-            let absMin = fabs(min)
-            let absMax = fabs(max)
-            reference = absMin > absMax ? absMin : absMax
+            reference = Swift.max(abs(min), abs(max))
         }
         
     
-        if _defaultValueFormatter is DefaultValueFormatter
+        if let formatter = defaultValueFormatter as? DefaultValueFormatter
         {
             // setup the formatter with a new number of digits
             let digits = reference.decimalPlaces
-            
-            (_defaultValueFormatter as? DefaultValueFormatter)?.decimals
-             = digits
+            formatter.decimals = digits
         }
     }
     
     open override func draw(_ rect: CGRect)
     {
-        let optionalContext = NSUIGraphicsGetCurrentContext()
-        guard let context = optionalContext else { return }
-        
-        let frame = self.bounds
+        guard let context = NSUIGraphicsGetCurrentContext() else { return }
 
-        if _data === nil && noDataText.count > 0
+        if data === nil && !noDataText.isEmpty
         {
             context.saveGState()
             defer { context.restoreGState() }
 
-            let paragraphStyle = NSMutableParagraphStyle.default.mutableCopy() as! NSMutableParagraphStyle
+            let paragraphStyle = MutableParagraphStyle.default.mutableCopy() as! MutableParagraphStyle
             paragraphStyle.minimumLineHeight = noDataFont.lineHeight
             paragraphStyle.lineBreakMode = .byWordWrapping
             paragraphStyle.alignment = noDataTextAlignment
 
-            ChartUtils.drawMultilineText(
-                context: context,
-                text: noDataText,
-                point: CGPoint(x: frame.width / 2.0, y: frame.height / 2.0),
-                attributes:
-                [.font: noDataFont,
-                 .foregroundColor: noDataTextColor,
-                 .paragraphStyle: paragraphStyle],
-                constrainedToSize: self.bounds.size,
-                anchor: CGPoint(x: 0.5, y: 0.5),
-                angleRadians: 0.0)
-            
+            context.drawMultilineText(noDataText,
+                                      at: CGPoint(x: bounds.width / 2.0, y: bounds.height / 2.0),
+                                      constrainedTo: bounds.size,
+                                      anchor: CGPoint(x: 0.5, y: 0.5),
+                                      angleRadians: 0.0,
+                                      attributes: [.font: noDataFont,
+                                                   .foregroundColor: noDataTextColor,
+                                                   .paragraphStyle: paragraphStyle])
+
             return
         }
         
-        if !_offsetsCalculated
+        if !offsetsCalculated
         {
             calculateOffsets()
-            _offsetsCalculated = true
+            offsetsCalculated = true
         }
     }
     
     /// Draws the description text in the bottom right corner of the chart (per default)
-    internal func drawDescription(context: CGContext)
+    internal func drawDescription(in context: CGContext)
     {
+        let description = chartDescription
+
         // check if description should be drawn
         guard
-            let description = chartDescription,
             description.isEnabled,
             let descriptionText = description.text,
-            descriptionText.count > 0
+            !descriptionText.isEmpty
             else { return }
         
-        let position = description.position ?? CGPoint(x: bounds.width - _viewPortHandler.offsetRight - description.xOffset,
-                                                       y: bounds.height - _viewPortHandler.offsetBottom - description.yOffset - description.font.lineHeight)
-        
-        var attrs = [NSAttributedString.Key : Any]()
-        
-        attrs[NSAttributedString.Key.font] = description.font
-        attrs[NSAttributedString.Key.foregroundColor] = description.textColor
+        let position = description.position ?? CGPoint(x: bounds.width - viewPortHandler.offsetRight - description.xOffset,
+                                                       y: bounds.height - viewPortHandler.offsetBottom - description.yOffset - description.font.lineHeight)
+
+        let attrs: [NSAttributedString.Key : Any] = [
+            .font: description.font,
+            .foregroundColor: description.textColor
+        ]
 
-        ChartUtils.drawText(
-            context: context,
-            text: descriptionText,
-            point: position,
-            align: description.textAlign,
-            attributes: attrs)
+        context.drawText(descriptionText,
+                         at: position,
+                         align: description.textAlign,
+                         attributes: attrs)
     }
     
     // MARK: - Accessibility
@@ -386,22 +320,12 @@ open class ChartViewBase: NSUIView, ChartDataProvider, AnimatorDelegate
     }
 
     // MARK: - Highlighting
-    
-    /// The array of currently highlighted values. This might an empty if nothing is highlighted.
-    @objc open var highlighted: [Highlight]
-    {
-        return _indicesToHighlight
-    }
-    
+
     /// Set this to false to prevent values from being highlighted by tap gesture.
     /// Values can still be highlighted via drag or programmatically.
     /// **default**: true
-    @objc open var highlightPerTapEnabled: Bool
-    {
-        get { return _highlightPerTapEnabled }
-        set { _highlightPerTapEnabled = newValue }
-    }
-    
+    @objc open var highlightPerTapEnabled: Bool = true
+
     /// `true` if values can be highlighted via tap gesture, `false` ifnot.
     @objc open var isHighLightPerTapEnabled: Bool
     {
@@ -413,7 +337,7 @@ open class ChartViewBase: NSUIView, ChartDataProvider, AnimatorDelegate
     /// - Returns: `true` if there are values to highlight, `false` ifthere are no values to highlight.
     @objc open func valuesToHighlight() -> Bool
     {
-        return !_indicesToHighlight.isEmpty
+        return !highlighted.isEmpty
     }
 
     /// Highlights the values at the given indices in the given DataSets. Provide
@@ -423,16 +347,9 @@ open class ChartViewBase: NSUIView, ChartDataProvider, AnimatorDelegate
     @objc open func highlightValues(_ highs: [Highlight]?)
     {
         // set the indices to highlight
-        _indicesToHighlight = highs ?? [Highlight]()
-        
-        if _indicesToHighlight.isEmpty
-        {
-            self.lastHighlighted = nil
-        }
-        else
-        {
-            self.lastHighlighted = _indicesToHighlight[0]
-        }
+        highlighted = highs ?? []
+
+        lastHighlighted = highlighted.first
 
         // redraw the chart
         setNeedsDisplay()
@@ -489,19 +406,19 @@ open class ChartViewBase: NSUIView, ChartDataProvider, AnimatorDelegate
     ///   - callDelegate: Should the delegate be called for this change
     @objc open func highlightValue(x: Double, y: Double, dataSetIndex: Int, dataIndex: Int = -1, callDelegate: Bool)
     {
-        guard let data = _data else
+        guard let data = data else
         {
             Swift.print("Value not highlighted because data is nil")
             return
         }
-        
-        if dataSetIndex < 0 || dataSetIndex >= data.dataSetCount
+
+        if data.indices.contains(dataSetIndex)
         {
-            highlightValue(nil, callDelegate: callDelegate)
+            highlightValue(Highlight(x: x, y: y, dataSetIndex: dataSetIndex, dataIndex: dataIndex), callDelegate: callDelegate)
         }
         else
         {
-            highlightValue(Highlight(x: x, y: y, dataSetIndex: dataSetIndex, dataIndex: dataIndex), callDelegate: callDelegate)
+            highlightValue(nil, callDelegate: callDelegate)
         }
     }
     
@@ -518,42 +435,31 @@ open class ChartViewBase: NSUIView, ChartDataProvider, AnimatorDelegate
     /// Highlights the value selected by touch gesture.
     @objc open func highlightValue(_ highlight: Highlight?, callDelegate: Bool)
     {
-        var entry: ChartDataEntry?
-        var h = highlight
-        
-        if h == nil
+        var high = highlight
+        guard
+            let h = high,
+            let entry = data?.entry(for: h)
+            else
         {
-            self.lastHighlighted = nil
-            _indicesToHighlight.removeAll(keepingCapacity: false)
+                high = nil
+                highlighted.removeAll(keepingCapacity: false)
+                if callDelegate
+                {
+                    delegate?.chartValueNothingSelected?(self)
+                }
+                setNeedsDisplay()
+                return
         }
-        else
+
+        // set the indices to highlight
+       highlighted = [h]
+
+        if callDelegate
         {
-            // set the indices to highlight
-            entry = _data?.entryForHighlight(h!)
-            if entry == nil
-            {
-                h = nil
-                _indicesToHighlight.removeAll(keepingCapacity: false)
-            }
-            else
-            {
-                _indicesToHighlight = [h!]
-            }
+            // notify the listener
+            delegate?.chartValueSelected?(self, entry: entry, highlight: h)
         }
-        
-        if callDelegate, let delegate = delegate
-        {
-            if let h = h
-            {
-                // notify the listener
-                delegate.chartValueSelected?(self, entry: entry!, highlight: h)
-            }
-            else
-            {
-                delegate.chartValueNothingSelected?(self)
-            }
-        }
-        
+
         // redraw the chart
         setNeedsDisplay()
     }
@@ -563,7 +469,7 @@ open class ChartViewBase: NSUIView, ChartDataProvider, AnimatorDelegate
     /// CandleStick-Chart.
     @objc open func getHighlightByTouchPoint(_ pt: CGPoint) -> Highlight?
     {
-        if _data === nil
+        guard data != nil else
         {
             Swift.print("Can't select by touch. No data set.")
             return nil
@@ -582,33 +488,25 @@ open class ChartViewBase: NSUIView, ChartDataProvider, AnimatorDelegate
     {
         // if there is no marker view or drawing marker is disabled
         guard
-            let marker = marker
-            , isDrawMarkersEnabled &&
-                valuesToHighlight()
+            let marker = marker,
+            isDrawMarkersEnabled,
+            valuesToHighlight()
             else { return }
         
-        for i in 0 ..< _indicesToHighlight.count
+        for highlight in highlighted
         {
-            let highlight = _indicesToHighlight[i]
-            
-            guard let
-                set = data?.getDataSetByIndex(highlight.dataSetIndex),
-                let e = _data?.entryForHighlight(highlight)
+            guard
+                let set = data?[highlight.dataSetIndex],
+                let e = data?.entry(for: highlight)
                 else { continue }
             
             let entryIndex = set.entryIndex(entry: e)
-            if entryIndex > Int(Double(set.entryCount) * _animator.phaseX)
-            {
-                continue
-            }
+            guard entryIndex <= Int(Double(set.entryCount) * chartAnimator.phaseX) else { continue }
 
             let pos = getMarkerPosition(highlight: highlight)
 
             // check bounds
-            if !_viewPortHandler.isInBounds(x: pos.x, y: pos.y)
-            {
-                continue
-            }
+            guard viewPortHandler.isInBounds(x: pos.x, y: pos.y) else { continue }
 
             // callbacks to update the content
             marker.refreshContent(entry: e, highlight: highlight)
@@ -625,13 +523,7 @@ open class ChartViewBase: NSUIView, ChartDataProvider, AnimatorDelegate
     }
     
     // MARK: - Animation
-    
-    /// The animator responsible for animating chart values.
-    @objc open var chartAnimator: Animator!
-    {
-        return _animator
-    }
-    
+
     /// Animates the drawing / rendering of the chart on both x- and y-axis with the specified animation time.
     /// If `animate(...)` is called, no further calling of `invalidate()` is necessary to refresh the chart.
     ///
@@ -642,7 +534,7 @@ open class ChartViewBase: NSUIView, ChartDataProvider, AnimatorDelegate
     ///   - easingY: an easing function for the animation on the y axis
     @objc open func animate(xAxisDuration: TimeInterval, yAxisDuration: TimeInterval, easingX: ChartEasingFunctionBlock?, easingY: ChartEasingFunctionBlock?)
     {
-        _animator.animate(xAxisDuration: xAxisDuration, yAxisDuration: yAxisDuration, easingX: easingX, easingY: easingY)
+        chartAnimator.animate(xAxisDuration: xAxisDuration, yAxisDuration: yAxisDuration, easingX: easingX, easingY: easingY)
     }
     
     /// Animates the drawing / rendering of the chart on both x- and y-axis with the specified animation time.
@@ -655,7 +547,7 @@ open class ChartViewBase: NSUIView, ChartDataProvider, AnimatorDelegate
     ///   - easingOptionY: the easing function for the animation on the y axis
     @objc open func animate(xAxisDuration: TimeInterval, yAxisDuration: TimeInterval, easingOptionX: ChartEasingOption, easingOptionY: ChartEasingOption)
     {
-        _animator.animate(xAxisDuration: xAxisDuration, yAxisDuration: yAxisDuration, easingOptionX: easingOptionX, easingOptionY: easingOptionY)
+        chartAnimator.animate(xAxisDuration: xAxisDuration, yAxisDuration: yAxisDuration, easingOptionX: easingOptionX, easingOptionY: easingOptionY)
     }
     
     /// Animates the drawing / rendering of the chart on both x- and y-axis with the specified animation time.
@@ -667,7 +559,7 @@ open class ChartViewBase: NSUIView, ChartDataProvider, AnimatorDelegate
     ///   - easing: an easing function for the animation
     @objc open func animate(xAxisDuration: TimeInterval, yAxisDuration: TimeInterval, easing: ChartEasingFunctionBlock?)
     {
-        _animator.animate(xAxisDuration: xAxisDuration, yAxisDuration: yAxisDuration, easing: easing)
+        chartAnimator.animate(xAxisDuration: xAxisDuration, yAxisDuration: yAxisDuration, easing: easing)
     }
     
     /// Animates the drawing / rendering of the chart on both x- and y-axis with the specified animation time.
@@ -679,7 +571,7 @@ open class ChartViewBase: NSUIView, ChartDataProvider, AnimatorDelegate
     ///   - easingOption: the easing function for the animation
     @objc open func animate(xAxisDuration: TimeInterval, yAxisDuration: TimeInterval, easingOption: ChartEasingOption)
     {
-        _animator.animate(xAxisDuration: xAxisDuration, yAxisDuration: yAxisDuration, easingOption: easingOption)
+        chartAnimator.animate(xAxisDuration: xAxisDuration, yAxisDuration: yAxisDuration, easingOption: easingOption)
     }
     
     /// Animates the drawing / rendering of the chart on both x- and y-axis with the specified animation time.
@@ -690,7 +582,7 @@ open class ChartViewBase: NSUIView, ChartDataProvider, AnimatorDelegate
     ///   - yAxisDuration: duration for animating the y axis
     @objc open func animate(xAxisDuration: TimeInterval, yAxisDuration: TimeInterval)
     {
-        _animator.animate(xAxisDuration: xAxisDuration, yAxisDuration: yAxisDuration)
+        chartAnimator.animate(xAxisDuration: xAxisDuration, yAxisDuration: yAxisDuration)
     }
     
     /// Animates the drawing / rendering of the chart the x-axis with the specified animation time.
@@ -701,7 +593,7 @@ open class ChartViewBase: NSUIView, ChartDataProvider, AnimatorDelegate
     ///   - easing: an easing function for the animation
     @objc open func animate(xAxisDuration: TimeInterval, easing: ChartEasingFunctionBlock?)
     {
-        _animator.animate(xAxisDuration: xAxisDuration, easing: easing)
+        chartAnimator.animate(xAxisDuration: xAxisDuration, easing: easing)
     }
     
     /// Animates the drawing / rendering of the chart the x-axis with the specified animation time.
@@ -712,7 +604,7 @@ open class ChartViewBase: NSUIView, ChartDataProvider, AnimatorDelegate
     ///   - easingOption: the easing function for the animation
     @objc open func animate(xAxisDuration: TimeInterval, easingOption: ChartEasingOption)
     {
-        _animator.animate(xAxisDuration: xAxisDuration, easingOption: easingOption)
+        chartAnimator.animate(xAxisDuration: xAxisDuration, easingOption: easingOption)
     }
     
     /// Animates the drawing / rendering of the chart the x-axis with the specified animation time.
@@ -722,7 +614,7 @@ open class ChartViewBase: NSUIView, ChartDataProvider, AnimatorDelegate
     ///   - xAxisDuration: duration for animating the x axis
     @objc open func animate(xAxisDuration: TimeInterval)
     {
-        _animator.animate(xAxisDuration: xAxisDuration)
+        chartAnimator.animate(xAxisDuration: xAxisDuration)
     }
     
     /// Animates the drawing / rendering of the chart the y-axis with the specified animation time.
@@ -733,7 +625,7 @@ open class ChartViewBase: NSUIView, ChartDataProvider, AnimatorDelegate
     ///   - easing: an easing function for the animation
     @objc open func animate(yAxisDuration: TimeInterval, easing: ChartEasingFunctionBlock?)
     {
-        _animator.animate(yAxisDuration: yAxisDuration, easing: easing)
+        chartAnimator.animate(yAxisDuration: yAxisDuration, easing: easing)
     }
     
     /// Animates the drawing / rendering of the chart the y-axis with the specified animation time.
@@ -744,7 +636,7 @@ open class ChartViewBase: NSUIView, ChartDataProvider, AnimatorDelegate
     ///   - easingOption: the easing function for the animation
     @objc open func animate(yAxisDuration: TimeInterval, easingOption: ChartEasingOption)
     {
-        _animator.animate(yAxisDuration: yAxisDuration, easingOption: easingOption)
+        chartAnimator.animate(yAxisDuration: yAxisDuration, easingOption: easingOption)
     }
     
     /// Animates the drawing / rendering of the chart the y-axis with the specified animation time.
@@ -754,7 +646,7 @@ open class ChartViewBase: NSUIView, ChartDataProvider, AnimatorDelegate
     ///   - yAxisDuration: duration for animating the y axis
     @objc open func animate(yAxisDuration: TimeInterval)
     {
-        _animator.animate(yAxisDuration: yAxisDuration)
+        chartAnimator.animate(yAxisDuration: yAxisDuration)
     }
     
     // MARK: - Accessors
@@ -762,78 +654,58 @@ open class ChartViewBase: NSUIView, ChartDataProvider, AnimatorDelegate
     /// The current y-max value across all DataSets
     open var chartYMax: Double
     {
-        return _data?.yMax ?? 0.0
+        return data?.yMax ?? 0.0
     }
 
     /// The current y-min value across all DataSets
     open var chartYMin: Double
     {
-        return _data?.yMin ?? 0.0
+        return data?.yMin ?? 0.0
     }
     
     open var chartXMax: Double
     {
-        return _xAxis._axisMaximum
+        return xAxis._axisMaximum
     }
     
     open var chartXMin: Double
     {
-        return _xAxis._axisMinimum
+        return xAxis._axisMinimum
     }
     
     open var xRange: Double
     {
-        return _xAxis.axisRange
+        return xAxis.axisRange
     }
     
     /// - Note: (Equivalent of getCenter() in MPAndroidChart, as center is already a standard in iOS that returns the center point relative to superview, and MPAndroidChart returns relative to self)*
     /// The center point of the chart (the whole View) in pixels.
     @objc open var midPoint: CGPoint
     {
-        let bounds = self.bounds
         return CGPoint(x: bounds.origin.x + bounds.size.width / 2.0, y: bounds.origin.y + bounds.size.height / 2.0)
     }
     
     /// The center of the chart taking offsets under consideration. (returns the center of the content rectangle)
     open var centerOffsets: CGPoint
     {
-        return _viewPortHandler.contentCenter
-    }
-    
-    /// The Legend object of the chart. This method can be used to get an instance of the legend in order to customize the automatically generated Legend.
-    @objc open var legend: Legend
-    {
-        return _legend
-    }
-    
-    /// The renderer object responsible for rendering / drawing the Legend.
-    @objc open var legendRenderer: LegendRenderer!
-    {
-        return _legendRenderer
+        return viewPortHandler.contentCenter
     }
-    
+
     /// The rectangle that defines the borders of the chart-value surface (into which the actual values are drawn).
     @objc open var contentRect: CGRect
     {
-        return _viewPortHandler.contentRect
-    }
-    
-    /// - Returns: The ViewPortHandler of the chart that is responsible for the
-    /// content area of the chart and its offsets and dimensions.
-    @objc open var viewPortHandler: ViewPortHandler!
-    {
-        return _viewPortHandler
+        return viewPortHandler.contentRect
     }
-    
+
     /// - Returns: The bitmap that represents the chart.
     @objc open func getChartImage(transparent: Bool) -> NSUIImage?
     {
-        NSUIGraphicsBeginImageContextWithOptions(bounds.size, isOpaque || !transparent, NSUIScreen.nsuiMain?.nsuiScale ?? 1.0)
+        NSUIGraphicsBeginImageContextWithOptions(bounds.size, isOpaque || !transparent, NSUIMainScreen()?.nsuiScale ?? 1.0)
         
         guard let context = NSUIGraphicsGetCurrentContext()
             else { return nil }
         
-        let rect = CGRect(origin: CGPoint(x: 0, y: 0), size: bounds.size)
+        let rect = CGRect(origin: .zero, size: bounds.size)
         
         if isOpaque || !transparent
         {
@@ -906,11 +778,10 @@ open class ChartViewBase: NSUIView, ChartDataProvider, AnimatorDelegate
         {
             let bounds = self.bounds
             
-            if (_viewPortHandler !== nil &&
-                (bounds.size.width != _viewPortHandler.chartWidth ||
-                bounds.size.height != _viewPortHandler.chartHeight))
+            if ((bounds.size.width != viewPortHandler.chartWidth ||
+                bounds.size.height != viewPortHandler.chartHeight))
             {
-                _viewPortHandler.setChartDimens(width: bounds.size.width, height: bounds.size.height)
+                viewPortHandler.setChartDimens(width: bounds.size.width, height: bounds.size.height)
                 
                 // This may cause the chart view to mutate properties affecting the view port -- lets do this
                 // before we try to run any pending jobs on the view port itself
@@ -941,7 +812,7 @@ open class ChartViewBase: NSUIView, ChartDataProvider, AnimatorDelegate
     
     @objc open func addViewportJob(_ job: ViewPortJob)
     {
-        if _viewPortHandler.hasChartDimens
+        if viewPortHandler.hasChartDimens
         {
             job.doJob()
         }
@@ -960,8 +831,6 @@ open class ChartViewBase: NSUIView, ChartDataProvider, AnimatorDelegate
     
     /// Deceleration friction coefficient in [0 ; 1] interval, higher values indicate that speed will decrease slowly, for example if it set to 0, it will stop immediately.
     /// 1 is an invalid value, and will be converted to 0.999 automatically.
-    /// 
-    /// **default**: true
     @objc open var dragDecelerationFrictionCoef: CGFloat
     {
         get
@@ -970,19 +839,10 @@ open class ChartViewBase: NSUIView, ChartDataProvider, AnimatorDelegate
         }
         set
         {
-            var val = newValue
-            if val < 0.0
-            {
-                val = 0.0
-            }
-            if val >= 1.0
-            {
-                val = 0.999
-            }
-            
-            _dragDecelerationFrictionCoef = val
+            _dragDecelerationFrictionCoef = max(0, min(newValue, 0.999))
         }
     }
+    private var _dragDecelerationFrictionCoef: CGFloat = 0.9
     
     /// The maximum distance in screen pixels away from an entry causing it to highlight.
     /// **default**: 500.0
@@ -991,7 +851,7 @@ open class ChartViewBase: NSUIView, ChartDataProvider, AnimatorDelegate
     /// the number of maximum visible drawn values on the chart only active when `drawValuesEnabled` is enabled
     open var maxVisibleCount: Int
     {
-        return Int(INT_MAX)
+        return .max
     }
     
     // MARK: - AnimatorDelegate
@@ -1010,33 +870,21 @@ open class ChartViewBase: NSUIView, ChartDataProvider, AnimatorDelegate
     
     open override func nsuiTouchesBegan(_ touches: Set<NSUITouch>, withEvent event: NSUIEvent?)
     {
-        if !_interceptTouchEvents
-        {
-            super.nsuiTouchesBegan(touches, withEvent: event)
-        }
+        super.nsuiTouchesBegan(touches, withEvent: event)
     }
     
     open override func nsuiTouchesMoved(_ touches: Set<NSUITouch>, withEvent event: NSUIEvent?)
     {
-        if !_interceptTouchEvents
-        {
-            super.nsuiTouchesMoved(touches, withEvent: event)
-        }
+        super.nsuiTouchesMoved(touches, withEvent: event)
     }
     
     open override func nsuiTouchesEnded(_ touches: Set<NSUITouch>, withEvent event: NSUIEvent?)
     {
-        if !_interceptTouchEvents
-        {
-            super.nsuiTouchesEnded(touches, withEvent: event)
-        }
+        super.nsuiTouchesEnded(touches, withEvent: event)
     }
     
     open override func nsuiTouchesCancelled(_ touches: Set<NSUITouch>?, withEvent event: NSUIEvent?)
     {
-        if !_interceptTouchEvents
-        {
-            super.nsuiTouchesCancelled(touches, withEvent: event)
-        }
+        super.nsuiTouchesCancelled(touches, withEvent: event)
     }
 }

+ 10 - 10
Pods/Charts/Source/Charts/Charts/CombinedChartView.swift

@@ -16,7 +16,7 @@ import CoreGraphics
 open class CombinedChartView: BarLineChartViewBase, CombinedChartDataProvider
 {
     /// the fill-formatter used for determining the position of the fill-line
-    internal var _fillFormatter: IFillFormatter!
+    internal var _fillFormatter: FillFormatter!
     
     /// enum that allows to specify the order in which the different data objects for the combined-chart are drawn
     @objc(CombinedChartDrawOrder)
@@ -40,7 +40,7 @@ open class CombinedChartView: BarLineChartViewBase, CombinedChartDataProvider
         
         _fillFormatter = DefaultFillFormatter()
         
-        renderer = CombinedChartRenderer(chart: self, animator: _animator, viewPortHandler: _viewPortHandler)
+        renderer = CombinedChartRenderer(chart: self, animator: chartAnimator, viewPortHandler: viewPortHandler)
     }
     
     open override var data: ChartData?
@@ -60,7 +60,7 @@ open class CombinedChartView: BarLineChartViewBase, CombinedChartDataProvider
         }
     }
     
-    @objc open var fillFormatter: IFillFormatter
+    @objc open var fillFormatter: FillFormatter
     {
         get
         {
@@ -79,7 +79,7 @@ open class CombinedChartView: BarLineChartViewBase, CombinedChartDataProvider
     /// - Returns: The Highlight object (contains x-index and DataSet index) of the selected value at the given touch point inside the CombinedChart.
     open override func getHighlightByTouchPoint(_ pt: CGPoint) -> Highlight?
     {
-        if _data === nil
+        if data === nil
         {
             Swift.print("Can't select by touch. No data set.")
             return nil
@@ -106,7 +106,7 @@ open class CombinedChartView: BarLineChartViewBase, CombinedChartDataProvider
     {
         get
         {
-            return _data as? CombinedChartData
+            return data as? CombinedChartData
         }
     }
     
@@ -213,17 +213,17 @@ open class CombinedChartView: BarLineChartViewBase, CombinedChartDataProvider
             isDrawMarkersEnabled && valuesToHighlight()
             else { return }
         
-        for i in 0 ..< _indicesToHighlight.count
+        for i in highlighted.indices
         {
-            let highlight = _indicesToHighlight[i]
+            let highlight = highlighted[i]
             
             guard 
                 let set = combinedData?.getDataSetByHighlight(highlight),
-                let e = _data?.entryForHighlight(highlight)
+                let e = data?.entry(for: highlight)
                 else { continue }
             
             let entryIndex = set.entryIndex(entry: e)
-            if entryIndex > Int(Double(set.entryCount) * _animator.phaseX)
+            if entryIndex > Int(Double(set.entryCount) * chartAnimator.phaseX)
             {
                 continue
             }
@@ -231,7 +231,7 @@ open class CombinedChartView: BarLineChartViewBase, CombinedChartDataProvider
             let pos = getMarkerPosition(highlight: highlight)
             
             // check bounds
-            if !_viewPortHandler.isInBounds(x: pos.x, y: pos.y)
+            if !viewPortHandler.isInBounds(x: pos.x, y: pos.y)
             {
                 continue
             }

+ 26 - 27
Pods/Charts/Source/Charts/Charts/HorizontalBarChartView.swift

@@ -19,21 +19,20 @@ open class HorizontalBarChartView: BarChartView
     {
         super.initialize()
         
-        _leftAxisTransformer = TransformerHorizontalBarChart(viewPortHandler: _viewPortHandler)
-        _rightAxisTransformer = TransformerHorizontalBarChart(viewPortHandler: _viewPortHandler)
-        
-        renderer = HorizontalBarChartRenderer(dataProvider: self, animator: _animator, viewPortHandler: _viewPortHandler)
-        leftYAxisRenderer = YAxisRendererHorizontalBarChart(viewPortHandler: _viewPortHandler, yAxis: leftAxis, transformer: _leftAxisTransformer)
-        rightYAxisRenderer = YAxisRendererHorizontalBarChart(viewPortHandler: _viewPortHandler, yAxis: rightAxis, transformer: _rightAxisTransformer)
-        xAxisRenderer = XAxisRendererHorizontalBarChart(viewPortHandler: _viewPortHandler, xAxis: _xAxis, transformer: _leftAxisTransformer, chart: self)
-        
+        _leftAxisTransformer = TransformerHorizontalBarChart(viewPortHandler: viewPortHandler)
+        _rightAxisTransformer = TransformerHorizontalBarChart(viewPortHandler: viewPortHandler)
+
+        renderer = HorizontalBarChartRenderer(dataProvider: self, animator: chartAnimator, viewPortHandler: viewPortHandler)
+        leftYAxisRenderer = YAxisRendererHorizontalBarChart(viewPortHandler: viewPortHandler, axis: leftAxis, transformer: _leftAxisTransformer)
+        rightYAxisRenderer = YAxisRendererHorizontalBarChart(viewPortHandler: viewPortHandler, axis: rightAxis, transformer: _rightAxisTransformer)
+        xAxisRenderer = XAxisRendererHorizontalBarChart(viewPortHandler: viewPortHandler, axis: xAxis, transformer: _leftAxisTransformer, chart: self)
+
         self.highlighter = HorizontalBarHighlighter(chart: self)
     }
     
     internal override func calculateLegendOffsets(offsetLeft: inout CGFloat, offsetTop: inout CGFloat, offsetRight: inout CGFloat, offsetBottom: inout CGFloat)
     {
         guard
-            let legend = _legend,
             legend.isEnabled,
             !legend.drawInside
         else { return }
@@ -45,20 +44,20 @@ open class HorizontalBarChartView: BarChartView
             switch legend.horizontalAlignment
             {
             case .left:
-                offsetLeft += min(legend.neededWidth, _viewPortHandler.chartWidth * legend.maxSizePercent) + legend.xOffset
+                offsetLeft += min(legend.neededWidth, viewPortHandler.chartWidth * legend.maxSizePercent) + legend.xOffset
                 
             case .right:
-                offsetRight += min(legend.neededWidth, _viewPortHandler.chartWidth * legend.maxSizePercent) + legend.xOffset
+                offsetRight += min(legend.neededWidth, viewPortHandler.chartWidth * legend.maxSizePercent) + legend.xOffset
                 
             case .center:
                 
                 switch legend.verticalAlignment
                 {
                 case .top:
-                    offsetTop += min(legend.neededHeight, _viewPortHandler.chartHeight * legend.maxSizePercent) + legend.yOffset
+                    offsetTop += min(legend.neededHeight, viewPortHandler.chartHeight * legend.maxSizePercent) + legend.yOffset
                     
                 case .bottom:
-                    offsetBottom += min(legend.neededHeight, _viewPortHandler.chartHeight * legend.maxSizePercent) + legend.yOffset
+                    offsetBottom += min(legend.neededHeight, viewPortHandler.chartHeight * legend.maxSizePercent) + legend.yOffset
                     
                 default:
                     break
@@ -69,7 +68,7 @@ open class HorizontalBarChartView: BarChartView
             switch legend.verticalAlignment
             {
             case .top:
-                offsetTop += min(legend.neededHeight, _viewPortHandler.chartHeight * legend.maxSizePercent) + legend.yOffset
+                offsetTop += min(legend.neededHeight, viewPortHandler.chartHeight * legend.maxSizePercent) + legend.yOffset
                 
                 // left axis equals the top x-axis in a horizontal chart
                 if leftAxis.isEnabled && leftAxis.isDrawLabelsEnabled
@@ -78,7 +77,7 @@ open class HorizontalBarChartView: BarChartView
                 }
                 
             case .bottom:
-                offsetBottom += min(legend.neededHeight, _viewPortHandler.chartHeight * legend.maxSizePercent) + legend.yOffset
+                offsetBottom += min(legend.neededHeight, viewPortHandler.chartHeight * legend.maxSizePercent) + legend.yOffset
 
                 // right axis equals the bottom x-axis in a horizontal chart
                 if rightAxis.isEnabled && rightAxis.isDrawLabelsEnabled
@@ -114,20 +113,20 @@ open class HorizontalBarChartView: BarChartView
             offsetBottom += rightAxis.getRequiredHeightSpace()
         }
         
-        let xlabelwidth = _xAxis.labelRotatedWidth
+        let xlabelwidth = xAxis.labelRotatedWidth
         
-        if _xAxis.isEnabled
+        if xAxis.isEnabled
         {
             // offsets for x-labels
-            if _xAxis.labelPosition == .bottom
+            if xAxis.labelPosition == .bottom
             {
                 offsetLeft += xlabelwidth
             }
-            else if _xAxis.labelPosition == .top
+            else if xAxis.labelPosition == .top
             {
                 offsetRight += xlabelwidth
             }
-            else if _xAxis.labelPosition == .bothSided
+            else if xAxis.labelPosition == .bothSided
             {
                 offsetLeft += xlabelwidth
                 offsetRight += xlabelwidth
@@ -139,7 +138,7 @@ open class HorizontalBarChartView: BarChartView
         offsetBottom += self.extraBottomOffset
         offsetLeft += self.extraLeftOffset
 
-        _viewPortHandler.restrainViewPort(
+        viewPortHandler.restrainViewPort(
             offsetLeft: max(self.minOffset, offsetLeft),
             offsetTop: max(self.minOffset, offsetTop),
             offsetRight: max(self.minOffset, offsetRight),
@@ -151,8 +150,8 @@ open class HorizontalBarChartView: BarChartView
     
     internal override func prepareValuePxMatrix()
     {
-        _rightAxisTransformer.prepareMatrixValuePx(chartXMin: rightAxis._axisMinimum, deltaX: CGFloat(rightAxis.axisRange), deltaY: CGFloat(_xAxis.axisRange), chartYMin: _xAxis._axisMinimum)
-        _leftAxisTransformer.prepareMatrixValuePx(chartXMin: leftAxis._axisMinimum, deltaX: CGFloat(leftAxis.axisRange), deltaY: CGFloat(_xAxis.axisRange), chartYMin: _xAxis._axisMinimum)
+        _rightAxisTransformer.prepareMatrixValuePx(chartXMin: rightAxis._axisMinimum, deltaX: CGFloat(rightAxis.axisRange), deltaY: CGFloat(xAxis.axisRange), chartYMin: xAxis._axisMinimum)
+        _leftAxisTransformer.prepareMatrixValuePx(chartXMin: leftAxis._axisMinimum, deltaX: CGFloat(leftAxis.axisRange), deltaY: CGFloat(xAxis.axisRange), chartYMin: xAxis._axisMinimum)
     }
     
     open override func getMarkerPosition(highlight: Highlight) -> CGPoint
@@ -163,9 +162,9 @@ open class HorizontalBarChartView: BarChartView
     open override func getBarBounds(entry e: BarChartDataEntry) -> CGRect
     {
         guard
-            let data = _data as? BarChartData,
-            let set = data.getDataSetForEntry(e) as? IBarChartDataSet
-            else { return CGRect.null }
+            let data = data as? BarChartData,
+            let set = data.getDataSetForEntry(e) as? BarChartDataSetProtocol
+            else { return .null }
         
         let y = e.y
         let x = e.x
@@ -195,7 +194,7 @@ open class HorizontalBarChartView: BarChartView
 
     open override func getHighlightByTouchPoint(_ pt: CGPoint) -> Highlight?
     {
-        if _data === nil
+        if data === nil
         {
             Swift.print("Can't select by touch. No data set.", terminator: "\n")
             return nil

+ 2 - 2
Pods/Charts/Source/Charts/Charts/LineChartView.swift

@@ -19,10 +19,10 @@ open class LineChartView: BarLineChartViewBase, LineChartDataProvider
     {
         super.initialize()
         
-        renderer = LineChartRenderer(dataProvider: self, animator: _animator, viewPortHandler: _viewPortHandler)
+        renderer = LineChartRenderer(dataProvider: self, animator: chartAnimator, viewPortHandler: viewPortHandler)
     }
     
     // MARK: - LineChartDataProvider
     
-    open var lineData: LineChartData? { return _data as? LineChartData }
+    open var lineData: LineChartData? { return data as? LineChartData }
 }

+ 31 - 46
Pods/Charts/Source/Charts/Charts/PieChartView.swift

@@ -12,14 +12,10 @@
 import Foundation
 import CoreGraphics
 
-#if canImport(UIKit)
+#if !os(OSX)
     import UIKit
 #endif
 
-#if canImport(Cocoa)
-import Cocoa
-#endif
-
 /// View that represents a pie chart. Draws cake like slices.
 open class PieChartView: PieRadarChartViewBase
 {
@@ -90,9 +86,8 @@ open class PieChartView: PieRadarChartViewBase
     {
         super.initialize()
         
-        renderer = PieChartRenderer(chart: self, animator: _animator, viewPortHandler: _viewPortHandler)
-        _xAxis = nil
-        
+        renderer = PieChartRenderer(chart: self, animator: chartAnimator, viewPortHandler: viewPortHandler)
+
         self.highlighter = PieHighlighter(chart: self)
     }
     
@@ -100,7 +95,7 @@ open class PieChartView: PieRadarChartViewBase
     {
         super.draw(rect)
         
-        if _data === nil
+        if data === nil
         {
             return
         }
@@ -115,7 +110,7 @@ open class PieChartView: PieRadarChartViewBase
         
         if (valuesToHighlight())
         {
-            renderer.drawHighlighted(context: context, indices: _indicesToHighlight)
+            renderer.drawHighlighted(context: context, indices: highlighted)
         }
         
         renderer.drawExtras(context: context)
@@ -124,7 +119,7 @@ open class PieChartView: PieRadarChartViewBase
         
         legendRenderer.renderLegend(context: context)
         
-        drawDescription(context: context)
+        drawDescription(in: context)
         
         drawMarkers(context: context)
     }
@@ -132,7 +127,7 @@ open class PieChartView: PieRadarChartViewBase
     /// if width is larger than height
     private var widthLarger: Bool
     {
-        return _viewPortHandler.contentRect.orientation == .landscape
+        return viewPortHandler.contentRect.orientation == .landscape
     }
 
     /// adjusted radius. Use diameter when it's half pie and width is larger
@@ -154,7 +149,7 @@ open class PieChartView: PieRadarChartViewBase
         super.calculateOffsets()
         
         // prevent nullpointer when no data set
-        if _data === nil
+        if data === nil
         {
             return
         }
@@ -210,29 +205,10 @@ open class PieChartView: PieRadarChartViewBase
     @objc open override func distanceToCenter(x: CGFloat, y: CGFloat) -> CGFloat
     {
         let c = adjustedCenterOffsets()
-
         var dist = CGFloat(0.0)
 
-        var xDist = CGFloat(0.0)
-        var yDist = CGFloat(0.0)
-
-        if x > c.x
-        {
-            xDist = x - c.x
-        }
-        else
-        {
-            xDist = c.x - x
-        }
-
-        if y > c.y
-        {
-            yDist = y - c.y
-        }
-        else
-        {
-            yDist = c.y - y
-        }
+        let xDist = x > c.x ? x - c.x : c.x - x
+        let yDist = y > c.y ? y - c.y : c.y - y
 
         // pythagoras
         dist = sqrt(pow(xDist, 2.0) + pow(yDist, 2.0))
@@ -262,9 +238,9 @@ open class PieChartView: PieRadarChartViewBase
         let offset = drawAngles[entryIndex] / 2.0
         
         // calculate the text position
-        let x: CGFloat = (r * cos(((rotationAngle + absoluteAngles[entryIndex] - offset) * CGFloat(_animator.phaseY)).DEG2RAD) + center.x)
-        let y: CGFloat = (r * sin(((rotationAngle + absoluteAngles[entryIndex] - offset) * CGFloat(_animator.phaseY)).DEG2RAD) + center.y)
-        
+        let x = (r * cos(((rotationAngle + absoluteAngles[entryIndex] - offset) * CGFloat(chartAnimator.phaseY)).DEG2RAD) + center.x)
+        let y = (r * sin(((rotationAngle + absoluteAngles[entryIndex] - offset) * CGFloat(chartAnimator.phaseY)).DEG2RAD) + center.y)
+
         return CGPoint(x: x, y: y)
     }
     
@@ -274,18 +250,18 @@ open class PieChartView: PieRadarChartViewBase
         _drawAngles = [CGFloat]()
         _absoluteAngles = [CGFloat]()
         
-        guard let data = _data else { return }
+        guard let data = data else { return }
 
         let entryCount = data.entryCount
         
         _drawAngles.reserveCapacity(entryCount)
         _absoluteAngles.reserveCapacity(entryCount)
         
-        let yValueSum = (_data as! PieChartData).yValueSum
+        let yValueSum = (data as! PieChartData).yValueSum
 
         var cnt = 0
 
-        for set in data.dataSets
+        for set in data
         {
             for j in 0 ..< set.entryCount
             {
@@ -310,13 +286,13 @@ open class PieChartView: PieRadarChartViewBase
     /// Checks if the given index is set to be highlighted.
     @objc open func needsHighlight(index: Int) -> Bool
     {
-        return _indicesToHighlight.contains { Int($0.x) == index }
+        return highlighted.contains { Int($0.x) == index }
     }
     
     /// calculates the needed angle for a given value
     private func calcAngle(_ value: Double) -> CGFloat
     {
-        return calcAngle(value: value, yValueSum: (_data as! PieChartData).yValueSum)
+        return calcAngle(value: value, yValueSum: (data as! PieChartData).yValueSum)
     }
     
     /// calculates the needed angle for a given value
@@ -328,7 +304,8 @@ open class PieChartView: PieRadarChartViewBase
     /// This will throw an exception, PieChart has no XAxis object.
     open override var xAxis: XAxis
     {
-        fatalError("PieChart has no XAxis")
+        get { fatalError("PieChart has no XAxis") }
+        set { fatalError("PieChart has no XAxis") }
     }
 
     open override func indexForAngle(_ angle: CGFloat) -> Int
@@ -343,7 +320,7 @@ open class PieChartView: PieRadarChartViewBase
     @objc open func dataSetIndexForIndex(_ xValue: Double) -> Int
     {
         // TODO: Return nil instead of -1
-        return _data?.dataSets.firstIndex {
+        return data?.firstIndex {
             $0.entryForXValue(xValue, closestToY: .nan) != nil
         } ?? -1
     }
@@ -440,7 +417,7 @@ open class PieChartView: PieRadarChartViewBase
             }
             else
             {
-                let paragraphStyle = NSParagraphStyle.default.mutableCopy() as! NSMutableParagraphStyle
+                let paragraphStyle = ParagraphStyle.default.mutableCopy() as! MutableParagraphStyle
                 paragraphStyle.lineBreakMode = .byTruncatingTail
                 paragraphStyle.alignment = .center
                 
@@ -508,7 +485,7 @@ open class PieChartView: PieRadarChartViewBase
     
     internal override var requiredLegendOffset: CGFloat
     {
-        return _legend.font.pointSize * 2.0
+        return legend.font.pointSize * 2.0
     }
     
     internal override var requiredBaseOffset: CGFloat
@@ -687,4 +664,12 @@ open class PieChartView: PieRadarChartViewBase
             }
         }
     }
+    
+    /// smallest pie slice angle that will have a label drawn in degrees, 0 by default
+    @objc open var sliceTextDrawingThreshold: CGFloat = 0.0
+    {
+        didSet {
+            setNeedsDisplay()
+        }
+    }
 }

+ 21 - 22
Pods/Charts/Source/Charts/Charts/PieRadarChartViewBase.swift

@@ -73,7 +73,7 @@ open class PieRadarChartViewBase: ChartViewBase
     
     internal override func calcMinMax()
     {
-        /*_xAxis.axisRange = Double((_data?.xVals.count ?? 0) - 1)*/
+        /*_xAxis.axisRange = Double((data?.xVals.count ?? 0) - 1)*/
     }
     
     open override var maxVisibleCount: Int
@@ -88,7 +88,7 @@ open class PieRadarChartViewBase: ChartViewBase
     {
         calcMinMax()
         
-        if let data = _data , _legend !== nil
+        if let data = data
         {
             legendRenderer.computeLegend(data: data)
         }
@@ -105,20 +105,20 @@ open class PieRadarChartViewBase: ChartViewBase
         var legendBottom = CGFloat(0.0)
         var legendTop = CGFloat(0.0)
 
-        if _legend != nil && _legend.enabled && !_legend.drawInside
+        if legend.enabled && !legend.drawInside
         {
-            let fullLegendWidth = min(_legend.neededWidth, _viewPortHandler.chartWidth * _legend.maxSizePercent)
+            let fullLegendWidth = min(legend.neededWidth, viewPortHandler.chartWidth * legend.maxSizePercent)
             
-            switch _legend.orientation
+            switch legend.orientation
             {
             case .vertical:
                 
                 var xLegendOffset: CGFloat = 0.0
                 
-                if _legend.horizontalAlignment == .left
-                    || _legend.horizontalAlignment == .right
+                if legend.horizontalAlignment == .left
+                    || legend.horizontalAlignment == .right
                 {
-                    if _legend.verticalAlignment == .center
+                    if legend.verticalAlignment == .center
                     {
                         // this is the space between the legend and the chart
                         let spacing = CGFloat(13.0)
@@ -131,11 +131,11 @@ open class PieRadarChartViewBase: ChartViewBase
                         let spacing = CGFloat(8.0)
                         
                         let legendWidth = fullLegendWidth + spacing
-                        let legendHeight = _legend.neededHeight + _legend.textHeightMax
+                        let legendHeight = legend.neededHeight + legend.textHeightMax
                         
                         let c = self.midPoint
                         
-                        let bottomX = _legend.horizontalAlignment == .right
+                        let bottomX = legend.horizontalAlignment == .right
                             ? self.bounds.width - legendWidth + 15.0
                             : legendWidth - 15.0
                         let bottomY = legendHeight + 15
@@ -160,7 +160,7 @@ open class PieRadarChartViewBase: ChartViewBase
                     }
                 }
                 
-                switch _legend.horizontalAlignment
+                switch legend.horizontalAlignment
                 {
                 case .left:
                     legendLeft = xLegendOffset
@@ -170,13 +170,13 @@ open class PieRadarChartViewBase: ChartViewBase
                     
                 case .center:
                     
-                    switch _legend.verticalAlignment
+                    switch legend.verticalAlignment
                     {
                     case .top:
-                        legendTop = min(_legend.neededHeight, _viewPortHandler.chartHeight * _legend.maxSizePercent)
+                        legendTop = min(legend.neededHeight, viewPortHandler.chartHeight * legend.maxSizePercent)
                         
                     case .bottom:
-                        legendBottom = min(_legend.neededHeight, _viewPortHandler.chartHeight * _legend.maxSizePercent)
+                        legendBottom = min(legend.neededHeight, viewPortHandler.chartHeight * legend.maxSizePercent)
                         
                     default:
                         break
@@ -187,8 +187,8 @@ open class PieRadarChartViewBase: ChartViewBase
                 
                 var yLegendOffset: CGFloat = 0.0
                 
-                if _legend.verticalAlignment == .top
-                    || _legend.verticalAlignment == .bottom
+                if legend.verticalAlignment == .top
+                    || legend.verticalAlignment == .bottom
                 {
                     // It's possible that we do not need this offset anymore as it
                     //   is available through the extraOffsets, but changing it can mean
@@ -196,11 +196,11 @@ open class PieRadarChartViewBase: ChartViewBase
                     let yOffset = self.requiredLegendOffset
                     
                     yLegendOffset = min(
-                        _legend.neededHeight + yOffset,
-                        _viewPortHandler.chartHeight * _legend.maxSizePercent)
+                        legend.neededHeight + yOffset,
+                        viewPortHandler.chartHeight * legend.maxSizePercent)
                 }
                 
-                switch _legend.verticalAlignment
+                switch legend.verticalAlignment
                 {
                 case .top:
                     
@@ -243,7 +243,7 @@ open class PieRadarChartViewBase: ChartViewBase
         let offsetRight = max(minOffset, legendRight)
         let offsetBottom = max(minOffset, max(self.requiredBaseOffset, legendBottom))
 
-        _viewPortHandler.restrainViewPort(offsetLeft: offsetLeft, offsetTop: offsetTop, offsetRight: offsetRight, offsetBottom: offsetBottom)
+        viewPortHandler.restrainViewPort(offsetLeft: offsetLeft, offsetTop: offsetTop, offsetRight: offsetRight, offsetBottom: offsetBottom)
     }
 
     /// - Returns: The angle relative to the chart center for the given point on the chart in degrees.
@@ -353,7 +353,7 @@ open class PieRadarChartViewBase: ChartViewBase
     /// The diameter of the pie- or radar-chart
     @objc open var diameter: CGFloat
     {
-        var content = _viewPortHandler.contentRect
+        var content = viewPortHandler.contentRect
         content.origin.x += extraLeftOffset
         content.origin.y += extraTopOffset
         content.size.width -= extraLeftOffset + extraRightOffset
@@ -678,7 +678,6 @@ open class PieRadarChartViewBase: ChartViewBase
 
         // Remove samples older than our sample time - 1 seconds
         // while keeping at least one sample
-        
         var i = 0, count = velocitySamples.count
         while (i < count - 2)
         {

+ 20 - 21
Pods/Charts/Source/Charts/Charts/RadarChartView.swift

@@ -61,11 +61,11 @@ open class RadarChartView: PieRadarChartViewBase
         _yAxis = YAxis(position: .left)
         _yAxis.labelXOffset = 10.0
         
-        renderer = RadarChartRenderer(chart: self, animator: _animator, viewPortHandler: _viewPortHandler)
-        
-        _yAxisRenderer = YAxisRendererRadarChart(viewPortHandler: _viewPortHandler, yAxis: _yAxis, chart: self)
-        _xAxisRenderer = XAxisRendererRadarChart(viewPortHandler: _viewPortHandler, xAxis: _xAxis, chart: self)
+        renderer = RadarChartRenderer(chart: self, animator: chartAnimator, viewPortHandler: viewPortHandler)
         
+        _yAxisRenderer = YAxisRendererRadarChart(viewPortHandler: viewPortHandler, axis: _yAxis, chart: self)
+        _xAxisRenderer = XAxisRendererRadarChart(viewPortHandler: viewPortHandler, axis: xAxis, chart: self)
+
         self.highlighter = RadarHighlighter(chart: self)
     }
 
@@ -73,10 +73,10 @@ open class RadarChartView: PieRadarChartViewBase
     {
         super.calcMinMax()
         
-        guard let data = _data else { return }
+        guard let data = data else { return }
         
         _yAxis.calculate(min: data.getYMin(axis: .left), max: data.getYMax(axis: .left))
-        _xAxis.calculate(min: 0.0, max: Double(data.maxEntryCountSet?.entryCount ?? 0))
+        xAxis.calculate(min: 0.0, max: Double(data.maxEntryCountSet?.entryCount ?? 0))
     }
     
     open override func notifyDataSetChanged()
@@ -84,13 +84,12 @@ open class RadarChartView: PieRadarChartViewBase
         calcMinMax()
 
         _yAxisRenderer?.computeAxis(min: _yAxis._axisMinimum, max: _yAxis._axisMaximum, inverted: _yAxis.isInverted)
-        _xAxisRenderer?.computeAxis(min: _xAxis._axisMinimum, max: _xAxis._axisMaximum, inverted: false)
+        _xAxisRenderer?.computeAxis(min: xAxis._axisMinimum, max: xAxis._axisMaximum, inverted: false)
         
-        if let data = _data,
-            let legend = _legend,
+        if let data = data,
             !legend.isLegendCustom
         {
-            legendRenderer?.computeLegend(data: data)
+            legendRenderer.computeLegend(data: data)
         }
         
         calculateOffsets()
@@ -107,9 +106,9 @@ open class RadarChartView: PieRadarChartViewBase
         let optionalContext = NSUIGraphicsGetCurrentContext()
         guard let context = optionalContext else { return }
         
-        if _xAxis.isEnabled
+        if xAxis.isEnabled
         {
-            _xAxisRenderer.computeAxis(min: _xAxis._axisMinimum, max: _xAxis._axisMaximum, inverted: false)
+            _xAxisRenderer.computeAxis(min: xAxis._axisMinimum, max: xAxis._axisMaximum, inverted: false)
         }
         
         _xAxisRenderer?.renderAxisLabels(context: context)
@@ -128,7 +127,7 @@ open class RadarChartView: PieRadarChartViewBase
 
         if valuesToHighlight()
         {
-            renderer.drawHighlighted(context: context, indices: _indicesToHighlight)
+            renderer.drawHighlighted(context: context, indices: highlighted)
         }
         
         if _yAxis.isEnabled && !_yAxis.isDrawLimitLinesBehindDataEnabled
@@ -142,7 +141,7 @@ open class RadarChartView: PieRadarChartViewBase
 
         legendRenderer.renderLegend(context: context)
 
-        drawDescription(context: context)
+        drawDescription(in: context)
 
         drawMarkers(context: context)
     }
@@ -150,7 +149,7 @@ open class RadarChartView: PieRadarChartViewBase
     /// The factor that is needed to transform values into pixels.
     @objc open var factor: CGFloat
     {
-        let content = _viewPortHandler.contentRect
+        let content = viewPortHandler.contentRect
         return min(content.width / 2.0, content.height / 2.0)
                 / CGFloat(_yAxis.axisRange)
     }
@@ -158,7 +157,7 @@ open class RadarChartView: PieRadarChartViewBase
     /// The angle that each slice in the radar chart occupies.
     @objc open var sliceAngle: CGFloat
     {
-        return 360.0 / CGFloat(_data?.maxEntryCountSet?.entryCount ?? 0)
+        return 360.0 / CGFloat(data?.maxEntryCountSet?.entryCount ?? 0)
     }
 
     open override func indexForAngle(_ angle: CGFloat) -> Int
@@ -168,10 +167,10 @@ open class RadarChartView: PieRadarChartViewBase
         
         let sliceAngle = self.sliceAngle
         
-        let max = _data?.maxEntryCountSet?.entryCount ?? 0
+        let max = data?.maxEntryCountSet?.entryCount ?? 0
         return (0..<max).firstIndex {
             sliceAngle * CGFloat($0 + 1) - sliceAngle / 2.0 > a
-        } ?? max
+        } ?? 0
     }
 
     /// The object that represents all y-labels of the RadarChart.
@@ -196,17 +195,17 @@ open class RadarChartView: PieRadarChartViewBase
     
     internal override var requiredLegendOffset: CGFloat
     {
-        return _legend.font.pointSize * 4.0
+        return legend.font.pointSize * 4.0
     }
 
     internal override var requiredBaseOffset: CGFloat
     {
-        return _xAxis.isEnabled && _xAxis.isDrawLabelsEnabled ? _xAxis.labelRotatedWidth : 10.0
+        return xAxis.isEnabled && xAxis.isDrawLabelsEnabled ? xAxis.labelRotatedWidth : 10.0
     }
 
     open override var radius: CGFloat
     {
-        let content = _viewPortHandler.contentRect
+        let content = viewPortHandler.contentRect
         return min(content.width / 2.0, content.height / 2.0)
     }
 

+ 2 - 2
Pods/Charts/Source/Charts/Charts/ScatterChartView.swift

@@ -19,7 +19,7 @@ open class ScatterChartView: BarLineChartViewBase, ScatterChartDataProvider
     {
         super.initialize()
         
-        renderer = ScatterChartRenderer(dataProvider: self, animator: _animator, viewPortHandler: _viewPortHandler)
+        renderer = ScatterChartRenderer(dataProvider: self, animator: chartAnimator, viewPortHandler: viewPortHandler)
 
         xAxis.spaceMin = 0.5
         xAxis.spaceMax = 0.5
@@ -27,5 +27,5 @@ open class ScatterChartView: BarLineChartViewBase, ScatterChartDataProvider
     
     // MARK: - ScatterChartDataProvider
     
-    open var scatterData: ScatterChartData? { return _data as? ScatterChartData }
+    open var scatterData: ScatterChartData? { return data as? ScatterChartData }
 }

+ 10 - 24
Pods/Charts/Source/Charts/Components/AxisBase.swift

@@ -22,7 +22,7 @@ open class AxisBase: ComponentBase
     }
     
     /// Custom formatter that is used instead of the auto-formatter if set
-    private var _axisValueFormatter: IAxisValueFormatter?
+    private lazy var _axisValueFormatter: AxisValueFormatter = DefaultAxisValueFormatter(decimals: decimals)
     
     @objc open var labelFont = NSUIFont.systemFont(ofSize: 10.0)
     @objc open var labelTextColor = NSUIColor.labelOrBlack
@@ -133,28 +133,18 @@ open class AxisBase: ComponentBase
     
     @objc open func getLongestLabel() -> String
     {
-        var longest = ""
-        
-        for i in 0 ..< entries.count
-        {
-            let text = getFormattedLabel(i)
-            
-            if longest.count < text.count
-            {
-                longest = text
-            }
-        }
-        
-        return longest
+        let longest = entries.indices
+            .lazy
+            .map(getFormattedLabel(_:))
+            .max(by: \.count)
+
+        return longest ?? ""
     }
     
     /// - Returns: The formatted label at the specified index. This will either use the auto-formatter or the custom formatter (if one is set).
     @objc open func getFormattedLabel(_ index: Int) -> String
     {
-        if index < 0 || index >= entries.count
-        {
-            return ""
-        }
+        guard entries.indices.contains(index) else { return "" }
         
         return valueFormatter?.stringForValue(entries[index], axis: self) ?? ""
     }
@@ -162,15 +152,11 @@ open class AxisBase: ComponentBase
     /// Sets the formatter to be used for formatting the axis labels.
     /// If no formatter is set, the chart will automatically determine a reasonable formatting (concerning decimals) for all the values that are drawn inside the chart.
     /// Use `nil` to use the formatter calculated by the chart.
-    @objc open var valueFormatter: IAxisValueFormatter?
+    @objc open var valueFormatter: AxisValueFormatter?
     {
         get
         {
-            if _axisValueFormatter == nil
-            {
-                _axisValueFormatter = DefaultAxisValueFormatter(decimals: decimals)
-            }
-            else if _axisValueFormatter is DefaultAxisValueFormatter &&
+            if _axisValueFormatter is DefaultAxisValueFormatter &&
             (_axisValueFormatter as! DefaultAxisValueFormatter).hasAutoDecimals &&
                 (_axisValueFormatter as! DefaultAxisValueFormatter).decimals != decimals
             {

+ 5 - 5
Pods/Charts/Source/Charts/Components/ChartLimitLine.swift

@@ -20,10 +20,10 @@ open class ChartLimitLine: ComponentBase
     @objc(ChartLimitLabelPosition)
     public enum LabelPosition: Int
     {
-        case topLeft
-        case topRight
-        case bottomLeft
-        case bottomRight
+        case leftTop
+        case leftBottom
+        case rightTop
+        case rightBottom
     }
     
     /// limit / maximum (the y-value or xIndex)
@@ -39,7 +39,7 @@ open class ChartLimitLine: ComponentBase
     
     @objc open var drawLabelEnabled = true
     @objc open var label = ""
-    @objc open var labelPosition = LabelPosition.topRight
+    @objc open var labelPosition = LabelPosition.rightTop
     
     public override init()
     {

+ 1 - 1
Pods/Charts/Source/Charts/Components/Description.swift

@@ -44,7 +44,7 @@ open class Description: ComponentBase
     open var position: CGPoint? = nil
     
     /// The text alignment of the description text. Default RIGHT.
-    @objc open var textAlign: NSTextAlignment = NSTextAlignment.right
+    @objc open var textAlign: TextAlignment = TextAlignment.right
     
     /// Font object used for drawing the description text.
     @objc open var font: NSUIFont

+ 9 - 11
Pods/Charts/Source/Charts/Components/Legend.swift

@@ -229,13 +229,12 @@ open class Legend: ComponentBase
             
             var wasStacked = false
             
-            for i in 0 ..< entryCount
+            for i in entries.indices
             {
                 let e = entries[i]
                 let drawingForm = e.form != .none
                 let formSize = e.formSize.isNaN ? defaultFormSize : e.formSize
-                let label = e.label
-                
+
                 if !wasStacked
                 {
                     width = 0.0
@@ -250,10 +249,10 @@ open class Legend: ComponentBase
                     width += formSize
                 }
                 
-                if label != nil
+                if let label = e.label
                 {
-                    let size = (label! as NSString).size(withAttributes: [.font: labelFont])
-                    
+                    let size = (label as NSString).size(withAttributes: [.font: labelFont])
+
                     if drawingForm && !wasStacked
                     {
                         width += formToTextSpace
@@ -307,13 +306,12 @@ open class Legend: ComponentBase
             
             // Start calculating layout
             
-            let labelAttrs = [NSAttributedString.Key.font: labelFont]
             var maxLineWidth: CGFloat = 0.0
             var currentLineWidth: CGFloat = 0.0
             var requiredWidth: CGFloat = 0.0
             var stackedStartIndex: Int = -1
             
-            for i in 0 ..< entryCount
+            for i in entries.indices
             {
                 let e = entries[i]
                 let drawingForm = e.form != .none
@@ -333,9 +331,9 @@ open class Legend: ComponentBase
                 }
                 
                 // grouped forms have null labels
-                if label != nil
+                if let label = label
                 {
-                    calculatedLabelSizes[i] = (label! as NSString).size(withAttributes: labelAttrs)
+                    calculatedLabelSizes[i] = (label as NSString).size(withAttributes: [.font: labelFont])
                     requiredWidth += drawingForm ? formToTextSpace + formSize : 0.0
                     requiredWidth += calculatedLabelSizes[i].width
                 }
@@ -386,7 +384,7 @@ open class Legend: ComponentBase
             
             neededWidth = maxLineWidth
             neededHeight = labelLineHeight * CGFloat(calculatedLineSizes.count) +
-                yEntrySpace * CGFloat(calculatedLineSizes.count == 0 ? 0 : (calculatedLineSizes.count - 1))
+                yEntrySpace * CGFloat(calculatedLineSizes.isEmpty ? 0 : (calculatedLineSizes.count - 1))
         }
         
         neededWidth += xOffset

+ 6 - 21
Pods/Charts/Source/Charts/Components/LegendEntry.swift

@@ -23,33 +23,18 @@ open class LegendEntry: NSObject
     /// - Parameters:
     ///   - label:                  The legend entry text.
     ///                                     A `nil` label will start a group.
-    ///   - form:                   The form to draw for this entry.
-    ///   - formSize:               Set to NaN to use the legend's default.
-    ///   - formLineWidth:          Set to NaN to use the legend's default.
-    ///   - formLineDashPhase:      Line dash configuration.
-    ///   - formLineDashLengths:    Line dash configurationas NaN to use the legend's default.
-    ///   - formColor:              The color for drawing the form.
-    @objc public init(label: String?,
-                form: Legend.Form,
-                formSize: CGFloat,
-                formLineWidth: CGFloat,
-                formLineDashPhase: CGFloat,
-                formLineDashLengths: [CGFloat]?,
-                formColor: NSUIColor?)
+    @objc public init(label: String?)
     {
         self.label = label
-        self.form = form
-        self.formSize = formSize
-        self.formLineWidth = formLineWidth
-        self.formLineDashPhase = formLineDashPhase
-        self.formLineDashLengths = formLineDashLengths
-        self.formColor = formColor
     }
-    
+
     /// The legend entry text.
     /// A `nil` label will start a group.
     @objc open var label: String?
-    
+
+    /// The color for drawing the label
+    @objc open var labelColor: NSUIColor?
+
     /// The form to draw for this entry.
     ///
     /// `None` will avoid drawing a form, and any related space.

+ 1 - 1
Pods/Charts/Source/Charts/Components/MarkerImage.swift

@@ -13,7 +13,7 @@ import Foundation
 import CoreGraphics
 
 @objc(ChartMarkerImage)
-open class MarkerImage: NSObject, IMarker
+open class MarkerImage: NSObject, Marker
 {
     /// The marker image to render
     @objc open var image: NSUIImage?

+ 4 - 5
Pods/Charts/Source/Charts/Components/MarkerView.swift

@@ -17,7 +17,7 @@ import AppKit
 #endif
 
 @objc(ChartMarkerView)
-open class MarkerView: NSUIView, IMarker
+open class MarkerView: NSUIView, Marker
 {
     open var offset: CGPoint = CGPoint()
     
@@ -82,15 +82,14 @@ open class MarkerView: NSUIView, IMarker
             options: nil)?[0] as? MarkerView
         #else
         
-        var loadedObjects = NSArray()
-        let loadedObjectsPointer = AutoreleasingUnsafeMutablePointer<NSArray?>(&loadedObjects)
+        var loadedObjects: NSArray? = NSArray()
         
         if bundle.loadNibNamed(
             NSNib.Name(String(describing: self)),
             owner: nil,
-            topLevelObjects: loadedObjectsPointer)
+            topLevelObjects: &loadedObjects)
         {
-            return loadedObjects[0] as? MarkerView
+            return loadedObjects?[0] as? MarkerView
         }
         
         return nil

+ 2 - 2
Pods/Charts/Source/Charts/Components/YAxis.swift

@@ -78,7 +78,7 @@ open class YAxis: AxisBase
     @objc open var labelPosition = LabelPosition.outsideChart
 
     /// the alignment of the text in the y-label
-    @objc open var labelAlignment: NSTextAlignment = .left
+    @objc open var labelAlignment: TextAlignment = .left
 
     /// the horizontal offset of the y-label
     @objc open var labelXOffset: CGFloat = 0.0
@@ -121,7 +121,7 @@ open class YAxis: AxisBase
     @objc open func requiredSize() -> CGSize
     {
         let label = getLongestLabel() as NSString
-        var size = label.size(withAttributes: [NSAttributedString.Key.font: labelFont])
+        var size = label.size(withAttributes: [.font: labelFont])
         size.width += xOffset * 2.0
         size.height += yOffset * 2.0
         size.width = max(minWidth, min(size.width, maxWidth > 0.0 ? maxWidth : size.width))

+ 10 - 32
Pods/Charts/Source/Charts/Data/Implementations/ChartBaseDataSet.swift

@@ -13,7 +13,7 @@ import Foundation
 import CoreGraphics
 
 
-open class ChartBaseDataSet: NSObject, IChartDataSet, NSCopying
+open class ChartBaseDataSet: NSObject, ChartDataSetProtocol, NSCopying
 {
     public required override init()
     {
@@ -24,7 +24,7 @@ open class ChartBaseDataSet: NSObject, IChartDataSet, NSCopying
         valueColors.append(.labelOrBlack)
     }
     
-    @objc public init(label: String?)
+    @objc public init(label: String)
     {
         super.init()
         
@@ -271,35 +271,10 @@ open class ChartBaseDataSet: NSObject, IChartDataSet, NSCopying
     
     /// `true` if value highlighting is enabled for this dataset
     open var isHighlightEnabled: Bool { return highlightEnabled }
-    
-    /// Custom formatter that is used instead of the auto-formatter if set
-    internal var _valueFormatter: IValueFormatter?
-    
+        
     /// Custom formatter that is used instead of the auto-formatter if set
-    open var valueFormatter: IValueFormatter?
-    {
-        get
-        {
-            if needsFormatter
-            {
-                return ChartUtils.defaultValueFormatter()
-            }
-            
-            return _valueFormatter
-        }
-        set
-        {
-            if newValue == nil { return }
-            
-            _valueFormatter = newValue
-        }
-    }
-    
-    open var needsFormatter: Bool
-    {
-        return _valueFormatter == nil
-    }
-    
+    open lazy var valueFormatter: ValueFormatter = DefaultValueFormatter()
+
     /// Sets/get a single color for value text.
     /// Setting the color clears the colors array and adds a single color.
     /// Getting will return the first color in the array.
@@ -330,6 +305,9 @@ open class ChartBaseDataSet: NSObject, IChartDataSet, NSCopying
     /// the font for the value-text labels
     open var valueFont: NSUIFont = NSUIFont.systemFont(ofSize: 7.0)
     
+    /// The rotation angle (in degrees) for value-text labels
+    open var valueLabelAngle: CGFloat = CGFloat(0.0)
+    
     /// The form to draw for this dataset in the legend.
     open var form = Legend.Form.default
     
@@ -418,7 +396,7 @@ open class ChartBaseDataSet: NSObject, IChartDataSet, NSCopying
         copy.label = label
         copy.axisDependency = axisDependency
         copy.highlightEnabled = highlightEnabled
-        copy._valueFormatter = _valueFormatter
+        copy.valueFormatter = valueFormatter
         copy.valueFont = valueFont
         copy.form = form
         copy.formSize = formSize
@@ -426,7 +404,7 @@ open class ChartBaseDataSet: NSObject, IChartDataSet, NSCopying
         copy.formLineDashPhase = formLineDashPhase
         copy.formLineDashLengths = formLineDashLengths
         copy.drawValuesEnabled = drawValuesEnabled
-        copy.drawValuesEnabled = drawValuesEnabled
+        copy.drawIconsEnabled = drawIconsEnabled
         copy.iconsOffset = iconsOffset
         copy.visible = visible
         

+ 13 - 12
Pods/Charts/Source/Charts/Data/Implementations/Standard/BarChartData.swift

@@ -14,16 +14,21 @@ import CoreGraphics
 
 open class BarChartData: BarLineScatterCandleBubbleChartData
 {
-    public override init()
+    public required init()
     {
         super.init()
     }
     
-    public override init(dataSets: [IChartDataSet]?)
+    public override init(dataSets: [ChartDataSetProtocol])
     {
         super.init(dataSets: dataSets)
     }
-    
+
+    public required init(arrayLiteral elements: ChartDataSetProtocol...)
+    {
+        super.init(dataSets: elements)
+    }
+
     /// The width of the bars on the x-axis, in values (not pixels)
     ///
     /// **default**: 0.85
@@ -39,13 +44,11 @@ open class BarChartData: BarLineScatterCandleBubbleChartData
     ///   - barSpace: The space between individual bars in values (not pixels) e.g. 0.1f for bar width 1f
     @objc open func groupBars(fromX: Double, groupSpace: Double, barSpace: Double)
     {
-        let setCount = _dataSets.count
-        if setCount <= 1
-        {
+        guard !isEmpty else {
             print("BarData needs to hold at least 2 BarDataSets to allow grouping.", terminator: "\n")
             return
         }
-        
+
         let max = maxEntryCountSet
         let maxEntryCount = max?.entryCount ?? 0
         
@@ -57,12 +60,12 @@ open class BarChartData: BarLineScatterCandleBubbleChartData
         
         let interval = groupWidth(groupSpace: groupSpace, barSpace: barSpace)
 
-        for i in stride(from: 0, to: maxEntryCount, by: 1)
+        for i in 0..<maxEntryCount
         {
             let start = fromX
             fromX += groupSpaceWidthHalf
             
-            (_dataSets as? [IBarChartDataSet])?.forEach { set in
+            (_dataSets as! [BarChartDataSetProtocol]).forEach { set in
                 fromX += barSpaceHalf
                 fromX += barWidthHalf
                 
@@ -88,7 +91,6 @@ open class BarChartData: BarLineScatterCandleBubbleChartData
             {
                 fromX += diff
             }
-
         }
         
         notifyDataChanged()
@@ -101,7 +103,6 @@ open class BarChartData: BarLineScatterCandleBubbleChartData
     ///   - barSpace:
     @objc open func groupWidth(groupSpace: Double, barSpace: Double) -> Double
     {
-        return Double(_dataSets.count) * (self.barWidth + barSpace) + groupSpace
+        return Double(count) * (self.barWidth + barSpace) + groupSpace
     }
-    
 }

+ 9 - 25
Pods/Charts/Source/Charts/Data/Implementations/Standard/BarChartDataEntry.swift

@@ -89,22 +89,14 @@ open class BarChartDataEntry: ChartDataEntry
         self.data = data
     }
     
-    @objc open func sumBelow(stackIndex :Int) -> Double
+    @objc open func sumBelow(stackIndex: Int) -> Double
     {
-        guard let yVals = _yVals else
+        guard let yVals = _yVals, yVals.indices.contains(stackIndex) else
         {
             return 0
         }
-        
-        var remainder: Double = 0.0
-        var index = yVals.count - 1
-        
-        while (index > stackIndex && index >= 0)
-        {
-            remainder += yVals[index]
-            index -= 1
-        }
-        
+
+        let remainder = yVals[stackIndex...].reduce(into: 0.0) { $0 += $1 }
         return remainder
     }
     
@@ -120,6 +112,8 @@ open class BarChartDataEntry: ChartDataEntry
         return _positiveSum
     }
 
+    var stackSize: Int { yValues?.count ?? 1}
+
     @objc open func calcPosNegSum()
     {
         (_negativeSum, _positiveSum) = _yVals?.reduce(into: (0,0)) { (result, y) in
@@ -183,7 +177,7 @@ open class BarChartDataEntry: ChartDataEntry
         get { return self._yVals }
         set
         {
-            self.y = BarChartDataEntry.calcSum(values: newValue)
+            self.y = BarChartDataEntry.calcSum(values: newValue ?? [])
             self._yVals = newValue
             calcPosNegSum()
             calcRanges()
@@ -213,18 +207,8 @@ open class BarChartDataEntry: ChartDataEntry
     /// - Parameters:
     ///   - vals:
     /// - Returns:
-    private static func calcSum(values: [Double]?) -> Double
+    private static func calcSum(values: [Double]) -> Double
     {
-        guard let values = values
-            else { return 0.0 }
-        
-        var sum = 0.0
-        
-        for f in values
-        {
-            sum += f
-        }
-        
-        return sum
+        values.reduce(into: 0, +=)
     }
 }

+ 21 - 54
Pods/Charts/Source/Charts/Data/Implementations/Standard/BarChartDataSet.swift

@@ -13,7 +13,7 @@ import Foundation
 import CoreGraphics
 
 
-open class BarChartDataSet: BarLineScatterCandleBubbleChartDataSet, IBarChartDataSet
+open class BarChartDataSet: BarLineScatterCandleBubbleChartDataSet, BarChartDataSetProtocol
 {
     private func initialize()
     {
@@ -29,7 +29,7 @@ open class BarChartDataSet: BarLineScatterCandleBubbleChartDataSet, IBarChartDat
         initialize()
     }
     
-    public override init(entries: [ChartDataEntry]?, label: String?)
+    public override init(entries: [ChartDataEntry], label: String)
     {
         super.init(entries: entries, label: label)
         initialize()
@@ -48,70 +48,37 @@ open class BarChartDataSet: BarLineScatterCandleBubbleChartDataSet, IBarChartDat
     /// stacks. All values belonging to a stack are calculated separately.
     private func calcEntryCountIncludingStacks(entries: [BarChartDataEntry])
     {
-        _entryCountStacks = 0
-        
-        for i in 0 ..< entries.count
-        {
-            if let vals = entries[i].yValues
-            {
-                _entryCountStacks += vals.count
-            }
-            else
-            {
-                _entryCountStacks += 1
-            }
-        }
+        _entryCountStacks = entries.lazy
+            .map(\.stackSize)
+            .reduce(into: 0, +=)
     }
     
     /// calculates the maximum stacksize that occurs in the Entries array of this DataSet
     private func calcStackSize(entries: [BarChartDataEntry])
     {
-        for i in 0 ..< entries.count
-        {
-            if let vals = entries[i].yValues
-            {
-                if vals.count > _stackSize
-                {
-                    _stackSize = vals.count
-                }
-            }
-        }
+        _stackSize = entries.lazy
+            .map(\.stackSize)
+            .max() ?? 1
     }
     
     open override func calcMinMax(entry e: ChartDataEntry)
     {
-        guard let e = e as? BarChartDataEntry
+        guard let e = e as? BarChartDataEntry,
+            !e.y.isNaN
             else { return }
         
-        if !e.y.isNaN
+        if e.yValues == nil
+        {
+            _yMin = Swift.min(e.y, _yMin)
+            _yMax = Swift.max(e.y, _yMax)
+        }
+        else
         {
-            if e.yValues == nil
-            {
-                if e.y < _yMin
-                {
-                    _yMin = e.y
-                }
-                
-                if e.y > _yMax
-                {
-                    _yMax = e.y
-                }
-            }
-            else
-            {
-                if -e.negativeSum < _yMin
-                {
-                    _yMin = -e.negativeSum
-                }
-                
-                if e.positiveSum > _yMax
-                {
-                    _yMax = e.positiveSum
-                }
-            }
-            
-            calcMinMaxX(entry: e)
+            _yMin = Swift.min(-e.negativeSum, _yMin)
+            _yMax = Swift.max(e.positiveSum, _yMax)
         }
+
+        calcMinMaxX(entry: e)
     }
     
     /// The maximum number of bars that can be stacked upon another in this DataSet.
@@ -123,7 +90,7 @@ open class BarChartDataSet: BarLineScatterCandleBubbleChartDataSet, IBarChartDat
     /// `true` if this DataSet is stacked (stacksize > 1) or not.
     open var isStacked: Bool
     {
-        return _stackSize > 1 ? true : false
+        return _stackSize > 1
     }
     
     /// The overall entry count, including counting each stack-value individually

+ 7 - 2
Pods/Charts/Source/Charts/Data/Implementations/Standard/BarLineScatterCandleBubbleChartData.swift

@@ -13,13 +13,18 @@ import Foundation
 
 open class BarLineScatterCandleBubbleChartData: ChartData
 {
-    public override init()
+    public required init()
     {
         super.init()
     }
     
-    public override init(dataSets: [IChartDataSet]?)
+    public override init(dataSets: [ChartDataSetProtocol])
     {
         super.init(dataSets: dataSets)
     }
+
+    public required init(arrayLiteral elements: ChartDataSetProtocol...)
+    {
+        super.init(dataSets: elements)
+    }
 }

+ 1 - 1
Pods/Charts/Source/Charts/Data/Implementations/Standard/BarLineScatterCandleBubbleChartDataSet.swift

@@ -13,7 +13,7 @@ import Foundation
 import CoreGraphics
 
 
-open class BarLineScatterCandleBubbleChartDataSet: ChartDataSet, IBarLineScatterCandleBubbleChartDataSet
+open class BarLineScatterCandleBubbleChartDataSet: ChartDataSet, BarLineScatterCandleBubbleChartDataSetProtocol
 {
     // MARK: - Data functions and accessors
     

+ 9 - 4
Pods/Charts/Source/Charts/Data/Implementations/Standard/BubbleChartData.swift

@@ -14,19 +14,24 @@ import CoreGraphics
 
 open class BubbleChartData: BarLineScatterCandleBubbleChartData
 {
-    public override init()
+    public required init()
     {
         super.init()
     }
     
-    public override init(dataSets: [IChartDataSet]?)
+    public override init(dataSets: [ChartDataSetProtocol])
     {
         super.init(dataSets: dataSets)
     }
-    
+
+    public required init(arrayLiteral elements: ChartDataSetProtocol...)
+    {
+        super.init(dataSets: elements)
+    }
+
     /// Sets the width of the circle that surrounds the bubble when highlighted for all DataSet objects this data object contains
     @objc open func setHighlightCircleWidth(_ width: CGFloat)
     {
-        (_dataSets as? [IBubbleChartDataSet])?.forEach { $0.highlightCircleWidth = width }
+        (_dataSets as? [BubbleChartDataSetProtocol])?.forEach { $0.highlightCircleWidth = width }
     }
 }

+ 2 - 7
Pods/Charts/Source/Charts/Data/Implementations/Standard/BubbleChartDataSet.swift

@@ -13,7 +13,7 @@ import Foundation
 import CoreGraphics
 
 
-open class BubbleChartDataSet: BarLineScatterCandleBubbleChartDataSet, IBubbleChartDataSet
+open class BubbleChartDataSet: BarLineScatterCandleBubbleChartDataSet, BubbleChartDataSetProtocol
 {
     // MARK: - Data functions and accessors
     
@@ -30,12 +30,7 @@ open class BubbleChartDataSet: BarLineScatterCandleBubbleChartDataSet, IBubbleCh
         
         super.calcMinMax(entry: e)
         
-        let size = e.size
-        
-        if size > _maxSize
-        {
-            _maxSize = size
-        }
+        _maxSize = Swift.max(e.size, maxSize)
     }
     
     // MARK: - Styling functions and accessors

+ 7 - 2
Pods/Charts/Source/Charts/Data/Implementations/Standard/CandleChartData.swift

@@ -13,13 +13,18 @@ import Foundation
 
 open class CandleChartData: BarLineScatterCandleBubbleChartData
 {
-    public override init()
+    public required init()
     {
         super.init()
     }
     
-    public override init(dataSets: [IChartDataSet]?)
+    public override init(dataSets: [ChartDataSetProtocol])
     {
         super.init(dataSets: dataSets)
     }
+
+    public required init(arrayLiteral elements: ChartDataSetProtocol...)
+    {
+        super.init(dataSets: elements)
+    }
 }

+ 14 - 33
Pods/Charts/Source/Charts/Data/Implementations/Standard/CandleChartDataSet.swift

@@ -13,7 +13,7 @@ import Foundation
 import CoreGraphics
 
 
-open class CandleChartDataSet: LineScatterCandleRadarChartDataSet, ICandleChartDataSet
+open class CandleChartDataSet: LineScatterCandleRadarChartDataSet, CandleChartDataSetProtocol
 {
     
     public required init()
@@ -21,7 +21,7 @@ open class CandleChartDataSet: LineScatterCandleRadarChartDataSet, ICandleChartD
         super.init()
     }
     
-    public override init(entries: [ChartDataEntry]?, label: String?)
+    public override init(entries: [ChartDataEntry], label: String)
     {
         super.init(entries: entries, label: label)
     }
@@ -32,17 +32,10 @@ open class CandleChartDataSet: LineScatterCandleRadarChartDataSet, ICandleChartD
     {
         guard let e = e as? CandleChartDataEntry
             else { return }
-        
-        if e.low < _yMin
-        {
-            _yMin = e.low
-        }
-        
-        if e.high > _yMax
-        {
-            _yMax = e.high
-        }
-        
+
+        _yMin = Swift.min(e.low, _yMin)
+        _yMax = Swift.max(e.high, _yMax)
+
         calcMinMaxX(entry: e)
     }
     
@@ -50,24 +43,12 @@ open class CandleChartDataSet: LineScatterCandleRadarChartDataSet, ICandleChartD
     {
         guard let e = e as? CandleChartDataEntry
             else { return }
-        
-        if e.high < _yMin
-        {
-            _yMin = e.high
-        }
-        if e.high > _yMax
-        {
-            _yMax = e.high
-        }
-        
-        if e.low < _yMin
-        {
-            _yMin = e.low
-        }
-        if e.low > _yMax
-        {
-            _yMax = e.low
-        }
+
+        _yMin = Swift.min(e.low, _yMin)
+        _yMax = Swift.max(e.high, _yMin)
+
+        _yMin = Swift.min(e.low, _yMax)
+        _yMax = Swift.max(e.high, _yMax)
     }
     
     // MARK: - Styling functions and accessors
@@ -75,8 +56,8 @@ open class CandleChartDataSet: LineScatterCandleRadarChartDataSet, ICandleChartD
     /// the space between the candle entries
     ///
     /// **default**: 0.1 (10%)
-    private var _barSpace = CGFloat(0.1)
-    
+    private var _barSpace: CGFloat = 0.1
+
     /// the space that is left out on the left and right side of each candle,
     /// **default**: 0.1 (10%), max 0.45, min 0.0
     open var barSpace: CGFloat

+ 324 - 360
Pods/Charts/Source/Charts/Data/Implementations/Standard/ChartData.swift

@@ -11,45 +11,58 @@
 
 import Foundation
 
-open class ChartData: NSObject
+open class ChartData: NSObject, ExpressibleByArrayLiteral
 {
-    internal var _yMax: Double = -Double.greatestFiniteMagnitude
-    internal var _yMin: Double = Double.greatestFiniteMagnitude
-    internal var _xMax: Double = -Double.greatestFiniteMagnitude
-    internal var _xMin: Double = Double.greatestFiniteMagnitude
-    internal var _leftAxisMax: Double = -Double.greatestFiniteMagnitude
-    internal var _leftAxisMin: Double = Double.greatestFiniteMagnitude
-    internal var _rightAxisMax: Double = -Double.greatestFiniteMagnitude
-    internal var _rightAxisMin: Double = Double.greatestFiniteMagnitude
+
+    @objc public internal(set) var xMax = -Double.greatestFiniteMagnitude
+    @objc public internal(set) var xMin = Double.greatestFiniteMagnitude
+    @objc public internal(set) var yMax = -Double.greatestFiniteMagnitude
+    @objc public internal(set) var yMin = Double.greatestFiniteMagnitude
+    var leftAxisMax = -Double.greatestFiniteMagnitude
+    var leftAxisMin = Double.greatestFiniteMagnitude
+    var rightAxisMax = -Double.greatestFiniteMagnitude
+    var rightAxisMin = Double.greatestFiniteMagnitude
+
+    // MARK: - Accessibility
+    
+    /// When the data entry labels are generated identifiers, set this property to prepend a string before each identifier
+    ///
+    /// For example, if a label is "#3", settings this property to "Item" allows it to be spoken as "Item #3"
+    @objc open var accessibilityEntryLabelPrefix: String?
+    
+    /// When the data entry value requires a unit, use this property to append the string representation of the unit to the value
+    ///
+    /// For example, if a value is "44.1", setting this property to "m" allows it to be spoken as "44.1 m"
+    @objc open var accessibilityEntryLabelSuffix: String?
     
-    internal var _dataSets = [IChartDataSet]()
+    /// If the data entry value is a count, set this to true to allow plurals and other grammatical changes
+    /// **default**: false
+    @objc open var accessibilityEntryLabelSuffixIsCount: Bool = false
     
-    public override init()
+    var _dataSets = [Element]()
+    
+    public override required init()
     {
         super.init()
-        
-        _dataSets = [IChartDataSet]()
     }
-    
-    @objc public init(dataSets: [IChartDataSet]?)
+
+    public required init(arrayLiteral elements: Element...)
     {
         super.init()
-        
-        _dataSets = dataSets ?? [IChartDataSet]()
-        
-        self.initialize(dataSets: _dataSets)
+        self.dataSets = elements
     }
-    
-    @objc public convenience init(dataSet: IChartDataSet?)
+
+    @objc public init(dataSets: [Element])
     {
-        self.init(dataSets: dataSet === nil ? nil : [dataSet!])
+        super.init()
+        self.dataSets = dataSets
     }
     
-    internal func initialize(dataSets: [IChartDataSet])
+    @objc public convenience init(dataSet: Element)
     {
-        notifyDataChanged()
+        self.init(dataSets: [dataSet])
     }
-    
+
     /// 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.
     @objc open func notifyDataChanged()
@@ -59,7 +72,8 @@ open class ChartData: NSObject
     
     @objc open func calcMinMaxY(fromX: Double, toX: Double)
     {
-        _dataSets.forEach { $0.calcMinMaxY(fromX: fromX, toX: toX) }
+        forEach { $0.calcMinMaxY(fromX: fromX, toX: toX) }
+        
         // apply the new data
         calcMinMax()
     }
@@ -67,39 +81,35 @@ open class ChartData: NSObject
     /// calc minimum and maximum y value over all datasets
     @objc open func calcMinMax()
     {
-        _yMax = -Double.greatestFiniteMagnitude
-        _yMin = Double.greatestFiniteMagnitude
-        _xMax = -Double.greatestFiniteMagnitude
-        _xMin = Double.greatestFiniteMagnitude
-        
-        _dataSets.forEach { calcMinMax(dataSet: $0) }
-        
-        _leftAxisMax = -Double.greatestFiniteMagnitude
-        _leftAxisMin = Double.greatestFiniteMagnitude
-        _rightAxisMax = -Double.greatestFiniteMagnitude
-        _rightAxisMin = Double.greatestFiniteMagnitude
-        
+        leftAxisMax = -.greatestFiniteMagnitude
+        leftAxisMin = .greatestFiniteMagnitude
+        rightAxisMax = -.greatestFiniteMagnitude
+        rightAxisMin = .greatestFiniteMagnitude
+        yMax = -.greatestFiniteMagnitude
+        yMin = .greatestFiniteMagnitude
+        xMax = -.greatestFiniteMagnitude
+        xMin = .greatestFiniteMagnitude
+
+        forEach { calcMinMax(dataSet: $0) }
+
         // left axis
         let firstLeft = getFirstLeft(dataSets: dataSets)
         
         if firstLeft !== nil
         {
-            _leftAxisMax = firstLeft!.yMax
-            _leftAxisMin = firstLeft!.yMin
-            
-            for dataSet in _dataSets
+            leftAxisMax = firstLeft!.yMax
+            leftAxisMin = firstLeft!.yMin
+
+            for dataSet in _dataSets where dataSet.axisDependency == .left
             {
-                if dataSet.axisDependency == .left
+                if dataSet.yMin < leftAxisMin
                 {
-                    if dataSet.yMin < _leftAxisMin
-                    {
-                        _leftAxisMin = dataSet.yMin
-                    }
-                    
-                    if dataSet.yMax > _leftAxisMax
-                    {
-                        _leftAxisMax = dataSet.yMax
-                    }
+                    leftAxisMin = dataSet.yMin
+                }
+
+                if dataSet.yMax > leftAxisMax
+                {
+                    leftAxisMax = dataSet.yMax
                 }
             }
         }
@@ -109,220 +119,126 @@ open class ChartData: NSObject
         
         if firstRight !== nil
         {
-            _rightAxisMax = firstRight!.yMax
-            _rightAxisMin = firstRight!.yMin
+            rightAxisMax = firstRight!.yMax
+            rightAxisMin = firstRight!.yMin
             
-            for dataSet in _dataSets
+            for dataSet in _dataSets where dataSet.axisDependency == .right
             {
-                if dataSet.axisDependency == .right
+                if dataSet.yMin < rightAxisMin
                 {
-                    if dataSet.yMin < _rightAxisMin
-                    {
-                        _rightAxisMin = dataSet.yMin
-                    }
-                    
-                    if dataSet.yMax > _rightAxisMax
-                    {
-                        _rightAxisMax = dataSet.yMax
-                    }
+                    rightAxisMin = dataSet.yMin
+                }
+
+                if dataSet.yMax > rightAxisMax
+                {
+                    rightAxisMax = dataSet.yMax
                 }
             }
         }
     }
-    
+
     /// Adjusts the current minimum and maximum values based on the provided Entry object.
     @objc open func calcMinMax(entry e: ChartDataEntry, axis: YAxis.AxisDependency)
     {
-        if _yMax < e.y
-        {
-            _yMax = e.y
-        }
-        
-        if _yMin > e.y
-        {
-            _yMin = e.y
-        }
-        
-        if _xMax < e.x
-        {
-            _xMax = e.x
-        }
-        
-        if _xMin > e.x
-        {
-            _xMin = e.x
-        }
-        
-        if axis == .left
-        {
-            if _leftAxisMax < e.y
-            {
-                _leftAxisMax = e.y
-            }
-            
-            if _leftAxisMin > e.y
-            {
-                _leftAxisMin = e.y
-            }
-        }
-        else
+        xMax = Swift.max(xMax, e.x)
+        xMin = Swift.min(xMin, e.x)
+        yMax = Swift.max(yMax, e.y)
+        yMin = Swift.min(yMin, e.y)
+
+        switch axis
         {
-            if _rightAxisMax < e.y
-            {
-                _rightAxisMax = e.y
-            }
-            
-            if _rightAxisMin > e.y
-            {
-                _rightAxisMin = e.y
-            }
+        case .left:
+            leftAxisMax = Swift.max(leftAxisMax, e.y)
+            leftAxisMin = Swift.min(leftAxisMin, e.y)
+
+        case .right:
+            rightAxisMax = Swift.max(rightAxisMax, e.y)
+            rightAxisMin = Swift.min(rightAxisMin, e.y)
         }
     }
     
     /// Adjusts the minimum and maximum values based on the given DataSet.
-    @objc open func calcMinMax(dataSet d: IChartDataSet)
+    @objc open func calcMinMax(dataSet d: Element)
     {
-        if _yMax < d.yMax
-        {
-            _yMax = d.yMax
-        }
-        
-        if _yMin > d.yMin
-        {
-            _yMin = d.yMin
-        }
-        
-        if _xMax < d.xMax
-        {
-            _xMax = d.xMax
-        }
-        
-        if _xMin > d.xMin
-        {
-            _xMin = d.xMin
-        }
-        
-        if d.axisDependency == .left
-        {
-            if _leftAxisMax < d.yMax
-            {
-                _leftAxisMax = d.yMax
-            }
-            
-            if _leftAxisMin > d.yMin
-            {
-                _leftAxisMin = d.yMin
-            }
-        }
-        else
+        xMax = Swift.max(xMax, d.xMax)
+        xMin = Swift.min(xMin, d.xMin)
+        yMax = Swift.max(yMax, d.yMax)
+        yMin = Swift.min(yMin, d.yMin)
+
+        switch d.axisDependency
         {
-            if _rightAxisMax < d.yMax
-            {
-                _rightAxisMax = d.yMax
-            }
-            
-            if _rightAxisMin > d.yMin
-            {
-                _rightAxisMin = d.yMin
-            }
+        case .left:
+            leftAxisMax = Swift.max(leftAxisMax, d.yMax)
+            leftAxisMin = Swift.min(leftAxisMin, d.yMin)
+
+        case .right:
+            rightAxisMax = Swift.max(rightAxisMax, d.yMax)
+            rightAxisMin = Swift.min(rightAxisMin, d.yMin)
         }
     }
     
     /// The number of LineDataSets this object contains
+    // exists only for objc compatibility
     @objc open var dataSetCount: Int
     {
-        return _dataSets.count
-    }
-    
-    /// The smallest y-value the data object contains.
-    @objc open var yMin: Double
-    {
-        return _yMin
-    }
-    
-    @nonobjc
-    open func getYMin() -> Double
-    {
-        return _yMin
+        return dataSets.count
     }
-    
+
     @objc open func getYMin(axis: YAxis.AxisDependency) -> Double
     {
-        if axis == .left
+        // TODO: Why does it make sense to return the other axisMin if there is none for the one requested?
+        switch axis
         {
-            if _leftAxisMin == Double.greatestFiniteMagnitude
+        case .left:
+            if leftAxisMin == .greatestFiniteMagnitude
             {
-                return _rightAxisMin
+                return rightAxisMin
             }
             else
             {
-                return _leftAxisMin
+                return leftAxisMin
             }
-        }
-        else
-        {
-            if _rightAxisMin == Double.greatestFiniteMagnitude
+
+        case .right:
+            if rightAxisMin == .greatestFiniteMagnitude
             {
-                return _leftAxisMin
+                return leftAxisMin
             }
             else
             {
-                return _rightAxisMin
+                return rightAxisMin
             }
         }
     }
     
-    /// The greatest y-value the data object contains.
-    @objc open var yMax: Double
-    {
-        return _yMax
-    }
-    
-    @nonobjc
-    open func getYMax() -> Double
-    {
-        return _yMax
-    }
-    
     @objc open func getYMax(axis: YAxis.AxisDependency) -> Double
     {
         if axis == .left
         {
-            if _leftAxisMax == -Double.greatestFiniteMagnitude
+            if leftAxisMax == -.greatestFiniteMagnitude
             {
-                return _rightAxisMax
+                return rightAxisMax
             }
             else
             {
-                return _leftAxisMax
+                return leftAxisMax
             }
         }
         else
         {
-            if _rightAxisMax == -Double.greatestFiniteMagnitude
+            if rightAxisMax == -.greatestFiniteMagnitude
             {
-                return _leftAxisMax
+                return leftAxisMax
             }
             else
             {
-                return _rightAxisMax
+                return rightAxisMax
             }
         }
     }
     
-    /// The minimum x-value the data object contains.
-    @objc open var xMin: Double
-    {
-        return _xMin
-    }
-    /// The maximum x-value the data object contains.
-    @objc open var xMax: Double
-    {
-        return _xMax
-    }
-    
     /// All DataSet objects this ChartData object holds.
-    @objc open var dataSets: [IChartDataSet]
+    @objc open var dataSets: [Element]
     {
         get
         {
@@ -334,46 +250,16 @@ open class ChartData: NSObject
             notifyDataChanged()
         }
     }
-    
-    /// Retrieve the index of a ChartDataSet with a specific label from the ChartData. Search can be case sensitive or not.
-    /// 
-    /// **IMPORTANT: This method does calculations at runtime, do not over-use in performance critical situations.**
-    ///
-    /// - Parameters:
-    ///   - dataSets: the DataSet array to search
-    ///   - type:
-    ///   - ignorecase: if true, the search is not case-sensitive
-    /// - Returns: The index of the DataSet Object with the given label. Sensitive or not.
-    internal func getDataSetIndexByLabel(_ label: String, ignorecase: Bool) -> Int
-    {
-        // TODO: Return nil instead of -1
-        if ignorecase
-        {
-            return dataSets.firstIndex { $0.label?.caseInsensitiveCompare(label) == .orderedSame }
-                ?? -1
-        }
-        else
-        {
-            return dataSets.firstIndex { $0.label == label }
-                ?? -1
-        }
-    }
 
     /// Get the Entry for a corresponding highlight object
     ///
     /// - Parameters:
     ///   - highlight:
     /// - Returns: The entry that is highlighted
-    @objc open func entryForHighlight(_ highlight: Highlight) -> ChartDataEntry?
+    @objc open func entry(for highlight: Highlight) -> ChartDataEntry?
     {
-        if highlight.dataSetIndex >= dataSets.count
-        {
-            return nil
-        }
-        else
-        {
-            return dataSets[highlight.dataSetIndex].entryForXValue(highlight.x, closestToY: highlight.y)
-        }
+        guard highlight.dataSetIndex < dataSets.endIndex else { return nil }
+        return self[highlight.dataSetIndex].entryForXValue(highlight.x, closestToY: highlight.y)
     }
     
     /// **IMPORTANT: This method does calculations at runtime. Use with care in performance critical situations.**
@@ -382,93 +268,49 @@ open class ChartData: NSObject
     ///   - label:
     ///   - ignorecase:
     /// - Returns: The DataSet Object with the given label. Sensitive or not.
-    @objc open func getDataSetByLabel(_ label: String, ignorecase: Bool) -> IChartDataSet?
-    {
-        let index = getDataSetIndexByLabel(label, ignorecase: ignorecase)
-        
-        if index < 0 || index >= _dataSets.count
-        {
-            return nil
-        }
-        else
-        {
-            return _dataSets[index]
-        }
-    }
-    
-    @objc open func getDataSetByIndex(_ index: Int) -> IChartDataSet!
+    @objc open func dataSet(forLabel label: String, ignorecase: Bool) -> Element?
     {
-        if index < 0 || index >= _dataSets.count
-        {
-            return nil
-        }
-        
-        return _dataSets[index]
+        guard let index = index(forLabel: label, ignoreCase: ignorecase) else { return nil }
+        return self[index]
     }
     
-    @objc open func addDataSet(_ dataSet: IChartDataSet!)
+    @objc(dataSetAtIndex:)
+    open func dataSet(at index: Index) -> Element?
     {
-        calcMinMax(dataSet: dataSet)
-        
-        _dataSets.append(dataSet)
+        guard dataSets.indices.contains(index) else { return nil }
+        return self[index]
     }
-    
+
     /// Removes the given DataSet from this data object.
     /// Also recalculates all minimum and maximum values.
     ///
     /// - Returns: `true` if a DataSet was removed, `false` ifno DataSet could be removed.
-    @objc @discardableResult open func removeDataSet(_ dataSet: IChartDataSet) -> Bool
+    @objc @discardableResult open func removeDataSet(_ dataSet: Element) -> Element?
     {
-        guard let i = _dataSets.firstIndex(where: { $0 === dataSet }) else { return false }
-        return removeDataSetByIndex(i)
+        guard let index = firstIndex(where: { $0 === dataSet }) else { return nil }
+        return remove(at: index)
     }
-    
-    /// Removes the DataSet at the given index in the DataSet array from the data object. 
-    /// Also recalculates all minimum and maximum values. 
-    ///
-    /// - Returns: `true` if a DataSet was removed, `false` ifno DataSet could be removed.
-    @objc @discardableResult open func removeDataSetByIndex(_ index: Int) -> Bool
-    {
-        if index >= _dataSets.count || index < 0
-        {
-            return false
-        }
-        
-        _dataSets.remove(at: index)
-        
-        calcMinMax()
-        
-        return true
-    }
-    
+
     /// Adds an Entry to the DataSet at the specified index. Entries are added to the end of the list.
-    @objc open func addEntry(_ e: ChartDataEntry, dataSetIndex: Int)
+    @objc(addEntry:dataSetIndex:)
+    open func appendEntry(_ e: ChartDataEntry, toDataSet dataSetIndex: Index)
     {
-        if _dataSets.count > dataSetIndex && dataSetIndex >= 0
-        {
-            let set = _dataSets[dataSetIndex]
-            
-            if !set.addEntry(e) { return }
-            
-            calcMinMax(entry: e, axis: set.axisDependency)
-        }
-        else
-        {
-            print("ChartData.addEntry() - Cannot add Entry because dataSetIndex too high or too low.", terminator: "\n")
+        guard dataSets.indices.contains(dataSetIndex) else {
+            return print("ChartData.addEntry() - Cannot add Entry because dataSetIndex too high or too low.", terminator: "\n")
         }
+
+        let set = self[dataSetIndex]
+        if !set.addEntry(e) { return }
+        calcMinMax(entry: e, axis: set.axisDependency)
     }
-    
+
     /// Removes the given Entry object from the DataSet at the specified index.
-    @objc @discardableResult open func removeEntry(_ entry: ChartDataEntry, dataSetIndex: Int) -> Bool
+    @objc @discardableResult open func removeEntry(_ entry: ChartDataEntry, dataSetIndex: Index) -> Bool
     {
-        // entry outofbounds
-        if dataSetIndex >= _dataSets.count
-        {
-            return false
-        }
-        
+        guard dataSets.indices.contains(dataSetIndex) else { return false }
+
         // remove the entry from the dataset
-        let removed = _dataSets[dataSetIndex].removeEntry(entry)
+        let removed = self[dataSetIndex].removeEntry(entry)
         
         if removed
         {
@@ -482,129 +324,251 @@ open class ChartData: NSObject
     /// specified index. 
     ///
     /// - Returns: `true` if an entry was removed, `false` ifno Entry was found that meets the specified requirements.
-    @objc @discardableResult open func removeEntry(xValue: Double, dataSetIndex: Int) -> Bool
+    @objc @discardableResult open func removeEntry(xValue: Double, dataSetIndex: Index) -> Bool
     {
-        if dataSetIndex >= _dataSets.count
-        {
-            return false
-        }
-        
-        if let entry = _dataSets[dataSetIndex].entryForXValue(xValue, closestToY: Double.nan)
-        {
-            return removeEntry(entry, dataSetIndex: dataSetIndex)
-        }
-        
-        return false
+        guard
+            dataSets.indices.contains(dataSetIndex),
+            let entry = self[dataSetIndex].entryForXValue(xValue, closestToY: .nan)
+            else { return false }
+
+        return removeEntry(entry, dataSetIndex: dataSetIndex)
     }
     
     /// - Returns: The DataSet that contains the provided Entry, or null, if no DataSet contains this entry.
-    @objc open func getDataSetForEntry(_ e: ChartDataEntry) -> IChartDataSet?
+    @objc open func getDataSetForEntry(_ e: ChartDataEntry) -> Element?
     {
-        return _dataSets.first { $0.entryForXValue(e.x, closestToY: e.y) === e }
+        return first { $0.entryForXValue(e.x, closestToY: e.y) === e }
     }
 
     /// - Returns: The index of the provided DataSet in the DataSet array of this data object, or -1 if it does not exist.
-    @objc open func indexOfDataSet(_ dataSet: IChartDataSet) -> Int
+    @objc open func index(of dataSet: Element) -> Index
     {
         // TODO: Return nil instead of -1
-        return _dataSets.firstIndex { $0 === dataSet } ?? -1
+        return firstIndex(where: { $0 === dataSet }) ?? -1
     }
     
     /// - Returns: The first DataSet from the datasets-array that has it's dependency on the left axis. Returns null if no DataSet with left dependency could be found.
-    @objc open func getFirstLeft(dataSets: [IChartDataSet]) -> IChartDataSet?
+    @objc open func getFirstLeft(dataSets: [Element]) -> Element?
     {
-        return dataSets.first { $0.axisDependency == .left }
+        return first { $0.axisDependency == .left }
     }
     
     /// - Returns: The first DataSet from the datasets-array that has it's dependency on the right axis. Returns null if no DataSet with right dependency could be found.
-    @objc open func getFirstRight(dataSets: [IChartDataSet]) -> IChartDataSet?
+    @objc open func getFirstRight(dataSets: [Element]) -> Element?
     {
-        return dataSets.first { $0.axisDependency == .right }
+        return first { $0.axisDependency == .right }
     }
     
     /// - Returns: All colors used across all DataSet objects this object represents.
-    @objc open func getColors() -> [NSUIColor]?
+    @objc open var colors: [NSUIColor]
     {
         // TODO: Don't return nil
-        return _dataSets.flatMap { $0.colors }
+        return reduce(into: []) { $0 += $1.colors }
     }
     
-    /// Sets a custom IValueFormatter for all DataSets this data object contains.
-    @objc open func setValueFormatter(_ formatter: IValueFormatter)
+    /// Sets a custom ValueFormatter for all DataSets this data object contains.
+    @objc open func setValueFormatter(_ formatter: ValueFormatter)
     {
-        dataSets.forEach { $0.valueFormatter = formatter }
+        forEach { $0.valueFormatter = formatter }
     }
     
     /// Sets the color of the value-text (color in which the value-labels are drawn) for all DataSets this data object contains.
     @objc open func setValueTextColor(_ color: NSUIColor)
     {
-        dataSets.forEach { $0.valueTextColor = color }
+        forEach { $0.valueTextColor = color }
     }
     
     /// Sets the font for all value-labels for all DataSets this data object contains.
     @objc open func setValueFont(_ font: NSUIFont)
     {
-        dataSets.forEach { $0.valueFont = font }
+        forEach { $0.valueFont = font }
     }
 
     /// Enables / disables drawing values (value-text) for all DataSets this data object contains.
     @objc open func setDrawValues(_ enabled: Bool)
     {
-        dataSets.forEach { $0.drawValuesEnabled = enabled }
+        forEach { $0.drawValuesEnabled = enabled }
     }
     
     /// Enables / disables highlighting values for all DataSets this data object contains.
     /// If set to true, this means that values can be highlighted programmatically or by touch gesture.
-    @objc open var highlightEnabled: Bool
+    @objc open var isHighlightEnabled: Bool
     {
-        get { return dataSets.allSatisfy { $0.highlightEnabled } }
-        set { dataSets.forEach { $0.highlightEnabled = newValue } }
+        get { return allSatisfy { $0.isHighlightEnabled } }
+        set { forEach { $0.highlightEnabled = newValue } }
     }
-    
-    /// if true, value highlightning is enabled
-    @objc open var isHighlightEnabled: Bool { return highlightEnabled }
-    
+
     /// Clears this data object from all DataSets and removes all Entries.
     /// Don't forget to invalidate the chart after this.
     @objc open func clearValues()
     {
-        dataSets.removeAll(keepingCapacity: false)
-        notifyDataChanged()
+        removeAll(keepingCapacity: false)
     }
     
     /// Checks if this data object contains the specified DataSet. 
     ///
     /// - Returns: `true` if so, `false` ifnot.
-    @objc open func contains(dataSet: IChartDataSet) -> Bool
+    @objc open func contains(dataSet: Element) -> Bool
     {
-        return dataSets.contains { $0 === dataSet }
+        return contains { $0 === dataSet }
     }
     
     /// The total entry count across all DataSet objects this data object contains.
     @objc open var entryCount: Int
     {
-        return _dataSets.reduce(0) { $0 + $1.entryCount }
+        return reduce(0) { return $0 + $1.entryCount }
     }
 
     /// The DataSet object with the maximum number of entries or null if there are no DataSets.
-    @objc open var maxEntryCountSet: IChartDataSet?
+    @objc open var maxEntryCountSet: Element?
     {
-        return dataSets.max { $0.entryCount < $1.entryCount }
+        return self.max { $0.entryCount < $1.entryCount }
     }
+}
 
-    // MARK: - Accessibility
+// MARK: MutableCollection
+extension ChartData: MutableCollection
+{
+    public typealias Index = Int
+    public typealias Element = ChartDataSetProtocol
 
-    /// When the data entry labels are generated identifiers, set this property to prepend a string before each identifier
-    ///
-    /// For example, if a label is "#3", settings this property to "Item" allows it to be spoken as "Item #3"
-    @objc open var accessibilityEntryLabelPrefix: String?
+    public var startIndex: Index
+    {
+        return dataSets.startIndex
+    }
 
-    /// When the data entry value requires a unit, use this property to append the string representation of the unit to the value
+    public var endIndex: Index
+    {
+        return dataSets.endIndex
+    }
+
+    public func index(after: Index) -> Index
+    {
+        return dataSets.index(after: after)
+    }
+
+    public subscript(position: Index) -> Element
+    {
+        get { return dataSets[position] }
+        set { self._dataSets[position] = newValue }
+    }
+}
+
+// MARK: RandomAccessCollection
+extension ChartData: RandomAccessCollection
+{
+    public func index(before: Index) -> Index
+    {
+        return dataSets.index(before: before)
+    }
+}
+
+// TODO: Conform when dropping Objective-C support
+// MARK: RangeReplaceableCollection
+extension ChartData//: RangeReplaceableCollection
+{
+    @objc(addDataSet:)
+    public func append(_ newElement: Element)
+    {
+        _dataSets.append(newElement)
+        calcMinMax(dataSet: newElement)
+    }
+
+    @objc(removeDataSetByIndex:)
+    public func remove(at position: Index) -> Element
+    {
+        let element = _dataSets.remove(at: position)
+        calcMinMax()
+        return element
+    }
+
+    public func removeFirst() -> Element
+    {
+        assert(!(self is CombinedChartData), "\(#function) not supported for CombinedData")
+
+        let element = _dataSets.removeFirst()
+        notifyDataChanged()
+        return element
+    }
+
+    public func removeFirst(_ n: Int)
+    {
+        assert(!(self is CombinedChartData), "\(#function) not supported for CombinedData")
+
+        _dataSets.removeFirst(n)
+        notifyDataChanged()
+    }
+
+    public func removeLast() -> Element
+    {
+        assert(!(self is CombinedChartData), "\(#function) not supported for CombinedData")
+
+        let element = _dataSets.removeLast()
+        notifyDataChanged()
+        return element
+    }
+
+    public func removeLast(_ n: Int)
+    {
+        assert(!(self is CombinedChartData), "\(#function) not supported for CombinedData")
+
+        _dataSets.removeLast(n)
+        notifyDataChanged()
+    }
+
+    public func removeSubrange<R>(_ bounds: R) where R : RangeExpression, Index == R.Bound
+    {
+        assert(!(self is CombinedChartData), "\(#function) not supported for CombinedData")
+
+        _dataSets.removeSubrange(bounds)
+        notifyDataChanged()
+    }
+
+    public func removeAll(keepingCapacity keepCapacity: Bool)
+    {
+        assert(!(self is CombinedChartData), "\(#function) not supported for CombinedData")
+
+        _dataSets.removeAll(keepingCapacity: keepCapacity)
+        notifyDataChanged()
+    }
+
+    public func replaceSubrange<C>(_ subrange: Swift.Range<Index>, with newElements: C) where C : Collection, Element == C.Element
+    {
+        assert(!(self is CombinedChartData), "\(#function) not supported for CombinedData")
+
+        _dataSets.replaceSubrange(subrange, with: newElements)
+        newElements.forEach { self.calcMinMax(dataSet: $0) }
+    }
+}
+
+// MARK: Swift Accessors
+extension ChartData
+{
+    /// Retrieve the index of a ChartDataSet with a specific label from the ChartData. Search can be case sensitive or not.
+    /// **IMPORTANT: This method does calculations at runtime, do not over-use in performance critical situations.**
     ///
-    /// For example, if a value is "44.1", setting this property to "m" allows it to be spoken as "44.1 m"
-    @objc open var accessibilityEntryLabelSuffix: String?
+    /// - Parameters:
+    ///   - label: The label to search for
+    ///   - ignoreCase: if true, the search is not case-sensitive
+    /// - Returns: The index of the DataSet Object with the given label. `nil` if not found
+    public func index(forLabel label: String, ignoreCase: Bool) -> Index?
+    {
+        return ignoreCase
+            ? firstIndex { $0.label?.caseInsensitiveCompare(label) == .orderedSame }
+            : firstIndex { $0.label == label }
+    }
 
-    /// If the data entry value is a count, set this to true to allow plurals and other grammatical changes
-    /// **default**: false
-    @objc open var accessibilityEntryLabelSuffixIsCount: Bool = false
+    public subscript(label label: String, ignoreCase ignoreCase: Bool) -> Element?
+    {
+        guard let index = index(forLabel: label, ignoreCase: ignoreCase) else { return nil }
+        return self[index]
+    }
+
+    public subscript(entry entry: ChartDataEntry) -> Element?
+    {
+        assert(!(self is CombinedChartData), "\(#function) not supported for CombinedData")
+
+        guard let index = firstIndex(where: { $0.entryForXValue(entry.x, closestToY: entry.y) === entry }) else { return nil }
+        return self[index]
+    }
 }

+ 88 - 173
Pods/Charts/Source/Charts/Data/Implementations/Standard/ChartDataSet.swift

@@ -9,6 +9,7 @@
 //  https://github.com/danielgindi/Charts
 //
 
+import Algorithms
 import Foundation
 
 /// Determines how to round DataSet index values for `ChartDataSet.entryIndex(x, rounding)` when an exact x-value is not found.
@@ -27,25 +28,25 @@ open class ChartDataSet: ChartBaseDataSet
     public required init()
     {
         entries = []
-
+        
         super.init()
     }
     
-    public override convenience init(label: String?)
+    public override convenience init(label: String)
     {
-        self.init(entries: nil, label: label)
+        self.init(entries: [], label: label)
     }
     
-    @objc public init(entries: [ChartDataEntry]?, label: String?)
+    @objc public init(entries: [ChartDataEntry], label: String)
     {
-        self.entries = entries ?? []
+        self.entries = entries 
 
         super.init(label: label)
 
         self.calcMinMax()
     }
     
-    @objc public convenience init(entries: [ChartDataEntry]?)
+    @objc public convenience init(entries: [ChartDataEntry])
     {
         self.init(entries: entries, label: "DataSet")
     }
@@ -55,10 +56,6 @@ open class ChartDataSet: ChartBaseDataSet
     /// - Note: Calls `notifyDataSetChanged()` after setting a new value.
     /// - Returns: The array of y-values that this DataSet represents.
     /// the entries that this dataset represents / holds together
-    @available(*, unavailable, renamed: "entries")
-    @objc
-    open var values: [ChartDataEntry] { return entries }
-
     @objc
     open private(set) var entries: [ChartDataEntry]
 
@@ -104,36 +101,25 @@ open class ChartDataSet: ChartBaseDataSet
 
         guard !isEmpty else { return }
         
-        let indexFrom = entryIndex(x: fromX, closestToY: Double.nan, rounding: .down)
-        let indexTo = entryIndex(x: toX, closestToY: Double.nan, rounding: .up)
+        let indexFrom = entryIndex(x: fromX, closestToY: .nan, rounding: .closest)
+        var indexTo = entryIndex(x: toX, closestToY: .nan, rounding: .up)
+        if indexTo == -1 { indexTo = entryIndex(x: toX, closestToY: .nan, rounding: .closest) }
         
-        guard !(indexTo < indexFrom) else { return }
+        guard indexTo >= indexFrom else { return }
         // only recalculate y
         self[indexFrom...indexTo].forEach(calcMinMaxY)
     }
     
     @objc open func calcMinMaxX(entry e: ChartDataEntry)
     {
-        if e.x < _xMin
-        {
-            _xMin = e.x
-        }
-        if e.x > _xMax
-        {
-            _xMax = e.x
-        }
+        _xMin = Swift.min(e.x, _xMin)
+        _xMax = Swift.max(e.x, _xMax)
     }
     
     @objc open func calcMinMaxY(entry e: ChartDataEntry)
     {
-        if e.y < _yMin
-        {
-            _yMin = e.y
-        }
-        if e.y > _yMax
-        {
-            _yMax = e.y
-        }
+        _yMin = Swift.min(e.y, _yMin)
+        _yMax = Swift.max(e.y, _yMax)
     }
     
     /// Updates the min and max x and y value of this DataSet based on the given Entry.
@@ -147,16 +133,16 @@ open class ChartDataSet: ChartBaseDataSet
     }
     
     /// The minimum y-value this DataSet holds
-    open override var yMin: Double { return _yMin }
+    @objc open override var yMin: Double { return _yMin }
     
     /// The maximum y-value this DataSet holds
-    open override var yMax: Double { return _yMax }
+    @objc open override var yMax: Double { return _yMax }
     
     /// The minimum x-value this DataSet holds
-    open override var xMin: Double { return _xMin }
+    @objc open override var xMin: Double { return _xMin }
     
     /// The maximum x-value this DataSet holds
-    open override var xMax: Double { return _xMax }
+    @objc open override var xMax: Double { return _xMax }
     
     /// The number of y-values this DataSet represents
     @available(*, deprecated, message: "Use `count` instead")
@@ -168,7 +154,7 @@ open class ChartDataSet: ChartBaseDataSet
     @available(*, deprecated, message: "Use `subscript(index:)` instead.")
     open override func entryForIndex(_ i: Int) -> ChartDataEntry?
     {
-        guard i >= startIndex, i < endIndex else {
+        guard indices.contains(i) else {
             return nil
         }
         return self[i]
@@ -211,58 +197,12 @@ open class ChartDataSet: ChartBaseDataSet
     /// An empty array if no Entry object at that index.
     open override func entriesForXValue(_ xValue: Double) -> [ChartDataEntry]
     {
-        var entries = [ChartDataEntry]()
-        
-        var low = startIndex
-        var high = endIndex - 1
-        
-        while low <= high
-        {
-            var m = (high + low) / 2
-            var entry = self[m]
-            
-            // if we have a match
-            if xValue == entry.x
-            {
-                while m > 0 && self[m - 1].x == xValue
-                {
-                    m -= 1
-                }
-                
-                high = endIndex
-                
-                // loop over all "equal" entries
-                while m < high
-                {
-                    entry = self[m]
-                    if entry.x == xValue
-                    {
-                        entries.append(entry)
-                    }
-                    else
-                    {
-                        break
-                    }
-                    
-                    m += 1
-                }
-                
-                break
-            }
-            else
-            {
-                if xValue > entry.x
-                {
-                    low = m + 1
-                }
-                else
-                {
-                    high = m - 1
-                }
-            }
-        }
-        
-        return entries
+        let match: (ChartDataEntry) -> Bool = { $0.x == xValue }
+        var partitioned = self.entries
+        _ = partitioned.partition(by: match)
+        let i = partitioned.partitioningIndex(where: match)
+        guard i < endIndex else { return [] }
+        return partitioned[i...].prefix(while: match)
     }
     
     /// - Parameters:
@@ -276,98 +216,66 @@ open class ChartDataSet: ChartBaseDataSet
         closestToY yValue: Double,
         rounding: ChartDataSetRounding) -> Int
     {
-        var low = startIndex
-        var high = endIndex - 1
-        var closest = high
-        
-        while low < high
-        {
-            let m = (low + high) / 2
-            
-            let d1 = self[m].x - xValue
-            let d2 = self[m + 1].x - xValue
-            let ad1 = abs(d1), ad2 = abs(d2)
-            
-            if ad2 < ad1
+        var closest = partitioningIndex { $0.x >= xValue }
+        guard closest < endIndex else { return index(before: endIndex) }
+
+        var closestXValue = self[closest].x
+
+        switch rounding {
+        case .up:
+            // If rounding up, and found x-value is lower than specified x, and we can go upper...
+            if closestXValue < xValue && closest < index(before: endIndex)
             {
-                // [m + 1] is closer to xValue
-                // Search in an higher place
-                low = m + 1
+                formIndex(after: &closest)
             }
-            else if ad1 < ad2
+
+        case .down:
+            // If rounding down, and found x-value is upper than specified x, and we can go lower...
+            if closestXValue > xValue && closest > startIndex
             {
-                // [m] is closer to xValue
-                // Search in a lower place
-                high = m
+                formIndex(before: &closest)
             }
-            else
-            {
-                // We have multiple sequential x-value with same distance
-                
-                if d1 >= 0.0
-                {
-                    // Search in a lower place
-                    high = m
-                }
-                else if d1 < 0.0
+
+        case .closest:
+            // The closest value in the beginning of this function
+            // `var closest = partitioningIndex { $0.x >= xValue }`
+            // doesn't guarantee closest rounding method
+            if closest > startIndex {
+                let distanceAfter = abs(self[closest].x - xValue)
+                let distanceBefore = abs(self[index(before: closest)].x - xValue)
+                if distanceBefore < distanceAfter
                 {
-                    // Search in an higher place
-                    low = m + 1
+                    closest = index(before: closest)
                 }
+                closestXValue = self[closest].x
             }
-            
-            closest = high
         }
-        
-        if closest != -1
+
+        // Search by closest to y-value
+        if !yValue.isNaN
         {
-            let closestXValue = self[closest].x
-            
-            if rounding == .up
+            while closest > startIndex && self[index(before: closest)].x == closestXValue
             {
-                // If rounding up, and found x-value is lower than specified x, and we can go upper...
-                if closestXValue < xValue && closest < endIndex - 1
-                {
-                    closest += 1
-                }
-            }
-            else if rounding == .down
-            {
-                // If rounding down, and found x-value is upper than specified x, and we can go lower...
-                if closestXValue > xValue && closest > 0
-                {
-                    closest -= 1
-                }
+                formIndex(before: &closest)
             }
-            
-            // Search by closest to y-value
-            if !yValue.isNaN
+
+            var closestYValue = self[closest].y
+            var closestYIndex = closest
+
+            while closest < index(before: endIndex)
             {
-                while closest > 0 && self[closest - 1].x == closestXValue
-                {
-                    closest -= 1
-                }
-                
-                var closestYValue = self[closest].y
-                var closestYIndex = closest
-                
-                while true
+                formIndex(after: &closest)
+                let value = self[closest]
+
+                if value.x != closestXValue { break }
+                if abs(value.y - yValue) <= abs(closestYValue - yValue)
                 {
-                    closest += 1
-                    if closest >= endIndex { break }
-                    
-                    let value = self[closest]
-                    
-                    if value.x != closestXValue { break }
-                    if abs(value.y - yValue) <= abs(closestYValue - yValue)
-                    {
-                        closestYValue = yValue
-                        closestYIndex = closest
-                    }
+                    closestYValue = yValue
+                    closestYIndex = closest
                 }
-                
-                closest = closestYIndex
             }
+
+            closest = closestYIndex
         }
         
         return closest
@@ -376,6 +284,7 @@ open class ChartDataSet: ChartBaseDataSet
     /// - Parameters:
     ///   - e: the entry to search for
     /// - Returns: The array-index of the specified entry
+    // TODO: Should be returning `nil` to follow Swift convention
     @available(*, deprecated, message: "Use `firstIndex(of:)` or `lastIndex(of:)`")
     open override func entryIndex(entry e: ChartDataEntry) -> Int
     {
@@ -389,7 +298,8 @@ open class ChartDataSet: ChartBaseDataSet
     /// - Parameters:
     ///   - e: the entry to add
     /// - Returns: True
-    @available(*, deprecated, message: "Use `append(_:)` instead")
+    // TODO: This should return `Void` to follow Swift convention
+    @available(*, deprecated, message: "Use `append(_:)` instead", renamed: "append(_:)")
     open override func addEntry(_ e: ChartDataEntry) -> Bool
     {
         append(e)
@@ -403,17 +313,15 @@ open class ChartDataSet: ChartBaseDataSet
     /// - Parameters:
     ///   - e: the entry to add
     /// - Returns: True
+    // TODO: This should return `Void` to follow Swift convention
     open override func addEntryOrdered(_ e: ChartDataEntry) -> Bool
     {
-        calcMinMax(entry: e)
-        
         if let last = last, last.x > e.x
         {
-            var closestIndex = entryIndex(x: e.x, closestToY: e.y, rounding: .up)
-            while self[closestIndex].x < e.x
-            {
-                closestIndex += 1
-            }
+            let startIndex = entryIndex(x: e.x, closestToY: e.y, rounding: .up)
+            let closestIndex = self[startIndex...].lastIndex { $0.x < e.x }
+                ?? startIndex
+            calcMinMax(entry: e)
             entries.insert(e, at: closestIndex)
         }
         else
@@ -427,7 +335,7 @@ open class ChartDataSet: ChartBaseDataSet
     @available(*, renamed: "remove(_:)")
     open override func removeEntry(_ entry: ChartDataEntry) -> Bool
     {
-        return remove(entry)
+        remove(entry)
     }
 
     /// Removes an Entry from the DataSet dynamically.
@@ -446,6 +354,7 @@ open class ChartDataSet: ChartBaseDataSet
     /// Removes the first Entry (at index 0) of this DataSet from the entries array.
     ///
     /// - Returns: `true` if successful, `false` if not.
+    // TODO: This should return the removed entry to follow Swift convention.
     @available(*, deprecated, message: "Use `func removeFirst() -> ChartDataEntry` instead.")
     open override func removeFirst() -> Bool
     {
@@ -456,6 +365,7 @@ open class ChartDataSet: ChartBaseDataSet
     /// Removes the last Entry (at index size-1) of this DataSet from the entries array.
     ///
     /// - Returns: `true` if successful, `false` if not.
+    // TODO: This should return the removed entry to follow Swift convention.
     @available(*, deprecated, message: "Use `func removeLast() -> ChartDataEntry` instead.")
     open override func removeLast() -> Bool
     {
@@ -471,7 +381,7 @@ open class ChartDataSet: ChartBaseDataSet
     }
     
     // MARK: - Data functions and accessors
-
+    
     // MARK: - NSCopying
     
     open override func copy(with zone: NSZone? = nil) -> Any
@@ -528,6 +438,11 @@ extension ChartDataSet: RandomAccessCollection {
 
 // MARK: RangeReplaceableCollection
 extension ChartDataSet: RangeReplaceableCollection {
+    public func replaceSubrange<C>(_ subrange: Swift.Range<Index>, with newElements: C) where C : Collection, Element == C.Element {
+        entries.replaceSubrange(subrange, with: newElements)
+        notifyDataSetChanged()
+    }
+    
     public func append(_ newElement: Element) {
         calcMinMax(entry: newElement)
         entries.append(newElement)

+ 74 - 83
Pods/Charts/Source/Charts/Data/Implementations/Standard/CombinedChartData.swift

@@ -19,15 +19,20 @@ open class CombinedChartData: BarLineScatterCandleBubbleChartData
     private var _candleData: CandleChartData!
     private var _bubbleData: BubbleChartData!
     
-    public override init()
+    public required init()
     {
         super.init()
     }
     
-    public override init(dataSets: [IChartDataSet]?)
+    public override init(dataSets: [ChartDataSetProtocol])
     {
         super.init(dataSets: dataSets)
     }
+
+    public required init(arrayLiteral elements: ChartDataSetProtocol...)
+    {
+        super.init(dataSets: elements)
+    }
     
     @objc open var lineData: LineChartData!
     {
@@ -98,15 +103,15 @@ open class CombinedChartData: BarLineScatterCandleBubbleChartData
     {
         _dataSets.removeAll()
         
-        _yMax = -Double.greatestFiniteMagnitude
-        _yMin = Double.greatestFiniteMagnitude
-        _xMax = -Double.greatestFiniteMagnitude
-        _xMin = Double.greatestFiniteMagnitude
+        yMax = -Double.greatestFiniteMagnitude
+        yMin = Double.greatestFiniteMagnitude
+        xMax = -Double.greatestFiniteMagnitude
+        xMin = Double.greatestFiniteMagnitude
         
-        _leftAxisMax = -Double.greatestFiniteMagnitude
-        _leftAxisMin = Double.greatestFiniteMagnitude
-        _rightAxisMax = -Double.greatestFiniteMagnitude
-        _rightAxisMin = Double.greatestFiniteMagnitude
+        leftAxisMax = -Double.greatestFiniteMagnitude
+        leftAxisMin = Double.greatestFiniteMagnitude
+        rightAxisMax = -Double.greatestFiniteMagnitude
+        rightAxisMin = Double.greatestFiniteMagnitude
         
         let allData = self.allData
         
@@ -114,51 +119,50 @@ open class CombinedChartData: BarLineScatterCandleBubbleChartData
         {
             data.calcMinMax()
             
-            let sets = data.dataSets
-            _dataSets.append(contentsOf: sets)
+            _dataSets.append(contentsOf: data)
             
-            if data.yMax > _yMax
+            if data.yMax > yMax
             {
-                _yMax = data.yMax
+                yMax = data.yMax
             }
             
-            if data.yMin < _yMin
+            if data.yMin < yMin
             {
-                _yMin = data.yMin
+                yMin = data.yMin
             }
             
-            if data.xMax > _xMax
+            if data.xMax > xMax
             {
-                _xMax = data.xMax
+                xMax = data.xMax
             }
             
-            if data.xMin < _xMin
+            if data.xMin < xMin
             {
-                _xMin = data.xMin
+                xMin = data.xMin
             }
 
-            for dataset in sets
+            for set in data
             {
-                if dataset.axisDependency == .left
+                if set.axisDependency == .left
                 {
-                    if dataset.yMax > _leftAxisMax
+                    if set.yMax > leftAxisMax
                     {
-                        _leftAxisMax = dataset.yMax
+                        leftAxisMax = set.yMax
                     }
-                    if dataset.yMin < _leftAxisMin
+                    if set.yMin < leftAxisMin
                     {
-                        _leftAxisMin = dataset.yMin
+                        leftAxisMin = set.yMin
                     }
                 }
                 else
                 {
-                    if dataset.yMax > _rightAxisMax
+                    if set.yMax > rightAxisMax
                     {
-                        _rightAxisMax = dataset.yMax
+                        rightAxisMax = set.yMax
                     }
-                    if dataset.yMin < _rightAxisMin
+                    if set.yMin < rightAxisMin
                     {
-                        _rightAxisMin = dataset.yMin
+                        rightAxisMin = set.yMin
                     }
                 }
             }
@@ -204,17 +208,19 @@ open class CombinedChartData: BarLineScatterCandleBubbleChartData
         return allData.firstIndex(of: data)
     }
     
-    open override func removeDataSet(_ dataSet: IChartDataSet) -> Bool
+    open override func removeDataSet(_ dataSet: ChartDataSetProtocol) -> Element?
     {
-        return allData.contains { $0.removeDataSet(dataSet) }
-    }
-    
-    open override func removeDataSetByIndex(_ index: Int) -> Bool
-    {
-        print("removeDataSet(index) not supported for CombinedData", terminator: "\n")
-        return false
+        for data in allData
+        {
+            if let e = data.removeDataSet(dataSet)
+            {
+                return e
+            }
+        }
+        
+        return nil
     }
-    
+
     open override func removeEntry(_ entry: ChartDataEntry, dataSetIndex: Int) -> Bool
     {
         print("removeEntry(entry, dataSetIndex) not supported for CombinedData", terminator: "\n")
@@ -229,27 +235,12 @@ open class CombinedChartData: BarLineScatterCandleBubbleChartData
     
     open override func notifyDataChanged()
     {
-        if _lineData !== nil
-        {
-            _lineData.notifyDataChanged()
-        }
-        if _barData !== nil
-        {
-            _barData.notifyDataChanged()
-        }
-        if _scatterData !== nil
-        {
-            _scatterData.notifyDataChanged()
-        }
-        if _candleData !== nil
-        {
-            _candleData.notifyDataChanged()
-        }
-        if _bubbleData !== nil
-        {
-            _bubbleData.notifyDataChanged()
-        }
-        
+        _lineData?.notifyDataChanged()
+        _barData?.notifyDataChanged()
+        _scatterData?.notifyDataChanged()
+        _candleData?.notifyDataChanged()
+        _bubbleData?.notifyDataChanged()
+
         super.notifyDataChanged() // recalculate everything
     }
     
@@ -258,23 +249,12 @@ open class CombinedChartData: BarLineScatterCandleBubbleChartData
     /// - Parameters:
     ///   - highlight:
     /// - Returns: The entry that is highlighted
-    open override func entryForHighlight(_ highlight: Highlight) -> ChartDataEntry?
+    @objc override open func entry(for highlight: Highlight) -> ChartDataEntry?
     {
-        if highlight.dataIndex >= allData.count
-        {
-            return nil
-        }
-        
-        let data = dataByIndex(highlight.dataIndex)
-        
-        if highlight.dataSetIndex >= data.dataSetCount
-        {
-            return nil
-        }
-        
         // The value of the highlighted entry could be NaN - if we are not interested in highlighting a specific value.
-        let entries = data.getDataSetByIndex(highlight.dataSetIndex).entriesForXValue(highlight.x)
-        return entries.first { $0.y == highlight.y || highlight.y.isNaN }
+        getDataSetByHighlight(highlight)?
+            .entriesForXValue(highlight.x)
+            .first { $0.y == highlight.y || highlight.y.isNaN }
     }
     
     /// Get dataset for highlight
@@ -282,20 +262,31 @@ open class CombinedChartData: BarLineScatterCandleBubbleChartData
     /// - Parameters:
     ///   - highlight: current highlight
     /// - Returns: dataset related to highlight
-    @objc open func getDataSetByHighlight(_ highlight: Highlight) -> IChartDataSet!
-    {  
-        if highlight.dataIndex >= allData.count
+    @objc open func getDataSetByHighlight(_ highlight: Highlight) -> ChartDataSetProtocol!
+    {
+        guard allData.indices.contains(highlight.dataIndex) else
         {
             return nil
         }
-        
+
         let data = dataByIndex(highlight.dataIndex)
-        
-        if highlight.dataSetIndex >= data.dataSetCount
+
+        guard data.indices.contains(highlight.dataSetIndex) else
         {
             return nil
         }
-        
-        return data.dataSets[highlight.dataSetIndex]
+
+        // The value of the highlighted entry could be NaN - if we are not interested in highlighting a specific value.
+        return data[highlight.dataSetIndex]
+    }
+
+    // MARK: Unsupported Collection Methods
+
+    public override func append(_ newElement: ChartData.Element) {
+        fatalError("append(_:) not supported for CombinedData")
+    }
+
+    public override func remove(at i: Int) -> ChartDataSetProtocol {
+        fatalError("remove(at:) not supported for CombinedData")
     }
 }

+ 7 - 2
Pods/Charts/Source/Charts/Data/Implementations/Standard/LineChartData.swift

@@ -14,13 +14,18 @@ import Foundation
 /// Data object that encapsulates all data associated with a LineChart.
 open class LineChartData: ChartData
 {
-    public override init()
+    public required init()
     {
         super.init()
     }
     
-    public override init(dataSets: [IChartDataSet]?)
+    public override init(dataSets: [ChartDataSetProtocol])
     {
         super.init(dataSets: dataSets)
     }
+
+    public required init(arrayLiteral elements: ChartDataSetProtocol...)
+    {
+        super.init(dataSets: elements)
+    }
 }

+ 10 - 6
Pods/Charts/Source/Charts/Data/Implementations/Standard/LineChartDataSet.swift

@@ -13,7 +13,7 @@ import Foundation
 import CoreGraphics
 
 
-open class LineChartDataSet: LineRadarChartDataSet, ILineChartDataSet
+open class LineChartDataSet: LineRadarChartDataSet, LineChartDataSetProtocol
 {
     @objc(LineChartMode)
     public enum Mode: Int
@@ -36,7 +36,7 @@ open class LineChartDataSet: LineRadarChartDataSet, ILineChartDataSet
         initialize()
     }
     
-    public override init(entries: [ChartDataEntry]?, label: String?)
+    public override init(entries: [ChartDataEntry], label: String)
     {
         super.init(entries: entries, label: label)
         initialize()
@@ -67,7 +67,11 @@ open class LineChartDataSet: LineRadarChartDataSet, ILineChartDataSet
             _cubicIntensity = newValue.clamped(to: 0.05...1)
         }
     }
-        
+
+    open var isDrawLineWithGradientEnabled = false
+
+    open var gradientPositions: [CGFloat]?
+    
     /// The radius of the drawn circles.
     open var circleRadius = CGFloat(8.0)
     
@@ -136,10 +140,10 @@ open class LineChartDataSet: LineRadarChartDataSet, ILineChartDataSet
     open var lineCapType = CGLineCap.butt
     
     /// formatter for customizing the position of the fill-line
-    private var _fillFormatter: IFillFormatter = DefaultFillFormatter()
+    private var _fillFormatter: FillFormatter = DefaultFillFormatter()
     
-    /// Sets a custom IFillFormatter to the chart that handles the position of the filled-line for each DataSet. Set this to null to use the default logic.
-    open var fillFormatter: IFillFormatter?
+    /// Sets a custom FillFormatterProtocol to the chart that handles the position of the filled-line for each DataSet. Set this to null to use the default logic.
+    open var fillFormatter: FillFormatter?
     {
         get
         {

+ 1 - 1
Pods/Charts/Source/Charts/Data/Implementations/Standard/LineRadarChartDataSet.swift

@@ -13,7 +13,7 @@ import Foundation
 import CoreGraphics
 
 
-open class LineRadarChartDataSet: LineScatterCandleRadarChartDataSet, ILineRadarChartDataSet
+open class LineRadarChartDataSet: LineScatterCandleRadarChartDataSet, LineRadarChartDataSetProtocol
 {
     // MARK: - Data functions and accessors
     

+ 1 - 1
Pods/Charts/Source/Charts/Data/Implementations/Standard/LineScatterCandleRadarChartDataSet.swift

@@ -12,7 +12,7 @@
 import Foundation
 
 
-open class LineScatterCandleRadarChartDataSet: BarLineScatterCandleBubbleChartDataSet, ILineScatterCandleRadarChartDataSet
+open class LineScatterCandleRadarChartDataSet: BarLineScatterCandleBubbleChartDataSet, LineScatterCandleRadarChartDataSetProtocol
 {
     // MARK: - Data functions and accessors
     

+ 27 - 44
Pods/Charts/Source/Charts/Data/Implementations/Standard/PieChartData.swift

@@ -13,41 +13,32 @@ import Foundation
 
 open class PieChartData: ChartData
 {
-    public override init()
+    public required init()
     {
         super.init()
     }
     
-    public override init(dataSets: [IChartDataSet]?)
+    public override init(dataSets: [ChartDataSetProtocol])
     {
         super.init(dataSets: dataSets)
     }
 
-    /// All DataSet objects this ChartData object holds.
-    @objc open override var dataSets: [IChartDataSet]
+    public required init(arrayLiteral elements: ChartDataSetProtocol...)
     {
-        get
-        {
-            assert(super.dataSets.count <= 1, "Found multiple data sets while pie chart only allows one")
-            return super.dataSets
-        }
-        set
-        {
-            super.dataSets = newValue
-        }
+        super.init(dataSets: elements)
     }
 
-    @objc var dataSet: IPieChartDataSet?
+    @objc public var dataSet: PieChartDataSetProtocol?
     {
         get
         {
-            return dataSets.count > 0 ? dataSets[0] as? IPieChartDataSet : nil
+            return dataSets.first as? PieChartDataSetProtocol
         }
         set
         {
-            if let newValue = newValue
+            if let set = newValue
             {
-                dataSets = [newValue]
+                dataSets = [set]
             }
             else
             {
@@ -55,19 +46,30 @@ open class PieChartData: ChartData
             }
         }
     }
-    
-    open override func getDataSetByIndex(_ index: Int) -> IChartDataSet?
+
+    /// - returns: All up to one dataSet object this ChartData object holds.
+    @objc open override var dataSets: [ChartDataSetProtocol]
     {
-        if index != 0
+        get
         {
-            return nil
+            assert(super.dataSets.count <= 1, "Found multiple data sets while pie chart only allows one")
+            return super.dataSets
+        }
+        set
+        {
+            super.dataSets = newValue
         }
-        return super.getDataSetByIndex(index)
     }
     
-    open override func getDataSetByLabel(_ label: String, ignorecase: Bool) -> IChartDataSet?
+    open override func dataSet(at index: ChartData.Index) -> ChartData.Element?
     {
-        if dataSets.count == 0 || dataSets[0].label == nil
+        guard index == 0 else { return nil }
+        return self[index]
+    }
+    
+    open override func dataSet(forLabel label: String, ignorecase: Bool) -> ChartDataSetProtocol?
+    {
+        if dataSets.first?.label == nil
         {
             return nil
         }
@@ -89,30 +91,11 @@ open class PieChartData: ChartData
         return nil
     }
     
-    open override func entryForHighlight(_ highlight: Highlight) -> ChartDataEntry?
+    @objc override open func entry(for highlight: Highlight) -> ChartDataEntry?
     {
         return dataSet?.entryForIndex(Int(highlight.x))
     }
     
-    open override func addDataSet(_ d: IChartDataSet!)
-    {   
-        super.addDataSet(d)
-    }
-    
-    /// Removes the DataSet at the given index in the DataSet array from the data object.
-    /// Also recalculates all minimum and maximum values.
-    ///
-    /// - Returns: `true` if a DataSet was removed, `false` ifno DataSet could be removed.
-    open override func removeDataSetByIndex(_ index: Int) -> Bool
-    {
-        if index >= _dataSets.count || index < 0
-        {
-            return false
-        }
-        
-        return false
-    }
-    
     /// The total y-value sum across all DataSet objects the this object represents.
     @objc open var yValueSum: Double
     {

+ 6 - 11
Pods/Charts/Source/Charts/Data/Implementations/Standard/PieChartDataSet.swift

@@ -12,7 +12,7 @@
 import Foundation
 import CoreGraphics
 
-open class PieChartDataSet: ChartDataSet, IPieChartDataSet
+open class PieChartDataSet: ChartDataSet, PieChartDataSetProtocol
 {
     @objc(PieChartValuePosition)
     public enum ValuePosition: Int
@@ -33,7 +33,7 @@ open class PieChartDataSet: ChartDataSet, IPieChartDataSet
         initialize()
     }
 
-    public override init(entries: [ChartDataEntry]?, label: String?)
+    public override init(entries: [ChartDataEntry], label: String)
     {
         super.init(entries: entries, label: label)
         initialize()
@@ -59,16 +59,11 @@ open class PieChartDataSet: ChartDataSet, IPieChartDataSet
         }
         set
         {
-            var space = newValue
-            if space > 20.0
-            {
-                space = 20.0
+            switch newValue {
+            case ..<0.0: _sliceSpace = 0.0
+            case 20.0...: _sliceSpace = 20.0
+            default: _sliceSpace = newValue
             }
-            if space < 0.0
-            {
-                space = 0.0
-            }
-            _sliceSpace = space
         }
     }
 

+ 10 - 5
Pods/Charts/Source/Charts/Data/Implementations/Standard/RadarChartData.swift

@@ -29,18 +29,23 @@ open class RadarChartData: ChartData
         self.labels = labels
     }
     
-    public override init()
+    public required init()
     {
         super.init()
     }
     
-    public override init(dataSets: [IChartDataSet]?)
+    public override init(dataSets: [ChartDataSetProtocol])
     {
         super.init(dataSets: dataSets)
     }
-    
-    open override func entryForHighlight(_ highlight: Highlight) -> ChartDataEntry?
+
+    public required init(arrayLiteral elements: ChartDataSetProtocol...)
+    {
+        super.init(dataSets: elements)
+    }
+
+    @objc open override func entry(for highlight: Highlight) -> ChartDataEntry?
     {
-        return getDataSetByIndex(highlight.dataSetIndex)?.entryForIndex(Int(highlight.x))
+        return self[highlight.dataSetIndex].entryForIndex(Int(highlight.x))
     }
 }

+ 2 - 2
Pods/Charts/Source/Charts/Data/Implementations/Standard/RadarChartDataSet.swift

@@ -13,7 +13,7 @@ import Foundation
 import CoreGraphics
 
 
-open class RadarChartDataSet: LineRadarChartDataSet, IRadarChartDataSet
+open class RadarChartDataSet: LineRadarChartDataSet, RadarChartDataSetProtocol
 {
     private func initialize()
     {
@@ -26,7 +26,7 @@ open class RadarChartDataSet: LineRadarChartDataSet, IRadarChartDataSet
         initialize()
     }
     
-    public required override init(entries: [ChartDataEntry]?, label: String?)
+    public required override init(entries: [ChartDataEntry], label: String)
     {
         super.init(entries: entries, label: label)
         initialize()

+ 8 - 3
Pods/Charts/Source/Charts/Data/Implementations/Standard/ScatterChartData.swift

@@ -14,20 +14,25 @@ import CoreGraphics
 
 open class ScatterChartData: BarLineScatterCandleBubbleChartData
 {
-    public override init()
+    public required init()
     {
         super.init()
     }
     
-    public override init(dataSets: [IChartDataSet]?)
+    public override init(dataSets: [ChartDataSetProtocol])
     {
         super.init(dataSets: dataSets)
     }
+
+    public required init(arrayLiteral elements: ChartDataSetProtocol...)
+    {
+        super.init(dataSets: elements)
+    }
     
     /// - Returns: The maximum shape-size across all DataSets.
     @objc open func getGreatestShapeSize() -> CGFloat
     {
-        return (_dataSets as? [IScatterChartDataSet])?
+        return (_dataSets as? [ScatterChartDataSetProtocol])?
             .max { $0.scatterShapeSize < $1.scatterShapeSize }?
             .scatterShapeSize ?? 0
     }

+ 4 - 4
Pods/Charts/Source/Charts/Data/Implementations/Standard/ScatterChartDataSet.swift

@@ -12,7 +12,7 @@
 import Foundation
 import CoreGraphics
 
-open class ScatterChartDataSet: LineScatterCandleRadarChartDataSet, IScatterChartDataSet
+open class ScatterChartDataSet: LineScatterCandleRadarChartDataSet, ScatterChartDataSetProtocol
 {
     
     @objc(ScatterShape)
@@ -39,7 +39,7 @@ open class ScatterChartDataSet: LineScatterCandleRadarChartDataSet, IScatterChar
     open var scatterShapeHoleColor: NSUIColor? = nil
     
     /// Sets the ScatterShape this DataSet should be drawn with.
-    /// This will search for an available IShapeRenderer and set this renderer for the DataSet
+    /// This will search for an available ShapeRenderer and set this renderer for the DataSet
     @objc open func setScatterShape(_ shape: Shape)
     {
         self.shapeRenderer = ScatterChartDataSet.renderer(forShape: shape)
@@ -48,9 +48,9 @@ open class ScatterChartDataSet: LineScatterCandleRadarChartDataSet, IScatterChar
     /// The IShapeRenderer responsible for rendering this DataSet.
     /// This can also be used to set a custom IShapeRenderer aside from the default ones.
     /// **default**: `SquareShapeRenderer`
-    open var shapeRenderer: IShapeRenderer? = SquareShapeRenderer()
+    open var shapeRenderer: ShapeRenderer? = SquareShapeRenderer()
     
-    @objc open class func renderer(forShape shape: Shape) -> IShapeRenderer
+    @objc open class func renderer(forShape shape: Shape) -> ShapeRenderer
     {
         switch shape
         {

+ 3 - 3
Pods/Charts/Source/Charts/Filters/DataApproximator+N.swift

@@ -78,12 +78,12 @@ extension DataApproximator {
         var keep = [Bool](repeating: false, count: points.count)
         
         // first and last always stay
-        keep[0] = true
-        keep[points.count - 1] = true
+        keep[points.startIndex] = true
+        keep[points.endIndex - 1] = true
         var currentStoredPoints = 2
         
         var queue = [LineAlt]()
-        let line = LineAlt(start: 0, end: points.count - 1, points: points)
+        let line = LineAlt(start: points.startIndex, end: points.endIndex - 1, points: points)
         queue.append(line)
         
         repeat {

+ 4 - 4
Pods/Charts/Source/Charts/Filters/DataApproximator.swift

@@ -27,14 +27,14 @@ open class DataApproximator: NSObject
         var keep = [Bool](repeating: false, count: points.count)
         
         // first and last always stay
-        keep[0] = true
-        keep[points.count - 1] = true
+        keep[points.startIndex] = true
+        keep[points.endIndex - 1] = true
         
         // first and last entry are entry point to recursion
         reduceWithDouglasPeuker(points: points,
                                 tolerance: tolerance,
-                                start: 0,
-                                end: points.count - 1,
+                                start: points.startIndex,
+                                end: points.endIndex - 1,
                                 keep: &keep)
         
         // create a new array with series, only take the kept ones

+ 1 - 1
Pods/Charts/Source/Charts/Formatters/DefaultAxisValueFormatter.swift

@@ -12,7 +12,7 @@
 import Foundation
 
 @objc(ChartDefaultAxisValueFormatter)
-open class DefaultAxisValueFormatter: NSObject, IAxisValueFormatter
+open class DefaultAxisValueFormatter: NSObject, AxisValueFormatter
 {
     public typealias Block = (
         _ value: Double,

+ 3 - 3
Pods/Charts/Source/Charts/Formatters/DefaultFillFormatter.swift

@@ -14,10 +14,10 @@ import CoreGraphics
 
 /// Default formatter that calculates the position of the filled line.
 @objc(ChartDefaultFillFormatter)
-open class DefaultFillFormatter: NSObject, IFillFormatter
+open class DefaultFillFormatter: NSObject, FillFormatter
 {
     public typealias Block = (
-        _ dataSet: ILineChartDataSet,
+        _ dataSet: LineChartDataSetProtocol,
         _ dataProvider: LineChartDataProvider) -> CGFloat
     
     @objc open var block: Block?
@@ -35,7 +35,7 @@ open class DefaultFillFormatter: NSObject, IFillFormatter
     }
     
     open func getFillLinePosition(
-        dataSet: ILineChartDataSet,
+        dataSet: LineChartDataSetProtocol,
         dataProvider: LineChartDataProvider) -> CGFloat
     {
         guard block == nil else { return block!(dataSet, dataProvider) }

+ 38 - 30
Pods/Charts/Source/Charts/Formatters/DefaultValueFormatter.swift

@@ -11,8 +11,9 @@
 
 import Foundation
 
+/// The default value formatter used for all chart components that needs a default
 @objc(ChartDefaultValueFormatter)
-open class DefaultValueFormatter: NSObject, IValueFormatter
+open class DefaultValueFormatter: NSObject, ValueFormatter
 {
     public typealias Block = (
         _ value: Double,
@@ -22,69 +23,76 @@ open class DefaultValueFormatter: NSObject, IValueFormatter
     
     @objc open var block: Block?
     
-    @objc open var hasAutoDecimals: Bool = false
+    @objc open var hasAutoDecimals: Bool
     
-    private var _formatter: NumberFormatter?
     @objc open var formatter: NumberFormatter?
     {
-        get { return _formatter }
-        set
+        willSet
         {
             hasAutoDecimals = false
-            _formatter = newValue
         }
     }
     
-    private var _decimals: Int?
     open var decimals: Int?
     {
-        get { return _decimals }
-        set
+        didSet
         {
-            _decimals = newValue
-            
-            if let digits = newValue
-            {
-                self.formatter?.minimumFractionDigits = digits
-                self.formatter?.maximumFractionDigits = digits
-                self.formatter?.usesGroupingSeparator = true
-            }
+            setupDecimals(decimals: decimals)
+        }
+    }
+
+    private func setupDecimals(decimals: Int?)
+    {
+        if let digits = decimals
+        {
+            formatter?.minimumFractionDigits = digits
+            formatter?.maximumFractionDigits = digits
+            formatter?.usesGroupingSeparator = true
         }
     }
     
     public override init()
     {
-        super.init()
-        
-        self.formatter = NumberFormatter()
+        formatter = NumberFormatter()
+        formatter?.usesGroupingSeparator = true
+        decimals = 1
         hasAutoDecimals = true
+
+        super.init()
+        setupDecimals(decimals: decimals)
     }
     
     @objc public init(formatter: NumberFormatter)
     {
-        super.init()
-        
         self.formatter = formatter
+        hasAutoDecimals = false
+
+        super.init()
     }
     
     @objc public init(decimals: Int)
     {
-        super.init()
-        
-        self.formatter = NumberFormatter()
-        self.formatter?.usesGroupingSeparator = true
+        formatter = NumberFormatter()
+        formatter?.usesGroupingSeparator = true
         self.decimals = decimals
         hasAutoDecimals = true
+
+        super.init()
+        setupDecimals(decimals: decimals)
     }
     
     @objc public init(block: @escaping Block)
     {
-        super.init()
-        
         self.block = block
+        hasAutoDecimals = false
+
+        super.init()
     }
-    
-    @objc public static func with(block: @escaping Block) -> DefaultValueFormatter?
+
+    /// This function is deprecated - Use `init(block:)` instead.
+    // DEC 11, 2017
+    @available(*, deprecated, message: "Use `init(block:)` instead.")
+    @objc public static func with(block: @escaping Block) -> DefaultValueFormatter
     {
         return DefaultValueFormatter(block: block)
     }

+ 4 - 18
Pods/Charts/Source/Charts/Formatters/IndexAxisValueFormatter.swift

@@ -13,24 +13,10 @@ import Foundation
 
 /// This formatter is used for passing an array of x-axis labels, on whole x steps.
 @objc(ChartIndexAxisValueFormatter)
-open class IndexAxisValueFormatter: NSObject, IAxisValueFormatter
+open class IndexAxisValueFormatter: NSObject, AxisValueFormatter
 {
-    private var _values: [String] = [String]()
-    private var _valueCount: Int = 0
-    
-    @objc public var values: [String]
-    {
-        get
-        {
-            return _values
-        }
-        set
-        {
-            _values = newValue
-            _valueCount = _values.count
-        }
-    }
-    
+    @objc public var values: [String] = [String]()
+
     public override init()
     {
         super.init()
@@ -54,6 +40,6 @@ open class IndexAxisValueFormatter: NSObject, IAxisValueFormatter
     {
         let index = Int(value.rounded())
         guard values.indices.contains(index), index == Int(value) else { return "" }
-        return _values[index]
+        return values[index]
     }
 }

+ 5 - 4
Pods/Charts/Source/Charts/Highlight/BarHighlighter.swift

@@ -24,7 +24,7 @@ open class BarHighlighter: ChartHighlighter
         
         let pos = getValsForTouch(x: x, y: y)
 
-        if let set = barData.getDataSetByIndex(high.dataSetIndex) as? IBarChartDataSet,
+        if let set = barData[high.dataSetIndex] as? BarChartDataSetProtocol,
             set.isStacked
         {
             return getStackedHighlight(high: high,
@@ -57,7 +57,7 @@ open class BarHighlighter: ChartHighlighter
     ///   - yValue:
     /// - Returns:
     @objc open func getStackedHighlight(high: Highlight,
-                                  set: IBarChartDataSet,
+                                  set: BarChartDataSetProtocol,
                                   xValue: Double,
                                   yValue: Double) -> Highlight?
     {
@@ -74,7 +74,7 @@ open class BarHighlighter: ChartHighlighter
         
         guard
             let ranges = entry.ranges,
-            ranges.count > 0
+            !ranges.isEmpty
             else { return nil }
 
         let stackIndex = getClosestStackIndex(ranges: ranges, value: yValue)
@@ -98,10 +98,11 @@ open class BarHighlighter: ChartHighlighter
     @objc open func getClosestStackIndex(ranges: [Range]?, value: Double) -> Int
     {
         guard let ranges = ranges else { return 0 }
+        
         if let stackIndex = ranges.firstIndex(where: { $0.contains(value) }) {
             return stackIndex
         } else {
-            let length = max(ranges.count - 1, 0)
+            let length = max(ranges.endIndex - 1, 0)
             return (value > ranges[length].to) ? length : 0
         }
     }

+ 6 - 11
Pods/Charts/Source/Charts/Highlight/ChartHighlighter.swift

@@ -9,10 +9,11 @@
 //  https://github.com/danielgindi/Charts
 //
 
+import Algorithms
 import Foundation
 import CoreGraphics
 
-open class ChartHighlighter : NSObject, IHighlighter
+open class ChartHighlighter : NSObject, Highlighter
 {
     /// instance of the data-provider
     @objc open weak var chart: ChartDataProvider?
@@ -73,17 +74,11 @@ open class ChartHighlighter : NSObject, IHighlighter
         
         guard let data = self.data else { return vals }
         
-        for i in 0 ..< data.dataSetCount
+        for (i, set) in data.indexed() where set.isHighlightEnabled
         {
-            guard
-                let dataSet = data.getDataSetByIndex(i),
-                dataSet.isHighlightEnabled      // don't include datasets that cannot be highlighted
-                else { continue }
-            
-
             // extract all y-values from all DataSets at the given x-value.
             // some datasets (i.e bubble charts) make sense to have multiple values for an x-value. We'll have to find a way to handle that later on. It's more complicated now when x-indices are floating point.
-            vals.append(contentsOf: buildHighlights(dataSet: dataSet, dataSetIndex: i, xValue: xValue, rounding: .closest))
+            vals.append(contentsOf: buildHighlights(dataSet: set, dataSetIndex: i, xValue: xValue, rounding: .closest))
         }
         
         return vals
@@ -91,7 +86,7 @@ open class ChartHighlighter : NSObject, IHighlighter
     
     /// - Returns: An array of `Highlight` objects corresponding to the selected xValue and dataSetIndex.
     internal func buildHighlights(
-        dataSet set: IChartDataSet,
+        dataSet set: ChartDataSetProtocol,
         dataSetIndex: Int,
         xValue: Double,
         rounding: ChartDataSetRounding) -> [Highlight]
@@ -99,7 +94,7 @@ open class ChartHighlighter : NSObject, IHighlighter
         guard let chart = self.chart as? BarLineScatterCandleBubbleChartDataProvider else { return [] }
         
         var entries = set.entriesForXValue(xValue)
-        if entries.count == 0, let closest = set.entryForXValue(xValue, closestToY: .nan, rounding: rounding)
+        if entries.isEmpty, let closest = set.entryForXValue(xValue, closestToY: .nan, rounding: rounding)
         {
             // Try to find closest x-value and take all entries for that x-value
             entries = set.entriesForXValue(closest.x)

+ 4 - 9
Pods/Charts/Source/Charts/Highlight/CombinedHighlighter.swift

@@ -9,6 +9,7 @@
 //  https://github.com/danielgindi/Charts
 //
 
+import Algorithms
 import Foundation
 import CoreGraphics
 
@@ -35,10 +36,8 @@ open class CombinedHighlighter: ChartHighlighter
             let dataObjects = chart.combinedData?.allData
             else { return vals }
         
-        for i in 0..<dataObjects.count
+        for (i, dataObject) in dataObjects.indexed()
         {
-            let dataObject = dataObjects[i]
-
             // in case of BarData, let the BarHighlighter take over
             if barHighlighter != nil && dataObject is BarChartData,
                 let high = barHighlighter?.getHighlight(x: x, y: y)
@@ -48,13 +47,9 @@ open class CombinedHighlighter: ChartHighlighter
             }
             else
             {
-                for j in 0..<dataObject.dataSetCount
+                for (j, set) in dataObject.indexed() where set.isHighlightEnabled
                 {
-                    guard let dataSet = dataObject.getDataSetByIndex(j),
-                        dataSet.isHighlightEnabled      // don't include datasets that cannot be highlighted
-                        else { continue }
-
-                    let highs = buildHighlights(dataSet: dataSet, dataSetIndex: j, xValue: xValue, rounding: .closest)
+                    let highs = buildHighlights(dataSet: set, dataSetIndex: j, xValue: xValue, rounding: .closest)
 
                     for high in highs
                     {

+ 3 - 3
Pods/Charts/Source/Charts/Highlight/HorizontalBarHighlighter.swift

@@ -22,7 +22,7 @@ open class HorizontalBarHighlighter: BarHighlighter
         let pos = getValsForTouch(x: y, y: x)
         guard let high = getHighlight(xValue: Double(pos.y), x: y, y: x) else { return nil }
 
-        if let set = barData.getDataSetByIndex(high.dataSetIndex) as? IBarChartDataSet,
+        if let set = barData[high.dataSetIndex] as? BarChartDataSetProtocol,
             set.isStacked
         {
             return getStackedHighlight(high: high,
@@ -35,7 +35,7 @@ open class HorizontalBarHighlighter: BarHighlighter
     }
     
     internal override func buildHighlights(
-        dataSet set: IChartDataSet,
+        dataSet set: ChartDataSetProtocol,
         dataSetIndex: Int,
         xValue: Double,
         rounding: ChartDataSetRounding) -> [Highlight]
@@ -43,7 +43,7 @@ open class HorizontalBarHighlighter: BarHighlighter
         guard let chart = self.chart as? BarLineScatterCandleBubbleChartDataProvider else { return [] }
         
         var entries = set.entriesForXValue(xValue)
-        if entries.count == 0, let closest = set.entryForXValue(xValue, closestToY: .nan, rounding: rounding)
+        if entries.isEmpty, let closest = set.entryForXValue(xValue, closestToY: .nan, rounding: rounding)
         {
             // Try to find closest x-value and take all entries for that x-value
             entries = set.entriesForXValue(closest.x)

+ 1 - 1
Pods/Charts/Source/Charts/Highlight/PieHighlighter.swift

@@ -18,7 +18,7 @@ open class PieHighlighter: PieRadarHighlighter
     open override func closestHighlight(index: Int, x: CGFloat, y: CGFloat) -> Highlight?
     {
         guard
-            let set = chart?.data?.dataSets[0],
+            let set = chart?.data?[0],
             let entry = set.entryForIndex(index)
             else { return nil }
                 

+ 7 - 18
Pods/Charts/Source/Charts/Highlight/RadarHighlighter.swift

@@ -22,20 +22,12 @@ open class RadarHighlighter: PieRadarHighlighter
         let highlights = getHighlights(forIndex: index)
         
         let distanceToCenter = Double(chart.distanceToCenter(x: x, y: y) / chart.factor)
-        
-        var closest: Highlight?
-        var distance = Double.greatestFiniteMagnitude
-        
-        for high in highlights
-        {
-            let cdistance = abs(high.y - distanceToCenter)
-            if cdistance < distance
-            {
-                closest = high
-                distance = cdistance
-            }
+
+        func closestToCenter(lhs: Highlight, rhs: Highlight) -> Bool {
+            abs(lhs.y - distanceToCenter) < abs(rhs.y - distanceToCenter)
         }
-        
+
+        let closest = highlights.min(by: closestToCenter(lhs:rhs:))
         return closest
     }
     
@@ -57,12 +49,9 @@ open class RadarHighlighter: PieRadarHighlighter
         let sliceangle = chart.sliceAngle
         let factor = chart.factor
 
-        for i in chartData.dataSets.indices
+        for (i, dataSet) in chartData.indexed()
         {
-            guard
-                let dataSet = chartData.getDataSetByIndex(i),
-                let entry = dataSet.entryForIndex(index)
-                else { continue }
+            guard let entry = dataSet.entryForIndex(index) else { continue }
             
             let y = (entry.y - chart.chartYMin)
             

+ 0 - 6
Pods/Charts/Source/Charts/Jobs/AnimatedMoveViewJob.swift

@@ -16,12 +16,6 @@ open class AnimatedMoveViewJob: AnimatedViewPortJob
 {
     internal override func animationUpdate()
     {
-        guard
-            let viewPortHandler = viewPortHandler,
-            let transformer = transformer,
-            let view = view
-            else { return }
-        
         var pt = CGPoint(
             x: xOrigin + (CGFloat(xValue) - xOrigin) * phase,
             y: yOrigin + (CGFloat(yValue) - yOrigin) * phase

+ 5 - 5
Pods/Charts/Source/Charts/Jobs/AnimatedViewPortJob.swift

@@ -37,16 +37,16 @@ open class AnimatedViewPortJob: ViewPortJob
         duration: TimeInterval,
         easing: ChartEasingFunctionBlock?)
     {
+        self.xOrigin = xOrigin
+        self.yOrigin = yOrigin
+        self._duration = duration
+        self._easing = easing
+
         super.init(viewPortHandler: viewPortHandler,
             xValue: xValue,
             yValue: yValue,
             transformer: transformer,
             view: view)
-        
-        self.xOrigin = xOrigin
-        self.yOrigin = yOrigin
-        self._duration = duration
-        self._easing = easing
     }
     
     deinit

+ 12 - 18
Pods/Charts/Source/Charts/Jobs/AnimatedZoomViewJob.swift

@@ -14,7 +14,7 @@ import CoreGraphics
 
 open class AnimatedZoomViewJob: AnimatedViewPortJob
 {
-    internal var yAxis: YAxis?
+    internal var yAxis: YAxis
     internal var xAxisRange: Double = 0.0
     internal var scaleX: CGFloat = 0.0
     internal var scaleY: CGFloat = 0.0
@@ -40,6 +40,15 @@ open class AnimatedZoomViewJob: AnimatedViewPortJob
         duration: TimeInterval,
         easing: ChartEasingFunctionBlock?)
     {
+        self.yAxis = yAxis
+        self.xAxisRange = xAxisRange
+        self.scaleX = scaleX
+        self.scaleY = scaleY
+        self.zoomCenterX = zoomCenterX
+        self.zoomCenterY = zoomCenterY
+        self.zoomOriginX = zoomOriginX
+        self.zoomOriginY = zoomOriginY
+
         super.init(viewPortHandler: viewPortHandler,
             xValue: 0.0,
             yValue: 0.0,
@@ -49,32 +58,17 @@ open class AnimatedZoomViewJob: AnimatedViewPortJob
             yOrigin: yOrigin,
             duration: duration,
             easing: easing)
-        
-        self.yAxis = yAxis
-        self.xAxisRange = xAxisRange
-        self.scaleX = scaleX
-        self.scaleY = scaleY
-        self.zoomCenterX = zoomCenterX
-        self.zoomCenterY = zoomCenterY
-        self.zoomOriginX = zoomOriginX
-        self.zoomOriginY = zoomOriginY
     }
     
     internal override func animationUpdate()
     {
-        guard
-            let viewPortHandler = viewPortHandler,
-            let transformer = transformer,
-            let view = view
-            else { return }
-        
         let scaleX = xOrigin + (self.scaleX - xOrigin) * phase
         let scaleY = yOrigin + (self.scaleY - yOrigin) * phase
         
         var matrix = viewPortHandler.setZoom(scaleX: scaleX, scaleY: scaleY)
         viewPortHandler.refresh(newMatrix: matrix, chart: view, invalidate: false)
         
-        let valsInView = CGFloat(yAxis?.axisRange ?? 0.0) / viewPortHandler.scaleY
+        let valsInView = CGFloat(yAxis.axisRange) / viewPortHandler.scaleY
         let xsInView = CGFloat(xAxisRange) / viewPortHandler.scaleX
         
         var pt = CGPoint(
@@ -91,6 +85,6 @@ open class AnimatedZoomViewJob: AnimatedViewPortJob
     internal override func animationEnd()
     {
         (view as? BarLineChartViewBase)?.calculateOffsets()
-        view?.setNeedsDisplay()
+        view.setNeedsDisplay()
     }
 }

+ 1 - 7
Pods/Charts/Source/Charts/Jobs/MoveViewJob.swift

@@ -14,15 +14,9 @@ import CoreGraphics
 
 @objc(MoveChartViewJob)
 open class MoveViewJob: ViewPortJob
-{    
+{
     open override func doJob()
     {
-        guard
-            let viewPortHandler = viewPortHandler,
-            let transformer = transformer,
-            let view = view
-            else { return }
-        
         var pt = CGPoint(
             x: xValue,
             y: yValue

+ 9 - 9
Pods/Charts/Source/Charts/Jobs/ViewPortJob.swift

@@ -16,13 +16,13 @@ import CoreGraphics
 @objc(ChartViewPortJob)
 open class ViewPortJob: NSObject
 {
-    internal var point: CGPoint = CGPoint()
-    internal weak var viewPortHandler: ViewPortHandler?
-    internal var xValue: Double = 0.0
-    internal var yValue: Double = 0.0
-    internal weak var transformer: Transformer?
-    internal weak var view: ChartViewBase?
-    
+    internal var point: CGPoint = .zero
+    internal unowned var viewPortHandler: ViewPortHandler
+    internal var xValue = 0.0
+    internal var yValue = 0.0
+    internal unowned var transformer: Transformer
+    internal unowned var view: ChartViewBase
+
     @objc public init(
         viewPortHandler: ViewPortHandler,
         xValue: Double,
@@ -30,13 +30,13 @@ open class ViewPortJob: NSObject
         transformer: Transformer,
         view: ChartViewBase)
     {
-        super.init()
-        
         self.viewPortHandler = viewPortHandler
         self.xValue = xValue
         self.yValue = yValue
         self.transformer = transformer
         self.view = view
+
+        super.init()
     }
     
     @objc open func doJob()

+ 6 - 11
Pods/Charts/Source/Charts/Jobs/ZoomViewJob.swift

@@ -18,7 +18,7 @@ open class ZoomViewJob: ViewPortJob
     internal var scaleX: CGFloat = 0.0
     internal var scaleY: CGFloat = 0.0
     internal var axisDependency: YAxis.AxisDependency = .left
-    
+
     @objc public init(
         viewPortHandler: ViewPortHandler,
         scaleX: CGFloat,
@@ -29,26 +29,21 @@ open class ZoomViewJob: ViewPortJob
         axis: YAxis.AxisDependency,
         view: ChartViewBase)
     {
+        self.scaleX = scaleX
+        self.scaleY = scaleY
+        self.axisDependency = axis
+
         super.init(
             viewPortHandler: viewPortHandler,
             xValue: xValue,
             yValue: yValue,
             transformer: transformer,
             view: view)
-        
-        self.scaleX = scaleX
-        self.scaleY = scaleY
-        self.axisDependency = axis
+
     }
     
     open override func doJob()
     {
-        guard
-            let viewPortHandler = viewPortHandler,
-            let transformer = transformer,
-            let view = view
-            else { return }
-        
         var matrix = viewPortHandler.setZoom(scaleX: scaleX, scaleY: scaleY)
         viewPortHandler.refresh(newMatrix: matrix, chart: view, invalidate: false)
         

+ 224 - 293
Pods/Charts/Source/Charts/Renderers/BarChartRenderer.swift

@@ -12,14 +12,10 @@
 import Foundation
 import CoreGraphics
 
-#if canImport(UIKit)
+#if !os(OSX)
     import UIKit
 #endif
 
-#if canImport(Cocoa)
-import Cocoa
-#endif
-
 open class BarChartRenderer: BarLineScatterCandleBubbleRenderer
 {
     /// A nested array of elements ordered logically (i.e not in visual/drawing order) for use with VoiceOver
@@ -44,10 +40,7 @@ open class BarChartRenderer: BarLineScatterCandleBubbleRenderer
     /// The ````internal```` specifier is to allow subclasses (HorizontalBar) to populate the same array
     internal lazy var accessibilityOrderedElements: [[NSUIAccessibilityElement]] = accessibilityCreateEmptyOrderedElements()
 
-    private class Buffer
-    {
-        var rects = [CGRect]()
-    }
+    private typealias Buffer = [CGRect]
     
     @objc open weak var dataProvider: BarChartDataProvider?
     
@@ -63,70 +56,103 @@ open class BarChartRenderer: BarLineScatterCandleBubbleRenderer
     
     open override func initBuffers()
     {
-        if let barData = dataProvider?.barData
+        guard let barData = dataProvider?.barData else { return _buffers.removeAll() }
+
+        // Match buffers count to dataset count
+        if _buffers.count != barData.count
         {
-            // Matche buffers count to dataset count
-            if _buffers.count != barData.dataSetCount
+            while _buffers.count < barData.count
             {
-                while _buffers.count < barData.dataSetCount
-                {
-                    _buffers.append(Buffer())
-                }
-                while _buffers.count > barData.dataSetCount
-                {
-                    _buffers.removeLast()
-                }
+                _buffers.append(Buffer())
             }
-            
-            for i in stride(from: 0, to: barData.dataSetCount, by: 1)
+            while _buffers.count > barData.count
             {
-                let set = barData.dataSets[i] as! IBarChartDataSet
-                let size = set.entryCount * (set.isStacked ? set.stackSize : 1)
-                if _buffers[i].rects.count != size
-                {
-                    _buffers[i].rects = [CGRect](repeating: CGRect(), count: size)
-                }
+                _buffers.removeLast()
             }
         }
-        else
-        {
-            _buffers.removeAll()
+
+        _buffers = zip(_buffers, barData).map { buffer, set -> Buffer in
+            let set = set as! BarChartDataSetProtocol
+            let size = set.entryCount * (set.isStacked ? set.stackSize : 1)
+            return buffer.count == size
+                ? buffer
+                : Buffer(repeating: .zero, count: size)
         }
     }
     
-    private func prepareBuffer(dataSet: IBarChartDataSet, index: Int)
+    private func prepareBuffer(dataSet: BarChartDataSetProtocol, index: Int)
     {
         guard
             let dataProvider = dataProvider,
             let barData = dataProvider.barData
             else { return }
         
-        let barWidthHalf = barData.barWidth / 2.0
+        let barWidthHalf = CGFloat(barData.barWidth / 2.0)
     
-        let buffer = _buffers[index]
         var bufferIndex = 0
         let containsStacks = dataSet.isStacked
         
         let isInverted = dataProvider.isInverted(axis: dataSet.axisDependency)
-        let phaseY = animator.phaseY
-        var barRect = CGRect()
-        var x: Double
-        var y: Double
+        let phaseY = CGFloat(animator.phaseY)
 
-        
-        for i in stride(from: 0, to: min(Int(ceil(Double(dataSet.entryCount) * animator.phaseX)), dataSet.entryCount), by: 1)
+        for i in (0..<dataSet.entryCount).clamped(to: 0..<Int(ceil(Double(dataSet.entryCount) * animator.phaseX)))
         {
             guard let e = dataSet.entryForIndex(i) as? BarChartDataEntry else { continue }
-            
-            let vals = e.yValues
 
-            x = e.x
-            y = e.y
+            let x = CGFloat(e.x)
+            let left = x - barWidthHalf
+            let right = x + barWidthHalf
+
+            var y = e.y
+
+            if containsStacks, let vals = e.yValues
+            {
+                var posY = 0.0
+                var negY = -e.negativeSum
+                var yStart = 0.0
+                
+                // fill the stack
+                for value in vals
+                {
+                    if value == 0.0 && (posY == 0.0 || negY == 0.0)
+                    {
+                        // Take care of the situation of a 0.0 value, which overlaps a non-zero bar
+                        y = value
+                        yStart = y
+                    }
+                    else if value >= 0.0
+                    {
+                        y = posY
+                        yStart = posY + value
+                        posY = yStart
+                    }
+                    else
+                    {
+                        y = negY
+                        yStart = negY + abs(value)
+                        negY += abs(value)
+                    }
+                    
+                    var top = isInverted
+                        ? (y <= yStart ? CGFloat(y) : CGFloat(yStart))
+                        : (y >= yStart ? CGFloat(y) : CGFloat(yStart))
+                    var bottom = isInverted
+                        ? (y >= yStart ? CGFloat(y) : CGFloat(yStart))
+                        : (y <= yStart ? CGFloat(y) : CGFloat(yStart))
+                    
+                    // multiply the height of the rect with the phase
+                    top *= phaseY
+                    bottom *= phaseY
 
-            if !containsStacks || vals == nil
+                    let barRect = CGRect(x: left, y: top,
+                                         width: right - left,
+                                         height: bottom - top)
+                    _buffers[index][bufferIndex] = barRect
+                    bufferIndex += 1
+                }
+            }
+            else
             {
-                let left = CGFloat(x - barWidthHalf)
-                let right = CGFloat(x + barWidthHalf)
                 var top = isInverted
                     ? (y <= 0.0 ? CGFloat(y) : 0)
                     : (y >= 0.0 ? CGFloat(y) : 0)
@@ -212,72 +238,19 @@ open class BarChartRenderer: BarLineScatterCandleBubbleRenderer
                 // explicitly add 0 + topOffset to indicate this is changed after adding accessibility support (#3650, #3520)
                 if top > 0 + topOffset
                 {
-                    top *= CGFloat(phaseY)
+                    top *= phaseY
                 }
                 else
                 {
-                    bottom *= CGFloat(phaseY)
+                    bottom *= phaseY
                 }
 
-                barRect.origin.x = left
-                barRect.origin.y = top
-                barRect.size.width = right - left
-                barRect.size.height = bottom - top
-                buffer.rects[bufferIndex] = barRect
+                let barRect = CGRect(x: left, y: top,
+                                     width: right - left,
+                                     height: bottom - top)
+                _buffers[index][bufferIndex] = barRect
                 bufferIndex += 1
             }
-            else
-            {
-                var posY = 0.0
-                var negY = -e.negativeSum
-                var yStart = 0.0
-                
-                // fill the stack
-                for k in 0 ..< vals!.count
-                {
-                    let value = vals![k]
-                    
-                    if value == 0.0 && (posY == 0.0 || negY == 0.0)
-                    {
-                        // Take care of the situation of a 0.0 value, which overlaps a non-zero bar
-                        y = value
-                        yStart = y
-                    }
-                    else if value >= 0.0
-                    {
-                        y = posY
-                        yStart = posY + value
-                        posY = yStart
-                    }
-                    else
-                    {
-                        y = negY
-                        yStart = negY + abs(value)
-                        negY += abs(value)
-                    }
-                    
-                    let left = CGFloat(x - barWidthHalf)
-                    let right = CGFloat(x + barWidthHalf)
-                    var top = isInverted
-                        ? (y <= yStart ? CGFloat(y) : CGFloat(yStart))
-                        : (y >= yStart ? CGFloat(y) : CGFloat(yStart))
-                    var bottom = isInverted
-                        ? (y >= yStart ? CGFloat(y) : CGFloat(yStart))
-                        : (y <= yStart ? CGFloat(y) : CGFloat(yStart))
-                    
-                    // multiply the height of the rect with the phase
-                    top *= CGFloat(phaseY)
-                    bottom *= CGFloat(phaseY)
-                    
-                    barRect.origin.x = left
-                    barRect.size.width = right - left
-                    barRect.origin.y = top
-                    barRect.size.height = bottom - top
-                    
-                    buffer.rects[bufferIndex] = barRect
-                    bufferIndex += 1
-                }
-            }
         }
     }
 
@@ -301,19 +274,15 @@ open class BarChartRenderer: BarLineScatterCandleBubbleRenderer
         }
 
         // Populate logically ordered nested elements into accessibilityOrderedElements in drawDataSet()
-        for i in 0 ..< barData.dataSetCount
+        for i in barData.indices
         {
-            guard let set = barData.getDataSetByIndex(i) else { continue }
-            
-            if set.isVisible
-            {
-                if !(set is IBarChartDataSet)
-                {
-                    fatalError("Datasets for BarChartRenderer must conform to IBarChartDataset")
-                }
-                
-                drawDataSet(context: context, dataSet: set as! IBarChartDataSet, index: i)
+            guard let set = barData[i] as? BarChartDataSetProtocol else {
+                fatalError("Datasets for BarChartRenderer must conform to IBarChartDataset")
             }
+
+            guard set.isVisible else { continue }
+
+            drawDataSet(context: context, dataSet: set, index: i)
         }
 
         // Merge nested ordered arrays into the single accessibleChartElements.
@@ -322,21 +291,22 @@ open class BarChartRenderer: BarLineScatterCandleBubbleRenderer
     }
 
     private var _barShadowRectBuffer: CGRect = CGRect()
-
-    @objc open func drawDataSet(context: CGContext, dataSet: IBarChartDataSet, index: Int)
+    
+    @objc open func drawDataSet(context: CGContext, dataSet: BarChartDataSetProtocol, index: Int)
     {
         guard let dataProvider = dataProvider else { return }
 
         let trans = dataProvider.getTransformer(forAxis: dataSet.axisDependency)
 
         prepareBuffer(dataSet: dataSet, index: index)
-        trans.rectValuesToPixel(&_buffers[index].rects)
-
+        trans.rectValuesToPixel(&_buffers[index])
+        
         let borderWidth = dataSet.barBorderWidth
         let borderColor = dataSet.barBorderColor
         let drawBorder = borderWidth > 0.0
         
         context.saveGState()
+        defer { context.restoreGState() }
         
         // draw the bar shadow before the values
         if dataProvider.isDrawBarShadowEnabled
@@ -346,8 +316,9 @@ open class BarChartRenderer: BarLineScatterCandleBubbleRenderer
             let barWidth = barData.barWidth
             let barWidthHalf = barWidth / 2.0
             var x: Double = 0.0
-            
-            for i in stride(from: 0, to: min(Int(ceil(Double(dataSet.entryCount) * animator.phaseX)), dataSet.entryCount), by: 1)
+
+            let range = (0..<dataSet.entryCount).clamped(to: 0..<Int(ceil(Double(dataSet.entryCount) * animator.phaseX)))
+            for i in range
             {
                 guard let e = dataSet.entryForIndex(i) as? BarChartDataEntry else { continue }
                 
@@ -358,15 +329,9 @@ open class BarChartRenderer: BarLineScatterCandleBubbleRenderer
                 
                 trans.rectValueToPixel(&_barShadowRectBuffer)
                 
-                if !viewPortHandler.isInBoundsLeft(_barShadowRectBuffer.origin.x + _barShadowRectBuffer.size.width)
-                {
-                    continue
-                }
+                guard viewPortHandler.isInBoundsLeft(_barShadowRectBuffer.origin.x + _barShadowRectBuffer.size.width) else { continue }
                 
-                if !viewPortHandler.isInBoundsRight(_barShadowRectBuffer.origin.x)
-                {
-                    break
-                }
+                guard viewPortHandler.isInBoundsRight(_barShadowRectBuffer.origin.x) else { break }
                 
                 _barShadowRectBuffer.origin.y = viewPortHandler.contentTop
                 _barShadowRectBuffer.size.height = viewPortHandler.contentHeight
@@ -381,20 +346,10 @@ open class BarChartRenderer: BarLineScatterCandleBubbleRenderer
         // draw the bar shadow before the values
         if dataProvider.isDrawBarShadowEnabled
         {
-            for j in stride(from: 0, to: buffer.rects.count, by: 1)
+            for barRect in buffer where viewPortHandler.isInBoundsLeft(barRect.origin.x + barRect.size.width)
             {
-                let barRect = buffer.rects[j]
-                
-                if (!viewPortHandler.isInBoundsLeft(barRect.origin.x + barRect.size.width))
-                {
-                    continue
-                }
-                
-                if (!viewPortHandler.isInBoundsRight(barRect.origin.x))
-                {
-                    break
-                }
-                
+                guard viewPortHandler.isInBoundsRight(barRect.origin.x) else { break }
+
                 context.setFillColor(dataSet.barShadowColor.cgColor)
                 context.fill(barRect)
             }
@@ -406,25 +361,18 @@ open class BarChartRenderer: BarLineScatterCandleBubbleRenderer
         {
             context.setFillColor(dataSet.color(atIndex: 0).cgColor)
         }
-
+        
         // In case the chart is stacked, we need to accomodate individual bars within accessibilityOrdereredElements
         let isStacked = dataSet.isStacked
         let stackSize = isStacked ? dataSet.stackSize : 1
 
-        for j in stride(from: 0, to: buffer.rects.count, by: 1)
+        for j in buffer.indices
         {
-            let barRect = buffer.rects[j]
-
-            if (!viewPortHandler.isInBoundsLeft(barRect.origin.x + barRect.size.width))
-            {
-                continue
-            }
-            
-            if (!viewPortHandler.isInBoundsRight(barRect.origin.x))
-            {
-                break
-            }
+            let barRect = buffer[j]
             
+            guard viewPortHandler.isInBoundsLeft(barRect.origin.x + barRect.size.width) else { continue }
+            guard viewPortHandler.isInBoundsRight(barRect.origin.x) else { break }
+
             if !isSingleColor
             {
                 // Set the color for the currently drawn value. If the index is out of bounds, reuse colors.
@@ -443,20 +391,19 @@ open class BarChartRenderer: BarLineScatterCandleBubbleRenderer
             // Create and append the corresponding accessibility element to accessibilityOrderedElements
             if let chart = dataProvider as? BarChartView
             {
-                let element = createAccessibleElement(withIndex: j,
-                                                      container: chart,
-                                                      dataSet: dataSet,
-                                                      dataSetIndex: index,
-                                                      stackSize: stackSize)
-                { (element) in
+                let element = createAccessibleElement(
+                    withIndex: j,
+                    container: chart,
+                    dataSet: dataSet,
+                    dataSetIndex: index,
+                    stackSize: stackSize
+                ) { (element) in
                     element.accessibilityFrame = barRect
                 }
 
                 accessibilityOrderedElements[j/stackSize].append(element)
             }
         }
-        
-        context.restoreGState()
     }
     
     open func prepareBarHighlight(
@@ -490,20 +437,20 @@ open class BarChartRenderer: BarLineScatterCandleBubbleRenderer
                 let barData = dataProvider.barData
                 else { return }
 
-            let dataSets = barData.dataSets
-
             let valueOffsetPlus: CGFloat = 4.5
             var posOffset: CGFloat
             var negOffset: CGFloat
             let drawValueAboveBar = dataProvider.isDrawValueAboveBarEnabled
             
-            for dataSetIndex in 0 ..< barData.dataSetCount
+            for dataSetIndex in barData.indices
             {
-                guard let
-                    dataSet = dataSets[dataSetIndex] as? IBarChartDataSet,
+                guard
+                    let dataSet = barData[dataSetIndex] as? BarChartDataSetProtocol,
                     shouldDrawValues(forDataSet: dataSet)
                     else { continue }
                 
+                let angleRadians = dataSet.valueLabelAngle.DEG2RAD
+                
                 let isInverted = dataProvider.isInverted(axis: dataSet.axisDependency)
                 
                 // calculate the correct offset depending on the draw position of the value
@@ -520,7 +467,7 @@ open class BarChartRenderer: BarLineScatterCandleBubbleRenderer
                 
                 let buffer = _buffers[dataSetIndex]
                 
-                guard let formatter = dataSet.valueFormatter else { continue }
+                let formatter = dataSet.valueFormatter
                 
                 let trans = dataProvider.getTransformer(forAxis: dataSet.axisDependency)
                 
@@ -531,24 +478,20 @@ open class BarChartRenderer: BarLineScatterCandleBubbleRenderer
                 // if only single values are drawn (sum)
                 if !dataSet.isStacked
                 {
-                    for j in 0 ..< Int(ceil(Double(dataSet.entryCount) * animator.phaseX))
+                    let range = 0 ..< Int(ceil(Double(dataSet.entryCount) * animator.phaseX))
+                    for j in range
                     {
                         guard let e = dataSet.entryForIndex(j) as? BarChartDataEntry else { continue }
                         
-                        let rect = buffer.rects[j]
+                        let rect = buffer[j]
                         
                         let x = rect.origin.x + rect.size.width / 2.0
                         
-                        if !viewPortHandler.isInBoundsRight(x)
-                        {
-                            break
-                        }
+                        guard viewPortHandler.isInBoundsRight(x) else { break }
                         
-                        if !viewPortHandler.isInBoundsY(rect.origin.y)
-                            || !viewPortHandler.isInBoundsLeft(x)
-                        {
-                            continue
-                        }
+                        guard viewPortHandler.isInBoundsY(rect.origin.y),
+                            viewPortHandler.isInBoundsLeft(x)
+                            else { continue }
                         
                         let val = e.y
                         
@@ -567,7 +510,9 @@ open class BarChartRenderer: BarLineScatterCandleBubbleRenderer
                                     : (rect.origin.y + rect.size.height + negOffset),
                                 font: valueFont,
                                 align: .center,
-                                color: dataSet.valueTextColorAt(j))
+                                color: dataSet.valueTextColorAt(j),
+                                anchor: CGPoint(x: 0.5, y: 0.5),
+                                angleRadians: angleRadians)
                         }
                         
                         if let icon = e.icon, dataSet.isDrawIconsEnabled
@@ -580,13 +525,11 @@ open class BarChartRenderer: BarLineScatterCandleBubbleRenderer
                             px += iconsOffset.x
                             py += iconsOffset.y
                             
-                            ChartUtils.drawImage(
-                                context: context,
-                                image: icon,
-                                x: px,
-                                y: py,
-                                size: icon.size)
+                            context.drawImage(icon,
+                                              atCenter: CGPoint(x: px, y: py),
+                                              size: icon.size)
                         }
+                        
                     }
                 }
                 else
@@ -594,79 +537,30 @@ open class BarChartRenderer: BarLineScatterCandleBubbleRenderer
                     // if we have stacks
                     
                     var bufferIndex = 0
-                    
-                    for index in 0 ..< Int(ceil(Double(dataSet.entryCount) * animator.phaseX))
+                    let lastIndex = ceil(Double(dataSet.entryCount) * animator.phaseX)
+
+                    for index in 0 ..< Int(lastIndex)
                     {
                         guard let e = dataSet.entryForIndex(index) as? BarChartDataEntry else { continue }
                         
                         let vals = e.yValues
                         
-                        let rect = buffer.rects[bufferIndex]
+                        let rect = buffer[bufferIndex]
                         
                         let x = rect.origin.x + rect.size.width / 2.0
                         
                         // we still draw stacked bars, but there is one non-stacked in between
-                        if vals == nil
-                        {
-                            if !viewPortHandler.isInBoundsRight(x)
-                            {
-                                break
-                            }
-                            
-                            if !viewPortHandler.isInBoundsY(rect.origin.y)
-                                || !viewPortHandler.isInBoundsLeft(x)
-                            {
-                                continue
-                            }
-                            
-                            if dataSet.isDrawValuesEnabled
-                            {
-                                drawValue(
-                                    context: context,
-                                    value: formatter.stringForValue(
-                                        e.y,
-                                        entry: e,
-                                        dataSetIndex: dataSetIndex,
-                                        viewPortHandler: viewPortHandler),
-                                    xPos: x,
-                                    yPos: rect.origin.y +
-                                        (e.y >= 0 ? posOffset : negOffset),
-                                    font: valueFont,
-                                    align: .center,
-                                    color: dataSet.valueTextColorAt(index))
-                            }
-                            
-                            if let icon = e.icon, dataSet.isDrawIconsEnabled
-                            {
-                                var px = x
-                                var py = rect.origin.y +
-                                    (e.y >= 0 ? posOffset : negOffset)
-                                
-                                px += iconsOffset.x
-                                py += iconsOffset.y
-                                
-                                ChartUtils.drawImage(
-                                    context: context,
-                                    image: icon,
-                                    x: px,
-                                    y: py,
-                                    size: icon.size)
-                            }
-                        }
-                        else
+                        if let values = vals
                         {
                             // draw stack values
-                            
-                            let vals = vals!
                             var transformed = [CGPoint]()
-                            
+
                             var posY = 0.0
                             var negY = -e.negativeSum
-                            
-                            for k in 0 ..< vals.count
+
+                            for value in values
                             {
-                                let value = vals[k]
-                                var y: Double
+                                let y: Double
                                 
                                 if value == 0.0 && (posY == 0.0 || negY == 0.0)
                                 {
@@ -683,34 +577,28 @@ open class BarChartRenderer: BarLineScatterCandleBubbleRenderer
                                     y = negY
                                     negY -= value
                                 }
-                                
+
                                 transformed.append(CGPoint(x: 0.0, y: CGFloat(y * phaseY)))
                             }
-                            
+
                             trans.pointValuesToPixel(&transformed)
-                            
-                            for k in 0 ..< transformed.count
+
+                            for (value, transformed) in zip(values, transformed)
                             {
-                                let val = vals[k]
-                                let drawBelow = (val == 0.0 && negY == 0.0 && posY > 0.0) || val < 0.0
-                                let y = transformed[k].y + (drawBelow ? negOffset : posOffset)
-                                
-                                if !viewPortHandler.isInBoundsRight(x)
-                                {
-                                    break
-                                }
-                                
-                                if !viewPortHandler.isInBoundsY(y) || !viewPortHandler.isInBoundsLeft(x)
-                                {
-                                    continue
-                                }
-                                
+                                let drawBelow = (value == 0.0 && negY == 0.0 && posY > 0.0) || value < 0.0
+                                let y = transformed.y + (drawBelow ? negOffset : posOffset)
+
+                                guard viewPortHandler.isInBoundsRight(x) else { break }
+                                guard viewPortHandler.isInBoundsY(y),
+                                    viewPortHandler.isInBoundsLeft(x)
+                                    else { continue }
+
                                 if dataSet.isDrawValuesEnabled
                                 {
                                     drawValue(
                                         context: context,
                                         value: formatter.stringForValue(
-                                            vals[k],
+                                            value,
                                             entry: e,
                                             dataSetIndex: dataSetIndex,
                                             viewPortHandler: viewPortHandler),
@@ -718,22 +606,61 @@ open class BarChartRenderer: BarLineScatterCandleBubbleRenderer
                                         yPos: y,
                                         font: valueFont,
                                         align: .center,
-                                        color: dataSet.valueTextColorAt(index))
+                                        color: dataSet.valueTextColorAt(index),
+                                        anchor: CGPoint(x: 0.5, y: 0.5),
+                                        angleRadians: angleRadians)
                                 }
-                                
+
                                 if let icon = e.icon, dataSet.isDrawIconsEnabled
                                 {
-                                    ChartUtils.drawImage(
-                                        context: context,
-                                        image: icon,
-                                        x: x + iconsOffset.x,
-                                        y: y + iconsOffset.y,
-                                        size: icon.size)
+                                    context.drawImage(icon,
+                                                      atCenter: CGPoint(x: x + iconsOffset.x,
+                                                                      y: y + iconsOffset.y),
+                                                      size: icon.size)
                                 }
                             }
                         }
-                        
-                        bufferIndex = vals == nil ? (bufferIndex + 1) : (bufferIndex + vals!.count)
+                        else
+                        {
+                            guard viewPortHandler.isInBoundsRight(x) else { break }
+                            guard viewPortHandler.isInBoundsY(rect.origin.y),
+                                viewPortHandler.isInBoundsLeft(x) else { continue }
+
+                            if dataSet.isDrawValuesEnabled
+                            {
+                                drawValue(
+                                    context: context,
+                                    value: formatter.stringForValue(
+                                        e.y,
+                                        entry: e,
+                                        dataSetIndex: dataSetIndex,
+                                        viewPortHandler: viewPortHandler),
+                                    xPos: x,
+                                    yPos: rect.origin.y +
+                                        (e.y >= 0 ? posOffset : negOffset),
+                                    font: valueFont,
+                                    align: .center,
+                                    color: dataSet.valueTextColorAt(index),
+                                    anchor: CGPoint(x: 0.5, y: 0.5),
+                                    angleRadians: angleRadians)
+                            }
+                            
+                            if let icon = e.icon, dataSet.isDrawIconsEnabled
+                            {
+                                var px = x
+                                var py = rect.origin.y +
+                                    (e.y >= 0 ? posOffset : negOffset)
+                                
+                                px += iconsOffset.x
+                                py += iconsOffset.y
+                                
+                                context.drawImage(icon,
+                                                  atCenter: CGPoint(x: px, y: py),
+                                                  size: icon.size)
+                            }
+                        }
+
+                        bufferIndex += vals?.count ?? 1
                     }
                 }
             }
@@ -741,10 +668,19 @@ open class BarChartRenderer: BarLineScatterCandleBubbleRenderer
     }
     
     /// Draws a value at the specified x and y position.
-    @objc open func drawValue(context: CGContext, value: String, xPos: CGFloat, yPos: CGFloat, font: NSUIFont, align: NSTextAlignment, color: NSUIColor)
+    @objc open func drawValue(context: CGContext, value: String, xPos: CGFloat, yPos: CGFloat, font: NSUIFont, align: TextAlignment, color: NSUIColor, anchor: CGPoint, angleRadians: CGFloat)
     {
-        ChartUtils.drawText(context: context, text: value, point: CGPoint(x: xPos, y: yPos), align: align, attributes: [NSAttributedString.Key.font: font, NSAttributedString.Key.foregroundColor: color])
+        if (angleRadians == 0.0)
+        {
+            context.drawText(value, at: CGPoint(x: xPos, y: yPos), align: align, attributes: [.font: font, .foregroundColor: color])
+        }
+        else
+        {
+            // align left to center text with rotation
+            context.drawText(value, at: CGPoint(x: xPos, y: yPos), align: align, anchor: anchor, angleRadians: angleRadians, attributes: [.font: font, .foregroundColor: color])
+        }
     }
+
     
     open override func drawExtras(context: CGContext)
     {
@@ -759,22 +695,19 @@ open class BarChartRenderer: BarLineScatterCandleBubbleRenderer
             else { return }
         
         context.saveGState()
-        
+        defer { context.restoreGState() }
         var barRect = CGRect()
         
         for high in indices
         {
             guard
-                let set = barData.getDataSetByIndex(high.dataSetIndex) as? IBarChartDataSet,
+                let set = barData[high.dataSetIndex] as? BarChartDataSetProtocol,
                 set.isHighlightEnabled
                 else { continue }
             
             if let e = set.entryForXValue(high.x, closestToY: high.y) as? BarChartDataEntry
             {
-                if !isInBoundsX(entry: e, dataSet: set)
-                {
-                    continue
-                }
+                guard isInBoundsX(entry: e, dataSet: set) else { continue }
                 
                 let trans = dataProvider.getTransformer(forAxis: set.axisDependency)
                 
@@ -814,8 +747,6 @@ open class BarChartRenderer: BarLineScatterCandleBubbleRenderer
                 context.fill(barRect)
             }
         }
-        
-        context.restoreGState()
     }
 
     /// Sets the drawing position of the highlight object based on the given bar-rect.
@@ -842,7 +773,7 @@ open class BarChartRenderer: BarLineScatterCandleBubbleRenderer
     /// Note that it is marked internal to support subclass modification in the HorizontalBarChart.
     internal func createAccessibleElement(withIndex idx: Int,
                                           container: BarChartView,
-                                          dataSet: IBarChartDataSet,
+                                          dataSet: BarChartDataSetProtocol,
                                           dataSetIndex: Int,
                                           stackSize: Int,
                                           modifier: (NSUIAccessibilityElement) -> ()) -> NSUIAccessibilityElement
@@ -858,18 +789,18 @@ open class BarChartRenderer: BarLineScatterCandleBubbleRenderer
         // there is the possibility of some labels being rounded up. A floor() might fix this, but seems to be a brute force solution.
         let label = xAxis.valueFormatter?.stringForValue(e.x, axis: xAxis) ?? "\(e.x)"
 
-        var elementValueText = dataSet.valueFormatter?.stringForValue(
+        var elementValueText = dataSet.valueFormatter.stringForValue(
             e.y,
             entry: e,
             dataSetIndex: dataSetIndex,
-            viewPortHandler: viewPortHandler) ?? "\(e.y)"
+            viewPortHandler: viewPortHandler)
 
         if dataSet.isStacked, let vals = e.yValues
         {
             let labelCount = min(dataSet.colors.count, stackSize)
 
             let stackLabel: String?
-            if (dataSet.stackLabels.count > 0 && labelCount > 0) {
+            if (!dataSet.stackLabels.isEmpty && labelCount > 0) {
                 let labelIndex = idx % labelCount
                 stackLabel = dataSet.stackLabels.indices.contains(labelIndex) ? dataSet.stackLabels[labelIndex] : nil
             } else {
@@ -878,12 +809,12 @@ open class BarChartRenderer: BarLineScatterCandleBubbleRenderer
             
             //Handles empty array of yValues
             let yValue = vals.isEmpty ? 0.0 : vals[idx % vals.count]
-            
-            elementValueText = dataSet.valueFormatter?.stringForValue(
+
+            elementValueText = dataSet.valueFormatter.stringForValue(
                 yValue,
                 entry: e,
                 dataSetIndex: dataSetIndex,
-                viewPortHandler: viewPortHandler) ?? "\(e.y)"
+                viewPortHandler: viewPortHandler)
 
             if let stackLabel = stackLabel {
                 elementValueText = stackLabel + " \(elementValueText)"

+ 38 - 9
Pods/Charts/Source/Charts/Renderers/BarLineScatterCandleBubbleRenderer.swift

@@ -13,17 +13,34 @@ import Foundation
 import CoreGraphics
 
 @objc(BarLineScatterCandleBubbleChartRenderer)
-open class BarLineScatterCandleBubbleRenderer: DataRenderer
+open class BarLineScatterCandleBubbleRenderer: NSObject, DataRenderer
 {
+    public let viewPortHandler: ViewPortHandler
+
+    public final var accessibleChartElements: [NSUIAccessibilityElement] = []
+
+    public let animator: Animator
+
     internal var _xBounds = XBounds() // Reusable XBounds object
     
-    public override init(animator: Animator, viewPortHandler: ViewPortHandler)
+    public init(animator: Animator, viewPortHandler: ViewPortHandler)
     {
-        super.init(animator: animator, viewPortHandler: viewPortHandler)
+        self.viewPortHandler = viewPortHandler
+        self.animator = animator
+
+        super.init()
     }
-    
+
+    open func drawData(context: CGContext) { }
+
+    open func drawValues(context: CGContext) { }
+
+    open func drawExtras(context: CGContext) { }
+
+    open func drawHighlighted(context: CGContext, indices: [Highlight]) { }
+
     /// Checks if the provided entry object is in bounds for drawing considering the current animation phase.
-    internal func isInBoundsX(entry e: ChartDataEntry, dataSet: IBarLineScatterCandleBubbleChartDataSet) -> Bool
+    internal func isInBoundsX(entry e: ChartDataEntry, dataSet: BarLineScatterCandleBubbleChartDataSetProtocol) -> Bool
     {
         let entryIndex = dataSet.entryIndex(entry: e)
         return Double(entryIndex) < Double(dataSet.entryCount) * animator.phaseX
@@ -32,18 +49,26 @@ open class BarLineScatterCandleBubbleRenderer: DataRenderer
     /// Calculates and returns the x-bounds for the given DataSet in terms of index in their values array.
     /// This includes minimum and maximum visible x, as well as range.
     internal func xBounds(chart: BarLineScatterCandleBubbleChartDataProvider,
-                          dataSet: IBarLineScatterCandleBubbleChartDataSet,
+                          dataSet: BarLineScatterCandleBubbleChartDataSetProtocol,
                           animator: Animator?) -> XBounds
     {
         return XBounds(chart: chart, dataSet: dataSet, animator: animator)
     }
     
     /// - Returns: `true` if the DataSet values should be drawn, `false` if not.
-    internal func shouldDrawValues(forDataSet set: IChartDataSet) -> Bool
+    internal func shouldDrawValues(forDataSet set: ChartDataSetProtocol) -> Bool
     {
         return set.isVisible && (set.isDrawValuesEnabled || set.isDrawIconsEnabled)
     }
 
+    open func initBuffers() { }
+
+    open func isDrawingValuesAllowed(dataProvider: ChartDataProvider?) -> Bool
+    {
+        guard let data = dataProvider?.data else { return false }
+        return data.entryCount < Int(CGFloat(dataProvider?.maxVisibleCount ?? 0) * viewPortHandler.scaleX)
+    }
+
     /// Class representing the bounds of the current viewport in terms of indices in the values array of a DataSet.
     open class XBounds
     {
@@ -62,7 +87,7 @@ open class BarLineScatterCandleBubbleRenderer: DataRenderer
         }
         
         public init(chart: BarLineScatterCandleBubbleChartDataProvider,
-                    dataSet: IBarLineScatterCandleBubbleChartDataSet,
+                    dataSet: BarLineScatterCandleBubbleChartDataSetProtocol,
                     animator: Animator?)
         {
             self.set(chart: chart, dataSet: dataSet, animator: animator)
@@ -70,7 +95,7 @@ open class BarLineScatterCandleBubbleRenderer: DataRenderer
         
         /// Calculates the minimum and maximum x values as well as the range between them.
         open func set(chart: BarLineScatterCandleBubbleChartDataProvider,
-                      dataSet: IBarLineScatterCandleBubbleChartDataSet,
+                      dataSet: BarLineScatterCandleBubbleChartDataSetProtocol,
                       animator: Animator?)
         {
             let phaseX = Swift.max(0.0, Swift.min(1.0, animator?.phaseX ?? 1.0))
@@ -86,6 +111,10 @@ open class BarLineScatterCandleBubbleRenderer: DataRenderer
             range = Int(Double(self.max - self.min) * phaseX)
         }
     }
+    
+    public func createAccessibleHeader(usingChart chart: ChartViewBase, andData data: ChartData, withDefaultDescription defaultDescription: String) -> NSUIAccessibilityElement {
+        return AccessibleHeader.create(usingChart: chart, andData: data, withDefaultDescription: defaultDescription)
+    }
 }
 
 extension BarLineScatterCandleBubbleRenderer.XBounds: RangeExpression {

+ 29 - 28
Pods/Charts/Source/Charts/Renderers/BubbleChartRenderer.swift

@@ -45,7 +45,8 @@ open class BubbleChartRenderer: BarLineScatterCandleBubbleRenderer
             accessibleChartElements.append(element)
         }
 
-        for (i, set) in (bubbleData.dataSets as! [IBubbleChartDataSet]).enumerated() where set.isVisible
+        let sets = bubbleData.dataSets as! [BubbleChartDataSet]
+        for case let (i, set) in zip(sets.indices, sets) where set.isVisible
         {
             drawDataSet(context: context, dataSet: set, dataSetIndex: i)
         }
@@ -71,7 +72,7 @@ open class BubbleChartRenderer: BarLineScatterCandleBubbleRenderer
     private var _pointBuffer = CGPoint()
     private var _sizeBuffer = [CGPoint](repeating: CGPoint(), count: 2)
     
-    @objc open func drawDataSet(context: CGContext, dataSet: IBubbleChartDataSet, dataSetIndex: Int)
+    @objc open func drawDataSet(context: CGContext, dataSet: BubbleChartDataSetProtocol, dataSetIndex: Int)
     {
         guard let dataProvider = dataProvider else { return }
         
@@ -153,8 +154,7 @@ open class BubbleChartRenderer: BarLineScatterCandleBubbleRenderer
         guard let
             dataProvider = dataProvider,
             let bubbleData = dataProvider.bubbleData,
-            isDrawingValuesAllowed(dataProvider: dataProvider),
-            let dataSets = bubbleData.dataSets as? [IBubbleChartDataSet]
+            isDrawingValuesAllowed(dataProvider: dataProvider)
             else { return }
 
         let phaseX = max(0.0, min(1.0, animator.phaseX))
@@ -162,15 +162,16 @@ open class BubbleChartRenderer: BarLineScatterCandleBubbleRenderer
 
         var pt = CGPoint()
 
-        for i in 0..<dataSets.count
+        for i in bubbleData.indices
         {
-            let dataSet = dataSets[i]
-
-            guard
-                shouldDrawValues(forDataSet: dataSet),
-                let formatter = dataSet.valueFormatter
-                else { continue }
+            guard let dataSet = bubbleData[i] as? BubbleChartDataSetProtocol,
+                  shouldDrawValues(forDataSet: dataSet)
+            else
+            {
+                continue
+            }
 
+            let formatter = dataSet.valueFormatter
             let alpha = phaseX == 1 ? phaseY : phaseX
 
             _xBounds.set(chart: dataProvider, dataSet: dataSet, animator: animator)
@@ -179,6 +180,8 @@ open class BubbleChartRenderer: BarLineScatterCandleBubbleRenderer
             let valueToPixelMatrix = trans.valueToPixelMatrix
 
             let iconsOffset = dataSet.iconsOffset
+            
+            let angleRadians = dataSet.valueLabelAngle.DEG2RAD
 
             for j in _xBounds
             {
@@ -209,23 +212,21 @@ open class BubbleChartRenderer: BarLineScatterCandleBubbleRenderer
 
                 if dataSet.isDrawValuesEnabled
                 {
-                    ChartUtils.drawText(
-                        context: context,
-                        text: text,
-                        point: CGPoint(
-                            x: pt.x,
-                            y: pt.y - (0.5 * lineHeight)),
-                        align: .center,
-                        attributes: [NSAttributedString.Key.font: valueFont, NSAttributedString.Key.foregroundColor: valueTextColor])
+                    context.drawText(text,
+                                     at: CGPoint(x: pt.x,
+                                                    y: pt.y - (0.5 * lineHeight)),
+                                     align: .center,
+                                     angleRadians: angleRadians,
+                                     attributes: [.font: valueFont,
+                                                  .foregroundColor: valueTextColor])
                 }
 
                 if let icon = e.icon, dataSet.isDrawIconsEnabled
                 {
-                    ChartUtils.drawImage(context: context,
-                                         image: icon,
-                                         x: pt.x + iconsOffset.x,
-                                         y: pt.y + iconsOffset.y,
-                                         size: icon.size)
+                    context.drawImage(icon,
+                                      atCenter: CGPoint(x: pt.x + iconsOffset.x,
+                                                      y: pt.y + iconsOffset.y),
+                                      size: icon.size)
                 }
             }
         }
@@ -251,7 +252,7 @@ open class BubbleChartRenderer: BarLineScatterCandleBubbleRenderer
         for high in indices
         {
             guard
-                let dataSet = bubbleData.getDataSetByIndex(high.dataSetIndex) as? IBubbleChartDataSet,
+                let dataSet = bubbleData[high.dataSetIndex] as? BubbleChartDataSetProtocol,
                 dataSet.isHighlightEnabled,
                 let entry = dataSet.entryForXValue(high.x, closestToY: high.y) as? BubbleChartDataEntry,
                 isInBoundsX(entry: entry, dataSet: dataSet)
@@ -326,7 +327,7 @@ open class BubbleChartRenderer: BarLineScatterCandleBubbleRenderer
     /// Creates an NSUIAccessibleElement representing individual bubbles location and relative size.
     private func createAccessibleElement(withIndex idx: Int,
                                          container: BubbleChartView,
-                                         dataSet: IBubbleChartDataSet,
+                                         dataSet: BubbleChartDataSetProtocol,
                                          dataSetIndex: Int,
                                          shapeSize: CGFloat,
                                          modifier: (NSUIAccessibilityElement) -> ()) -> NSUIAccessibilityElement
@@ -342,10 +343,10 @@ open class BubbleChartRenderer: BarLineScatterCandleBubbleRenderer
         // there is the possibility of some labels being rounded up. A floor() might fix this, but seems to be a brute force solution.
         let label = xAxis.valueFormatter?.stringForValue(e.x, axis: xAxis) ?? "\(e.x)"
 
-        let elementValueText = dataSet.valueFormatter?.stringForValue(e.y,
+        let elementValueText = dataSet.valueFormatter.stringForValue(e.y,
                                                                       entry: e,
                                                                       dataSetIndex: dataSetIndex,
-                                                                      viewPortHandler: viewPortHandler) ?? "\(e.y)"
+                                                                      viewPortHandler: viewPortHandler)
 
         let dataSetCount = dataProvider.bubbleData?.dataSetCount ?? -1
         let doesContainMultipleDataSets = dataSetCount > 1

+ 24 - 27
Pods/Charts/Source/Charts/Renderers/CandleStickChartRenderer.swift

@@ -38,7 +38,7 @@ open class CandleStickChartRenderer: LineScatterCandleRadarRenderer
             accessibleChartElements.append(element)
         }
 
-        for set in candleData.dataSets as! [ICandleChartDataSet] where set.isVisible
+        for case let set as CandleChartDataSetProtocol in (candleData as ChartData) where set.isVisible
         {
             drawDataSet(context: context, dataSet: set)
         }
@@ -51,7 +51,7 @@ open class CandleStickChartRenderer: LineScatterCandleRadarRenderer
     private var _bodyRect = CGRect()
     private var _lineSegments = [CGPoint](repeating: CGPoint(), count: 2)
     
-    @objc open func drawDataSet(context: CGContext, dataSet: ICandleChartDataSet)
+    @objc open func drawDataSet(context: CGContext, dataSet: CandleChartDataSetProtocol)
     {
         guard
             let dataProvider = dataProvider
@@ -81,7 +81,7 @@ open class CandleStickChartRenderer: LineScatterCandleRadarRenderer
             let high = e.high
             let low = e.low
             
-            let doesContainMultipleDataSets = (dataProvider.candleData?.dataSets.count ?? 1) > 1
+            let doesContainMultipleDataSets = (dataProvider.candleData?.count ?? 1) > 1
             var accessibilityMovementDescription = "neutral"
             var accessibilityRect = CGRect(x: CGFloat(xPos) + 0.5 - barSpace,
                                            y: CGFloat(low * phaseY),
@@ -275,28 +275,28 @@ open class CandleStickChartRenderer: LineScatterCandleRadarRenderer
         // if values are drawn
         if isDrawingValuesAllowed(dataProvider: dataProvider)
         {
-            let dataSets = candleData.dataSets
-            
             let phaseY = animator.phaseY
             
             var pt = CGPoint()
             
-            for i in 0 ..< dataSets.count
+            for i in candleData.indices
             {
                 guard let
-                    dataSet = dataSets[i] as? IBarLineScatterCandleBubbleChartDataSet,
+                    dataSet = candleData[i] as? BarLineScatterCandleBubbleChartDataSetProtocol,
                     shouldDrawValues(forDataSet: dataSet)
                     else { continue }
                 
                 let valueFont = dataSet.valueFont
                 
-                guard let formatter = dataSet.valueFormatter else { continue }
+                let formatter = dataSet.valueFormatter
                 
                 let trans = dataProvider.getTransformer(forAxis: dataSet.axisDependency)
                 let valueToPixelMatrix = trans.valueToPixelMatrix
                 
                 let iconsOffset = dataSet.iconsOffset
                 
+                let angleRadians = dataSet.valueLabelAngle.DEG2RAD
+                
                 _xBounds.set(chart: dataProvider, dataSet: dataSet, animator: animator)
                 
                 let lineHeight = valueFont.lineHeight
@@ -322,27 +322,24 @@ open class CandleStickChartRenderer: LineScatterCandleRadarRenderer
                     
                     if dataSet.isDrawValuesEnabled
                     {
-                        ChartUtils.drawText(
-                            context: context,
-                            text: formatter.stringForValue(
-                                e.high,
-                                entry: e,
-                                dataSetIndex: i,
-                                viewPortHandler: viewPortHandler),
-                            point: CGPoint(
-                                x: pt.x,
-                                y: pt.y - yOffset),
-                            align: .center,
-                            attributes: [NSAttributedString.Key.font: valueFont, NSAttributedString.Key.foregroundColor: dataSet.valueTextColorAt(j)])
+                        context.drawText(formatter.stringForValue(e.high,
+                                                                  entry: e,
+                                                                  dataSetIndex: i,
+                                                                  viewPortHandler: viewPortHandler),
+                                         at: CGPoint(x: pt.x,
+                                                     y: pt.y - yOffset),
+                                         align: .center,
+                                         angleRadians: angleRadians,
+                                         attributes: [.font: valueFont,
+                                                      .foregroundColor: dataSet.valueTextColorAt(j)])
                     }
                     
                     if let icon = e.icon, dataSet.isDrawIconsEnabled
                     {
-                        ChartUtils.drawImage(context: context,
-                                             image: icon,
-                                             x: pt.x + iconsOffset.x,
-                                             y: pt.y + iconsOffset.y,
-                                             size: icon.size)
+                        context.drawImage(icon,
+                                          atCenter: CGPoint(x: pt.x + iconsOffset.x,
+                                                          y: pt.y + iconsOffset.y),
+                                          size: icon.size)
                     }
                 }
             }
@@ -365,7 +362,7 @@ open class CandleStickChartRenderer: LineScatterCandleRadarRenderer
         for high in indices
         {
             guard
-                let set = candleData.getDataSetByIndex(high.dataSetIndex) as? ICandleChartDataSet,
+                let set = candleData[high.dataSetIndex] as? CandleChartDataSetProtocol,
                 set.isHighlightEnabled
                 else { continue }
             
@@ -407,7 +404,7 @@ open class CandleStickChartRenderer: LineScatterCandleRadarRenderer
 
     private func createAccessibleElement(withIndex idx: Int,
                                          container: CandleChartDataProvider,
-                                         dataSet: ICandleChartDataSet,
+                                         dataSet: CandleChartDataSetProtocol,
                                          modifier: (NSUIAccessibilityElement) -> ()) -> NSUIAccessibilityElement {
 
         let element = NSUIAccessibilityElement(accessibilityContainer: container)

+ 30 - 38
Pods/Charts/Source/Charts/Renderers/CombinedChartRenderer.swift

@@ -12,8 +12,14 @@
 import Foundation
 import CoreGraphics
 
-open class CombinedChartRenderer: DataRenderer
+open class CombinedChartRenderer: NSObject, DataRenderer
 {
+    public let viewPortHandler: ViewPortHandler
+
+    public final var accessibleChartElements: [NSUIAccessibilityElement] = []
+
+    public let animator: Animator
+
     @objc open weak var chart: CombinedChartView?
     
     /// if set to true, all values are drawn above their bars, instead of below their top
@@ -28,9 +34,11 @@ open class CombinedChartRenderer: DataRenderer
     
     @objc public init(chart: CombinedChartView, animator: Animator, viewPortHandler: ViewPortHandler)
     {
-        super.init(animator: animator, viewPortHandler: viewPortHandler)
-        
         self.chart = chart
+        self.viewPortHandler = viewPortHandler
+        self.animator = animator
+
+        super.init()
         
         createRenderers()
     }
@@ -51,46 +59,41 @@ open class CombinedChartRenderer: DataRenderer
                 {
                     _renderers.append(BarChartRenderer(dataProvider: chart, animator: animator, viewPortHandler: viewPortHandler))
                 }
-                break
-                
+
             case .line:
                 if chart.lineData !== nil
                 {
                     _renderers.append(LineChartRenderer(dataProvider: chart, animator: animator, viewPortHandler: viewPortHandler))
                 }
-                break
-                
+
             case .candle:
                 if chart.candleData !== nil
                 {
                     _renderers.append(CandleStickChartRenderer(dataProvider: chart, animator: animator, viewPortHandler: viewPortHandler))
                 }
-                break
-                
+
             case .scatter:
                 if chart.scatterData !== nil
                 {
                     _renderers.append(ScatterChartRenderer(dataProvider: chart, animator: animator, viewPortHandler: viewPortHandler))
                 }
-                break
-                
+
             case .bubble:
                 if chart.bubbleData !== nil
                 {
                     _renderers.append(BubbleChartRenderer(dataProvider: chart, animator: animator, viewPortHandler: viewPortHandler))
                 }
-                break
             }
         }
 
     }
     
-    open override func initBuffers()
+    open func initBuffers()
     {
         _renderers.forEach { $0.initBuffers() }
     }
     
-    open override func drawData(context: CGContext)
+    open func drawData(context: CGContext)
     {
         // If we redraw the data, remove and repopulate accessible elements to update label values and frames
         accessibleChartElements.removeAll()
@@ -111,17 +114,17 @@ open class CombinedChartRenderer: DataRenderer
         _renderers.forEach { $0.drawData(context: context) }
     }
     
-    open override func drawValues(context: CGContext)
+    open func drawValues(context: CGContext)
     {
         _renderers.forEach { $0.drawValues(context: context) }
     }
     
-    open override func drawExtras(context: CGContext)
+    open func drawExtras(context: CGContext)
     {
         _renderers.forEach { $0.drawExtras(context: context) }
     }
     
-    open override func drawHighlighted(context: CGContext, indices: [Highlight])
+    open func drawHighlighted(context: CGContext, indices: [Highlight])
     {
         for renderer in _renderers
         {
@@ -148,12 +151,7 @@ open class CombinedChartRenderer: DataRenderer
                 data = (renderer as! BubbleChartRenderer).dataProvider?.bubbleData
             }
             
-            let dataIndex: Int? = {
-                guard let data = data else { return nil }
-                return (chart?.data as? CombinedChartData)?
-                    .allData
-                    .firstIndex(of: data)
-            }()
+            let dataIndex = data == nil ? nil : (chart?.data as? CombinedChartData)?.allData.firstIndex(of: data!)
             
             let dataIndices = indices.filter{ $0.dataIndex == dataIndex || $0.dataIndex == -1 }
             
@@ -161,17 +159,10 @@ open class CombinedChartRenderer: DataRenderer
         }
     }
 
-    /// - Returns: The sub-renderer object at the specified index.
-    @objc open func getSubRenderer(index: Int) -> DataRenderer?
+    open func isDrawingValuesAllowed(dataProvider: ChartDataProvider?) -> Bool
     {
-        if index >= _renderers.count || index < 0
-        {
-            return nil
-        }
-        else
-        {
-            return _renderers[index]
-        }
+        guard let data = dataProvider?.data else { return false }
+        return data.entryCount < Int(CGFloat(dataProvider?.maxVisibleCount ?? 0) * viewPortHandler.scaleX)
     }
 
     /// All sub-renderers.
@@ -194,16 +185,17 @@ open class CombinedChartRenderer: DataRenderer
     /// e.g. if you provide [DrawOrder.Bar, DrawOrder.Line], the bars will be drawn behind the lines.
     open var drawOrder: [CombinedChartView.DrawOrder]
     {
-        get
-        {
-            return _drawOrder
-        }
+        get { _drawOrder }
         set
         {
-            if newValue.count > 0
+            if !newValue.isEmpty
             {
                 _drawOrder = newValue
             }
         }
     }
+    
+    public func createAccessibleHeader(usingChart chart: ChartViewBase, andData data: ChartData, withDefaultDescription defaultDescription: String) -> NSUIAccessibilityElement {
+        return AccessibleHeader.create(usingChart: chart, andData: data, withDefaultDescription: defaultDescription)
+    }
 }

+ 46 - 51
Pods/Charts/Source/Charts/Renderers/HorizontalBarChartRenderer.swift

@@ -12,13 +12,10 @@
 import Foundation
 import CoreGraphics
 
-#if canImport(UIKit)
+#if !os(OSX)
     import UIKit
 #endif
 
-#if canImport(Cocoa)
-import Cocoa
-#endif
 
 open class HorizontalBarChartRenderer: BarChartRenderer
 {
@@ -40,21 +37,21 @@ open class HorizontalBarChartRenderer: BarChartRenderer
         if let barData = dataProvider?.barData
         {
             // Matche buffers count to dataset count
-            if _buffers.count != barData.dataSetCount
+            if _buffers.count != barData.count
             {
-                while _buffers.count < barData.dataSetCount
+                while _buffers.count < barData.count
                 {
                     _buffers.append(Buffer())
                 }
-                while _buffers.count > barData.dataSetCount
+                while _buffers.count > barData.count
                 {
                     _buffers.removeLast()
                 }
             }
             
-            for i in stride(from: 0, to: barData.dataSetCount, by: 1)
+            for i in barData.indices
             {
-                let set = barData.dataSets[i] as! IBarChartDataSet
+                let set = barData[i] as! BarChartDataSetProtocol
                 let size = set.entryCount * (set.isStacked ? set.stackSize : 1)
                 if _buffers[i].rects.count != size
                 {
@@ -68,7 +65,7 @@ open class HorizontalBarChartRenderer: BarChartRenderer
         }
     }
     
-    private func prepareBuffer(dataSet: IBarChartDataSet, index: Int)
+    private func prepareBuffer(dataSet: BarChartDataSetProtocol, index: Int)
     {
         guard let
             dataProvider = dataProvider,
@@ -132,7 +129,7 @@ open class HorizontalBarChartRenderer: BarChartRenderer
                 var yStart = 0.0
                 
                 // fill the stack
-                for k in 0 ..< vals!.count
+                for k in vals!.indices
                 {
                     let value = vals![k]
                     
@@ -182,7 +179,7 @@ open class HorizontalBarChartRenderer: BarChartRenderer
     
     private var _barShadowRectBuffer: CGRect = CGRect()
     
-    open override func drawDataSet(context: CGContext, dataSet: IBarChartDataSet, index: Int)
+    open override func drawDataSet(context: CGContext, dataSet: BarChartDataSetProtocol, index: Int)
     {
         guard let dataProvider = dataProvider else { return }
         
@@ -248,7 +245,7 @@ open class HorizontalBarChartRenderer: BarChartRenderer
         let isStacked = dataSet.isStacked
         let stackSize = isStacked ? dataSet.stackSize : 1
 
-        for j in stride(from: 0, to: buffer.rects.count, by: 1)
+        for j in buffer.rects.indices
         {
             let barRect = buffer.rects[j]
             
@@ -326,29 +323,29 @@ open class HorizontalBarChartRenderer: BarChartRenderer
                 let dataProvider = dataProvider,
                 let barData = dataProvider.barData
                 else { return }
-            
-            let dataSets = barData.dataSets
-            
-            let textAlign = NSTextAlignment.left
+
+            let textAlign = TextAlignment.left
             
             let valueOffsetPlus: CGFloat = 5.0
             var posOffset: CGFloat
             var negOffset: CGFloat
             let drawValueAboveBar = dataProvider.isDrawValueAboveBarEnabled
             
-            for dataSetIndex in 0 ..< barData.dataSetCount
+            for dataSetIndex in barData.indices
             {
                 guard let
-                    dataSet = dataSets[dataSetIndex] as? IBarChartDataSet,
+                    dataSet = barData[dataSetIndex] as? BarChartDataSetProtocol,
                     shouldDrawValues(forDataSet: dataSet)
                     else { continue }
                 
+                let angleRadians = dataSet.valueLabelAngle.DEG2RAD
+                
                 let isInverted = dataProvider.isInverted(axis: dataSet.axisDependency)
                 
                 let valueFont = dataSet.valueFont
                 let yOffset = -valueFont.lineHeight / 2.0
                 
-                guard let formatter = dataSet.valueFormatter else { continue }
+                let formatter = dataSet.valueFormatter
                 
                 let trans = dataProvider.getTransformer(forAxis: dataSet.axisDependency)
                 
@@ -392,7 +389,7 @@ open class HorizontalBarChartRenderer: BarChartRenderer
                             viewPortHandler: viewPortHandler)
                         
                         // calculate the correct offset depending on the draw position of the value
-                        let valueTextWidth = valueText.size(withAttributes: [NSAttributedString.Key.font: valueFont]).width
+                        let valueTextWidth = valueText.size(withAttributes: [.font: valueFont]).width
                         posOffset = (drawValueAboveBar ? valueOffsetPlus : -(valueTextWidth + valueOffsetPlus))
                         negOffset = (drawValueAboveBar ? -(valueTextWidth + valueOffsetPlus) : valueOffsetPlus) - rect.size.width
                         
@@ -412,7 +409,9 @@ open class HorizontalBarChartRenderer: BarChartRenderer
                                 yPos: y + yOffset,
                                 font: valueFont,
                                 align: textAlign,
-                                color: dataSet.valueTextColorAt(j))
+                                color: dataSet.valueTextColorAt(j),
+                                anchor: CGPoint.zero,
+                                angleRadians: angleRadians)
                         }
                         
                         if let icon = e.icon, dataSet.isDrawIconsEnabled
@@ -424,12 +423,9 @@ open class HorizontalBarChartRenderer: BarChartRenderer
                             px += iconsOffset.x
                             py += iconsOffset.y
                             
-                            ChartUtils.drawImage(
-                                context: context,
-                                image: icon,
-                                x: px,
-                                y: py,
-                                size: icon.size)
+                            context.drawImage(icon,
+                                              atCenter: CGPoint(x: px, y: py),
+                                              size: icon.size)
                         }
                     }
                 }
@@ -493,7 +489,9 @@ open class HorizontalBarChartRenderer: BarChartRenderer
                                     yPos: rect.origin.y + yOffset,
                                     font: valueFont,
                                     align: textAlign,
-                                    color: dataSet.valueTextColorAt(index))
+                                    color: dataSet.valueTextColorAt(index),
+                                    anchor: CGPoint.zero,
+                                    angleRadians: angleRadians)
                             }
                             
                             if let icon = e.icon, dataSet.isDrawIconsEnabled
@@ -505,12 +503,9 @@ open class HorizontalBarChartRenderer: BarChartRenderer
                                 px += iconsOffset.x
                                 py += iconsOffset.y
                                 
-                                ChartUtils.drawImage(
-                                    context: context,
-                                    image: icon,
-                                    x: px,
-                                    y: py,
-                                    size: icon.size)
+                                context.drawImage(icon,
+                                                  atCenter: CGPoint(x: px, y: py),
+                                                  size: icon.size)
                             }
                         }
                         else
@@ -521,7 +516,7 @@ open class HorizontalBarChartRenderer: BarChartRenderer
                             var posY = 0.0
                             var negY = -e.negativeSum
                             
-                            for k in 0 ..< vals.count
+                            for k in vals.indices
                             {
                                 let value = vals[k]
                                 var y: Double
@@ -547,7 +542,7 @@ open class HorizontalBarChartRenderer: BarChartRenderer
                             
                             trans.pointValuesToPixel(&transformed)
                             
-                            for k in 0 ..< transformed.count
+                            for k in transformed.indices
                             {
                                 let val = vals[k]
                                 let valueText = formatter.stringForValue(
@@ -557,7 +552,7 @@ open class HorizontalBarChartRenderer: BarChartRenderer
                                     viewPortHandler: viewPortHandler)
                                 
                                 // calculate the correct offset depending on the draw position of the value
-                                let valueTextWidth = valueText.size(withAttributes: [NSAttributedString.Key.font: valueFont]).width
+                                let valueTextWidth = valueText.size(withAttributes: [.font: valueFont]).width
                                 posOffset = (drawValueAboveBar ? valueOffsetPlus : -(valueTextWidth + valueOffsetPlus))
                                 negOffset = (drawValueAboveBar ? -(valueTextWidth + valueOffsetPlus) : valueOffsetPlus)
                                 
@@ -590,27 +585,27 @@ open class HorizontalBarChartRenderer: BarChartRenderer
                                 if dataSet.isDrawValuesEnabled
                                 {
                                     drawValue(context: context,
-                                        value: valueText,
-                                        xPos: x,
-                                        yPos: y + yOffset,
-                                        font: valueFont,
-                                        align: textAlign,
-                                        color: dataSet.valueTextColorAt(index))
+                                              value: valueText,
+                                              xPos: x,
+                                              yPos: y + yOffset,
+                                              font: valueFont,
+                                              align: textAlign,
+                                              color: dataSet.valueTextColorAt(index),
+                                              anchor: CGPoint.zero,
+                                              angleRadians: angleRadians)
                                 }
                                 
                                 if let icon = e.icon, dataSet.isDrawIconsEnabled
                                 {
-                                    ChartUtils.drawImage(
-                                        context: context,
-                                        image: icon,
-                                        x: x + iconsOffset.x,
-                                        y: y + iconsOffset.y,
-                                        size: icon.size)
+                                    context.drawImage(icon,
+                                                      atCenter: CGPoint(x: x + iconsOffset.x,
+                                                                      y: y + iconsOffset.y),
+                                                      size: icon.size)
                                 }
                             }
                         }
                         
-                        bufferIndex = vals == nil ? (bufferIndex + 1) : (bufferIndex + vals!.count)
+                        bufferIndex += vals?.count ?? 1
                     }
                 }
             }

+ 82 - 107
Pods/Charts/Source/Charts/Renderers/LegendRenderer.swift

@@ -13,16 +13,19 @@ import Foundation
 import CoreGraphics
 
 @objc(ChartLegendRenderer)
-open class LegendRenderer: Renderer
+open class LegendRenderer: NSObject, Renderer
 {
+    @objc public let viewPortHandler: ViewPortHandler
+
     /// the legend object this renderer renders
     @objc open var legend: Legend?
 
     @objc public init(viewPortHandler: ViewPortHandler, legend: Legend?)
     {
-        super.init(viewPortHandler: viewPortHandler)
-        
+        self.viewPortHandler = viewPortHandler
         self.legend = legend
+
+        super.init()
     }
 
     /// Prepares the legend and calculates all needed forms, labels and colors.
@@ -35,25 +38,23 @@ open class LegendRenderer: Renderer
             var entries: [LegendEntry] = []
             
             // loop for building up the colors and labels used in the legend
-            for i in 0..<data.dataSetCount
-            {
-                guard let dataSet = data.getDataSetByIndex(i) else { continue }
-                
+            for dataSet in data
+            {                
                 let clrs: [NSUIColor] = dataSet.colors
                 let entryCount = dataSet.entryCount
                 
                 // if we have a barchart with stacked bars
-                if dataSet is IBarChartDataSet &&
-                    (dataSet as! IBarChartDataSet).isStacked
+                if dataSet is BarChartDataSetProtocol &&
+                    (dataSet as! BarChartDataSetProtocol).isStacked
                 {
-                    let bds = dataSet as! IBarChartDataSet
+                    let bds = dataSet as! BarChartDataSetProtocol
                     let sLabels = bds.stackLabels
                     let minEntries = min(clrs.count, bds.stackSize)
 
                     for j in 0..<minEntries
                     {
                         let label: String?
-                        if (sLabels.count > 0)
+                        if !sLabels.isEmpty && minEntries > 0
                         {
                             let labelIndex = j % minEntries
                             label = sLabels.indices.contains(labelIndex) ? sLabels[labelIndex] : nil
@@ -63,100 +64,76 @@ open class LegendRenderer: Renderer
                             label = nil
                         }
 
-                        entries.append(
-                            LegendEntry(
-                                label: label,
-                                form: dataSet.form,
-                                formSize: dataSet.formSize,
-                                formLineWidth: dataSet.formLineWidth,
-                                formLineDashPhase: dataSet.formLineDashPhase,
-                                formLineDashLengths: dataSet.formLineDashLengths,
-                                formColor: clrs[j]
-                            )
-                        )
+                        let entry = LegendEntry(label: label)
+                        entry.form = dataSet.form
+                        entry.formSize = dataSet.formSize
+                        entry.formLineWidth = dataSet.formLineWidth
+                        entry.formLineDashPhase = dataSet.formLineDashPhase
+                        entry.formLineDashLengths = dataSet.formLineDashLengths
+                        entry.formColor = clrs[j]
+
+                        entries.append(entry)
                     }
                     
                     if dataSet.label != nil
                     {
                         // add the legend description label
-                        
-                        entries.append(
-                            LegendEntry(
-                                label: dataSet.label,
-                                form: .none,
-                                formSize: CGFloat.nan,
-                                formLineWidth: CGFloat.nan,
-                                formLineDashPhase: 0.0,
-                                formLineDashLengths: nil,
-                                formColor: nil
-                            )
-                        )
+                        let entry = LegendEntry(label: dataSet.label)
+                        entry.form = .none
+
+                        entries.append(entry)
                     }
                 }
-                else if dataSet is IPieChartDataSet
+                else if dataSet is PieChartDataSetProtocol
                 {
-                    let pds = dataSet as! IPieChartDataSet
+                    let pds = dataSet as! PieChartDataSetProtocol
                     
                     for j in 0..<min(clrs.count, entryCount)
                     {
-                        entries.append(
-                            LegendEntry(
-                                label: (pds.entryForIndex(j) as? PieChartDataEntry)?.label,
-                                form: dataSet.form,
-                                formSize: dataSet.formSize,
-                                formLineWidth: dataSet.formLineWidth,
-                                formLineDashPhase: dataSet.formLineDashPhase,
-                                formLineDashLengths: dataSet.formLineDashLengths,
-                                formColor: clrs[j]
-                            )
-                        )
+                        let entry = LegendEntry(label: (pds.entryForIndex(j) as? PieChartDataEntry)?.label)
+                        entry.form = dataSet.form
+                        entry.formSize = dataSet.formSize
+                        entry.formLineWidth = dataSet.formLineWidth
+                        entry.formLineDashPhase = dataSet.formLineDashPhase
+                        entry.formLineDashLengths = dataSet.formLineDashLengths
+                        entry.formColor = clrs[j]
+
+                        entries.append(entry)
                     }
                     
                     if dataSet.label != nil
                     {
                         // add the legend description label
-                        
-                        entries.append(
-                            LegendEntry(
-                                label: dataSet.label,
-                                form: .none,
-                                formSize: CGFloat.nan,
-                                formLineWidth: CGFloat.nan,
-                                formLineDashPhase: 0.0,
-                                formLineDashLengths: nil,
-                                formColor: nil
-                            )
-                        )
+                        let entry = LegendEntry(label: dataSet.label)
+                        entry.form = .none
+
+                        entries.append(entry)
                     }
                 }
-                else if dataSet is ICandleChartDataSet &&
-                    (dataSet as! ICandleChartDataSet).decreasingColor != nil
+                else if dataSet is CandleChartDataSetProtocol &&
+                    (dataSet as! CandleChartDataSetProtocol).decreasingColor != nil
                 {
-                    let candleDataSet = dataSet as! ICandleChartDataSet
-                    
-                    entries.append(
-                        LegendEntry(
-                            label: nil,
-                            form: dataSet.form,
-                            formSize: dataSet.formSize,
-                            formLineWidth: dataSet.formLineWidth,
-                            formLineDashPhase: dataSet.formLineDashPhase,
-                            formLineDashLengths: dataSet.formLineDashLengths,
-                            formColor: candleDataSet.decreasingColor
-                        )
-                    )
-                    
-                    entries.append(
-                        LegendEntry(
-                            label: dataSet.label,
-                            form: dataSet.form,
-                            formSize: dataSet.formSize,
-                            formLineWidth: dataSet.formLineWidth,
-                            formLineDashPhase: dataSet.formLineDashPhase,
-                            formLineDashLengths: dataSet.formLineDashLengths,
-                            formColor: candleDataSet.increasingColor
-                        )
-                    )
+                    let candleDataSet = dataSet as! CandleChartDataSetProtocol
+
+                    let decreasingEntry = LegendEntry(label: nil)
+                    decreasingEntry.form = dataSet.form
+                    decreasingEntry.formSize = dataSet.formSize
+                    decreasingEntry.formLineWidth = dataSet.formLineWidth
+                    decreasingEntry.formLineDashPhase = dataSet.formLineDashPhase
+                    decreasingEntry.formLineDashLengths = dataSet.formLineDashLengths
+                    decreasingEntry.formColor = candleDataSet.decreasingColor
+
+                    entries.append(decreasingEntry)
+
+                    let increasingEntry = LegendEntry(label: dataSet.label)
+                    increasingEntry.form = dataSet.form
+                    increasingEntry.formSize = dataSet.formSize
+                    increasingEntry.formLineWidth = dataSet.formLineWidth
+                    increasingEntry.formLineDashPhase = dataSet.formLineDashPhase
+                    increasingEntry.formLineDashLengths = dataSet.formLineDashLengths
+                    increasingEntry.formColor = candleDataSet.increasingColor
+
+                    entries.append(increasingEntry)
                 }
                 else
                 { // all others
@@ -174,18 +151,16 @@ open class LegendRenderer: Renderer
                         { // add label to the last entry
                             label = dataSet.label
                         }
-                        
-                        entries.append(
-                            LegendEntry(
-                                label: label,
-                                form: dataSet.form,
-                                formSize: dataSet.formSize,
-                                formLineWidth: dataSet.formLineWidth,
-                                formLineDashPhase: dataSet.formLineDashPhase,
-                                formLineDashLengths: dataSet.formLineDashLengths,
-                                formColor: clrs[j]
-                            )
-                        )
+
+                        let entry = LegendEntry(label: label)
+                        entry.form = dataSet.form
+                        entry.formSize = dataSet.formSize
+                        entry.formLineWidth = dataSet.formLineWidth
+                        entry.formLineDashPhase = dataSet.formLineDashPhase
+                        entry.formLineDashLengths = dataSet.formLineDashLengths
+                        entry.formColor = clrs[j]
+
+                        entries.append(entry)
                     }
                 }
             }
@@ -320,13 +295,13 @@ open class LegendRenderer: Renderer
             
             var lineIndex: Int = 0
             
-            for i in 0 ..< entries.count
+            for i in entries.indices
             {
                 let e = entries[i]
                 let drawingForm = e.form != .none
                 let formSize = e.formSize.isNaN ? defaultFormSize : e.formSize
                 
-                if i < calculatedLabelBreakPoints.count &&
+                if i < calculatedLabelBreakPoints.endIndex &&
                     calculatedLabelBreakPoints[i]
                 {
                     posX = originPosX
@@ -335,7 +310,7 @@ open class LegendRenderer: Renderer
                 
                 if posX == originPosX &&
                     horizontalAlignment == .center &&
-                    lineIndex < calculatedLineSizes.count
+                    lineIndex < calculatedLineSizes.endIndex
                 {
                     posX += (direction == .rightToLeft
                         ? calculatedLineSizes[lineIndex].width
@@ -383,7 +358,7 @@ open class LegendRenderer: Renderer
                         y: posY,
                         label: e.label!,
                         font: labelFont,
-                        textColor: labelTextColor)
+                        textColor: e.labelColor ?? labelTextColor)
                     
                     if direction == .leftToRight
                     {
@@ -425,7 +400,7 @@ open class LegendRenderer: Renderer
                 posY = viewPortHandler.chartHeight / 2.0 - legend.neededHeight / 2.0 + legend.yOffset
             }
             
-            for i in 0 ..< entries.count
+            for i in entries.indices
             {
                 let e = entries[i]
                 let drawingForm = e.form != .none
@@ -475,12 +450,12 @@ open class LegendRenderer: Renderer
                     
                     if !wasStacked
                     {
-                        drawLabel(context: context, x: posX, y: posY, label: e.label!, font: labelFont, textColor: labelTextColor)
+                        drawLabel(context: context, x: posX, y: posY, label: e.label!, font: labelFont, textColor: e.labelColor ?? labelTextColor)
                     }
                     else
                     {
                         posY += labelLineHeight + yEntrySpace
-                        drawLabel(context: context, x: posX, y: posY, label: e.label!, font: labelFont, textColor: labelTextColor)
+                        drawLabel(context: context, x: posX, y: posY, label: e.label!, font: labelFont, textColor: e.labelColor ?? labelTextColor)
                     }
                     
                     // make a step down
@@ -551,7 +526,7 @@ open class LegendRenderer: Renderer
             
             context.setLineWidth(formLineWidth)
             
-            if formLineDashLengths != nil && formLineDashLengths!.count > 0
+            if formLineDashLengths != nil && !formLineDashLengths!.isEmpty
             {
                 context.setLineDash(phase: formLineDashPhase, lengths: formLineDashLengths!)
             }
@@ -573,6 +548,6 @@ open class LegendRenderer: Renderer
     /// Draws the provided label at the given position.
     @objc open func drawLabel(context: CGContext, x: CGFloat, y: CGFloat, label: String, font: NSUIFont, textColor: NSUIColor)
     {
-        ChartUtils.drawText(context: context, text: label, point: CGPoint(x: x, y: y), align: .left, attributes: [NSAttributedString.Key.font: font, NSAttributedString.Key.foregroundColor: textColor])
+        context.drawText(label, at: CGPoint(x: x, y: y), align: .left, attributes: [.font: font, .foregroundColor: textColor])
     }
 }

+ 260 - 143
Pods/Charts/Source/Charts/Renderers/LineChartRenderer.swift

@@ -32,24 +32,17 @@ open class LineChartRenderer: LineRadarRenderer
     open override func drawData(context: CGContext)
     {
         guard let lineData = dataProvider?.lineData else { return }
-        
-        for i in 0 ..< lineData.dataSetCount
-        {
-            guard let set = lineData.getDataSetByIndex(i) else { continue }
-            
-            if set.isVisible
-            {
-                if !(set is ILineChartDataSet)
-                {
-                    fatalError("Datasets for LineChartRenderer must conform to ILineChartDataSet")
-                }
-                
-                drawDataSet(context: context, dataSet: set as! ILineChartDataSet)
-            }
-        }
+
+        let sets = lineData.dataSets as? [LineChartDataSet]
+        assert(sets != nil, "Datasets for LineChartRenderer must conform to ILineChartDataSet")
+
+        let drawDataSet = { self.drawDataSet(context: context, dataSet: $0) }
+        sets!.lazy
+            .filter(\.isVisible)
+            .forEach(drawDataSet)
     }
     
-    @objc open func drawDataSet(context: CGContext, dataSet: ILineChartDataSet)
+    @objc open func drawDataSet(context: CGContext, dataSet: LineChartDataSetProtocol)
     {
         if dataSet.entryCount < 1
         {
@@ -86,8 +79,19 @@ open class LineChartRenderer: LineRadarRenderer
         
         context.restoreGState()
     }
+
+    private func drawLine(
+        context: CGContext,
+        spline: CGMutablePath,
+        drawingColor: NSUIColor)
+    {
+        context.beginPath()
+        context.addPath(spline)
+        context.setStrokeColor(drawingColor.cgColor)
+        context.strokePath()
+    }
     
-    @objc open func drawCubicBezier(context: CGContext, dataSet: ILineChartDataSet)
+    @objc open func drawCubicBezier(context: CGContext, dataSet: LineChartDataSetProtocol)
     {
         guard let dataProvider = dataProvider else { return }
         
@@ -162,7 +166,8 @@ open class LineChartRenderer: LineRadarRenderer
         }
         
         context.saveGState()
-        
+        defer { context.restoreGState() }
+
         if dataSet.isDrawFilledEnabled
         {
             // Copy this path because we make changes to it
@@ -170,16 +175,18 @@ open class LineChartRenderer: LineRadarRenderer
             
             drawCubicFill(context: context, dataSet: dataSet, spline: fillPath!, matrix: valueToPixelMatrix, bounds: _xBounds)
         }
-        
-        context.beginPath()
-        context.addPath(cubicPath)
-        context.setStrokeColor(drawingColor.cgColor)
-        context.strokePath()
-        
-        context.restoreGState()
+
+        if dataSet.isDrawLineWithGradientEnabled
+        {
+            drawGradientLine(context: context, dataSet: dataSet, spline: cubicPath, matrix: valueToPixelMatrix)
+        }
+        else
+        {
+            drawLine(context: context, spline: cubicPath, drawingColor: drawingColor)
+        }
     }
     
-    @objc open func drawHorizontalBezier(context: CGContext, dataSet: ILineChartDataSet)
+    @objc open func drawHorizontalBezier(context: CGContext, dataSet: LineChartDataSetProtocol)
     {
         guard let dataProvider = dataProvider else { return }
         
@@ -229,6 +236,7 @@ open class LineChartRenderer: LineRadarRenderer
         }
         
         context.saveGState()
+        defer { context.restoreGState() }
         
         if dataSet.isDrawFilledEnabled
         {
@@ -237,25 +245,27 @@ open class LineChartRenderer: LineRadarRenderer
             
             drawCubicFill(context: context, dataSet: dataSet, spline: fillPath!, matrix: valueToPixelMatrix, bounds: _xBounds)
         }
-        
-        context.beginPath()
-        context.addPath(cubicPath)
-        context.setStrokeColor(drawingColor.cgColor)
-        context.strokePath()
-        
-        context.restoreGState()
+
+        if dataSet.isDrawLineWithGradientEnabled
+        {
+            drawGradientLine(context: context, dataSet: dataSet, spline: cubicPath, matrix: valueToPixelMatrix)
+        }
+        else
+        {
+            drawLine(context: context, spline: cubicPath, drawingColor: drawingColor)
+        }
     }
     
     open func drawCubicFill(
         context: CGContext,
-                dataSet: ILineChartDataSet,
-                spline: CGMutablePath,
-                matrix: CGAffineTransform,
-                bounds: XBounds)
+        dataSet: LineChartDataSetProtocol,
+        spline: CGMutablePath,
+        matrix: CGAffineTransform,
+        bounds: XBounds)
     {
         guard
             let dataProvider = dataProvider
-            else { return }
+        else { return }
         
         if bounds.range <= 0
         {
@@ -285,7 +295,7 @@ open class LineChartRenderer: LineRadarRenderer
     
     private var _lineSegments = [CGPoint](repeating: CGPoint(), count: 2)
     
-    @objc open func drawLinear(context: CGContext, dataSet: ILineChartDataSet)
+    @objc open func drawLinear(context: CGContext, dataSet: LineChartDataSetProtocol)
     {
         guard let dataProvider = dataProvider else { return }
         
@@ -308,80 +318,140 @@ open class LineChartRenderer: LineRadarRenderer
         }
         
         context.saveGState()
+        defer { context.restoreGState() }
 
+        // more than 1 color
+        if dataSet.colors.count > 1, !dataSet.isDrawLineWithGradientEnabled
+        {
             if _lineSegments.count != pointsPerEntryPair
             {
                 // Allocate once in correct size
                 _lineSegments = [CGPoint](repeating: CGPoint(), count: pointsPerEntryPair)
             }
 
-        for j in _xBounds.dropLast()
-        {
-            var e: ChartDataEntry! = dataSet.entryForIndex(j)
-            
-            if e == nil { continue }
-            
-            _lineSegments[0].x = CGFloat(e.x)
-            _lineSegments[0].y = CGFloat(e.y * phaseY)
-            
-            if j < _xBounds.max
+            for j in _xBounds.dropLast()
             {
-                // TODO: remove the check.
-                // With the new XBounds iterator, j is always smaller than _xBounds.max
-                // Keeping this check for a while, if xBounds have no further breaking changes, it should be safe to remove the check
-                e = dataSet.entryForIndex(j + 1)
+                var e: ChartDataEntry! = dataSet.entryForIndex(j)
                 
-                if e == nil { break }
+                if e == nil { continue }
                 
-                if isDrawSteppedEnabled
+                _lineSegments[0].x = CGFloat(e.x)
+                _lineSegments[0].y = CGFloat(e.y * phaseY)
+                
+                if j < _xBounds.max
                 {
-                    _lineSegments[1] = CGPoint(x: CGFloat(e.x), y: _lineSegments[0].y)
-                    _lineSegments[2] = _lineSegments[1]
-                    _lineSegments[3] = CGPoint(x: CGFloat(e.x), y: CGFloat(e.y * phaseY))
+                    // TODO: remove the check.
+                    // With the new XBounds iterator, j is always smaller than _xBounds.max
+                    // Keeping this check for a while, if xBounds have no further breaking changes, it should be safe to remove the check
+                    e = dataSet.entryForIndex(j + 1)
+                    
+                    if e == nil { break }
+                    
+                    if isDrawSteppedEnabled
+                    {
+                        _lineSegments[1] = CGPoint(x: CGFloat(e.x), y: _lineSegments[0].y)
+                        _lineSegments[2] = _lineSegments[1]
+                        _lineSegments[3] = CGPoint(x: CGFloat(e.x), y: CGFloat(e.y * phaseY))
+                    }
+                    else
+                    {
+                        _lineSegments[1] = CGPoint(x: CGFloat(e.x), y: CGFloat(e.y * phaseY))
+                    }
                 }
                 else
                 {
-                    _lineSegments[1] = CGPoint(x: CGFloat(e.x), y: CGFloat(e.y * phaseY))
+                    _lineSegments[1] = _lineSegments[0]
+                }
+
+                _lineSegments = _lineSegments.map { $0.applying(valueToPixelMatrix) }
+
+                if (!viewPortHandler.isInBoundsRight(_lineSegments[0].x))
+                {
+                    break
+                }
+
+                // Determine the start and end coordinates of the line, and make sure they differ.
+                guard
+                    let firstCoordinate = _lineSegments.first,
+                    let lastCoordinate = _lineSegments.last,
+                    firstCoordinate != lastCoordinate else { continue }
+                
+                // make sure the lines don't do shitty things outside bounds
+                if !viewPortHandler.isInBoundsLeft(lastCoordinate.x) ||
+                    !viewPortHandler.isInBoundsTop(max(firstCoordinate.y, lastCoordinate.y)) ||
+                    !viewPortHandler.isInBoundsBottom(min(firstCoordinate.y, lastCoordinate.y))
+                {
+                    continue
                 }
+                
+                // get the color that is set for this line-segment
+                context.setStrokeColor(dataSet.color(atIndex: j).cgColor)
+                context.strokeLineSegments(between: _lineSegments)
             }
-            else
-            {
-                _lineSegments[1] = _lineSegments[0]
+        }
+        else
+        { // only one color per dataset
+            guard dataSet.entryForIndex(_xBounds.min) != nil else {
+                return
             }
 
-            for i in 0..<_lineSegments.count
-            {
-                _lineSegments[i] = _lineSegments[i].applying(valueToPixelMatrix)
-            }
-            
-            if !viewPortHandler.isInBoundsRight(_lineSegments[0].x)
+            var firstPoint = true
+
+            let path = CGMutablePath()
+            for x in stride(from: _xBounds.min, through: _xBounds.range + _xBounds.min, by: 1)
             {
-                break
+                guard let e1 = dataSet.entryForIndex(x == 0 ? 0 : (x - 1)) else { continue }
+                guard let e2 = dataSet.entryForIndex(x) else { continue }
+                
+                let startPoint =
+                    CGPoint(
+                        x: CGFloat(e1.x),
+                        y: CGFloat(e1.y * phaseY))
+                    .applying(valueToPixelMatrix)
+                
+                if firstPoint
+                {
+                    path.move(to: startPoint)
+                    firstPoint = false
+                }
+                else
+                {
+                    path.addLine(to: startPoint)
+                }
+                
+                if isDrawSteppedEnabled
+                {
+                    let steppedPoint =
+                        CGPoint(
+                            x: CGFloat(e2.x),
+                            y: CGFloat(e1.y * phaseY))
+                        .applying(valueToPixelMatrix)
+                    path.addLine(to: steppedPoint)
+                }
+
+                let endPoint =
+                    CGPoint(
+                        x: CGFloat(e2.x),
+                        y: CGFloat(e2.y * phaseY))
+                    .applying(valueToPixelMatrix)
+                path.addLine(to: endPoint)
             }
             
-            // Determine the start and end coordinates of the line, and make sure they differ.
-            guard
-                let firstCoordinate = _lineSegments.first,
-                let lastCoordinate = _lineSegments.last,
-                firstCoordinate != lastCoordinate else { continue }
-            
-            // make sure the lines don't do shitty things outside bounds
-            if !viewPortHandler.isInBoundsLeft(lastCoordinate.x) ||
-                !viewPortHandler.isInBoundsTop(max(firstCoordinate.y, lastCoordinate.y)) ||
-                !viewPortHandler.isInBoundsBottom(min(firstCoordinate.y, lastCoordinate.y))
+            if !firstPoint
             {
-                continue
+                if dataSet.isDrawLineWithGradientEnabled {
+                    drawGradientLine(context: context, dataSet: dataSet, spline: path, matrix: valueToPixelMatrix)
+                } else {
+                    context.beginPath()
+                    context.addPath(path)
+                    context.setStrokeColor(dataSet.color(atIndex: 0).cgColor)
+                    context.strokePath()
+                }
             }
-            
-            // get the color that is set for this line-segment
-            context.setStrokeColor(dataSet.color(atIndex: j).cgColor)
-            context.strokeLineSegments(between: _lineSegments)
         }
-        
-        context.restoreGState()
     }
     
-    open func drawLinearFill(context: CGContext, dataSet: ILineChartDataSet, trans: Transformer, bounds: XBounds)
+    open func drawLinearFill(context: CGContext, dataSet: LineChartDataSetProtocol, trans: Transformer, bounds: XBounds)
     {
         guard let dataProvider = dataProvider else { return }
         
@@ -402,7 +472,7 @@ open class LineChartRenderer: LineRadarRenderer
     }
     
     /// Generates the path that is used for filled drawing.
-    private func generateFilledPath(dataSet: ILineChartDataSet, fillMin: CGFloat, bounds: XBounds, matrix: CGAffineTransform) -> CGPath
+    private func generateFilledPath(dataSet: LineChartDataSetProtocol, fillMin: CGFloat, bounds: XBounds, matrix: CGAffineTransform) -> CGPath
     {
         let phaseY = animator.phaseY
         let isDrawSteppedEnabled = dataSet.mode == .stepped
@@ -449,26 +519,26 @@ open class LineChartRenderer: LineRadarRenderer
         guard
             let dataProvider = dataProvider,
             let lineData = dataProvider.lineData
-            else { return }
+        else { return }
 
         if isDrawingValuesAllowed(dataProvider: dataProvider)
         {
-            let dataSets = lineData.dataSets
-            
             let phaseY = animator.phaseY
             
             var pt = CGPoint()
             
-            for i in 0 ..< dataSets.count
+            for i in lineData.indices
             {
                 guard let
-                    dataSet = dataSets[i] as? ILineChartDataSet,
-                    shouldDrawValues(forDataSet: dataSet)
-                    else { continue }
+                        dataSet = lineData[i] as? LineChartDataSetProtocol,
+                      shouldDrawValues(forDataSet: dataSet)
+                else { continue }
                 
                 let valueFont = dataSet.valueFont
                 
-                guard let formatter = dataSet.valueFormatter else { continue }
+                let formatter = dataSet.valueFormatter
+                
+                let angleRadians = dataSet.valueLabelAngle.DEG2RAD
                 
                 let trans = dataProvider.getTransformer(forAxis: dataSet.axisDependency)
                 let valueToPixelMatrix = trans.valueToPixelMatrix
@@ -503,28 +573,26 @@ open class LineChartRenderer: LineRadarRenderer
                         continue
                     }
                     
-                    if dataSet.isDrawValuesEnabled {
-                        ChartUtils.drawText(
-                            context: context,
-                            text: formatter.stringForValue(
-                                e.y,
-                                entry: e,
-                                dataSetIndex: i,
-                                viewPortHandler: viewPortHandler),
-                            point: CGPoint(
-                                x: pt.x,
-                                y: pt.y - CGFloat(valOffset) - valueFont.lineHeight),
-                            align: .center,
-                            attributes: [NSAttributedString.Key.font: valueFont, NSAttributedString.Key.foregroundColor: dataSet.valueTextColorAt(j)])
+                    if dataSet.isDrawValuesEnabled
+                    {
+                        context.drawText(formatter.stringForValue(e.y,
+                                                                  entry: e,
+                                                                  dataSetIndex: i,
+                                                                  viewPortHandler: viewPortHandler),
+                                         at: CGPoint(x: pt.x,
+                                                     y: pt.y - CGFloat(valOffset) - valueFont.lineHeight),
+                                         align: .center,
+                                         angleRadians: angleRadians,
+                                         attributes: [.font: valueFont,
+                                                      .foregroundColor: dataSet.valueTextColorAt(j)])
                     }
                     
                     if let icon = e.icon, dataSet.isDrawIconsEnabled
                     {
-                        ChartUtils.drawImage(context: context,
-                                             image: icon,
-                                             x: pt.x + iconsOffset.x,
-                                             y: pt.y + iconsOffset.y,
-                                             size: icon.size)
+                        context.drawImage(icon,
+                                          atCenter: CGPoint(x: pt.x + iconsOffset.x,
+                                                            y: pt.y + iconsOffset.y),
+                                          size: icon.size)
                     }
                 }
             }
@@ -541,11 +609,9 @@ open class LineChartRenderer: LineRadarRenderer
         guard
             let dataProvider = dataProvider,
             let lineData = dataProvider.lineData
-            else { return }
+        else { return }
         
         let phaseY = animator.phaseY
-
-        let dataSets = lineData.dataSets
         
         var pt = CGPoint()
         var rect = CGRect()
@@ -564,11 +630,13 @@ open class LineChartRenderer: LineRadarRenderer
 
         context.saveGState()
 
-        for i in 0 ..< dataSets.count
+        for i in lineData.indices
         {
-            guard let dataSet = lineData.getDataSetByIndex(i) as? ILineChartDataSet else { continue }
-            
-            if !dataSet.isVisible || dataSet.entryCount == 0
+            guard let dataSet = lineData[i] as? LineChartDataSetProtocol else { continue }
+
+            // Skip Circles and Accessibility if not enabled,
+            // reduces CPU significantly if not needed
+            if !dataSet.isVisible || !dataSet.isDrawCirclesEnabled || dataSet.entryCount == 0
             {
                 continue
             }
@@ -609,14 +677,6 @@ open class LineChartRenderer: LineRadarRenderer
                     continue
                 }
                 
-                
-                // Skip Circles and Accessibility if not enabled,
-                // reduces CPU significantly if not needed
-                if !dataSet.isDrawCirclesEnabled
-                {
-                    continue
-                }
-                
                 // Accessibility element geometry
                 let scaleFactor: CGFloat = 3
                 let accessibilityRect = CGRect(x: pt.x - (scaleFactor * circleRadius),
@@ -667,7 +727,7 @@ open class LineChartRenderer: LineRadarRenderer
                     if drawCircleHole
                     {
                         context.setFillColor(dataSet.circleHoleColor!.cgColor)
-                     
+
                         // The hole rect
                         rect.origin.x = pt.x - circleHoleRadius
                         rect.origin.y = pt.y - circleHoleRadius
@@ -692,7 +752,7 @@ open class LineChartRenderer: LineRadarRenderer
         guard
             let dataProvider = dataProvider,
             let lineData = dataProvider.lineData
-            else { return }
+        else { return }
         
         let chartXMax = dataProvider.chartXMax
         
@@ -700,9 +760,9 @@ open class LineChartRenderer: LineRadarRenderer
         
         for high in indices
         {
-            guard let set = lineData.getDataSetByIndex(high.dataSetIndex) as? ILineChartDataSet
-                , set.isHighlightEnabled
-                else { continue }
+            guard let set = lineData[high.dataSetIndex] as? LineChartDataSetProtocol,
+                  set.isHighlightEnabled
+            else { continue }
             
             guard let e = set.entryForXValue(high.x, closestToY: high.y) else { continue }
             
@@ -710,7 +770,7 @@ open class LineChartRenderer: LineRadarRenderer
             {
                 continue
             }
-        
+
             context.setStrokeColor(set.highlightColor.cgColor)
             context.setLineWidth(set.highlightLineWidth)
             if set.highlightLineDashLengths != nil
@@ -743,6 +803,63 @@ open class LineChartRenderer: LineRadarRenderer
         context.restoreGState()
     }
 
+    func drawGradientLine(context: CGContext, dataSet: LineChartDataSetProtocol, spline: CGPath, matrix: CGAffineTransform)
+    {
+        guard let gradientPositions = dataSet.gradientPositions else
+        {
+            assertionFailure("Must set `gradientPositions if `dataSet.isDrawLineWithGradientEnabled` is true")
+            return
+        }
+
+        // `insetBy` is applied since bounding box
+        // doesn't take into account line width
+        // so that peaks are trimmed since
+        // gradient start and gradient end calculated wrong
+        let boundingBox = spline.boundingBox
+            .insetBy(dx: -dataSet.lineWidth / 2, dy: -dataSet.lineWidth / 2)
+
+        guard !boundingBox.isNull, !boundingBox.isInfinite, !boundingBox.isEmpty else {
+            return
+        }
+
+        let gradientStart = CGPoint(x: 0, y: boundingBox.minY)
+        let gradientEnd = CGPoint(x: 0, y: boundingBox.maxY)
+        let gradientColorComponents: [CGFloat] = dataSet.colors
+            .reversed()
+            .reduce(into: []) { (components, color) in
+                guard let (r, g, b, a) = color.nsuirgba else {
+                    return
+                }
+                components += [r, g, b, a]
+            }
+        let gradientLocations: [CGFloat] = gradientPositions.reversed()
+            .map { (position) in
+                let location = CGPoint(x: boundingBox.minX, y: position)
+                    .applying(matrix)
+                let normalizedLocation = (location.y - boundingBox.minY)
+                    / (boundingBox.maxY - boundingBox.minY)
+                return normalizedLocation.clamped(to: 0...1)
+            }
+
+        let baseColorSpace = CGColorSpaceCreateDeviceRGB()
+        guard let gradient = CGGradient(
+                colorSpace: baseColorSpace,
+                colorComponents: gradientColorComponents,
+                locations: gradientLocations,
+                count: gradientLocations.count) else {
+            return
+        }
+
+        context.saveGState()
+        defer { context.restoreGState() }
+
+        context.beginPath()
+        context.addPath(spline)
+        context.replacePathWithStrokedPath()
+        context.clip()
+        context.drawLinearGradient(gradient, start: gradientStart, end: gradientEnd, options: [])
+    }
+    
     /// Creates a nested array of empty subarrays each of which will be populated with NSUIAccessibilityElements.
     /// This is marked internal to support HorizontalBarChartRenderer as well.
     private func accessibilityCreateEmptyOrderedElements() -> [[NSUIAccessibilityElement]]
@@ -759,10 +876,10 @@ open class LineChartRenderer: LineRadarRenderer
     /// i.e. in case of a stacked chart, this returns each stack, not the combined bar.
     /// Note that it is marked internal to support subclass modification in the HorizontalBarChart.
     private func createAccessibleElement(withIndex idx: Int,
-                                          container: LineChartView,
-                                          dataSet: ILineChartDataSet,
-                                          dataSetIndex: Int,
-                                          modifier: (NSUIAccessibilityElement) -> ()) -> NSUIAccessibilityElement
+                                         container: LineChartView,
+                                         dataSet: LineChartDataSetProtocol,
+                                         dataSetIndex: Int,
+                                         modifier: (NSUIAccessibilityElement) -> ()) -> NSUIAccessibilityElement
     {
         let element = NSUIAccessibilityElement(accessibilityContainer: container)
         let xAxis = container.xAxis
@@ -775,10 +892,10 @@ open class LineChartRenderer: LineRadarRenderer
         // there is the possibility of some labels being rounded up. A floor() might fix this, but seems to be a brute force solution.
         let label = xAxis.valueFormatter?.stringForValue(e.x, axis: xAxis) ?? "\(e.x)"
 
-        let elementValueText = dataSet.valueFormatter?.stringForValue(e.y,
-                                                                      entry: e,
-                                                                      dataSetIndex: dataSetIndex,
-                                                                      viewPortHandler: viewPortHandler) ?? "\(e.y)"
+        let elementValueText = dataSet.valueFormatter.stringForValue(e.y,
+                                                                     entry: e,
+                                                                     dataSetIndex: dataSetIndex,
+                                                                     viewPortHandler: viewPortHandler)
 
         let dataSetCount = dataProvider.lineData?.dataSetCount ?? -1
         let doesContainMultipleDataSets = dataSetCount > 1

+ 1 - 1
Pods/Charts/Source/Charts/Renderers/LineScatterCandleRadarRenderer.swift

@@ -25,7 +25,7 @@ open class LineScatterCandleRadarRenderer: BarLineScatterCandleBubbleRenderer
     /// :param: points
     /// :param: horizontal
     /// :param: vertical
-    @objc open func drawHighlightLines(context: CGContext, point: CGPoint, set: ILineScatterCandleRadarChartDataSet)
+    @objc open func drawHighlightLines(context: CGContext, point: CGPoint, set: LineScatterCandleRadarChartDataSetProtocol)
     {
         
         // draw vertical highlight lines

+ 123 - 127
Pods/Charts/Source/Charts/Renderers/PieChartRenderer.swift

@@ -12,41 +12,41 @@
 import Foundation
 import CoreGraphics
 
-#if canImport(UIKit)
+#if !os(OSX)
     import UIKit
 #endif
 
-#if canImport(Cocoa)
-import Cocoa
-#endif
 
-open class PieChartRenderer: DataRenderer
+open class PieChartRenderer: NSObject, DataRenderer
 {
+    public let viewPortHandler: ViewPortHandler
+    
+    public final var accessibleChartElements: [NSUIAccessibilityElement] = []
+
+    public let animator: Animator
+
     @objc open weak var chart: PieChartView?
 
     @objc public init(chart: PieChartView, animator: Animator, viewPortHandler: ViewPortHandler)
     {
-        super.init(animator: animator, viewPortHandler: viewPortHandler)
-
+        self.viewPortHandler = viewPortHandler
+        self.animator = animator
         self.chart = chart
-    }
 
-    open override func drawData(context: CGContext)
+        super.init()
+    }
+    
+    open func drawData(context: CGContext)
     {
-        guard let chart = chart else { return }
+        guard let chart = chart, let pieData = chart.data else { return }
 
-        let pieData = chart.data
+        // If we redraw the data, remove and repopulate accessible elements to update label values and frames
+        accessibleChartElements.removeAll()
 
-        if pieData != nil
+        for case let set as PieChartDataSetProtocol in pieData where
+            set.isVisible && set.entryCount > 0
         {
-            // If we redraw the data, remove and repopulate accessible elements to update label values and frames
-            accessibleChartElements.removeAll()
-
-            for set in pieData!.dataSets as! [IPieChartDataSet]
-                where set.isVisible && set.entryCount > 0
-            {
-                drawDataSet(context: context, dataSet: set)
-            }
+            drawDataSet(context: context, dataSet: set)
         }
     }
 
@@ -92,7 +92,7 @@ open class PieChartRenderer: DataRenderer
     }
 
     /// Calculates the sliceSpace to use based on visible values and their size compared to the set sliceSpace.
-    @objc open func getSliceSpace(dataSet: IPieChartDataSet) -> CGFloat
+    @objc open func getSliceSpace(dataSet: PieChartDataSetProtocol) -> CGFloat
     {
         guard
             dataSet.automaticallyDisableSliceSpacing,
@@ -109,7 +109,7 @@ open class PieChartRenderer: DataRenderer
         return sliceSpace
     }
 
-    @objc open func drawDataSet(context: CGContext, dataSet: IPieChartDataSet)
+    @objc open func drawDataSet(context: CGContext, dataSet: PieChartDataSetProtocol)
     {
         guard let chart = chart else {return }
 
@@ -148,7 +148,7 @@ open class PieChartRenderer: DataRenderer
         // i.e. We want to VO to say "3 Elements" even if the developer didn't specify an accessibility prefix
         // If prefix is unspecified it is safe to assume they did not want to use "Element 1", so that uses a default empty string
         let prefix: String = chart.data?.accessibilityEntryLabelPrefix ?? "Element"
-        let description = chart.chartDescription?.text ?? dataSet.label ?? chart.centerText ??  "Pie Chart"
+        let description = chart.chartDescription.text ?? dataSet.label ?? chart.centerText ??  "Pie Chart"
 
         let
         element = NSUIAccessibilityElement(accessibilityContainer: chart)
@@ -293,8 +293,8 @@ open class PieChartRenderer: DataRenderer
 
         context.restoreGState()
     }
-
-    open override func drawValues(context: CGContext)
+    
+    open func drawValues(context: CGContext)
     {
         guard
             let chart = chart,
@@ -321,12 +321,11 @@ open class PieChartRenderer: DataRenderer
 
         let labelRadius = radius - labelRadiusOffset
 
-        let dataSets = data.dataSets
-
         let yValueSum = (data as! PieChartData).yValueSum
 
         let drawEntryLabels = chart.isDrawEntryLabelsEnabled
         let usePercentValuesEnabled = chart.usePercentValuesEnabled
+        let sliceTextDrawingThreshold = chart.sliceTextDrawingThreshold
 
         var angle: CGFloat = 0.0
         var xIndex = 0
@@ -334,10 +333,10 @@ open class PieChartRenderer: DataRenderer
         context.saveGState()
         defer { context.restoreGState() }
 
-        for i in 0 ..< dataSets.count
+        for i in data.indices
         {
-            guard let dataSet = dataSets[i] as? IPieChartDataSet else { continue }
-
+            guard let dataSet = data[i] as? PieChartDataSetProtocol else { continue }
+            
             let drawValues = dataSet.isDrawValuesEnabled
 
             if !drawValues && !drawEntryLabels && !dataSet.isDrawIconsEnabled
@@ -347,15 +346,17 @@ open class PieChartRenderer: DataRenderer
 
             let iconsOffset = dataSet.iconsOffset
 
+            let angleRadians = dataSet.valueLabelAngle.DEG2RAD
+
             let xValuePosition = dataSet.xValuePosition
             let yValuePosition = dataSet.yValuePosition
 
             let valueFont = dataSet.valueFont
-            let entryLabelFont = dataSet.entryLabelFont ?? chart.entryLabelFont
+            let entryLabelFont = dataSet.entryLabelFont
             let lineHeight = valueFont.lineHeight
-
-            guard let formatter = dataSet.valueFormatter else { continue }
-
+            
+            let formatter = dataSet.valueFormatter
+            
             for j in 0 ..< dataSet.entryCount
             {
                 guard let e = dataSet.entryForIndex(j) else { continue }
@@ -390,14 +391,14 @@ open class PieChartRenderer: DataRenderer
 
                 let sliceXBase = cos(transformedAngle.DEG2RAD)
                 let sliceYBase = sin(transformedAngle.DEG2RAD)
-
-                let drawXOutside = drawEntryLabels && xValuePosition == .outsideSlice
-                let drawYOutside = drawValues && yValuePosition == .outsideSlice
-                let drawXInside = drawEntryLabels && xValuePosition == .insideSlice
-                let drawYInside = drawValues && yValuePosition == .insideSlice
-
+                
+                let drawXOutside = sliceAngle > sliceTextDrawingThreshold && drawEntryLabels && xValuePosition == .outsideSlice
+                let drawYOutside = sliceAngle > sliceTextDrawingThreshold && drawValues && yValuePosition == .outsideSlice
+                let drawXInside = sliceAngle > sliceTextDrawingThreshold && drawEntryLabels && xValuePosition == .insideSlice
+                let drawYInside = sliceAngle > sliceTextDrawingThreshold && drawValues && yValuePosition == .insideSlice
+                
                 let valueTextColor = dataSet.valueTextColorAt(j)
-                let entryLabelColor = dataSet.entryLabelColor ?? chart.entryLabelColor
+                let entryLabelColor = dataSet.entryLabelColor
 
                 if drawXOutside || drawYOutside
                 {
@@ -407,7 +408,7 @@ open class PieChartRenderer: DataRenderer
 
                     var pt2: CGPoint
                     var labelPoint: CGPoint
-                    var align: NSTextAlignment
+                    var align: TextAlignment
 
                     var line1Radius: CGFloat
 
@@ -470,51 +471,46 @@ open class PieChartRenderer: DataRenderer
                     
                     if drawXOutside && drawYOutside
                     {
-                        ChartUtils.drawText(
-                            context: context,
-                            text: valueText,
-                            point: labelPoint,
-                            align: align,
-                            attributes: [NSAttributedString.Key.font: valueFont, NSAttributedString.Key.foregroundColor: valueTextColor]
-                        )
-
+                        context.drawText(valueText,
+                                         at: labelPoint,
+                                         align: align,
+                                         angleRadians: angleRadians,
+                                         attributes: [.font: valueFont,
+                                                      .foregroundColor: valueTextColor])
+                        
                         if j < data.entryCount && pe?.label != nil
                         {
-                            ChartUtils.drawText(
-                                context: context,
-                                text: pe!.label!,
-                                point: CGPoint(x: labelPoint.x, y: labelPoint.y + lineHeight),
-                                align: align,
-                                attributes: [
-                                    NSAttributedString.Key.font: entryLabelFont ?? valueFont,
-                                    NSAttributedString.Key.foregroundColor: entryLabelColor ?? valueTextColor]
-                            )
+                            context.drawText(pe!.label!,
+                                             at: CGPoint(x: labelPoint.x,
+                                                         y: labelPoint.y + lineHeight),
+                                             align: align,
+                                             angleRadians: angleRadians,
+                                             attributes: [.font: entryLabelFont ?? valueFont,
+                                                          .foregroundColor: entryLabelColor ?? valueTextColor])
                         }
                     }
                     else if drawXOutside
                     {
                         if j < data.entryCount && pe?.label != nil
                         {
-                            ChartUtils.drawText(
-                                context: context,
-                                text: pe!.label!,
-                                point: CGPoint(x: labelPoint.x, y: labelPoint.y + lineHeight / 2.0),
-                                align: align,
-                                attributes: [
-                                    NSAttributedString.Key.font: entryLabelFont ?? valueFont,
-                                    NSAttributedString.Key.foregroundColor: entryLabelColor ?? valueTextColor]
-                            )
+                            context.drawText(pe!.label!,
+                                             at: CGPoint(x: labelPoint.x,
+                                                         y: labelPoint.y + lineHeight / 2.0),
+                                             align: align,
+                                             angleRadians: angleRadians,
+                                             attributes: [.font: entryLabelFont ?? valueFont,
+                                                          .foregroundColor: entryLabelColor ?? valueTextColor])
                         }
                     }
                     else if drawYOutside
                     {
-                        ChartUtils.drawText(
-                            context: context,
-                            text: valueText,
-                            point: CGPoint(x: labelPoint.x, y: labelPoint.y + lineHeight / 2.0),
-                            align: align,
-                            attributes: [NSAttributedString.Key.font: valueFont, NSAttributedString.Key.foregroundColor: valueTextColor]
-                        )
+                        context.drawText(valueText,
+                                         at: CGPoint(x: labelPoint.x,
+                                                     y: labelPoint.y + lineHeight / 2.0),
+                                         align: align,
+                                         angleRadians: angleRadians,
+                                         attributes: [.font: valueFont,
+                                                      .foregroundColor: valueTextColor])
                     }
                 }
 
@@ -526,51 +522,41 @@ open class PieChartRenderer: DataRenderer
 
                     if drawXInside && drawYInside
                     {
-                        ChartUtils.drawText(
-                            context: context,
-                            text: valueText,
-                            point: CGPoint(x: x, y: y),
-                            align: .center,
-                            attributes: [NSAttributedString.Key.font: valueFont, NSAttributedString.Key.foregroundColor: valueTextColor]
-                        )
-
+                        context.drawText(valueText,
+                                         at: CGPoint(x: x, y: y),
+                                         align: .center,
+                                         angleRadians: angleRadians,
+                                         attributes: [.font: valueFont, .foregroundColor: valueTextColor])
+                        
                         if j < data.entryCount && pe?.label != nil
                         {
-                            ChartUtils.drawText(
-                                context: context,
-                                text: pe!.label!,
-                                point: CGPoint(x: x, y: y + lineHeight),
-                                align: .center,
-                                attributes: [
-                                    NSAttributedString.Key.font: entryLabelFont ?? valueFont,
-                                    NSAttributedString.Key.foregroundColor: entryLabelColor ?? valueTextColor]
-                            )
+                            context.drawText(pe!.label!,
+                                             at: CGPoint(x: x, y: y + lineHeight),
+                                             align: .center,
+                                             angleRadians: angleRadians,
+                                             attributes: [.font: entryLabelFont ?? valueFont,
+                                                          .foregroundColor: entryLabelColor ?? valueTextColor])
                         }
                     }
                     else if drawXInside
                     {
                         if j < data.entryCount && pe?.label != nil
                         {
-                            ChartUtils.drawText(
-                                context: context,
-                                text: pe!.label!,
-                                point: CGPoint(x: x, y: y + lineHeight / 2.0),
-                                align: .center,
-                                attributes: [
-                                    NSAttributedString.Key.font: entryLabelFont ?? valueFont,
-                                    NSAttributedString.Key.foregroundColor: entryLabelColor ?? valueTextColor]
-                            )
+                            context.drawText(pe!.label!,
+                                             at: CGPoint(x: x, y: y + lineHeight / 2.0),
+                                             align: .center,
+                                             angleRadians: angleRadians,
+                                             attributes: [.font: entryLabelFont ?? valueFont,
+                                                          .foregroundColor: entryLabelColor ?? valueTextColor])
                         }
                     }
                     else if drawYInside
                     {
-                        ChartUtils.drawText(
-                            context: context,
-                            text: valueText,
-                            point: CGPoint(x: x, y: y + lineHeight / 2.0),
-                            align: .center,
-                            attributes: [NSAttributedString.Key.font: valueFont, NSAttributedString.Key.foregroundColor: valueTextColor]
-                        )
+                        context.drawText(valueText,
+                                         at: CGPoint(x: x, y: y + lineHeight / 2.0),
+                                         align: .center,
+                                         angleRadians: angleRadians,
+                                         attributes: [.font: valueFont, .foregroundColor: valueTextColor])
                     }
                 }
 
@@ -581,25 +567,31 @@ open class PieChartRenderer: DataRenderer
                     let x = (labelRadius + iconsOffset.y) * sliceXBase + center.x
                     var y = (labelRadius + iconsOffset.y) * sliceYBase + center.y
                     y += iconsOffset.x
-
-                    ChartUtils.drawImage(context: context,
-                                         image: icon,
-                                         x: x,
-                                         y: y,
-                                         size: icon.size)
+                    
+                    context.drawImage(icon,
+                                      atCenter: CGPoint(x: x, y: y),
+                                      size: icon.size)
                 }
 
                 xIndex += 1
             }
         }
     }
-
-    open override func drawExtras(context: CGContext)
+    
+    open func drawExtras(context: CGContext)
     {
         drawHole(context: context)
         drawCenterText(context: context)
     }
 
+    open func initBuffers() { }
+
+    open func isDrawingValuesAllowed(dataProvider: ChartDataProvider?) -> Bool
+    {
+        guard let data = dataProvider?.data else { return false }
+        return data.entryCount < Int(CGFloat(dataProvider?.maxVisibleCount ?? 0) * viewPortHandler.scaleX)
+    }
+
     /// draws the hole in the center of the chart and the transparent circle / hole
     private func drawHole(context: CGContext)
     {
@@ -704,8 +696,8 @@ open class PieChartRenderer: DataRenderer
             context.restoreGState()
         }
     }
-
-    open override func drawHighlighted(context: CGContext, indices: [Highlight])
+    
+    open func drawHighlighted(context: CGContext, indices highlights: [Highlight])
     {
         guard
             let chart = chart,
@@ -730,19 +722,18 @@ open class PieChartRenderer: DataRenderer
         // Append highlighted accessibility slices into this array, so we can prioritize them over unselected slices
         var highlightedAccessibleElements: [NSUIAccessibilityElement] = []
 
-        for i in 0 ..< indices.count
+        for hightlight in highlights
         {
             // get the index to highlight
-            let index = Int(indices[i].x)
-            if index >= drawAngles.count
+            let index = Int(hightlight.x)
+            guard index < drawAngles.count,
+                  let set = data[hightlight.dataSetIndex] as? PieChartDataSetProtocol,
+                  set.isHighlightEnabled
+            else
             {
                 continue
             }
 
-            guard let set = data.getDataSetByIndex(indices[i].dataSetIndex) as? IPieChartDataSet else { continue }
-            
-            if !set.isHighlightEnabled { continue }
-
             let entryCount = set.entryCount
             var visibleAngleCount = 0
             for j in 0 ..< entryCount
@@ -901,15 +892,16 @@ open class PieChartRenderer: DataRenderer
     /// The element only has it's container and label set based on the chart and dataSet. Use the modifier to alter traits and frame.
     private func createAccessibleElement(withIndex idx: Int,
                                          container: PieChartView,
-                                         dataSet: IPieChartDataSet,
+                                         dataSet: PieChartDataSetProtocol,
                                          modifier: (NSUIAccessibilityElement) -> ()) -> NSUIAccessibilityElement {
 
         let element = NSUIAccessibilityElement(accessibilityContainer: container)
 
         guard let e = dataSet.entryForIndex(idx) else { return element }
-        guard let formatter = dataSet.valueFormatter else { return element }
         guard let data = container.data as? PieChartData else { return element }
 
+        let formatter = dataSet.valueFormatter
+        
         var elementValueText = formatter.stringForValue(
             e.y,
             entry: e,
@@ -938,4 +930,8 @@ open class PieChartRenderer: DataRenderer
 
         return element
     }
+    
+    public func createAccessibleHeader(usingChart chart: ChartViewBase, andData data: ChartData, withDefaultDescription defaultDescription: String) -> NSUIAccessibilityElement {
+        return AccessibleHeader.create(usingChart: chart, andData: data, withDefaultDescription: defaultDescription)
+    }
 }

+ 36 - 42
Pods/Charts/Source/Charts/Renderers/RadarChartRenderer.swift

@@ -35,29 +35,26 @@ open class RadarChartRenderer: LineRadarRenderer
     
     open override func drawData(context: CGContext)
     {
-        guard let chart = chart else { return }
-        
-        let radarData = chart.data
-        
-        if radarData != nil
+        guard let chart = chart,
+              let radarData = chart.data as? RadarChartData else
         {
-            let mostEntries = radarData?.maxEntryCountSet?.entryCount ?? 0
+            return
+        }
+        
+        let mostEntries = radarData.maxEntryCountSet?.entryCount ?? 0
 
-            // If we redraw the data, remove and repopulate accessible elements to update label values and frames
-            self.accessibleChartElements.removeAll()
+        // If we redraw the data, remove and repopulate accessible elements to update label values and frames
+        self.accessibleChartElements.removeAll()
 
-            // Make the chart header the first element in the accessible elements array
-            if let accessibilityHeaderData = radarData as? RadarChartData {
-                let element = createAccessibleHeader(usingChart: chart,
-                                                     andData: accessibilityHeaderData,
-                                                     withDefaultDescription: "Radar Chart")
-                self.accessibleChartElements.append(element)
-            }
+        // Make the chart header the first element in the accessible elements array
+        let element = createAccessibleHeader(usingChart: chart,
+                                             andData: radarData,
+                                             withDefaultDescription: "Radar Chart")
+        self.accessibleChartElements.append(element)
 
-            for set in radarData!.dataSets as! [IRadarChartDataSet] where set.isVisible
-            {
-                drawDataSet(context: context, dataSet: set, mostEntries: mostEntries)
-            }
+        for case let set as RadarChartDataSetProtocol in (radarData as ChartData) where set.isVisible
+        {
+            drawDataSet(context: context, dataSet: set, mostEntries: mostEntries)
         }
     }
     
@@ -67,7 +64,7 @@ open class RadarChartRenderer: LineRadarRenderer
     ///   - context:
     ///   - dataSet:
     ///   - mostEntries: the entry count of the dataset with the most entries
-    internal func drawDataSet(context: CGContext, dataSet: IRadarChartDataSet, mostEntries: Int)
+    internal func drawDataSet(context: CGContext, dataSet: RadarChartDataSetProtocol, mostEntries: Int)
     {
         guard let chart = chart else { return }
         
@@ -211,13 +208,15 @@ open class RadarChartRenderer: LineRadarRenderer
         
         let yoffset = CGFloat(5.0)
         
-        for i in 0 ..< data.dataSetCount
+        for i in data.indices
         {
             guard let
-                dataSet = data.getDataSetByIndex(i) as? IRadarChartDataSet,
+                dataSet = data[i] as? RadarChartDataSetProtocol,
                 shouldDrawValues(forDataSet: dataSet)
                 else { continue }
             
+            let angleRadians = dataSet.valueLabelAngle.DEG2RAD
+            
             let entryCount = dataSet.entryCount
             
             let iconsOffset = dataSet.iconsOffset
@@ -231,22 +230,19 @@ open class RadarChartRenderer: LineRadarRenderer
                 
                 let valueFont = dataSet.valueFont
                 
-                guard let formatter = dataSet.valueFormatter else { continue }
+                let formatter = dataSet.valueFormatter
                 
                 if dataSet.isDrawValuesEnabled
                 {
-                    ChartUtils.drawText(
-                        context: context,
-                        text: formatter.stringForValue(
-                            e.y,
-                            entry: e,
-                            dataSetIndex: i,
-                            viewPortHandler: viewPortHandler),
-                        point: CGPoint(x: p.x, y: p.y - yoffset - valueFont.lineHeight),
-                        align: .center,
-                        attributes: [NSAttributedString.Key.font: valueFont,
-                            NSAttributedString.Key.foregroundColor: dataSet.valueTextColorAt(j)]
-                    )
+                    context.drawText(formatter.stringForValue(e.y,
+                                                              entry: e,
+                                                              dataSetIndex: i,
+                                                              viewPortHandler: viewPortHandler),
+                                     at: CGPoint(x: p.x, y: p.y - yoffset - valueFont.lineHeight),
+                                     align: .center,
+                                     angleRadians: angleRadians,
+                                     attributes: [.font: valueFont,
+                                                  .foregroundColor: dataSet.valueTextColorAt(j)])
                 }
                 
                 if let icon = e.icon, dataSet.isDrawIconsEnabled
@@ -255,11 +251,9 @@ open class RadarChartRenderer: LineRadarRenderer
                                               atAngle: sliceangle * CGFloat(j) * CGFloat(phaseX) + chart.rotationAngle)
                     pIcon.y += iconsOffset.x
                     
-                    ChartUtils.drawImage(context: context,
-                                         image: icon,
-                                         x: pIcon.x,
-                                         y: pIcon.y,
-                                         size: icon.size)
+                    context.drawImage(icon,
+                                      atCenter: CGPoint(x: pIcon.x, y: pIcon.y),
+                                      size: icon.size)
                 }
             }
         }
@@ -360,7 +354,7 @@ open class RadarChartRenderer: LineRadarRenderer
         for high in indices
         {
             guard
-                let set = chart.data?.getDataSetByIndex(high.dataSetIndex) as? IRadarChartDataSet,
+                let set = chart.data?[high.dataSetIndex] as? RadarChartDataSetProtocol,
                 set.isHighlightEnabled
                 else { continue }
             
@@ -461,7 +455,7 @@ open class RadarChartRenderer: LineRadarRenderer
 
     private func createAccessibleElement(withDescription description: String,
                                          container: RadarChartView,
-                                         dataSet: IRadarChartDataSet,
+                                         dataSet: RadarChartDataSetProtocol,
                                          modifier: (NSUIAccessibilityElement) -> ()) -> NSUIAccessibilityElement {
 
         let element = NSUIAccessibilityElement(accessibilityContainer: container)

+ 3 - 9
Pods/Charts/Source/Charts/Renderers/Renderer.swift

@@ -13,14 +13,8 @@ import Foundation
 import CoreGraphics
 
 @objc(ChartRenderer)
-open class Renderer: NSObject
-{
-    /// the component that handles the drawing area of the chart and it's offsets
-    @objc public let viewPortHandler: ViewPortHandler
+public protocol Renderer {
 
-    @objc public init(viewPortHandler: ViewPortHandler)
-    {
-        self.viewPortHandler = viewPortHandler
-        super.init()
-    }
+    /// the component that handles the drawing area of the chart and it's offsets
+    var viewPortHandler: ViewPortHandler { get }
 }

+ 2 - 2
Pods/Charts/Source/Charts/Renderers/Scatter/ChevronDownShapeRenderer.swift

@@ -11,11 +11,11 @@
 import Foundation
 import CoreGraphics
 
-open class ChevronDownShapeRenderer : NSObject, IShapeRenderer
+open class ChevronDownShapeRenderer : NSObject, ShapeRenderer
 {
     open func renderShape(
         context: CGContext,
-                dataSet: IScatterChartDataSet,
+                dataSet: ScatterChartDataSetProtocol,
                 viewPortHandler: ViewPortHandler,
                 point: CGPoint,
                 color: NSUIColor)

+ 2 - 2
Pods/Charts/Source/Charts/Renderers/Scatter/ChevronUpShapeRenderer.swift

@@ -11,11 +11,11 @@
 import Foundation
 import CoreGraphics
 
-open class ChevronUpShapeRenderer : NSObject, IShapeRenderer
+open class ChevronUpShapeRenderer : NSObject, ShapeRenderer
 {
     open func renderShape(
         context: CGContext,
-                dataSet: IScatterChartDataSet,
+                dataSet: ScatterChartDataSetProtocol,
                 viewPortHandler: ViewPortHandler,
                 point: CGPoint,
                 color: NSUIColor)

+ 2 - 2
Pods/Charts/Source/Charts/Renderers/Scatter/CircleShapeRenderer.swift

@@ -11,11 +11,11 @@
 import Foundation
 import CoreGraphics
 
-open class CircleShapeRenderer : NSObject, IShapeRenderer
+open class CircleShapeRenderer : NSObject, ShapeRenderer
 {
     open func renderShape(
         context: CGContext,
-        dataSet: IScatterChartDataSet,
+        dataSet: ScatterChartDataSetProtocol,
         viewPortHandler: ViewPortHandler,
         point: CGPoint,
         color: NSUIColor)

+ 2 - 2
Pods/Charts/Source/Charts/Renderers/Scatter/CrossShapeRenderer.swift

@@ -11,11 +11,11 @@
 import Foundation
 import CoreGraphics
 
-open class CrossShapeRenderer : NSObject, IShapeRenderer
+open class CrossShapeRenderer : NSObject, ShapeRenderer
 {
     open func renderShape(
         context: CGContext,
-        dataSet: IScatterChartDataSet,
+        dataSet: ScatterChartDataSetProtocol,
         viewPortHandler: ViewPortHandler,
         point: CGPoint,
         color: NSUIColor)

+ 2 - 2
Pods/Charts/Source/Charts/Renderers/Scatter/SquareShapeRenderer.swift

@@ -11,11 +11,11 @@
 import Foundation
 import CoreGraphics
 
-open class SquareShapeRenderer : NSObject, IShapeRenderer
+open class SquareShapeRenderer : NSObject, ShapeRenderer
 {
     open func renderShape(
         context: CGContext,
-        dataSet: IScatterChartDataSet,
+        dataSet: ScatterChartDataSetProtocol,
         viewPortHandler: ViewPortHandler,
         point: CGPoint,
         color: NSUIColor)

+ 2 - 2
Pods/Charts/Source/Charts/Renderers/Scatter/TriangleShapeRenderer.swift

@@ -11,11 +11,11 @@
 import Foundation
 import CoreGraphics
 
-open class TriangleShapeRenderer : NSObject, IShapeRenderer
+open class TriangleShapeRenderer : NSObject, ShapeRenderer
 {
     open func renderShape(
         context: CGContext,
-        dataSet: IScatterChartDataSet,
+        dataSet: ScatterChartDataSetProtocol,
         viewPortHandler: ViewPortHandler,
         point: CGPoint,
         color: NSUIColor)

+ 2 - 2
Pods/Charts/Source/Charts/Renderers/Scatter/XShapeRenderer.swift

@@ -11,11 +11,11 @@
 import Foundation
 import CoreGraphics
 
-open class XShapeRenderer : NSObject, IShapeRenderer
+open class XShapeRenderer : NSObject, ShapeRenderer
 {
     open func renderShape(
         context: CGContext,
-        dataSet: IScatterChartDataSet,
+        dataSet: ScatterChartDataSetProtocol,
         viewPortHandler: ViewPortHandler,
         point: CGPoint,
         color: NSUIColor)

+ 29 - 38
Pods/Charts/Source/Charts/Renderers/ScatterChartRenderer.swift

@@ -41,25 +41,18 @@ open class ScatterChartRenderer: LineScatterCandleRadarRenderer
         // TODO: Due to the potential complexity of data presented in Scatter charts, a more usable way
         // for VO accessibility would be to use axis based traversal rather than by dataset.
         // Hence, accessibleChartElements is not populated below. (Individual renderers guard against dataSource being their respective views)
-        for i in 0 ..< scatterData.dataSetCount
-        {
-            guard let set = scatterData.getDataSetByIndex(i) else { continue }
-            
-            if set.isVisible
-            {
-                if !(set is IScatterChartDataSet)
-                {
-                    fatalError("Datasets for ScatterChartRenderer must conform to IScatterChartDataSet")
-                }
-                
-                drawDataSet(context: context, dataSet: set as! IScatterChartDataSet)
-            }
-        }
+        let sets = scatterData.dataSets as? [ScatterChartDataSet]
+        assert(sets != nil, "Datasets for ScatterChartRenderer must conform to IScatterChartDataSet")
+        
+        let drawDataSet = { self.drawDataSet(context: context, dataSet: $0) }
+        sets!.lazy
+            .filter(\.isVisible)
+            .forEach(drawDataSet)
     }
     
     private var _lineSegments = [CGPoint](repeating: CGPoint(), count: 2)
     
-    @objc open func drawDataSet(context: CGContext, dataSet: IScatterChartDataSet)
+    @objc open func drawDataSet(context: CGContext, dataSet: ScatterChartDataSetProtocol)
     {
         guard let dataProvider = dataProvider else { return }
         
@@ -103,7 +96,7 @@ open class ScatterChartRenderer: LineScatterCandleRadarRenderer
         }
         else
         {
-            print("There's no IShapeRenderer specified for ScatterDataSet", terminator: "\n")
+            print("There's no ShapeRenderer specified for ScatterDataSet", terminator: "\n")
         }
     }
     
@@ -116,28 +109,28 @@ open class ScatterChartRenderer: LineScatterCandleRadarRenderer
         
         // if values are drawn
         if isDrawingValuesAllowed(dataProvider: dataProvider)
-        {
-            guard let dataSets = scatterData.dataSets as? [IScatterChartDataSet] else { return }
-            
+        {            
             let phaseY = animator.phaseY
             
             var pt = CGPoint()
             
-            for i in 0 ..< scatterData.dataSetCount
+            for i in scatterData.indices
             {
-                let dataSet = dataSets[i]
-                guard let
-                    formatter = dataSet.valueFormatter,
-                    shouldDrawValues(forDataSet: dataSet)
+                guard let dataSet = scatterData[i] as? ScatterChartDataSetProtocol,
+                      shouldDrawValues(forDataSet: dataSet)
                     else { continue }
                 
                 let valueFont = dataSet.valueFont
                 
+                let formatter = dataSet.valueFormatter
+                
                 let trans = dataProvider.getTransformer(forAxis: dataSet.axisDependency)
                 let valueToPixelMatrix = trans.valueToPixelMatrix
                 
                 let iconsOffset = dataSet.iconsOffset
                 
+                let angleRadians = dataSet.valueLabelAngle.DEG2RAD
+                
                 let shapeSize = dataSet.scatterShapeSize
                 let lineHeight = valueFont.lineHeight
                 
@@ -171,24 +164,22 @@ open class ScatterChartRenderer: LineScatterCandleRadarRenderer
                     
                     if dataSet.isDrawValuesEnabled
                     {
-                        ChartUtils.drawText(
-                            context: context,
-                            text: text,
-                            point: CGPoint(
-                                x: pt.x,
-                                y: pt.y - shapeSize - lineHeight),
-                            align: .center,
-                            attributes: [NSAttributedString.Key.font: valueFont, NSAttributedString.Key.foregroundColor: dataSet.valueTextColorAt(j)]
+                        context.drawText(text,
+                                         at: CGPoint(x: pt.x,
+                                                     y: pt.y - shapeSize - lineHeight),
+                                         align: .center,
+                                         angleRadians: angleRadians,
+                                         attributes: [.font: valueFont,
+                                                      .foregroundColor: dataSet.valueTextColorAt(j)]
                         )
                     }
                     
                     if let icon = e.icon, dataSet.isDrawIconsEnabled
                     {
-                        ChartUtils.drawImage(context: context,
-                                             image: icon,
-                                             x: pt.x + iconsOffset.x,
-                                             y: pt.y + iconsOffset.y,
-                                             size: icon.size)
+                        context.drawImage(icon,
+                                          atCenter: CGPoint(x: pt.x + iconsOffset.x,
+                                                          y: pt.y + iconsOffset.y),
+                                          size: icon.size)
                     }
                 }
             }
@@ -212,7 +203,7 @@ open class ScatterChartRenderer: LineScatterCandleRadarRenderer
         for high in indices
         {
             guard
-                let set = scatterData.getDataSetByIndex(high.dataSetIndex) as? IScatterChartDataSet,
+                let set = scatterData[high.dataSetIndex] as? ScatterChartDataSetProtocol,
                 set.isHighlightEnabled
                 else { continue }
             

+ 276 - 236
Pods/Charts/Source/Charts/Renderers/XAxisRenderer.swift

@@ -12,244 +12,303 @@
 import Foundation
 import CoreGraphics
 
-#if canImport(UIKit)
-    import UIKit
-#endif
-
-#if canImport(Cocoa)
-import Cocoa
-#endif
 
 @objc(ChartXAxisRenderer)
-open class XAxisRenderer: AxisRendererBase
+open class XAxisRenderer: NSObject, AxisRenderer
 {
-    @objc public init(viewPortHandler: ViewPortHandler, xAxis: XAxis?, transformer: Transformer?)
+    @objc public let viewPortHandler: ViewPortHandler
+    @objc public let axis: XAxis
+    @objc public let transformer: Transformer?
+
+    @objc public init(viewPortHandler: ViewPortHandler, axis: XAxis, transformer: Transformer?)
     {
-        super.init(viewPortHandler: viewPortHandler, transformer: transformer, axis: xAxis)
+        self.viewPortHandler = viewPortHandler
+        self.axis = axis
+        self.transformer = transformer
+
+        super.init()
     }
     
-    open override func computeAxis(min: Double, max: Double, inverted: Bool)
+    open func computeAxis(min: Double, max: Double, inverted: Bool)
     {
         var min = min, max = max
         
-        if let transformer = self.transformer
+        if let transformer = self.transformer,
+            viewPortHandler.contentWidth > 10,
+            !viewPortHandler.isFullyZoomedOutX
         {
             // calculate the starting and entry point of the y-labels (depending on
             // zoom / contentrect bounds)
-            if viewPortHandler.contentWidth > 10 && !viewPortHandler.isFullyZoomedOutX
-            {
-                let p1 = transformer.valueForTouchPoint(CGPoint(x: viewPortHandler.contentLeft, y: viewPortHandler.contentTop))
-                let p2 = transformer.valueForTouchPoint(CGPoint(x: viewPortHandler.contentRight, y: viewPortHandler.contentTop))
-                
-                if inverted
-                {
-                    min = Double(p2.x)
-                    max = Double(p1.x)
-                }
-                else
-                {
-                    min = Double(p1.x)
-                    max = Double(p2.x)
-                }
-            }
+            let p1 = transformer.valueForTouchPoint(CGPoint(x: viewPortHandler.contentLeft, y: viewPortHandler.contentTop))
+            let p2 = transformer.valueForTouchPoint(CGPoint(x: viewPortHandler.contentRight, y: viewPortHandler.contentTop))
+
+            min = inverted ? Double(p2.x) : Double(p1.x)
+            max = inverted ? Double(p1.x) : Double(p2.x)
         }
         
         computeAxisValues(min: min, max: max)
     }
     
-    open override func computeAxisValues(min: Double, max: Double)
+    open func computeAxisValues(min: Double, max: Double)
     {
-        super.computeAxisValues(min: min, max: max)
+        let yMin = min
+        let yMax = max
+
+        let labelCount = axis.labelCount
+        let range = abs(yMax - yMin)
+
+        guard
+            labelCount != 0,
+            range > 0,
+            range.isFinite
+            else
+        {
+            axis.entries = []
+            axis.centeredEntries = []
+            return
+        }
+
+        // Find out how much spacing (in y value space) between axis values
+        let rawInterval = range / Double(labelCount)
+        var interval = rawInterval.roundedToNextSignificant()
+
+        // If granularity is enabled, then do not allow the interval to go below specified granularity.
+        // This is used to avoid repeated values when rounding values for display.
+        if axis.granularityEnabled
+        {
+            interval = Swift.max(interval, axis.granularity)
+        }
+
+        // Normalize interval
+        let intervalMagnitude = pow(10.0, Double(Int(log10(interval)))).roundedToNextSignificant()
+        let intervalSigDigit = Int(interval / intervalMagnitude)
+        if intervalSigDigit > 5
+        {
+            // Use one order of magnitude higher, to avoid intervals like 0.9 or 90
+            interval = floor(10.0 * Double(intervalMagnitude))
+        }
+
+        var n = axis.centerAxisLabelsEnabled ? 1 : 0
+
+        // force label count
+        if axis.isForceLabelsEnabled
+        {
+            interval = range / Double(labelCount - 1)
+
+            // Ensure stops contains at least n elements.
+            axis.entries.removeAll(keepingCapacity: true)
+            axis.entries.reserveCapacity(labelCount)
+
+            let values = stride(from: yMin, to: Double(labelCount) * interval + yMin, by: interval)
+            axis.entries.append(contentsOf: values)
+
+            n = labelCount
+        }
+        else
+        {
+            // no forced count
+
+            var first = interval == 0.0 ? 0.0 : ceil(yMin / interval) * interval
+
+            if axis.centerAxisLabelsEnabled
+            {
+                first -= interval
+            }
+
+            let last = interval == 0.0 ? 0.0 : (floor(yMax / interval) * interval).nextUp
+
+            if interval != 0.0, last != first
+            {
+                stride(from: first, through: last, by: interval).forEach { _ in n += 1 }
+            }
+
+            // Ensure stops contains at least n elements.
+            axis.entries.removeAll(keepingCapacity: true)
+            axis.entries.reserveCapacity(labelCount)
+
+            let start = first, end = first + Double(n) * interval
+
+            // Fix for IEEE negative zero case (Where value == -0.0, and 0.0 == -0.0)
+            let values = stride(from: start, to: end, by: interval).map { $0 == 0.0 ? 0.0 : $0 }
+            axis.entries.append(contentsOf: values)
+        }
+
+        // set decimals
+        if interval < 1
+        {
+            axis.decimals = Int(ceil(-log10(interval)))
+        }
+        else
+        {
+            axis.decimals = 0
+        }
+
+        if axis.centerAxisLabelsEnabled
+        {
+            let offset: Double = interval / 2.0
+            axis.centeredEntries = axis.entries[..<n]
+                .map { $0 + offset }
+        }
         
         computeSize()
     }
     
     @objc open func computeSize()
     {
-        guard let
-            xAxis = self.axis as? XAxis
-            else { return }
-        
-        let longest = xAxis.getLongestLabel()
-        
-        let labelSize = longest.size(withAttributes: [NSAttributedString.Key.font: xAxis.labelFont])
+        let longest = axis.getLongestLabel()
         
+        let labelSize = longest.size(withAttributes: [.font: axis.labelFont])
+
         let labelWidth = labelSize.width
         let labelHeight = labelSize.height
         
-        let labelRotatedSize = labelSize.rotatedBy(degrees: xAxis.labelRotationAngle)
+        let labelRotatedSize = labelSize.rotatedBy(degrees: axis.labelRotationAngle)
         
-        xAxis.labelWidth = labelWidth
-        xAxis.labelHeight = labelHeight
-        xAxis.labelRotatedWidth = labelRotatedSize.width
-        xAxis.labelRotatedHeight = labelRotatedSize.height
+        axis.labelWidth = labelWidth
+        axis.labelHeight = labelHeight
+        axis.labelRotatedWidth = labelRotatedSize.width
+        axis.labelRotatedHeight = labelRotatedSize.height
     }
     
-    open override func renderAxisLabels(context: CGContext)
+    open func renderAxisLabels(context: CGContext)
     {
-        guard let xAxis = self.axis as? XAxis else { return }
-        
-        if !xAxis.isEnabled || !xAxis.isDrawLabelsEnabled
-        {
-            return
-        }
-        
-        let yOffset = xAxis.yOffset
+        guard
+            axis.isEnabled,
+            axis.isDrawLabelsEnabled
+            else { return }
+
+        let yOffset = axis.yOffset
         
-        if xAxis.labelPosition == .top
-        {
+        switch axis.labelPosition {
+        case .top:
             drawLabels(context: context, pos: viewPortHandler.contentTop - yOffset, anchor: CGPoint(x: 0.5, y: 1.0))
-        }
-        else if xAxis.labelPosition == .topInside
-        {
-            drawLabels(context: context, pos: viewPortHandler.contentTop + yOffset + xAxis.labelRotatedHeight, anchor: CGPoint(x: 0.5, y: 1.0))
-        }
-        else if xAxis.labelPosition == .bottom
-        {
+
+        case .topInside:
+            drawLabels(context: context, pos: viewPortHandler.contentTop + yOffset + axis.labelRotatedHeight, anchor: CGPoint(x: 0.5, y: 1.0))
+
+        case .bottom:
             drawLabels(context: context, pos: viewPortHandler.contentBottom + yOffset, anchor: CGPoint(x: 0.5, y: 0.0))
-        }
-        else if xAxis.labelPosition == .bottomInside
-        {
-            drawLabels(context: context, pos: viewPortHandler.contentBottom - yOffset - xAxis.labelRotatedHeight, anchor: CGPoint(x: 0.5, y: 0.0))
-        }
-        else
-        { // BOTH SIDED
+
+        case .bottomInside:
+            drawLabels(context: context, pos: viewPortHandler.contentBottom - yOffset - axis.labelRotatedHeight, anchor: CGPoint(x: 0.5, y: 0.0))
+
+        case .bothSided:
             drawLabels(context: context, pos: viewPortHandler.contentTop - yOffset, anchor: CGPoint(x: 0.5, y: 1.0))
             drawLabels(context: context, pos: viewPortHandler.contentBottom + yOffset, anchor: CGPoint(x: 0.5, y: 0.0))
         }
     }
     
-    private var _axisLineSegmentsBuffer = [CGPoint](repeating: CGPoint(), count: 2)
+    private var axisLineSegmentsBuffer = [CGPoint](repeating: .zero, count: 2)
     
-    open override func renderAxisLine(context: CGContext)
+    open func renderAxisLine(context: CGContext)
     {
-        guard let xAxis = self.axis as? XAxis else { return }
-        
-        if !xAxis.isEnabled || !xAxis.isDrawAxisLineEnabled
-        {
-            return
-        }
-        
+        guard
+            axis.isEnabled,
+            axis.isDrawAxisLineEnabled
+            else { return }
+
         context.saveGState()
+        defer { context.restoreGState() }
         
-        context.setStrokeColor(xAxis.axisLineColor.cgColor)
-        context.setLineWidth(xAxis.axisLineWidth)
-        if xAxis.axisLineDashLengths != nil
+        context.setStrokeColor(axis.axisLineColor.cgColor)
+        context.setLineWidth(axis.axisLineWidth)
+        if axis.axisLineDashLengths != nil
         {
-            context.setLineDash(phase: xAxis.axisLineDashPhase, lengths: xAxis.axisLineDashLengths)
+            context.setLineDash(phase: axis.axisLineDashPhase, lengths: axis.axisLineDashLengths)
         }
         else
         {
             context.setLineDash(phase: 0.0, lengths: [])
         }
         
-        if xAxis.labelPosition == .top
-            || xAxis.labelPosition == .topInside
-            || xAxis.labelPosition == .bothSided
+        if axis.labelPosition == .top
+            || axis.labelPosition == .topInside
+            || axis.labelPosition == .bothSided
         {
-            _axisLineSegmentsBuffer[0].x = viewPortHandler.contentLeft
-            _axisLineSegmentsBuffer[0].y = viewPortHandler.contentTop
-            _axisLineSegmentsBuffer[1].x = viewPortHandler.contentRight
-            _axisLineSegmentsBuffer[1].y = viewPortHandler.contentTop
-            context.strokeLineSegments(between: _axisLineSegmentsBuffer)
+            axisLineSegmentsBuffer[0].x = viewPortHandler.contentLeft
+            axisLineSegmentsBuffer[0].y = viewPortHandler.contentTop
+            axisLineSegmentsBuffer[1].x = viewPortHandler.contentRight
+            axisLineSegmentsBuffer[1].y = viewPortHandler.contentTop
+            context.strokeLineSegments(between: axisLineSegmentsBuffer)
         }
         
-        if xAxis.labelPosition == .bottom
-            || xAxis.labelPosition == .bottomInside
-            || xAxis.labelPosition == .bothSided
+        if axis.labelPosition == .bottom
+            || axis.labelPosition == .bottomInside
+            || axis.labelPosition == .bothSided
         {
-            _axisLineSegmentsBuffer[0].x = viewPortHandler.contentLeft
-            _axisLineSegmentsBuffer[0].y = viewPortHandler.contentBottom
-            _axisLineSegmentsBuffer[1].x = viewPortHandler.contentRight
-            _axisLineSegmentsBuffer[1].y = viewPortHandler.contentBottom
-            context.strokeLineSegments(between: _axisLineSegmentsBuffer)
+            axisLineSegmentsBuffer[0].x = viewPortHandler.contentLeft
+            axisLineSegmentsBuffer[0].y = viewPortHandler.contentBottom
+            axisLineSegmentsBuffer[1].x = viewPortHandler.contentRight
+            axisLineSegmentsBuffer[1].y = viewPortHandler.contentBottom
+            context.strokeLineSegments(between: axisLineSegmentsBuffer)
         }
-        
-        context.restoreGState()
     }
     
     /// draws the x-labels on the specified y-position
     @objc open func drawLabels(context: CGContext, pos: CGFloat, anchor: CGPoint)
     {
-        guard
-            let xAxis = self.axis as? XAxis,
-            let transformer = self.transformer
-            else { return }
+        guard let transformer = self.transformer else { return }
         
-        let paraStyle = NSParagraphStyle.default.mutableCopy() as! NSMutableParagraphStyle
+        let paraStyle = ParagraphStyle.default.mutableCopy() as! MutableParagraphStyle
         paraStyle.alignment = .center
         
-        let labelAttrs: [NSAttributedString.Key : Any] = [
-            .font: xAxis.labelFont,
-            .foregroundColor: xAxis.labelTextColor,
-            .paragraphStyle: paraStyle
-        ]
-        let labelRotationAngleRadians = xAxis.labelRotationAngle.DEG2RAD
-        
-        let centeringEnabled = xAxis.isCenterAxisLabelsEnabled
+        let labelAttrs: [NSAttributedString.Key : Any] = [.font: axis.labelFont,
+                                                         .foregroundColor: axis.labelTextColor,
+                                                         .paragraphStyle: paraStyle]
 
+        let labelRotationAngleRadians = axis.labelRotationAngle.DEG2RAD
+        let isCenteringEnabled = axis.isCenterAxisLabelsEnabled
         let valueToPixelMatrix = transformer.valueToPixelMatrix
+
+        var position = CGPoint.zero
+        var labelMaxSize = CGSize.zero
         
-        var position = CGPoint(x: 0.0, y: 0.0)
-        
-        var labelMaxSize = CGSize()
-        
-        if xAxis.isWordWrapEnabled
+        if axis.isWordWrapEnabled
         {
-            labelMaxSize.width = xAxis.wordWrapWidthPercent * valueToPixelMatrix.a
+            labelMaxSize.width = axis.wordWrapWidthPercent * valueToPixelMatrix.a
         }
         
-        let entries = xAxis.entries
+        let entries = axis.entries
         
-        for i in stride(from: 0, to: entries.count, by: 1)
+        for i in entries.indices
         {
-            if centeringEnabled
-            {
-                position.x = CGFloat(xAxis.centeredEntries[i])
-            }
-            else
-            {
-                position.x = CGFloat(entries[i])
-            }
+            let px = isCenteringEnabled ? CGFloat(axis.centeredEntries[i]) : CGFloat(entries[i])
+            position = CGPoint(x: px, y: 0)
+                .applying(valueToPixelMatrix)
+
+            guard viewPortHandler.isInBoundsX(position.x) else { continue }
             
-            position.y = 0.0
-            position = position.applying(valueToPixelMatrix)
+            let label = axis.valueFormatter?.stringForValue(axis.entries[i], axis: axis) ?? ""
+            let labelns = label as NSString
             
-            if viewPortHandler.isInBoundsX(position.x)
+            if axis.isAvoidFirstLastClippingEnabled
             {
-                let label = xAxis.valueFormatter?.stringForValue(xAxis.entries[i], axis: xAxis) ?? ""
-
-                let labelns = label as NSString
-                
-                if xAxis.isAvoidFirstLastClippingEnabled
+                // avoid clipping of the last
+                if i == axis.entryCount - 1 && axis.entryCount > 1
                 {
-                    // avoid clipping of the last
-                    if i == xAxis.entryCount - 1 && xAxis.entryCount > 1
+                    let width = labelns.boundingRect(with: labelMaxSize, options: .usesLineFragmentOrigin, attributes: labelAttrs, context: nil).size.width
+                    
+                    if width > viewPortHandler.offsetRight * 2.0,
+                        position.x + width > viewPortHandler.chartWidth
                     {
-                        let width = labelns.boundingRect(with: labelMaxSize, options: .usesLineFragmentOrigin, attributes: labelAttrs, context: nil).size.width
-                        
-                        if width > viewPortHandler.offsetRight * 2.0
-                            && position.x + width > viewPortHandler.chartWidth
-                        {
-                            position.x -= width / 2.0
-                        }
-                    }
-                    else if i == 0
-                    { // avoid clipping of the first
-                        let width = labelns.boundingRect(with: labelMaxSize, options: .usesLineFragmentOrigin, attributes: labelAttrs, context: nil).size.width
-                        position.x += width / 2.0
+                        position.x -= width / 2.0
                     }
                 }
-                
-                drawLabel(context: context,
-                          formattedLabel: label,
-                          x: position.x,
-                          y: pos,
-                          attributes: labelAttrs,
-                          constrainedToSize: labelMaxSize,
-                          anchor: anchor,
-                          angleRadians: labelRotationAngleRadians)
+                else if i == 0
+                { // avoid clipping of the first
+                    let width = labelns.boundingRect(with: labelMaxSize, options: .usesLineFragmentOrigin, attributes: labelAttrs, context: nil).size.width
+                    position.x += width / 2.0
+                }
             }
+            
+            drawLabel(context: context,
+                      formattedLabel: label,
+                      x: position.x,
+                      y: pos,
+                      attributes: labelAttrs,
+                      constrainedTo: labelMaxSize,
+                      anchor: anchor,
+                      angleRadians: labelRotationAngleRadians)
         }
     }
     
@@ -259,44 +318,39 @@ open class XAxisRenderer: AxisRendererBase
         x: CGFloat,
         y: CGFloat,
         attributes: [NSAttributedString.Key : Any],
-        constrainedToSize: CGSize,
+        constrainedTo size: CGSize,
         anchor: CGPoint,
         angleRadians: CGFloat)
     {
-        ChartUtils.drawMultilineText(
-            context: context,
-            text: formattedLabel,
-            point: CGPoint(x: x, y: y),
-            attributes: attributes,
-            constrainedToSize: constrainedToSize,
-            anchor: anchor,
-            angleRadians: angleRadians)
+        context.drawMultilineText(formattedLabel,
+                                  at: CGPoint(x: x, y: y),
+                                  constrainedTo: size,
+                                  anchor: anchor,
+                                  angleRadians: angleRadians,
+                                  attributes: attributes)
     }
     
-    open override func renderGridLines(context: CGContext)
+    open func renderGridLines(context: CGContext)
     {
         guard
-            let xAxis = self.axis as? XAxis,
-            let transformer = self.transformer
+            let transformer = self.transformer,
+            axis.isEnabled,
+            axis.isDrawGridLinesEnabled
             else { return }
         
-        if !xAxis.isDrawGridLinesEnabled || !xAxis.isEnabled
-        {
-            return
-        }
-        
         context.saveGState()
         defer { context.restoreGState() }
+
         context.clip(to: self.gridClippingRect)
         
-        context.setShouldAntialias(xAxis.gridAntialiasEnabled)
-        context.setStrokeColor(xAxis.gridColor.cgColor)
-        context.setLineWidth(xAxis.gridLineWidth)
-        context.setLineCap(xAxis.gridLineCap)
+        context.setShouldAntialias(axis.gridAntialiasEnabled)
+        context.setStrokeColor(axis.gridColor.cgColor)
+        context.setLineWidth(axis.gridLineWidth)
+        context.setLineCap(axis.gridLineCap)
         
-        if xAxis.gridLineDashLengths != nil
+        if axis.gridLineDashLengths != nil
         {
-            context.setLineDash(phase: xAxis.gridLineDashPhase, lengths: xAxis.gridLineDashLengths)
+            context.setLineDash(phase: axis.gridLineDashPhase, lengths: axis.gridLineDashLengths)
         }
         else
         {
@@ -305,14 +359,14 @@ open class XAxisRenderer: AxisRendererBase
         
         let valueToPixelMatrix = transformer.valueToPixelMatrix
         
-        var position = CGPoint(x: 0.0, y: 0.0)
+        var position = CGPoint.zero
         
-        let entries = xAxis.entries
+        let entries = axis.entries
         
-        for i in stride(from: 0, to: entries.count, by: 1)
+        for entry in entries
         {
-            position.x = CGFloat(entries[i])
-            position.y = position.x
+            position.x = CGFloat(entry)
+            position.y = CGFloat(entry)
             position = position.applying(valueToPixelMatrix)
             
             drawGridLine(context: context, x: position.x, y: position.y)
@@ -322,7 +376,7 @@ open class XAxisRenderer: AxisRendererBase
     @objc open var gridClippingRect: CGRect
     {
         var contentRect = viewPortHandler.contentRect
-        let dx = self.axis?.gridLineWidth ?? 0.0
+        let dx = self.axis.gridLineWidth
         contentRect.origin.x -= dx / 2.0
         contentRect.size.width += dx
         return contentRect
@@ -330,29 +384,26 @@ open class XAxisRenderer: AxisRendererBase
     
     @objc open func drawGridLine(context: CGContext, x: CGFloat, y: CGFloat)
     {
-        if x >= viewPortHandler.offsetLeft
-            && x <= viewPortHandler.chartWidth
-        {
-            context.beginPath()
-            context.move(to: CGPoint(x: x, y: viewPortHandler.contentTop))
-            context.addLine(to: CGPoint(x: x, y: viewPortHandler.contentBottom))
-            context.strokePath()
-        }
+        guard x >= viewPortHandler.offsetLeft && x <= viewPortHandler.chartWidth else { return }
+
+        context.beginPath()
+        context.move(to: CGPoint(x: x, y: viewPortHandler.contentTop))
+        context.addLine(to: CGPoint(x: x, y: viewPortHandler.contentBottom))
+        context.strokePath()
     }
     
-    open override func renderLimitLines(context: CGContext)
+    open func renderLimitLines(context: CGContext)
     {
         guard
-            let xAxis = self.axis as? XAxis,
             let transformer = self.transformer,
-            !xAxis.limitLines.isEmpty
+            !axis.limitLines.isEmpty
             else { return }
         
         let trans = transformer.valueToPixelMatrix
         
-        var position = CGPoint(x: 0.0, y: 0.0)
+        var position = CGPoint.zero
         
-        for l in xAxis.limitLines where l.isEnabled
+        for l in axis.limitLines where l.isEnabled
         {
             context.saveGState()
             defer { context.restoreGState() }
@@ -373,7 +424,6 @@ open class XAxisRenderer: AxisRendererBase
     
     @objc open func renderLimitLineLine(context: CGContext, limitLine: ChartLimitLine, position: CGPoint)
     {
-        
         context.beginPath()
         context.move(to: CGPoint(x: position.x, y: viewPortHandler.contentTop))
         context.addLine(to: CGPoint(x: position.x, y: viewPortHandler.contentBottom))
@@ -394,55 +444,45 @@ open class XAxisRenderer: AxisRendererBase
     
     @objc open func renderLimitLineLabel(context: CGContext, limitLine: ChartLimitLine, position: CGPoint, yOffset: CGFloat)
     {
-        
         let label = limitLine.label
+        
+        // if drawing the limit-value label is enabled
         guard limitLine.drawLabelEnabled, !label.isEmpty else { return }
 
         let labelLineHeight = limitLine.valueFont.lineHeight
 
         let xOffset: CGFloat = limitLine.lineWidth + limitLine.xOffset
-        let attributes: [NSAttributedString.Key : Any] = [
-            .font : limitLine.valueFont,
-            .foregroundColor : limitLine.valueTextColor
-        ]
-
-        let (point, align): (CGPoint, NSTextAlignment)
-        switch limitLine.labelPosition {
-        case .topRight:
-            point = CGPoint(
-                x: position.x + xOffset,
-                y: viewPortHandler.contentTop + yOffset
-            )
+
+        let align: TextAlignment
+        let point: CGPoint
+
+        switch limitLine.labelPosition
+        {
+        case .rightTop:
             align = .left
+            point = CGPoint(x: position.x + xOffset,
+                            y: viewPortHandler.contentTop + yOffset)
 
-        case .bottomRight:
-            point = CGPoint(
-                x: position.x + xOffset,
-                y: viewPortHandler.contentBottom - labelLineHeight - yOffset
-            )
+        case .rightBottom:
             align = .left
+            point = CGPoint(x: position.x + xOffset,
+                            y: viewPortHandler.contentBottom - labelLineHeight - yOffset)
 
-        case .topLeft:
-            point = CGPoint(
-                x: position.x - xOffset,
-                y: viewPortHandler.contentTop + yOffset
-            )
+        case .leftTop:
             align = .right
+            point = CGPoint(x: position.x - xOffset,
+                            y: viewPortHandler.contentTop + yOffset)
 
-        case .bottomLeft:
-            point = CGPoint(
-                x: position.x - xOffset,
-                y: viewPortHandler.contentBottom - labelLineHeight - yOffset
-            )
+        case .leftBottom:
             align = .right
+            point = CGPoint(x: position.x - xOffset,
+                            y: viewPortHandler.contentBottom - labelLineHeight - yOffset)
         }
 
-        ChartUtils.drawText(
-            context: context,
-            text: label,
-            point: point,
-            align: align,
-            attributes: attributes
-        )
+        context.drawText(label,
+                         at: point,
+                         align: align,
+                         attributes: [.font: limitLine.valueFont,
+                                      .foregroundColor: limitLine.valueTextColor])
     }
 }

+ 120 - 186
Pods/Charts/Source/Charts/Renderers/XAxisRendererHorizontalBarChart.swift

@@ -16,9 +16,9 @@ open class XAxisRendererHorizontalBarChart: XAxisRenderer
 {
     internal weak var chart: BarChartView?
     
-    @objc public init(viewPortHandler: ViewPortHandler, xAxis: XAxis?, transformer: Transformer?, chart: BarChartView)
+    @objc public init(viewPortHandler: ViewPortHandler, axis: XAxis, transformer: Transformer?, chart: BarChartView)
     {
-        super.init(viewPortHandler: viewPortHandler, xAxis: xAxis, transformer: transformer)
+        super.init(viewPortHandler: viewPortHandler, axis: axis, transformer: transformer)
         
         self.chart = chart
     }
@@ -27,26 +27,17 @@ open class XAxisRendererHorizontalBarChart: XAxisRenderer
     {
         var min = min, max = max
         
-        if let transformer = self.transformer
+        if let transformer = self.transformer,
+            viewPortHandler.contentWidth > 10,
+            !viewPortHandler.isFullyZoomedOutY
         {
             // calculate the starting and entry point of the y-labels (depending on
             // zoom / contentrect bounds)
-            if viewPortHandler.contentWidth > 10 && !viewPortHandler.isFullyZoomedOutY
-            {
-                let p1 = transformer.valueForTouchPoint(CGPoint(x: viewPortHandler.contentLeft, y: viewPortHandler.contentBottom))
-                let p2 = transformer.valueForTouchPoint(CGPoint(x: viewPortHandler.contentLeft, y: viewPortHandler.contentTop))
-                
-                if inverted
-                {
-                    min = Double(p2.y)
-                    max = Double(p1.y)
-                }
-                else
-                {
-                    min = Double(p1.y)
-                    max = Double(p2.y)
-                }
-            }
+            let p1 = transformer.valueForTouchPoint(CGPoint(x: viewPortHandler.contentLeft, y: viewPortHandler.contentBottom))
+            let p2 = transformer.valueForTouchPoint(CGPoint(x: viewPortHandler.contentLeft, y: viewPortHandler.contentTop))
+
+            min = inverted ? Double(p2.y) : Double(p1.y)
+            max = inverted ? Double(p1.y) : Double(p2.y)
         }
         
         computeAxisValues(min: min, max: max)
@@ -54,55 +45,44 @@ open class XAxisRendererHorizontalBarChart: XAxisRenderer
     
     open override func computeSize()
     {
-        guard let
-            xAxis = self.axis as? XAxis
-            else { return }
-       
-        let longest = xAxis.getLongestLabel() as NSString
+        let longest = axis.getLongestLabel() as NSString
         
-        let labelSize = longest.size(withAttributes: [NSAttributedString.Key.font: xAxis.labelFont])
-        
-        let labelWidth = floor(labelSize.width + xAxis.xOffset * 3.5)
+        let labelSize = longest.size(withAttributes: [.font: axis.labelFont])
+
+        let labelWidth = floor(labelSize.width + axis.xOffset * 3.5)
         let labelHeight = labelSize.height
-        let labelRotatedSize = CGSize(width: labelSize.width, height: labelHeight).rotatedBy(degrees: xAxis.labelRotationAngle)
+        let labelRotatedSize = CGSize(width: labelSize.width, height: labelHeight).rotatedBy(degrees: axis.labelRotationAngle)
 
-        xAxis.labelWidth = labelWidth
-        xAxis.labelHeight = labelHeight
-        xAxis.labelRotatedWidth = round(labelRotatedSize.width + xAxis.xOffset * 3.5)
-        xAxis.labelRotatedHeight = round(labelRotatedSize.height)
+        axis.labelWidth = labelWidth
+        axis.labelHeight = labelHeight
+        axis.labelRotatedWidth = round(labelRotatedSize.width + axis.xOffset * 3.5)
+        axis.labelRotatedHeight = round(labelRotatedSize.height)
     }
 
     open override func renderAxisLabels(context: CGContext)
     {
         guard
-            let xAxis = self.axis as? XAxis
+            axis.isEnabled,
+            axis.isDrawLabelsEnabled,
+            chart?.data != nil
             else { return }
         
-        if !xAxis.isEnabled || !xAxis.isDrawLabelsEnabled || chart?.data === nil
-        {
-            return
-        }
-        
-        let xoffset = xAxis.xOffset
-        
-        if xAxis.labelPosition == .top
-        {
+        let xoffset = axis.xOffset
+
+        switch axis.labelPosition {
+        case .top:
             drawLabels(context: context, pos: viewPortHandler.contentRight + xoffset, anchor: CGPoint(x: 0.0, y: 0.5))
-        }
-        else if xAxis.labelPosition == .topInside
-        {
+
+        case .topInside:
             drawLabels(context: context, pos: viewPortHandler.contentRight - xoffset, anchor: CGPoint(x: 1.0, y: 0.5))
-        }
-        else if xAxis.labelPosition == .bottom
-        {
+
+        case .bottom:
             drawLabels(context: context, pos: viewPortHandler.contentLeft - xoffset, anchor: CGPoint(x: 1.0, y: 0.5))
-        }
-        else if xAxis.labelPosition == .bottomInside
-        {
+
+        case .bottomInside:
             drawLabels(context: context, pos: viewPortHandler.contentLeft + xoffset, anchor: CGPoint(x: 0.0, y: 0.5))
-        }
-        else
-        { // BOTH SIDED
+
+        case .bothSided:
             drawLabels(context: context, pos: viewPortHandler.contentRight + xoffset, anchor: CGPoint(x: 0.0, y: 0.5))
             drawLabels(context: context, pos: viewPortHandler.contentLeft - xoffset, anchor: CGPoint(x: 1.0, y: 0.5))
         }
@@ -111,50 +91,35 @@ open class XAxisRendererHorizontalBarChart: XAxisRenderer
     /// draws the x-labels on the specified y-position
     open override func drawLabels(context: CGContext, pos: CGFloat, anchor: CGPoint)
     {
-        guard
-            let xAxis = self.axis as? XAxis,
-            let transformer = self.transformer
-            else { return }
+        guard let transformer = self.transformer else { return }
         
-        let labelFont = xAxis.labelFont
-        let labelTextColor = xAxis.labelTextColor
-        let labelRotationAngleRadians = xAxis.labelRotationAngle.DEG2RAD
+        let labelFont = axis.labelFont
+        let labelTextColor = axis.labelTextColor
+        let labelRotationAngleRadians = axis.labelRotationAngle.DEG2RAD
         
-        let centeringEnabled = xAxis.isCenterAxisLabelsEnabled
+        let centeringEnabled = axis.isCenterAxisLabelsEnabled
         
         // pre allocate to save performance (dont allocate in loop)
-        var position = CGPoint(x: 0.0, y: 0.0)
+        var position = CGPoint.zero
         
-        for i in stride(from: 0, to: xAxis.entryCount, by: 1)
+        for i in 0..<axis.entryCount
         {
             // only fill x values
-            
             position.x = 0.0
-            
-            if centeringEnabled
-            {
-                position.y = CGFloat(xAxis.centeredEntries[i])
-            }
-            else
-            {
-                position.y = CGFloat(xAxis.entries[i])
-            }
-            
+            position.y = centeringEnabled ? CGFloat(axis.centeredEntries[i]) : CGFloat(axis.entries[i])
+
             transformer.pointValueToPixel(&position)
             
-            if viewPortHandler.isInBoundsY(position.y)
+            if viewPortHandler.isInBoundsY(position.y),
+                let label = axis.valueFormatter?.stringForValue(axis.entries[i], axis: axis)
             {
-                if let label = xAxis.valueFormatter?.stringForValue(xAxis.entries[i], axis: xAxis)
-                {
-                    drawLabel(
-                        context: context,
-                        formattedLabel: label,
-                        x: pos,
-                        y: position.y,
-                        attributes: [NSAttributedString.Key.font: labelFont, NSAttributedString.Key.foregroundColor: labelTextColor],
-                        anchor: anchor,
-                        angleRadians: labelRotationAngleRadians)
-                }
+                drawLabel(context: context,
+                          formattedLabel: label,
+                          x: pos,
+                          y: position.y,
+                          attributes: [.font: labelFont, .foregroundColor: labelTextColor],
+                          anchor: anchor,
+                          angleRadians: labelRotationAngleRadians)
             }
         }
     }
@@ -168,62 +133,56 @@ open class XAxisRendererHorizontalBarChart: XAxisRenderer
         anchor: CGPoint,
         angleRadians: CGFloat)
     {
-        ChartUtils.drawText(
-            context: context,
-            text: formattedLabel,
-            point: CGPoint(x: x, y: y),
-            attributes: attributes,
-            anchor: anchor,
-            angleRadians: angleRadians)
+        context.drawText(formattedLabel,
+                         at: CGPoint(x: x, y: y),
+                         anchor: anchor,
+                         angleRadians: angleRadians,
+                         attributes: attributes)
     }
     
     open override var gridClippingRect: CGRect
     {
         var contentRect = viewPortHandler.contentRect
-        let dy = self.axis?.gridLineWidth ?? 0.0
+        let dy = self.axis.gridLineWidth
         contentRect.origin.y -= dy / 2.0
         contentRect.size.height += dy
         return contentRect
     }
-    
-    private var _gridLineSegmentsBuffer = [CGPoint](repeating: CGPoint(), count: 2)
-    
+
     open override func drawGridLine(context: CGContext, x: CGFloat, y: CGFloat)
     {
-        if viewPortHandler.isInBoundsY(y)
-        {
-            context.beginPath()
-            context.move(to: CGPoint(x: viewPortHandler.contentLeft, y: y))
-            context.addLine(to: CGPoint(x: viewPortHandler.contentRight, y: y))
-            context.strokePath()
-        }
+        guard viewPortHandler.isInBoundsY(y) else { return }
+
+        context.beginPath()
+        context.move(to: CGPoint(x: viewPortHandler.contentLeft, y: y))
+        context.addLine(to: CGPoint(x: viewPortHandler.contentRight, y: y))
+        context.strokePath()
     }
     
     open override func renderAxisLine(context: CGContext)
     {
-        guard let xAxis = self.axis as? XAxis else { return }
-        
-        if !xAxis.isEnabled || !xAxis.isDrawAxisLineEnabled
-        {
-            return
-        }
-        
+        guard
+            axis.isEnabled,
+            axis.isDrawAxisLineEnabled
+            else { return }
+
         context.saveGState()
-        
-        context.setStrokeColor(xAxis.axisLineColor.cgColor)
-        context.setLineWidth(xAxis.axisLineWidth)
-        if xAxis.axisLineDashLengths != nil
+        defer { context.restoreGState() }
+
+        context.setStrokeColor(axis.axisLineColor.cgColor)
+        context.setLineWidth(axis.axisLineWidth)
+        if axis.axisLineDashLengths != nil
         {
-            context.setLineDash(phase: xAxis.axisLineDashPhase, lengths: xAxis.axisLineDashLengths)
+            context.setLineDash(phase: axis.axisLineDashPhase, lengths: axis.axisLineDashLengths)
         }
         else
         {
             context.setLineDash(phase: 0.0, lengths: [])
         }
         
-        if xAxis.labelPosition == .top ||
-            xAxis.labelPosition == .topInside ||
-            xAxis.labelPosition == .bothSided
+        if axis.labelPosition == .top ||
+            axis.labelPosition == .topInside ||
+            axis.labelPosition == .bothSided
         {
             context.beginPath()
             context.move(to: CGPoint(x: viewPortHandler.contentRight, y: viewPortHandler.contentTop))
@@ -231,46 +190,31 @@ open class XAxisRendererHorizontalBarChart: XAxisRenderer
             context.strokePath()
         }
         
-        if xAxis.labelPosition == .bottom ||
-            xAxis.labelPosition == .bottomInside ||
-            xAxis.labelPosition == .bothSided
+        if axis.labelPosition == .bottom ||
+            axis.labelPosition == .bottomInside ||
+            axis.labelPosition == .bothSided
         {
             context.beginPath()
             context.move(to: CGPoint(x: viewPortHandler.contentLeft, y: viewPortHandler.contentTop))
             context.addLine(to: CGPoint(x: viewPortHandler.contentLeft, y: viewPortHandler.contentBottom))
             context.strokePath()
         }
-        
-        context.restoreGState()
     }
     
     open override func renderLimitLines(context: CGContext)
     {
-        guard
-            let xAxis = self.axis as? XAxis,
-            let transformer = self.transformer
-            else { return }
+        guard let transformer = self.transformer else { return }
         
-        let limitLines = xAxis.limitLines
-        
-        if limitLines.count == 0
-        {
-            return
-        }
+        let limitLines = axis.limitLines
         
+        guard !limitLines.isEmpty else { return }
+
         let trans = transformer.valueToPixelMatrix
         
-        var position = CGPoint(x: 0.0, y: 0.0)
+        var position = CGPoint.zero
         
-        for i in 0 ..< limitLines.count
+        for l in limitLines where l.isEnabled
         {
-            let l = limitLines[i]
-            
-            if !l.isEnabled
-            {
-                continue
-            }
-            
             context.saveGState()
             defer { context.restoreGState() }
             
@@ -303,53 +247,43 @@ open class XAxisRendererHorizontalBarChart: XAxisRenderer
             let label = l.label
             
             // if drawing the limit-value label is enabled
-            if l.drawLabelEnabled && label.count > 0
+            if l.drawLabelEnabled, !label.isEmpty
             {
                 let labelLineHeight = l.valueFont.lineHeight
                 
-                let xOffset: CGFloat = 4.0 + l.xOffset
-                let yOffset: CGFloat = l.lineWidth + labelLineHeight + l.yOffset
-                
-                if l.labelPosition == .topRight
-                {
-                    ChartUtils.drawText(context: context,
-                        text: label,
-                        point: CGPoint(
-                            x: viewPortHandler.contentRight - xOffset,
-                            y: position.y - yOffset),
-                        align: .right,
-                        attributes: [NSAttributedString.Key.font: l.valueFont, NSAttributedString.Key.foregroundColor: l.valueTextColor])
-                }
-                else if l.labelPosition == .bottomRight
-                {
-                    ChartUtils.drawText(context: context,
-                        text: label,
-                        point: CGPoint(
-                            x: viewPortHandler.contentRight - xOffset,
-                            y: position.y + yOffset - labelLineHeight),
-                        align: .right,
-                        attributes: [NSAttributedString.Key.font: l.valueFont, NSAttributedString.Key.foregroundColor: l.valueTextColor])
-                }
-                else if l.labelPosition == .topLeft
-                {
-                    ChartUtils.drawText(context: context,
-                        text: label,
-                        point: CGPoint(
-                            x: viewPortHandler.contentLeft + xOffset,
-                            y: position.y - yOffset),
-                        align: .left,
-                        attributes: [NSAttributedString.Key.font: l.valueFont, NSAttributedString.Key.foregroundColor: l.valueTextColor])
-                }
-                else
+                let xOffset = 4.0 + l.xOffset
+                let yOffset = l.lineWidth + labelLineHeight + l.yOffset
+
+                let align: TextAlignment
+                let point: CGPoint
+
+                switch l.labelPosition
                 {
-                    ChartUtils.drawText(context: context,
-                        text: label,
-                        point: CGPoint(
-                            x: viewPortHandler.contentLeft + xOffset,
-                            y: position.y + yOffset - labelLineHeight),
-                        align: .left,
-                        attributes: [NSAttributedString.Key.font: l.valueFont, NSAttributedString.Key.foregroundColor: l.valueTextColor])
+                case .rightTop:
+                    align = .right
+                    point = CGPoint(x: viewPortHandler.contentRight - xOffset,
+                                    y: position.y - yOffset)
+
+                case .rightBottom:
+                    align = .right
+                    point = CGPoint(x: viewPortHandler.contentRight - xOffset,
+                                    y: position.y + yOffset - labelLineHeight)
+
+                case .leftTop:
+                    align = .left
+                    point = CGPoint(x: viewPortHandler.contentLeft + xOffset,
+                                    y: position.y - yOffset)
+
+                case .leftBottom:
+                    align = .left
+                    point = CGPoint(x: viewPortHandler.contentLeft + xOffset,
+                                    y: position.y + yOffset - labelLineHeight)
                 }
+
+                context.drawText(label,
+                                 at: point,
+                                 align: align,
+                                 attributes: [.font: l.valueFont, .foregroundColor: l.valueTextColor])
             }
         }
     }

+ 21 - 30
Pods/Charts/Source/Charts/Renderers/XAxisRendererRadarChart.swift

@@ -16,28 +16,24 @@ open class XAxisRendererRadarChart: XAxisRenderer
 {
     @objc open weak var chart: RadarChartView?
     
-    @objc public init(viewPortHandler: ViewPortHandler, xAxis: XAxis?, chart: RadarChartView)
+    @objc public init(viewPortHandler: ViewPortHandler, axis: XAxis, chart: RadarChartView)
     {
-        super.init(viewPortHandler: viewPortHandler, xAxis: xAxis, transformer: nil)
+        super.init(viewPortHandler: viewPortHandler, axis: axis, transformer: nil)
         
         self.chart = chart
     }
     
     open override func renderAxisLabels(context: CGContext)
     {
-        guard let
-            xAxis = axis as? XAxis,
-            let chart = chart
+        guard
+            let chart = chart,
+            axis.isEnabled,
+            axis.isDrawLabelsEnabled
             else { return }
-        
-        if !xAxis.isEnabled || !xAxis.isDrawLabelsEnabled
-        {
-            return
-        }
-        
-        let labelFont = xAxis.labelFont
-        let labelTextColor = xAxis.labelTextColor
-        let labelRotationAngleRadians = xAxis.labelRotationAngle.RAD2DEG
+
+        let labelFont = axis.labelFont
+        let labelTextColor = axis.labelTextColor
+        let labelRotationAngleRadians = axis.labelRotationAngle.RAD2DEG
         let drawLabelAnchor = CGPoint(x: 0.5, y: 0.25)
         
         let sliceangle = chart.sliceAngle
@@ -47,20 +43,17 @@ open class XAxisRendererRadarChart: XAxisRenderer
         
         let center = chart.centerOffsets
         
-        for i in stride(from: 0, to: chart.data?.maxEntryCountSet?.entryCount ?? 0, by: 1)
+        for i in 0..<(chart.data?.maxEntryCountSet?.entryCount ?? 0)
         {
-            
-            let label = xAxis.valueFormatter?.stringForValue(Double(i), axis: xAxis) ?? ""
-            
+            let label = axis.valueFormatter?.stringForValue(Double(i), axis: axis) ?? ""
             let angle = (sliceangle * CGFloat(i) + chart.rotationAngle).truncatingRemainder(dividingBy: 360.0)
-            
-            let p = center.moving(distance: CGFloat(chart.yRange) * factor + xAxis.labelRotatedWidth / 2.0, atAngle: angle)
-            
+            let p = center.moving(distance: CGFloat(chart.yRange) * factor + axis.labelRotatedWidth / 2.0, atAngle: angle)
+
             drawLabel(context: context,
                       formattedLabel: label,
                       x: p.x,
-                      y: p.y - xAxis.labelRotatedHeight / 2.0,
-                      attributes: [NSAttributedString.Key.font: labelFont, NSAttributedString.Key.foregroundColor: labelTextColor],
+                      y: p.y - axis.labelRotatedHeight / 2.0,
+                      attributes: [.font: labelFont, .foregroundColor: labelTextColor],
                       anchor: drawLabelAnchor,
                       angleRadians: labelRotationAngleRadians)
         }
@@ -75,13 +68,11 @@ open class XAxisRendererRadarChart: XAxisRenderer
         anchor: CGPoint,
         angleRadians: CGFloat)
     {
-        ChartUtils.drawText(
-            context: context,
-            text: formattedLabel,
-            point: CGPoint(x: x, y: y),
-            attributes: attributes,
-            anchor: anchor,
-            angleRadians: angleRadians)
+        context.drawText(formattedLabel,
+                         at: CGPoint(x: x, y: y),
+                         anchor: anchor,
+                         angleRadians: angleRadians,
+                         attributes: attributes)
     }
     
     open override func renderLimitLines(context: CGContext)

+ 238 - 178
Pods/Charts/Source/Charts/Renderers/YAxisRenderer.swift

@@ -12,41 +12,39 @@
 import Foundation
 import CoreGraphics
 
-#if canImport(UIKit)
-    import UIKit
-#endif
-
-#if canImport(Cocoa)
-import Cocoa
-#endif
 
 @objc(ChartYAxisRenderer)
-open class YAxisRenderer: AxisRendererBase
+open class YAxisRenderer: NSObject, AxisRenderer
 {
-    @objc public init(viewPortHandler: ViewPortHandler, yAxis: YAxis?, transformer: Transformer?)
+    @objc public let viewPortHandler: ViewPortHandler
+    @objc public let axis: YAxis
+    @objc public let transformer: Transformer?
+
+    @objc public init(viewPortHandler: ViewPortHandler, axis: YAxis, transformer: Transformer?)
     {
-        super.init(viewPortHandler: viewPortHandler, transformer: transformer, axis: yAxis)
+        self.viewPortHandler = viewPortHandler
+        self.axis = axis
+        self.transformer = transformer
+        
+        super.init()
     }
     
     /// draws the y-axis labels to the screen
-    open override func renderAxisLabels(context: CGContext)
+    open func renderAxisLabels(context: CGContext)
     {
-        guard let yAxis = self.axis as? YAxis else { return }
-        
-        if !yAxis.isEnabled || !yAxis.isDrawLabelsEnabled
-        {
-            return
-        }
-        
-        let xoffset = yAxis.xOffset
-        let yoffset = yAxis.labelFont.lineHeight / 2.5 + yAxis.yOffset
-        
-        let dependency = yAxis.axisDependency
-        let labelPosition = yAxis.labelPosition
+        guard
+            axis.isEnabled,
+            axis.isDrawLabelsEnabled
+            else { return }
+
+        let xoffset = axis.xOffset
+        let yoffset = axis.labelFont.lineHeight / 2.5 + axis.yOffset
         
-        var xPos = CGFloat(0.0)
+        let dependency = axis.axisDependency
+        let labelPosition = axis.labelPosition
         
-        var textAlign: NSTextAlignment
+        let xPos: CGFloat
+        let textAlign: TextAlignment
         
         if dependency == .left
         {
@@ -60,7 +58,6 @@ open class YAxisRenderer: AxisRendererBase
                 textAlign = .left
                 xPos = viewPortHandler.offsetLeft + xoffset
             }
-            
         }
         else
         {
@@ -76,37 +73,35 @@ open class YAxisRenderer: AxisRendererBase
             }
         }
         
-        drawYLabels(
-            context: context,
-            fixedPosition: xPos,
-            positions: transformedPositions(),
-            offset: yoffset - yAxis.labelFont.lineHeight,
-            textAlign: textAlign)
+        drawYLabels(context: context,
+                    fixedPosition: xPos,
+                    positions: transformedPositions(),
+                    offset: yoffset - axis.labelFont.lineHeight,
+                    textAlign: textAlign)
     }
     
-    open override func renderAxisLine(context: CGContext)
+    open func renderAxisLine(context: CGContext)
     {
-        guard let yAxis = self.axis as? YAxis else { return }
-        
-        if !yAxis.isEnabled || !yAxis.drawAxisLineEnabled
-        {
-            return
-        }
-        
+        guard
+            axis.isEnabled,
+            axis.drawAxisLineEnabled
+            else { return }
+
         context.saveGState()
-        
-        context.setStrokeColor(yAxis.axisLineColor.cgColor)
-        context.setLineWidth(yAxis.axisLineWidth)
-        if yAxis.axisLineDashLengths != nil
+        defer { context.restoreGState() }
+
+        context.setStrokeColor(axis.axisLineColor.cgColor)
+        context.setLineWidth(axis.axisLineWidth)
+        if axis.axisLineDashLengths != nil
         {
-            context.setLineDash(phase: yAxis.axisLineDashPhase, lengths: yAxis.axisLineDashLengths)
+            context.setLineDash(phase: axis.axisLineDashPhase, lengths: axis.axisLineDashLengths)
         }
         else
         {
             context.setLineDash(phase: 0.0, lengths: [])
         }
         
-        if yAxis.axisDependency == .left
+        if axis.axisDependency == .left
         {
             context.beginPath()
             context.move(to: CGPoint(x: viewPortHandler.contentLeft, y: viewPortHandler.contentTop))
@@ -120,8 +115,6 @@ open class YAxisRenderer: AxisRendererBase
             context.addLine(to: CGPoint(x: viewPortHandler.contentRight, y: viewPortHandler.contentBottom))
             context.strokePath()
         }
-        
-        context.restoreGState()
     }
     
     /// draws the y-labels on the specified x-position
@@ -130,46 +123,31 @@ open class YAxisRenderer: AxisRendererBase
         fixedPosition: CGFloat,
         positions: [CGPoint],
         offset: CGFloat,
-        textAlign: NSTextAlignment)
+        textAlign: TextAlignment)
     {
-        guard
-            let yAxis = self.axis as? YAxis
-            else { return }
-        
-        let labelFont = yAxis.labelFont
-        let labelTextColor = yAxis.labelTextColor
+        let labelFont = axis.labelFont
+        let labelTextColor = axis.labelTextColor
         
-        let from = yAxis.isDrawBottomYLabelEntryEnabled ? 0 : 1
-        let to = yAxis.isDrawTopYLabelEntryEnabled ? yAxis.entryCount : (yAxis.entryCount - 1)
+        let from = axis.isDrawBottomYLabelEntryEnabled ? 0 : 1
+        let to = axis.isDrawTopYLabelEntryEnabled ? axis.entryCount : (axis.entryCount - 1)
         
-        let xOffset = yAxis.labelXOffset
+        let xOffset = axis.labelXOffset
         
-        for i in stride(from: from, to: to, by: 1)
+        for i in from..<to
         {
-            let text = yAxis.getFormattedLabel(i)
-            
-            ChartUtils.drawText(
-                context: context,
-                text: text,
-                point: CGPoint(x: fixedPosition + xOffset, y: positions[i].y + offset),
-                align: textAlign,
-                attributes: [.font: labelFont, .foregroundColor: labelTextColor]
-            )
+            let text = axis.getFormattedLabel(i)
+            context.drawText(text,
+                             at: CGPoint(x: fixedPosition + xOffset, y: positions[i].y + offset),
+                             align: textAlign,
+                             attributes: [.font: labelFont, .foregroundColor: labelTextColor])
         }
     }
     
-    open override func renderGridLines(context: CGContext)
+    open func renderGridLines(context: CGContext)
     {
-        guard let
-            yAxis = self.axis as? YAxis
-            else { return }
-        
-        if !yAxis.isEnabled
-        {
-            return
-        }
-        
-        if yAxis.drawGridLinesEnabled
+        guard axis.isEnabled else { return }
+
+        if axis.drawGridLinesEnabled
         {
             let positions = transformedPositions()
             
@@ -177,15 +155,14 @@ open class YAxisRenderer: AxisRendererBase
             defer { context.restoreGState() }
             context.clip(to: self.gridClippingRect)
             
-            context.setShouldAntialias(yAxis.gridAntialiasEnabled)
-            context.setStrokeColor(yAxis.gridColor.cgColor)
-            context.setLineWidth(yAxis.gridLineWidth)
-            context.setLineCap(yAxis.gridLineCap)
+            context.setShouldAntialias(axis.gridAntialiasEnabled)
+            context.setStrokeColor(axis.gridColor.cgColor)
+            context.setLineWidth(axis.gridLineWidth)
+            context.setLineCap(axis.gridLineCap)
             
-            if yAxis.gridLineDashLengths != nil
+            if axis.gridLineDashLengths != nil
             {
-                context.setLineDash(phase: yAxis.gridLineDashPhase, lengths: yAxis.gridLineDashLengths)
-                
+                context.setLineDash(phase: axis.gridLineDashPhase, lengths: axis.gridLineDashLengths)
             }
             else
             {
@@ -196,7 +173,7 @@ open class YAxisRenderer: AxisRendererBase
             positions.forEach { drawGridLine(context: context, position: $0) }
         }
 
-        if yAxis.drawZeroLineEnabled
+        if axis.drawZeroLineEnabled
         {
             // draw zero line
             drawZeroLine(context: context)
@@ -206,7 +183,7 @@ open class YAxisRenderer: AxisRendererBase
     @objc open var gridClippingRect: CGRect
     {
         var contentRect = viewPortHandler.contentRect
-        let dy = self.axis?.gridLineWidth ?? 0.0
+        let dy = self.axis.gridLineWidth
         contentRect.origin.y -= dy / 2.0
         contentRect.size.height += dy
         return contentRect
@@ -224,21 +201,9 @@ open class YAxisRenderer: AxisRendererBase
     
     @objc open func transformedPositions() -> [CGPoint]
     {
-        guard
-            let yAxis = self.axis as? YAxis,
-            let transformer = self.transformer
-            else { return [CGPoint]() }
-        
-        var positions = [CGPoint]()
-        positions.reserveCapacity(yAxis.entryCount)
-        
-        let entries = yAxis.entries
+        guard let transformer = self.transformer else { return [] }
         
-        for i in stride(from: 0, to: yAxis.entryCount, by: 1)
-        {
-            positions.append(CGPoint(x: 0.0, y: entries[i]))
-        }
-
+        var positions = axis.entries.map { CGPoint(x: 0.0, y: $0) }
         transformer.pointValuesToPixel(&positions)
         
         return positions
@@ -248,27 +213,26 @@ open class YAxisRenderer: AxisRendererBase
     @objc open func drawZeroLine(context: CGContext)
     {
         guard
-            let yAxis = self.axis as? YAxis,
             let transformer = self.transformer,
-            let zeroLineColor = yAxis.zeroLineColor
+            let zeroLineColor = axis.zeroLineColor
             else { return }
         
         context.saveGState()
         defer { context.restoreGState() }
         
         var clippingRect = viewPortHandler.contentRect
-        clippingRect.origin.y -= yAxis.zeroLineWidth / 2.0
-        clippingRect.size.height += yAxis.zeroLineWidth
+        clippingRect.origin.y -= axis.zeroLineWidth / 2.0
+        clippingRect.size.height += axis.zeroLineWidth
         context.clip(to: clippingRect)
 
         context.setStrokeColor(zeroLineColor.cgColor)
-        context.setLineWidth(yAxis.zeroLineWidth)
+        context.setLineWidth(axis.zeroLineWidth)
         
         let pos = transformer.pixelForValues(x: 0.0, y: 0.0)
-    
-        if yAxis.zeroLineDashLengths != nil
+
+        if axis.zeroLineDashLengths != nil
         {
-            context.setLineDash(phase: yAxis.zeroLineDashPhase, lengths: yAxis.zeroLineDashLengths!)
+            context.setLineDash(phase: axis.zeroLineDashPhase, lengths: axis.zeroLineDashLengths!)
         }
         else
         {
@@ -280,35 +244,23 @@ open class YAxisRenderer: AxisRendererBase
         context.drawPath(using: CGPathDrawingMode.stroke)
     }
     
-    open override func renderLimitLines(context: CGContext)
+    open func renderLimitLines(context: CGContext)
     {
-        guard
-            let yAxis = self.axis as? YAxis,
-            let transformer = self.transformer
-            else { return }
+        guard let transformer = self.transformer else { return }
         
-        let limitLines = yAxis.limitLines
-        
-        if limitLines.count == 0
-        {
-            return
-        }
+        let limitLines = axis.limitLines
         
+        guard !limitLines.isEmpty else { return }
+
         context.saveGState()
-        
+        defer { context.restoreGState() }
+
         let trans = transformer.valueToPixelMatrix
         
         var position = CGPoint(x: 0.0, y: 0.0)
         
-        for i in 0 ..< limitLines.count
+        for l in limitLines where l.isEnabled
         {
-            let l = limitLines[i]
-            
-            if !l.isEnabled
-            {
-                continue
-            }
-            
             context.saveGState()
             defer { context.restoreGState() }
             
@@ -341,56 +293,164 @@ open class YAxisRenderer: AxisRendererBase
             let label = l.label
             
             // if drawing the limit-value label is enabled
-            if l.drawLabelEnabled && label.count > 0
+            guard l.drawLabelEnabled, !label.isEmpty else { continue }
+
+            let labelLineHeight = l.valueFont.lineHeight
+
+            let xOffset = 4.0 + l.xOffset
+            let yOffset = l.lineWidth + labelLineHeight + l.yOffset
+
+            let align: TextAlignment
+            let point: CGPoint
+
+            switch l.labelPosition
             {
-                let labelLineHeight = l.valueFont.lineHeight
-                
-                let xOffset: CGFloat = 4.0 + l.xOffset
-                let yOffset: CGFloat = l.lineWidth + labelLineHeight + l.yOffset
-                
-                if l.labelPosition == .topRight
-                {
-                    ChartUtils.drawText(context: context,
-                        text: label,
-                        point: CGPoint(
-                            x: viewPortHandler.contentRight - xOffset,
-                            y: position.y - yOffset),
-                        align: .right,
-                        attributes: [NSAttributedString.Key.font: l.valueFont, NSAttributedString.Key.foregroundColor: l.valueTextColor])
-                }
-                else if l.labelPosition == .bottomRight
-                {
-                    ChartUtils.drawText(context: context,
-                        text: label,
-                        point: CGPoint(
-                            x: viewPortHandler.contentRight - xOffset,
-                            y: position.y + yOffset - labelLineHeight),
-                        align: .right,
-                        attributes: [NSAttributedString.Key.font: l.valueFont, NSAttributedString.Key.foregroundColor: l.valueTextColor])
-                }
-                else if l.labelPosition == .topLeft
-                {
-                    ChartUtils.drawText(context: context,
-                        text: label,
-                        point: CGPoint(
-                            x: viewPortHandler.contentLeft + xOffset,
-                            y: position.y - yOffset),
-                        align: .left,
-                        attributes: [NSAttributedString.Key.font: l.valueFont, NSAttributedString.Key.foregroundColor: l.valueTextColor])
-                }
-                else
-                {
-                    ChartUtils.drawText(context: context,
-                        text: label,
-                        point: CGPoint(
-                            x: viewPortHandler.contentLeft + xOffset,
-                            y: position.y + yOffset - labelLineHeight),
-                        align: .left,
-                        attributes: [NSAttributedString.Key.font: l.valueFont, NSAttributedString.Key.foregroundColor: l.valueTextColor])
-                }
+            case .rightTop:
+                align = .right
+                point = CGPoint(x: viewPortHandler.contentRight - xOffset,
+                                y: position.y - yOffset)
+
+            case .rightBottom:
+                align = .right
+                point = CGPoint(x: viewPortHandler.contentRight - xOffset,
+                                y: position.y + yOffset - labelLineHeight)
+
+            case .leftTop:
+                align = .left
+                point = CGPoint(x: viewPortHandler.contentLeft + xOffset,
+                                y: position.y - yOffset)
+
+            case .leftBottom:
+                align = .left
+                point = CGPoint(x: viewPortHandler.contentLeft + xOffset,
+                                y: position.y + yOffset - labelLineHeight)
             }
+
+            context.drawText(label,
+                             at: point,
+                             align: align,
+                             attributes: [.font: l.valueFont, .foregroundColor: l.valueTextColor])
+        }
+    }
+
+    @objc open func computeAxis(min: Double, max: Double, inverted: Bool)
+    {
+        var min = min, max = max
+
+        if let transformer = self.transformer,
+            viewPortHandler.contentWidth > 10.0,
+            !viewPortHandler.isFullyZoomedOutY
+        {
+            // calculate the starting and entry point of the y-labels (depending on zoom / contentrect bounds)
+            let p1 = transformer.valueForTouchPoint(CGPoint(x: viewPortHandler.contentLeft, y: viewPortHandler.contentTop))
+            let p2 = transformer.valueForTouchPoint(CGPoint(x: viewPortHandler.contentLeft, y: viewPortHandler.contentBottom))
+
+            min = inverted ? Double(p1.y) : Double(p2.y)
+            max = inverted ? Double(p2.y) : Double(p1.y)
+        }
+
+        computeAxisValues(min: min, max: max)
+    }
+
+    @objc open func computeAxisValues(min: Double, max: Double)
+    {
+        let yMin = min
+        let yMax = max
+
+        let labelCount = axis.labelCount
+        let range = abs(yMax - yMin)
+
+        guard
+            labelCount != 0,
+            range > 0,
+            range.isFinite
+            else
+        {
+            axis.entries = []
+            axis.centeredEntries = []
+            return
+        }
+
+        // Find out how much spacing (in y value space) between axis values
+        let rawInterval = range / Double(labelCount)
+        var interval = rawInterval.roundedToNextSignificant()
+
+        // If granularity is enabled, then do not allow the interval to go below specified granularity.
+        // This is used to avoid repeated values when rounding values for display.
+        if axis.granularityEnabled
+        {
+            interval = Swift.max(interval, axis.granularity)
+        }
+
+        // Normalize interval
+        let intervalMagnitude = pow(10.0, Double(Int(log10(interval)))).roundedToNextSignificant()
+        let intervalSigDigit = Int(interval / intervalMagnitude)
+        if intervalSigDigit > 5
+        {
+            // Use one order of magnitude higher, to avoid intervals like 0.9 or 90
+            interval = floor(10.0 * Double(intervalMagnitude))
+        }
+
+        var n = axis.centerAxisLabelsEnabled ? 1 : 0
+
+        // force label count
+        if axis.isForceLabelsEnabled
+        {
+            interval = Double(range) / Double(labelCount - 1)
+
+            // Ensure stops contains at least n elements.
+            axis.entries.removeAll(keepingCapacity: true)
+            axis.entries.reserveCapacity(labelCount)
+
+            let values = stride(from: yMin, to: Double(labelCount) * interval + yMin, by: interval)
+            axis.entries.append(contentsOf: values)
+
+            n = labelCount
+        }
+        else
+        {
+            // no forced count
+
+            var first = interval == 0.0 ? 0.0 : ceil(yMin / interval) * interval
+
+            if axis.centerAxisLabelsEnabled
+            {
+                first -= interval
+            }
+
+            let last = interval == 0.0 ? 0.0 : (floor(yMax / interval) * interval).nextUp
+
+            if interval != 0.0, last != first
+            {
+                stride(from: first, through: last, by: interval).forEach { _ in n += 1 }
+            }
+
+            // Ensure stops contains at least n elements.
+            axis.entries.removeAll(keepingCapacity: true)
+            axis.entries.reserveCapacity(labelCount)
+
+            // Fix for IEEE negative zero case (Where value == -0.0, and 0.0 == -0.0)
+            let values = stride(from: first, to: Double(n) * interval + first, by: interval).map { $0 == 0.0 ? 0.0 : $0 }
+            axis.entries.append(contentsOf: values)
+        }
+
+        // set decimals
+        if interval < 1
+        {
+            axis.decimals = Int(ceil(-log10(interval)))
+        }
+        else
+        {
+            axis.decimals = 0
+        }
+
+        if axis.centerAxisLabelsEnabled
+        {
+            axis.centeredEntries.reserveCapacity(n)
+            axis.centeredEntries.removeAll()
+
+            let offset: Double = interval / 2.0
+            axis.centeredEntries.append(contentsOf: axis.entries.map { $0 + offset })
         }
-        
-        context.restoreGState()
     }
 }

+ 114 - 188
Pods/Charts/Source/Charts/Renderers/YAxisRendererHorizontalBarChart.swift

@@ -14,34 +14,26 @@ import CoreGraphics
 
 open class YAxisRendererHorizontalBarChart: YAxisRenderer
 {
-    public override init(viewPortHandler: ViewPortHandler, yAxis: YAxis?, transformer: Transformer?)
+    public override init(viewPortHandler: ViewPortHandler, axis: YAxis, transformer: Transformer?)
     {
-        super.init(viewPortHandler: viewPortHandler, yAxis: yAxis, transformer: transformer)
+        super.init(viewPortHandler: viewPortHandler, axis: axis, transformer: transformer)
     }
 
     /// Computes the axis values.
     open override func computeAxis(min: Double, max: Double, inverted: Bool)
     {
-        guard let transformer = self.transformer else { return }
-        
         var min = min, max = max
         
         // calculate the starting and entry point of the y-labels (depending on zoom / contentrect bounds)
-        if viewPortHandler.contentHeight > 10.0 && !viewPortHandler.isFullyZoomedOutX
+        if let transformer = transformer,
+            viewPortHandler.contentHeight > 10.0,
+            !viewPortHandler.isFullyZoomedOutX
         {
             let p1 = transformer.valueForTouchPoint(CGPoint(x: viewPortHandler.contentLeft, y: viewPortHandler.contentTop))
             let p2 = transformer.valueForTouchPoint(CGPoint(x: viewPortHandler.contentRight, y: viewPortHandler.contentTop))
-            
-            if !inverted
-            {
-                min = Double(p1.x)
-                max = Double(p2.x)
-            }
-            else
-            {
-                min = Double(p2.x)
-                max = Double(p1.x)
-            }
+
+            min = inverted ? Double(p2.x) : Double(p1.x)
+            max = inverted ? Double(p1.x) : Double(p2.x)
         }
         
         computeAxisValues(min: min, max: max)
@@ -50,92 +42,77 @@ open class YAxisRendererHorizontalBarChart: YAxisRenderer
     /// draws the y-axis labels to the screen
     open override func renderAxisLabels(context: CGContext)
     {
-        guard let yAxis = axis as? YAxis else { return }
-        
-        if !yAxis.isEnabled || !yAxis.isDrawLabelsEnabled
-        {
-            return
-        }
-        
-        let lineHeight = yAxis.labelFont.lineHeight
+        guard
+            axis.isEnabled,
+            axis.isDrawLabelsEnabled
+            else { return }
+
+        let lineHeight = axis.labelFont.lineHeight
         let baseYOffset: CGFloat = 2.5
         
-        let dependency = yAxis.axisDependency
-        let labelPosition = yAxis.labelPosition
-        
-        var yPos: CGFloat = 0.0
+        let dependency = axis.axisDependency
+        let labelPosition = axis.labelPosition
         
-        if dependency == .left
-        {
-            if labelPosition == .outsideChart
-            {
-                yPos = viewPortHandler.contentTop - baseYOffset
-            }
-            else
-            {
-                yPos = viewPortHandler.contentTop - baseYOffset
-            }
-        }
-        else
+        // Comparing with Android code, the code here is slightly different about lineHeight
+        let yPos: CGFloat =
         {
-            if labelPosition == .outsideChart
-            {
-                yPos = viewPortHandler.contentBottom + lineHeight + baseYOffset
-            }
-            else
+            switch (dependency, labelPosition)
             {
-                yPos = viewPortHandler.contentBottom + lineHeight + baseYOffset
+            case (.left, .outsideChart):
+                return viewPortHandler.contentTop - baseYOffset - lineHeight
+
+            case (.left, .insideChart):
+                return viewPortHandler.contentTop - baseYOffset - lineHeight
+
+            case (.right, .outsideChart):
+                return viewPortHandler.contentBottom + baseYOffset
+
+            case (.right, .insideChart):
+                return viewPortHandler.contentBottom + baseYOffset
             }
-        }
-        
-        // For compatibility with Android code, we keep above calculation the same,
-        // And here we pull the line back up
-        yPos -= lineHeight
-        
+        }()
+
         drawYLabels(
             context: context,
             fixedPosition: yPos,
             positions: transformedPositions(),
-            offset: yAxis.yOffset)
+            offset: axis.yOffset
+        )
     }
     
     open override func renderAxisLine(context: CGContext)
     {
-        guard let yAxis = axis as? YAxis else { return }
-        
-        if !yAxis.isEnabled || !yAxis.drawAxisLineEnabled
-        {
-            return
-        }
-        
+        guard
+            axis.isEnabled,
+            axis.drawAxisLineEnabled
+            else { return }
+
         context.saveGState()
+        defer { context.restoreGState() }
         
-        context.setStrokeColor(yAxis.axisLineColor.cgColor)
-        context.setLineWidth(yAxis.axisLineWidth)
-        if yAxis.axisLineDashLengths != nil
+        context.setStrokeColor(axis.axisLineColor.cgColor)
+        context.setLineWidth(axis.axisLineWidth)
+        if axis.axisLineDashLengths != nil
         {
-            context.setLineDash(phase: yAxis.axisLineDashPhase, lengths: yAxis.axisLineDashLengths)
+            context.setLineDash(phase: axis.axisLineDashPhase, lengths: axis.axisLineDashLengths)
         }
         else
         {
             context.setLineDash(phase: 0.0, lengths: [])
         }
 
-        if yAxis.axisDependency == .left
+        context.beginPath()
+        if axis.axisDependency == .left
         {
-            context.beginPath()
             context.move(to: CGPoint(x: viewPortHandler.contentLeft, y: viewPortHandler.contentTop))
             context.addLine(to: CGPoint(x: viewPortHandler.contentRight, y: viewPortHandler.contentTop))
-            context.strokePath()
         }
         else
         {
-            context.beginPath()
             context.move(to: CGPoint(x: viewPortHandler.contentLeft, y: viewPortHandler.contentBottom))
             context.addLine(to: CGPoint(x: viewPortHandler.contentRight, y: viewPortHandler.contentBottom))
-            context.strokePath()        }
-        
-        context.restoreGState()
+        }
+        context.strokePath()
     }
 
     /// draws the y-labels on the specified x-position
@@ -145,38 +122,28 @@ open class YAxisRendererHorizontalBarChart: YAxisRenderer
         positions: [CGPoint],
         offset: CGFloat)
     {
-        guard let
-            yAxis = axis as? YAxis
-            else { return }
+        let labelFont = axis.labelFont
+        let labelTextColor = axis.labelTextColor
         
-        let labelFont = yAxis.labelFont
-        let labelTextColor = yAxis.labelTextColor
+        let from = axis.isDrawBottomYLabelEntryEnabled ? 0 : 1
+        let to = axis.isDrawTopYLabelEntryEnabled ? axis.entryCount : (axis.entryCount - 1)
         
-        let from = yAxis.isDrawBottomYLabelEntryEnabled ? 0 : 1
-        let to = yAxis.isDrawTopYLabelEntryEnabled ? yAxis.entryCount : (yAxis.entryCount - 1)
+        let xOffset = axis.labelXOffset
         
-        let xOffset = yAxis.labelXOffset
-        
-        for i in stride(from: from, to: to, by: 1)
+        for i in from..<to
         {
-            let text = yAxis.getFormattedLabel(i)
-            
-            ChartUtils.drawText(
-                context: context,
-                text: text,
-                point: CGPoint(
-                    x: positions[i].x, y:
-                    fixedPosition - offset + xOffset
-                ),
-                align: .center,
-                attributes: [NSAttributedString.Key.font: labelFont, NSAttributedString.Key.foregroundColor: labelTextColor])
+            let text = axis.getFormattedLabel(i)
+            context.drawText(text,
+                             at: CGPoint(x: positions[i].x, y: fixedPosition - offset + xOffset),
+                             align: .center,
+                             attributes: [.font: labelFont, .foregroundColor: labelTextColor])
         }
     }
     
     open override var gridClippingRect: CGRect
     {
         var contentRect = viewPortHandler.contentRect
-        let dx = self.axis?.gridLineWidth ?? 0.0
+        let dx = self.axis.gridLineWidth
         contentRect.origin.x -= dx / 2.0
         contentRect.size.width += dx
         return contentRect
@@ -194,21 +161,9 @@ open class YAxisRendererHorizontalBarChart: YAxisRenderer
     
     open override func transformedPositions() -> [CGPoint]
     {
-        guard
-            let yAxis = self.axis as? YAxis,
-            let transformer = self.transformer
-            else { return [CGPoint]() }
-        
-        var positions = [CGPoint]()
-        positions.reserveCapacity(yAxis.entryCount)
-        
-        let entries = yAxis.entries
-        
-        for i in stride(from: 0, to: yAxis.entryCount, by: 1)
-        {
-            positions.append(CGPoint(x: entries[i], y: 0.0))
-        }
+        guard let transformer = self.transformer else { return [] }
         
+        var positions = axis.entries.map { CGPoint(x: $0, y: 0.0) }
         transformer.pointValuesToPixel(&positions)
         
         return positions
@@ -218,27 +173,26 @@ open class YAxisRendererHorizontalBarChart: YAxisRenderer
     open override func drawZeroLine(context: CGContext)
     {
         guard
-            let yAxis = self.axis as? YAxis,
             let transformer = self.transformer,
-            let zeroLineColor = yAxis.zeroLineColor
+            let zeroLineColor = axis.zeroLineColor
             else { return }
         
         context.saveGState()
         defer { context.restoreGState() }
         
         var clippingRect = viewPortHandler.contentRect
-        clippingRect.origin.x -= yAxis.zeroLineWidth / 2.0
-        clippingRect.size.width += yAxis.zeroLineWidth
+        clippingRect.origin.x -= axis.zeroLineWidth / 2.0
+        clippingRect.size.width += axis.zeroLineWidth
         context.clip(to: clippingRect)
         
         context.setStrokeColor(zeroLineColor.cgColor)
-        context.setLineWidth(yAxis.zeroLineWidth)
+        context.setLineWidth(axis.zeroLineWidth)
         
         let pos = transformer.pixelForValues(x: 0.0, y: 0.0)
         
-        if yAxis.zeroLineDashLengths != nil
+        if axis.zeroLineDashLengths != nil
         {
-            context.setLineDash(phase: yAxis.zeroLineDashPhase, lengths: yAxis.zeroLineDashLengths!)
+            context.setLineDash(phase: axis.zeroLineDashPhase, lengths: axis.zeroLineDashLengths!)
         }
         else
         {
@@ -247,40 +201,25 @@ open class YAxisRendererHorizontalBarChart: YAxisRenderer
         
         context.move(to: CGPoint(x: pos.x - 1.0, y: viewPortHandler.contentTop))
         context.addLine(to: CGPoint(x: pos.x - 1.0, y: viewPortHandler.contentBottom))
-        context.drawPath(using: CGPathDrawingMode.stroke)
+        context.drawPath(using: .stroke)
     }
-    
-    private var _limitLineSegmentsBuffer = [CGPoint](repeating: CGPoint(), count: 2)
-    
+        
     open override func renderLimitLines(context: CGContext)
     {
-        guard
-            let yAxis = axis as? YAxis,
-            let transformer = self.transformer
-            else { return }
+        guard let transformer = self.transformer else { return }
         
-        let limitLines = yAxis.limitLines
+        let limitLines = axis.limitLines
+
+        guard !limitLines.isEmpty else { return }
 
-        if limitLines.count <= 0
-        {
-            return
-        }
-        
         context.saveGState()
-        
+        defer { context.restoreGState() }
+
         let trans = transformer.valueToPixelMatrix
-        
-        var position = CGPoint(x: 0.0, y: 0.0)
-        
-        for i in 0 ..< limitLines.count
+        var position = CGPoint.zero
+
+        for l in limitLines where l.isEnabled
         {
-            let l = limitLines[i]
-            
-            if !l.isEnabled
-            {
-                continue
-            }
-            
             context.saveGState()
             defer { context.restoreGState() }
 
@@ -288,11 +227,10 @@ open class YAxisRendererHorizontalBarChart: YAxisRenderer
             clippingRect.origin.x -= l.lineWidth / 2.0
             clippingRect.size.width += l.lineWidth
             context.clip(to: clippingRect)
-            
-            position.x = CGFloat(l.limit)
-            position.y = 0.0
-            position = position.applying(trans)
-            
+
+            position = CGPoint(x: l.limit, y: 0)
+                .applying(trans)
+
             context.beginPath()
             context.move(to: CGPoint(x: position.x, y: viewPortHandler.contentTop))
             context.addLine(to: CGPoint(x: position.x, y: viewPortHandler.contentBottom))
@@ -313,56 +251,44 @@ open class YAxisRendererHorizontalBarChart: YAxisRenderer
             let label = l.label
 
             // if drawing the limit-value label is enabled
-            if l.drawLabelEnabled && label.count > 0
+            if l.drawLabelEnabled, !label.isEmpty
             {
                 let labelLineHeight = l.valueFont.lineHeight
                 
-                let xOffset: CGFloat = l.lineWidth + l.xOffset
-                let yOffset: CGFloat = 2.0 + l.yOffset
+                let xOffset = l.lineWidth + l.xOffset
+                let yOffset = 2.0 + l.yOffset
 
-                if l.labelPosition == .topRight
-                {
-                    ChartUtils.drawText(context: context,
-                        text: label,
-                        point: CGPoint(
-                            x: position.x + xOffset,
-                            y: viewPortHandler.contentTop + yOffset),
-                        align: .left,
-                        attributes: [NSAttributedString.Key.font: l.valueFont, NSAttributedString.Key.foregroundColor: l.valueTextColor])
-                }
-                else if l.labelPosition == .bottomRight
-                {
-                    ChartUtils.drawText(context: context,
-                        text: label,
-                        point: CGPoint(
-                            x: position.x + xOffset,
-                            y: viewPortHandler.contentBottom - labelLineHeight - yOffset),
-                        align: .left,
-                        attributes: [NSAttributedString.Key.font: l.valueFont, NSAttributedString.Key.foregroundColor: l.valueTextColor])
-                }
-                else if l.labelPosition == .topLeft
-                {
-                    ChartUtils.drawText(context: context,
-                        text: label,
-                        point: CGPoint(
-                            x: position.x - xOffset,
-                            y: viewPortHandler.contentTop + yOffset),
-                        align: .right,
-                        attributes: [NSAttributedString.Key.font: l.valueFont, NSAttributedString.Key.foregroundColor: l.valueTextColor])
-                }
-                else
+                let align: TextAlignment
+                let point: CGPoint
+
+                switch l.labelPosition
                 {
-                    ChartUtils.drawText(context: context,
-                        text: label,
-                        point: CGPoint(
-                            x: position.x - xOffset,
-                            y: viewPortHandler.contentBottom - labelLineHeight - yOffset),
-                        align: .right,
-                        attributes: [NSAttributedString.Key.font: l.valueFont, NSAttributedString.Key.foregroundColor: l.valueTextColor])
+                case .rightTop:
+                    align = .left
+                    point = CGPoint(x: position.x + xOffset,
+                                    y: viewPortHandler.contentTop + yOffset)
+
+                case .rightBottom:
+                    align = .left
+                    point = CGPoint(x: position.x + xOffset,
+                                    y: viewPortHandler.contentBottom - labelLineHeight - yOffset)
+
+                case .leftTop:
+                    align = .right
+                    point = CGPoint(x: position.x - xOffset,
+                                    y: viewPortHandler.contentTop + yOffset)
+
+                case .leftBottom:
+                    align = .right
+                    point = CGPoint(x: position.x - xOffset,
+                                    y: viewPortHandler.contentBottom - labelLineHeight - yOffset)
                 }
+
+                context.drawText(label,
+                                 at: point,
+                                 align: align,
+                                 attributes: [.font: l.valueFont, .foregroundColor: l.valueTextColor])
             }
         }
-        
-        context.restoreGState()
     }
 }

+ 60 - 121
Pods/Charts/Source/Charts/Renderers/YAxisRendererRadarChart.swift

@@ -12,54 +12,46 @@
 import Foundation
 import CoreGraphics
 
-#if canImport(UIKit)
-    import UIKit
-#endif
-
-#if canImport(Cocoa)
-import Cocoa
-#endif
 
 open class YAxisRendererRadarChart: YAxisRenderer
 {
     private weak var chart: RadarChartView?
     
-    @objc public init(viewPortHandler: ViewPortHandler, yAxis: YAxis?, chart: RadarChartView)
+    @objc public init(viewPortHandler: ViewPortHandler, axis: YAxis, chart: RadarChartView)
     {
-        super.init(viewPortHandler: viewPortHandler, yAxis: yAxis, transformer: nil)
-        
         self.chart = chart
+
+        super.init(viewPortHandler: viewPortHandler, axis: axis, transformer: nil)
     }
     
     open override func computeAxisValues(min yMin: Double, max yMax: Double)
     {
-        guard let
-            axis = axis as? YAxis
-            else { return }
-        
         let labelCount = axis.labelCount
         let range = abs(yMax - yMin)
         
-        if labelCount == 0 || range <= 0 || range.isInfinite
+        guard labelCount != 0,
+            range > 0,
+            range.isFinite
+            else
         {
-            axis.entries = [Double]()
-            axis.centeredEntries = [Double]()
+            axis.entries = []
+            axis.centeredEntries = []
             return
         }
         
         // Find out how much spacing (in yValue space) between axis values
         let rawInterval = range / Double(labelCount)
-        var interval = rawInterval.roundedToNextSignficant()
-        
+        var interval = rawInterval.roundedToNextSignificant()
+
         // If granularity is enabled, then do not allow the interval to go below specified granularity.
         // This is used to avoid repeated values when rounding values for display.
         if axis.isGranularityEnabled
         {
-            interval = interval < axis.granularity ? axis.granularity : interval
+            interval = max(interval, axis.granularity)
         }
         
         // Normalize interval
-        let intervalMagnitude = pow(10.0, floor(log10(interval))).roundedToNextSignficant()
+        let intervalMagnitude = pow(10.0, floor(log10(interval))).roundedToNextSignificant()
         let intervalSigDigit = Int(interval / intervalMagnitude)
         
         if intervalSigDigit > 5
@@ -75,19 +67,14 @@ open class YAxisRendererRadarChart: YAxisRenderer
         // force label count
         if axis.isForceLabelsEnabled
         {
-            let step = Double(range) / Double(labelCount - 1)
+            let step = range / Double(labelCount - 1)
             
             // Ensure stops contains at least n elements.
             axis.entries.removeAll(keepingCapacity: true)
             axis.entries.reserveCapacity(labelCount)
-            
-            var v = yMin
-            
-            for _ in 0 ..< labelCount
-            {
-                axis.entries.append(v)
-                v += step
-            }
+
+            let values = stride(from: yMin, to: Double(labelCount) * step + yMin, by: step)
+            axis.entries.append(contentsOf: values)
             
             n = labelCount
         }
@@ -106,10 +93,7 @@ open class YAxisRendererRadarChart: YAxisRenderer
             
             if interval != 0.0
             {
-                for _ in stride(from: first, through: last, by: interval)
-                {
-                    n += 1
-                }
+                stride(from: first, through: last, by: interval).forEach { _ in n += 1 }
             }
             
             n += 1
@@ -117,22 +101,10 @@ open class YAxisRendererRadarChart: YAxisRenderer
             // Ensure stops contains at least n elements.
             axis.entries.removeAll(keepingCapacity: true)
             axis.entries.reserveCapacity(labelCount)
-            
-            var f = first
-            var i = 0
-            while i < n
-            {
-                if f == 0.0
-                {
-                    // Fix for IEEE negative zero case (Where value == -0.0, and 0.0 == -0.0)
-                    f = 0.0
-                }
 
-                axis.entries.append(Double(f))
-                
-                f += interval
-                i += 1
-            }
+            // Fix for IEEE negative zero case (Where value == -0.0, and 0.0 == -0.0)
+            let values = stride(from: first, to: Double(n) * interval + first, by: interval).map { $0 == 0.0 ? 0.0 : $0 }
+            axis.entries.append(contentsOf: values)
         }
         
         // set decimals
@@ -147,85 +119,66 @@ open class YAxisRendererRadarChart: YAxisRenderer
         
         if centeringEnabled
         {
-            axis.centeredEntries.reserveCapacity(n)
-            axis.centeredEntries.removeAll()
-            
             let offset = (axis.entries[1] - axis.entries[0]) / 2.0
-            
-            for i in 0 ..< n
-            {
-                axis.centeredEntries.append(axis.entries[i] + offset)
-            }
+            axis.centeredEntries = axis.entries.map { $0 + offset }
         }
         
-        axis._axisMinimum = axis.entries[0]
-        axis._axisMaximum = axis.entries[n-1]
+        axis._axisMinimum = axis.entries.first!
+        axis._axisMaximum = axis.entries.last!
         axis.axisRange = abs(axis._axisMaximum - axis._axisMinimum)
     }
     
     open override func renderAxisLabels(context: CGContext)
     {
-        guard let
-            yAxis = axis as? YAxis,
-            let chart = chart
+        guard
+            let chart = chart,
+            axis.isEnabled,
+            axis.isDrawLabelsEnabled
             else { return }
-        
-        if !yAxis.isEnabled || !yAxis.isDrawLabelsEnabled
-        {
-            return
-        }
-        
-        let labelFont = yAxis.labelFont
-        let labelTextColor = yAxis.labelTextColor
+
+        let labelFont = axis.labelFont
+        let labelTextColor = axis.labelTextColor
         
         let center = chart.centerOffsets
         let factor = chart.factor
         
-        let labelLineHeight = yAxis.labelFont.lineHeight
+        let labelLineHeight = axis.labelFont.lineHeight
         
-        let from = yAxis.isDrawBottomYLabelEntryEnabled ? 0 : 1
-        let to = yAxis.isDrawTopYLabelEntryEnabled ? yAxis.entryCount : (yAxis.entryCount - 1)
+        let from = axis.isDrawBottomYLabelEntryEnabled ? 0 : 1
+        let to = axis.isDrawTopYLabelEntryEnabled ? axis.entryCount : (axis.entryCount - 1)
 
-        let alignment: NSTextAlignment = yAxis.labelAlignment
-        let xOffset = yAxis.labelXOffset
-        
-        for j in stride(from: from, to: to, by: 1)
-        {
-            let r = CGFloat(yAxis.entries[j] - yAxis._axisMinimum) * factor
-            
+        let alignment = axis.labelAlignment
+        let xOffset = axis.labelXOffset
+
+        let entries = axis.entries[from..<to]
+        entries.indexed().forEach { index, entry in
+            let r = CGFloat(entry - axis._axisMinimum) * factor
             let p = center.moving(distance: r, atAngle: chart.rotationAngle)
-            
-            let label = yAxis.getFormattedLabel(j)
-            
-            ChartUtils.drawText(
-                context: context,
-                text: label,
-                point: CGPoint(x: p.x + xOffset, y: p.y - labelLineHeight),
+            let label = axis.getFormattedLabel(index)
+            context.drawText(
+                label,
+                at: CGPoint(x: p.x + xOffset, y: p.y - labelLineHeight),
                 align: alignment,
-                attributes: [
-                    NSAttributedString.Key.font: labelFont,
-                    NSAttributedString.Key.foregroundColor: labelTextColor
-                ])
+                attributes: [.font: labelFont,
+                             .foregroundColor: labelTextColor]
+            )
         }
     }
     
     open override func renderLimitLines(context: CGContext)
     {
         guard
-            let yAxis = axis as? YAxis,
             let chart = chart,
             let data = chart.data
             else { return }
         
-        let limitLines = yAxis.limitLines
-        
-        if limitLines.count == 0
-        {
-            return
-        }
+        let limitLines = axis.limitLines
         
+        guard !limitLines.isEmpty else { return }
+
         context.saveGState()
-        
+        defer { context.restoreGState() }
+
         let sliceangle = chart.sliceAngle
         
         // calculate the factor that is needed for transforming the value to pixels
@@ -233,15 +186,8 @@ open class YAxisRendererRadarChart: YAxisRenderer
         
         let center = chart.centerOffsets
         
-        for i in 0 ..< limitLines.count
+        for l in limitLines where l.isEnabled
         {
-            let l = limitLines[i]
-            
-            if !l.isEnabled
-            {
-                continue
-            }
-            
             context.setStrokeColor(l.lineColor.cgColor)
             context.setLineWidth(l.lineWidth)
             if l.lineDashLengths != nil
@@ -257,25 +203,18 @@ open class YAxisRendererRadarChart: YAxisRenderer
             
             context.beginPath()
             
-            for j in 0 ..< (data.maxEntryCountSet?.entryCount ?? 0)
+            for i in 0 ..< (data.maxEntryCountSet?.entryCount ?? 0)
             {
-                let p = center.moving(distance: r, atAngle: sliceangle * CGFloat(j) + chart.rotationAngle)
-                
-                if j == 0
-                {
-                    context.move(to: CGPoint(x: p.x, y: p.y))
-                }
-                else
-                {
-                    context.addLine(to: CGPoint(x: p.x, y: p.y))
-                }
+                let p = center.moving(
+                    distance: r,
+                    atAngle: sliceangle * CGFloat(i) + chart.rotationAngle
+                )
+
+                i == 0 ? context.move(to: p) : context.addLine(to: p)
             }
             
             context.closePath()
-            
             context.strokePath()
         }
-        
-        context.restoreGState()
     }
 }

+ 24 - 28
Pods/Charts/Source/Charts/Utils/ChartColorTemplates.swift

@@ -89,41 +89,37 @@ open class ChartColorTemplates: NSObject
         if colorString.hasPrefix("#")
         {
             var argb: [UInt] = [255, 0, 0, 0]
-            let colorString = colorString.unicodeScalars
-            var length = colorString.count
+            let colorString = colorString.unicodeScalars.dropFirst()
+            let length = colorString.count
             var index = colorString.startIndex
             let endIndex = colorString.endIndex
-            
-            index = colorString.index(after: index)
-            length = length - 1
-            
-            if length == 3 || length == 6 || length == 8
+
+            guard [3, 6, 8].contains(length) else { return .black }
+
+            var i = length == 8 ? 0 : 1
+            while index < endIndex
             {
-                var i = length == 8 ? 0 : 1
-                while index < endIndex
+                var c = colorString[index]
+                index = colorString.index(after: index)
+
+                var val = (c.value >= 0x61 && c.value <= 0x66) ? (c.value - 0x61 + 10) : c.value - 0x30
+                argb[i] = UInt(val) * 16
+                if length == 3
+                {
+                    argb[i] = argb[i] + UInt(val)
+                }
+                else
                 {
-                    var c = colorString[index]
+                    c = colorString[index]
                     index = colorString.index(after: index)
-                    
-                    var val = (c.value >= 0x61 && c.value <= 0x66) ? (c.value - 0x61 + 10) : c.value - 0x30
-                    argb[i] = UInt(val) * 16
-                    if length == 3
-                    {
-                        argb[i] = argb[i] + UInt(val)
-                    }
-                    else
-                    {
-                        c = colorString[index]
-                        index = colorString.index(after: index)
-                        
-                        val = (c.value >= 0x61 && c.value <= 0x66) ? (c.value - 0x61 + 10) : c.value - 0x30
-                        argb[i] = argb[i] + UInt(val)
-                    }
-                    
-                    i += 1
+
+                    val = (c.value >= 0x61 && c.value <= 0x66) ? (c.value - 0x61 + 10) : c.value - 0x30
+                    argb[i] = argb[i] + UInt(val)
                 }
+
+                i += 1
             }
-            
+
             return NSUIColor(red: CGFloat(argb[1]) / 255.0, green: CGFloat(argb[2]) / 255.0, blue: CGFloat(argb[3]) / 255.0, alpha: CGFloat(argb[0]) / 255.0)
         }
         else if colorString.hasPrefix("rgba")

+ 83 - 96
Pods/Charts/Source/Charts/Utils/ChartUtils.swift

@@ -12,14 +12,6 @@
 import Foundation
 import CoreGraphics
 
-#if canImport(UIKit)
-    import UIKit
-#endif
-
-#if canImport(Cocoa)
-import Cocoa
-#endif
-
 extension Comparable
 {
     func clamped(to range: ClosedRange<Self>) -> Self
@@ -80,7 +72,7 @@ extension CGSize
 extension Double
 {
     /// Rounds the number to the nearest multiple of it's order of magnitude, rounding away from zero if halfway.
-    func roundedToNextSignficant() -> Double
+    func roundedToNextSignificant() -> Double
     {
         guard
             !isInfinite,
@@ -103,7 +95,7 @@ extension Double
             self != 0.0
             else { return 0 }
 
-        let i = self.roundedToNextSignficant()
+        let i = roundedToNextSignificant()
 
         guard
             !i.isInfinite,
@@ -124,155 +116,162 @@ extension CGPoint
     }
 }
 
-open class ChartUtils
+extension CGContext
 {
-    private static var _defaultValueFormatter: IValueFormatter = ChartUtils.generateDefaultValueFormatter()
-    
-    open class func drawImage(
-        context: CGContext,
-        image: NSUIImage,
-        x: CGFloat,
-        y: CGFloat,
-        size: CGSize)
+
+    public func drawImage(_ image: NSUIImage, atCenter center: CGPoint, size: CGSize)
     {
         var drawOffset = CGPoint()
-        drawOffset.x = x - (size.width / 2)
-        drawOffset.y = y - (size.height / 2)
-        
-        NSUIGraphicsPushContext(context)
-        
+        drawOffset.x = center.x - (size.width / 2)
+        drawOffset.y = center.y - (size.height / 2)
+
+        NSUIGraphicsPushContext(self)
+
         if image.size.width != size.width && image.size.height != size.height
         {
             let key = "resized_\(size.width)_\(size.height)"
-            
+
             // Try to take scaled image from cache of this image
             var scaledImage = objc_getAssociatedObject(image, key) as? NSUIImage
             if scaledImage == nil
             {
                 // Scale the image
                 NSUIGraphicsBeginImageContextWithOptions(size, false, 0.0)
-                
-                image.draw(in: CGRect(origin: CGPoint(x: 0, y: 0), size: size))
-                
+
+                image.draw(in: CGRect(origin: .zero, size: size))
+
                 scaledImage = NSUIGraphicsGetImageFromCurrentImageContext()
                 NSUIGraphicsEndImageContext()
-                
+
                 // Put the scaled image in a cache owned by the original image
                 objc_setAssociatedObject(image, key, scaledImage, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
             }
-            
+
             scaledImage?.draw(in: CGRect(origin: drawOffset, size: size))
         }
         else
         {
             image.draw(in: CGRect(origin: drawOffset, size: size))
         }
-        
+
         NSUIGraphicsPopContext()
     }
-    
-    open class func drawText(context: CGContext, text: String, point: CGPoint, align: NSTextAlignment, attributes: [NSAttributedString.Key : Any]?)
+
+    public func drawText(_ text: String, at point: CGPoint, align: TextAlignment, anchor: CGPoint = CGPoint(x: 0.5, y: 0.5), angleRadians: CGFloat = 0.0, attributes: [NSAttributedString.Key : Any]?)
     {
-        var point = point
+        let drawPoint = getDrawPoint(text: text, point: point, align: align, attributes: attributes)
         
-        if align == .center
+        if (angleRadians == 0.0)
         {
-            point.x -= text.size(withAttributes: attributes).width / 2.0
+            NSUIGraphicsPushContext(self)
+            
+            (text as NSString).draw(at: drawPoint, withAttributes: attributes)
+            
+            NSUIGraphicsPopContext()
         }
-        else if align == .right
+        else
         {
-            point.x -= text.size(withAttributes: attributes).width
+            drawText(text, at: drawPoint, anchor: anchor, angleRadians: angleRadians, attributes: attributes)
         }
-        
-        NSUIGraphicsPushContext(context)
-        
-        (text as NSString).draw(at: point, withAttributes: attributes)
-        
-        NSUIGraphicsPopContext()
     }
     
-    open class func drawText(context: CGContext, text: String, point: CGPoint, attributes: [NSAttributedString.Key : Any]?, anchor: CGPoint, angleRadians: CGFloat)
+    public func drawText(_ text: String, at point: CGPoint, anchor: CGPoint = CGPoint(x: 0.5, y: 0.5), angleRadians: CGFloat, attributes: [NSAttributedString.Key : Any]?)
     {
         var drawOffset = CGPoint()
-        
-        NSUIGraphicsPushContext(context)
-        
+
+        NSUIGraphicsPushContext(self)
+
         if angleRadians != 0.0
         {
             let size = text.size(withAttributes: attributes)
-            
+
             // Move the text drawing rect in a way that it always rotates around its center
             drawOffset.x = -size.width * 0.5
             drawOffset.y = -size.height * 0.5
-            
+
             var translate = point
-            
+
             // Move the "outer" rect relative to the anchor, assuming its centered
             if anchor.x != 0.5 || anchor.y != 0.5
             {
                 let rotatedSize = size.rotatedBy(radians: angleRadians)
-                
+
                 translate.x -= rotatedSize.width * (anchor.x - 0.5)
                 translate.y -= rotatedSize.height * (anchor.y - 0.5)
             }
-            
-            context.saveGState()
-            context.translateBy(x: translate.x, y: translate.y)
-            context.rotate(by: angleRadians)
-            
+
+            saveGState()
+            translateBy(x: translate.x, y: translate.y)
+            rotate(by: angleRadians)
+
             (text as NSString).draw(at: drawOffset, withAttributes: attributes)
-            
-            context.restoreGState()
+
+            restoreGState()
         }
         else
         {
             if anchor.x != 0.0 || anchor.y != 0.0
             {
                 let size = text.size(withAttributes: attributes)
-                
+
                 drawOffset.x = -size.width * anchor.x
                 drawOffset.y = -size.height * anchor.y
             }
-            
+
             drawOffset.x += point.x
             drawOffset.y += point.y
-            
+
             (text as NSString).draw(at: drawOffset, withAttributes: attributes)
         }
-        
+
         NSUIGraphicsPopContext()
     }
-    
-    internal class func drawMultilineText(context: CGContext, text: String, knownTextSize: CGSize, point: CGPoint, attributes: [NSAttributedString.Key : Any]?, constrainedToSize: CGSize, anchor: CGPoint, angleRadians: CGFloat)
+
+    private func getDrawPoint(text: String, point: CGPoint, align: TextAlignment, attributes: [NSAttributedString.Key : Any]?) -> CGPoint
     {
-        var rect = CGRect(origin: CGPoint(), size: knownTextSize)
-        
-        NSUIGraphicsPushContext(context)
+        var point = point
         
+        if align == .center
+        {
+            point.x -= text.size(withAttributes: attributes).width / 2.0
+        }
+        else if align == .right
+        {
+            point.x -= text.size(withAttributes: attributes).width
+        }
+        return point
+    }
+    
+    func drawMultilineText(_ text: String, at point: CGPoint, constrainedTo size: CGSize, anchor: CGPoint, knownTextSize: CGSize, angleRadians: CGFloat, attributes: [NSAttributedString.Key : Any]?)
+    {
+        var rect = CGRect(origin: .zero, size: knownTextSize)
+
+        NSUIGraphicsPushContext(self)
+
         if angleRadians != 0.0
         {
             // Move the text drawing rect in a way that it always rotates around its center
             rect.origin.x = -knownTextSize.width * 0.5
             rect.origin.y = -knownTextSize.height * 0.5
-            
+
             var translate = point
-            
+
             // Move the "outer" rect relative to the anchor, assuming its centered
             if anchor.x != 0.5 || anchor.y != 0.5
             {
                 let rotatedSize = knownTextSize.rotatedBy(radians: angleRadians)
-                
+
                 translate.x -= rotatedSize.width * (anchor.x - 0.5)
                 translate.y -= rotatedSize.height * (anchor.y - 0.5)
             }
-            
-            context.saveGState()
-            context.translateBy(x: translate.x, y: translate.y)
-            context.rotate(by: angleRadians)
-            
+
+            saveGState()
+            translateBy(x: translate.x, y: translate.y)
+            rotate(by: angleRadians)
+
             (text as NSString).draw(with: rect, options: .usesLineFragmentOrigin, attributes: attributes, context: nil)
-            
-            context.restoreGState()
+
+            restoreGState()
         }
         else
         {
@@ -281,31 +280,19 @@ open class ChartUtils
                 rect.origin.x = -knownTextSize.width * anchor.x
                 rect.origin.y = -knownTextSize.height * anchor.y
             }
-            
+
             rect.origin.x += point.x
             rect.origin.y += point.y
-            
+
             (text as NSString).draw(with: rect, options: .usesLineFragmentOrigin, attributes: attributes, context: nil)
         }
-        
+
         NSUIGraphicsPopContext()
     }
-    
-    internal class func drawMultilineText(context: CGContext, text: String, point: CGPoint, attributes: [NSAttributedString.Key : Any]?, constrainedToSize: CGSize, anchor: CGPoint, angleRadians: CGFloat)
-    {
-        let rect = text.boundingRect(with: constrainedToSize, options: .usesLineFragmentOrigin, attributes: attributes, context: nil)
-        drawMultilineText(context: context, text: text, knownTextSize: rect.size, point: point, attributes: attributes, constrainedToSize: constrainedToSize, anchor: anchor, angleRadians: angleRadians)
-    }
 
-    private class func generateDefaultValueFormatter() -> IValueFormatter
-    {
-        let formatter = DefaultValueFormatter(decimals: 1)
-        return formatter
-    }
-    
-    /// - Returns: The default value formatter used for all chart components that needs a default
-    open class func defaultValueFormatter() -> IValueFormatter
+    func drawMultilineText(_ text: String, at point: CGPoint, constrainedTo size: CGSize, anchor: CGPoint, angleRadians: CGFloat, attributes: [NSAttributedString.Key : Any]?)
     {
-        return _defaultValueFormatter
+        let rect = text.boundingRect(with: size, options: .usesLineFragmentOrigin, attributes: attributes, context: nil)
+        drawMultilineText(text, at: point, constrainedTo: size, anchor: anchor, knownTextSize: rect.size, angleRadians: angleRadians, attributes: attributes)
     }
 }

+ 159 - 272
Pods/Charts/Source/Charts/Utils/Fill.swift

@@ -12,312 +12,199 @@
 import Foundation
 import CoreGraphics
 
-@objc(ChartFillType)
-public enum FillType: Int
+@objc(ChartFill)
+public protocol Fill
 {
-    case empty
-    case color
-    case linearGradient
-    case radialGradient
-    case image
-    case tiledImage
-    case layer
+
+    /// Draws the provided path in filled mode with the provided area
+    @objc func fillPath(context: CGContext, rect: CGRect)
 }
 
-@objc(ChartFill)
-open class Fill: NSObject
+@objc(ChartEmptyFill)
+public class EmptyFill: NSObject, Fill
 {
-    private var _type: FillType = FillType.empty
-    private var _color: CGColor?
-    private var _gradient: CGGradient?
-    private var _gradientAngle: CGFloat = 0.0
-    private var _gradientStartOffsetPercent: CGPoint = CGPoint()
-    private var _gradientStartRadiusPercent: CGFloat = 0.0
-    private var _gradientEndOffsetPercent: CGPoint = CGPoint()
-    private var _gradientEndRadiusPercent: CGFloat = 0.0
-    private var _image: CGImage?
-    private var _layer: CGLayer?
-    
-    // MARK: Properties
-    
-    @objc open var type: FillType
-    {
-        return _type
-    }
-    
-    @objc open var color: CGColor?
-    {
-        return _color
-    }
-    
-    @objc open var gradient: CGGradient?
-    {
-        return _gradient
-    }
-    
-    @objc open var gradientAngle: CGFloat
-    {
-        return _gradientAngle
-    }
-    
-    @objc open var gradientStartOffsetPercent: CGPoint
+
+    public func fillPath(context: CGContext, rect: CGRect) { }
+}
+
+@objc(ChartColorFill)
+public class ColorFill: NSObject, Fill
+{
+
+    @objc public let color: CGColor
+
+    @objc public init(cgColor: CGColor)
     {
-        return _gradientStartOffsetPercent
+        self.color = cgColor
+        super.init()
     }
-    
-    @objc open var gradientStartRadiusPercent: CGFloat
+
+    @objc public convenience init(color: NSUIColor)
     {
-        return _gradientStartRadiusPercent
+        self.init(cgColor: color.cgColor)
     }
-    
-    @objc open var gradientEndOffsetPercent: CGPoint
+
+    public func fillPath(context: CGContext, rect: CGRect)
     {
-        return _gradientEndOffsetPercent
+        context.saveGState()
+        defer { context.restoreGState() }
+
+        context.setFillColor(color)
+        context.fillPath()
     }
-    
-    @objc open var gradientEndRadiusPercent: CGFloat
+}
+
+@objc(ChartImageFill)
+public class ImageFill: NSObject, Fill
+{
+
+    @objc public let image: CGImage
+    @objc public let isTiled: Bool
+
+    @objc public init(cgImage: CGImage, isTiled: Bool = false)
     {
-        return _gradientEndRadiusPercent
+        image = cgImage
+        self.isTiled = isTiled
+        super.init()
     }
-    
-    @objc open var image: CGImage?
+
+    @objc public convenience init(image: NSUIImage, isTiled: Bool = false)
     {
-        return _image
+        self.init(cgImage: image.cgImage!, isTiled: isTiled)
     }
-    
-    @objc open var layer: CGLayer?
+
+    public func fillPath(context: CGContext, rect: CGRect)
     {
-        return _layer
+        context.saveGState()
+        defer { context.restoreGState() }
+
+        context.clip()
+        context.draw(image, in: rect, byTiling: isTiled)
     }
-    
-    // MARK: Constructors
-    
-    public override init()
+}
+
+@objc(ChartLayerFill)
+public class LayerFill: NSObject, Fill
+{
+
+    @objc public let layer: CGLayer
+
+    @objc public init(layer: CGLayer)
     {
+        self.layer = layer
+        super.init()
     }
-    
-    @objc public init(CGColor: CGColor)
+
+    public func fillPath(context: CGContext, rect: CGRect)
     {
-        _type = .color
-        _color = CGColor
+        context.saveGState()
+        defer { context.restoreGState() }
+
+        context.clip()
+        context.draw(layer, in: rect)
     }
-    
-    @objc public convenience init(color: NSUIColor)
+}
+
+@objc(ChartLinearGradientFill)
+public class LinearGradientFill: NSObject, Fill
+{
+
+    @objc public let gradient: CGGradient
+    @objc public let angle: CGFloat
+
+    @objc public init(gradient: CGGradient, angle: CGFloat = 0)
     {
-        self.init(CGColor: color.cgColor)
+        self.gradient = gradient
+        self.angle = angle
+        super.init()
     }
-    
-    @objc public init(linearGradient: CGGradient, angle: CGFloat)
+
+    public func fillPath(context: CGContext, rect: CGRect)
     {
-        _type = .linearGradient
-        _gradient = linearGradient
-        _gradientAngle = angle
+        context.saveGState()
+        defer { context.restoreGState() }
+
+        let radians = (360.0 - angle).DEG2RAD
+        let centerPoint = CGPoint(x: rect.midX, y: rect.midY)
+        let xAngleDelta = cos(radians) * rect.width / 2.0
+        let yAngleDelta = sin(radians) * rect.height / 2.0
+        let startPoint = CGPoint(
+            x: centerPoint.x - xAngleDelta,
+            y: centerPoint.y - yAngleDelta
+        )
+        let endPoint = CGPoint(
+            x: centerPoint.x + xAngleDelta,
+            y: centerPoint.y + yAngleDelta
+        )
+
+        context.clip()
+        context.drawLinearGradient(
+            gradient,
+            start: startPoint,
+            end: endPoint,
+            options: [.drawsAfterEndLocation, .drawsBeforeStartLocation]
+        )
     }
-    
+}
+
+@objc(ChartRadialGradientFill)
+public class RadialGradientFill: NSObject, Fill
+{
+
+    @objc public let gradient: CGGradient
+    @objc public let startOffsetPercent: CGPoint
+    @objc public let endOffsetPercent: CGPoint
+    @objc public let startRadiusPercent: CGFloat
+    @objc public let endRadiusPercent: CGFloat
+
     @objc public init(
-        radialGradient: CGGradient,
+        gradient: CGGradient,
         startOffsetPercent: CGPoint,
-        startRadiusPercent: CGFloat,
         endOffsetPercent: CGPoint,
-        endRadiusPercent: CGFloat
-        )
+        startRadiusPercent: CGFloat,
+        endRadiusPercent: CGFloat)
     {
-        _type = .radialGradient
-        _gradient = radialGradient
-        _gradientStartOffsetPercent = startOffsetPercent
-        _gradientStartRadiusPercent = startRadiusPercent
-        _gradientEndOffsetPercent = endOffsetPercent
-        _gradientEndRadiusPercent = endRadiusPercent
+        self.gradient = gradient
+        self.startOffsetPercent = startOffsetPercent
+        self.endOffsetPercent = endOffsetPercent
+        self.startRadiusPercent = startRadiusPercent
+        self.endRadiusPercent = endRadiusPercent
+        super.init()
     }
-    
-    @objc public convenience init(radialGradient: CGGradient)
+
+    @objc public convenience init(gradient: CGGradient)
     {
         self.init(
-            radialGradient: radialGradient,
-            startOffsetPercent: CGPoint(x: 0.0, y: 0.0),
-            startRadiusPercent: 0.0,
-            endOffsetPercent: CGPoint(x: 0.0, y: 0.0),
-            endRadiusPercent: 1.0
-        )
-    }
-    
-    @objc public init(CGImage: CGImage, tiled: Bool)
-    {
-        _type = tiled ? .tiledImage : .image
-        _image = CGImage
-    }
-    
-    @objc public convenience init(image: NSUIImage, tiled: Bool)
-    {
-        self.init(CGImage: image.cgImage!, tiled: tiled)
-    }
-    
-    @objc public convenience init(CGImage: CGImage)
-    {
-        self.init(CGImage: CGImage, tiled: false)
-    }
-    
-    @objc public convenience init(image: NSUIImage)
-    {
-        self.init(image: image, tiled: false)
-    }
-    
-    @objc public init(CGLayer: CGLayer)
-    {
-        _type = .layer
-        _layer = CGLayer
-    }
-    
-    // MARK: Constructors
-    
-    @objc open class func fillWithCGColor(_ CGColor: CGColor) -> Fill
-    {
-        return Fill(CGColor: CGColor)
-    }
-    
-    @objc open class func fillWithColor(_ color: NSUIColor) -> Fill
-    {
-        return Fill(color: color)
-    }
-    
-    @objc open class func fillWithLinearGradient(
-        _ linearGradient: CGGradient,
-        angle: CGFloat) -> Fill
-    {
-        return Fill(linearGradient: linearGradient, angle: angle)
-    }
-    
-    @objc open class func fillWithRadialGradient(
-        _ radialGradient: CGGradient,
-        startOffsetPercent: CGPoint,
-        startRadiusPercent: CGFloat,
-        endOffsetPercent: CGPoint,
-        endRadiusPercent: CGFloat
-        ) -> Fill
-    {
-        return Fill(
-            radialGradient: radialGradient,
-            startOffsetPercent: startOffsetPercent,
-            startRadiusPercent: startRadiusPercent,
-            endOffsetPercent: endOffsetPercent,
-            endRadiusPercent: endRadiusPercent
+            gradient: gradient,
+            startOffsetPercent: .zero,
+            endOffsetPercent: .zero,
+            startRadiusPercent: 0,
+            endRadiusPercent: 1
         )
     }
-    
-    @objc open class func fillWithRadialGradient(_ radialGradient: CGGradient) -> Fill
-    {
-        return Fill(radialGradient: radialGradient)
-    }
-    
-    @objc open class func fillWithCGImage(_ CGImage: CGImage, tiled: Bool) -> Fill
-    {
-        return Fill(CGImage: CGImage, tiled: tiled)
-    }
-    
-    @objc open class func fillWithImage(_ image: NSUIImage, tiled: Bool) -> Fill
-    {
-        return Fill(image: image, tiled: tiled)
-    }
-    
-    @objc open class func fillWithCGImage(_ CGImage: CGImage) -> Fill
-    {
-        return Fill(CGImage: CGImage)
-    }
-    
-    @objc open class func fillWithImage(_ image: NSUIImage) -> Fill
-    {
-        return Fill(image: image)
-    }
-    
-    @objc open class func fillWithCGLayer(_ CGLayer: CGLayer) -> Fill
-    {
-        return Fill(CGLayer: CGLayer)
-    }
-    
-    // MARK: Drawing code
-    
-    /// Draws the provided path in filled mode with the provided area
-    @objc open func fillPath(
-        context: CGContext,
-        rect: CGRect)
+
+    @objc public func fillPath(context: CGContext, rect: CGRect)
     {
-        let fillType = _type
-        if fillType == .empty
-        {
-            return
-        }
-        
         context.saveGState()
-        
-        switch fillType
-        {
-        case .color:
-            
-            context.setFillColor(_color!)
-            context.fillPath()
-            
-        case .image:
-            
-            context.clip()
-            context.draw(_image!, in: rect)
-            
-        case .tiledImage:
-            
-            context.clip()
-            context.draw(_image!, in: rect, byTiling: true)
-            
-        case .layer:
-            
-            context.clip()
-            context.draw(_layer!, in: rect)
-            
-        case .linearGradient:
-            
-            let radians = (360.0 - _gradientAngle).DEG2RAD
-            let centerPoint = CGPoint(x: rect.midX, y: rect.midY)
-            let xAngleDelta = cos(radians) * rect.width / 2.0
-            let yAngleDelta = sin(radians) * rect.height / 2.0
-            let startPoint = CGPoint(
-                x: centerPoint.x - xAngleDelta,
-                y: centerPoint.y - yAngleDelta
-            )
-            let endPoint = CGPoint(
-                x: centerPoint.x + xAngleDelta,
-                y: centerPoint.y + yAngleDelta
-            )
-            
-            context.clip()
-            context.drawLinearGradient(_gradient!,
-                start: startPoint,
-                end: endPoint,
-                options: [.drawsAfterEndLocation, .drawsBeforeStartLocation]
-            )
-            
-        case .radialGradient:
-            
-            let centerPoint = CGPoint(x: rect.midX, y: rect.midY)
-            let radius = max(rect.width, rect.height) / 2.0
-            
-            context.clip()
-            context.drawRadialGradient(_gradient!,
-                startCenter: CGPoint(
-                    x: centerPoint.x + rect.width * _gradientStartOffsetPercent.x,
-                    y: centerPoint.y + rect.height * _gradientStartOffsetPercent.y
-                ),
-                startRadius: radius * _gradientStartRadiusPercent,
-                endCenter: CGPoint(
-                    x: centerPoint.x + rect.width * _gradientEndOffsetPercent.x,
-                    y: centerPoint.y + rect.height * _gradientEndOffsetPercent.y
-                ),
-                endRadius: radius * _gradientEndRadiusPercent,
-                options: [.drawsAfterEndLocation, .drawsBeforeStartLocation]
-            )
-            
-        case .empty:
-            break
-        }
-        
-        context.restoreGState()
+        defer { context.restoreGState() }
+
+        let centerPoint = CGPoint(x: rect.midX, y: rect.midY)
+        let radius = max(rect.width, rect.height) / 2.0
+
+        context.clip()
+        context.drawRadialGradient(
+            gradient,
+            startCenter: CGPoint(
+                x: centerPoint.x + rect.width * startOffsetPercent.x,
+                y: centerPoint.y + rect.height * startOffsetPercent.y
+            ),
+            startRadius: radius * startRadiusPercent,
+            endCenter: CGPoint(
+                x: centerPoint.x + rect.width * endOffsetPercent.x,
+                y: centerPoint.y + rect.height * endOffsetPercent.y
+            ),
+            endRadius: radius * endRadiusPercent,
+            options: [.drawsAfterEndLocation, .drawsBeforeStartLocation]
+        )
     }
-    
 }

+ 8 - 13
Pods/Charts/Source/Charts/Utils/Platform+Accessibility.swift

@@ -12,18 +12,16 @@
 import Foundation
 
 #if os(iOS) || os(tvOS)
-#if canImport(UIKit)
-    import UIKit
-#endif
+import UIKit
 
 internal func accessibilityPostLayoutChangedNotification(withElement element: Any? = nil)
 {
-    UIAccessibility.post(notification: UIAccessibility.Notification.layoutChanged, argument: element)
+    UIAccessibility.post(notification: .layoutChanged, argument: element)
 }
 
 internal func accessibilityPostScreenChangedNotification(withElement element: Any? = nil)
 {
-    UIAccessibility.post(notification: UIAccessibility.Notification.screenChanged, argument: element)
+    UIAccessibility.post(notification: .screenChanged, argument: element)
 }
 
 /// A simple abstraction over UIAccessibilityElement and NSAccessibilityElement.
@@ -35,7 +33,7 @@ open class NSUIAccessibilityElement: UIAccessibilityElement
     {
         didSet
         {
-            accessibilityTraits = isHeader ? UIAccessibilityTraits.header : UIAccessibilityTraits.none
+            accessibilityTraits = isHeader ? .header : .none
         }
     }
 
@@ -43,14 +41,14 @@ open class NSUIAccessibilityElement: UIAccessibilityElement
         {
         didSet
         {
-            accessibilityTraits = isSelected ? UIAccessibilityTraits.selected : UIAccessibilityTraits.none
+            accessibilityTraits = isSelected ? .selected : .none
         }
     }
 
     override public init(accessibilityContainer container: Any)
     {
         // We can force unwrap since all chart views are subclasses of UIView
-        containerView = (container as! UIView)
+        containerView = container as? UIView
         super.init(accessibilityContainer: container)
     }
 
@@ -97,18 +95,15 @@ extension NSUIView
     open override func index(ofAccessibilityElement element: Any) -> Int
     {
         guard let axElement = element as? NSUIAccessibilityElement else { return NSNotFound }
-        return (accessibilityChildren() as? [NSUIAccessibilityElement])?
-            .firstIndex(of: axElement) ?? NSNotFound
+        return (accessibilityChildren() as? [NSUIAccessibilityElement])?.firstIndex(of: axElement) ?? NSNotFound
     }
 }
 
 #endif
 
 #if os(OSX)
-
-#if canImport(AppKit)
 import AppKit
-#endif
+
 
 internal func accessibilityPostLayoutChangedNotification(withElement element: Any? = nil)
 {

+ 223 - 178
Pods/Charts/Source/Charts/Utils/Platform.swift

@@ -1,240 +1,285 @@
 import Foundation
 
 /** This file provides a thin abstraction layer atop of UIKit (iOS, tvOS) and Cocoa (OS X). The two APIs are very much 
- alike, and for the chart library's usage of the APIs it is often sufficient to typealias one to the other. The NSUI*
- types are aliased to either their UI* implementation (on iOS) or their NS* implementation (on OS X). */
+alike, and for the chart library's usage of the APIs it is often sufficient to typealias one to the other. The NSUI*
+types are aliased to either their UI* implementation (on iOS) or their NS* implementation (on OS X). */
 #if os(iOS) || os(tvOS)
-#if canImport(UIKit)
-    import UIKit
-#endif
-
-public typealias NSUIFont = UIFont
-public typealias NSUIImage = UIImage
-public typealias NSUIScrollView = UIScrollView
-public typealias NSUIScreen = UIScreen
-public typealias NSUIDisplayLink = CADisplayLink
+	import UIKit
 
-open class NSUIView: UIView
-{
-    @objc var nsuiLayer: CALayer?
-    {
-        return self.layer
-    }
-}
 
-extension UIScrollView
-{
-    @objc var nsuiIsScrollEnabled: Bool
-        {
-        get { return isScrollEnabled }
-        set { isScrollEnabled = newValue }
-    }
-}
+    public typealias ParagraphStyle = NSParagraphStyle
+    public typealias MutableParagraphStyle = NSMutableParagraphStyle
+    public typealias TextAlignment = NSTextAlignment
+	public typealias NSUIFont = UIFont
+	public typealias NSUIImage = UIImage
+	public typealias NSUIScrollView = UIScrollView
+    public typealias NSUIScreen = UIScreen
+	public typealias NSUIDisplayLink = CADisplayLink
 
-extension UIScreen
-{
-    @objc final var nsuiScale: CGFloat
+    extension NSUIColor
     {
-        return self.scale
-    }
-}
-
-#endif
-
-#if os(OSX)
-import Cocoa
-import Quartz
+        var nsuirgba: (red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat)? {
+            var red: CGFloat = 0
+            var green: CGFloat = 0
+            var blue: CGFloat = 0
+            var alpha: CGFloat = 0
 
-public typealias NSUIFont = NSFont
-public typealias NSUIImage = NSImage
-public typealias NSUIScrollView = NSScrollView
-public typealias NSUIScreen = NSScreen
+            guard getRed(&red, green: &green, blue: &blue, alpha: &alpha) else {
+                return nil
+            }
 
-/** On OS X there is no CADisplayLink. Use a 60 fps timer to render the animations. */
-public class NSUIDisplayLink
-{
-    private var timer: Timer?
-    private var displayLink: CVDisplayLink?
-    private var _timestamp: CFTimeInterval = 0.0
-
-    private weak var _target: AnyObject?
-    private var _selector: Selector
-
-    public var timestamp: CFTimeInterval
-    {
-        return _timestamp
+            return (red: red, green: green, blue: blue, alpha: alpha)
+        }
     }
 
-		init(target: Any, selector: Selector)
+    open class NSUIView: UIView
     {
-        _target = target as AnyObject
-        _selector = selector
-
-        if CVDisplayLinkCreateWithActiveCGDisplays(&displayLink) == kCVReturnSuccess
-        {
-
-            CVDisplayLinkSetOutputCallback(displayLink!, { (displayLink, inNow, inOutputTime, flagsIn, flagsOut, userData) -> CVReturn in
-
-                let _self = unsafeBitCast(userData, to: NSUIDisplayLink.self)
-                    
-                _self._timestamp = CFAbsoluteTimeGetCurrent()
-                _self._target?.performSelector(onMainThread: _self._selector, with: _self, waitUntilDone: false)
-                    
-                return kCVReturnSuccess
-                }, Unmanaged.passUnretained(self).toOpaque())
-        }
-        else
+        @objc var nsuiLayer: CALayer?
         {
-            timer = Timer(timeInterval: 1.0 / 60.0, target: target, selector: selector, userInfo: nil, repeats: true)
+            return self.layer
         }
-		}
-
-    deinit
-    {
-        stop()
     }
 
-    open func add(to runloop: RunLoop, forMode mode: RunLoop.Mode)
+    extension UIScrollView
     {
-        if displayLink != nil
+        @objc var nsuiIsScrollEnabled: Bool
         {
-            CVDisplayLinkStart(displayLink!)
+            get { return isScrollEnabled }
+            set { isScrollEnabled = newValue }
         }
-        else if timer != nil
+    }
+    
+    extension UIScreen
+    {
+        @objc final var nsuiScale: CGFloat
         {
-            runloop.add(timer!, forMode: mode)
+            return self.scale
         }
     }
 
-    open func remove(from: RunLoop, forMode: RunLoop.Mode)
+    func NSUIMainScreen() -> NSUIScreen?
     {
-        stop()
+        return NSUIScreen.main
     }
 
-    private func stop()
+#endif
+
+#if os(OSX)
+	import Cocoa
+	import Quartz
+
+    public typealias ParagraphStyle = NSParagraphStyle
+    public typealias MutableParagraphStyle = NSMutableParagraphStyle
+    public typealias TextAlignment = NSTextAlignment
+    public typealias NSUIFont = NSFont
+    public typealias NSUIImage = NSImage
+    public typealias NSUIScrollView = NSScrollView
+    public typealias NSUIScreen = NSScreen
+
+	/** On OS X there is no CADisplayLink. Use a 60 fps timer to render the animations. */
+	public class NSUIDisplayLink
     {
-        if displayLink != nil
+        private var timer: Timer?
+        private var displayLink: CVDisplayLink?
+        private var _timestamp: CFTimeInterval = 0.0
+        
+        private weak var _target: AnyObject?
+        private var _selector: Selector
+        
+        public var timestamp: CFTimeInterval
         {
-            CVDisplayLinkStop(displayLink!)
+            return _timestamp
         }
-        if timer != nil
+
+		init(target: AnyObject, selector: Selector)
         {
-            timer?.invalidate()
+            _target = target
+            _selector = selector
+            
+            if CVDisplayLinkCreateWithActiveCGDisplays(&displayLink) == kCVReturnSuccess
+            {
+                
+                CVDisplayLinkSetOutputCallback(displayLink!, { (displayLink, inNow, inOutputTime, flagsIn, flagsOut, userData) -> CVReturn in
+                    
+                    let _self = unsafeBitCast(userData, to: NSUIDisplayLink.self)
+                    
+                    _self._timestamp = CFAbsoluteTimeGetCurrent()
+                    _self._target?.performSelector(onMainThread: _self._selector, with: _self, waitUntilDone: false)
+                    
+                    return kCVReturnSuccess
+                    }, Unmanaged.passUnretained(self).toOpaque())
+            }
+            else
+            {
+                timer = Timer(timeInterval: 1.0 / 60.0, target: target, selector: selector, userInfo: nil, repeats: true)
+            }
+		}
+        
+        deinit
+        {
+            stop()
         }
-    }
-}
-
-extension NSView
-{
-    final var nsuiGestureRecognizers: [NSGestureRecognizer]?
-    {
-        return self.gestureRecognizers
-    }
-}
 
-extension NSScrollView
-{
-    var nsuiIsScrollEnabled: Bool
-    {
-        get { return scrollEnabled }
-        set { scrollEnabled = newValue }
-    }
-}
+        open func add(to runloop: RunLoop, forMode mode: RunLoop.Mode)
+        {
+            if displayLink != nil
+            {
+                CVDisplayLinkStart(displayLink!)
+            }
+            else if timer != nil
+            {
+                runloop.add(timer!, forMode: mode)
+            }
+		}
 
-open class NSUIView: NSView
-{
-    /// A private constant to set the accessibility role during initialization.
-    /// It ensures parity with the iOS element ordering as well as numbered counts of chart components.
-    /// (See Platform+Accessibility for details)
-    private let role: NSAccessibility.Role = .list
+        open func remove(from: RunLoop, forMode: RunLoop.Mode)
+        {
+            stop()
+		}
+        
+        private func stop()
+        {
+            if displayLink != nil
+            {
+                CVDisplayLinkStop(displayLink!)
+            }
+            if timer != nil
+            {
+                timer?.invalidate()
+            }
+        }
+	}
 
-    public override init(frame frameRect: NSRect)
+    extension NSUIColor
     {
-        super.init(frame: frameRect)
-        setAccessibilityRole(role)
+        var nsuirgba: (red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat)? {
+            var red: CGFloat = 0
+            var green: CGFloat = 0
+            var blue: CGFloat = 0
+            var alpha: CGFloat = 0
+
+            guard let colorSpaceModel = cgColor.colorSpace?.model else {
+                return nil
+            }
+            guard colorSpaceModel == .rgb else {
+                return nil
+            }
+
+            getRed(&red, green: &green, blue: &blue, alpha: &alpha)
+            return (red: red, green: green, blue: blue, alpha: alpha)
+        }
     }
 
-    required public init?(coder decoder: NSCoder)
+	extension NSView
     {
-        super.init(coder: decoder)
-        setAccessibilityRole(role)
-    }
+		final var nsuiGestureRecognizers: [NSGestureRecognizer]?
+        {
+			return self.gestureRecognizers
+		}
+	}
 
-    public final override var isFlipped: Bool
+    extension NSScrollView
     {
-        return true
+        var nsuiIsScrollEnabled: Bool
+        {
+            get { return scrollEnabled }
+            set { scrollEnabled = newValue }
+        }
     }
-
-    func setNeedsDisplay()
+    
+	open class NSUIView: NSView
     {
-        self.setNeedsDisplay(self.bounds)
-    }
-
+        /// A private constant to set the accessibility role during initialization.
+        /// It ensures parity with the iOS element ordering as well as numbered counts of chart components.
+        /// (See Platform+Accessibility for details)
+        private let role: NSAccessibility.Role = .list
 
-    open var backgroundColor: NSUIColor?
+        public override init(frame frameRect: NSRect)
         {
-        get
+            super.init(frame: frameRect)
+            setAccessibilityRole(role)
+        }
+
+        required public init?(coder decoder: NSCoder)
         {
-            return self.layer?.backgroundColor == nil
-                ? nil
-                : NSColor(cgColor: self.layer!.backgroundColor!)
+            super.init(coder: decoder)
+            setAccessibilityRole(role)
         }
-        set
+
+		public final override var isFlipped: Bool
         {
-            self.wantsLayer = true
-            self.layer?.backgroundColor = newValue == nil ? nil : newValue!.cgColor
+			return true
+		}
+
+		func setNeedsDisplay()
+        {
+			self.setNeedsDisplay(self.bounds)
+		}
+
+		open var backgroundColor: NSUIColor?
+        {
+            get
+            {
+                return self.layer?.backgroundColor == nil
+                    ? nil
+                    : NSColor(cgColor: self.layer!.backgroundColor!)
+            }
+            set
+            {
+                self.wantsLayer = true
+                self.layer?.backgroundColor = newValue == nil ? nil : newValue!.cgColor
+            }
         }
-    }
 
-    final var nsuiLayer: CALayer?
-    {
-        return self.layer
-    }
-}
+		final var nsuiLayer: CALayer?
+        {
+			return self.layer
+		}
+	}
 
-extension NSFont
-{
-    var lineHeight: CGFloat
+	extension NSFont
     {
-        // Not sure if this is right, but it looks okay
-        return self.boundingRectForFont.size.height
-    }
-}
+		var lineHeight: CGFloat
+        {
+			// Not sure if this is right, but it looks okay
+			return self.boundingRectForFont.size.height
+		}
+	}
 
-extension NSScreen
-{
-    final var nsuiScale: CGFloat
+	extension NSScreen
     {
-        return self.backingScaleFactor
-    }
-}
+		final var nsuiScale: CGFloat
+        {
+			return self.backingScaleFactor
+		}
+	}
 
-extension NSImage
-{
-    var cgImage: CGImage?
+	extension NSImage
     {
-        return self.cgImage(forProposedRect: nil, context: nil, hints: nil)
-    }
-}
+		var cgImage: CGImage?
+        {
+            return self.cgImage(forProposedRect: nil, context: nil, hints: nil)
+		}
+	}
 
-extension NSScrollView
-{
-    /// NOTE: Unable to disable scrolling in macOS
-    var scrollEnabled: Bool
+	extension NSScrollView
     {
-        get
-        {
-            return true
-        }
-        set
+		var scrollEnabled: Bool
         {
-        }
+			get
+            {
+				return true
+			}
+            set
+            {
+                // FIXME: We can't disable  scrolling it on OSX
+            }
+		}
     }
-}
 
+	func NSUIMainScreen() -> NSUIScreen?
+    {
+		return NSUIScreen.main
+	}
+    
 #endif
-
-extension NSUIScreen
-{
-    class var nsuiMain: NSUIScreen? { .main }
-}

+ 0 - 0
Pods/Charts/Source/Charts/Utils/Transformer.swift


Неке датотеке нису приказане због велике количине промена