diff --git a/.travis.yml b/.travis.yml index 70a7ecae..95863699 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,12 +1,12 @@ language: objective-c -osx_image: xcode11 +osx_image: xcode12 matrix: include: - - osx_image: xcode11 + - osx_image: xcode12 env: PLATFORM="iOS" - - osx_image: xcode11 + - osx_image: xcode12 env: PLATFORM="tvOS" - - osx_image: xcode11 + - osx_image: xcode12 env: PLATFORM="macOS" env: global: @@ -18,7 +18,7 @@ before_install: - brew update - brew upgrade carthage || true - carthage version - - carthage bootstrap --platform $PLATFORM + - ./carthage.sh bootstrap --platform $PLATFORM --no-use-binaries script: - bundle exec rake ci[$PLATFORM] after_success: diff --git a/Cartfile.resolved b/Cartfile.resolved index 8f69010a..4f9d4369 100644 --- a/Cartfile.resolved +++ b/Cartfile.resolved @@ -1 +1 @@ -github "uber/ios-snapshot-test-case" "6.1.0" +github "uber/ios-snapshot-test-case" "6.2.0" diff --git a/Charts.podspec b/Charts.podspec index 4e48e4d9..6fa80ed4 100644 --- a/Charts.podspec +++ b/Charts.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "Charts" - s.version = "3.6.0" + s.version = "4.0.0" s.summary = "Charts is a powerful & easy to use chart library for iOS, tvOS and OSX (and Android)" s.homepage = "https://github.com/danielgindi/Charts" s.license = { :type => "Apache License, Version 2.0", :file => "LICENSE" } diff --git a/Charts.xcodeproj/project.pbxproj b/Charts.xcodeproj/project.pbxproj index 7ca07ea5..f8a25590 100644 --- a/Charts.xcodeproj/project.pbxproj +++ b/Charts.xcodeproj/project.pbxproj @@ -10,24 +10,24 @@ 00B8BF5901C2D220357B0B2A /* Media.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 41DDB768A1D033A34F0EF9E0 /* Media.xcassets */; }; 00BC23EF0E04E17188344403 /* BarChartDataProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D7184C8A5A60A3522AB9B05 /* BarChartDataProvider.swift */; }; 02A6E6E1A82A27A66B8D08C4 /* MoveViewJob.swift in Sources */ = {isa = PBXBuildFile; fileRef = 266E162DA8B29D9AEB6A9397 /* MoveViewJob.swift */; }; - 03960E8148C6AEDACE4B77CC /* IMarker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 596963A429D485E3894C4666 /* IMarker.swift */; }; + 03960E8148C6AEDACE4B77CC /* Marker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 596963A429D485E3894C4666 /* Marker.swift */; }; 0511E43EF3FD2CDE7F7F15DB /* ScatterChartDataProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2FD37A55B4D85D883E29C744 /* ScatterChartDataProvider.swift */; }; 05253AFC448C107DEF54C2FE /* CombinedChartRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52265C1B343CCC41AF2300E3 /* CombinedChartRenderer.swift */; }; 0529DD51622C8769C1121F90 /* CrossShapeRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 823F7DB281C6C6F069A69605 /* CrossShapeRenderer.swift */; }; 0577C2B38BCE4C871F262714 /* AnimatedZoomViewJob.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C2EA58CB336967198D30D20 /* AnimatedZoomViewJob.swift */; }; 064989461F5C99C7006E8BB3 /* Snapshot.swift in Sources */ = {isa = PBXBuildFile; fileRef = 064989451F5C99C7006E8BB3 /* Snapshot.swift */; }; + 06AB297F20FA726600BAD505 /* Highlighter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 06AB297E20FA726500BAD505 /* Highlighter.swift */; }; 0A772AEC08246FEC480673E5 /* PieRadarChartViewBase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A6C9631C69B2D772BBD9232 /* PieRadarChartViewBase.swift */; }; 0C52C70C6E6EA09BD7426386 /* RadarChartData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BBB57D6FA41029B08F26D7B /* RadarChartData.swift */; }; 0CAF514A280FF6A14E2A1A23 /* CombinedChartView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11EF1FE22549E885C8F40738 /* CombinedChartView.swift */; }; - 0D8A89398F9BD5DCC8D7F976 /* ICandleChartDataSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18BFB0A14A5C47A302A597D9 /* ICandleChartDataSet.swift */; }; + 0D8A89398F9BD5DCC8D7F976 /* CandleChartDataSetProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18BFB0A14A5C47A302A597D9 /* CandleChartDataSetProtocol.swift */; }; 11F68AA2EBF822D7208EE002 /* YAxisRendererRadarChart.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA5A16F4A382813C4FE8BDF9 /* YAxisRendererRadarChart.swift */; }; - 1311BEC21E9CC264E971EFAF /* ILineRadarChartDataSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4F7E6A99D82E6AE3804D5A39 /* ILineRadarChartDataSet.swift */; }; + 1311BEC21E9CC264E971EFAF /* LineRadarChartDataSetProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4F7E6A99D82E6AE3804D5A39 /* LineRadarChartDataSetProtocol.swift */; }; 135F11CE20425AF600D655A3 /* PieChartTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 135F11CD20425AF600D655A3 /* PieChartTests.swift */; }; - 146EE16342C2BADC92E45BF2 /* ILineScatterCandleRadarChartDataSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9249AD9AEC8C85772365A128 /* ILineScatterCandleRadarChartDataSet.swift */; }; + 146EE16342C2BADC92E45BF2 /* LineScatterCandleRadarChartDataSetProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9249AD9AEC8C85772365A128 /* LineScatterCandleRadarChartDataSetProtocol.swift */; }; 17E994DA88777AA1D8CCFC58 /* BarChartDataSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = C31AA65EA27776F8C653C7E8 /* BarChartDataSet.swift */; }; - 203A39685CC96FC625F616E4 /* IHighlighter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 998F2BFE318471AFC05B50AC /* IHighlighter.swift */; }; 219192CA6B4895319AB49DCA /* BarLineScatterCandleBubbleRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B1C588E9DF6FFD56D7ADF8E /* BarLineScatterCandleBubbleRenderer.swift */; }; - 224EFF991FBAAC4700CF9B3B /* EquatableTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 224EFF981FBAAC4700CF9B3B /* EquatableTests.swift */; }; + 2243BBFD1FF156EC00B49D0B /* EquatableTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2243BBFB1FF156D000B49D0B /* EquatableTests.swift */; }; 23649EFC635A76022F07FFA6 /* PieChartDataEntry.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD02157CF8CEE1189BF681DA /* PieChartDataEntry.swift */; }; 23FA50B2730D8C7ACA091C4F /* BarChartRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75F279974FE650E57A061B09 /* BarChartRenderer.swift */; }; 24151B0729D77251A8494D70 /* LineRadarRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 105FFC9D3773A9C7A60A897F /* LineRadarRenderer.swift */; }; @@ -38,7 +38,7 @@ 2B821AAC3EBD60A73EACBCE6 /* LegendRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = F715DB2C56C9E0615542625B /* LegendRenderer.swift */; }; 2BA03CEC36BADCF682F1328B /* LineChartDataProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFABD027DAF6851088F002AC /* LineChartDataProvider.swift */; }; 2BF85BEA981B359A65E9BF67 /* LineChartTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2E1819D72CD7B6C4A4E8048 /* LineChartTests.swift */; }; - 2C40CFFC8D88BEA70E0A50B0 /* IBubbleChartDataSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3788EC55EF908B0805D7C2F /* IBubbleChartDataSet.swift */; }; + 2C40CFFC8D88BEA70E0A50B0 /* BubbleChartDataSetProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3788EC55EF908B0805D7C2F /* BubbleChartDataSetProtocol.swift */; }; 2C879FC24D7A15D70BE4063F /* PieChartData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E03A4987F72414A02A0631B /* PieChartData.swift */; }; 2FBA7E982EB57932B9F3E9B5 /* YAxis.swift in Sources */ = {isa = PBXBuildFile; fileRef = FB92A80F861C1362EED8D946 /* YAxis.swift */; }; 3097296AC7FFA994FE4AD312 /* PieRadarHighlighter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04F7B9DF1F2D66E7279771D4 /* PieRadarHighlighter.swift */; }; @@ -58,7 +58,7 @@ 48E875BBD6540BDE1C1B7D3D /* AxisBase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B7AEFBF4D85B9D2EAAB3071 /* AxisBase.swift */; }; 4E98788ABEF6496C23F3E6C6 /* HorizontalBarHighlighter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33BE9A97FFA41D3D85CAFFC7 /* HorizontalBarHighlighter.swift */; }; 4FACC6FD308AFB231EB4A93D /* XAxisRendererRadarChart.swift in Sources */ = {isa = PBXBuildFile; fileRef = BC19DC2434D65FFB446A61B7 /* XAxisRendererRadarChart.swift */; }; - 50476F8E6662CAFC1EFE0723 /* IScatterChartDataSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 219BC9CEA037F897E92E45D1 /* IScatterChartDataSet.swift */; }; + 50476F8E6662CAFC1EFE0723 /* ScatterChartDataSetProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 219BC9CEA037F897E92E45D1 /* ScatterChartDataSetProtocol.swift */; }; 515E286E6C47594D3FFA3DD1 /* ViewPortHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72EAEBB7CF73E33565FC2896 /* ViewPortHandler.swift */; }; 53A91F6F86740E26FE733639 /* BarLineScatterCandleBubbleChartDataSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D717F0808DE7EC8A4AE9C2A /* BarLineScatterCandleBubbleChartDataSet.swift */; }; 56E0F5EA9255B9B92876E040 /* BubbleChartRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2194AA554712E6BA2677F114 /* BubbleChartRenderer.swift */; }; @@ -85,10 +85,10 @@ 7EE6EFE70CF4D8B09CAFCD01 /* AnimatedMoveViewJob.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA157EFF2F952192C11DF937 /* AnimatedMoveViewJob.swift */; }; 8102A555DD6C93AC1290EA7C /* Fill.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5A4CFFFB65819121595F06F1 /* Fill.swift */; }; 81892994002C0640AD858748 /* ChartData.swift in Sources */ = {isa = PBXBuildFile; fileRef = E120E76C6F1B5877D56126DD /* ChartData.swift */; }; - 83BBAF3EDC31FD452F8BF1DB /* IRadarChartDataSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2EAD807534620E3B53327F04 /* IRadarChartDataSet.swift */; }; + 83BBAF3EDC31FD452F8BF1DB /* RadarChartDataSetProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2EAD807534620E3B53327F04 /* RadarChartDataSetProtocol.swift */; }; 846AC09831FA93F66732591B /* YAxisRendererHorizontalBarChart.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAE417AAA0FCA0DD00E77489 /* YAxisRendererHorizontalBarChart.swift */; }; 8A463E2947F211C594CA5E95 /* TransformerHorizontalBarChart.swift in Sources */ = {isa = PBXBuildFile; fileRef = 324C9127B53A8D39C8B49277 /* TransformerHorizontalBarChart.swift */; }; - 8A9FF54E2075A9047CC8E953 /* IShapeRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA1D3D13180C2E3893A82546 /* IShapeRenderer.swift */; }; + 8A9FF54E2075A9047CC8E953 /* ShapeRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA1D3D13180C2E3893A82546 /* ShapeRenderer.swift */; }; 8BCCD709AACC565613D9DA68 /* CandleStickChartRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD5C6D20243EC2F19069AACD /* CandleStickChartRenderer.swift */; }; 8E1192F7A7152E9DA92C56A9 /* ChartUtilsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AB9062A28AAB9469752A954 /* ChartUtilsTests.swift */; }; 8EF7B3FBE37F72CC030CD865 /* SquareShapeRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32FC01A016DFF1BA73AF9182 /* SquareShapeRenderer.swift */; }; @@ -104,16 +104,16 @@ 9A26C8DB1F87B01700367599 /* DataApproximator+N.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A26C8DA1F87B01700367599 /* DataApproximator+N.swift */; }; 9C91C151608E2D6E19B1EAD1 /* Range.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0F099502DA50C56204E7B744 /* Range.swift */; }; 9F760570BCECB0BF5727AF90 /* BarLineChartViewBase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45C6D3723C4E001B119CA0C8 /* BarLineChartViewBase.swift */; }; - A40ACF0CCE96EEE104B0463D /* IValueFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EAA8AA30C377D54D22A577A /* IValueFormatter.swift */; }; + A40ACF0CCE96EEE104B0463D /* ValueFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EAA8AA30C377D54D22A577A /* ValueFormatter.swift */; }; A692D8BDE42717F69DB790BE /* HorizontalBarChartView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6021C9E424C36116AEA78CC9 /* HorizontalBarChartView.swift */; }; AEE9C4E4AC02B8FB3CD21975 /* ZoomViewJob.swift in Sources */ = {isa = PBXBuildFile; fileRef = FB3A4F5987E58F3E5BE855F9 /* ZoomViewJob.swift */; }; - AF4AAF3709ED9DDF6362EAE8 /* IBarLineScatterCandleBubbleChartDataSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5649B272BF3EBFC8A1EF0C1 /* IBarLineScatterCandleBubbleChartDataSet.swift */; }; + AF4AAF3709ED9DDF6362EAE8 /* BarLineScatterCandleBubbleChartDataSetProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5649B272BF3EBFC8A1EF0C1 /* BarLineScatterCandleBubbleChartDataSetProtocol.swift */; }; B0D28C68BB9A958DC56EB214 /* DefaultValueFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 107D8F8163EE54D6D9E916B0 /* DefaultValueFormatter.swift */; }; - B13C74B4FF705D7B595D01EF /* IAxisValueFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0BD9DF16AF59680A3BB49452 /* IAxisValueFormatter.swift */; }; + B13C74B4FF705D7B595D01EF /* AxisValueFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0BD9DF16AF59680A3BB49452 /* AxisValueFormatter.swift */; }; B539114951455C35BADAE3F3 /* PieChartDataSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = A4FB5E3761EF8B4D1E1E1014 /* PieChartDataSet.swift */; }; B66817462241E3CC00017CF1 /* HorizontalBarChartTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B66817452241E3CC00017CF1 /* HorizontalBarChartTests.swift */; }; B6BF9A561F91993A00E62A5D /* CombinedChartTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6BF9A551F91993A00E62A5D /* CombinedChartTests.swift */; }; - B6C9F450D937B87224D29D5C /* IFillFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 818AC6B12505B7C0A53D62F9 /* IFillFormatter.swift */; }; + B6C9F450D937B87224D29D5C /* FillFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 818AC6B12505B7C0A53D62F9 /* FillFormatter.swift */; }; B6DCC229615EFE706F64A37D /* LineScatterCandleRadarRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 923206233CA89FD03565FF87 /* LineScatterCandleRadarRenderer.swift */; }; B85DEB06B4C1AFFC8A0E3295 /* CircleShapeRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECE1B1623D3AF69CECAE8562 /* CircleShapeRenderer.swift */; }; BEFD9518F3A74ACF8FA33308 /* Charts.h in Headers */ = {isa = PBXBuildFile; fileRef = 4F9922F0641F7955DC6CD324 /* Charts.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -123,7 +123,7 @@ C20A62D8CB9120523D5FB650 /* LegendEntry.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E7C673B9ED4340F550A9283 /* LegendEntry.swift */; }; C2EFB4EC8C97FA9987F1B50D /* RadarChartDataEntry.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91EEEDE2AB8F2DA3AFCF0733 /* RadarChartDataEntry.swift */; }; C33E1AF5471A60BA42DAF52E /* RadarHighlighter.swift in Sources */ = {isa = PBXBuildFile; fileRef = F368CF209744D8F3B85B1028 /* RadarHighlighter.swift */; }; - C3F0DDB7F0A922F0BB7EDB8A /* IBarChartDataSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A53A9E42FC07FFDACA937C1 /* IBarChartDataSet.swift */; }; + C3F0DDB7F0A922F0BB7EDB8A /* BarChartDataSetProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A53A9E42FC07FFDACA937C1 /* BarChartDataSetProtocol.swift */; }; C7B150D740255670DEB9F455 /* Charts.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 65AD9E95D9ED4DC0BD73A743 /* Charts.framework */; }; C9AA360A2355F01F00C97D93 /* Platform+Color.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9AA36092355F01F00C97D93 /* Platform+Color.swift */; }; C9F3DC262355F791000C3215 /* Platform+Graphics.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9F3DC242355F791000C3215 /* Platform+Graphics.swift */; }; @@ -143,20 +143,20 @@ E4B2F363414E84C4D4B8A885 /* BubbleChartView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EED352A98860E031F13AFB7 /* BubbleChartView.swift */; }; E50D291A6B6E69BF0B56A67C /* ChartBaseDataSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9FE42E868A225C116537368 /* ChartBaseDataSet.swift */; }; E68CA3DC66EB638C956E09B8 /* BubbleChartData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7EDA3AD550AEFC93C8D15B9C /* BubbleChartData.swift */; }; - E8F0F4F47CD7D72B4EE5A794 /* IChartDataSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A32510073A303CBB38E094A /* IChartDataSet.swift */; }; + E8F0F4F47CD7D72B4EE5A794 /* ChartDataSetProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A32510073A303CBB38E094A /* ChartDataSetProtocol.swift */; }; E9FF0ECB5E0CA92DBF4C1BC4 /* Platform.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3ED23C354AFE81818D78E645 /* Platform.swift */; }; EAEA60D22CA8C1B7E18D3F7D /* ChartDataEntry.swift in Sources */ = {isa = PBXBuildFile; fileRef = F22750328058DEC2F019646F /* ChartDataEntry.swift */; }; EB56849433A76B08606B73EB /* ScatterChartDataSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB1DD1A0F64266A10EE94194 /* ScatterChartDataSet.swift */; }; ECE7EAE7179A7F57CE9BBD8F /* Legend.swift in Sources */ = {isa = PBXBuildFile; fileRef = E64A75540C627E09080B402A /* Legend.swift */; }; - ECECC58CEF03B1718F8267E8 /* AxisRendererBase.swift in Sources */ = {isa = PBXBuildFile; fileRef = C75935E899183DDFA181E2CC /* AxisRendererBase.swift */; }; + ECECC58CEF03B1718F8267E8 /* AxisRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = C75935E899183DDFA181E2CC /* AxisRenderer.swift */; }; F100D68395F169B93590FA96 /* HorizontalBarChartRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 539382766378B702660FDFB2 /* HorizontalBarChartRenderer.swift */; }; F103D90FC5DEEA0D7BB4407E /* ChevronUpShapeRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA70259ED16FF80D8EEB0F94 /* ChevronUpShapeRenderer.swift */; }; - F37B07008B8AE7F3909FFB9C /* ChartDataRendererBase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0216EDC6A1FE272F4EB19FCF /* ChartDataRendererBase.swift */; }; + F37B07008B8AE7F3909FFB9C /* DataRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0216EDC6A1FE272F4EB19FCF /* DataRenderer.swift */; }; F5A209116FAC68F5903D0B46 /* ChartAnimationEasing.swift in Sources */ = {isa = PBXBuildFile; fileRef = DFB762958EE8E6521563665D /* ChartAnimationEasing.swift */; }; F744C510DA9B85C228BBB335 /* DefaultFillFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6C1BEFDF17404666C7B6054 /* DefaultFillFormatter.swift */; }; - F941C88BF814DF51C465CB95 /* ILineChartDataSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 429E88F2729735DC092EE556 /* ILineChartDataSet.swift */; }; + F941C88BF814DF51C465CB95 /* LineChartDataSetProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 429E88F2729735DC092EE556 /* LineChartDataSetProtocol.swift */; }; FA07D034D9C3BC7795184ACA /* LineScatterCandleRadarChartDataSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = C58BD7B14BEA440783ED8D2B /* LineScatterCandleRadarChartDataSet.swift */; }; - FAAD9FF6565DED2652188584 /* IPieChartDataSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA2AA6CC89F809DCCD7605B4 /* IPieChartDataSet.swift */; }; + FAAD9FF6565DED2652188584 /* PieChartDataSetProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA2AA6CC89F809DCCD7605B4 /* PieChartDataSetProtocol.swift */; }; FD37AAC0270F390FFC470A65 /* ChartDataProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62B73FCEDD3841E7B958F6A9 /* ChartDataProvider.swift */; }; FDBDAFA7A5337C6E3992DACE /* ComponentBase.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8C9A105A7DB64F39DDA648B /* ComponentBase.swift */; }; /* End PBXBuildFile section */ @@ -173,11 +173,12 @@ /* Begin PBXFileReference section */ 0108D5925E21A47DA36A66AA /* BarChartData.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = BarChartData.swift; path = Source/Charts/Data/Implementations/Standard/BarChartData.swift; sourceTree = ""; }; - 0216EDC6A1FE272F4EB19FCF /* ChartDataRendererBase.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ChartDataRendererBase.swift; path = Source/Charts/Renderers/ChartDataRendererBase.swift; sourceTree = ""; }; + 0216EDC6A1FE272F4EB19FCF /* DataRenderer.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = DataRenderer.swift; path = Source/Charts/Renderers/DataRenderer.swift; sourceTree = ""; }; 04F7B9DF1F2D66E7279771D4 /* PieRadarHighlighter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = PieRadarHighlighter.swift; path = Source/Charts/Highlight/PieRadarHighlighter.swift; sourceTree = ""; }; 0619A877C69A95ECCC440A44 /* LineChartView.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = LineChartView.swift; path = Source/Charts/Charts/LineChartView.swift; sourceTree = ""; }; 064989451F5C99C7006E8BB3 /* Snapshot.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = Snapshot.swift; path = Tests/Charts/Snapshot.swift; sourceTree = ""; }; - 0BD9DF16AF59680A3BB49452 /* IAxisValueFormatter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = IAxisValueFormatter.swift; path = Source/Charts/Formatters/IAxisValueFormatter.swift; sourceTree = ""; }; + 06AB297E20FA726500BAD505 /* Highlighter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Highlighter.swift; path = Source/Charts/Highlight/Highlighter.swift; sourceTree = ""; }; + 0BD9DF16AF59680A3BB49452 /* AxisValueFormatter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = AxisValueFormatter.swift; path = Source/Charts/Formatters/AxisValueFormatter.swift; sourceTree = ""; }; 0DABDBBCCE6B3620C967F04A /* LineChartRenderer.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = LineChartRenderer.swift; path = Source/Charts/Renderers/LineChartRenderer.swift; sourceTree = ""; }; 0DDE409E9ECF54D2C146A6F0 /* CombinedChartData.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = CombinedChartData.swift; path = Source/Charts/Data/Implementations/Standard/CombinedChartData.swift; sourceTree = ""; }; 0F099502DA50C56204E7B744 /* Range.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Range.swift; path = Source/Charts/Highlight/Range.swift; sourceTree = ""; }; @@ -188,19 +189,19 @@ 12409C3EA15787C11AF0D2BC /* ChartDataEntryBase.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ChartDataEntryBase.swift; path = Source/Charts/Data/Implementations/Standard/ChartDataEntryBase.swift; sourceTree = ""; }; 135F11CD20425AF600D655A3 /* PieChartTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = PieChartTests.swift; path = Tests/Charts/PieChartTests.swift; sourceTree = ""; }; 18462BFDD9DEE76D51D40503 /* ScatterChartView.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ScatterChartView.swift; path = Source/Charts/Charts/ScatterChartView.swift; sourceTree = ""; }; - 18BFB0A14A5C47A302A597D9 /* ICandleChartDataSet.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ICandleChartDataSet.swift; path = Source/Charts/Data/Interfaces/ICandleChartDataSet.swift; sourceTree = ""; }; + 18BFB0A14A5C47A302A597D9 /* CandleChartDataSetProtocol.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = CandleChartDataSetProtocol.swift; path = Source/Charts/Data/Interfaces/CandleChartDataSetProtocol.swift; sourceTree = ""; }; 1C02C3AF5C92FCFC18224C35 /* XAxisRenderer.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = XAxisRenderer.swift; path = Source/Charts/Renderers/XAxisRenderer.swift; sourceTree = ""; }; 1CBBC58C6CE1EBEE9852CE41 /* ChartsTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ChartsTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 1F3D55A7E6176D52DC957D27 /* XAxisRendererHorizontalBarChart.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = XAxisRendererHorizontalBarChart.swift; path = Source/Charts/Renderers/XAxisRendererHorizontalBarChart.swift; sourceTree = ""; }; 2194AA554712E6BA2677F114 /* BubbleChartRenderer.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = BubbleChartRenderer.swift; path = Source/Charts/Renderers/BubbleChartRenderer.swift; sourceTree = ""; }; - 219BC9CEA037F897E92E45D1 /* IScatterChartDataSet.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = IScatterChartDataSet.swift; path = Source/Charts/Data/Interfaces/IScatterChartDataSet.swift; sourceTree = ""; }; - 224EFF981FBAAC4700CF9B3B /* EquatableTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = EquatableTests.swift; path = Tests/Charts/EquatableTests.swift; sourceTree = ""; }; + 219BC9CEA037F897E92E45D1 /* ScatterChartDataSetProtocol.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ScatterChartDataSetProtocol.swift; path = Source/Charts/Data/Interfaces/ScatterChartDataSetProtocol.swift; sourceTree = ""; }; + 2243BBFB1FF156D000B49D0B /* EquatableTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = EquatableTests.swift; path = Tests/Charts/EquatableTests.swift; sourceTree = ""; }; 23D35CF6F9177D77B6B97AE1 /* XShapeRenderer.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = XShapeRenderer.swift; path = Source/Charts/Renderers/Scatter/XShapeRenderer.swift; sourceTree = ""; }; 2440DB759AB93B4A928A3F6F /* RadarChartView.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RadarChartView.swift; path = Source/Charts/Charts/RadarChartView.swift; sourceTree = ""; }; 2465CB73738EBAFB46C57288 /* CombinedHighlighter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = CombinedHighlighter.swift; path = Source/Charts/Highlight/CombinedHighlighter.swift; sourceTree = ""; }; 266E162DA8B29D9AEB6A9397 /* MoveViewJob.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = MoveViewJob.swift; path = Source/Charts/Jobs/MoveViewJob.swift; sourceTree = ""; }; 274116834B1B0345D622E027 /* CandleChartDataSet.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = CandleChartDataSet.swift; path = Source/Charts/Data/Implementations/Standard/CandleChartDataSet.swift; sourceTree = ""; }; - 2EAD807534620E3B53327F04 /* IRadarChartDataSet.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = IRadarChartDataSet.swift; path = Source/Charts/Data/Interfaces/IRadarChartDataSet.swift; sourceTree = ""; }; + 2EAD807534620E3B53327F04 /* RadarChartDataSetProtocol.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RadarChartDataSetProtocol.swift; path = Source/Charts/Data/Interfaces/RadarChartDataSetProtocol.swift; sourceTree = ""; }; 2FD37A55B4D85D883E29C744 /* ScatterChartDataProvider.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ScatterChartDataProvider.swift; path = Source/Charts/Interfaces/ScatterChartDataProvider.swift; sourceTree = ""; }; 30EFAD7920F76360ADB3B5F5 /* ChartViewBase.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ChartViewBase.swift; path = Source/Charts/Charts/ChartViewBase.swift; sourceTree = ""; }; 324C9127B53A8D39C8B49277 /* TransformerHorizontalBarChart.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = TransformerHorizontalBarChart.swift; path = Source/Charts/Utils/TransformerHorizontalBarChart.swift; sourceTree = ""; }; @@ -208,13 +209,13 @@ 33BE9A97FFA41D3D85CAFFC7 /* HorizontalBarHighlighter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = HorizontalBarHighlighter.swift; path = Source/Charts/Highlight/HorizontalBarHighlighter.swift; sourceTree = ""; }; 392AAEB02DD7B351D92907C2 /* MarkerImage.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = MarkerImage.swift; path = Source/Charts/Components/MarkerImage.swift; sourceTree = ""; }; 3976E5F9D60E30CD94CE6156 /* Animator.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Animator.swift; path = Source/Charts/Animation/Animator.swift; sourceTree = ""; }; - 3A32510073A303CBB38E094A /* IChartDataSet.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = IChartDataSet.swift; path = Source/Charts/Data/Interfaces/IChartDataSet.swift; sourceTree = ""; }; + 3A32510073A303CBB38E094A /* ChartDataSetProtocol.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ChartDataSetProtocol.swift; path = Source/Charts/Data/Interfaces/ChartDataSetProtocol.swift; sourceTree = ""; }; 3D64616883374310C505EC39 /* Highlight.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Highlight.swift; path = Source/Charts/Highlight/Highlight.swift; sourceTree = ""; }; 3ED23C354AFE81818D78E645 /* Platform.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Platform.swift; path = Source/Charts/Utils/Platform.swift; sourceTree = ""; }; 3F8146ABC9FC311AF8CA699C /* CandleChartDataProvider.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = CandleChartDataProvider.swift; path = Source/Charts/Interfaces/CandleChartDataProvider.swift; sourceTree = ""; }; 3FDA09EF973925A110506799 /* ChartUtils.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ChartUtils.swift; path = Source/Charts/Utils/ChartUtils.swift; sourceTree = ""; }; 41DDB768A1D033A34F0EF9E0 /* Media.xcassets */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = folder.assetcatalog; name = Media.xcassets; path = "Tests/Supporting Files/Media.xcassets"; sourceTree = ""; }; - 429E88F2729735DC092EE556 /* ILineChartDataSet.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ILineChartDataSet.swift; path = Source/Charts/Data/Interfaces/ILineChartDataSet.swift; sourceTree = ""; }; + 429E88F2729735DC092EE556 /* LineChartDataSetProtocol.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = LineChartDataSetProtocol.swift; path = Source/Charts/Data/Interfaces/LineChartDataSetProtocol.swift; sourceTree = ""; }; 45C6D3723C4E001B119CA0C8 /* BarLineChartViewBase.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = BarLineChartViewBase.swift; path = Source/Charts/Charts/BarLineChartViewBase.swift; sourceTree = ""; }; 45E31A4356CC6F283C29954B /* LineRadarChartDataSet.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = LineRadarChartDataSet.swift; path = Source/Charts/Data/Implementations/Standard/LineRadarChartDataSet.swift; sourceTree = ""; }; 46D8013D44629521B1746364 /* PieChartRenderer.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = PieChartRenderer.swift; path = Source/Charts/Renderers/PieChartRenderer.swift; sourceTree = ""; }; @@ -224,16 +225,16 @@ 4BBB57D6FA41029B08F26D7B /* RadarChartData.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RadarChartData.swift; path = Source/Charts/Data/Implementations/Standard/RadarChartData.swift; sourceTree = ""; }; 4C2EA58CB336967198D30D20 /* AnimatedZoomViewJob.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = AnimatedZoomViewJob.swift; path = Source/Charts/Jobs/AnimatedZoomViewJob.swift; sourceTree = ""; }; 4C978F31F23C7D21197DC2A1 /* LineChartData.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = LineChartData.swift; path = Source/Charts/Data/Implementations/Standard/LineChartData.swift; sourceTree = ""; }; - 4EAA8AA30C377D54D22A577A /* IValueFormatter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = IValueFormatter.swift; path = Source/Charts/Formatters/IValueFormatter.swift; sourceTree = ""; }; + 4EAA8AA30C377D54D22A577A /* ValueFormatter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ValueFormatter.swift; path = Source/Charts/Formatters/ValueFormatter.swift; sourceTree = ""; }; 4EED352A98860E031F13AFB7 /* BubbleChartView.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = BubbleChartView.swift; path = Source/Charts/Charts/BubbleChartView.swift; sourceTree = ""; }; - 4F7E6A99D82E6AE3804D5A39 /* ILineRadarChartDataSet.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ILineRadarChartDataSet.swift; path = Source/Charts/Data/Interfaces/ILineRadarChartDataSet.swift; sourceTree = ""; }; + 4F7E6A99D82E6AE3804D5A39 /* LineRadarChartDataSetProtocol.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = LineRadarChartDataSetProtocol.swift; path = Source/Charts/Data/Interfaces/LineRadarChartDataSetProtocol.swift; sourceTree = ""; }; 4F9922F0641F7955DC6CD324 /* Charts.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = Charts.h; path = "Source/Supporting Files/Charts.h"; sourceTree = ""; }; 5225ABC3C0C2F65FC094EEBB /* XAxis.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = XAxis.swift; path = Source/Charts/Components/XAxis.swift; sourceTree = ""; }; 52265C1B343CCC41AF2300E3 /* CombinedChartRenderer.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = CombinedChartRenderer.swift; path = Source/Charts/Renderers/CombinedChartRenderer.swift; sourceTree = ""; }; 539382766378B702660FDFB2 /* HorizontalBarChartRenderer.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = HorizontalBarChartRenderer.swift; path = Source/Charts/Renderers/HorizontalBarChartRenderer.swift; sourceTree = ""; }; 543729805D897CC03E5F78D3 /* BarHighlighter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = BarHighlighter.swift; path = Source/Charts/Highlight/BarHighlighter.swift; sourceTree = ""; }; 559DB735FEA17AB90676D6CA /* BarLineScatterCandleBubbleChartData.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = BarLineScatterCandleBubbleChartData.swift; path = Source/Charts/Data/Implementations/Standard/BarLineScatterCandleBubbleChartData.swift; sourceTree = ""; }; - 596963A429D485E3894C4666 /* IMarker.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = IMarker.swift; path = Source/Charts/Components/IMarker.swift; sourceTree = ""; }; + 596963A429D485E3894C4666 /* Marker.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Marker.swift; path = Source/Charts/Components/Marker.swift; sourceTree = ""; }; 5983826927D825EF5F855C28 /* ChartHighlighter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ChartHighlighter.swift; path = Source/Charts/Highlight/ChartHighlighter.swift; sourceTree = ""; }; 5A4CFFFB65819121595F06F1 /* Fill.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Fill.swift; path = Source/Charts/Utils/Fill.swift; sourceTree = ""; }; 5B1C588E9DF6FFD56D7ADF8E /* BarLineScatterCandleBubbleRenderer.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = BarLineScatterCandleBubbleRenderer.swift; path = Source/Charts/Renderers/BarLineScatterCandleBubbleRenderer.swift; sourceTree = ""; }; @@ -251,28 +252,27 @@ 710D7C9B2F1DB4A331EE405A /* AnimatedViewPortJob.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = AnimatedViewPortJob.swift; path = Source/Charts/Jobs/AnimatedViewPortJob.swift; sourceTree = ""; }; 72EAEBB7CF73E33565FC2896 /* ViewPortHandler.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ViewPortHandler.swift; path = Source/Charts/Utils/ViewPortHandler.swift; sourceTree = ""; }; 75F279974FE650E57A061B09 /* BarChartRenderer.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = BarChartRenderer.swift; path = Source/Charts/Renderers/BarChartRenderer.swift; sourceTree = ""; }; - 7A53A9E42FC07FFDACA937C1 /* IBarChartDataSet.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = IBarChartDataSet.swift; path = Source/Charts/Data/Interfaces/IBarChartDataSet.swift; sourceTree = ""; }; + 7A53A9E42FC07FFDACA937C1 /* BarChartDataSetProtocol.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = BarChartDataSetProtocol.swift; path = Source/Charts/Data/Interfaces/BarChartDataSetProtocol.swift; sourceTree = ""; }; 7AB9062A28AAB9469752A954 /* ChartUtilsTests.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ChartUtilsTests.swift; path = Tests/Charts/ChartUtilsTests.swift; sourceTree = ""; }; 7AC9C3D69ACB5BDE22421E15 /* RadarChartRenderer.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RadarChartRenderer.swift; path = Source/Charts/Renderers/RadarChartRenderer.swift; sourceTree = ""; }; 7EDA3AD550AEFC93C8D15B9C /* BubbleChartData.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = BubbleChartData.swift; path = Source/Charts/Data/Implementations/Standard/BubbleChartData.swift; sourceTree = ""; }; 80D5B764EC0AE1E17E55DC67 /* ScatterChartRenderer.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ScatterChartRenderer.swift; path = Source/Charts/Renderers/ScatterChartRenderer.swift; sourceTree = ""; }; - 818AC6B12505B7C0A53D62F9 /* IFillFormatter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = IFillFormatter.swift; path = Source/Charts/Formatters/IFillFormatter.swift; sourceTree = ""; }; + 818AC6B12505B7C0A53D62F9 /* FillFormatter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = FillFormatter.swift; path = Source/Charts/Formatters/FillFormatter.swift; sourceTree = ""; }; 823F7DB281C6C6F069A69605 /* CrossShapeRenderer.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = CrossShapeRenderer.swift; path = Source/Charts/Renderers/Scatter/CrossShapeRenderer.swift; sourceTree = ""; }; 8FF03960A871A092F5B54315 /* BarLineScatterCandleBubbleChartDataProvider.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = BarLineScatterCandleBubbleChartDataProvider.swift; path = Source/Charts/Interfaces/BarLineScatterCandleBubbleChartDataProvider.swift; sourceTree = ""; }; 910DBFE1DA1B2CA237A736DF /* Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; name = Info.plist; path = "Source/Supporting Files/Info.plist"; sourceTree = ""; }; 91EEEDE2AB8F2DA3AFCF0733 /* RadarChartDataEntry.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RadarChartDataEntry.swift; path = Source/Charts/Data/Implementations/Standard/RadarChartDataEntry.swift; sourceTree = ""; }; 923206233CA89FD03565FF87 /* LineScatterCandleRadarRenderer.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = LineScatterCandleRadarRenderer.swift; path = Source/Charts/Renderers/LineScatterCandleRadarRenderer.swift; sourceTree = ""; }; - 9249AD9AEC8C85772365A128 /* ILineScatterCandleRadarChartDataSet.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ILineScatterCandleRadarChartDataSet.swift; path = Source/Charts/Data/Interfaces/ILineScatterCandleRadarChartDataSet.swift; sourceTree = ""; }; + 9249AD9AEC8C85772365A128 /* LineScatterCandleRadarChartDataSetProtocol.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = LineScatterCandleRadarChartDataSetProtocol.swift; path = Source/Charts/Data/Interfaces/LineScatterCandleRadarChartDataSetProtocol.swift; sourceTree = ""; }; 93EF9709CF635BEE70D1ABC5 /* DataApproximator.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = DataApproximator.swift; path = Source/Charts/Filters/DataApproximator.swift; sourceTree = ""; }; 97AD2D4520AF917100F9C24A /* Platform+Accessibility.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "Platform+Accessibility.swift"; path = "Source/Charts/Utils/Platform+Accessibility.swift"; sourceTree = ""; }; - 998F2BFE318471AFC05B50AC /* IHighlighter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = IHighlighter.swift; path = Source/Charts/Highlight/IHighlighter.swift; sourceTree = ""; }; 9A26C8DA1F87B01700367599 /* DataApproximator+N.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "DataApproximator+N.swift"; path = "Source/Charts/Filters/DataApproximator+N.swift"; sourceTree = ""; }; 9D7184C8A5A60A3522AB9B05 /* BarChartDataProvider.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = BarChartDataProvider.swift; path = Source/Charts/Interfaces/BarChartDataProvider.swift; sourceTree = ""; }; 9DCD13D558BA177D5952AD66 /* PieChartView.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = PieChartView.swift; path = Source/Charts/Charts/PieChartView.swift; sourceTree = ""; }; 9E7C673B9ED4340F550A9283 /* LegendEntry.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = LegendEntry.swift; path = Source/Charts/Components/LegendEntry.swift; sourceTree = ""; }; A140F644332704916947B58C /* CombinedChartDataProvider.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = CombinedChartDataProvider.swift; path = Source/Charts/Interfaces/CombinedChartDataProvider.swift; sourceTree = ""; }; A4FB5E3761EF8B4D1E1E1014 /* PieChartDataSet.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = PieChartDataSet.swift; path = Source/Charts/Data/Implementations/Standard/PieChartDataSet.swift; sourceTree = ""; }; - A5649B272BF3EBFC8A1EF0C1 /* IBarLineScatterCandleBubbleChartDataSet.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = IBarLineScatterCandleBubbleChartDataSet.swift; path = Source/Charts/Data/Interfaces/IBarLineScatterCandleBubbleChartDataSet.swift; sourceTree = ""; }; + A5649B272BF3EBFC8A1EF0C1 /* BarLineScatterCandleBubbleChartDataSetProtocol.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = BarLineScatterCandleBubbleChartDataSetProtocol.swift; path = Source/Charts/Data/Interfaces/BarLineScatterCandleBubbleChartDataSetProtocol.swift; sourceTree = ""; }; A5A75AA73C5AA381DA517959 /* LineChartDataSet.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = LineChartDataSet.swift; path = Source/Charts/Data/Implementations/Standard/LineChartDataSet.swift; sourceTree = ""; }; AA5A16F4A382813C4FE8BDF9 /* YAxisRendererRadarChart.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = YAxisRendererRadarChart.swift; path = Source/Charts/Renderers/YAxisRendererRadarChart.swift; sourceTree = ""; }; AA70259ED16FF80D8EEB0F94 /* ChevronUpShapeRenderer.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ChevronUpShapeRenderer.swift; path = Source/Charts/Renderers/Scatter/ChevronUpShapeRenderer.swift; sourceTree = ""; }; @@ -287,12 +287,12 @@ BD02157CF8CEE1189BF681DA /* PieChartDataEntry.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = PieChartDataEntry.swift; path = Source/Charts/Data/Implementations/Standard/PieChartDataEntry.swift; sourceTree = ""; }; BD5C6D20243EC2F19069AACD /* CandleStickChartRenderer.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = CandleStickChartRenderer.swift; path = Source/Charts/Renderers/CandleStickChartRenderer.swift; sourceTree = ""; }; BFABD027DAF6851088F002AC /* LineChartDataProvider.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = LineChartDataProvider.swift; path = Source/Charts/Interfaces/LineChartDataProvider.swift; sourceTree = ""; }; - C03E6D8023DAAB2600083010 /* ChartDataTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChartDataTests.swift; sourceTree = ""; }; + C03E6D8023DAAB2600083010 /* ChartDataTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ChartDataTests.swift; path = Tests/Charts/ChartDataTests.swift; sourceTree = ""; }; C31AA65EA27776F8C653C7E8 /* BarChartDataSet.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = BarChartDataSet.swift; path = Source/Charts/Data/Implementations/Standard/BarChartDataSet.swift; sourceTree = ""; }; C52E8344160B5E689DA3C25C /* ChevronDownShapeRenderer.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ChevronDownShapeRenderer.swift; path = Source/Charts/Renderers/Scatter/ChevronDownShapeRenderer.swift; sourceTree = ""; }; C574E1BC7E12D937A5471EF8 /* Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; name = Info.plist; path = "Tests/Supporting Files/Info.plist"; sourceTree = ""; }; C58BD7B14BEA440783ED8D2B /* LineScatterCandleRadarChartDataSet.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = LineScatterCandleRadarChartDataSet.swift; path = Source/Charts/Data/Implementations/Standard/LineScatterCandleRadarChartDataSet.swift; sourceTree = ""; }; - C75935E899183DDFA181E2CC /* AxisRendererBase.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = AxisRendererBase.swift; path = Source/Charts/Renderers/AxisRendererBase.swift; sourceTree = ""; }; + C75935E899183DDFA181E2CC /* AxisRenderer.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = AxisRenderer.swift; path = Source/Charts/Renderers/AxisRenderer.swift; sourceTree = ""; }; C8C9A105A7DB64F39DDA648B /* ComponentBase.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ComponentBase.swift; path = Source/Charts/Components/ComponentBase.swift; sourceTree = ""; }; C8FB6219B143F8F7DA762950 /* TriangleShapeRenderer.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = TriangleShapeRenderer.swift; path = Source/Charts/Renderers/Scatter/TriangleShapeRenderer.swift; sourceTree = ""; }; C9AA36092355F01F00C97D93 /* Platform+Color.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "Platform+Color.swift"; path = "Source/Charts/Utils/Platform+Color.swift"; sourceTree = ""; }; @@ -304,7 +304,7 @@ D2E1819D72CD7B6C4A4E8048 /* LineChartTests.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = LineChartTests.swift; path = Tests/Charts/LineChartTests.swift; sourceTree = ""; }; D2E698FF540029B70AC97AD7 /* CandleChartDataEntry.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = CandleChartDataEntry.swift; path = Source/Charts/Data/Implementations/Standard/CandleChartDataEntry.swift; sourceTree = ""; }; D6C1BEFDF17404666C7B6054 /* DefaultFillFormatter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = DefaultFillFormatter.swift; path = Source/Charts/Formatters/DefaultFillFormatter.swift; sourceTree = ""; }; - DA2AA6CC89F809DCCD7605B4 /* IPieChartDataSet.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = IPieChartDataSet.swift; path = Source/Charts/Data/Interfaces/IPieChartDataSet.swift; sourceTree = ""; }; + DA2AA6CC89F809DCCD7605B4 /* PieChartDataSetProtocol.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = PieChartDataSetProtocol.swift; path = Source/Charts/Data/Interfaces/PieChartDataSetProtocol.swift; sourceTree = ""; }; DD8ED233775EEC31243A6919 /* BubbleChartDataEntry.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = BubbleChartDataEntry.swift; path = Source/Charts/Data/Implementations/Standard/BubbleChartDataEntry.swift; sourceTree = ""; }; DFB762958EE8E6521563665D /* ChartAnimationEasing.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ChartAnimationEasing.swift; path = Source/Charts/Animation/ChartAnimationEasing.swift; sourceTree = ""; }; E120E76C6F1B5877D56126DD /* ChartData.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ChartData.swift; path = Source/Charts/Data/Implementations/Standard/ChartData.swift; sourceTree = ""; }; @@ -317,12 +317,12 @@ EDEAF554FD0D68EA4C0E7E49 /* BubbleChartDataProvider.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = BubbleChartDataProvider.swift; path = Source/Charts/Interfaces/BubbleChartDataProvider.swift; sourceTree = ""; }; F22750328058DEC2F019646F /* ChartDataEntry.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ChartDataEntry.swift; path = Source/Charts/Data/Implementations/Standard/ChartDataEntry.swift; sourceTree = ""; }; F368CF209744D8F3B85B1028 /* RadarHighlighter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RadarHighlighter.swift; path = Source/Charts/Highlight/RadarHighlighter.swift; sourceTree = ""; }; - F3788EC55EF908B0805D7C2F /* IBubbleChartDataSet.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = IBubbleChartDataSet.swift; path = Source/Charts/Data/Interfaces/IBubbleChartDataSet.swift; sourceTree = ""; }; + F3788EC55EF908B0805D7C2F /* BubbleChartDataSetProtocol.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = BubbleChartDataSetProtocol.swift; path = Source/Charts/Data/Interfaces/BubbleChartDataSetProtocol.swift; sourceTree = ""; }; F4785FEACAE4367F36FB8868 /* CandleChartData.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = CandleChartData.swift; path = Source/Charts/Data/Implementations/Standard/CandleChartData.swift; sourceTree = ""; }; F6227A646166E248F90F86AD /* ChartColorTemplates.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ChartColorTemplates.swift; path = Source/Charts/Utils/ChartColorTemplates.swift; sourceTree = ""; }; F6DEBFAB1D73E944ED430B4F /* ChartLimitLine.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ChartLimitLine.swift; path = Source/Charts/Components/ChartLimitLine.swift; sourceTree = ""; }; F715DB2C56C9E0615542625B /* LegendRenderer.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = LegendRenderer.swift; path = Source/Charts/Renderers/LegendRenderer.swift; sourceTree = ""; }; - FA1D3D13180C2E3893A82546 /* IShapeRenderer.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = IShapeRenderer.swift; path = Source/Charts/Renderers/Scatter/IShapeRenderer.swift; sourceTree = ""; }; + FA1D3D13180C2E3893A82546 /* ShapeRenderer.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ShapeRenderer.swift; path = Source/Charts/Renderers/Scatter/ShapeRenderer.swift; sourceTree = ""; }; FA7BDB22C97F39A4B33E38A7 /* ViewPortJob.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ViewPortJob.swift; path = Source/Charts/Jobs/ViewPortJob.swift; sourceTree = ""; }; FB3A4F5987E58F3E5BE855F9 /* ZoomViewJob.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ZoomViewJob.swift; path = Source/Charts/Jobs/ZoomViewJob.swift; sourceTree = ""; }; FB92A80F861C1362EED8D946 /* YAxis.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = YAxis.swift; path = Source/Charts/Components/YAxis.swift; sourceTree = ""; }; @@ -348,7 +348,7 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ - 031D7C33F3BF172E30664862 /* Interfaces */ = { + 031D7C33F3BF172E30664862 /* DataProviders */ = { isa = PBXGroup; children = ( 9D7184C8A5A60A3522AB9B05 /* BarChartDataProvider.swift */, @@ -360,7 +360,7 @@ BFABD027DAF6851088F002AC /* LineChartDataProvider.swift */, 2FD37A55B4D85D883E29C744 /* ScatterChartDataProvider.swift */, ); - name = Interfaces; + name = DataProviders; sourceTree = ""; }; 033FD152BB2F906750106A85 /* Frameworks */ = { @@ -373,8 +373,10 @@ 098621EDFBF928494B94BEA1 /* Data */ = { isa = PBXGroup; children = ( - 3B9DD76FCE8D873300A822C7 /* Implementations */, - DB2D9648877455028EBEAA8F /* Interfaces */, + 22C014222006FFE800D5B025 /* ChartData */, + 3B9DD76FCE8D873300A822C7 /* ChartDataSet */, + 22C014232006FFFA00D5B025 /* ChartEntry */, + DB2D9648877455028EBEAA8F /* DataSet Protocols */, ); name = Data; sourceTree = ""; @@ -388,6 +390,71 @@ name = Source; sourceTree = ""; }; + 2227EA571FF1F219007D98D9 /* AxisRenderers */ = { + isa = PBXGroup; + children = ( + C75935E899183DDFA181E2CC /* AxisRenderer.swift */, + 1C02C3AF5C92FCFC18224C35 /* XAxisRenderer.swift */, + 1F3D55A7E6176D52DC957D27 /* XAxisRendererHorizontalBarChart.swift */, + BC19DC2434D65FFB446A61B7 /* XAxisRendererRadarChart.swift */, + 688B80F1AA88AE54152BE768 /* YAxisRenderer.swift */, + EAE417AAA0FCA0DD00E77489 /* YAxisRendererHorizontalBarChart.swift */, + AA5A16F4A382813C4FE8BDF9 /* YAxisRendererRadarChart.swift */, + ); + name = AxisRenderers; + sourceTree = ""; + }; + 2227EA581FF1F224007D98D9 /* ChartRenderers */ = { + isa = PBXGroup; + children = ( + 0216EDC6A1FE272F4EB19FCF /* DataRenderer.swift */, + 75F279974FE650E57A061B09 /* BarChartRenderer.swift */, + 5B1C588E9DF6FFD56D7ADF8E /* BarLineScatterCandleBubbleRenderer.swift */, + 2194AA554712E6BA2677F114 /* BubbleChartRenderer.swift */, + BD5C6D20243EC2F19069AACD /* CandleStickChartRenderer.swift */, + 52265C1B343CCC41AF2300E3 /* CombinedChartRenderer.swift */, + 539382766378B702660FDFB2 /* HorizontalBarChartRenderer.swift */, + 0DABDBBCCE6B3620C967F04A /* LineChartRenderer.swift */, + 105FFC9D3773A9C7A60A897F /* LineRadarRenderer.swift */, + 923206233CA89FD03565FF87 /* LineScatterCandleRadarRenderer.swift */, + 46D8013D44629521B1746364 /* PieChartRenderer.swift */, + 7AC9C3D69ACB5BDE22421E15 /* RadarChartRenderer.swift */, + 80D5B764EC0AE1E17E55DC67 /* ScatterChartRenderer.swift */, + ); + name = ChartRenderers; + sourceTree = ""; + }; + 22C014222006FFE800D5B025 /* ChartData */ = { + isa = PBXGroup; + children = ( + 0108D5925E21A47DA36A66AA /* BarChartData.swift */, + 559DB735FEA17AB90676D6CA /* BarLineScatterCandleBubbleChartData.swift */, + 7EDA3AD550AEFC93C8D15B9C /* BubbleChartData.swift */, + F4785FEACAE4367F36FB8868 /* CandleChartData.swift */, + E120E76C6F1B5877D56126DD /* ChartData.swift */, + 0DDE409E9ECF54D2C146A6F0 /* CombinedChartData.swift */, + 4C978F31F23C7D21197DC2A1 /* LineChartData.swift */, + 6E03A4987F72414A02A0631B /* PieChartData.swift */, + 4BBB57D6FA41029B08F26D7B /* RadarChartData.swift */, + E7AD2FC320A16CA1EE0A52F4 /* ScatterChartData.swift */, + ); + name = ChartData; + sourceTree = ""; + }; + 22C014232006FFFA00D5B025 /* ChartEntry */ = { + isa = PBXGroup; + children = ( + E3F8BFF1CBC58D5B9DBFFB9B /* BarChartDataEntry.swift */, + DD8ED233775EEC31243A6919 /* BubbleChartDataEntry.swift */, + D2E698FF540029B70AC97AD7 /* CandleChartDataEntry.swift */, + F22750328058DEC2F019646F /* ChartDataEntry.swift */, + 12409C3EA15787C11AF0D2BC /* ChartDataEntryBase.swift */, + BD02157CF8CEE1189BF681DA /* PieChartDataEntry.swift */, + 91EEEDE2AB8F2DA3AFCF0733 /* RadarChartDataEntry.swift */, + ); + name = ChartEntry; + sourceTree = ""; + }; 2647844720BC6574A544A337 /* Charts */ = { isa = PBXGroup; children = ( @@ -398,7 +465,7 @@ AA79AB82B0ADCA926510B73E /* Filters */, 74A391010038924F637D6752 /* Formatters */, 42824E1F334B0C484AF4C594 /* Highlight */, - 031D7C33F3BF172E30664862 /* Interfaces */, + 031D7C33F3BF172E30664862 /* DataProviders */, AD1224C45A29A5C88D6B7450 /* Jobs */, E7589D3E7C2BD2449960AD59 /* Renderers */, D047819AB7170595896D6FE8 /* Utils */, @@ -406,24 +473,34 @@ name = Charts; sourceTree = ""; }; - 3B9DD76FCE8D873300A822C7 /* Implementations */ = { + 3B9DD76FCE8D873300A822C7 /* ChartDataSet */ = { isa = PBXGroup; children = ( C9FE42E868A225C116537368 /* ChartBaseDataSet.swift */, - 740017197A160047EBB8A9A0 /* Standard */, + C31AA65EA27776F8C653C7E8 /* BarChartDataSet.swift */, + 6D717F0808DE7EC8A4AE9C2A /* BarLineScatterCandleBubbleChartDataSet.swift */, + B44829AF0ADA583F1F0279B7 /* BubbleChartDataSet.swift */, + 274116834B1B0345D622E027 /* CandleChartDataSet.swift */, + 6CEC0C69C89CE9B99F3B4409 /* ChartDataSet.swift */, + A5A75AA73C5AA381DA517959 /* LineChartDataSet.swift */, + 45E31A4356CC6F283C29954B /* LineRadarChartDataSet.swift */, + C58BD7B14BEA440783ED8D2B /* LineScatterCandleRadarChartDataSet.swift */, + A4FB5E3761EF8B4D1E1E1014 /* PieChartDataSet.swift */, + B1BA6B21CBDF77A15848994F /* RadarChartDataSet.swift */, + CB1DD1A0F64266A10EE94194 /* ScatterChartDataSet.swift */, ); - name = Implementations; + name = ChartDataSet; sourceTree = ""; }; 42824E1F334B0C484AF4C594 /* Highlight */ = { isa = PBXGroup; children = ( + 06AB297E20FA726500BAD505 /* Highlighter.swift */, 543729805D897CC03E5F78D3 /* BarHighlighter.swift */, 5983826927D825EF5F855C28 /* ChartHighlighter.swift */, 2465CB73738EBAFB46C57288 /* CombinedHighlighter.swift */, 3D64616883374310C505EC39 /* Highlight.swift */, 33BE9A97FFA41D3D85CAFFC7 /* HorizontalBarHighlighter.swift */, - 998F2BFE318471AFC05B50AC /* IHighlighter.swift */, 7036F11832C017E26AC750A4 /* PieHighlighter.swift */, 04F7B9DF1F2D66E7279771D4 /* PieRadarHighlighter.swift */, F368CF209744D8F3B85B1028 /* RadarHighlighter.swift */, @@ -439,7 +516,7 @@ F6DEBFAB1D73E944ED430B4F /* ChartLimitLine.swift */, C8C9A105A7DB64F39DDA648B /* ComponentBase.swift */, B137428B41C143D5115726C4 /* Description.swift */, - 596963A429D485E3894C4666 /* IMarker.swift */, + 596963A429D485E3894C4666 /* Marker.swift */, E64A75540C627E09080B402A /* Legend.swift */, 9E7C673B9ED4340F550A9283 /* LegendEntry.swift */, 392AAEB02DD7B351D92907C2 /* MarkerImage.swift */, @@ -450,51 +527,16 @@ name = Components; sourceTree = ""; }; - 740017197A160047EBB8A9A0 /* Standard */ = { - isa = PBXGroup; - children = ( - 0108D5925E21A47DA36A66AA /* BarChartData.swift */, - E3F8BFF1CBC58D5B9DBFFB9B /* BarChartDataEntry.swift */, - C31AA65EA27776F8C653C7E8 /* BarChartDataSet.swift */, - 559DB735FEA17AB90676D6CA /* BarLineScatterCandleBubbleChartData.swift */, - 6D717F0808DE7EC8A4AE9C2A /* BarLineScatterCandleBubbleChartDataSet.swift */, - 7EDA3AD550AEFC93C8D15B9C /* BubbleChartData.swift */, - DD8ED233775EEC31243A6919 /* BubbleChartDataEntry.swift */, - B44829AF0ADA583F1F0279B7 /* BubbleChartDataSet.swift */, - F4785FEACAE4367F36FB8868 /* CandleChartData.swift */, - D2E698FF540029B70AC97AD7 /* CandleChartDataEntry.swift */, - 274116834B1B0345D622E027 /* CandleChartDataSet.swift */, - E120E76C6F1B5877D56126DD /* ChartData.swift */, - F22750328058DEC2F019646F /* ChartDataEntry.swift */, - 12409C3EA15787C11AF0D2BC /* ChartDataEntryBase.swift */, - 6CEC0C69C89CE9B99F3B4409 /* ChartDataSet.swift */, - 0DDE409E9ECF54D2C146A6F0 /* CombinedChartData.swift */, - 4C978F31F23C7D21197DC2A1 /* LineChartData.swift */, - A5A75AA73C5AA381DA517959 /* LineChartDataSet.swift */, - 45E31A4356CC6F283C29954B /* LineRadarChartDataSet.swift */, - C58BD7B14BEA440783ED8D2B /* LineScatterCandleRadarChartDataSet.swift */, - 6E03A4987F72414A02A0631B /* PieChartData.swift */, - BD02157CF8CEE1189BF681DA /* PieChartDataEntry.swift */, - A4FB5E3761EF8B4D1E1E1014 /* PieChartDataSet.swift */, - 4BBB57D6FA41029B08F26D7B /* RadarChartData.swift */, - 91EEEDE2AB8F2DA3AFCF0733 /* RadarChartDataEntry.swift */, - B1BA6B21CBDF77A15848994F /* RadarChartDataSet.swift */, - E7AD2FC320A16CA1EE0A52F4 /* ScatterChartData.swift */, - CB1DD1A0F64266A10EE94194 /* ScatterChartDataSet.swift */, - ); - name = Standard; - sourceTree = ""; - }; 74A391010038924F637D6752 /* Formatters */ = { isa = PBXGroup; children = ( 6A4770E0F75EFFC30707A7C8 /* DefaultAxisValueFormatter.swift */, D6C1BEFDF17404666C7B6054 /* DefaultFillFormatter.swift */, 107D8F8163EE54D6D9E916B0 /* DefaultValueFormatter.swift */, - 0BD9DF16AF59680A3BB49452 /* IAxisValueFormatter.swift */, - 818AC6B12505B7C0A53D62F9 /* IFillFormatter.swift */, + 0BD9DF16AF59680A3BB49452 /* AxisValueFormatter.swift */, + 818AC6B12505B7C0A53D62F9 /* FillFormatter.swift */, 10DD0A02E3CF611BD11EBA9B /* IndexAxisValueFormatter.swift */, - 4EAA8AA30C377D54D22A577A /* IValueFormatter.swift */, + 4EAA8AA30C377D54D22A577A /* ValueFormatter.swift */, ); name = Formatters; sourceTree = ""; @@ -533,8 +575,8 @@ children = ( 5C3F5E1A69EC06E86505F7B1 /* BarChartTests.swift */, B66817452241E3CC00017CF1 /* HorizontalBarChartTests.swift */, - 224EFF981FBAAC4700CF9B3B /* EquatableTests.swift */, 7AB9062A28AAB9469752A954 /* ChartUtilsTests.swift */, + 2243BBFB1FF156D000B49D0B /* EquatableTests.swift */, B6BF9A551F91993A00E62A5D /* CombinedChartTests.swift */, D2E1819D72CD7B6C4A4E8048 /* LineChartTests.swift */, 135F11CD20425AF600D655A3 /* PieChartTests.swift */, @@ -621,50 +663,32 @@ name = Tests; sourceTree = ""; }; - DB2D9648877455028EBEAA8F /* Interfaces */ = { + DB2D9648877455028EBEAA8F /* DataSet Protocols */ = { isa = PBXGroup; children = ( - 7A53A9E42FC07FFDACA937C1 /* IBarChartDataSet.swift */, - A5649B272BF3EBFC8A1EF0C1 /* IBarLineScatterCandleBubbleChartDataSet.swift */, - F3788EC55EF908B0805D7C2F /* IBubbleChartDataSet.swift */, - 18BFB0A14A5C47A302A597D9 /* ICandleChartDataSet.swift */, - 3A32510073A303CBB38E094A /* IChartDataSet.swift */, - 429E88F2729735DC092EE556 /* ILineChartDataSet.swift */, - 4F7E6A99D82E6AE3804D5A39 /* ILineRadarChartDataSet.swift */, - 9249AD9AEC8C85772365A128 /* ILineScatterCandleRadarChartDataSet.swift */, - DA2AA6CC89F809DCCD7605B4 /* IPieChartDataSet.swift */, - 2EAD807534620E3B53327F04 /* IRadarChartDataSet.swift */, - 219BC9CEA037F897E92E45D1 /* IScatterChartDataSet.swift */, + 7A53A9E42FC07FFDACA937C1 /* BarChartDataSetProtocol.swift */, + A5649B272BF3EBFC8A1EF0C1 /* BarLineScatterCandleBubbleChartDataSetProtocol.swift */, + F3788EC55EF908B0805D7C2F /* BubbleChartDataSetProtocol.swift */, + 18BFB0A14A5C47A302A597D9 /* CandleChartDataSetProtocol.swift */, + 3A32510073A303CBB38E094A /* ChartDataSetProtocol.swift */, + 429E88F2729735DC092EE556 /* LineChartDataSetProtocol.swift */, + 4F7E6A99D82E6AE3804D5A39 /* LineRadarChartDataSetProtocol.swift */, + 9249AD9AEC8C85772365A128 /* LineScatterCandleRadarChartDataSetProtocol.swift */, + DA2AA6CC89F809DCCD7605B4 /* PieChartDataSetProtocol.swift */, + 2EAD807534620E3B53327F04 /* RadarChartDataSetProtocol.swift */, + 219BC9CEA037F897E92E45D1 /* ScatterChartDataSetProtocol.swift */, ); - name = Interfaces; + name = "DataSet Protocols"; sourceTree = ""; }; E7589D3E7C2BD2449960AD59 /* Renderers */ = { isa = PBXGroup; children = ( - C75935E899183DDFA181E2CC /* AxisRendererBase.swift */, - 75F279974FE650E57A061B09 /* BarChartRenderer.swift */, - 5B1C588E9DF6FFD56D7ADF8E /* BarLineScatterCandleBubbleRenderer.swift */, - 2194AA554712E6BA2677F114 /* BubbleChartRenderer.swift */, - BD5C6D20243EC2F19069AACD /* CandleStickChartRenderer.swift */, - 0216EDC6A1FE272F4EB19FCF /* ChartDataRendererBase.swift */, - 52265C1B343CCC41AF2300E3 /* CombinedChartRenderer.swift */, - 539382766378B702660FDFB2 /* HorizontalBarChartRenderer.swift */, F715DB2C56C9E0615542625B /* LegendRenderer.swift */, - 0DABDBBCCE6B3620C967F04A /* LineChartRenderer.swift */, - 105FFC9D3773A9C7A60A897F /* LineRadarRenderer.swift */, - 923206233CA89FD03565FF87 /* LineScatterCandleRadarRenderer.swift */, - 46D8013D44629521B1746364 /* PieChartRenderer.swift */, - 7AC9C3D69ACB5BDE22421E15 /* RadarChartRenderer.swift */, 6F66B32AD8A878CBD6DB6ED2 /* Renderer.swift */, - F7059584CB30EF419CFB3335 /* Scatter */, - 80D5B764EC0AE1E17E55DC67 /* ScatterChartRenderer.swift */, - 1C02C3AF5C92FCFC18224C35 /* XAxisRenderer.swift */, - 1F3D55A7E6176D52DC957D27 /* XAxisRendererHorizontalBarChart.swift */, - BC19DC2434D65FFB446A61B7 /* XAxisRendererRadarChart.swift */, - 688B80F1AA88AE54152BE768 /* YAxisRenderer.swift */, - EAE417AAA0FCA0DD00E77489 /* YAxisRendererHorizontalBarChart.swift */, - AA5A16F4A382813C4FE8BDF9 /* YAxisRendererRadarChart.swift */, + 2227EA571FF1F219007D98D9 /* AxisRenderers */, + 2227EA581FF1F224007D98D9 /* ChartRenderers */, + F7059584CB30EF419CFB3335 /* ShapeRenderer */, ); name = Renderers; sourceTree = ""; @@ -678,19 +702,19 @@ name = "Supporting Files"; sourceTree = ""; }; - F7059584CB30EF419CFB3335 /* Scatter */ = { + F7059584CB30EF419CFB3335 /* ShapeRenderer */ = { isa = PBXGroup; children = ( C52E8344160B5E689DA3C25C /* ChevronDownShapeRenderer.swift */, AA70259ED16FF80D8EEB0F94 /* ChevronUpShapeRenderer.swift */, ECE1B1623D3AF69CECAE8562 /* CircleShapeRenderer.swift */, 823F7DB281C6C6F069A69605 /* CrossShapeRenderer.swift */, - FA1D3D13180C2E3893A82546 /* IShapeRenderer.swift */, + FA1D3D13180C2E3893A82546 /* ShapeRenderer.swift */, 32FC01A016DFF1BA73AF9182 /* SquareShapeRenderer.swift */, C8FB6219B143F8F7DA762950 /* TriangleShapeRenderer.swift */, 23D35CF6F9177D77B6B97AE1 /* XShapeRenderer.swift */, ); - name = Scatter; + name = ShapeRenderer; sourceTree = ""; }; /* End PBXGroup section */ @@ -755,7 +779,7 @@ LastUpgradeCheck = 1200; TargetAttributes = { A58A4ED274A941CA248EA921 = { - LastSwiftMigration = 0900; + LastSwiftMigration = 1150; }; F2749BD5443C1CB5FE2080C2 = { LastSwiftMigration = 0900; @@ -852,7 +876,7 @@ 4390D74986A92DEF4F4F2BF0 /* ChartLimitLine.swift in Sources */, FDBDAFA7A5337C6E3992DACE /* ComponentBase.swift in Sources */, DBC9DB402CC9BB84B76968C4 /* Description.swift in Sources */, - 03960E8148C6AEDACE4B77CC /* IMarker.swift in Sources */, + 03960E8148C6AEDACE4B77CC /* Marker.swift in Sources */, ECE7EAE7179A7F57CE9BBD8F /* Legend.swift in Sources */, C9F3DC272355F791000C3215 /* Platform+Gestures.swift in Sources */, C20A62D8CB9120523D5FB650 /* LegendEntry.swift in Sources */, @@ -891,32 +915,31 @@ 9A26C8DB1F87B01700367599 /* DataApproximator+N.swift in Sources */, 2B791E64E7C4523B1A63F72A /* ScatterChartData.swift in Sources */, EB56849433A76B08606B73EB /* ScatterChartDataSet.swift in Sources */, - C3F0DDB7F0A922F0BB7EDB8A /* IBarChartDataSet.swift in Sources */, - AF4AAF3709ED9DDF6362EAE8 /* IBarLineScatterCandleBubbleChartDataSet.swift in Sources */, - 2C40CFFC8D88BEA70E0A50B0 /* IBubbleChartDataSet.swift in Sources */, - 0D8A89398F9BD5DCC8D7F976 /* ICandleChartDataSet.swift in Sources */, - E8F0F4F47CD7D72B4EE5A794 /* IChartDataSet.swift in Sources */, - F941C88BF814DF51C465CB95 /* ILineChartDataSet.swift in Sources */, - 1311BEC21E9CC264E971EFAF /* ILineRadarChartDataSet.swift in Sources */, - 146EE16342C2BADC92E45BF2 /* ILineScatterCandleRadarChartDataSet.swift in Sources */, - FAAD9FF6565DED2652188584 /* IPieChartDataSet.swift in Sources */, - 83BBAF3EDC31FD452F8BF1DB /* IRadarChartDataSet.swift in Sources */, - 50476F8E6662CAFC1EFE0723 /* IScatterChartDataSet.swift in Sources */, + C3F0DDB7F0A922F0BB7EDB8A /* BarChartDataSetProtocol.swift in Sources */, + AF4AAF3709ED9DDF6362EAE8 /* BarLineScatterCandleBubbleChartDataSetProtocol.swift in Sources */, + 2C40CFFC8D88BEA70E0A50B0 /* BubbleChartDataSetProtocol.swift in Sources */, + 0D8A89398F9BD5DCC8D7F976 /* CandleChartDataSetProtocol.swift in Sources */, + E8F0F4F47CD7D72B4EE5A794 /* ChartDataSetProtocol.swift in Sources */, + F941C88BF814DF51C465CB95 /* LineChartDataSetProtocol.swift in Sources */, + 1311BEC21E9CC264E971EFAF /* LineRadarChartDataSetProtocol.swift in Sources */, + 146EE16342C2BADC92E45BF2 /* LineScatterCandleRadarChartDataSetProtocol.swift in Sources */, + FAAD9FF6565DED2652188584 /* PieChartDataSetProtocol.swift in Sources */, + 83BBAF3EDC31FD452F8BF1DB /* RadarChartDataSetProtocol.swift in Sources */, + 50476F8E6662CAFC1EFE0723 /* ScatterChartDataSetProtocol.swift in Sources */, 97E033CC0ABEF0F448DAFA8E /* DataApproximator.swift in Sources */, 779B46E9F13A087BFA47D539 /* DefaultAxisValueFormatter.swift in Sources */, F744C510DA9B85C228BBB335 /* DefaultFillFormatter.swift in Sources */, B0D28C68BB9A958DC56EB214 /* DefaultValueFormatter.swift in Sources */, - B13C74B4FF705D7B595D01EF /* IAxisValueFormatter.swift in Sources */, - B6C9F450D937B87224D29D5C /* IFillFormatter.swift in Sources */, + B13C74B4FF705D7B595D01EF /* AxisValueFormatter.swift in Sources */, + B6C9F450D937B87224D29D5C /* FillFormatter.swift in Sources */, 967EE2EDDE3337C5C4337C59 /* IndexAxisValueFormatter.swift in Sources */, - A40ACF0CCE96EEE104B0463D /* IValueFormatter.swift in Sources */, + A40ACF0CCE96EEE104B0463D /* ValueFormatter.swift in Sources */, C9F3DC262355F791000C3215 /* Platform+Graphics.swift in Sources */, 3CBE95F1E9394FA08CDCF31E /* BarHighlighter.swift in Sources */, D326491E8BCDE54A0921E137 /* ChartHighlighter.swift in Sources */, 64FA1EDB4DC1F65727D52D10 /* CombinedHighlighter.swift in Sources */, 758EB1C75063ED3373542F3B /* Highlight.swift in Sources */, 4E98788ABEF6496C23F3E6C6 /* HorizontalBarHighlighter.swift in Sources */, - 203A39685CC96FC625F616E4 /* IHighlighter.swift in Sources */, 73EDF662AD989E930D365B72 /* PieHighlighter.swift in Sources */, 3097296AC7FFA994FE4AD312 /* PieRadarHighlighter.swift in Sources */, C33E1AF5471A60BA42DAF52E /* RadarHighlighter.swift in Sources */, @@ -930,18 +953,19 @@ 65EA404AE098EBCE8D5DE04B /* CombinedChartDataProvider.swift in Sources */, 2BA03CEC36BADCF682F1328B /* LineChartDataProvider.swift in Sources */, 0511E43EF3FD2CDE7F7F15DB /* ScatterChartDataProvider.swift in Sources */, + 06AB297F20FA726600BAD505 /* Highlighter.swift in Sources */, 7EE6EFE70CF4D8B09CAFCD01 /* AnimatedMoveViewJob.swift in Sources */, CC7F8198A13249B5DEBBF25E /* AnimatedViewPortJob.swift in Sources */, 0577C2B38BCE4C871F262714 /* AnimatedZoomViewJob.swift in Sources */, 02A6E6E1A82A27A66B8D08C4 /* MoveViewJob.swift in Sources */, 9400725714D0DA707DDECD2E /* ViewPortJob.swift in Sources */, AEE9C4E4AC02B8FB3CD21975 /* ZoomViewJob.swift in Sources */, - ECECC58CEF03B1718F8267E8 /* AxisRendererBase.swift in Sources */, + ECECC58CEF03B1718F8267E8 /* AxisRenderer.swift in Sources */, 23FA50B2730D8C7ACA091C4F /* BarChartRenderer.swift in Sources */, 219192CA6B4895319AB49DCA /* BarLineScatterCandleBubbleRenderer.swift in Sources */, 56E0F5EA9255B9B92876E040 /* BubbleChartRenderer.swift in Sources */, 8BCCD709AACC565613D9DA68 /* CandleStickChartRenderer.swift in Sources */, - F37B07008B8AE7F3909FFB9C /* ChartDataRendererBase.swift in Sources */, + F37B07008B8AE7F3909FFB9C /* DataRenderer.swift in Sources */, 05253AFC448C107DEF54C2FE /* CombinedChartRenderer.swift in Sources */, F100D68395F169B93590FA96 /* HorizontalBarChartRenderer.swift in Sources */, 2B821AAC3EBD60A73EACBCE6 /* LegendRenderer.swift in Sources */, @@ -956,7 +980,7 @@ F103D90FC5DEEA0D7BB4407E /* ChevronUpShapeRenderer.swift in Sources */, B85DEB06B4C1AFFC8A0E3295 /* CircleShapeRenderer.swift in Sources */, 0529DD51622C8769C1121F90 /* CrossShapeRenderer.swift in Sources */, - 8A9FF54E2075A9047CC8E953 /* IShapeRenderer.swift in Sources */, + 8A9FF54E2075A9047CC8E953 /* ShapeRenderer.swift in Sources */, 8EF7B3FBE37F72CC030CD865 /* SquareShapeRenderer.swift in Sources */, 8F4B1A9060472764073DFA0B /* TriangleShapeRenderer.swift in Sources */, 93A94E1FF55041A6032891FE /* XShapeRenderer.swift in Sources */, @@ -983,13 +1007,13 @@ files = ( 3B11556EB7DC034E2FC958E4 /* BarChartTests.swift in Sources */, 8E1192F7A7152E9DA92C56A9 /* ChartUtilsTests.swift in Sources */, + 2243BBFD1FF156EC00B49D0B /* EquatableTests.swift in Sources */, B6BF9A561F91993A00E62A5D /* CombinedChartTests.swift in Sources */, 2BF85BEA981B359A65E9BF67 /* LineChartTests.swift in Sources */, B66817462241E3CC00017CF1 /* HorizontalBarChartTests.swift in Sources */, 135F11CE20425AF600D655A3 /* PieChartTests.swift in Sources */, 064989461F5C99C7006E8BB3 /* Snapshot.swift in Sources */, C03E6D8123DAAB2600083010 /* ChartDataTests.swift in Sources */, - 224EFF991FBAAC4700CF9B3B /* EquatableTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1024,7 +1048,7 @@ IPHONEOS_DEPLOYMENT_TARGET = 9.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; MACOSX_DEPLOYMENT_TARGET = 10.11; - MARKETING_VERSION = 3.6.0; + MARKETING_VERSION = 4.0.0; MTL_ENABLE_DEBUG_INFO = YES; PRODUCT_BUNDLE_IDENTIFIER = com.dcg.Charts; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -1203,7 +1227,7 @@ IPHONEOS_DEPLOYMENT_TARGET = 9.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; MACOSX_DEPLOYMENT_TARGET = 10.11; - MARKETING_VERSION = 3.6.0; + MARKETING_VERSION = 4.0.0; MTL_ENABLE_DEBUG_INFO = NO; PRODUCT_BUNDLE_IDENTIFIER = com.dcg.Charts; PRODUCT_NAME = "$(TARGET_NAME)"; diff --git a/ChartsDemo-iOS/ChartsDemo-iOS.xcodeproj/project.pbxproj b/ChartsDemo-iOS/ChartsDemo-iOS.xcodeproj/project.pbxproj index 581836ad..c6e200ba 100644 --- a/ChartsDemo-iOS/ChartsDemo-iOS.xcodeproj/project.pbxproj +++ b/ChartsDemo-iOS/ChartsDemo-iOS.xcodeproj/project.pbxproj @@ -656,12 +656,12 @@ TargetAttributes = { 225B361C1F6EB9A50005B3D5 = { CreatedOnToolsVersion = 9.0; - LastSwiftMigration = 1000; + LastSwiftMigration = 1150; }; 5B57BBAE1A9B26AA0036A6CC = { CreatedOnToolsVersion = 6.1.1; - LastSwiftMigration = 0900; - ProvisioningStyle = Manual; + LastSwiftMigration = 1150; + ProvisioningStyle = Automatic; }; }; }; @@ -897,6 +897,7 @@ CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; DEBUG_INFORMATION_FORMAT = dwarf; + DEVELOPMENT_TEAM = ""; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = "$(SRCROOT)/Supporting Files/Info.plist"; IPHONEOS_DEPLOYMENT_TARGET = 9.0; @@ -928,6 +929,7 @@ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEVELOPMENT_TEAM = ""; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = "$(SRCROOT)/Supporting Files/Info.plist"; IPHONEOS_DEPLOYMENT_TARGET = 9.0; @@ -1049,12 +1051,16 @@ ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; + CODE_SIGN_IDENTITY = "Apple Development"; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = ""; FRAMEWORK_SEARCH_PATHS = "$(SOURCE_ROOT)/../Carthage/Build/iOS"; INFOPLIST_FILE = "Supporting Files/Info.plist"; IPHONEOS_DEPLOYMENT_TARGET = 9.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.dcg.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "ChartsDemo-iOS"; + PROVISIONING_PROFILE_SPECIFIER = ""; SUPPORTED_PLATFORMS = "iphonesimulator iphoneos appletvsimulator appletvos"; SWIFT_OBJC_BRIDGING_HEADER = "Supporting Files/ChartsDemo-Bridging-Header.h"; SWIFT_OBJC_INTERFACE_HEADER_NAME = "$(SWIFT_MODULE_NAME)-Swift.h"; @@ -1069,12 +1075,16 @@ ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; + CODE_SIGN_IDENTITY = "Apple Development"; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = ""; FRAMEWORK_SEARCH_PATHS = "$(SOURCE_ROOT)/../Carthage/Build/iOS"; INFOPLIST_FILE = "Supporting Files/Info.plist"; IPHONEOS_DEPLOYMENT_TARGET = 9.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.dcg.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "ChartsDemo-iOS"; + PROVISIONING_PROFILE_SPECIFIER = ""; SUPPORTED_PLATFORMS = "iphonesimulator iphoneos appletvsimulator appletvos"; SWIFT_OBJC_BRIDGING_HEADER = "Supporting Files/ChartsDemo-Bridging-Header.h"; SWIFT_OBJC_INTERFACE_HEADER_NAME = "$(SWIFT_MODULE_NAME)-Swift.h"; diff --git a/ChartsDemo-iOS/Objective-C/Components/XYMarkerView.swift b/ChartsDemo-iOS/Objective-C/Components/XYMarkerView.swift index f985bd50..4d2654d4 100644 --- a/ChartsDemo-iOS/Objective-C/Components/XYMarkerView.swift +++ b/ChartsDemo-iOS/Objective-C/Components/XYMarkerView.swift @@ -12,11 +12,11 @@ import Charts open class XYMarkerView: BalloonMarker { - @objc open var xAxisValueFormatter: IAxisValueFormatter? + @objc open var xAxisValueFormatter: AxisValueFormatter? fileprivate var yFormatter = NumberFormatter() @objc public init(color: UIColor, font: UIFont, textColor: UIColor, insets: UIEdgeInsets, - xAxisValueFormatter: IAxisValueFormatter) + xAxisValueFormatter: AxisValueFormatter) { super.init(color: color, font: font, textColor: textColor, insets: insets) self.xAxisValueFormatter = xAxisValueFormatter diff --git a/ChartsDemo-iOS/Objective-C/DemoBaseViewController.m b/ChartsDemo-iOS/Objective-C/DemoBaseViewController.m index 4e6392a9..a264f2a7 100644 --- a/ChartsDemo-iOS/Objective-C/DemoBaseViewController.m +++ b/ChartsDemo-iOS/Objective-C/DemoBaseViewController.m @@ -75,7 +75,7 @@ - (void)handleOption:(NSString *)key forChartView:(ChartViewBase *)chartView { if ([key isEqualToString:@"toggleValues"]) { - for (id set in chartView.data.dataSets) + for (id set in chartView.data.dataSets) { set.drawValuesEnabled = !set.isDrawValuesEnabled; } @@ -85,7 +85,7 @@ - (void)handleOption:(NSString *)key forChartView:(ChartViewBase *)chartView if ([key isEqualToString:@"toggleIcons"]) { - for (id set in chartView.data.dataSets) + for (id set in chartView.data.dataSets) { set.drawIconsEnabled = !set.isDrawIconsEnabled; } @@ -95,7 +95,7 @@ - (void)handleOption:(NSString *)key forChartView:(ChartViewBase *)chartView if ([key isEqualToString:@"toggleHighlight"]) { - chartView.data.highlightEnabled = !chartView.data.isHighlightEnabled; + chartView.data.isHighlightEnabled = !chartView.data.isHighlightEnabled; [chartView setNeedsDisplay]; } @@ -143,9 +143,9 @@ - (void)handleOption:(NSString *)key forChartView:(ChartViewBase *)chartView if ([key isEqualToString:@"toggleBarBorders"]) { - for (id set in chartView.data.dataSets) + for (id set in chartView.data.dataSets) { - if ([set conformsToProtocol:@protocol(IBarChartDataSet)]) + if ([set conformsToProtocol:@protocol(BarChartDataSetProtocol)]) { set.barBorderWidth = set.barBorderWidth == 1.0 ? 0.0 : 1.0; } diff --git a/ChartsDemo-iOS/Objective-C/Demos/CandleStickChartViewController.m b/ChartsDemo-iOS/Objective-C/Demos/CandleStickChartViewController.m index 25a0e73c..740268c8 100644 --- a/ChartsDemo-iOS/Objective-C/Demos/CandleStickChartViewController.m +++ b/ChartsDemo-iOS/Objective-C/Demos/CandleStickChartViewController.m @@ -128,7 +128,7 @@ - (void)optionTapped:(NSString *)key { if ([key isEqualToString:@"toggleShadowColorSameAsCandle"]) { - for (id set in _chartView.data.dataSets) + for (id set in _chartView.data.dataSets) { set.shadowColorSameAsCandle = !set.shadowColorSameAsCandle; } @@ -137,7 +137,7 @@ - (void)optionTapped:(NSString *)key return; } else if ([key isEqualToString:@"toggleShowCandleBar"]) { - for (id set in _chartView.data.dataSets) + for (id set in _chartView.data.dataSets) { set.showCandleBar = !set.showCandleBar; } diff --git a/ChartsDemo-iOS/Objective-C/Demos/ColoredLineChartViewController.m b/ChartsDemo-iOS/Objective-C/Demos/ColoredLineChartViewController.m index 520770f2..a832bc00 100644 --- a/ChartsDemo-iOS/Objective-C/Demos/ColoredLineChartViewController.m +++ b/ChartsDemo-iOS/Objective-C/Demos/ColoredLineChartViewController.m @@ -44,7 +44,7 @@ - (void)viewDidLoad - (void)setupChart:(LineChartView *)chart data:(LineChartData *)data color:(UIColor *)color { - [(LineChartDataSet *)[data getDataSetByIndex:0] setCircleHoleColor:color]; + [(LineChartDataSet *)[data dataSetAtIndex:0] setCircleHoleColor:color]; chart.delegate = self; chart.backgroundColor = color; diff --git a/ChartsDemo-iOS/Objective-C/Demos/CombinedChartViewController.m b/ChartsDemo-iOS/Objective-C/Demos/CombinedChartViewController.m index 995c4192..a4700b25 100644 --- a/ChartsDemo-iOS/Objective-C/Demos/CombinedChartViewController.m +++ b/ChartsDemo-iOS/Objective-C/Demos/CombinedChartViewController.m @@ -14,7 +14,7 @@ #define ITEM_COUNT 12 -@interface CombinedChartViewController () +@interface CombinedChartViewController () { NSArray *months; } @@ -122,7 +122,7 @@ - (void)optionTapped:(NSString *)key { if ([key isEqualToString:@"toggleLineValues"]) { - for (NSObject *set in _chartView.data.dataSets) + for (NSObject *set in _chartView.data.dataSets) { if ([set isKindOfClass:LineChartDataSet.class]) { @@ -136,7 +136,7 @@ - (void)optionTapped:(NSString *)key if ([key isEqualToString:@"toggleBarValues"]) { - for (NSObject *set in _chartView.data.dataSets) + for (NSObject *set in _chartView.data.dataSets) { if ([set isKindOfClass:BarChartDataSet.class]) { @@ -151,7 +151,7 @@ - (void)optionTapped:(NSString *)key if ([key isEqualToString:@"removeDataSet"]) { int rnd = (int)arc4random_uniform((float)_chartView.data.dataSetCount); - [_chartView.data removeDataSet:[_chartView.data getDataSetByIndex:rnd]]; + [_chartView.data removeDataSet:[_chartView.data dataSetAtIndex:rnd]]; [_chartView.data notifyDataChanged]; [_chartView notifyDataSetChanged]; } @@ -313,7 +313,7 @@ - (void)chartValueNothingSelected:(ChartViewBase * __nonnull)chartView NSLog(@"chartValueNothingSelected"); } -#pragma mark - IAxisValueFormatter +#pragma mark - AxisValueFormatter - (NSString *)stringForValue:(double)value axis:(ChartAxisBase *)axis diff --git a/ChartsDemo-iOS/Objective-C/Demos/CubicLineChartViewController.m b/ChartsDemo-iOS/Objective-C/Demos/CubicLineChartViewController.m index 0d590fbf..1912cf60 100644 --- a/ChartsDemo-iOS/Objective-C/Demos/CubicLineChartViewController.m +++ b/ChartsDemo-iOS/Objective-C/Demos/CubicLineChartViewController.m @@ -12,7 +12,7 @@ #import "CubicLineChartViewController.h" #import "ChartsDemo_iOS-Swift.h" -@interface CubicLineSampleFillFormatter : NSObject +@interface CubicLineSampleFillFormatter : NSObject { } @end @@ -158,7 +158,7 @@ - (void)optionTapped:(NSString *)key { if ([key isEqualToString:@"toggleFilled"]) { - for (id set in _chartView.data.dataSets) + for (id set in _chartView.data.dataSets) { set.drawFilledEnabled = !set.isDrawFilledEnabled; } @@ -169,7 +169,7 @@ - (void)optionTapped:(NSString *)key if ([key isEqualToString:@"toggleCircles"]) { - for (id set in _chartView.data.dataSets) + for (id set in _chartView.data.dataSets) { set.drawCirclesEnabled = !set.isDrawCirclesEnabled; } @@ -180,7 +180,7 @@ - (void)optionTapped:(NSString *)key if ([key isEqualToString:@"toggleCubic"]) { - for (id set in _chartView.data.dataSets) + for (id set in _chartView.data.dataSets) { set.mode = set.mode == LineChartModeCubicBezier ? LineChartModeLinear : LineChartModeCubicBezier; } @@ -191,7 +191,7 @@ - (void)optionTapped:(NSString *)key if ([key isEqualToString:@"toggleStepped"]) { - for (id set in _chartView.data.dataSets) + for (id set in _chartView.data.dataSets) { set.mode = set.mode == LineChartModeStepped ? LineChartModeLinear : LineChartModeStepped; } @@ -201,7 +201,7 @@ - (void)optionTapped:(NSString *)key if ([key isEqualToString:@"toggleHorizontalCubic"]) { - for (id set in _chartView.data.dataSets) + for (id set in _chartView.data.dataSets) { set.mode = set.mode == LineChartModeCubicBezier ? LineChartModeHorizontalBezier : LineChartModeCubicBezier; } diff --git a/ChartsDemo-iOS/Objective-C/Demos/LineChart1ViewController.m b/ChartsDemo-iOS/Objective-C/Demos/LineChart1ViewController.m index 40297feb..c191983f 100644 --- a/ChartsDemo-iOS/Objective-C/Demos/LineChart1ViewController.m +++ b/ChartsDemo-iOS/Objective-C/Demos/LineChart1ViewController.m @@ -61,7 +61,7 @@ - (void)viewDidLoad ChartLimitLine *llXAxis = [[ChartLimitLine alloc] initWithLimit:10.0 label:@"Index 10"]; llXAxis.lineWidth = 4.0; llXAxis.lineDashLengths = @[@(10.f), @(10.f), @(0.f)]; - llXAxis.labelPosition = ChartLimitLabelPositionBottomRight; + llXAxis.labelPosition = ChartLimitLabelPositionRightBottom; llXAxis.valueFont = [UIFont systemFontOfSize:10.f]; //[_chartView.xAxis addLimitLine:llXAxis]; @@ -72,13 +72,13 @@ - (void)viewDidLoad ChartLimitLine *ll1 = [[ChartLimitLine alloc] initWithLimit:150.0 label:@"Upper Limit"]; ll1.lineWidth = 4.0; ll1.lineDashLengths = @[@5.f, @5.f]; - ll1.labelPosition = ChartLimitLabelPositionTopRight; + ll1.labelPosition = ChartLimitLabelPositionRightTop; ll1.valueFont = [UIFont systemFontOfSize:10.0]; ChartLimitLine *ll2 = [[ChartLimitLine alloc] initWithLimit:-30.0 label:@"Lower Limit"]; ll2.lineWidth = 4.0; ll2.lineDashLengths = @[@5.f, @5.f]; - ll2.labelPosition = ChartLimitLabelPositionBottomRight; + ll2.labelPosition = ChartLimitLabelPositionRightBottom; ll2.valueFont = [UIFont systemFontOfSize:10.0]; ChartYAxis *leftAxis = _chartView.leftAxis; @@ -174,7 +174,7 @@ - (void)setDataCount:(int)count range:(double)range CGGradientRef gradient = CGGradientCreateWithColors(nil, (CFArrayRef)gradientColors, nil); set1.fillAlpha = 1.f; - set1.fill = [ChartFill fillWithLinearGradient:gradient angle:90.f]; + set1.fill = [[ChartLinearGradientFill alloc] initWithGradient:gradient angle:90.0f]; set1.drawFilledEnabled = YES; CGGradientRelease(gradient); @@ -192,7 +192,7 @@ - (void)optionTapped:(NSString *)key { if ([key isEqualToString:@"toggleFilled"]) { - for (id set in _chartView.data.dataSets) + for (id set in _chartView.data.dataSets) { set.drawFilledEnabled = !set.isDrawFilledEnabled; } @@ -203,7 +203,7 @@ - (void)optionTapped:(NSString *)key if ([key isEqualToString:@"toggleCircles"]) { - for (id set in _chartView.data.dataSets) + for (id set in _chartView.data.dataSets) { set.drawCirclesEnabled = !set.isDrawCirclesEnabled; } @@ -214,7 +214,7 @@ - (void)optionTapped:(NSString *)key if ([key isEqualToString:@"toggleCubic"]) { - for (id set in _chartView.data.dataSets) + for (id set in _chartView.data.dataSets) { set.mode = set.mode == LineChartModeCubicBezier ? LineChartModeLinear : LineChartModeCubicBezier; } @@ -225,7 +225,7 @@ - (void)optionTapped:(NSString *)key if ([key isEqualToString:@"toggleStepped"]) { - for (id set in _chartView.data.dataSets) + for (id set in _chartView.data.dataSets) { switch (set.mode) { case LineChartModeLinear: @@ -242,7 +242,7 @@ - (void)optionTapped:(NSString *)key if ([key isEqualToString:@"toggleHorizontalCubic"]) { - for (id set in _chartView.data.dataSets) + for (id set in _chartView.data.dataSets) { set.mode = set.mode == LineChartModeHorizontalBezier ? LineChartModeCubicBezier : LineChartModeHorizontalBezier; } diff --git a/ChartsDemo-iOS/Objective-C/Demos/LineChart2ViewController.m b/ChartsDemo-iOS/Objective-C/Demos/LineChart2ViewController.m index 75eceade..c6de87c1 100644 --- a/ChartsDemo-iOS/Objective-C/Demos/LineChart2ViewController.m +++ b/ChartsDemo-iOS/Objective-C/Demos/LineChart2ViewController.m @@ -204,7 +204,7 @@ - (void)optionTapped:(NSString *)key { if ([key isEqualToString:@"toggleFilled"]) { - for (id set in _chartView.data.dataSets) + for (id set in _chartView.data.dataSets) { set.drawFilledEnabled = !set.isDrawFilledEnabled; } @@ -215,7 +215,7 @@ - (void)optionTapped:(NSString *)key if ([key isEqualToString:@"toggleCircles"]) { - for (id set in _chartView.data.dataSets) + for (id set in _chartView.data.dataSets) { set.drawCirclesEnabled = !set.isDrawCirclesEnabled; } @@ -226,7 +226,7 @@ - (void)optionTapped:(NSString *)key if ([key isEqualToString:@"toggleCubic"]) { - for (id set in _chartView.data.dataSets) + for (id set in _chartView.data.dataSets) { set.mode = set.mode == LineChartModeCubicBezier ? LineChartModeLinear : LineChartModeCubicBezier; } @@ -237,7 +237,7 @@ - (void)optionTapped:(NSString *)key if ([key isEqualToString:@"toggleStepped"]) { - for (id set in _chartView.data.dataSets) + for (id set in _chartView.data.dataSets) { switch (set.mode) { case LineChartModeLinear: @@ -254,7 +254,7 @@ - (void)optionTapped:(NSString *)key if ([key isEqualToString:@"toggleHorizontalCubic"]) { - for (id set in _chartView.data.dataSets) + for (id set in _chartView.data.dataSets) { set.mode = set.mode == LineChartModeCubicBezier ? LineChartModeHorizontalBezier : LineChartModeCubicBezier; } @@ -282,7 +282,7 @@ - (void)chartValueSelected:(ChartViewBase * __nonnull)chartView entry:(ChartData { NSLog(@"chartValueSelected"); - [_chartView centerViewToAnimatedWithXValue:entry.x yValue:entry.y axis:[_chartView.data getDataSetByIndex:highlight.dataSetIndex].axisDependency duration:1.0]; + [_chartView centerViewToAnimatedWithXValue:entry.x yValue:entry.y axis:[_chartView.data dataSetAtIndex:highlight.dataSetIndex].axisDependency duration:1.0]; //[_chartView moveViewToAnimatedWithXValue:entry.x yValue:entry.y axis:[_chartView.data getDataSetByIndex:dataSetIndex].axisDependency duration:1.0]; //[_chartView zoomAndCenterViewAnimatedWithScaleX:1.8 scaleY:1.8 xValue:entry.x yValue:entry.y axis:[_chartView.data getDataSetByIndex:dataSetIndex].axisDependency duration:1.0]; diff --git a/ChartsDemo-iOS/Objective-C/Demos/LineChartFilledViewController.m b/ChartsDemo-iOS/Objective-C/Demos/LineChartFilledViewController.m index f6ec7934..3d0b3bb8 100644 --- a/ChartsDemo-iOS/Objective-C/Demos/LineChartFilledViewController.m +++ b/ChartsDemo-iOS/Objective-C/Demos/LineChartFilledViewController.m @@ -123,7 +123,7 @@ - (void)setDataCount:(int)count range:(double)range set1.fillColor = UIColor.whiteColor; set1.highlightColor = [UIColor colorWithRed:244/255.0 green:117/255.0 blue:117/255.0 alpha:1.0]; set1.drawCircleHoleEnabled = NO; - set1.fillFormatter = [ChartDefaultFillFormatter withBlock:^CGFloat(id _Nonnull dataSet, id _Nonnull dataProvider) { + set1.fillFormatter = [ChartDefaultFillFormatter withBlock:^CGFloat(id _Nonnull dataSet, id _Nonnull dataProvider) { return self.chartView.leftAxis.axisMinimum; }]; @@ -138,7 +138,7 @@ - (void)setDataCount:(int)count range:(double)range set2.fillColor = UIColor.whiteColor; set2.highlightColor = [UIColor colorWithRed:244/255.0 green:117/255.0 blue:117/255.0 alpha:1.0]; set2.drawCircleHoleEnabled = NO; - set2.fillFormatter = [ChartDefaultFillFormatter withBlock:^CGFloat(id _Nonnull dataSet, id _Nonnull dataProvider) { + set2.fillFormatter = [ChartDefaultFillFormatter withBlock:^CGFloat(id _Nonnull dataSet, id _Nonnull dataProvider) { return self.chartView.leftAxis.axisMaximum; }]; diff --git a/ChartsDemo-iOS/Objective-C/Demos/LineChartTimeViewController.m b/ChartsDemo-iOS/Objective-C/Demos/LineChartTimeViewController.m index 06e6808f..7433c4f3 100644 --- a/ChartsDemo-iOS/Objective-C/Demos/LineChartTimeViewController.m +++ b/ChartsDemo-iOS/Objective-C/Demos/LineChartTimeViewController.m @@ -158,7 +158,7 @@ - (void)optionTapped:(NSString *)key { if ([key isEqualToString:@"toggleFilled"]) { - for (id set in _chartView.data.dataSets) + for (id set in _chartView.data.dataSets) { set.drawFilledEnabled = !set.isDrawFilledEnabled; } @@ -169,7 +169,7 @@ - (void)optionTapped:(NSString *)key if ([key isEqualToString:@"toggleCircles"]) { - for (id set in _chartView.data.dataSets) + for (id set in _chartView.data.dataSets) { set.drawCirclesEnabled = !set.isDrawCirclesEnabled; } @@ -180,7 +180,7 @@ - (void)optionTapped:(NSString *)key if ([key isEqualToString:@"toggleCubic"]) { - for (id set in _chartView.data.dataSets) + for (id set in _chartView.data.dataSets) { set.mode = set.mode == LineChartModeCubicBezier ? LineChartModeLinear : LineChartModeCubicBezier; } @@ -191,7 +191,7 @@ - (void)optionTapped:(NSString *)key if ([key isEqualToString:@"toggleStepped"]) { - for (id set in _chartView.data.dataSets) + for (id set in _chartView.data.dataSets) { switch (set.mode) { case LineChartModeLinear: @@ -208,7 +208,7 @@ - (void)optionTapped:(NSString *)key if ([key isEqualToString:@"toggleHorizontalCubic"]) { - for (id set in _chartView.data.dataSets) + for (id set in _chartView.data.dataSets) { set.mode = set.mode == LineChartModeCubicBezier ? LineChartModeHorizontalBezier : LineChartModeCubicBezier; } diff --git a/ChartsDemo-iOS/Objective-C/Demos/MultipleLinesChartViewController.m b/ChartsDemo-iOS/Objective-C/Demos/MultipleLinesChartViewController.m index 358a7e21..63ad2519 100644 --- a/ChartsDemo-iOS/Objective-C/Demos/MultipleLinesChartViewController.m +++ b/ChartsDemo-iOS/Objective-C/Demos/MultipleLinesChartViewController.m @@ -130,7 +130,7 @@ - (void)optionTapped:(NSString *)key { if ([key isEqualToString:@"toggleFilled"]) { - for (id set in _chartView.data.dataSets) + for (id set in _chartView.data.dataSets) { set.drawFilledEnabled = !set.isDrawFilledEnabled; } @@ -141,7 +141,7 @@ - (void)optionTapped:(NSString *)key if ([key isEqualToString:@"toggleCircles"]) { - for (id set in _chartView.data.dataSets) + for (id set in _chartView.data.dataSets) { set.drawCirclesEnabled = !set.isDrawCirclesEnabled; } @@ -152,7 +152,7 @@ - (void)optionTapped:(NSString *)key if ([key isEqualToString:@"toggleCubic"]) { - for (id set in _chartView.data.dataSets) + for (id set in _chartView.data.dataSets) { set.mode = set.mode == LineChartModeCubicBezier ? LineChartModeLinear : LineChartModeCubicBezier; } @@ -163,7 +163,7 @@ - (void)optionTapped:(NSString *)key if ([key isEqualToString:@"toggleStepped"]) { - for (id set in _chartView.data.dataSets) + for (id set in _chartView.data.dataSets) { switch (set.mode) { case LineChartModeLinear: diff --git a/ChartsDemo-iOS/Objective-C/Demos/NegativeStackedBarChartViewController.m b/ChartsDemo-iOS/Objective-C/Demos/NegativeStackedBarChartViewController.m index b87ef62a..2083e415 100644 --- a/ChartsDemo-iOS/Objective-C/Demos/NegativeStackedBarChartViewController.m +++ b/ChartsDemo-iOS/Objective-C/Demos/NegativeStackedBarChartViewController.m @@ -12,7 +12,7 @@ #import "NegativeStackedBarChartViewController.h" #import "ChartsDemo_iOS-Swift.h" -@interface NegativeStackedBarChartViewController () +@interface NegativeStackedBarChartViewController () @property (nonatomic, strong) IBOutlet HorizontalBarChartView *chartView; @@ -184,7 +184,7 @@ - (void)chartValueNothingSelected:(ChartViewBase * __nonnull)chartView NSLog(@"chartValueNothingSelected"); } -#pragma mark - IAxisValueFormatter +#pragma mark - AxisValueFormatter - (NSString *)stringForValue:(double)value axis:(ChartAxisBase *)axis diff --git a/ChartsDemo-iOS/Objective-C/Demos/PieChartViewController.m b/ChartsDemo-iOS/Objective-C/Demos/PieChartViewController.m index 5bc3a9d6..1d35f2ae 100644 --- a/ChartsDemo-iOS/Objective-C/Demos/PieChartViewController.m +++ b/ChartsDemo-iOS/Objective-C/Demos/PieChartViewController.m @@ -36,6 +36,7 @@ - (void)viewDidLoad @{@"key": @"togglePercent", @"label": @"Toggle Percent"}, @{@"key": @"toggleHole", @"label": @"Toggle Hole"}, @{@"key": @"toggleIcons", @"label": @"Toggle Icons"}, + @{@"key": @"toggleLabelsMinimumAngle", @"label": @"Toggle Labels Minimum Angle"}, @{@"key": @"animateX", @"label": @"Animate X"}, @{@"key": @"animateY", @"label": @"Animate Y"}, @{@"key": @"animateXY", @"label": @"Animate XY"}, @@ -59,7 +60,7 @@ - (void)viewDidLoad l.yOffset = 0.0; // entry label styling - _chartView.entryLabelColor = UIColor.whiteColor; + _chartView.entryLabelColor = UIColor.blackColor; _chartView.entryLabelFont = [UIFont fontWithName:@"HelveticaNeue-Light" size:12.f]; _sliderX.value = 4.0; @@ -125,7 +126,7 @@ - (void)setDataCount:(int)count range:(double)range pFormatter.percentSymbol = @" %"; [data setValueFormatter:[[ChartDefaultValueFormatter alloc] initWithFormatter:pFormatter]]; [data setValueFont:[UIFont fontWithName:@"HelveticaNeue-Light" size:11.f]]; - [data setValueTextColor:UIColor.whiteColor]; + [data setValueTextColor:UIColor.blackColor]; _chartView.data = data; [_chartView highlightValues:nil]; @@ -157,6 +158,12 @@ - (void)optionTapped:(NSString *)key return; } + if ([key isEqualToString:@"toggleLabelsMinimumAngle"]) + { + CGFloat newMinimum = _chartView.sliceTextDrawingThreshold == 20.0 ? 0.0 : 20.0; + _chartView.sliceTextDrawingThreshold = newMinimum; + } + if ([key isEqualToString:@"drawCenter"]) { _chartView.drawCenterTextEnabled = !_chartView.isDrawCenterTextEnabled; diff --git a/ChartsDemo-iOS/Objective-C/Demos/PiePolylineChartViewController.m b/ChartsDemo-iOS/Objective-C/Demos/PiePolylineChartViewController.m index 81f092e9..3d5db273 100644 --- a/ChartsDemo-iOS/Objective-C/Demos/PiePolylineChartViewController.m +++ b/ChartsDemo-iOS/Objective-C/Demos/PiePolylineChartViewController.m @@ -31,6 +31,7 @@ - (void)viewDidLoad @{@"key": @"toggleXValues", @"label": @"Toggle X-Values"}, @{@"key": @"togglePercent", @"label": @"Toggle Percent"}, @{@"key": @"toggleHole", @"label": @"Toggle Hole"}, + @{@"key": @"toggleLabelsMinimumAngle", @"label": @"Toggle Labels Minimum Angle"}, @{@"key": @"animateX", @"label": @"Animate X"}, @{@"key": @"animateY", @"label": @"Animate Y"}, @{@"key": @"animateXY", @"label": @"Animate XY"}, @@ -144,6 +145,12 @@ - (void)optionTapped:(NSString *)key return; } + if ([key isEqualToString:@"toggleLabelsMinimumAngle"]) + { + CGFloat newMinimum = _chartView.sliceTextDrawingThreshold == 20.0 ? 0.0 : 20.0; + _chartView.sliceTextDrawingThreshold = newMinimum; + } + if ([key isEqualToString:@"drawCenter"]) { _chartView.drawCenterTextEnabled = !_chartView.isDrawCenterTextEnabled; diff --git a/ChartsDemo-iOS/Objective-C/Demos/PositiveNegativeBarChartViewController.m b/ChartsDemo-iOS/Objective-C/Demos/PositiveNegativeBarChartViewController.m index 2440fe9e..fe6e9be9 100644 --- a/ChartsDemo-iOS/Objective-C/Demos/PositiveNegativeBarChartViewController.m +++ b/ChartsDemo-iOS/Objective-C/Demos/PositiveNegativeBarChartViewController.m @@ -12,7 +12,7 @@ #import "PositiveNegativeBarChartViewController.h" #import "ChartsDemo_iOS-Swift.h" -@interface PositiveNegativeBarChartViewController () +@interface PositiveNegativeBarChartViewController () { NSArray *dataList; } @@ -182,7 +182,7 @@ - (void)chartValueNothingSelected:(ChartViewBase * __nonnull)chartView NSLog(@"chartValueNothingSelected"); } -#pragma mark - IAxisValueFormatter +#pragma mark - AxisValueFormatter - (NSString *)stringForValue:(double)value axis:(ChartAxisBase *)axis diff --git a/ChartsDemo-iOS/Objective-C/Demos/RadarChartViewController.m b/ChartsDemo-iOS/Objective-C/Demos/RadarChartViewController.m index 24cfea5b..e4f5cbcf 100644 --- a/ChartsDemo-iOS/Objective-C/Demos/RadarChartViewController.m +++ b/ChartsDemo-iOS/Objective-C/Demos/RadarChartViewController.m @@ -12,7 +12,7 @@ #import "RadarChartViewController.h" #import "ChartsDemo_iOS-Swift.h" -@interface RadarChartViewController () +@interface RadarChartViewController () @property (nonatomic, strong) IBOutlet RadarChartView *chartView; @property (nonatomic, strong) NSArray *activities; diff --git a/ChartsDemo-iOS/Objective-C/Formatters/DateValueFormatter.h b/ChartsDemo-iOS/Objective-C/Formatters/DateValueFormatter.h index 2e94536a..770ff316 100644 --- a/ChartsDemo-iOS/Objective-C/Formatters/DateValueFormatter.h +++ b/ChartsDemo-iOS/Objective-C/Formatters/DateValueFormatter.h @@ -12,6 +12,6 @@ #import #import "ChartsDemo_iOS-Swift.h" -@interface DateValueFormatter : NSObject +@interface DateValueFormatter : NSObject @end diff --git a/ChartsDemo-iOS/Objective-C/Formatters/DayAxisValueFormatter.h b/ChartsDemo-iOS/Objective-C/Formatters/DayAxisValueFormatter.h index 4de193d0..3189325a 100644 --- a/ChartsDemo-iOS/Objective-C/Formatters/DayAxisValueFormatter.h +++ b/ChartsDemo-iOS/Objective-C/Formatters/DayAxisValueFormatter.h @@ -7,7 +7,7 @@ #import #import "ChartsDemo_iOS-Swift.h" -@interface DayAxisValueFormatter : NSObject +@interface DayAxisValueFormatter : NSObject - (id)initForChart:(BarLineChartViewBase *)chart; diff --git a/ChartsDemo-iOS/Objective-C/Formatters/IntAxisValueFormatter.h b/ChartsDemo-iOS/Objective-C/Formatters/IntAxisValueFormatter.h index 6401ed07..c390c0bc 100644 --- a/ChartsDemo-iOS/Objective-C/Formatters/IntAxisValueFormatter.h +++ b/ChartsDemo-iOS/Objective-C/Formatters/IntAxisValueFormatter.h @@ -7,6 +7,6 @@ #import #import "ChartsDemo_iOS-Swift.h" -@interface IntAxisValueFormatter : NSObject +@interface IntAxisValueFormatter : NSObject @end diff --git a/ChartsDemo-iOS/Objective-C/Formatters/LargeValueFormatter.swift b/ChartsDemo-iOS/Objective-C/Formatters/LargeValueFormatter.swift index 47ca78fd..1f37660e 100644 --- a/ChartsDemo-iOS/Objective-C/Formatters/LargeValueFormatter.swift +++ b/ChartsDemo-iOS/Objective-C/Formatters/LargeValueFormatter.swift @@ -7,7 +7,7 @@ import Foundation import Charts -open class LargeValueFormatter: NSObject, IValueFormatter, IAxisValueFormatter +open class LargeValueFormatter: NSObject, ValueFormatter, AxisValueFormatter { fileprivate static let MAX_LENGTH = 5 diff --git a/ChartsDemo-iOS/Swift/Components/XYMarkerView.swift b/ChartsDemo-iOS/Swift/Components/XYMarkerView.swift index 9fd1174b..4958e10f 100644 --- a/ChartsDemo-iOS/Swift/Components/XYMarkerView.swift +++ b/ChartsDemo-iOS/Swift/Components/XYMarkerView.swift @@ -13,11 +13,11 @@ import Charts #endif public class XYMarkerView: BalloonMarker { - public var xAxisValueFormatter: IAxisValueFormatter + public var xAxisValueFormatter: AxisValueFormatter fileprivate var yFormatter = NumberFormatter() public init(color: UIColor, font: UIFont, textColor: UIColor, insets: UIEdgeInsets, - xAxisValueFormatter: IAxisValueFormatter) { + xAxisValueFormatter: AxisValueFormatter) { self.xAxisValueFormatter = xAxisValueFormatter yFormatter.minimumFractionDigits = 1 yFormatter.maximumFractionDigits = 1 diff --git a/ChartsDemo-iOS/Swift/DemoBaseViewController.swift b/ChartsDemo-iOS/Swift/DemoBaseViewController.swift index 444d1f47..3f0f920a 100644 --- a/ChartsDemo-iOS/Swift/DemoBaseViewController.swift +++ b/ChartsDemo-iOS/Swift/DemoBaseViewController.swift @@ -23,6 +23,8 @@ enum Option { case toggleAutoScaleMinMax case toggleData case toggleBarBorders + // LineChart + case toggleGradientLine // CandleChart case toggleShadowColorSameAsCandle case toggleShowCandleBar @@ -42,6 +44,7 @@ enum Option { case toggleHole case spin case drawCenter + case toggleLabelsMinimumAngle // RadarChart case toggleXLabels case toggleYLabels @@ -61,6 +64,8 @@ enum Option { case .toggleAutoScaleMinMax: return "Toggle auto scale min/max" case .toggleData: return "Toggle Data" case .toggleBarBorders: return "Toggle Bar Borders" + // LineChart + case .toggleGradientLine: return "Toggle Gradient Line" // CandleChart case .toggleShadowColorSameAsCandle: return "Toggle shadow same color" case .toggleShowCandleBar: return "Toggle show candle bar" @@ -80,6 +85,7 @@ enum Option { case .toggleHole: return "Toggle Hole" case .spin: return "Spin" case .drawCenter: return "Draw CenterText" + case .toggleLabelsMinimumAngle: return "Toggle Labels Minimum Angle" // RadarChart case .toggleXLabels: return "Toggle X-Labels" case .toggleYLabels: return "Toggle Y-Labels" @@ -121,19 +127,19 @@ class DemoBaseViewController: UIViewController, ChartViewDelegate { func handleOption(_ option: Option, forChartView chartView: ChartViewBase) { switch option { case .toggleValues: - for set in chartView.data!.dataSets { + for set in chartView.data! { set.drawValuesEnabled = !set.drawValuesEnabled } chartView.setNeedsDisplay() case .toggleIcons: - for set in chartView.data!.dataSets { + for set in chartView.data! { set.drawIconsEnabled = !set.drawIconsEnabled } chartView.setNeedsDisplay() case .toggleHighlight: - chartView.data!.highlightEnabled = !chartView.data!.isHighlightEnabled + chartView.data!.isHighlightEnabled = !chartView.data!.isHighlightEnabled chartView.setNeedsDisplay() case .animateX: @@ -163,7 +169,7 @@ class DemoBaseViewController: UIViewController, ChartViewDelegate { updateChartData() case .toggleBarBorders: - for set in chartView.data!.dataSets { + for set in chartView.data! { if let set = set as? BarChartDataSet { set.barBorderWidth = set.barBorderWidth == 1.0 ? 0.0 : 1.0 } @@ -238,7 +244,7 @@ class DemoBaseViewController: UIViewController, ChartViewDelegate { chartView.drawSlicesUnderHoleEnabled = false chartView.holeRadiusPercent = 0.58 chartView.transparentCircleRadiusPercent = 0.61 - chartView.chartDescription?.enabled = false + chartView.chartDescription.enabled = false chartView.setExtraOffsets(left: 5, top: 10, right: 5, bottom: 5) chartView.drawCenterTextEnabled = true @@ -273,11 +279,11 @@ class DemoBaseViewController: UIViewController, ChartViewDelegate { } func setup(radarChartView chartView: RadarChartView) { - chartView.chartDescription?.enabled = false + chartView.chartDescription.enabled = false } func setup(barLineChartView chartView: BarLineChartViewBase) { - chartView.chartDescription?.enabled = false + chartView.chartDescription.enabled = false chartView.dragEnabled = true chartView.setScaleEnabled(true) diff --git a/ChartsDemo-iOS/Swift/Demos/AnotherBarChartViewController.swift b/ChartsDemo-iOS/Swift/Demos/AnotherBarChartViewController.swift index 45391a05..568c3c99 100644 --- a/ChartsDemo-iOS/Swift/Demos/AnotherBarChartViewController.swift +++ b/ChartsDemo-iOS/Swift/Demos/AnotherBarChartViewController.swift @@ -37,7 +37,7 @@ class AnotherBarChartViewController: DemoBaseViewController { chartView.delegate = self - chartView.chartDescription?.enabled = false + chartView.chartDescription.enabled = false chartView.maxVisibleCount = 60 chartView.pinchZoomEnabled = false chartView.drawBarShadowEnabled = false @@ -70,7 +70,7 @@ class AnotherBarChartViewController: DemoBaseViewController { } var set1: BarChartDataSet! = nil - if let set = chartView.data?.dataSets.first as? BarChartDataSet { + if let set = chartView.data?.first as? BarChartDataSet { set1 = set set1?.replaceEntries(yVals) chartView.data?.notifyDataChanged() diff --git a/ChartsDemo-iOS/Swift/Demos/BarChartViewController.swift b/ChartsDemo-iOS/Swift/Demos/BarChartViewController.swift index 54006468..7f66cda3 100644 --- a/ChartsDemo-iOS/Swift/Demos/BarChartViewController.swift +++ b/ChartsDemo-iOS/Swift/Demos/BarChartViewController.swift @@ -124,7 +124,7 @@ class BarChartViewController: DemoBaseViewController { } var set1: BarChartDataSet! = nil - if let set = chartView.data?.dataSets.first as? BarChartDataSet { + if let set = chartView.data?.first as? BarChartDataSet { set1 = set set1.replaceEntries(yVals) chartView.data?.notifyDataChanged() diff --git a/ChartsDemo-iOS/Swift/Demos/BubbleChartViewController.swift b/ChartsDemo-iOS/Swift/Demos/BubbleChartViewController.swift index 06435402..b6db99cf 100644 --- a/ChartsDemo-iOS/Swift/Demos/BubbleChartViewController.swift +++ b/ChartsDemo-iOS/Swift/Demos/BubbleChartViewController.swift @@ -37,7 +37,7 @@ class BubbleChartViewController: DemoBaseViewController { chartView.delegate = self - chartView.chartDescription?.enabled = false + chartView.chartDescription.enabled = false chartView.dragEnabled = false chartView.setScaleEnabled(true) @@ -106,7 +106,7 @@ class BubbleChartViewController: DemoBaseViewController { set3.setColor(ChartColorTemplates.colorful()[2], alpha: 0.5) set3.drawValuesEnabled = true - let data = BubbleChartData(dataSets: [set1, set2, set3]) + let data = [set1, set2, set3] as BubbleChartData data.setDrawValues(false) data.setValueFont(UIFont(name: "HelveticaNeue-Light", size: 7)!) data.setHighlightCircleWidth(1.5) diff --git a/ChartsDemo-iOS/Swift/Demos/CandleStickChartViewController.swift b/ChartsDemo-iOS/Swift/Demos/CandleStickChartViewController.swift index 42460be9..33cb7edc 100644 --- a/ChartsDemo-iOS/Swift/Demos/CandleStickChartViewController.swift +++ b/ChartsDemo-iOS/Swift/Demos/CandleStickChartViewController.swift @@ -39,7 +39,7 @@ class CandleStickChartViewController: DemoBaseViewController { chartView.delegate = self - chartView.chartDescription?.enabled = false + chartView.chartDescription.enabled = false chartView.dragEnabled = false chartView.setScaleEnabled(true) @@ -108,7 +108,7 @@ class CandleStickChartViewController: DemoBaseViewController { override func optionTapped(_ option: Option) { switch option { case .toggleShadowColorSameAsCandle: - for set in chartView.data!.dataSets as! [CandleChartDataSet] { + for case let set as CandleChartDataSet in chartView.data! { set.shadowColorSameAsCandle = !set.shadowColorSameAsCandle } chartView.notifyDataSetChanged() diff --git a/ChartsDemo-iOS/Swift/Demos/ColoredLineChartViewController.swift b/ChartsDemo-iOS/Swift/Demos/ColoredLineChartViewController.swift index c5dd3566..0586923f 100644 --- a/ChartsDemo-iOS/Swift/Demos/ColoredLineChartViewController.swift +++ b/ChartsDemo-iOS/Swift/Demos/ColoredLineChartViewController.swift @@ -33,12 +33,12 @@ class ColoredLineChartViewController: DemoBaseViewController { } func setupChart(_ chart: LineChartView, data: LineChartData, color: UIColor) { - (data.getDataSetByIndex(0) as! LineChartDataSet).circleHoleColor = color + (data[0] as! LineChartDataSet).circleHoleColor = color chart.delegate = self chart.backgroundColor = color - chart.chartDescription?.enabled = false + chart.chartDescription.enabled = false chart.dragEnabled = true chart.setScaleEnabled(true) diff --git a/ChartsDemo-iOS/Swift/Demos/CombinedChartViewController.swift b/ChartsDemo-iOS/Swift/Demos/CombinedChartViewController.swift index 8ec5263b..c6d2619c 100644 --- a/ChartsDemo-iOS/Swift/Demos/CombinedChartViewController.swift +++ b/ChartsDemo-iOS/Swift/Demos/CombinedChartViewController.swift @@ -39,7 +39,7 @@ class CombinedChartViewController: DemoBaseViewController { chartView.delegate = self - chartView.chartDescription?.enabled = false + chartView.chartDescription.enabled = false chartView.drawBarShadowEnabled = false chartView.highlightFullBarEnabled = false @@ -99,7 +99,7 @@ class CombinedChartViewController: DemoBaseViewController { override func optionTapped(_ option: Option) { switch option { case .toggleLineValues: - for set in chartView.data!.dataSets { + for set in chartView.data! { if let set = set as? LineChartDataSet { set.drawValuesEnabled = !set .drawValuesEnabled @@ -108,7 +108,7 @@ class CombinedChartViewController: DemoBaseViewController { chartView.setNeedsDisplay() case .toggleBarValues: - for set in chartView.data!.dataSets { + for set in chartView.data! { if let set = set as? BarChartDataSet { set.drawValuesEnabled = !set .drawValuesEnabled } @@ -117,7 +117,7 @@ class CombinedChartViewController: DemoBaseViewController { case .removeDataSet: let rnd = Int(arc4random_uniform(UInt32(chartView.data!.dataSetCount))) - chartView.data?.removeDataSet(chartView.data!.getDataSetByIndex(rnd)) + chartView.data?.removeDataSet(chartView.data![rnd]) chartView.data?.notifyDataChanged() chartView.notifyDataSetChanged() @@ -176,7 +176,7 @@ class CombinedChartViewController: DemoBaseViewController { let barWidth = 0.45 // x2 dataset // (0.45 + 0.02) * 2 + 0.06 = 1.00 -> interval per "group" - let data = BarChartData(dataSets: [set1, set2]) + let data: BarChartData = [set1, set2] data.barWidth = barWidth // make this BarData object grouped @@ -231,7 +231,7 @@ class CombinedChartViewController: DemoBaseViewController { } } -extension CombinedChartViewController: IAxisValueFormatter { +extension CombinedChartViewController: AxisValueFormatter { func stringForValue(_ value: Double, axis: AxisBase?) -> String { return months[Int(value) % months.count] } diff --git a/ChartsDemo-iOS/Swift/Demos/CubicLineChartViewController.swift b/ChartsDemo-iOS/Swift/Demos/CubicLineChartViewController.swift index c1a65a2d..022ea71c 100644 --- a/ChartsDemo-iOS/Swift/Demos/CubicLineChartViewController.swift +++ b/ChartsDemo-iOS/Swift/Demos/CubicLineChartViewController.swift @@ -11,8 +11,8 @@ #endif import Charts -private class CubicLineSampleFillFormatter: IFillFormatter { - func getFillLinePosition(dataSet: ILineChartDataSet, dataProvider: LineChartDataProvider) -> CGFloat { +private class CubicLineSampleFillFormatter: FillFormatter { + func getFillLinePosition(dataSet: LineChartDataSetProtocol, dataProvider: LineChartDataProvider) -> CGFloat { return -10 } } @@ -111,33 +111,35 @@ class CubicLineChartViewController: DemoBaseViewController { } override func optionTapped(_ option: Option) { + guard let data = chartView.data else { return } + switch option { case .toggleFilled: - for set in chartView.data!.dataSets as! [LineChartDataSet] { + for case let set as LineChartDataSet in data { set.drawFilledEnabled = !set.drawFilledEnabled } chartView.setNeedsDisplay() case .toggleCircles: - for set in chartView.data!.dataSets as! [LineChartDataSet] { + for case let set as LineChartDataSet in data { set.drawCirclesEnabled = !set.drawCirclesEnabled } chartView.setNeedsDisplay() case .toggleCubic: - for set in chartView.data!.dataSets as! [LineChartDataSet] { + for case let set as LineChartDataSet in data { set.mode = (set.mode == .cubicBezier) ? .linear : .cubicBezier } chartView.setNeedsDisplay() case .toggleStepped: - for set in chartView.data!.dataSets as! [LineChartDataSet] { + for case let set as LineChartDataSet in data { set.mode = (set.mode == .stepped) ? .linear : .stepped } chartView.setNeedsDisplay() case .toggleHorizontalCubic: - for set in chartView.data!.dataSets as! [LineChartDataSet] { + for case let set as LineChartDataSet in data { set.mode = (set.mode == .cubicBezier) ? .horizontalBezier : .cubicBezier } chartView.setNeedsDisplay() diff --git a/ChartsDemo-iOS/Swift/Demos/LineChart1ViewController.swift b/ChartsDemo-iOS/Swift/Demos/LineChart1ViewController.swift index 43e5ff4f..e676cd9e 100644 --- a/ChartsDemo-iOS/Swift/Demos/LineChart1ViewController.swift +++ b/ChartsDemo-iOS/Swift/Demos/LineChart1ViewController.swift @@ -6,9 +6,7 @@ // Copyright © 2017 jc. All rights reserved. // -#if canImport(UIKit) - import UIKit -#endif +import UIKit import Charts class LineChart1ViewController: DemoBaseViewController { @@ -32,6 +30,7 @@ class LineChart1ViewController: DemoBaseViewController { .toggleIcons, .toggleStepped, .toggleHighlight, + .toggleGradientLine, .animateX, .animateY, .animateXY, @@ -39,36 +38,36 @@ class LineChart1ViewController: DemoBaseViewController { .togglePinchZoom, .toggleAutoScaleMinMax, .toggleData] - + chartView.delegate = self - - chartView.chartDescription?.enabled = false + + chartView.chartDescription.enabled = false chartView.dragEnabled = true chartView.setScaleEnabled(true) chartView.pinchZoomEnabled = true - + // x-axis limit line let llXAxis = ChartLimitLine(limit: 10, label: "Index 10") llXAxis.lineWidth = 4 llXAxis.lineDashLengths = [10, 10, 0] - llXAxis.labelPosition = .bottomRight + llXAxis.labelPosition = .rightBottom llXAxis.valueFont = .systemFont(ofSize: 10) - + chartView.xAxis.gridLineDashLengths = [10, 10] chartView.xAxis.gridLineDashPhase = 0 - + let ll1 = ChartLimitLine(limit: 150, label: "Upper Limit") ll1.lineWidth = 4 ll1.lineDashLengths = [5, 5] - ll1.labelPosition = .topRight + ll1.labelPosition = .rightTop ll1.valueFont = .systemFont(ofSize: 10) - + let ll2 = ChartLimitLine(limit: -30, label: "Lower Limit") ll2.lineWidth = 4 ll2.lineDashLengths = [5,5] - ll2.labelPosition = .bottomRight + ll2.labelPosition = .rightBottom ll2.valueFont = .systemFont(ofSize: 10) - + let leftAxis = chartView.leftAxis leftAxis.removeAllLimitLines() leftAxis.addLimitLine(ll1) @@ -77,9 +76,9 @@ class LineChart1ViewController: DemoBaseViewController { leftAxis.axisMinimum = -50 leftAxis.gridLineDashLengths = [5, 5] leftAxis.drawLimitLinesBehindDataEnabled = true - + chartView.rightAxis.enabled = false - + //[_chartView.viewPortHandler setMaximumScaleY: 2.f]; //[_chartView.viewPortHandler setMaximumScaleX: 2.f]; @@ -90,13 +89,13 @@ class LineChart1ViewController: DemoBaseViewController { marker.chartView = chartView marker.minimumSize = CGSize(width: 80, height: 40) chartView.marker = marker - + chartView.legend.form = .line - + sliderX.value = 45 sliderY.value = 100 slidersValueChanged(nil) - + chartView.animate(xAxisDuration: 2.5) } @@ -105,7 +104,7 @@ class LineChart1ViewController: DemoBaseViewController { chartView.data = nil return } - + self.setDataCount(Int(sliderX.value), range: UInt32(sliderY.value)) } @@ -114,67 +113,95 @@ class LineChart1ViewController: DemoBaseViewController { let val = Double(arc4random_uniform(range) + 3) return ChartDataEntry(x: Double(i), y: val, icon: #imageLiteral(resourceName: "icon")) } - + let set1 = LineChartDataSet(entries: values, label: "DataSet 1") set1.drawIconsEnabled = false - - set1.lineDashLengths = [5, 2.5] - set1.highlightLineDashLengths = [5, 2.5] - set1.setColor(.black) - set1.setCircleColor(.black) - set1.lineWidth = 1 - set1.circleRadius = 3 - set1.drawCircleHoleEnabled = false - set1.valueFont = .systemFont(ofSize: 9) - set1.formLineDashLengths = [5, 2.5] - set1.formLineWidth = 1 - set1.formSize = 15 - + setup(set1) + + let value = ChartDataEntry(x: Double(3), y: 3) + set1.addEntryOrdered(value) let gradientColors = [ChartColorTemplates.colorFromString("#00ff0000").cgColor, ChartColorTemplates.colorFromString("#ffff0000").cgColor] let gradient = CGGradient(colorsSpace: nil, colors: gradientColors as CFArray, locations: nil)! - + set1.fillAlpha = 1 - set1.fill = Fill(linearGradient: gradient, angle: 90) //.linearGradient(gradient, angle: 90) + set1.fill = LinearGradientFill(gradient: gradient, angle: 90) set1.drawFilledEnabled = true - + let data = LineChartData(dataSet: set1) - + chartView.data = data } - + + private func setup(_ dataSet: LineChartDataSet) { + if dataSet.isDrawLineWithGradientEnabled { + dataSet.lineDashLengths = nil + dataSet.highlightLineDashLengths = nil + dataSet.setColors(.black, .red, .white) + dataSet.setCircleColor(.black) + dataSet.gradientPositions = [0, 40, 100] + dataSet.lineWidth = 1 + dataSet.circleRadius = 3 + dataSet.drawCircleHoleEnabled = false + dataSet.valueFont = .systemFont(ofSize: 9) + dataSet.formLineDashLengths = nil + dataSet.formLineWidth = 1 + dataSet.formSize = 15 + } else { + dataSet.lineDashLengths = [5, 2.5] + dataSet.highlightLineDashLengths = [5, 2.5] + dataSet.setColor(.black) + dataSet.setCircleColor(.black) + dataSet.gradientPositions = nil + dataSet.lineWidth = 1 + dataSet.circleRadius = 3 + dataSet.drawCircleHoleEnabled = false + dataSet.valueFont = .systemFont(ofSize: 9) + dataSet.formLineDashLengths = [5, 2.5] + dataSet.formLineWidth = 1 + dataSet.formSize = 15 + } + } + override func optionTapped(_ option: Option) { + guard let data = chartView.data else { return } + switch option { case .toggleFilled: - for set in chartView.data!.dataSets as! [LineChartDataSet] { + for case let set as LineChartDataSet in data { set.drawFilledEnabled = !set.drawFilledEnabled } chartView.setNeedsDisplay() - + case .toggleCircles: - for set in chartView.data!.dataSets as! [LineChartDataSet] { + for case let set as LineChartDataSet in data { set.drawCirclesEnabled = !set.drawCirclesEnabled } chartView.setNeedsDisplay() - + case .toggleCubic: - for set in chartView.data!.dataSets as! [LineChartDataSet] { + for case let set as LineChartDataSet in data { set.mode = (set.mode == .cubicBezier) ? .linear : .cubicBezier } chartView.setNeedsDisplay() - + case .toggleStepped: - for set in chartView.data!.dataSets as! [LineChartDataSet] { + for case let set as LineChartDataSet in data { set.mode = (set.mode == .stepped) ? .linear : .stepped } chartView.setNeedsDisplay() - + case .toggleHorizontalCubic: - for set in chartView.data!.dataSets as! [LineChartDataSet] { + for case let set as LineChartDataSet in data { set.mode = (set.mode == .cubicBezier) ? .horizontalBezier : .cubicBezier } chartView.setNeedsDisplay() - + case .toggleGradientLine: + for set in chartView.data!.dataSets as! [LineChartDataSet] { + set.isDrawLineWithGradientEnabled = !set.isDrawLineWithGradientEnabled + setup(set) + } + chartView.setNeedsDisplay() default: super.handleOption(option, forChartView: chartView) } @@ -183,7 +210,7 @@ class LineChart1ViewController: DemoBaseViewController { @IBAction func slidersValueChanged(_ sender: Any?) { sliderTextX.text = "\(Int(sliderX.value))" sliderTextY.text = "\(Int(sliderY.value))" - + self.updateChartData() } } diff --git a/ChartsDemo-iOS/Swift/Demos/LineChart2ViewController.swift b/ChartsDemo-iOS/Swift/Demos/LineChart2ViewController.swift index d2ee8c82..9ae9688f 100644 --- a/ChartsDemo-iOS/Swift/Demos/LineChart2ViewController.swift +++ b/ChartsDemo-iOS/Swift/Demos/LineChart2ViewController.swift @@ -41,7 +41,7 @@ class LineChart2ViewController: DemoBaseViewController { chartView.delegate = self - chartView.chartDescription?.enabled = false + chartView.chartDescription.enabled = false chartView.dragEnabled = true chartView.setScaleEnabled(true) chartView.pinchZoomEnabled = true @@ -137,7 +137,7 @@ class LineChart2ViewController: DemoBaseViewController { set3.highlightColor = UIColor(red: 244/255, green: 117/255, blue: 117/255, alpha: 1) set3.drawCircleHoleEnabled = false - let data = LineChartData(dataSets: [set1, set2, set3]) + let data: LineChartData = [set1, set2, set3] data.setValueTextColor(.white) data.setValueFont(.systemFont(ofSize: 9)) @@ -145,33 +145,35 @@ class LineChart2ViewController: DemoBaseViewController { } override func optionTapped(_ option: Option) { + guard let data = chartView.data else { return } + switch option { case .toggleFilled: - for set in chartView.data!.dataSets as! [LineChartDataSet] { + for case let set as LineChartDataSet in data { set.drawFilledEnabled = !set.drawFilledEnabled } chartView.setNeedsDisplay() case .toggleCircles: - for set in chartView.data!.dataSets as! [LineChartDataSet] { + for case let set as LineChartDataSet in data { set.drawCirclesEnabled = !set.drawCirclesEnabled } chartView.setNeedsDisplay() case .toggleCubic: - for set in chartView.data!.dataSets as! [LineChartDataSet] { + for case let set as LineChartDataSet in data { set.mode = (set.mode == .cubicBezier) ? .linear : .cubicBezier } chartView.setNeedsDisplay() case .toggleStepped: - for set in chartView.data!.dataSets as! [LineChartDataSet] { + for case let set as LineChartDataSet in data { set.mode = (set.mode == .stepped) ? .linear : .stepped } chartView.setNeedsDisplay() case .toggleHorizontalCubic: - for set in chartView.data!.dataSets as! [LineChartDataSet] { + for case let set as LineChartDataSet in data { set.mode = (set.mode == .cubicBezier) ? .horizontalBezier : .cubicBezier } chartView.setNeedsDisplay() @@ -194,7 +196,7 @@ class LineChart2ViewController: DemoBaseViewController { super.chartValueSelected(chartView, entry: entry, highlight: highlight) self.chartView.centerViewToAnimated(xValue: entry.x, yValue: entry.y, - axis: self.chartView.data!.getDataSetByIndex(highlight.dataSetIndex).axisDependency, + axis: self.chartView.data![highlight.dataSetIndex].axisDependency, duration: 1) //[_chartView moveViewToAnimatedWithXValue:entry.x yValue:entry.y axis:[_chartView.data getDataSetByIndex:dataSetIndex].axisDependency duration:1.0]; //[_chartView zoomAndCenterViewAnimatedWithScaleX:1.8 scaleY:1.8 xValue:entry.x yValue:entry.y axis:[_chartView.data getDataSetByIndex:dataSetIndex].axisDependency duration:1.0]; diff --git a/ChartsDemo-iOS/Swift/Demos/LineChartFilledViewController.swift b/ChartsDemo-iOS/Swift/Demos/LineChartFilledViewController.swift index 3d17d968..ad99136a 100644 --- a/ChartsDemo-iOS/Swift/Demos/LineChartFilledViewController.swift +++ b/ChartsDemo-iOS/Swift/Demos/LineChartFilledViewController.swift @@ -33,7 +33,7 @@ class LineChartFilledViewController: DemoBaseViewController { chartView.drawBordersEnabled = true - chartView.chartDescription?.enabled = false + chartView.chartDescription.enabled = false chartView.pinchZoomEnabled = false chartView.dragEnabled = true @@ -104,7 +104,7 @@ class LineChartFilledViewController: DemoBaseViewController { return CGFloat(self.chartView.leftAxis.axisMaximum) } - let data = LineChartData(dataSets: [set1, set2]) + let data: LineChartData = [set1, set2] data.setDrawValues(false) chartView.data = data diff --git a/ChartsDemo-iOS/Swift/Demos/LineChartTimeViewController.swift b/ChartsDemo-iOS/Swift/Demos/LineChartTimeViewController.swift index b5e14da3..303c6361 100644 --- a/ChartsDemo-iOS/Swift/Demos/LineChartTimeViewController.swift +++ b/ChartsDemo-iOS/Swift/Demos/LineChartTimeViewController.swift @@ -38,7 +38,7 @@ class LineChartTimeViewController: DemoBaseViewController { chartView.delegate = self - chartView.chartDescription?.enabled = false + chartView.chartDescription.enabled = false chartView.dragEnabled = true chartView.setScaleEnabled(true) @@ -120,33 +120,35 @@ class LineChartTimeViewController: DemoBaseViewController { } override func optionTapped(_ option: Option) { + guard let data = chartView.data else { return } + switch option { case .toggleFilled: - for set in chartView.data!.dataSets as! [LineChartDataSet] { + for case let set as LineChartDataSet in data { set.drawFilledEnabled = !set.drawFilledEnabled } chartView.setNeedsDisplay() case .toggleCircles: - for set in chartView.data!.dataSets as! [LineChartDataSet] { + for case let set as LineChartDataSet in data { set.drawCirclesEnabled = !set.drawCirclesEnabled } chartView.setNeedsDisplay() case .toggleCubic: - for set in chartView.data!.dataSets as! [LineChartDataSet] { + for case let set as LineChartDataSet in data { set.mode = (set.mode == .cubicBezier) ? .linear : .cubicBezier } chartView.setNeedsDisplay() case .toggleStepped: - for set in chartView.data!.dataSets as! [LineChartDataSet] { + for case let set as LineChartDataSet in data { set.mode = (set.mode == .stepped) ? .linear : .stepped } chartView.setNeedsDisplay() case .toggleHorizontalCubic: - for set in chartView.data!.dataSets as! [LineChartDataSet] { + for case let set as LineChartDataSet in data { set.mode = (set.mode == .cubicBezier) ? .horizontalBezier : .cubicBezier } chartView.setNeedsDisplay() diff --git a/ChartsDemo-iOS/Swift/Demos/MultipleBarChartViewController.swift b/ChartsDemo-iOS/Swift/Demos/MultipleBarChartViewController.swift index ca7f54a3..871e2ebe 100644 --- a/ChartsDemo-iOS/Swift/Demos/MultipleBarChartViewController.swift +++ b/ChartsDemo-iOS/Swift/Demos/MultipleBarChartViewController.swift @@ -38,7 +38,7 @@ class MultipleBarChartViewController: DemoBaseViewController { chartView.delegate = self - chartView.chartDescription?.enabled = false + chartView.chartDescription.enabled = false chartView.pinchZoomEnabled = false chartView.drawBarShadowEnabled = false @@ -121,7 +121,7 @@ class MultipleBarChartViewController: DemoBaseViewController { let set4 = BarChartDataSet(entries: yVals4, label: "Company D") set4.setColor(UIColor(red: 255/255, green: 102/255, blue: 0/255, alpha: 1)) - let data = BarChartData(dataSets: [set1, set2, set3, set4]) + let data: BarChartData = [set1, set2, set3, set4] data.setValueFont(.systemFont(ofSize: 10, weight: .light)) data.setValueFormatter(LargeValueFormatter()) diff --git a/ChartsDemo-iOS/Swift/Demos/MultipleLinesChartViewController.swift b/ChartsDemo-iOS/Swift/Demos/MultipleLinesChartViewController.swift index 29c8efbb..098bf07b 100644 --- a/ChartsDemo-iOS/Swift/Demos/MultipleLinesChartViewController.swift +++ b/ChartsDemo-iOS/Swift/Demos/MultipleLinesChartViewController.swift @@ -40,7 +40,7 @@ class MultipleLinesChartViewController: DemoBaseViewController { chartView.delegate = self - chartView.chartDescription?.enabled = false + chartView.chartDescription.enabled = false chartView.leftAxis.enabled = false chartView.rightAxis.drawAxisLineEnabled = false @@ -101,27 +101,29 @@ class MultipleLinesChartViewController: DemoBaseViewController { } override func optionTapped(_ option: Option) { + guard let data = chartView.data else { return } + switch option { case .toggleFilled: - for set in chartView.data!.dataSets as! [LineChartDataSet] { + for case let set as LineChartDataSet in data { set.drawFilledEnabled = !set.drawFilledEnabled } chartView.setNeedsDisplay() case .toggleCircles: - for set in chartView.data!.dataSets as! [LineChartDataSet] { + for case let set as LineChartDataSet in data { set.drawCirclesEnabled = !set.drawCirclesEnabled } chartView.setNeedsDisplay() case .toggleCubic: - for set in chartView.data!.dataSets as! [LineChartDataSet] { + for case let set as LineChartDataSet in data { set.mode = (set.mode == .cubicBezier) ? .linear : .cubicBezier } chartView.setNeedsDisplay() case .toggleStepped: - for set in chartView.data!.dataSets as! [LineChartDataSet] { + for case let set as LineChartDataSet in data { set.mode = (set.mode == .stepped) ? .linear : .stepped } chartView.setNeedsDisplay() diff --git a/ChartsDemo-iOS/Swift/Demos/NegativeStackedBarChartViewController.swift b/ChartsDemo-iOS/Swift/Demos/NegativeStackedBarChartViewController.swift index 6585aad9..01a656f9 100644 --- a/ChartsDemo-iOS/Swift/Demos/NegativeStackedBarChartViewController.swift +++ b/ChartsDemo-iOS/Swift/Demos/NegativeStackedBarChartViewController.swift @@ -45,7 +45,7 @@ class NegativeStackedBarChartViewController: DemoBaseViewController { chartView.delegate = self - chartView.chartDescription?.enabled = false + chartView.chartDescription.enabled = false chartView.drawBarShadowEnabled = false chartView.drawValueAboveBarEnabled = true @@ -127,7 +127,7 @@ class NegativeStackedBarChartViewController: DemoBaseViewController { } } -extension NegativeStackedBarChartViewController: IAxisValueFormatter { +extension NegativeStackedBarChartViewController: AxisValueFormatter { func stringForValue(_ value: Double, axis: AxisBase?) -> String { return String(format: "%03.0f-%03.0f", value, value + 10) } diff --git a/ChartsDemo-iOS/Swift/Demos/PieChartViewController.swift b/ChartsDemo-iOS/Swift/Demos/PieChartViewController.swift index 4f8cb318..dc8523d0 100644 --- a/ChartsDemo-iOS/Swift/Demos/PieChartViewController.swift +++ b/ChartsDemo-iOS/Swift/Demos/PieChartViewController.swift @@ -30,6 +30,7 @@ class PieChartViewController: DemoBaseViewController { .togglePercent, .toggleHole, .toggleIcons, + .toggleLabelsMinimumAngle, .animateX, .animateY, .animateXY, @@ -101,7 +102,7 @@ class PieChartViewController: DemoBaseViewController { data.setValueFormatter(DefaultValueFormatter(formatter: pFormatter)) data.setValueFont(.systemFont(ofSize: 11, weight: .light)) - data.setValueTextColor(.white) + data.setValueTextColor(.black) chartView.data = data chartView.highlightValues(nil) @@ -121,6 +122,10 @@ class PieChartViewController: DemoBaseViewController { chartView.drawHoleEnabled = !chartView.drawHoleEnabled chartView.setNeedsDisplay() + case .toggleLabelsMinimumAngle: + chartView.sliceTextDrawingThreshold = chartView.sliceTextDrawingThreshold == 0.0 ? 20.0 : 0.0 + chartView.setNeedsDisplay() + case .drawCenter: chartView.drawCenterTextEnabled = !chartView.drawCenterTextEnabled chartView.setNeedsDisplay() diff --git a/ChartsDemo-iOS/Swift/Demos/PiePolylineChartViewController.swift b/ChartsDemo-iOS/Swift/Demos/PiePolylineChartViewController.swift index a2500073..42021249 100644 --- a/ChartsDemo-iOS/Swift/Demos/PiePolylineChartViewController.swift +++ b/ChartsDemo-iOS/Swift/Demos/PiePolylineChartViewController.swift @@ -27,6 +27,7 @@ class PiePolylineChartViewController: DemoBaseViewController { .toggleXValues, .togglePercent, .toggleHole, + .toggleLabelsMinimumAngle, .animateX, .animateY, .animateXY, @@ -111,6 +112,10 @@ class PiePolylineChartViewController: DemoBaseViewController { chartView.drawHoleEnabled = !chartView.drawHoleEnabled chartView.setNeedsDisplay() + case .toggleLabelsMinimumAngle: + chartView.sliceTextDrawingThreshold = chartView.sliceTextDrawingThreshold == 0.0 ? 20.0 : 0.0 + chartView.setNeedsDisplay() + case .drawCenter: chartView.drawCenterTextEnabled = !chartView.drawCenterTextEnabled chartView.setNeedsDisplay() diff --git a/ChartsDemo-iOS/Swift/Demos/PositiveNegativeBarChartViewController.swift b/ChartsDemo-iOS/Swift/Demos/PositiveNegativeBarChartViewController.swift index 36771b97..2f1a65e6 100644 --- a/ChartsDemo-iOS/Swift/Demos/PositiveNegativeBarChartViewController.swift +++ b/ChartsDemo-iOS/Swift/Demos/PositiveNegativeBarChartViewController.swift @@ -46,7 +46,7 @@ class PositiveNegativeBarChartViewController: DemoBaseViewController { chartView.drawBarShadowEnabled = false chartView.drawValueAboveBarEnabled = true - chartView.chartDescription?.enabled = false + chartView.chartDescription.enabled = false chartView.rightAxis.enabled = false @@ -115,7 +115,7 @@ class PositiveNegativeBarChartViewController: DemoBaseViewController { } } -extension PositiveNegativeBarChartViewController: IAxisValueFormatter { +extension PositiveNegativeBarChartViewController: AxisValueFormatter { func stringForValue(_ value: Double, axis: AxisBase?) -> String { return dataLabels[min(max(Int(value), 0), dataLabels.count - 1)] } diff --git a/ChartsDemo-iOS/Swift/Demos/RadarChartViewController.swift b/ChartsDemo-iOS/Swift/Demos/RadarChartViewController.swift index 79f308d6..a9842f89 100644 --- a/ChartsDemo-iOS/Swift/Demos/RadarChartViewController.swift +++ b/ChartsDemo-iOS/Swift/Demos/RadarChartViewController.swift @@ -41,7 +41,7 @@ class RadarChartViewController: DemoBaseViewController { chartView.delegate = self - chartView.chartDescription?.enabled = false + chartView.chartDescription.enabled = false chartView.webLineWidth = 1 chartView.innerWebLineWidth = 1 chartView.webColor = .lightGray @@ -144,7 +144,7 @@ class RadarChartViewController: DemoBaseViewController { set2.drawHighlightCircleEnabled = true set2.setDrawHighlightIndicators(false) - let data = RadarChartData(dataSets: [set1, set2]) + let data: RadarChartData = [set1, set2] data.setValueFont(.systemFont(ofSize: 8, weight: .light)) data.setDrawValues(false) data.setValueTextColor(.white) @@ -153,6 +153,8 @@ class RadarChartViewController: DemoBaseViewController { } override func optionTapped(_ option: Option) { + guard let data = chartView.data else { return } + switch option { case .toggleXLabels: chartView.xAxis.drawLabelsEnabled = !chartView.xAxis.drawLabelsEnabled @@ -168,14 +170,14 @@ class RadarChartViewController: DemoBaseViewController { chartView.rotationEnabled = !chartView.rotationEnabled case .toggleFilled: - for set in chartView.data!.dataSets as! [RadarChartDataSet] { + for case let set as RadarChartDataSet in data { set.drawFilledEnabled = !set.drawFilledEnabled } chartView.setNeedsDisplay() case .toggleHighlightCircle: - for set in chartView.data!.dataSets as! [RadarChartDataSet] { + for case let set as RadarChartDataSet in data { set.drawHighlightCircleEnabled = !set.drawHighlightCircleEnabled } chartView.setNeedsDisplay() @@ -198,7 +200,7 @@ class RadarChartViewController: DemoBaseViewController { } } -extension RadarChartViewController: IAxisValueFormatter { +extension RadarChartViewController: AxisValueFormatter { func stringForValue(_ value: Double, axis: AxisBase?) -> String { return activities[Int(value) % activities.count] } diff --git a/ChartsDemo-iOS/Swift/Demos/ScatterChartViewController.swift b/ChartsDemo-iOS/Swift/Demos/ScatterChartViewController.swift index b3d6907d..bcc691c9 100644 --- a/ChartsDemo-iOS/Swift/Demos/ScatterChartViewController.swift +++ b/ChartsDemo-iOS/Swift/Demos/ScatterChartViewController.swift @@ -35,8 +35,8 @@ class ScatterChartViewController: DemoBaseViewController { .toggleData] chartView.delegate = self - - chartView.chartDescription?.enabled = false + + chartView.chartDescription.enabled = false chartView.dragEnabled = true chartView.setScaleEnabled(true) @@ -107,7 +107,7 @@ class ScatterChartViewController: DemoBaseViewController { set3.setColor(ChartColorTemplates.colorful()[2]) set3.scatterShapeSize = 8 - let data = ScatterChartData(dataSets: [set1, set2, set3]) + let data: ScatterChartData = [set1, set2, set3] data.setValueFont(.systemFont(ofSize: 7, weight: .light)) chartView.data = data diff --git a/ChartsDemo-iOS/Swift/Demos/SinusBarChartViewController.swift b/ChartsDemo-iOS/Swift/Demos/SinusBarChartViewController.swift index 918aef21..0a966c4c 100644 --- a/ChartsDemo-iOS/Swift/Demos/SinusBarChartViewController.swift +++ b/ChartsDemo-iOS/Swift/Demos/SinusBarChartViewController.swift @@ -34,7 +34,7 @@ class SinusBarChartViewController: DemoBaseViewController { chartView.delegate = self - chartView.chartDescription?.enabled = false + chartView.chartDescription.enabled = false chartView.drawBarShadowEnabled = false chartView.drawValueAboveBarEnabled = false diff --git a/ChartsDemo-iOS/Swift/Demos/StackedBarChartViewController.swift b/ChartsDemo-iOS/Swift/Demos/StackedBarChartViewController.swift index 87f3d644..e48d8824 100644 --- a/ChartsDemo-iOS/Swift/Demos/StackedBarChartViewController.swift +++ b/ChartsDemo-iOS/Swift/Demos/StackedBarChartViewController.swift @@ -48,7 +48,7 @@ class StackedBarChartViewController: DemoBaseViewController { chartView.delegate = self - chartView.chartDescription?.enabled = false + chartView.chartDescription.enabled = false chartView.maxVisibleCount = 40 chartView.drawBarShadowEnabled = false diff --git a/ChartsDemo-iOS/Swift/Formatters/DateValueFormatter.swift b/ChartsDemo-iOS/Swift/Formatters/DateValueFormatter.swift index 2962a685..aa39e3d4 100644 --- a/ChartsDemo-iOS/Swift/Formatters/DateValueFormatter.swift +++ b/ChartsDemo-iOS/Swift/Formatters/DateValueFormatter.swift @@ -9,7 +9,7 @@ import Foundation import Charts -public class DateValueFormatter: NSObject, IAxisValueFormatter { +public class DateValueFormatter: NSObject, AxisValueFormatter { private let dateFormatter = DateFormatter() override init() { diff --git a/ChartsDemo-iOS/Swift/Formatters/DayAxisValueFormatter.swift b/ChartsDemo-iOS/Swift/Formatters/DayAxisValueFormatter.swift index 245a25c8..f403daa0 100644 --- a/ChartsDemo-iOS/Swift/Formatters/DayAxisValueFormatter.swift +++ b/ChartsDemo-iOS/Swift/Formatters/DayAxisValueFormatter.swift @@ -9,7 +9,7 @@ import Foundation import Charts -public class DayAxisValueFormatter: NSObject, IAxisValueFormatter { +public class DayAxisValueFormatter: NSObject, AxisValueFormatter { weak var chart: BarLineChartViewBase? let months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", diff --git a/ChartsDemo-iOS/Swift/Formatters/IntAxisValueFormatter.swift b/ChartsDemo-iOS/Swift/Formatters/IntAxisValueFormatter.swift index bd3062a1..00157055 100644 --- a/ChartsDemo-iOS/Swift/Formatters/IntAxisValueFormatter.swift +++ b/ChartsDemo-iOS/Swift/Formatters/IntAxisValueFormatter.swift @@ -9,7 +9,7 @@ import Foundation import Charts -public class IntAxisValueFormatter: NSObject, IAxisValueFormatter { +public class IntAxisValueFormatter: NSObject, AxisValueFormatter { public func stringForValue(_ value: Double, axis: AxisBase?) -> String { return "\(Int(value))" } diff --git a/ChartsDemo-iOS/Swift/Formatters/LargeValueFormatter.swift b/ChartsDemo-iOS/Swift/Formatters/LargeValueFormatter.swift index c95ca034..8cf679d2 100644 --- a/ChartsDemo-iOS/Swift/Formatters/LargeValueFormatter.swift +++ b/ChartsDemo-iOS/Swift/Formatters/LargeValueFormatter.swift @@ -11,7 +11,7 @@ private let MAX_LENGTH = 5 @objc protocol Testing123 { } -public class LargeValueFormatter: NSObject, IValueFormatter, IAxisValueFormatter { +public class LargeValueFormatter: NSObject, ValueFormatter, AxisValueFormatter { /// Suffix to be appended after the values. /// diff --git a/ChartsDemo-macOS/ChartsDemo-macOS/Demos/BarDemoViewController.swift b/ChartsDemo-macOS/ChartsDemo-macOS/Demos/BarDemoViewController.swift index bf0d91c7..13102156 100644 --- a/ChartsDemo-macOS/ChartsDemo-macOS/Demos/BarDemoViewController.swift +++ b/ChartsDemo-macOS/ChartsDemo-macOS/Demos/BarDemoViewController.swift @@ -31,11 +31,11 @@ open class BarDemoViewController: NSViewController let data = BarChartData() let ds1 = BarChartDataSet(entries: yse1, label: "Hello") ds1.colors = [NSUIColor.red] - data.addDataSet(ds1) + data.append(ds1) let ds2 = BarChartDataSet(entries: yse2, label: "World") ds2.colors = [NSUIColor.blue] - data.addDataSet(ds2) + data.append(ds2) let barWidth = 0.4 let barSpace = 0.05 @@ -51,7 +51,7 @@ open class BarDemoViewController: NSViewController self.barChartView.gridBackgroundColor = NSUIColor.white - self.barChartView.chartDescription?.text = "Barchart Demo" + self.barChartView.chartDescription.text = "Barchart Demo" } @IBAction func save(_ sender: Any) diff --git a/ChartsDemo-macOS/ChartsDemo-macOS/Demos/LineDemoViewController.swift b/ChartsDemo-macOS/ChartsDemo-macOS/Demos/LineDemoViewController.swift index 5f555649..51ba836f 100644 --- a/ChartsDemo-macOS/ChartsDemo-macOS/Demos/LineDemoViewController.swift +++ b/ChartsDemo-macOS/ChartsDemo-macOS/Demos/LineDemoViewController.swift @@ -30,16 +30,16 @@ open class LineDemoViewController: NSViewController let data = LineChartData() let ds1 = LineChartDataSet(entries: yse1, label: "Hello") ds1.colors = [NSUIColor.red] - data.addDataSet(ds1) + data.append(ds1) let ds2 = LineChartDataSet(entries: yse2, label: "World") ds2.colors = [NSUIColor.blue] - data.addDataSet(ds2) + data.append(ds2) self.lineChartView.data = data self.lineChartView.gridBackgroundColor = NSUIColor.white - self.lineChartView.chartDescription?.text = "Linechart Demo" + self.lineChartView.chartDescription.text = "Linechart Demo" } override open func viewWillAppear() diff --git a/ChartsDemo-macOS/ChartsDemo-macOS/Demos/PieDemoViewController.swift b/ChartsDemo-macOS/ChartsDemo-macOS/Demos/PieDemoViewController.swift index 5a566f58..51430516 100644 --- a/ChartsDemo-macOS/ChartsDemo-macOS/Demos/PieDemoViewController.swift +++ b/ChartsDemo-macOS/ChartsDemo-macOS/Demos/PieDemoViewController.swift @@ -30,7 +30,7 @@ open class PieDemoViewController: NSViewController ds1.colors = ChartColorTemplates.vordiplom() - data.addDataSet(ds1) + data.append(ds1) let paragraphStyle: NSMutableParagraphStyle = NSParagraphStyle.default.mutableCopy() as! NSMutableParagraphStyle paragraphStyle.lineBreakMode = .byTruncatingTail @@ -44,7 +44,7 @@ open class PieDemoViewController: NSViewController self.pieChartView.data = data - self.pieChartView.chartDescription?.text = "Piechart Demo" + self.pieChartView.chartDescription.text = "Piechart Demo" } override open func viewWillAppear() diff --git a/ChartsDemo-macOS/ChartsDemo-macOS/Demos/RadarDemoViewController.swift b/ChartsDemo-macOS/ChartsDemo-macOS/Demos/RadarDemoViewController.swift index e147a268..3eecf732 100644 --- a/ChartsDemo-macOS/ChartsDemo-macOS/Demos/RadarDemoViewController.swift +++ b/ChartsDemo-macOS/ChartsDemo-macOS/Demos/RadarDemoViewController.swift @@ -30,13 +30,13 @@ open class RadarDemoViewController: NSViewController let data = RadarChartData() let ds1 = RadarChartDataSet(entries: yse1, label: "Hello") ds1.colors = [NSUIColor.red] - data.addDataSet(ds1) + data.append(ds1) let ds2 = RadarChartDataSet(entries: yse2, label: "World") ds2.colors = [NSUIColor.blue] - data.addDataSet(ds2) + data.append(ds2) self.radarChartView.data = data - self.radarChartView.chartDescription?.text = "Radarchart Demo" + self.radarChartView.chartDescription.text = "Radarchart Demo" } diff --git a/ChartsDemo-macOS/PlaygroundChart.playground/Contents.o b/ChartsDemo-macOS/PlaygroundChart.playground/Contents.o deleted file mode 100644 index e7a031a9..00000000 Binary files a/ChartsDemo-macOS/PlaygroundChart.playground/Contents.o and /dev/null differ diff --git a/README.md b/README.md index a469fbd5..c32e9ce2 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -**Version 3.5.0**, synced to [MPAndroidChart #f6a398b](https://github.com/PhilJay/MPAndroidChart/commit/f6a398b) +**Version 4.0.0**, synced to [MPAndroidChart #f6a398b](https://github.com/PhilJay/MPAndroidChart/commit/f6a398b) ![alt tag](https://raw.github.com/danielgindi/Charts/master/Assets/feature_graphic.png) ![Supported Platforms](https://img.shields.io/cocoapods/p/Charts.svg) [![Releases](https://img.shields.io/github/release/danielgindi/Charts.svg)](https://github.com/danielgindi/Charts/releases) [![Latest pod release](https://img.shields.io/cocoapods/v/Charts.svg)](http://cocoapods.org/pods/charts) [![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) [![Build Status](https://travis-ci.org/danielgindi/Charts.svg?branch=master)](https://travis-ci.org/danielgindi/Charts) [![codecov](https://codecov.io/gh/danielgindi/Charts/branch/master/graph/badge.svg)](https://codecov.io/gh/danielgindi/Charts) @@ -86,8 +86,8 @@ For [Realm](https://realm.io/) support, please add `pod 'ChartsRealm'` too. Charts now include Carthage prebuilt binaries. ```carthage -github "danielgindi/Charts" == 3.5.0 -github "danielgindi/Charts" ~> 3.5.0 +github "danielgindi/Charts" == 4.0.0 +github "danielgindi/Charts" ~> 4.0.0 ``` In order to build the binaries for a new release, use `carthage build --no-skip-current && carthage archive Charts`. diff --git a/Source/Charts/Charts/BarChartView.swift b/Source/Charts/Charts/BarChartView.swift index 4f9aaa0b..92332774 100644 --- a/Source/Charts/Charts/BarChartView.swift +++ b/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 } diff --git a/Source/Charts/Charts/BarLineChartViewBase.swift b/Source/Charts/Charts/BarLineChartViewBase.swift index 1f8fdf81..0724cabe 100644 --- a/Source/Charts/Charts/BarLineChartViewBase.swift +++ b/Source/Charts/Charts/BarLineChartViewBase.swift @@ -12,14 +12,10 @@ import Foundation import CoreGraphics -#if canImport(UIKit) +#if !os(OSX) import UIKit #endif -#if canImport(Cocoa) -import Cocoa -#endif - /// Base-class of LineChart, BarChart, ScatterChart and CandleStickChart. open class BarLineChartViewBase: ChartViewBase, BarLineScatterCandleBubbleChartDataProvider, NSUIGestureRecognizerDelegate { @@ -76,19 +72,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 +114,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 +134,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 +194,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 +211,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 +227,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 +246,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 +275,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 +286,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 +299,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 +323,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 +342,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 +360,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 +401,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 +466,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 +489,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 +517,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 +529,7 @@ open class BarLineChartViewBase: ChartViewBase, BarLineScatterCandleBubbleChartD @objc private func tapGestureRecognized(_ recognizer: NSUITapGestureRecognizer) { - if _data === nil + if data === nil { return } @@ -560,31 +555,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 +589,7 @@ open class BarLineChartViewBase: ChartViewBase, BarLineScatterCandleBubbleChartD { stopDeceleration() - if _data !== nil && + if data !== nil && (_pinchZoomEnabled || _scaleXEnabled || _scaleYEnabled) { _isScaling = true @@ -637,8 +629,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 +639,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 +657,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 +679,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 } @@ -818,12 +810,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 +880,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 +891,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 } @@ -934,11 +926,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 +978,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 +991,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 +1004,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 +1026,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 +1111,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 +1172,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 +1182,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 +1198,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 +1209,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 +1221,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 +1236,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 +1247,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 +1260,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 +1285,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 +1306,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 +1338,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 +1403,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 +1435,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 +1495,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 +1593,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 +1610,7 @@ open class BarLineChartViewBase: ChartViewBase, BarLineScatterCandleBubbleChartD { _scaleXEnabled = newValue #if !os(tvOS) - _pinchGestureRecognizer.isEnabled = _pinchZoomEnabled || _scaleXEnabled || _scaleYEnabled + _pinchGestureRecognizer.isEnabled = _pinchZoomEnabled || _scaleXEnabled || _scaleYEnabled #endif } } @@ -1636,7 +1628,7 @@ open class BarLineChartViewBase: ChartViewBase, BarLineScatterCandleBubbleChartD { _scaleYEnabled = newValue #if !os(tvOS) - _pinchGestureRecognizer.isEnabled = _pinchZoomEnabled || _scaleXEnabled || _scaleYEnabled + _pinchGestureRecognizer.isEnabled = _pinchZoomEnabled || _scaleXEnabled || _scaleYEnabled #endif } } @@ -1716,44 +1708,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 +1765,7 @@ open class BarLineChartViewBase: ChartViewBase, BarLineScatterCandleBubbleChartD { _pinchZoomEnabled = newValue #if !os(tvOS) - _pinchGestureRecognizer.isEnabled = _pinchZoomEnabled || _scaleXEnabled || _scaleYEnabled + _pinchGestureRecognizer.isEnabled = _pinchZoomEnabled || _scaleXEnabled || _scaleYEnabled #endif } } @@ -1796,18 +1779,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 { diff --git a/Source/Charts/Charts/BubbleChartView.swift b/Source/Charts/Charts/BubbleChartView.swift index 1b136775..14e8b462 100644 --- a/Source/Charts/Charts/BubbleChartView.swift +++ b/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 } } diff --git a/Source/Charts/Charts/CandleStickChartView.swift b/Source/Charts/Charts/CandleStickChartView.swift index 0366e8b8..33c2174a 100644 --- a/Source/Charts/Charts/CandleStickChartView.swift +++ b/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 } } diff --git a/Source/Charts/Charts/ChartViewBase.swift b/Source/Charts/Charts/ChartViewBase.swift index 0fccebc4..9ce56fc1 100644 --- a/Source/Charts/Charts/ChartViewBase.swift +++ b/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,53 @@ 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? - + @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 + { + if set.valueFormatter is DefaultValueFormatter + { + set.valueFormatter = defaultValueFormatter + } + } + + // let the chart know there is new data + notifyDataSetChanged() + } + } + /// Flag that indicates if highlighting per tap (touch) is enabled private var _highlightPerTapEnabled = true /// 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 + // TODO: This is used nowhere and can't be used by a consumer. Can we remove this property? 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? @@ -103,24 +109,30 @@ open class ChartViewBase: NSUIView, ChartDataProvider, AnimatorDelegate /// alignment of the no data text @objc open var noDataTextAlignment: NSTextAlignment = .left - internal var _legendRenderer: LegendRenderer! - + /// The renderer object responsible for rendering / drawing the Legend. + @objc open lazy var legendRenderer = LegendRenderer(viewPortHandler: viewPortHandler, legend: legend) + /// 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 +143,11 @@ 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? + + // TODO: There is no way to modify this value. Should it exist? + private let interceptTouchEvents = false + /// An extra offset to be appended to the viewport's top @objc open var extraTopOffset: CGFloat = 0.0 @@ -146,7 +159,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 +184,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 +214,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,9 +247,9 @@ 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) } @@ -303,13 +261,11 @@ open class ChartViewBase: NSUIView, ChartDataProvider, AnimatorDelegate } - 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 } } @@ -317,10 +273,8 @@ open class ChartViewBase: NSUIView, ChartDataProvider, AnimatorDelegate { let optionalContext = NSUIGraphicsGetCurrentContext() guard let context = optionalContext else { return } - - let frame = self.bounds - if _data === nil && noDataText.count > 0 + if data === nil && !noDataText.isEmpty { context.saveGState() defer { context.restoreGState() } @@ -330,53 +284,49 @@ open class ChartViewBase: NSUIView, ChartDataProvider, AnimatorDelegate 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,13 +336,7 @@ 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 @@ -413,7 +357,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 +367,12 @@ 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.isEmpty + ? nil + : highlighted[0] + // redraw the chart setNeedsDisplay() @@ -489,19 +429,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 +458,30 @@ 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 - { - self.lastHighlighted = nil - _indicesToHighlight.removeAll(keepingCapacity: false) - } - else - { - // set the indices to highlight - entry = _data?.entryForHighlight(h!) - if entry == nil - { - h = nil - _indicesToHighlight.removeAll(keepingCapacity: false) - } + var high = highlight + guard + let h = high, + let entry = data?.entry(for: h) else - { - _indicesToHighlight = [h!] - } + { + high = nil + highlighted.removeAll(keepingCapacity: false) + if callDelegate + { + delegate?.chartValueNothingSelected?(self) + } + return } - - if callDelegate, let delegate = delegate + + // set the indices to highlight + highlighted = [h] + + if callDelegate { - if let h = h - { - // notify the listener - delegate.chartValueSelected?(self, entry: entry!, highlight: h) - } - else - { - delegate.chartValueNothingSelected?(self) - } + // notify the listener + delegate?.chartValueSelected?(self, entry: entry, highlight: h) } - + // redraw the chart setNeedsDisplay() } @@ -563,7 +491,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 +510,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 +545,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 +556,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 +569,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 +581,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 +593,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 +604,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 +615,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 +626,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 +636,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 +647,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 +658,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 +668,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,28 +676,28 @@ 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)* @@ -797,43 +711,24 @@ open class ChartViewBase: NSUIView, ChartDataProvider, AnimatorDelegate /// 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 + return viewPortHandler.contentCenter } - - /// The renderer object responsible for rendering / drawing the Legend. - @objc open var legendRenderer: LegendRenderer! - { - return _legendRenderer - } - + /// 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 + 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 - } - + /// - 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 +801,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 +835,7 @@ open class ChartViewBase: NSUIView, ChartDataProvider, AnimatorDelegate @objc open func addViewportJob(_ job: ViewPortJob) { - if _viewPortHandler.hasChartDimens + if viewPortHandler.hasChartDimens { job.doJob() } @@ -960,8 +854,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 +862,15 @@ open class ChartViewBase: NSUIView, ChartDataProvider, AnimatorDelegate } set { - var val = newValue - if val < 0.0 - { - val = 0.0 - } - if val >= 1.0 + switch newValue { - val = 0.999 + case ..<0.0: _dragDecelerationFrictionCoef = 0 + case 1.0...: _dragDecelerationFrictionCoef = 0.999 + default: _dragDecelerationFrictionCoef = newValue } - - _dragDecelerationFrictionCoef = val } } + 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 +879,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,7 +898,7 @@ open class ChartViewBase: NSUIView, ChartDataProvider, AnimatorDelegate open override func nsuiTouchesBegan(_ touches: Set, withEvent event: NSUIEvent?) { - if !_interceptTouchEvents + if !interceptTouchEvents { super.nsuiTouchesBegan(touches, withEvent: event) } @@ -1018,7 +906,7 @@ open class ChartViewBase: NSUIView, ChartDataProvider, AnimatorDelegate open override func nsuiTouchesMoved(_ touches: Set, withEvent event: NSUIEvent?) { - if !_interceptTouchEvents + if !interceptTouchEvents { super.nsuiTouchesMoved(touches, withEvent: event) } @@ -1026,7 +914,7 @@ open class ChartViewBase: NSUIView, ChartDataProvider, AnimatorDelegate open override func nsuiTouchesEnded(_ touches: Set, withEvent event: NSUIEvent?) { - if !_interceptTouchEvents + if !interceptTouchEvents { super.nsuiTouchesEnded(touches, withEvent: event) } @@ -1034,7 +922,7 @@ open class ChartViewBase: NSUIView, ChartDataProvider, AnimatorDelegate open override func nsuiTouchesCancelled(_ touches: Set?, withEvent event: NSUIEvent?) { - if !_interceptTouchEvents + if !interceptTouchEvents { super.nsuiTouchesCancelled(touches, withEvent: event) } diff --git a/Source/Charts/Charts/CombinedChartView.swift b/Source/Charts/Charts/CombinedChartView.swift index 47eebd6c..6b2ecbf1 100644 --- a/Source/Charts/Charts/CombinedChartView.swift +++ b/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 } diff --git a/Source/Charts/Charts/HorizontalBarChartView.swift b/Source/Charts/Charts/HorizontalBarChartView.swift index 7b6163c8..2da79521 100644 --- a/Source/Charts/Charts/HorizontalBarChartView.swift +++ b/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 diff --git a/Source/Charts/Charts/LineChartView.swift b/Source/Charts/Charts/LineChartView.swift index c5fbecfa..e7918266 100644 --- a/Source/Charts/Charts/LineChartView.swift +++ b/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 } } diff --git a/Source/Charts/Charts/PieChartView.swift b/Source/Charts/Charts/PieChartView.swift index 7a036c01..edf00bb5 100644 --- a/Source/Charts/Charts/PieChartView.swift +++ b/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 } @@ -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() + } + } } diff --git a/Source/Charts/Charts/PieRadarChartViewBase.swift b/Source/Charts/Charts/PieRadarChartViewBase.swift index 86edcd84..45b8e0f1 100644 --- a/Source/Charts/Charts/PieRadarChartViewBase.swift +++ b/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) { diff --git a/Source/Charts/Charts/RadarChartView.swift b/Source/Charts/Charts/RadarChartView.swift index 6bcad336..3b21cedd 100644 --- a/Source/Charts/Charts/RadarChartView.swift +++ b/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.. 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) } diff --git a/Source/Charts/Charts/ScatterChartView.swift b/Source/Charts/Charts/ScatterChartView.swift index 22c710ad..070acc68 100644 --- a/Source/Charts/Charts/ScatterChartView.swift +++ b/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 } } diff --git a/Source/Charts/Components/AxisBase.swift b/Source/Charts/Components/AxisBase.swift index 0b59628d..2544f90d 100644 --- a/Source/Charts/Components/AxisBase.swift +++ b/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 @@ -135,7 +135,7 @@ open class AxisBase: ComponentBase { var longest = "" - for i in 0 ..< entries.count + for i in entries.indices { let text = getFormattedLabel(i) @@ -151,10 +151,7 @@ open class AxisBase: ComponentBase /// - 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 +159,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 { diff --git a/Source/Charts/Components/ChartLimitLine.swift b/Source/Charts/Components/ChartLimitLine.swift index 407c7cd4..fc876b4d 100644 --- a/Source/Charts/Components/ChartLimitLine.swift +++ b/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() { diff --git a/Source/Charts/Components/Legend.swift b/Source/Charts/Components/Legend.swift index 2a92f4eb..e86d59ca 100644 --- a/Source/Charts/Components/Legend.swift +++ b/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 diff --git a/Source/Charts/Components/LegendEntry.swift b/Source/Charts/Components/LegendEntry.swift index 5868137e..9d2ae5ea 100644 --- a/Source/Charts/Components/LegendEntry.swift +++ b/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. diff --git a/Source/Charts/Components/IMarker.swift b/Source/Charts/Components/Marker.swift similarity index 84% rename from Source/Charts/Components/IMarker.swift rename to Source/Charts/Components/Marker.swift index a4b75260..c643517a 100644 --- a/Source/Charts/Components/IMarker.swift +++ b/Source/Charts/Components/Marker.swift @@ -12,8 +12,8 @@ import Foundation import CoreGraphics -@objc(IChartMarker) -public protocol IMarker: class +@objc(ChartMarker) +public protocol Marker: class { /// - Returns: The desired (general) offset you wish the IMarker to have on the x-axis. /// By returning x: -(width / 2) you will center the IMarker horizontally. @@ -27,13 +27,13 @@ public protocol IMarker: class /// If you have no adjustments to make, return self.offset(). func offsetForDrawing(atPoint: CGPoint) -> CGPoint - /// This method enables a custom IMarker to update it's content every time the IMarker is redrawn according to the data entry it points to. + /// This method enables a custom Marker to update it's content every time the Marker is redrawn according to the data entry it points to. /// /// - Parameters: /// - entry: The Entry the IMarker belongs to. This can also be any subclass of Entry, like BarEntry or CandleEntry, simply cast it at runtime. /// - highlight: The highlight object contains information about the highlighted value such as it's dataset-index, the selected range or stack-index (only stacked bar entries). func refreshContent(entry: ChartDataEntry, highlight: Highlight) - /// Draws the IMarker on the given position on the given context + /// Draws the Marker on the given position on the given context func draw(context: CGContext, point: CGPoint) } diff --git a/Source/Charts/Components/MarkerImage.swift b/Source/Charts/Components/MarkerImage.swift index 341b1186..eed33422 100644 --- a/Source/Charts/Components/MarkerImage.swift +++ b/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? diff --git a/Source/Charts/Components/MarkerView.swift b/Source/Charts/Components/MarkerView.swift index bf65e67c..5271fb64 100644 --- a/Source/Charts/Components/MarkerView.swift +++ b/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() diff --git a/Source/Charts/Components/YAxis.swift b/Source/Charts/Components/YAxis.swift index 8f528615..b2b1b75a 100644 --- a/Source/Charts/Components/YAxis.swift +++ b/Source/Charts/Components/YAxis.swift @@ -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)) diff --git a/Source/Charts/Data/Implementations/ChartBaseDataSet.swift b/Source/Charts/Data/Implementations/ChartBaseDataSet.swift index b416a422..fc485db5 100644 --- a/Source/Charts/Data/Implementations/ChartBaseDataSet.swift +++ b/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 diff --git a/Source/Charts/Data/Implementations/Standard/BarChartData.swift b/Source/Charts/Data/Implementations/Standard/BarChartData.swift index 6697c32c..ff7ac7e3 100644 --- a/Source/Charts/Data/Implementations/Standard/BarChartData.swift +++ b/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.. Double { - return Double(_dataSets.count) * (self.barWidth + barSpace) + groupSpace + return Double(count) * (self.barWidth + barSpace) + groupSpace } - } diff --git a/Source/Charts/Data/Implementations/Standard/BarChartDataEntry.swift b/Source/Charts/Data/Implementations/Standard/BarChartDataEntry.swift index 31c51b0f..196f1aec 100644 --- a/Source/Charts/Data/Implementations/Standard/BarChartDataEntry.swift +++ b/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 } diff --git a/Source/Charts/Data/Implementations/Standard/BarChartDataSet.swift b/Source/Charts/Data/Implementations/Standard/BarChartDataSet.swift index 2478aecc..8e080ae0 100644 --- a/Source/Charts/Data/Implementations/Standard/BarChartDataSet.swift +++ b/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() @@ -50,68 +50,36 @@ open class BarChartDataSet: BarLineScatterCandleBubbleChartDataSet, IBarChartDat { _entryCountStacks = 0 - for i in 0 ..< entries.count - { - if let vals = entries[i].yValues - { - _entryCountStacks += vals.count - } - else - { - _entryCountStacks += 1 - } - } + entries.forEach { _entryCountStacks += $0.yValues?.count ?? 1 } } /// calculates the maximum stacksize that occurs in the Entries array of this DataSet private func calcStackSize(entries: [BarChartDataEntry]) { - for i in 0 ..< entries.count + for e in entries where (e.yValues?.count ?? 0) > _stackSize { - if let vals = entries[i].yValues - { - if vals.count > _stackSize - { - _stackSize = vals.count - } - } + _stackSize = e.yValues!.count } } 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 { - 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.y, _yMin) + _yMax = Swift.max(e.y, _yMax) } + else + { + _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 +91,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 diff --git a/Source/Charts/Data/Implementations/Standard/BarLineScatterCandleBubbleChartData.swift b/Source/Charts/Data/Implementations/Standard/BarLineScatterCandleBubbleChartData.swift index c98bb1d0..75eb8a27 100644 --- a/Source/Charts/Data/Implementations/Standard/BarLineScatterCandleBubbleChartData.swift +++ b/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) + } } diff --git a/Source/Charts/Data/Implementations/Standard/BarLineScatterCandleBubbleChartDataSet.swift b/Source/Charts/Data/Implementations/Standard/BarLineScatterCandleBubbleChartDataSet.swift index 91382515..6d233db5 100644 --- a/Source/Charts/Data/Implementations/Standard/BarLineScatterCandleBubbleChartDataSet.swift +++ b/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 diff --git a/Source/Charts/Data/Implementations/Standard/BubbleChartData.swift b/Source/Charts/Data/Implementations/Standard/BubbleChartData.swift index 433f384f..5a0a8556 100644 --- a/Source/Charts/Data/Implementations/Standard/BubbleChartData.swift +++ b/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 } } } diff --git a/Source/Charts/Data/Implementations/Standard/BubbleChartDataSet.swift b/Source/Charts/Data/Implementations/Standard/BubbleChartDataSet.swift index 775fafb8..02bdc399 100644 --- a/Source/Charts/Data/Implementations/Standard/BubbleChartDataSet.swift +++ b/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 diff --git a/Source/Charts/Data/Implementations/Standard/CandleChartData.swift b/Source/Charts/Data/Implementations/Standard/CandleChartData.swift index 5158668a..3cfe5bac 100644 --- a/Source/Charts/Data/Implementations/Standard/CandleChartData.swift +++ b/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) + } } diff --git a/Source/Charts/Data/Implementations/Standard/CandleChartDataSet.swift b/Source/Charts/Data/Implementations/Standard/CandleChartDataSet.swift index 1c51da7d..a860a3b9 100644 --- a/Source/Charts/Data/Implementations/Standard/CandleChartDataSet.swift +++ b/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 diff --git a/Source/Charts/Data/Implementations/Standard/ChartData.swift b/Source/Charts/Data/Implementations/Standard/ChartData.swift index f4699ef7..e5e22d0a 100644 --- a/Source/Charts/Data/Implementations/Standard/ChartData.swift +++ b/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(_ 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(_ subrange: Swift.Range, 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] + } } diff --git a/Source/Charts/Data/Implementations/Standard/ChartDataSet.swift b/Source/Charts/Data/Implementations/Standard/ChartDataSet.swift index 9922878d..1d80da16 100644 --- a/Source/Charts/Data/Implementations/Standard/ChartDataSet.swift +++ b/Source/Charts/Data/Implementations/Standard/ChartDataSet.swift @@ -27,25 +27,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 +55,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 +100,24 @@ 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: .down) + let indexTo = entryIndex(x: toX, closestToY: .nan, rounding: .up) - 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 +131,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 +152,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] @@ -376,6 +360,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 +374,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 +389,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 +411,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 +430,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 +441,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 +457,7 @@ open class ChartDataSet: ChartBaseDataSet } // MARK: - Data functions and accessors - + // MARK: - NSCopying open override func copy(with zone: NSZone? = nil) -> Any diff --git a/Source/Charts/Data/Implementations/Standard/CombinedChartData.swift b/Source/Charts/Data/Implementations/Standard/CombinedChartData.swift index e883c8b7..9659055a 100644 --- a/Source/Charts/Data/Implementations/Standard/CombinedChartData.swift +++ b/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") } } diff --git a/Source/Charts/Data/Implementations/Standard/LineChartData.swift b/Source/Charts/Data/Implementations/Standard/LineChartData.swift index 2ebd6b42..fe3eb928 100644 --- a/Source/Charts/Data/Implementations/Standard/LineChartData.swift +++ b/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) + } } diff --git a/Source/Charts/Data/Implementations/Standard/LineChartDataSet.swift b/Source/Charts/Data/Implementations/Standard/LineChartDataSet.swift index b53ddd4d..423ac54c 100644 --- a/Source/Charts/Data/Implementations/Standard/LineChartDataSet.swift +++ b/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 { diff --git a/Source/Charts/Data/Implementations/Standard/LineRadarChartDataSet.swift b/Source/Charts/Data/Implementations/Standard/LineRadarChartDataSet.swift index 54a3af69..91ad13e4 100644 --- a/Source/Charts/Data/Implementations/Standard/LineRadarChartDataSet.swift +++ b/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 diff --git a/Source/Charts/Data/Implementations/Standard/LineScatterCandleRadarChartDataSet.swift b/Source/Charts/Data/Implementations/Standard/LineScatterCandleRadarChartDataSet.swift index 1c68983b..1392cd24 100644 --- a/Source/Charts/Data/Implementations/Standard/LineScatterCandleRadarChartDataSet.swift +++ b/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 diff --git a/Source/Charts/Data/Implementations/Standard/PieChartData.swift b/Source/Charts/Data/Implementations/Standard/PieChartData.swift index 7f343835..accda2ed 100644 --- a/Source/Charts/Data/Implementations/Standard/PieChartData.swift +++ b/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 { diff --git a/Source/Charts/Data/Implementations/Standard/PieChartDataSet.swift b/Source/Charts/Data/Implementations/Standard/PieChartDataSet.swift index ac0e6348..07287ad0 100644 --- a/Source/Charts/Data/Implementations/Standard/PieChartDataSet.swift +++ b/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 } } diff --git a/Source/Charts/Data/Implementations/Standard/RadarChartData.swift b/Source/Charts/Data/Implementations/Standard/RadarChartData.swift index 31fd7d2b..2f8a2db7 100644 --- a/Source/Charts/Data/Implementations/Standard/RadarChartData.swift +++ b/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)) } } diff --git a/Source/Charts/Data/Implementations/Standard/RadarChartDataSet.swift b/Source/Charts/Data/Implementations/Standard/RadarChartDataSet.swift index 030269d6..9b859d14 100644 --- a/Source/Charts/Data/Implementations/Standard/RadarChartDataSet.swift +++ b/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() diff --git a/Source/Charts/Data/Implementations/Standard/ScatterChartData.swift b/Source/Charts/Data/Implementations/Standard/ScatterChartData.swift index e06a6032..49b1e89b 100644 --- a/Source/Charts/Data/Implementations/Standard/ScatterChartData.swift +++ b/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 } diff --git a/Source/Charts/Data/Implementations/Standard/ScatterChartDataSet.swift b/Source/Charts/Data/Implementations/Standard/ScatterChartDataSet.swift index bc9767a0..161deb2f 100644 --- a/Source/Charts/Data/Implementations/Standard/ScatterChartDataSet.swift +++ b/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 { diff --git a/Source/Charts/Data/Interfaces/IBarChartDataSet.swift b/Source/Charts/Data/Interfaces/BarChartDataSetProtocol.swift similarity index 91% rename from Source/Charts/Data/Interfaces/IBarChartDataSet.swift rename to Source/Charts/Data/Interfaces/BarChartDataSetProtocol.swift index b90b4dc0..3ea0903c 100644 --- a/Source/Charts/Data/Interfaces/IBarChartDataSet.swift +++ b/Source/Charts/Data/Interfaces/BarChartDataSetProtocol.swift @@ -1,5 +1,5 @@ // -// IBarChartDataSet.swift +// BarChartDataSetProtocol.swift // Charts // // Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda @@ -13,7 +13,7 @@ import Foundation import CoreGraphics @objc -public protocol IBarChartDataSet: IBarLineScatterCandleBubbleChartDataSet +public protocol BarChartDataSetProtocol: BarLineScatterCandleBubbleChartDataSetProtocol { // MARK: - Data functions and accessors diff --git a/Source/Charts/Data/Interfaces/IBarLineScatterCandleBubbleChartDataSet.swift b/Source/Charts/Data/Interfaces/BarLineScatterCandleBubbleChartDataSetProtocol.swift similarity index 79% rename from Source/Charts/Data/Interfaces/IBarLineScatterCandleBubbleChartDataSet.swift rename to Source/Charts/Data/Interfaces/BarLineScatterCandleBubbleChartDataSetProtocol.swift index 8af47ff4..cbc90147 100644 --- a/Source/Charts/Data/Interfaces/IBarLineScatterCandleBubbleChartDataSet.swift +++ b/Source/Charts/Data/Interfaces/BarLineScatterCandleBubbleChartDataSetProtocol.swift @@ -1,5 +1,5 @@ // -// IBarLineScatterCandleBubbleChartDataSet.swift +// BarLineScatterCandleBubbleChartDataSetProtocol.swift // Charts // // Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda @@ -13,7 +13,7 @@ import Foundation import CoreGraphics @objc -public protocol IBarLineScatterCandleBubbleChartDataSet: IChartDataSet +public protocol BarLineScatterCandleBubbleChartDataSetProtocol: ChartDataSetProtocol { // MARK: - Data functions and accessors diff --git a/Source/Charts/Data/Interfaces/IBubbleChartDataSet.swift b/Source/Charts/Data/Interfaces/BubbleChartDataSetProtocol.swift similarity index 81% rename from Source/Charts/Data/Interfaces/IBubbleChartDataSet.swift rename to Source/Charts/Data/Interfaces/BubbleChartDataSetProtocol.swift index 10c5d9ee..5cc94579 100644 --- a/Source/Charts/Data/Interfaces/IBubbleChartDataSet.swift +++ b/Source/Charts/Data/Interfaces/BubbleChartDataSetProtocol.swift @@ -1,5 +1,5 @@ // -// IBubbleChartDataSet.swift +// BubbleChartDataSetProtocol.swift // Charts // // Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda @@ -13,7 +13,7 @@ import Foundation import CoreGraphics @objc -public protocol IBubbleChartDataSet: IBarLineScatterCandleBubbleChartDataSet +public protocol BubbleChartDataSetProtocol: BarLineScatterCandleBubbleChartDataSetProtocol { // MARK: - Data functions and accessors diff --git a/Source/Charts/Data/Interfaces/ICandleChartDataSet.swift b/Source/Charts/Data/Interfaces/CandleChartDataSetProtocol.swift similarity index 93% rename from Source/Charts/Data/Interfaces/ICandleChartDataSet.swift rename to Source/Charts/Data/Interfaces/CandleChartDataSetProtocol.swift index fac88d3b..d47b5a8c 100644 --- a/Source/Charts/Data/Interfaces/ICandleChartDataSet.swift +++ b/Source/Charts/Data/Interfaces/CandleChartDataSetProtocol.swift @@ -1,5 +1,5 @@ // -// ICandleChartDataSet.swift +// CandleChartDataSetProtocol.swift // Charts // // Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda @@ -13,7 +13,7 @@ import Foundation import CoreGraphics @objc -public protocol ICandleChartDataSet: ILineScatterCandleRadarChartDataSet +public protocol CandleChartDataSetProtocol: LineScatterCandleRadarChartDataSetProtocol { // MARK: - Data functions and accessors diff --git a/Source/Charts/Data/Interfaces/IChartDataSet.swift b/Source/Charts/Data/Interfaces/ChartDataSetProtocol.swift similarity index 97% rename from Source/Charts/Data/Interfaces/IChartDataSet.swift rename to Source/Charts/Data/Interfaces/ChartDataSetProtocol.swift index 849da103..9cf80d33 100644 --- a/Source/Charts/Data/Interfaces/IChartDataSet.swift +++ b/Source/Charts/Data/Interfaces/ChartDataSetProtocol.swift @@ -1,5 +1,5 @@ // -// IChartDataSet.swift +// ChartDataSetProtocol.swift // Charts // // Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda @@ -13,14 +13,14 @@ import Foundation import CoreGraphics @objc -public protocol IChartDataSet +public protocol ChartDataSetProtocol { // MARK: - Data functions and accessors /// Use this method to tell the data set that the underlying data has changed func notifyDataSetChanged() - /// Calculates the minimum and maximum x and y values (_xMin, _xMax, _yMin, _yMax). + /// Calculates the minimum and maximum x and y values (xMin, xMax, yMin, yMax). func calcMinMax() /// Calculates the min and max y-values from the Entry closest to the given fromX to the Entry closest to the given toX value. @@ -196,10 +196,7 @@ public protocol IChartDataSet var isHighlightEnabled: Bool { get } /// Custom formatter that is used instead of the auto-formatter if set - var valueFormatter: IValueFormatter? { get set } - - /// `true` if the valueFormatter object of this DataSet is null. - var needsFormatter: Bool { get } + var valueFormatter: ValueFormatter { get set } /// Sets/get a single color for value text. /// Setting the color clears the colors array and adds a single color. @@ -212,6 +209,9 @@ public protocol IChartDataSet /// the font for the value-text labels var valueFont: NSUIFont { get set } + /// The rotation angle (in degrees) for value-text labels + var valueLabelAngle: CGFloat { get set } + /// The form to draw for this dataset in the legend. /// /// Return `.Default` to use the default legend form. diff --git a/Source/Charts/Data/Interfaces/ILineChartDataSet.swift b/Source/Charts/Data/Interfaces/LineChartDataSetProtocol.swift similarity index 81% rename from Source/Charts/Data/Interfaces/ILineChartDataSet.swift rename to Source/Charts/Data/Interfaces/LineChartDataSetProtocol.swift index 071f2695..7cfc3ab2 100644 --- a/Source/Charts/Data/Interfaces/ILineChartDataSet.swift +++ b/Source/Charts/Data/Interfaces/LineChartDataSetProtocol.swift @@ -1,5 +1,5 @@ // -// ILineChartDataSet.swift +// LineChartDataSetProtocol.swift // Charts // // Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda @@ -14,7 +14,7 @@ import CoreGraphics @objc -public protocol ILineChartDataSet: ILineRadarChartDataSet +public protocol LineChartDataSetProtocol: LineRadarChartDataSetProtocol { // MARK: - Data functions and accessors @@ -29,7 +29,13 @@ public protocol ILineChartDataSet: ILineRadarChartDataSet /// /// **default**: 0.2 var cubicIntensity: CGFloat { get set } - + + /// If true, gradient lines are drawn instead of solid + var isDrawLineWithGradientEnabled: Bool { get set } + + /// The points where gradient should change color + var gradientPositions: [CGFloat]? { get set } + /// The radius of the drawn circles. var circleRadius: CGFloat { get set } @@ -75,6 +81,6 @@ public protocol ILineChartDataSet: ILineRadarChartDataSet /// Line cap type, default is CGLineCap.Butt var lineCapType: CGLineCap { get set } - /// 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. - var fillFormatter: IFillFormatter? { get set } + /// 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. + var fillFormatter: FillFormatter? { get set } } diff --git a/Source/Charts/Data/Interfaces/ILineRadarChartDataSet.swift b/Source/Charts/Data/Interfaces/LineRadarChartDataSetProtocol.swift similarity index 90% rename from Source/Charts/Data/Interfaces/ILineRadarChartDataSet.swift rename to Source/Charts/Data/Interfaces/LineRadarChartDataSetProtocol.swift index d9f8980b..aadcb28b 100644 --- a/Source/Charts/Data/Interfaces/ILineRadarChartDataSet.swift +++ b/Source/Charts/Data/Interfaces/LineRadarChartDataSetProtocol.swift @@ -1,5 +1,5 @@ // -// ILineRadarChartDataSet.swift +// LineRadarChartDataSetProtocol.swift // Charts // // Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda @@ -13,7 +13,7 @@ import Foundation import CoreGraphics @objc -public protocol ILineRadarChartDataSet: ILineScatterCandleRadarChartDataSet +public protocol LineRadarChartDataSetProtocol: LineScatterCandleRadarChartDataSetProtocol { // MARK: - Data functions and accessors diff --git a/Source/Charts/Data/Interfaces/ILineScatterCandleRadarChartDataSet.swift b/Source/Charts/Data/Interfaces/LineScatterCandleRadarChartDataSetProtocol.swift similarity index 87% rename from Source/Charts/Data/Interfaces/ILineScatterCandleRadarChartDataSet.swift rename to Source/Charts/Data/Interfaces/LineScatterCandleRadarChartDataSetProtocol.swift index 27c2bca9..25325e03 100644 --- a/Source/Charts/Data/Interfaces/ILineScatterCandleRadarChartDataSet.swift +++ b/Source/Charts/Data/Interfaces/LineScatterCandleRadarChartDataSetProtocol.swift @@ -1,5 +1,5 @@ // -// ILineScatterCandleRadarChartDataSet.swift +// LineScatterCandleRadarChartDataSetProtocol.swift // Charts // // Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda @@ -12,7 +12,7 @@ import Foundation @objc -public protocol ILineScatterCandleRadarChartDataSet: IBarLineScatterCandleBubbleChartDataSet +public protocol LineScatterCandleRadarChartDataSetProtocol: BarLineScatterCandleBubbleChartDataSetProtocol { // MARK: - Data functions and accessors diff --git a/Source/Charts/Data/Interfaces/IPieChartDataSet.swift b/Source/Charts/Data/Interfaces/PieChartDataSetProtocol.swift similarity index 95% rename from Source/Charts/Data/Interfaces/IPieChartDataSet.swift rename to Source/Charts/Data/Interfaces/PieChartDataSetProtocol.swift index 433c08f2..1b8ea878 100644 --- a/Source/Charts/Data/Interfaces/IPieChartDataSet.swift +++ b/Source/Charts/Data/Interfaces/PieChartDataSetProtocol.swift @@ -1,5 +1,5 @@ // -// IPieChartDataSet.swift +// PieChartDataSetProtocol.swift // Charts // // Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda @@ -13,7 +13,7 @@ import Foundation import CoreGraphics @objc -public protocol IPieChartDataSet: IChartDataSet +public protocol PieChartDataSetProtocol: ChartDataSetProtocol { // MARK: - Styling functions and accessors diff --git a/Source/Charts/Data/Interfaces/IRadarChartDataSet.swift b/Source/Charts/Data/Interfaces/RadarChartDataSetProtocol.swift similarity index 90% rename from Source/Charts/Data/Interfaces/IRadarChartDataSet.swift rename to Source/Charts/Data/Interfaces/RadarChartDataSetProtocol.swift index 2e37b4ff..98c12d77 100644 --- a/Source/Charts/Data/Interfaces/IRadarChartDataSet.swift +++ b/Source/Charts/Data/Interfaces/RadarChartDataSetProtocol.swift @@ -1,5 +1,5 @@ // -// IRadarChartDataSet.swift +// RadarChartDataSetProtocol.swift // Charts // // Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda @@ -13,7 +13,7 @@ import Foundation import CoreGraphics @objc -public protocol IRadarChartDataSet: ILineRadarChartDataSet +public protocol RadarChartDataSetProtocol: LineRadarChartDataSetProtocol { // MARK: - Data functions and accessors diff --git a/Source/Charts/Data/Interfaces/IScatterChartDataSet.swift b/Source/Charts/Data/Interfaces/ScatterChartDataSetProtocol.swift similarity index 72% rename from Source/Charts/Data/Interfaces/IScatterChartDataSet.swift rename to Source/Charts/Data/Interfaces/ScatterChartDataSetProtocol.swift index 05651467..4d160fcd 100644 --- a/Source/Charts/Data/Interfaces/IScatterChartDataSet.swift +++ b/Source/Charts/Data/Interfaces/ScatterChartDataSetProtocol.swift @@ -1,5 +1,5 @@ // -// IScatterChartDataSet.swift +// ScatterChartDataSetProtocol.swift // Charts // // Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda @@ -13,13 +13,13 @@ import Foundation import CoreGraphics @objc -public protocol IScatterChartDataSet: ILineScatterCandleRadarChartDataSet +public protocol ScatterChartDataSetProtocol: LineScatterCandleRadarChartDataSetProtocol { // MARK: - Data functions and accessors // MARK: - Styling functions and accessors - /// The size the scatter shape will have + /// - Returns: The size the scatter shape will have var scatterShapeSize: CGFloat { get } /// - Returns: The radius of the hole in the shape (applies to Square, Circle and Triangle) @@ -31,6 +31,6 @@ public protocol IScatterChartDataSet: ILineScatterCandleRadarChartDataSet /// **default**: nil var scatterShapeHoleColor: NSUIColor? { get } - /// The IShapeRenderer responsible for rendering this DataSet. - var shapeRenderer: IShapeRenderer? { get } + /// - Returns: The ShapeRenderer responsible for rendering this DataSet. + var shapeRenderer: ShapeRenderer? { get } } diff --git a/Source/Charts/Filters/DataApproximator+N.swift b/Source/Charts/Filters/DataApproximator+N.swift index b1949550..e291d84a 100644 --- a/Source/Charts/Filters/DataApproximator+N.swift +++ b/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 { diff --git a/Source/Charts/Filters/DataApproximator.swift b/Source/Charts/Filters/DataApproximator.swift index 234a7d11..db665abf 100644 --- a/Source/Charts/Filters/DataApproximator.swift +++ b/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 diff --git a/Source/Charts/Formatters/IAxisValueFormatter.swift b/Source/Charts/Formatters/AxisValueFormatter.swift similarity index 88% rename from Source/Charts/Formatters/IAxisValueFormatter.swift rename to Source/Charts/Formatters/AxisValueFormatter.swift index 302eee18..57d4cbbb 100644 --- a/Source/Charts/Formatters/IAxisValueFormatter.swift +++ b/Source/Charts/Formatters/AxisValueFormatter.swift @@ -1,5 +1,5 @@ // -// IAxisValueFormatter.swift +// AxisValueFormatter.swift // Charts // // Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda @@ -12,8 +12,8 @@ import Foundation /// An interface for providing custom axis Strings. -@objc(IChartAxisValueFormatter) -public protocol IAxisValueFormatter: class +@objc(ChartAxisValueFormatter) +public protocol AxisValueFormatter: class { /// Called when a value from an axis is formatted before being drawn. diff --git a/Source/Charts/Formatters/DefaultAxisValueFormatter.swift b/Source/Charts/Formatters/DefaultAxisValueFormatter.swift index 85193d0c..b698c5a3 100644 --- a/Source/Charts/Formatters/DefaultAxisValueFormatter.swift +++ b/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, diff --git a/Source/Charts/Formatters/DefaultFillFormatter.swift b/Source/Charts/Formatters/DefaultFillFormatter.swift index 3afadf35..07a6c344 100644 --- a/Source/Charts/Formatters/DefaultFillFormatter.swift +++ b/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) } diff --git a/Source/Charts/Formatters/DefaultValueFormatter.swift b/Source/Charts/Formatters/DefaultValueFormatter.swift index b3fff70a..ee86dc79 100644 --- a/Source/Charts/Formatters/DefaultValueFormatter.swift +++ b/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) } diff --git a/Source/Charts/Formatters/IFillFormatter.swift b/Source/Charts/Formatters/FillFormatter.swift similarity index 72% rename from Source/Charts/Formatters/IFillFormatter.swift rename to Source/Charts/Formatters/FillFormatter.swift index 7b684fd8..bd059811 100644 --- a/Source/Charts/Formatters/IFillFormatter.swift +++ b/Source/Charts/Formatters/FillFormatter.swift @@ -1,5 +1,5 @@ // -// IFillFormatter.swift +// FillFormatter.swift // Charts // // Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda @@ -13,9 +13,9 @@ import Foundation import CoreGraphics /// Protocol for providing a custom logic to where the filling line of a LineDataSet should end. This of course only works if setFillEnabled(...) is set to true. -@objc(IChartFillFormatter) -public protocol IFillFormatter +@objc(ChartFillFormatter) +public protocol FillFormatter { /// - Returns: The vertical (y-axis) position where the filled-line of the LineDataSet should end. - func getFillLinePosition(dataSet: ILineChartDataSet, dataProvider: LineChartDataProvider) -> CGFloat + func getFillLinePosition(dataSet: LineChartDataSetProtocol, dataProvider: LineChartDataProvider) -> CGFloat } diff --git a/Source/Charts/Formatters/IndexAxisValueFormatter.swift b/Source/Charts/Formatters/IndexAxisValueFormatter.swift index ae86509d..6f339eb3 100644 --- a/Source/Charts/Formatters/IndexAxisValueFormatter.swift +++ b/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] } } diff --git a/Source/Charts/Formatters/IValueFormatter.swift b/Source/Charts/Formatters/ValueFormatter.swift similarity index 93% rename from Source/Charts/Formatters/IValueFormatter.swift rename to Source/Charts/Formatters/ValueFormatter.swift index 53ca7a40..61fb23f5 100644 --- a/Source/Charts/Formatters/IValueFormatter.swift +++ b/Source/Charts/Formatters/ValueFormatter.swift @@ -1,5 +1,5 @@ // -// IValueFormatter.swift +// ValueFormatter.swift // Charts // // Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda @@ -16,8 +16,8 @@ import Foundation /// Simply create your own formatting class and let it implement ValueFormatter. Then override the stringForValue() /// method and return whatever you want. -@objc(IChartValueFormatter) -public protocol IValueFormatter: class +@objc(ChartValueFormatter) +public protocol ValueFormatter: class { /// Called when a value (from labels inside the chart) is formatted before being drawn. diff --git a/Source/Charts/Highlight/BarHighlighter.swift b/Source/Charts/Highlight/BarHighlighter.swift index da9e6da7..3191b5d7 100644 --- a/Source/Charts/Highlight/BarHighlighter.swift +++ b/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) @@ -101,7 +101,7 @@ open class BarHighlighter: ChartHighlighter 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 } } diff --git a/Source/Charts/Highlight/ChartHighlighter.swift b/Source/Charts/Highlight/ChartHighlighter.swift index 417ba0d0..08b75ac8 100644 --- a/Source/Charts/Highlight/ChartHighlighter.swift +++ b/Source/Charts/Highlight/ChartHighlighter.swift @@ -12,7 +12,7 @@ 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 +73,11 @@ open class ChartHighlighter : NSObject, IHighlighter guard let data = self.data else { return vals } - for i in 0 ..< data.dataSetCount + for (i, set) in zip(data.indices, data) 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 +85,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 +93,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) diff --git a/Source/Charts/Highlight/CombinedHighlighter.swift b/Source/Charts/Highlight/CombinedHighlighter.swift index 7053df09..40c254cf 100644 --- a/Source/Charts/Highlight/CombinedHighlighter.swift +++ b/Source/Charts/Highlight/CombinedHighlighter.swift @@ -35,7 +35,7 @@ open class CombinedHighlighter: ChartHighlighter let dataObjects = chart.combinedData?.allData else { return vals } - for i in 0.. [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) diff --git a/Source/Charts/Highlight/PieHighlighter.swift b/Source/Charts/Highlight/PieHighlighter.swift index 54bb3d7b..42b30a2b 100644 --- a/Source/Charts/Highlight/PieHighlighter.swift +++ b/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 } diff --git a/Source/Charts/Highlight/RadarHighlighter.swift b/Source/Charts/Highlight/RadarHighlighter.swift index cfaf57ae..e0e9844b 100644 --- a/Source/Charts/Highlight/RadarHighlighter.swift +++ b/Source/Charts/Highlight/RadarHighlighter.swift @@ -57,12 +57,9 @@ open class RadarHighlighter: PieRadarHighlighter let sliceangle = chart.sliceAngle let factor = chart.factor - for i in chartData.dataSets.indices + for (i, dataSet) in zip(chartData.indices, chartData) { - 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) diff --git a/Source/Charts/Jobs/AnimatedMoveViewJob.swift b/Source/Charts/Jobs/AnimatedMoveViewJob.swift index 7a758221..408883a9 100644 --- a/Source/Charts/Jobs/AnimatedMoveViewJob.swift +++ b/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 diff --git a/Source/Charts/Jobs/AnimatedViewPortJob.swift b/Source/Charts/Jobs/AnimatedViewPortJob.swift index 1bdfedf5..363bb008 100644 --- a/Source/Charts/Jobs/AnimatedViewPortJob.swift +++ b/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 diff --git a/Source/Charts/Jobs/AnimatedZoomViewJob.swift b/Source/Charts/Jobs/AnimatedZoomViewJob.swift index 4e9d5fd9..4f239112 100644 --- a/Source/Charts/Jobs/AnimatedZoomViewJob.swift +++ b/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() } } diff --git a/Source/Charts/Jobs/MoveViewJob.swift b/Source/Charts/Jobs/MoveViewJob.swift index 0b6ca320..a9a64fea 100644 --- a/Source/Charts/Jobs/MoveViewJob.swift +++ b/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 diff --git a/Source/Charts/Jobs/ViewPortJob.swift b/Source/Charts/Jobs/ViewPortJob.swift index c52562ed..c3adcca5 100644 --- a/Source/Charts/Jobs/ViewPortJob.swift +++ b/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() diff --git a/Source/Charts/Jobs/ZoomViewJob.swift b/Source/Charts/Jobs/ZoomViewJob.swift index a6a79394..79ce41c7 100644 --- a/Source/Charts/Jobs/ZoomViewJob.swift +++ b/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) diff --git a/Source/Charts/Renderers/AxisRenderer.swift b/Source/Charts/Renderers/AxisRenderer.swift new file mode 100644 index 00000000..35b1ddf7 --- /dev/null +++ b/Source/Charts/Renderers/AxisRenderer.swift @@ -0,0 +1,45 @@ +// +// AxisRenderer.swift +// Charts +// +// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda +// A port of MPAndroidChart for iOS +// Licensed under Apache License 2.0 +// +// https://github.com/danielgindi/Charts +// + +import Foundation +import CoreGraphics + + +public protocol AxisRenderer: Renderer { + + associatedtype Axis: AxisBase + + /// base axis this axis renderer works with + var axis: Axis { get } + + /// transformer to transform values to screen pixels and return + var transformer: Transformer? { get } + + /// Draws the axis labels on the specified context + func renderAxisLabels(context: CGContext) + + /// Draws the grid lines belonging to the axis. + func renderGridLines(context: CGContext) + + /// Draws the line that goes alongside the axis. + func renderAxisLine(context: CGContext) + + /// Draws the LimitLines associated with this axis to the screen. + func renderLimitLines(context: CGContext) + + /// Computes the axis values. + /// - parameter min: the minimum value in the data object for this axis + /// - parameter max: the maximum value in the data object for this axis + func computeAxis(min: Double, max: Double, inverted: Bool) + + /// Sets up the axis values. Computes the desired number of labels between the two given extremes. + func computeAxisValues(min: Double, max: Double) +} diff --git a/Source/Charts/Renderers/BarChartRenderer.swift b/Source/Charts/Renderers/BarChartRenderer.swift index c2ff0b10..9f71e9d6 100644 --- a/Source/Charts/Renderers/BarChartRenderer.swift +++ b/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..= 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..= 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 vals = 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 k in vals.indices { let value = vals[k] var y: Double - + 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 @@ -683,34 +576,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 (val, transformed) in zip(vals, 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 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], + val, entry: e, dataSetIndex: dataSetIndex, viewPortHandler: viewPortHandler), @@ -718,22 +605,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 +667,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: NSTextAlignment, 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 +694,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 +746,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 +772,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 +788,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 +808,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)" diff --git a/Source/Charts/Renderers/BarLineScatterCandleBubbleRenderer.swift b/Source/Charts/Renderers/BarLineScatterCandleBubbleRenderer.swift index 82e6df9c..2f4751d1 100644 --- a/Source/Charts/Renderers/BarLineScatterCandleBubbleRenderer.swift +++ b/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 { diff --git a/Source/Charts/Renderers/BubbleChartRenderer.swift b/Source/Charts/Renderers/BubbleChartRenderer.swift index 1a089e9f..ed1cf461 100644 --- a/Source/Charts/Renderers/BubbleChartRenderer.swift +++ b/Source/Charts/Renderers/BubbleChartRenderer.swift @@ -45,7 +45,7 @@ open class BubbleChartRenderer: BarLineScatterCandleBubbleRenderer accessibleChartElements.append(element) } - for (i, set) in (bubbleData.dataSets as! [IBubbleChartDataSet]).enumerated() where set.isVisible + for case let (i, set) as (Int, BubbleChartDataSetProtocol) in bubbleData.enumerated() where set.isVisible { drawDataSet(context: context, dataSet: set, dataSetIndex: i) } @@ -71,7 +71,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 +153,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 +161,16 @@ open class BubbleChartRenderer: BarLineScatterCandleBubbleRenderer var pt = CGPoint() - for i in 0.. ()) -> NSUIAccessibilityElement @@ -342,10 +342,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 diff --git a/Source/Charts/Renderers/CandleStickChartRenderer.swift b/Source/Charts/Renderers/CandleStickChartRenderer.swift index 2cdaadf5..5690fdb7 100644 --- a/Source/Charts/Renderers/CandleStickChartRenderer.swift +++ b/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 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) diff --git a/Source/Charts/Renderers/ChartDataRendererBase.swift b/Source/Charts/Renderers/ChartDataRendererBase.swift deleted file mode 100644 index abbbcb0d..00000000 --- a/Source/Charts/Renderers/ChartDataRendererBase.swift +++ /dev/null @@ -1,102 +0,0 @@ -// -// DataRenderer.swift -// Charts -// -// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda -// A port of MPAndroidChart for iOS -// Licensed under Apache License 2.0 -// -// https://github.com/danielgindi/Charts -// - -import Foundation -import CoreGraphics - -#if canImport(UIKit) - import UIKit -#endif - -#if canImport(Cocoa) -import Cocoa -#endif - -@objc(ChartDataRendererBase) -open class DataRenderer: Renderer -{ - /// An array of accessibility elements that are presented to the ChartViewBase accessibility methods. - /// - /// Note that the order of elements in this array determines the order in which they are presented and navigated by - /// Accessibility clients such as VoiceOver. - /// - /// Renderers should ensure that the order of elements makes sense to a client presenting an audio-only interface to a user. - /// Subclasses should populate this array in drawData() or drawDataSet() to make the chart accessible. - @objc final var accessibleChartElements: [NSUIAccessibilityElement] = [] - - @objc public let animator: Animator - - @objc public init(animator: Animator, viewPortHandler: ViewPortHandler) - { - self.animator = animator - - super.init(viewPortHandler: viewPortHandler) - } - - @objc open func drawData(context: CGContext) - { - fatalError("drawData() cannot be called on DataRenderer") - } - - @objc open func drawValues(context: CGContext) - { - fatalError("drawValues() cannot be called on DataRenderer") - } - - @objc open func drawExtras(context: CGContext) - { - fatalError("drawExtras() cannot be called on DataRenderer") - } - - /// Draws all highlight indicators for the values that are currently highlighted. - /// - /// - Parameters: - /// - indices: the highlighted values - @objc open func drawHighlighted(context: CGContext, indices: [Highlight]) - { - fatalError("drawHighlighted() cannot be called on DataRenderer") - } - - /// An opportunity for initializing internal buffers used for rendering with a new size. - /// Since this might do memory allocations, it should only be called if necessary. - @objc open func initBuffers() { } - - @objc open func isDrawingValuesAllowed(dataProvider: ChartDataProvider?) -> Bool - { - guard let data = dataProvider?.data else { return false } - return data.entryCount < Int(CGFloat(dataProvider?.maxVisibleCount ?? 0) * viewPortHandler.scaleX) - } - - /// Creates an ```NSUIAccessibilityElement``` that acts as the first and primary header describing a chart view. - /// - /// - Parameters: - /// - chart: The chartView object being described - /// - data: A non optional data source about the chart - /// - defaultDescription: A simple string describing the type/design of Chart. - /// - Returns: A header ```NSUIAccessibilityElement``` that can be added to accessibleChartElements. - @objc internal func createAccessibleHeader(usingChart chart: ChartViewBase, - andData data: ChartData, - withDefaultDescription defaultDescription: String = "Chart") -> NSUIAccessibilityElement - { - let chartDescriptionText = chart.chartDescription?.text ?? defaultDescription - let dataSetDescriptions = data.dataSets.map { $0.label ?? "" } - let dataSetDescriptionText = dataSetDescriptions.joined(separator: ", ") - let dataSetCount = data.dataSets.count - - let - element = NSUIAccessibilityElement(accessibilityContainer: chart) - element.accessibilityLabel = chartDescriptionText + ". \(dataSetCount) dataset\(dataSetCount == 1 ? "" : "s"). \(dataSetDescriptionText)" - element.accessibilityFrame = chart.bounds - element.isHeader = true - - return element - } -} diff --git a/Source/Charts/Renderers/CombinedChartRenderer.swift b/Source/Charts/Renderers/CombinedChartRenderer.swift index 8446c9b6..c215cd21 100644 --- a/Source/Charts/Renderers/CombinedChartRenderer.swift +++ b/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() } @@ -85,12 +93,12 @@ open class CombinedChartRenderer: DataRenderer } - 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 +119,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 +156,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 +164,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. @@ -200,10 +196,14 @@ open class CombinedChartRenderer: DataRenderer } 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) + } } diff --git a/Source/Charts/Renderers/DataRenderer.swift b/Source/Charts/Renderers/DataRenderer.swift new file mode 100644 index 00000000..e417b428 --- /dev/null +++ b/Source/Charts/Renderers/DataRenderer.swift @@ -0,0 +1,75 @@ +// +// DataRenderer.swift +// Charts +// +// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda +// A port of MPAndroidChart for iOS +// Licensed under Apache License 2.0 +// +// https://github.com/danielgindi/Charts +// + +import Foundation +import CoreGraphics + +@objc(ChartDataRenderer) +public protocol DataRenderer: Renderer +{ + /// An array of accessibility elements that are presented to the ChartViewBase accessibility methods. + /// + /// Note that the order of elements in this array determines the order in which they are presented and navigated by + /// Accessibility clients such as VoiceOver. + /// + /// Renderers should ensure that the order of elements makes sense to a client presenting an audio-only interface to a user. + /// Subclasses should populate this array in drawData() or drawDataSet() to make the chart accessible. + var accessibleChartElements: [NSUIAccessibilityElement] { get } + + var animator: Animator { get } + + func drawData(context: CGContext) + + func drawValues(context: CGContext) + + func drawExtras(context: CGContext) + + /// Draws all highlight indicators for the values that are currently highlighted. + /// + /// - Parameters: + /// - indices: the highlighted values + func drawHighlighted(context: CGContext, indices: [Highlight]) + + /// An opportunity for initializing internal buffers used for rendering with a new size. + /// Since this might do memory allocations, it should only be called if necessary. + func initBuffers() + + func isDrawingValuesAllowed(dataProvider: ChartDataProvider?) -> Bool + + /// Creates an ```NSUIAccessibilityElement``` that acts as the first and primary header describing a chart view. + /// + /// - Parameters: + /// - chart: The chartView object being described + /// - data: A non optional data source about the chart + /// - defaultDescription: A simple string describing the type/design of Chart. + /// - Returns: A header ```NSUIAccessibilityElement``` that can be added to accessibleChartElements. + func createAccessibleHeader(usingChart chart: ChartViewBase, + andData data: ChartData, + withDefaultDescription defaultDescription: String) -> NSUIAccessibilityElement +} + +internal struct AccessibleHeader { + static func create(usingChart chart: ChartViewBase, + andData data: ChartData, + withDefaultDescription defaultDescription: String = "Chart") -> NSUIAccessibilityElement + { + let chartDescriptionText = chart.chartDescription.text ?? defaultDescription + let dataSetDescriptions = data.map { $0.label ?? "" } + let dataSetDescriptionText = dataSetDescriptions.joined(separator: ", ") + + let element = NSUIAccessibilityElement(accessibilityContainer: chart) + element.accessibilityLabel = chartDescriptionText + ". \(data.count) dataset\(data.count == 1 ? "" : "s"). \(dataSetDescriptionText)" + element.accessibilityFrame = chart.bounds + element.isHeader = true + + return element + } +} diff --git a/Source/Charts/Renderers/HorizontalBarChartRenderer.swift b/Source/Charts/Renderers/HorizontalBarChartRenderer.swift index 36f4a6c8..f61cf42f 100644 --- a/Source/Charts/Renderers/HorizontalBarChartRenderer.swift +++ b/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,9 +323,7 @@ open class HorizontalBarChartRenderer: BarChartRenderer let dataProvider = dataProvider, let barData = dataProvider.barData else { return } - - let dataSets = barData.dataSets - + let textAlign = NSTextAlignment.left let valueOffsetPlus: CGFloat = 5.0 @@ -336,19 +331,21 @@ open class HorizontalBarChartRenderer: BarChartRenderer 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 } } } diff --git a/Source/Charts/Renderers/LegendRenderer.swift b/Source/Charts/Renderers/LegendRenderer.swift index b9514b4f..41fd499d 100755 --- a/Source/Charts/Renderers/LegendRenderer.swift +++ b/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.. 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.. 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]) } } diff --git a/Source/Charts/Renderers/LineChartRenderer.swift b/Source/Charts/Renderers/LineChartRenderer.swift index ce3a2591..459e2e8e 100644 --- a/Source/Charts/Renderers/LineChartRenderer.swift +++ b/Source/Charts/Renderers/LineChartRenderer.swift @@ -33,23 +33,20 @@ open class LineChartRenderer: LineRadarRenderer { guard let lineData = dataProvider?.lineData else { return } - for i in 0 ..< lineData.dataSetCount + for i in lineData.indices { - guard let set = lineData.getDataSetByIndex(i) else { continue } - - if set.isVisible + guard let set = lineData[i] as? LineChartDataSetProtocol else { - if !(set is ILineChartDataSet) - { - fatalError("Datasets for LineChartRenderer must conform to ILineChartDataSet") - } - - drawDataSet(context: context, dataSet: set as! ILineChartDataSet) + fatalError("Datasets for LineChartRenderer must conform to LineChartDataSetProtocol") } + + guard set.isVisible else { continue } + + drawDataSet(context: context, dataSet: set) } } - @objc open func drawDataSet(context: CGContext, dataSet: ILineChartDataSet) + @objc open func drawDataSet(context: CGContext, dataSet: LineChartDataSetProtocol) { if dataSet.entryCount < 1 { @@ -86,8 +83,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 +170,8 @@ open class LineChartRenderer: LineRadarRenderer } context.saveGState() - + defer { context.restoreGState() } + if dataSet.isDrawFilledEnabled { // Copy this path because we make changes to it @@ -170,16 +179,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 +240,7 @@ open class LineChartRenderer: LineRadarRenderer } context.saveGState() + defer { context.restoreGState() } if dataSet.isDrawFilledEnabled { @@ -237,21 +249,23 @@ 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 @@ -285,7 +299,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 +322,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] } - } - else - { - _lineSegments[1] = _lineSegments[0] - } - for i in 0..<_lineSegments.count - { - _lineSegments[i] = _lineSegments[i].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 } + _lineSegments = _lineSegments.map { $0.applying(valueToPixelMatrix) } + + if (!viewPortHandler.isInBoundsRight(_lineSegments[0].x)) + { + break + } - // make sure the lines don't do shitty things outside bounds + // 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 + { // only one color per dataset + guard dataSet.entryForIndex(_xBounds.min) != nil else { + return + } + + var firstPoint = true + + let path = CGMutablePath() + for x in stride(from: _xBounds.min, through: _xBounds.range + _xBounds.min, by: 1) { - continue + 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) } - // get the color that is set for this line-segment - context.setStrokeColor(dataSet.color(atIndex: j).cgColor) - context.strokeLineSegments(between: _lineSegments) + if !firstPoint + { + 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() + } + } } - - 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 +476,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 @@ -453,22 +527,22 @@ open class LineChartRenderer: LineRadarRenderer 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, + 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 +577,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) } } } @@ -544,8 +616,6 @@ open class LineChartRenderer: LineRadarRenderer else { return } let phaseY = animator.phaseY - - let dataSets = lineData.dataSets var pt = CGPoint() var rect = CGRect() @@ -564,11 +634,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 +681,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 +731,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 @@ -700,8 +764,8 @@ open class LineChartRenderer: LineRadarRenderer for high in indices { - guard let set = lineData.getDataSetByIndex(high.dataSetIndex) as? ILineChartDataSet - , set.isHighlightEnabled + 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 +774,7 @@ open class LineChartRenderer: LineRadarRenderer { continue } - + context.setStrokeColor(set.highlightColor.cgColor) context.setLineWidth(set.highlightLineWidth) if set.highlightLineDashLengths != nil @@ -743,6 +807,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]] @@ -760,7 +881,7 @@ open class LineChartRenderer: LineRadarRenderer /// Note that it is marked internal to support subclass modification in the HorizontalBarChart. private func createAccessibleElement(withIndex idx: Int, container: LineChartView, - dataSet: ILineChartDataSet, + dataSet: LineChartDataSetProtocol, dataSetIndex: Int, modifier: (NSUIAccessibilityElement) -> ()) -> NSUIAccessibilityElement { @@ -775,10 +896,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, + let elementValueText = dataSet.valueFormatter.stringForValue(e.y, entry: e, dataSetIndex: dataSetIndex, - viewPortHandler: viewPortHandler) ?? "\(e.y)" + viewPortHandler: viewPortHandler) let dataSetCount = dataProvider.lineData?.dataSetCount ?? -1 let doesContainMultipleDataSets = dataSetCount > 1 diff --git a/Source/Charts/Renderers/LineScatterCandleRadarRenderer.swift b/Source/Charts/Renderers/LineScatterCandleRadarRenderer.swift index 05203caf..dd33ffe8 100644 --- a/Source/Charts/Renderers/LineScatterCandleRadarRenderer.swift +++ b/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 diff --git a/Source/Charts/Renderers/PieChartRenderer.swift b/Source/Charts/Renderers/PieChartRenderer.swift index 19ea0d46..33e23e44 100644 --- a/Source/Charts/Renderers/PieChartRenderer.swift +++ b/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 { @@ -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) + } } diff --git a/Source/Charts/Renderers/RadarChartRenderer.swift b/Source/Charts/Renderers/RadarChartRenderer.swift index c2ab79fc..26da1e85 100644 --- a/Source/Charts/Renderers/RadarChartRenderer.swift +++ b/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 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) diff --git a/Source/Charts/Renderers/Renderer.swift b/Source/Charts/Renderers/Renderer.swift index e57a9b85..dbdcb8ae 100644 --- a/Source/Charts/Renderers/Renderer.swift +++ b/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 } } diff --git a/Source/Charts/Renderers/Scatter/ChevronDownShapeRenderer.swift b/Source/Charts/Renderers/Scatter/ChevronDownShapeRenderer.swift index 2d035bf3..1dab1cc4 100644 --- a/Source/Charts/Renderers/Scatter/ChevronDownShapeRenderer.swift +++ b/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) diff --git a/Source/Charts/Renderers/Scatter/ChevronUpShapeRenderer.swift b/Source/Charts/Renderers/Scatter/ChevronUpShapeRenderer.swift index 725533e7..0d077707 100644 --- a/Source/Charts/Renderers/Scatter/ChevronUpShapeRenderer.swift +++ b/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) diff --git a/Source/Charts/Renderers/Scatter/CircleShapeRenderer.swift b/Source/Charts/Renderers/Scatter/CircleShapeRenderer.swift index b94a5113..fc0c4dfe 100644 --- a/Source/Charts/Renderers/Scatter/CircleShapeRenderer.swift +++ b/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) diff --git a/Source/Charts/Renderers/Scatter/CrossShapeRenderer.swift b/Source/Charts/Renderers/Scatter/CrossShapeRenderer.swift index 18785d3d..7961da25 100644 --- a/Source/Charts/Renderers/Scatter/CrossShapeRenderer.swift +++ b/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) diff --git a/Source/Charts/Renderers/Scatter/IShapeRenderer.swift b/Source/Charts/Renderers/Scatter/ShapeRenderer.swift similarity index 87% rename from Source/Charts/Renderers/Scatter/IShapeRenderer.swift rename to Source/Charts/Renderers/Scatter/ShapeRenderer.swift index ff12ee3f..c334a5b8 100644 --- a/Source/Charts/Renderers/Scatter/IShapeRenderer.swift +++ b/Source/Charts/Renderers/Scatter/ShapeRenderer.swift @@ -1,5 +1,5 @@ // -// IShapeRenderer.swift +// ShapeRenderer.swift // Charts // // Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda @@ -13,7 +13,7 @@ import Foundation import CoreGraphics @objc -public protocol IShapeRenderer: class +public protocol ShapeRenderer: class { /// Renders the provided ScatterDataSet with a shape. /// @@ -25,7 +25,7 @@ public protocol IShapeRenderer: class /// - color: Color to draw the shape func renderShape( context: CGContext, - dataSet: IScatterChartDataSet, + dataSet: ScatterChartDataSetProtocol, viewPortHandler: ViewPortHandler, point: CGPoint, color: NSUIColor) diff --git a/Source/Charts/Renderers/Scatter/SquareShapeRenderer.swift b/Source/Charts/Renderers/Scatter/SquareShapeRenderer.swift index ea692e33..948c1ff2 100644 --- a/Source/Charts/Renderers/Scatter/SquareShapeRenderer.swift +++ b/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) diff --git a/Source/Charts/Renderers/Scatter/TriangleShapeRenderer.swift b/Source/Charts/Renderers/Scatter/TriangleShapeRenderer.swift index fa313b76..1f4bdca0 100644 --- a/Source/Charts/Renderers/Scatter/TriangleShapeRenderer.swift +++ b/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) diff --git a/Source/Charts/Renderers/Scatter/XShapeRenderer.swift b/Source/Charts/Renderers/Scatter/XShapeRenderer.swift index 8a546c5f..73e2efdd 100644 --- a/Source/Charts/Renderers/Scatter/XShapeRenderer.swift +++ b/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) diff --git a/Source/Charts/Renderers/ScatterChartRenderer.swift b/Source/Charts/Renderers/ScatterChartRenderer.swift index 57d348b2..d80e5729 100644 --- a/Source/Charts/Renderers/ScatterChartRenderer.swift +++ b/Source/Charts/Renderers/ScatterChartRenderer.swift @@ -41,25 +41,22 @@ 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 + for i in scatterData.indices { - guard let set = scatterData.getDataSetByIndex(i) else { continue } - - if set.isVisible + guard let set = scatterData[i] as? ScatterChartDataSetProtocol else { - if !(set is IScatterChartDataSet) - { - fatalError("Datasets for ScatterChartRenderer must conform to IScatterChartDataSet") - } - - drawDataSet(context: context, dataSet: set as! IScatterChartDataSet) + fatalError("Datasets for ScatterChartRenderer must conform to ScatterChartDataSetProtocol") } + + guard set.isVisible else { continue } + + drawDataSet(context: context, dataSet: set) } } 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 +100,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 +113,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 +168,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 +207,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 } diff --git a/Source/Charts/Renderers/XAxisRenderer.swift b/Source/Charts/Renderers/XAxisRenderer.swift index 2cb80bc2..db820a1e 100644 --- a/Source/Charts/Renderers/XAxisRenderer.swift +++ b/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?) + public let viewPortHandler: ViewPortHandler + public let axis: XAxis + 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[.. 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: NSTextAlignment + 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]) } } diff --git a/Source/Charts/Renderers/XAxisRendererHorizontalBarChart.swift b/Source/Charts/Renderers/XAxisRendererHorizontalBarChart.swift index 86c569d9..18f5f959 100644 --- a/Source/Charts/Renderers/XAxisRendererHorizontalBarChart.swift +++ b/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.. 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: NSTextAlignment + 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]) } } } diff --git a/Source/Charts/Renderers/XAxisRendererRadarChart.swift b/Source/Charts/Renderers/XAxisRendererRadarChart.swift index c5fcedf5..6dbf2631 100644 --- a/Source/Charts/Renderers/XAxisRendererRadarChart.swift +++ b/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) diff --git a/Source/Charts/Renderers/YAxisRenderer.swift b/Source/Charts/Renderers/YAxisRenderer.swift index 9d0017f4..74248f7f 100644 --- a/Source/Charts/Renderers/YAxisRenderer.swift +++ b/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?) + public let viewPortHandler: ViewPortHandler + public let axis: YAxis + 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: NSTextAlignment 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 @@ -132,44 +125,29 @@ open class YAxisRenderer: AxisRendererBase offset: CGFloat, textAlign: NSTextAlignment) { - 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.. [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 { return } + + let labelLineHeight = l.valueFont.lineHeight + + let xOffset = 4.0 + l.xOffset + let yOffset = l.lineWidth + labelLineHeight + l.yOffset + + let align: NSTextAlignment + 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() } } diff --git a/Source/Charts/Renderers/YAxisRendererHorizontalBarChart.swift b/Source/Charts/Renderers/YAxisRendererHorizontalBarChart.swift index de4f65e5..cd3a91f4 100644 --- a/Source/Charts/Renderers/YAxisRendererHorizontalBarChart.swift +++ b/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.. [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: NSTextAlignment + 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() } } diff --git a/Source/Charts/Renderers/YAxisRendererRadarChart.swift b/Source/Charts/Renderers/YAxisRendererRadarChart.swift index a5e44daa..a47bf6ac 100644 --- a/Source/Charts/Renderers/YAxisRendererRadarChart.swift +++ b/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..= 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") diff --git a/Source/Charts/Utils/ChartUtils.swift b/Source/Charts/Utils/ChartUtils.swift index 5e90873b..2c3767a9 100644 --- a/Source/Charts/Utils/ChartUtils.swift +++ b/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 @@ -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) + + open 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]?) + + open func drawText(_ text: String, at point: CGPoint, align: NSTextAlignment, 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) + open 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: NSTextAlignment, 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) } } diff --git a/Source/Charts/Utils/Fill.swift b/Source/Charts/Utils/Fill.swift index 1294b3ef..7a6520f1 100644 --- a/Source/Charts/Utils/Fill.swift +++ b/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] + ) } - } diff --git a/Source/Charts/Utils/Platform+Accessibility.swift b/Source/Charts/Utils/Platform+Accessibility.swift index 35668eab..d936ae2e 100644 --- a/Source/Charts/Utils/Platform+Accessibility.swift +++ b/Source/Charts/Utils/Platform+Accessibility.swift @@ -12,9 +12,7 @@ import Foundation #if os(iOS) || os(tvOS) -#if canImport(UIKit) - import UIKit -#endif +import UIKit internal func accessibilityPostLayoutChangedNotification(withElement element: Any? = nil) { @@ -50,7 +48,7 @@ open class NSUIAccessibilityElement: UIAccessibilityElement 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) { diff --git a/Source/Charts/Utils/Platform.swift b/Source/Charts/Utils/Platform.swift index 3722647d..270b803f 100644 --- a/Source/Charts/Utils/Platform.swift +++ b/Source/Charts/Utils/Platform.swift @@ -1,240 +1,278 @@ 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 + import UIKit + + public typealias NSUIFont = UIFont + public typealias NSUIImage = UIImage + public typealias NSUIScrollView = UIScrollView + public typealias NSUIScreen = UIScreen + public typealias NSUIDisplayLink = CADisplayLink + + extension NSUIColor + { + 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 getRed(&red, green: &green, blue: &blue, alpha: &alpha) else { + return nil + } -public typealias NSUIFont = UIFont -public typealias NSUIImage = UIImage -public typealias NSUIScrollView = UIScrollView -public typealias NSUIScreen = UIScreen -public typealias NSUIDisplayLink = CADisplayLink + return (red: red, green: green, blue: blue, alpha: alpha) + } + } -open class NSUIView: UIView -{ - @objc var nsuiLayer: CALayer? + open class NSUIView: UIView { - return self.layer + @objc var nsuiLayer: CALayer? + { + return self.layer + } } -} -extension UIScrollView -{ - @objc var nsuiIsScrollEnabled: Bool + extension UIScrollView + { + @objc var nsuiIsScrollEnabled: Bool + { + get { return isScrollEnabled } + set { isScrollEnabled = newValue } + } + } + + extension UIScreen + { + @objc final var nsuiScale: CGFloat { - get { return isScrollEnabled } - set { isScrollEnabled = newValue } + return self.scale + } } -} -extension UIScreen -{ - @objc final var nsuiScale: CGFloat + func NSUIMainScreen() -> NSUIScreen? { - return self.scale + return NSUIScreen.main } -} #endif #if os(OSX) -import Cocoa -import Quartz - -public typealias NSUIFont = NSFont -public typealias NSUIImage = NSImage -public typealias NSUIScrollView = NSScrollView -public typealias NSUIScreen = NSScreen + import Cocoa + import Quartz -/** 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 + public typealias NSUIFont = NSFont + public typealias NSUIImage = NSImage + public typealias NSUIScrollView = NSScrollView + public typealias NSUIScreen = NSScreen - private weak var _target: AnyObject? - private var _selector: Selector - - public var timestamp: CFTimeInterval + /** On OS X there is no CADisplayLink. Use a 60 fps timer to render the animations. */ + public class NSUIDisplayLink { - return _timestamp - } - - init(target: Any, selector: Selector) - { - _target = target as AnyObject - _selector = selector - - if CVDisplayLinkCreateWithActiveCGDisplays(&displayLink) == kCVReturnSuccess + 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 + } - CVDisplayLinkSetOutputCallback(displayLink!, { (displayLink, inNow, inOutputTime, flagsIn, flagsOut, userData) -> CVReturn in - - let _self = unsafeBitCast(userData, to: NSUIDisplayLink.self) + init(target: AnyObject, selector: Selector) + { + _target = target + _selector = selector + + if CVDisplayLinkCreateWithActiveCGDisplays(&displayLink) == kCVReturnSuccess + { + + CVDisplayLinkSetOutputCallback(displayLink!, { (displayLink, inNow, inOutputTime, flagsIn, flagsOut, userData) -> CVReturn in - _self._timestamp = CFAbsoluteTimeGetCurrent() - _self._target?.performSelector(onMainThread: _self._selector, with: _self, waitUntilDone: false) + let _self = unsafeBitCast(userData, to: NSUIDisplayLink.self) - return kCVReturnSuccess - }, Unmanaged.passUnretained(self).toOpaque()) - } - else - { - timer = Timer(timeInterval: 1.0 / 60.0, target: target, selector: selector, userInfo: nil, repeats: true) - } + _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() - } - - open func add(to runloop: RunLoop, forMode mode: RunLoop.Mode) - { - if displayLink != nil - { - CVDisplayLinkStart(displayLink!) - } - else if timer != nil + + deinit { - runloop.add(timer!, forMode: mode) + stop() } - } - open func remove(from: RunLoop, forMode: RunLoop.Mode) - { - stop() - } + open func add(to runloop: RunLoop, forMode mode: RunLoop.Mode) + { + if displayLink != nil + { + CVDisplayLinkStart(displayLink!) + } + else if timer != nil + { + runloop.add(timer!, forMode: mode) + } + } - private func stop() - { - if displayLink != nil + open func remove(from: RunLoop, forMode: RunLoop.Mode) { - CVDisplayLinkStop(displayLink!) - } - if timer != nil + stop() + } + + private func stop() { - timer?.invalidate() + if displayLink != nil + { + CVDisplayLinkStop(displayLink!) + } + if timer != nil + { + timer?.invalidate() + } } - } -} + } -extension NSView -{ - final var nsuiGestureRecognizers: [NSGestureRecognizer]? + extension NSUIColor { - return self.gestureRecognizers - } -} - -extension NSScrollView -{ - var nsuiIsScrollEnabled: Bool - { - get { return scrollEnabled } - set { scrollEnabled = newValue } + 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) + } } -} -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 - - public override init(frame frameRect: NSRect) + extension NSView { - super.init(frame: frameRect) - setAccessibilityRole(role) - } + final var nsuiGestureRecognizers: [NSGestureRecognizer]? + { + return self.gestureRecognizers + } + } - required public init?(coder decoder: NSCoder) + extension NSScrollView { - super.init(coder: decoder) - setAccessibilityRole(role) + var nsuiIsScrollEnabled: Bool + { + get { return scrollEnabled } + set { scrollEnabled = newValue } + } } - - public final override var isFlipped: Bool + + open class NSUIView: NSView { - return true - } + /// 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 - func setNeedsDisplay() - { - self.setNeedsDisplay(self.bounds) - } + public override init(frame frameRect: NSRect) + { + super.init(frame: frameRect) + setAccessibilityRole(role) + } + required public init?(coder decoder: NSCoder) + { + super.init(coder: decoder) + setAccessibilityRole(role) + } - open var backgroundColor: NSUIColor? + public final override var isFlipped: Bool { - get + return true + } + + func setNeedsDisplay() { - return self.layer?.backgroundColor == nil - ? nil - : NSColor(cgColor: self.layer!.backgroundColor!) - } - set + self.setNeedsDisplay(self.bounds) + } + + open var backgroundColor: NSUIColor? { - self.wantsLayer = true - self.layer?.backgroundColor = newValue == nil ? nil : newValue!.cgColor + 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 } -} diff --git a/Source/Charts/Utils/Transformer.swift b/Source/Charts/Utils/Transformer.swift index b50ea823..db27d17c 100644 --- a/Source/Charts/Utils/Transformer.swift +++ b/Source/Charts/Utils/Transformer.swift @@ -17,37 +17,37 @@ import CoreGraphics open class Transformer: NSObject { /// matrix to map the values to the screen pixels - internal var _matrixValueToPx = CGAffineTransform.identity + internal var matrixValueToPx = CGAffineTransform.identity /// matrix for handling the different offsets of the chart - internal var _matrixOffset = CGAffineTransform.identity + internal var matrixOffset = CGAffineTransform.identity - internal var _viewPortHandler: ViewPortHandler + internal var viewPortHandler: ViewPortHandler @objc public init(viewPortHandler: ViewPortHandler) { - _viewPortHandler = viewPortHandler + self.viewPortHandler = viewPortHandler } /// Prepares the matrix that transforms values to pixels. Calculates the scale factors from the charts size and offsets. @objc open func prepareMatrixValuePx(chartXMin: Double, deltaX: CGFloat, deltaY: CGFloat, chartYMin: Double) { - var scaleX = (_viewPortHandler.contentWidth / deltaX) - var scaleY = (_viewPortHandler.contentHeight / deltaY) + var scaleX = (viewPortHandler.contentWidth / deltaX) + var scaleY = (viewPortHandler.contentHeight / deltaY) - if CGFloat.infinity == scaleX + if .infinity == scaleX { scaleX = 0.0 } - if CGFloat.infinity == scaleY + if .infinity == scaleY { scaleY = 0.0 } // setup all matrices - _matrixValueToPx = CGAffineTransform.identity - _matrixValueToPx = _matrixValueToPx.scaledBy(x: scaleX, y: -scaleY) - _matrixValueToPx = _matrixValueToPx.translatedBy(x: CGFloat(-chartXMin), y: CGFloat(-chartYMin)) + matrixValueToPx = CGAffineTransform.identity + .scaledBy(x: scaleX, y: -scaleY) + .translatedBy(x: CGFloat(-chartXMin), y: CGFloat(-chartYMin)) } /// Prepares the matrix that contains all offsets. @@ -55,12 +55,12 @@ open class Transformer: NSObject { if !inverted { - _matrixOffset = CGAffineTransform(translationX: _viewPortHandler.offsetLeft, y: _viewPortHandler.chartHeight - _viewPortHandler.offsetBottom) + matrixOffset = CGAffineTransform(translationX: viewPortHandler.offsetLeft, y: viewPortHandler.chartHeight - viewPortHandler.offsetBottom) } else { - _matrixOffset = CGAffineTransform(scaleX: 1.0, y: -1.0) - _matrixOffset = _matrixOffset.translatedBy(x: _viewPortHandler.offsetLeft, y: -_viewPortHandler.offsetTop) + matrixOffset = CGAffineTransform(scaleX: 1.0, y: -1.0) + .translatedBy(x: viewPortHandler.offsetLeft, y: -viewPortHandler.offsetTop) } } @@ -158,8 +158,8 @@ open class Transformer: NSObject @objc open var valueToPixelMatrix: CGAffineTransform { return - _matrixValueToPx.concatenating(_viewPortHandler.touchMatrix - ).concatenating(_matrixOffset + matrixValueToPx.concatenating(viewPortHandler.touchMatrix) + .concatenating(matrixOffset ) } diff --git a/Source/Charts/Utils/TransformerHorizontalBarChart.swift b/Source/Charts/Utils/TransformerHorizontalBarChart.swift index d7e657bd..1a7d5579 100644 --- a/Source/Charts/Utils/TransformerHorizontalBarChart.swift +++ b/Source/Charts/Utils/TransformerHorizontalBarChart.swift @@ -20,13 +20,13 @@ open class TransformerHorizontalBarChart: Transformer { if !inverted { - _matrixOffset = CGAffineTransform(translationX: _viewPortHandler.offsetLeft, y: _viewPortHandler.chartHeight - _viewPortHandler.offsetBottom) + matrixOffset = CGAffineTransform(translationX: viewPortHandler.offsetLeft, y: viewPortHandler.chartHeight - viewPortHandler.offsetBottom) } else { - _matrixOffset = CGAffineTransform(scaleX: -1.0, y: 1.0) - _matrixOffset = _matrixOffset.translatedBy(x: -(_viewPortHandler.chartWidth - _viewPortHandler.offsetRight), - y: _viewPortHandler.chartHeight - _viewPortHandler.offsetBottom) + matrixOffset = CGAffineTransform(scaleX: -1.0, y: 1.0) + .translatedBy(x: -(viewPortHandler.chartWidth - viewPortHandler.offsetRight), + y: viewPortHandler.chartHeight - viewPortHandler.offsetBottom) } } } diff --git a/Source/Charts/Utils/ViewPortHandler.swift b/Source/Charts/Utils/ViewPortHandler.swift old mode 100755 new mode 100644 index 8916d068..bf27481b --- a/Source/Charts/Utils/ViewPortHandler.swift +++ b/Source/Charts/Utils/ViewPortHandler.swift @@ -17,44 +17,44 @@ import CoreGraphics open class ViewPortHandler: NSObject { /// matrix used for touch events - private var _touchMatrix = CGAffineTransform.identity - + @objc open private(set) var touchMatrix = CGAffineTransform.identity + /// this rectangle defines the area in which graph values can be drawn - private var _contentRect = CGRect() - - private var _chartWidth = CGFloat(0.0) - private var _chartHeight = CGFloat(0.0) + @objc open private(set) var contentRect = CGRect() + @objc open private(set) var chartWidth: CGFloat = 0 + @objc open private(set) var chartHeight: CGFloat = 0 + /// minimum scale value on the y-axis - private var _minScaleY = CGFloat(1.0) - + @objc open private(set) var minScaleY: CGFloat = 1.0 + /// maximum scale value on the y-axis - private var _maxScaleY = CGFloat.greatestFiniteMagnitude - + @objc open private(set) var maxScaleY = CGFloat.greatestFiniteMagnitude + /// minimum scale value on the x-axis - private var _minScaleX = CGFloat(1.0) - + @objc open private(set) var minScaleX: CGFloat = 1.0 + /// maximum scale value on the x-axis - private var _maxScaleX = CGFloat.greatestFiniteMagnitude - + @objc open private(set) var maxScaleX = CGFloat.greatestFiniteMagnitude + /// contains the current scale factor of the x-axis - private var _scaleX = CGFloat(1.0) - + @objc open private(set) var scaleX: CGFloat = 1.0 + /// contains the current scale factor of the y-axis - private var _scaleY = CGFloat(1.0) - - /// current translation (drag distance) on the x-axis - private var _transX = CGFloat(0.0) - - /// current translation (drag distance) on the y-axis - private var _transY = CGFloat(0.0) - + @objc open private(set) var scaleY: CGFloat = 1.0 + + /// current translation (drag / pan) distance on the x-axis + @objc open private(set) var transX: CGFloat = 0 + + /// current translation (drag / pan) distance on the y-axis + @objc open private(set) var transY: CGFloat = 0 + /// offset that allows the chart to be dragged over its bounds on the x-axis - private var _transOffsetX = CGFloat(0.0) - + private var transOffsetX: CGFloat = 0 + /// offset that allows the chart to be dragged over its bounds on the x-axis - private var _transOffsetY = CGFloat(0.0) - + private var transOffsetY: CGFloat = 0 + /// Constructor - don't forget calling setChartDimens(...) @objc public init(width: CGFloat, height: CGFloat) { @@ -70,100 +70,79 @@ open class ViewPortHandler: NSObject let offsetRight = self.offsetRight let offsetBottom = self.offsetBottom - _chartHeight = height - _chartWidth = width + chartHeight = height + chartWidth = width restrainViewPort(offsetLeft: offsetLeft, offsetTop: offsetTop, offsetRight: offsetRight, offsetBottom: offsetBottom) } @objc open var hasChartDimens: Bool { - if _chartHeight > 0.0 && _chartWidth > 0.0 - { - return true - } - else - { - return false - } + return chartHeight > 0.0 + && chartWidth > 0.0 } @objc open func restrainViewPort(offsetLeft: CGFloat, offsetTop: CGFloat, offsetRight: CGFloat, offsetBottom: CGFloat) { - _contentRect.origin.x = offsetLeft - _contentRect.origin.y = offsetTop - _contentRect.size.width = _chartWidth - offsetLeft - offsetRight - _contentRect.size.height = _chartHeight - offsetBottom - offsetTop + contentRect.origin.x = offsetLeft + contentRect.origin.y = offsetTop + contentRect.size.width = chartWidth - offsetLeft - offsetRight + contentRect.size.height = chartHeight - offsetBottom - offsetTop } @objc open var offsetLeft: CGFloat { - return _contentRect.origin.x + return contentRect.origin.x } @objc open var offsetRight: CGFloat { - return _chartWidth - _contentRect.size.width - _contentRect.origin.x + return chartWidth - contentRect.size.width - contentRect.origin.x } @objc open var offsetTop: CGFloat { - return _contentRect.origin.y + return contentRect.origin.y } @objc open var offsetBottom: CGFloat { - return _chartHeight - _contentRect.size.height - _contentRect.origin.y + return chartHeight - contentRect.size.height - contentRect.origin.y } @objc open var contentTop: CGFloat { - return _contentRect.origin.y + return contentRect.origin.y } @objc open var contentLeft: CGFloat { - return _contentRect.origin.x + return contentRect.origin.x } @objc open var contentRight: CGFloat { - return _contentRect.origin.x + _contentRect.size.width + return contentRect.origin.x + contentRect.size.width } @objc open var contentBottom: CGFloat { - return _contentRect.origin.y + _contentRect.size.height + return contentRect.origin.y + contentRect.size.height } @objc open var contentWidth: CGFloat { - return _contentRect.size.width + return contentRect.size.width } @objc open var contentHeight: CGFloat { - return _contentRect.size.height - } - - @objc open var contentRect: CGRect - { - return _contentRect + return contentRect.size.height } - + @objc open var contentCenter: CGPoint { - return CGPoint(x: _contentRect.origin.x + _contentRect.size.width / 2.0, y: _contentRect.origin.y + _contentRect.size.height / 2.0) - } - - @objc open var chartHeight: CGFloat - { - return _chartHeight - } - - @objc open var chartWidth: CGFloat - { - return _chartWidth + return CGPoint(x: contentRect.origin.x + contentRect.size.width / 2.0, y: contentRect.origin.y + contentRect.size.height / 2.0) } // MARK: - Scaling/Panning etc. @@ -171,16 +150,15 @@ open class ViewPortHandler: NSObject /// Zooms by the specified zoom factors. @objc open func zoom(scaleX: CGFloat, scaleY: CGFloat) -> CGAffineTransform { - return _touchMatrix.scaledBy(x: scaleX, y: scaleY) + return touchMatrix.scaledBy(x: scaleX, y: scaleY) } /// Zooms around the specified center @objc open func zoom(scaleX: CGFloat, scaleY: CGFloat, x: CGFloat, y: CGFloat) -> CGAffineTransform { - var matrix = _touchMatrix.translatedBy(x: x, y: y) - matrix = matrix.scaledBy(x: scaleX, y: scaleY) - matrix = matrix.translatedBy(x: -x, y: -y) - return matrix + return touchMatrix.translatedBy(x: x, y: y) + .scaledBy(x: scaleX, y: scaleY) + .translatedBy(x: -x, y: -y) } /// Zooms in by 1.4, x and y are the coordinates (in pixels) of the zoom center. @@ -204,7 +182,7 @@ open class ViewPortHandler: NSObject /// Sets the scale factor to the specified values. @objc open func setZoom(scaleX: CGFloat, scaleY: CGFloat) -> CGAffineTransform { - var matrix = _touchMatrix + var matrix = touchMatrix matrix.a = scaleX matrix.d = scaleY return matrix @@ -213,22 +191,22 @@ open class ViewPortHandler: NSObject /// Sets the scale factor to the specified values. x and y is pivot. @objc open func setZoom(scaleX: CGFloat, scaleY: CGFloat, x: CGFloat, y: CGFloat) -> CGAffineTransform { - var matrix = _touchMatrix + var matrix = touchMatrix matrix.a = 1.0 matrix.d = 1.0 matrix = matrix.translatedBy(x: x, y: y) - matrix = matrix.scaledBy(x: scaleX, y: scaleY) - matrix = matrix.translatedBy(x: -x, y: -y) + .scaledBy(x: scaleX, y: scaleY) + .translatedBy(x: -x, y: -y) return matrix } /// Resets all zooming and dragging and makes the chart fit exactly it's bounds. @objc open func fitScreen() -> CGAffineTransform { - _minScaleX = 1.0 - _minScaleY = 1.0 + minScaleX = 1.0 + minScaleY = 1.0 - return CGAffineTransform.identity + return .identity } /// Translates to the specified point. @@ -237,7 +215,7 @@ open class ViewPortHandler: NSObject let translateX = pt.x - offsetLeft let translateY = pt.y - offsetTop - let matrix = _touchMatrix.concatenating(CGAffineTransform(translationX: -translateX, y: -translateY)) + let matrix = touchMatrix.concatenating(CGAffineTransform(translationX: -translateX, y: -translateY)) return matrix } @@ -250,160 +228,91 @@ open class ViewPortHandler: NSObject let translateX = pt.x - offsetLeft let translateY = pt.y - offsetTop - let matrix = _touchMatrix.concatenating(CGAffineTransform(translationX: -translateX, y: -translateY)) + let matrix = touchMatrix.concatenating(CGAffineTransform(translationX: -translateX, y: -translateY)) refresh(newMatrix: matrix, chart: chart, invalidate: true) } /// call this method to refresh the graph with a given matrix @objc @discardableResult open func refresh(newMatrix: CGAffineTransform, chart: ChartViewBase, invalidate: Bool) -> CGAffineTransform { - _touchMatrix = newMatrix + touchMatrix = newMatrix // make sure scale and translation are within their bounds - limitTransAndScale(matrix: &_touchMatrix, content: _contentRect) + limitTransAndScale(matrix: &touchMatrix, content: contentRect) chart.setNeedsDisplay() - return _touchMatrix + return touchMatrix } /// limits the maximum scale and X translation of the given matrix - private func limitTransAndScale(matrix: inout CGAffineTransform, content: CGRect?) + private func limitTransAndScale(matrix: inout CGAffineTransform, content: CGRect) { // min scale-x is 1 - _scaleX = min(max(_minScaleX, matrix.a), _maxScaleX) + scaleX = min(max(minScaleX, matrix.a), maxScaleX) // min scale-y is 1 - _scaleY = min(max(_minScaleY, matrix.d), _maxScaleY) - - - var width: CGFloat = 0.0 - var height: CGFloat = 0.0 + scaleY = min(max(minScaleY, matrix.d), maxScaleY) - if content != nil - { - width = content!.width - height = content!.height - } - - let maxTransX = -width * (_scaleX - 1.0) - _transX = min(max(matrix.tx, maxTransX - _transOffsetX), _transOffsetX) + let width = content.width + let height = content.height + + let maxTransX = -width * (scaleX - 1.0) + transX = min(max(matrix.tx, maxTransX - transOffsetX), transOffsetX) - let maxTransY = height * (_scaleY - 1.0) - _transY = max(min(matrix.ty, maxTransY + _transOffsetY), -_transOffsetY) + let maxTransY = height * (scaleY - 1.0) + transY = max(min(matrix.ty, maxTransY + transOffsetY), -transOffsetY) - matrix.tx = _transX - matrix.a = _scaleX - matrix.ty = _transY - matrix.d = _scaleY + matrix.tx = transX + matrix.a = scaleX + matrix.ty = transY + matrix.d = scaleY } /// Sets the minimum scale factor for the x-axis @objc open func setMinimumScaleX(_ xScale: CGFloat) { - var newValue = xScale - - if newValue < 1.0 - { - newValue = 1.0 - } - - _minScaleX = newValue - - limitTransAndScale(matrix: &_touchMatrix, content: _contentRect) + minScaleX = max(xScale, 1) + limitTransAndScale(matrix: &touchMatrix, content: contentRect) } /// Sets the maximum scale factor for the x-axis @objc open func setMaximumScaleX(_ xScale: CGFloat) { - var newValue = xScale - - if newValue == 0.0 - { - newValue = CGFloat.greatestFiniteMagnitude - } - - _maxScaleX = newValue - - limitTransAndScale(matrix: &_touchMatrix, content: _contentRect) + maxScaleX = xScale == 0 ? .greatestFiniteMagnitude : xScale + limitTransAndScale(matrix: &touchMatrix, content: contentRect) } /// Sets the minimum and maximum scale factors for the x-axis @objc open func setMinMaxScaleX(minScaleX: CGFloat, maxScaleX: CGFloat) { - var newMin = minScaleX - var newMax = maxScaleX - - if newMin < 1.0 - { - newMin = 1.0 - } - if newMax == 0.0 - { - newMax = CGFloat.greatestFiniteMagnitude - } - - _minScaleX = newMin - _maxScaleX = maxScaleX - - limitTransAndScale(matrix: &_touchMatrix, content: _contentRect) + self.minScaleX = max(minScaleX, 1) + self.maxScaleX = maxScaleX == 0 ? .greatestFiniteMagnitude : maxScaleX + limitTransAndScale(matrix: &touchMatrix, content: contentRect) } /// Sets the minimum scale factor for the y-axis @objc open func setMinimumScaleY(_ yScale: CGFloat) { - var newValue = yScale - - if newValue < 1.0 - { - newValue = 1.0 - } - - _minScaleY = newValue - - limitTransAndScale(matrix: &_touchMatrix, content: _contentRect) + minScaleY = max(yScale, 1) + limitTransAndScale(matrix: &touchMatrix, content: contentRect) } /// Sets the maximum scale factor for the y-axis @objc open func setMaximumScaleY(_ yScale: CGFloat) { - var newValue = yScale - - if newValue == 0.0 - { - newValue = CGFloat.greatestFiniteMagnitude - } - - _maxScaleY = newValue - - limitTransAndScale(matrix: &_touchMatrix, content: _contentRect) + maxScaleY = yScale == 0 ? .greatestFiniteMagnitude : yScale + limitTransAndScale(matrix: &touchMatrix, content: contentRect) } @objc open func setMinMaxScaleY(minScaleY: CGFloat, maxScaleY: CGFloat) { - var minScaleY = minScaleY, maxScaleY = maxScaleY - - if minScaleY < 1.0 - { - minScaleY = 1.0 - } - - if maxScaleY == 0.0 - { - maxScaleY = CGFloat.greatestFiniteMagnitude - } - - _minScaleY = minScaleY - _maxScaleY = maxScaleY - - limitTransAndScale(matrix: &_touchMatrix, content: _contentRect) - } - @objc open var touchMatrix: CGAffineTransform - { - return _touchMatrix + self.minScaleY = max(minScaleY, 1) + self.maxScaleY = maxScaleY == 0 ? .greatestFiniteMagnitude : maxScaleY + limitTransAndScale(matrix: &touchMatrix, content: contentRect) } - + // MARK: - Boundaries Check @objc open func isInBoundsX(_ x: CGFloat) -> Bool @@ -434,24 +343,24 @@ open class ViewPortHandler: NSObject @objc open func isInBoundsLeft(_ x: CGFloat) -> Bool { - return _contentRect.origin.x <= x + 1.0 + return contentRect.origin.x <= x + 1.0 } @objc open func isInBoundsRight(_ x: CGFloat) -> Bool { let x = floor(x * 100.0) / 100.0 - return (_contentRect.origin.x + _contentRect.size.width) >= x - 1.0 + return (contentRect.origin.x + contentRect.size.width) >= x - 1.0 } @objc open func isInBoundsTop(_ y: CGFloat) -> Bool { - return _contentRect.origin.y <= y + return contentRect.origin.y <= y } @objc open func isInBoundsBottom(_ y: CGFloat) -> Bool { let normalizedY = floor(y * 100.0) / 100.0 - return (_contentRect.origin.y + _contentRect.size.height) >= normalizedY + return (contentRect.origin.y + contentRect.size.height) >= normalizedY } /** @@ -500,54 +409,6 @@ open class ViewPortHandler: NSObject return false } - /// The current x-scale factor - @objc open var scaleX: CGFloat - { - return _scaleX - } - - /// The current y-scale factor - @objc open var scaleY: CGFloat - { - return _scaleY - } - - /// The minimum x-scale factor - @objc open var minScaleX: CGFloat - { - return _minScaleX - } - - /// The minimum y-scale factor - @objc open var minScaleY: CGFloat - { - return _minScaleY - } - - /// The minimum x-scale factor - @objc open var maxScaleX: CGFloat - { - return _maxScaleX - } - - /// The minimum y-scale factor - @objc open var maxScaleY: CGFloat - { - return _maxScaleY - } - - /// The translation (drag / pan) distance on the x-axis - @objc open var transX: CGFloat - { - return _transX - } - - /// The translation (drag / pan) distance on the y-axis - @objc open var transY: CGFloat - { - return _transY - } - /// if the chart is fully zoomed out, return true @objc open var isFullyZoomedOut: Bool { @@ -557,54 +418,54 @@ open class ViewPortHandler: NSObject /// `true` if the chart is fully zoomed out on it's y-axis (vertical). @objc open var isFullyZoomedOutY: Bool { - return !(_scaleY > _minScaleY || _minScaleY > 1.0) + return !(scaleY > minScaleY || minScaleY > 1.0) } /// `true` if the chart is fully zoomed out on it's x-axis (horizontal). @objc open var isFullyZoomedOutX: Bool { - return !(_scaleX > _minScaleX || _minScaleX > 1.0) + return !(scaleX > minScaleX || minScaleX > 1.0) } /// Set an offset in pixels that allows the user to drag the chart over it's bounds on the x-axis. @objc open func setDragOffsetX(_ offset: CGFloat) { - _transOffsetX = offset + transOffsetX = offset } /// Set an offset in pixels that allows the user to drag the chart over it's bounds on the y-axis. @objc open func setDragOffsetY(_ offset: CGFloat) { - _transOffsetY = offset + transOffsetY = offset } /// `true` if both drag offsets (x and y) are zero or smaller. @objc open var hasNoDragOffset: Bool { - return _transOffsetX <= 0.0 && _transOffsetY <= 0.0 + return transOffsetX <= 0.0 && transOffsetY <= 0.0 } /// `true` if the chart is not yet fully zoomed out on the x-axis @objc open var canZoomOutMoreX: Bool { - return _scaleX > _minScaleX + return scaleX > minScaleX } /// `true` if the chart is not yet fully zoomed in on the x-axis @objc open var canZoomInMoreX: Bool { - return _scaleX < _maxScaleX + return scaleX < maxScaleX } /// `true` if the chart is not yet fully zoomed out on the y-axis @objc open var canZoomOutMoreY: Bool { - return _scaleY > _minScaleY + return scaleY > minScaleY } /// `true` if the chart is not yet fully zoomed in on the y-axis @objc open var canZoomInMoreY: Bool { - return _scaleY < _maxScaleY + return scaleY < maxScaleY } } diff --git a/ChartDataTests.swift b/Tests/Charts/ChartDataTests.swift similarity index 73% rename from ChartDataTests.swift rename to Tests/Charts/ChartDataTests.swift index 4e4cdbab..8dd52adf 100644 --- a/ChartDataTests.swift +++ b/Tests/Charts/ChartDataTests.swift @@ -45,25 +45,25 @@ class ChartDataTests: XCTestCase { } func testGetDataSetByLabelCaseSensitive() { - XCTAssertTrue(data.getDataSetByLabel(SetLabels.one, ignorecase: false)?.label == SetLabels.one) - XCTAssertTrue(data.getDataSetByLabel(SetLabels.two, ignorecase: false)?.label == SetLabels.two) - XCTAssertTrue(data.getDataSetByLabel(SetLabels.three, ignorecase: false)?.label == SetLabels.three) - XCTAssertTrue(data.getDataSetByLabel(SetLabels.one.uppercased(), ignorecase: false) == nil) + XCTAssertTrue(data.dataSet(forLabel: SetLabels.one, ignorecase: false)?.label == SetLabels.one) + XCTAssertTrue(data.dataSet(forLabel: SetLabels.two, ignorecase: false)?.label == SetLabels.two) + XCTAssertTrue(data.dataSet(forLabel: SetLabels.three, ignorecase: false)?.label == SetLabels.three) + XCTAssertTrue(data.dataSet(forLabel: SetLabels.one.uppercased(), ignorecase: false) == nil) } func testGetDataSetByLabelIgnoreCase() { - XCTAssertTrue(data.getDataSetByLabel(SetLabels.one, ignorecase: true)?.label == SetLabels.one) - XCTAssertTrue(data.getDataSetByLabel(SetLabels.two, ignorecase: true)?.label == SetLabels.two) - XCTAssertTrue(data.getDataSetByLabel(SetLabels.three, ignorecase: true)?.label == SetLabels.three) + XCTAssertTrue(data.dataSet(forLabel: SetLabels.one, ignorecase: true)?.label == SetLabels.one) + XCTAssertTrue(data.dataSet(forLabel: SetLabels.two, ignorecase: true)?.label == SetLabels.two) + XCTAssertTrue(data.dataSet(forLabel: SetLabels.three, ignorecase: true)?.label == SetLabels.three) - XCTAssertTrue(data.getDataSetByLabel(SetLabels.one.uppercased(), ignorecase: true)?.label == SetLabels.one) - XCTAssertTrue(data.getDataSetByLabel(SetLabels.two.uppercased(), ignorecase: true)?.label == SetLabels.two) - XCTAssertTrue(data.getDataSetByLabel(SetLabels.three.uppercased(), ignorecase: true)?.label == SetLabels.three) + XCTAssertTrue(data.dataSet(forLabel: SetLabels.one.uppercased(), ignorecase: true)?.label == SetLabels.one) + XCTAssertTrue(data.dataSet(forLabel: SetLabels.two.uppercased(), ignorecase: true)?.label == SetLabels.two) + XCTAssertTrue(data.dataSet(forLabel: SetLabels.three.uppercased(), ignorecase: true)?.label == SetLabels.three) } func testGetDataSetByLabelNilWithBadLabel() { - XCTAssertTrue(data.getDataSetByLabel(SetLabels.badLabel, ignorecase: true) == nil) - XCTAssertTrue(data.getDataSetByLabel(SetLabels.badLabel, ignorecase: false) == nil) + XCTAssertTrue(data.dataSet(forLabel: SetLabels.badLabel, ignorecase: true) == nil) + XCTAssertTrue(data.dataSet(forLabel: SetLabels.badLabel, ignorecase: false) == nil) } } diff --git a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testDefaultBarDataSetLabels_iOS_375_0_667_0@2x.png b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testDefaultBarDataSetLabels_iOS_375_0_667_0@2x.png index ed12b4a0..4eb66576 100644 Binary files a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testDefaultBarDataSetLabels_iOS_375_0_667_0@2x.png and b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testDefaultBarDataSetLabels_iOS_375_0_667_0@2x.png differ diff --git a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testDefaultBarDataSetLabels_tvOS_1920_0_1080_0@1x.png b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testDefaultBarDataSetLabels_tvOS_1920_0_1080_0@1x.png index 774b80ba..66d68f16 100644 Binary files a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testDefaultBarDataSetLabels_tvOS_1920_0_1080_0@1x.png and b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testDefaultBarDataSetLabels_tvOS_1920_0_1080_0@1x.png differ diff --git a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testDefaultValues_iOS_375_0_667_0@2x.png b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testDefaultValues_iOS_375_0_667_0@2x.png index f37161c2..09049799 100644 Binary files a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testDefaultValues_iOS_375_0_667_0@2x.png and b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testDefaultValues_iOS_375_0_667_0@2x.png differ diff --git a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testDefaultValues_tvOS_1920_0_1080_0@1x.png b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testDefaultValues_tvOS_1920_0_1080_0@1x.png index 0c3753bc..a25c78a7 100644 Binary files a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testDefaultValues_tvOS_1920_0_1080_0@1x.png and b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testDefaultValues_tvOS_1920_0_1080_0@1x.png differ diff --git a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testDrawIcons_iOS_375_0_667_0@2x.png b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testDrawIcons_iOS_375_0_667_0@2x.png index fa118f9d..c4f9641f 100644 Binary files a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testDrawIcons_iOS_375_0_667_0@2x.png and b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testDrawIcons_iOS_375_0_667_0@2x.png differ diff --git a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testDrawIcons_tvOS_1920_0_1080_0@1x.png b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testDrawIcons_tvOS_1920_0_1080_0@1x.png index d436812f..50651a5e 100644 Binary files a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testDrawIcons_tvOS_1920_0_1080_0@1x.png and b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testDrawIcons_tvOS_1920_0_1080_0@1x.png differ diff --git a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testHideHorizontalGridlines_iOS_375_0_667_0@2x.png b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testHideHorizontalGridlines_iOS_375_0_667_0@2x.png index 3286ae73..7cd2816c 100644 Binary files a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testHideHorizontalGridlines_iOS_375_0_667_0@2x.png and b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testHideHorizontalGridlines_iOS_375_0_667_0@2x.png differ diff --git a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testHideHorizontalGridlines_tvOS_1920_0_1080_0@1x.png b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testHideHorizontalGridlines_tvOS_1920_0_1080_0@1x.png index 8f34ba92..7ffbb0a4 100644 Binary files a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testHideHorizontalGridlines_tvOS_1920_0_1080_0@1x.png and b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testHideHorizontalGridlines_tvOS_1920_0_1080_0@1x.png differ diff --git a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testHideLeftAxis_iOS_375_0_667_0@2x.png b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testHideLeftAxis_iOS_375_0_667_0@2x.png index 97624e57..eef3f98f 100644 Binary files a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testHideLeftAxis_iOS_375_0_667_0@2x.png and b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testHideLeftAxis_iOS_375_0_667_0@2x.png differ diff --git a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testHideLeftAxis_tvOS_1920_0_1080_0@1x.png b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testHideLeftAxis_tvOS_1920_0_1080_0@1x.png index 0cd63953..7e2bd24b 100644 Binary files a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testHideLeftAxis_tvOS_1920_0_1080_0@1x.png and b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testHideLeftAxis_tvOS_1920_0_1080_0@1x.png differ diff --git a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testHideRightAxis_iOS_375_0_667_0@2x.png b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testHideRightAxis_iOS_375_0_667_0@2x.png index 183f5d99..e19a58f5 100644 Binary files a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testHideRightAxis_iOS_375_0_667_0@2x.png and b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testHideRightAxis_iOS_375_0_667_0@2x.png differ diff --git a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testHideRightAxis_tvOS_1920_0_1080_0@1x.png b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testHideRightAxis_tvOS_1920_0_1080_0@1x.png index 6f1f26cc..8f35b05e 100644 Binary files a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testHideRightAxis_tvOS_1920_0_1080_0@1x.png and b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testHideRightAxis_tvOS_1920_0_1080_0@1x.png differ diff --git a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testHideVerticalGridlines_iOS_375_0_667_0@2x.png b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testHideVerticalGridlines_iOS_375_0_667_0@2x.png index aa9c31f8..2f74c65e 100644 Binary files a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testHideVerticalGridlines_iOS_375_0_667_0@2x.png and b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testHideVerticalGridlines_iOS_375_0_667_0@2x.png differ diff --git a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testHideVerticalGridlines_tvOS_1920_0_1080_0@1x.png b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testHideVerticalGridlines_tvOS_1920_0_1080_0@1x.png index 8bc1be8e..13b78df4 100644 Binary files a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testHideVerticalGridlines_tvOS_1920_0_1080_0@1x.png and b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testHideVerticalGridlines_tvOS_1920_0_1080_0@1x.png differ diff --git a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testHidesValues_iOS_375_0_667_0@2x.png b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testHidesValues_iOS_375_0_667_0@2x.png index e9edc193..925ebdd1 100644 Binary files a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testHidesValues_iOS_375_0_667_0@2x.png and b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testHidesValues_iOS_375_0_667_0@2x.png differ diff --git a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testHidesValues_tvOS_1920_0_1080_0@1x.png b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testHidesValues_tvOS_1920_0_1080_0@1x.png index 9ff97061..577eb404 100644 Binary files a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testHidesValues_tvOS_1920_0_1080_0@1x.png and b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testHidesValues_tvOS_1920_0_1080_0@1x.png differ diff --git a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testInvertedLeftAxisWithNegativeValues_iOS_375_0_667_0@2x.png b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testInvertedLeftAxisWithNegativeValues_iOS_375_0_667_0@2x.png index 164c2749..9af55f08 100644 Binary files a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testInvertedLeftAxisWithNegativeValues_iOS_375_0_667_0@2x.png and b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testInvertedLeftAxisWithNegativeValues_iOS_375_0_667_0@2x.png differ diff --git a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testInvertedLeftAxisWithNegativeValues_tvOS_1920_0_1080_0@1x.png b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testInvertedLeftAxisWithNegativeValues_tvOS_1920_0_1080_0@1x.png index ecd7f1f0..804d2af9 100644 Binary files a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testInvertedLeftAxisWithNegativeValues_tvOS_1920_0_1080_0@1x.png and b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testInvertedLeftAxisWithNegativeValues_tvOS_1920_0_1080_0@1x.png differ diff --git a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testInvertedLeftAxisWithPositiveValues_iOS_375_0_667_0@2x.png b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testInvertedLeftAxisWithPositiveValues_iOS_375_0_667_0@2x.png index d3a3cb6f..abd85b9a 100644 Binary files a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testInvertedLeftAxisWithPositiveValues_iOS_375_0_667_0@2x.png and b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testInvertedLeftAxisWithPositiveValues_iOS_375_0_667_0@2x.png differ diff --git a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testInvertedLeftAxisWithPositiveValues_tvOS_1920_0_1080_0@1x.png b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testInvertedLeftAxisWithPositiveValues_tvOS_1920_0_1080_0@1x.png index 3efd56ab..388ce2ef 100644 Binary files a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testInvertedLeftAxisWithPositiveValues_tvOS_1920_0_1080_0@1x.png and b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testInvertedLeftAxisWithPositiveValues_tvOS_1920_0_1080_0@1x.png differ diff --git a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testInvertedLeftAxis_iOS_375_0_667_0@2x.png b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testInvertedLeftAxis_iOS_375_0_667_0@2x.png index 90426d88..8852d3d0 100644 Binary files a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testInvertedLeftAxis_iOS_375_0_667_0@2x.png and b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testInvertedLeftAxis_iOS_375_0_667_0@2x.png differ diff --git a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testInvertedLeftAxis_tvOS_1920_0_1080_0@1x.png b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testInvertedLeftAxis_tvOS_1920_0_1080_0@1x.png index 88c52a1d..129230b2 100644 Binary files a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testInvertedLeftAxis_tvOS_1920_0_1080_0@1x.png and b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testInvertedLeftAxis_tvOS_1920_0_1080_0@1x.png differ diff --git a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testInvertedRightAxisWithNegativeValues_iOS_375_0_667_0@2x.png b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testInvertedRightAxisWithNegativeValues_iOS_375_0_667_0@2x.png index bdb9e2e3..0c1ad46a 100644 Binary files a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testInvertedRightAxisWithNegativeValues_iOS_375_0_667_0@2x.png and b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testInvertedRightAxisWithNegativeValues_iOS_375_0_667_0@2x.png differ diff --git a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testInvertedRightAxisWithNegativeValues_tvOS_1920_0_1080_0@1x.png b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testInvertedRightAxisWithNegativeValues_tvOS_1920_0_1080_0@1x.png index d0401758..01a7f130 100644 Binary files a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testInvertedRightAxisWithNegativeValues_tvOS_1920_0_1080_0@1x.png and b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testInvertedRightAxisWithNegativeValues_tvOS_1920_0_1080_0@1x.png differ diff --git a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testInvertedRightAxisWithPositiveValues_iOS_375_0_667_0@2x.png b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testInvertedRightAxisWithPositiveValues_iOS_375_0_667_0@2x.png index 71d44dd7..2220543b 100644 Binary files a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testInvertedRightAxisWithPositiveValues_iOS_375_0_667_0@2x.png and b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testInvertedRightAxisWithPositiveValues_iOS_375_0_667_0@2x.png differ diff --git a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testInvertedRightAxisWithPositiveValues_tvOS_1920_0_1080_0@1x.png b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testInvertedRightAxisWithPositiveValues_tvOS_1920_0_1080_0@1x.png index 88974cc0..9afbab3d 100644 Binary files a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testInvertedRightAxisWithPositiveValues_tvOS_1920_0_1080_0@1x.png and b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testInvertedRightAxisWithPositiveValues_tvOS_1920_0_1080_0@1x.png differ diff --git a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testInvertedRightAxis_iOS_375_0_667_0@2x.png b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testInvertedRightAxis_iOS_375_0_667_0@2x.png index 6df80b26..f2bbef88 100644 Binary files a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testInvertedRightAxis_iOS_375_0_667_0@2x.png and b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testInvertedRightAxis_iOS_375_0_667_0@2x.png differ diff --git a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testInvertedRightAxis_tvOS_1920_0_1080_0@1x.png b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testInvertedRightAxis_tvOS_1920_0_1080_0@1x.png index 23bf75fb..3cfb610b 100644 Binary files a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testInvertedRightAxis_tvOS_1920_0_1080_0@1x.png and b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testInvertedRightAxis_tvOS_1920_0_1080_0@1x.png differ diff --git a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testNegativeValuesWithCustomAxisMaximum2_iOS_375_0_667_0@2x.png b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testNegativeValuesWithCustomAxisMaximum2_iOS_375_0_667_0@2x.png index 6958d3ad..6017ba20 100644 Binary files a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testNegativeValuesWithCustomAxisMaximum2_iOS_375_0_667_0@2x.png and b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testNegativeValuesWithCustomAxisMaximum2_iOS_375_0_667_0@2x.png differ diff --git a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testNegativeValuesWithCustomAxisMaximum2_tvOS_1920_0_1080_0@1x.png b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testNegativeValuesWithCustomAxisMaximum2_tvOS_1920_0_1080_0@1x.png index 15b171c9..186383dd 100644 Binary files a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testNegativeValuesWithCustomAxisMaximum2_tvOS_1920_0_1080_0@1x.png and b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testNegativeValuesWithCustomAxisMaximum2_tvOS_1920_0_1080_0@1x.png differ diff --git a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testNegativeValuesWithCustomAxisMaximumAndCustomAxisMaximum_iOS_375_0_667_0@2x.png b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testNegativeValuesWithCustomAxisMaximumAndCustomAxisMaximum_iOS_375_0_667_0@2x.png index ebf463b7..3dfd3d58 100644 Binary files a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testNegativeValuesWithCustomAxisMaximumAndCustomAxisMaximum_iOS_375_0_667_0@2x.png and b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testNegativeValuesWithCustomAxisMaximumAndCustomAxisMaximum_iOS_375_0_667_0@2x.png differ diff --git a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testNegativeValuesWithCustomAxisMaximumAndCustomAxisMaximum_tvOS_1920_0_1080_0@1x.png b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testNegativeValuesWithCustomAxisMaximumAndCustomAxisMaximum_tvOS_1920_0_1080_0@1x.png index a7783dfc..99ccd484 100644 Binary files a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testNegativeValuesWithCustomAxisMaximumAndCustomAxisMaximum_tvOS_1920_0_1080_0@1x.png and b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testNegativeValuesWithCustomAxisMaximumAndCustomAxisMaximum_tvOS_1920_0_1080_0@1x.png differ diff --git a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testNegativeValuesWithCustomAxisMaximum_iOS_375_0_667_0@2x.png b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testNegativeValuesWithCustomAxisMaximum_iOS_375_0_667_0@2x.png index 5d537329..033f9596 100644 Binary files a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testNegativeValuesWithCustomAxisMaximum_iOS_375_0_667_0@2x.png and b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testNegativeValuesWithCustomAxisMaximum_iOS_375_0_667_0@2x.png differ diff --git a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testNegativeValuesWithCustomAxisMaximum_tvOS_1920_0_1080_0@1x.png b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testNegativeValuesWithCustomAxisMaximum_tvOS_1920_0_1080_0@1x.png index d3259c27..ce8fca78 100644 Binary files a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testNegativeValuesWithCustomAxisMaximum_tvOS_1920_0_1080_0@1x.png and b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testNegativeValuesWithCustomAxisMaximum_tvOS_1920_0_1080_0@1x.png differ diff --git a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testNegativeValuesWithCustomAxisMinimum2_iOS_375_0_667_0@2x.png b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testNegativeValuesWithCustomAxisMinimum2_iOS_375_0_667_0@2x.png index 678b86f6..5df868b0 100644 Binary files a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testNegativeValuesWithCustomAxisMinimum2_iOS_375_0_667_0@2x.png and b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testNegativeValuesWithCustomAxisMinimum2_iOS_375_0_667_0@2x.png differ diff --git a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testNegativeValuesWithCustomAxisMinimum2_tvOS_1920_0_1080_0@1x.png b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testNegativeValuesWithCustomAxisMinimum2_tvOS_1920_0_1080_0@1x.png index 22e3d668..14f15dfa 100644 Binary files a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testNegativeValuesWithCustomAxisMinimum2_tvOS_1920_0_1080_0@1x.png and b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testNegativeValuesWithCustomAxisMinimum2_tvOS_1920_0_1080_0@1x.png differ diff --git a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testNegativeValuesWithCustomAxisMinimum_iOS_375_0_667_0@2x.png b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testNegativeValuesWithCustomAxisMinimum_iOS_375_0_667_0@2x.png index f9c1a291..a8e384f1 100644 Binary files a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testNegativeValuesWithCustomAxisMinimum_iOS_375_0_667_0@2x.png and b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testNegativeValuesWithCustomAxisMinimum_iOS_375_0_667_0@2x.png differ diff --git a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testNegativeValuesWithCustomAxisMinimum_tvOS_1920_0_1080_0@1x.png b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testNegativeValuesWithCustomAxisMinimum_tvOS_1920_0_1080_0@1x.png index d58e9f0e..a6048cc7 100644 Binary files a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testNegativeValuesWithCustomAxisMinimum_tvOS_1920_0_1080_0@1x.png and b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testNegativeValuesWithCustomAxisMinimum_tvOS_1920_0_1080_0@1x.png differ diff --git a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testNegativeValues_iOS_375_0_667_0@2x.png b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testNegativeValues_iOS_375_0_667_0@2x.png index 263c6fdb..6f9a2cb6 100644 Binary files a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testNegativeValues_iOS_375_0_667_0@2x.png and b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testNegativeValues_iOS_375_0_667_0@2x.png differ diff --git a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testNegativeValues_tvOS_1920_0_1080_0@1x.png b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testNegativeValues_tvOS_1920_0_1080_0@1x.png index 8f8931a9..0652ecba 100644 Binary files a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testNegativeValues_tvOS_1920_0_1080_0@1x.png and b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testNegativeValues_tvOS_1920_0_1080_0@1x.png differ diff --git a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testNotDrawValueAboveBars_iOS_375_0_667_0@2x.png b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testNotDrawValueAboveBars_iOS_375_0_667_0@2x.png index 2cd95fcd..5e48c901 100644 Binary files a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testNotDrawValueAboveBars_iOS_375_0_667_0@2x.png and b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testNotDrawValueAboveBars_iOS_375_0_667_0@2x.png differ diff --git a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testNotDrawValueAboveBars_tvOS_1920_0_1080_0@1x.png b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testNotDrawValueAboveBars_tvOS_1920_0_1080_0@1x.png index f78d593a..4115765b 100644 Binary files a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testNotDrawValueAboveBars_tvOS_1920_0_1080_0@1x.png and b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testNotDrawValueAboveBars_tvOS_1920_0_1080_0@1x.png differ diff --git a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testPositiveValuesWithCustomAxisMaximum2_iOS_375_0_667_0@2x.png b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testPositiveValuesWithCustomAxisMaximum2_iOS_375_0_667_0@2x.png index 492ba243..eeae48f4 100644 Binary files a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testPositiveValuesWithCustomAxisMaximum2_iOS_375_0_667_0@2x.png and b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testPositiveValuesWithCustomAxisMaximum2_iOS_375_0_667_0@2x.png differ diff --git a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testPositiveValuesWithCustomAxisMaximum2_tvOS_1920_0_1080_0@1x.png b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testPositiveValuesWithCustomAxisMaximum2_tvOS_1920_0_1080_0@1x.png index 3a302b11..bace9c90 100644 Binary files a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testPositiveValuesWithCustomAxisMaximum2_tvOS_1920_0_1080_0@1x.png and b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testPositiveValuesWithCustomAxisMaximum2_tvOS_1920_0_1080_0@1x.png differ diff --git a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testPositiveValuesWithCustomAxisMaximumAndCustomAxisMaximum_iOS_375_0_667_0@2x.png b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testPositiveValuesWithCustomAxisMaximumAndCustomAxisMaximum_iOS_375_0_667_0@2x.png index bd999759..ca4ac877 100644 Binary files a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testPositiveValuesWithCustomAxisMaximumAndCustomAxisMaximum_iOS_375_0_667_0@2x.png and b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testPositiveValuesWithCustomAxisMaximumAndCustomAxisMaximum_iOS_375_0_667_0@2x.png differ diff --git a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testPositiveValuesWithCustomAxisMaximumAndCustomAxisMaximum_tvOS_1920_0_1080_0@1x.png b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testPositiveValuesWithCustomAxisMaximumAndCustomAxisMaximum_tvOS_1920_0_1080_0@1x.png index b21e7efb..90e93ac7 100644 Binary files a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testPositiveValuesWithCustomAxisMaximumAndCustomAxisMaximum_tvOS_1920_0_1080_0@1x.png and b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testPositiveValuesWithCustomAxisMaximumAndCustomAxisMaximum_tvOS_1920_0_1080_0@1x.png differ diff --git a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testPositiveValuesWithCustomAxisMaximum_iOS_375_0_667_0@2x.png b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testPositiveValuesWithCustomAxisMaximum_iOS_375_0_667_0@2x.png index 5e9eaa55..b7a865d7 100644 Binary files a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testPositiveValuesWithCustomAxisMaximum_iOS_375_0_667_0@2x.png and b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testPositiveValuesWithCustomAxisMaximum_iOS_375_0_667_0@2x.png differ diff --git a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testPositiveValuesWithCustomAxisMaximum_tvOS_1920_0_1080_0@1x.png b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testPositiveValuesWithCustomAxisMaximum_tvOS_1920_0_1080_0@1x.png index e50fd51a..5142c7b2 100644 Binary files a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testPositiveValuesWithCustomAxisMaximum_tvOS_1920_0_1080_0@1x.png and b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testPositiveValuesWithCustomAxisMaximum_tvOS_1920_0_1080_0@1x.png differ diff --git a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testPositiveValuesWithCustomAxisMinimum2_iOS_375_0_667_0@2x.png b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testPositiveValuesWithCustomAxisMinimum2_iOS_375_0_667_0@2x.png index d46682b1..271de6a3 100644 Binary files a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testPositiveValuesWithCustomAxisMinimum2_iOS_375_0_667_0@2x.png and b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testPositiveValuesWithCustomAxisMinimum2_iOS_375_0_667_0@2x.png differ diff --git a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testPositiveValuesWithCustomAxisMinimum2_tvOS_1920_0_1080_0@1x.png b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testPositiveValuesWithCustomAxisMinimum2_tvOS_1920_0_1080_0@1x.png index 3dbb3abe..fb5b1966 100644 Binary files a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testPositiveValuesWithCustomAxisMinimum2_tvOS_1920_0_1080_0@1x.png and b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testPositiveValuesWithCustomAxisMinimum2_tvOS_1920_0_1080_0@1x.png differ diff --git a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testPositiveValuesWithCustomAxisMinimum_iOS_375_0_667_0@2x.png b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testPositiveValuesWithCustomAxisMinimum_iOS_375_0_667_0@2x.png index 40597837..54c6fd0f 100644 Binary files a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testPositiveValuesWithCustomAxisMinimum_iOS_375_0_667_0@2x.png and b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testPositiveValuesWithCustomAxisMinimum_iOS_375_0_667_0@2x.png differ diff --git a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testPositiveValuesWithCustomAxisMinimum_tvOS_1920_0_1080_0@1x.png b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testPositiveValuesWithCustomAxisMinimum_tvOS_1920_0_1080_0@1x.png index fcd79d80..f6aee4ba 100644 Binary files a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testPositiveValuesWithCustomAxisMinimum_tvOS_1920_0_1080_0@1x.png and b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testPositiveValuesWithCustomAxisMinimum_tvOS_1920_0_1080_0@1x.png differ diff --git a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testPositiveValues_iOS_375_0_667_0@2x.png b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testPositiveValues_iOS_375_0_667_0@2x.png index 0a30c866..9de6c480 100644 Binary files a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testPositiveValues_iOS_375_0_667_0@2x.png and b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testPositiveValues_iOS_375_0_667_0@2x.png differ diff --git a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testPositiveValues_tvOS_1920_0_1080_0@1x.png b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testPositiveValues_tvOS_1920_0_1080_0@1x.png index a3b6d33c..1cb0569f 100644 Binary files a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testPositiveValues_tvOS_1920_0_1080_0@1x.png and b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testPositiveValues_tvOS_1920_0_1080_0@1x.png differ diff --git a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testStackedDrawValues_iOS_375_0_667_0@2x.png b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testStackedDrawValues_iOS_375_0_667_0@2x.png index 6af925dc..70cf6c01 100644 Binary files a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testStackedDrawValues_iOS_375_0_667_0@2x.png and b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testStackedDrawValues_iOS_375_0_667_0@2x.png differ diff --git a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testStackedDrawValues_tvOS_1920_0_1080_0@1x.png b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testStackedDrawValues_tvOS_1920_0_1080_0@1x.png index 26d05bd6..16251319 100644 Binary files a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testStackedDrawValues_tvOS_1920_0_1080_0@1x.png and b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testStackedDrawValues_tvOS_1920_0_1080_0@1x.png differ diff --git a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testStackedNotDrawValuesAboveBars_iOS_375_0_667_0@2x.png b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testStackedNotDrawValuesAboveBars_iOS_375_0_667_0@2x.png index e4bb0d9e..e5abe404 100644 Binary files a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testStackedNotDrawValuesAboveBars_iOS_375_0_667_0@2x.png and b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testStackedNotDrawValuesAboveBars_iOS_375_0_667_0@2x.png differ diff --git a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testStackedNotDrawValuesAboveBars_tvOS_1920_0_1080_0@1x.png b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testStackedNotDrawValuesAboveBars_tvOS_1920_0_1080_0@1x.png index 0de93883..21fdb790 100644 Binary files a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testStackedNotDrawValuesAboveBars_tvOS_1920_0_1080_0@1x.png and b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testStackedNotDrawValuesAboveBars_tvOS_1920_0_1080_0@1x.png differ diff --git a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testStackedNotDrawValues_iOS_375_0_667_0@2x.png b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testStackedNotDrawValues_iOS_375_0_667_0@2x.png index 9cc9abe5..9f324a70 100644 Binary files a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testStackedNotDrawValues_iOS_375_0_667_0@2x.png and b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testStackedNotDrawValues_iOS_375_0_667_0@2x.png differ diff --git a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testStackedNotDrawValues_tvOS_1920_0_1080_0@1x.png b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testStackedNotDrawValues_tvOS_1920_0_1080_0@1x.png index b54f6c43..4230e0f4 100644 Binary files a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testStackedNotDrawValues_tvOS_1920_0_1080_0@1x.png and b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testStackedNotDrawValues_tvOS_1920_0_1080_0@1x.png differ diff --git a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testZeroValues_iOS_375_0_667_0@2x.png b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testZeroValues_iOS_375_0_667_0@2x.png index 02675974..6e1b5112 100644 Binary files a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testZeroValues_iOS_375_0_667_0@2x.png and b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testZeroValues_iOS_375_0_667_0@2x.png differ diff --git a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testZeroValues_tvOS_1920_0_1080_0@1x.png b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testZeroValues_tvOS_1920_0_1080_0@1x.png index 9e29303e..d231219f 100644 Binary files a/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testZeroValues_tvOS_1920_0_1080_0@1x.png and b/Tests/ReferenceImages_64/ChartsTests.BarChartTests/testZeroValues_tvOS_1920_0_1080_0@1x.png differ diff --git a/Tests/ReferenceImages_64/ChartsTests.CombinedChartTests/testAllRightAxisDependency_iOS_375_0_667_0@2x.png b/Tests/ReferenceImages_64/ChartsTests.CombinedChartTests/testAllRightAxisDependency_iOS_375_0_667_0@2x.png index de7f99f3..12d273d9 100644 Binary files a/Tests/ReferenceImages_64/ChartsTests.CombinedChartTests/testAllRightAxisDependency_iOS_375_0_667_0@2x.png and b/Tests/ReferenceImages_64/ChartsTests.CombinedChartTests/testAllRightAxisDependency_iOS_375_0_667_0@2x.png differ diff --git a/Tests/ReferenceImages_64/ChartsTests.CombinedChartTests/testAllRightAxisDependency_tvOS_1920_0_1080_0@1x.png b/Tests/ReferenceImages_64/ChartsTests.CombinedChartTests/testAllRightAxisDependency_tvOS_1920_0_1080_0@1x.png index 706f6598..aa6c1cfe 100644 Binary files a/Tests/ReferenceImages_64/ChartsTests.CombinedChartTests/testAllRightAxisDependency_tvOS_1920_0_1080_0@1x.png and b/Tests/ReferenceImages_64/ChartsTests.CombinedChartTests/testAllRightAxisDependency_tvOS_1920_0_1080_0@1x.png differ diff --git a/Tests/ReferenceImages_64/ChartsTests.CombinedChartTests/testDefaultAxisDependency_iOS_375_0_667_0@2x.png b/Tests/ReferenceImages_64/ChartsTests.CombinedChartTests/testDefaultAxisDependency_iOS_375_0_667_0@2x.png index de7f99f3..12d273d9 100644 Binary files a/Tests/ReferenceImages_64/ChartsTests.CombinedChartTests/testDefaultAxisDependency_iOS_375_0_667_0@2x.png and b/Tests/ReferenceImages_64/ChartsTests.CombinedChartTests/testDefaultAxisDependency_iOS_375_0_667_0@2x.png differ diff --git a/Tests/ReferenceImages_64/ChartsTests.CombinedChartTests/testDefaultAxisDependency_tvOS_1920_0_1080_0@1x.png b/Tests/ReferenceImages_64/ChartsTests.CombinedChartTests/testDefaultAxisDependency_tvOS_1920_0_1080_0@1x.png index 706f6598..aa6c1cfe 100644 Binary files a/Tests/ReferenceImages_64/ChartsTests.CombinedChartTests/testDefaultAxisDependency_tvOS_1920_0_1080_0@1x.png and b/Tests/ReferenceImages_64/ChartsTests.CombinedChartTests/testDefaultAxisDependency_tvOS_1920_0_1080_0@1x.png differ diff --git a/Tests/ReferenceImages_64/ChartsTests.CombinedChartTests/testLeftRightAxisDependency_iOS_375_0_667_0@2x.png b/Tests/ReferenceImages_64/ChartsTests.CombinedChartTests/testLeftRightAxisDependency_iOS_375_0_667_0@2x.png index 96371966..4d5fc540 100644 Binary files a/Tests/ReferenceImages_64/ChartsTests.CombinedChartTests/testLeftRightAxisDependency_iOS_375_0_667_0@2x.png and b/Tests/ReferenceImages_64/ChartsTests.CombinedChartTests/testLeftRightAxisDependency_iOS_375_0_667_0@2x.png differ diff --git a/Tests/ReferenceImages_64/ChartsTests.CombinedChartTests/testLeftRightAxisDependency_tvOS_1920_0_1080_0@1x.png b/Tests/ReferenceImages_64/ChartsTests.CombinedChartTests/testLeftRightAxisDependency_tvOS_1920_0_1080_0@1x.png index 4a9d5f68..00b5ce60 100644 Binary files a/Tests/ReferenceImages_64/ChartsTests.CombinedChartTests/testLeftRightAxisDependency_tvOS_1920_0_1080_0@1x.png and b/Tests/ReferenceImages_64/ChartsTests.CombinedChartTests/testLeftRightAxisDependency_tvOS_1920_0_1080_0@1x.png differ diff --git a/Tests/ReferenceImages_64/ChartsTests.HorizontalBarChartTests/testDefaultValues_iOS_375_0_667_0@2x.png b/Tests/ReferenceImages_64/ChartsTests.HorizontalBarChartTests/testDefaultValues_iOS_375_0_667_0@2x.png index 67bae60f..bd7d26f4 100644 Binary files a/Tests/ReferenceImages_64/ChartsTests.HorizontalBarChartTests/testDefaultValues_iOS_375_0_667_0@2x.png and b/Tests/ReferenceImages_64/ChartsTests.HorizontalBarChartTests/testDefaultValues_iOS_375_0_667_0@2x.png differ diff --git a/Tests/ReferenceImages_64/ChartsTests.HorizontalBarChartTests/testDefaultValues_tvOS_1920_0_1080_0@1x.png b/Tests/ReferenceImages_64/ChartsTests.HorizontalBarChartTests/testDefaultValues_tvOS_1920_0_1080_0@1x.png index cfa81c6b..4bb60795 100644 Binary files a/Tests/ReferenceImages_64/ChartsTests.HorizontalBarChartTests/testDefaultValues_tvOS_1920_0_1080_0@1x.png and b/Tests/ReferenceImages_64/ChartsTests.HorizontalBarChartTests/testDefaultValues_tvOS_1920_0_1080_0@1x.png differ diff --git a/Tests/ReferenceImages_64/ChartsTests.HorizontalBarChartTests/testHidesValues_iOS_375_0_667_0@2x.png b/Tests/ReferenceImages_64/ChartsTests.HorizontalBarChartTests/testHidesValues_iOS_375_0_667_0@2x.png index 90e0e892..93dcf9ba 100644 Binary files a/Tests/ReferenceImages_64/ChartsTests.HorizontalBarChartTests/testHidesValues_iOS_375_0_667_0@2x.png and b/Tests/ReferenceImages_64/ChartsTests.HorizontalBarChartTests/testHidesValues_iOS_375_0_667_0@2x.png differ diff --git a/Tests/ReferenceImages_64/ChartsTests.HorizontalBarChartTests/testHidesValues_tvOS_1920_0_1080_0@1x.png b/Tests/ReferenceImages_64/ChartsTests.HorizontalBarChartTests/testHidesValues_tvOS_1920_0_1080_0@1x.png index 370e141b..33d956d5 100644 Binary files a/Tests/ReferenceImages_64/ChartsTests.HorizontalBarChartTests/testHidesValues_tvOS_1920_0_1080_0@1x.png and b/Tests/ReferenceImages_64/ChartsTests.HorizontalBarChartTests/testHidesValues_tvOS_1920_0_1080_0@1x.png differ diff --git a/Tests/ReferenceImages_64/ChartsTests.HorizontalBarChartTests/testNotDrawValueAboveBars_iOS_375_0_667_0@2x.png b/Tests/ReferenceImages_64/ChartsTests.HorizontalBarChartTests/testNotDrawValueAboveBars_iOS_375_0_667_0@2x.png index 66fbc7f4..56b7ff30 100644 Binary files a/Tests/ReferenceImages_64/ChartsTests.HorizontalBarChartTests/testNotDrawValueAboveBars_iOS_375_0_667_0@2x.png and b/Tests/ReferenceImages_64/ChartsTests.HorizontalBarChartTests/testNotDrawValueAboveBars_iOS_375_0_667_0@2x.png differ diff --git a/Tests/ReferenceImages_64/ChartsTests.HorizontalBarChartTests/testNotDrawValueAboveBars_tvOS_1920_0_1080_0@1x.png b/Tests/ReferenceImages_64/ChartsTests.HorizontalBarChartTests/testNotDrawValueAboveBars_tvOS_1920_0_1080_0@1x.png index 2b8e7ef5..580f831c 100644 Binary files a/Tests/ReferenceImages_64/ChartsTests.HorizontalBarChartTests/testNotDrawValueAboveBars_tvOS_1920_0_1080_0@1x.png and b/Tests/ReferenceImages_64/ChartsTests.HorizontalBarChartTests/testNotDrawValueAboveBars_tvOS_1920_0_1080_0@1x.png differ diff --git a/Tests/ReferenceImages_64/ChartsTests.HorizontalBarChartTests/testStackedDrawValues_iOS_375_0_667_0@2x.png b/Tests/ReferenceImages_64/ChartsTests.HorizontalBarChartTests/testStackedDrawValues_iOS_375_0_667_0@2x.png index 60c8c2e3..cc59dbea 100644 Binary files a/Tests/ReferenceImages_64/ChartsTests.HorizontalBarChartTests/testStackedDrawValues_iOS_375_0_667_0@2x.png and b/Tests/ReferenceImages_64/ChartsTests.HorizontalBarChartTests/testStackedDrawValues_iOS_375_0_667_0@2x.png differ diff --git a/Tests/ReferenceImages_64/ChartsTests.HorizontalBarChartTests/testStackedDrawValues_tvOS_1920_0_1080_0@1x.png b/Tests/ReferenceImages_64/ChartsTests.HorizontalBarChartTests/testStackedDrawValues_tvOS_1920_0_1080_0@1x.png index e04192c0..26f3b010 100644 Binary files a/Tests/ReferenceImages_64/ChartsTests.HorizontalBarChartTests/testStackedDrawValues_tvOS_1920_0_1080_0@1x.png and b/Tests/ReferenceImages_64/ChartsTests.HorizontalBarChartTests/testStackedDrawValues_tvOS_1920_0_1080_0@1x.png differ diff --git a/Tests/ReferenceImages_64/ChartsTests.HorizontalBarChartTests/testStackedNotDrawValuesAboveBars_iOS_375_0_667_0@2x.png b/Tests/ReferenceImages_64/ChartsTests.HorizontalBarChartTests/testStackedNotDrawValuesAboveBars_iOS_375_0_667_0@2x.png index 697cfae5..3a1cffca 100644 Binary files a/Tests/ReferenceImages_64/ChartsTests.HorizontalBarChartTests/testStackedNotDrawValuesAboveBars_iOS_375_0_667_0@2x.png and b/Tests/ReferenceImages_64/ChartsTests.HorizontalBarChartTests/testStackedNotDrawValuesAboveBars_iOS_375_0_667_0@2x.png differ diff --git a/Tests/ReferenceImages_64/ChartsTests.HorizontalBarChartTests/testStackedNotDrawValuesAboveBars_tvOS_1920_0_1080_0@1x.png b/Tests/ReferenceImages_64/ChartsTests.HorizontalBarChartTests/testStackedNotDrawValuesAboveBars_tvOS_1920_0_1080_0@1x.png index e6a04a81..e52bc1fe 100644 Binary files a/Tests/ReferenceImages_64/ChartsTests.HorizontalBarChartTests/testStackedNotDrawValuesAboveBars_tvOS_1920_0_1080_0@1x.png and b/Tests/ReferenceImages_64/ChartsTests.HorizontalBarChartTests/testStackedNotDrawValuesAboveBars_tvOS_1920_0_1080_0@1x.png differ diff --git a/Tests/ReferenceImages_64/ChartsTests.HorizontalBarChartTests/testStackedNotDrawValues_iOS_375_0_667_0@2x.png b/Tests/ReferenceImages_64/ChartsTests.HorizontalBarChartTests/testStackedNotDrawValues_iOS_375_0_667_0@2x.png index 08b18724..c2149253 100644 Binary files a/Tests/ReferenceImages_64/ChartsTests.HorizontalBarChartTests/testStackedNotDrawValues_iOS_375_0_667_0@2x.png and b/Tests/ReferenceImages_64/ChartsTests.HorizontalBarChartTests/testStackedNotDrawValues_iOS_375_0_667_0@2x.png differ diff --git a/Tests/ReferenceImages_64/ChartsTests.HorizontalBarChartTests/testStackedNotDrawValues_tvOS_1920_0_1080_0@1x.png b/Tests/ReferenceImages_64/ChartsTests.HorizontalBarChartTests/testStackedNotDrawValues_tvOS_1920_0_1080_0@1x.png index 29696003..24fa1407 100644 Binary files a/Tests/ReferenceImages_64/ChartsTests.HorizontalBarChartTests/testStackedNotDrawValues_tvOS_1920_0_1080_0@1x.png and b/Tests/ReferenceImages_64/ChartsTests.HorizontalBarChartTests/testStackedNotDrawValues_tvOS_1920_0_1080_0@1x.png differ diff --git a/Tests/ReferenceImages_64/ChartsTests.LineChartTests/testDefaultValues_iOS_375_0_667_0@2x.png b/Tests/ReferenceImages_64/ChartsTests.LineChartTests/testDefaultValues_iOS_375_0_667_0@2x.png index 0bcfa84a..c87af731 100644 Binary files a/Tests/ReferenceImages_64/ChartsTests.LineChartTests/testDefaultValues_iOS_375_0_667_0@2x.png and b/Tests/ReferenceImages_64/ChartsTests.LineChartTests/testDefaultValues_iOS_375_0_667_0@2x.png differ diff --git a/Tests/ReferenceImages_64/ChartsTests.LineChartTests/testDefaultValues_tvOS_1920_0_1080_0@1x.png b/Tests/ReferenceImages_64/ChartsTests.LineChartTests/testDefaultValues_tvOS_1920_0_1080_0@1x.png index 94c78ed3..7a8a35b4 100644 Binary files a/Tests/ReferenceImages_64/ChartsTests.LineChartTests/testDefaultValues_tvOS_1920_0_1080_0@1x.png and b/Tests/ReferenceImages_64/ChartsTests.LineChartTests/testDefaultValues_tvOS_1920_0_1080_0@1x.png differ diff --git a/Tests/ReferenceImages_64/ChartsTests.LineChartTests/testDoesntDrawCircleHole_iOS_375_0_667_0@2x.png b/Tests/ReferenceImages_64/ChartsTests.LineChartTests/testDoesntDrawCircleHole_iOS_375_0_667_0@2x.png index ed42d174..a8d0c356 100644 Binary files a/Tests/ReferenceImages_64/ChartsTests.LineChartTests/testDoesntDrawCircleHole_iOS_375_0_667_0@2x.png and b/Tests/ReferenceImages_64/ChartsTests.LineChartTests/testDoesntDrawCircleHole_iOS_375_0_667_0@2x.png differ diff --git a/Tests/ReferenceImages_64/ChartsTests.LineChartTests/testDoesntDrawCircleHole_tvOS_1920_0_1080_0@1x.png b/Tests/ReferenceImages_64/ChartsTests.LineChartTests/testDoesntDrawCircleHole_tvOS_1920_0_1080_0@1x.png index 8f51194b..afd4faf1 100644 Binary files a/Tests/ReferenceImages_64/ChartsTests.LineChartTests/testDoesntDrawCircleHole_tvOS_1920_0_1080_0@1x.png and b/Tests/ReferenceImages_64/ChartsTests.LineChartTests/testDoesntDrawCircleHole_tvOS_1920_0_1080_0@1x.png differ diff --git a/Tests/ReferenceImages_64/ChartsTests.LineChartTests/testDoesntDrawCircles_iOS_375_0_667_0@2x.png b/Tests/ReferenceImages_64/ChartsTests.LineChartTests/testDoesntDrawCircles_iOS_375_0_667_0@2x.png index 8ff11365..4599f864 100644 Binary files a/Tests/ReferenceImages_64/ChartsTests.LineChartTests/testDoesntDrawCircles_iOS_375_0_667_0@2x.png and b/Tests/ReferenceImages_64/ChartsTests.LineChartTests/testDoesntDrawCircles_iOS_375_0_667_0@2x.png differ diff --git a/Tests/ReferenceImages_64/ChartsTests.LineChartTests/testDoesntDrawCircles_tvOS_1920_0_1080_0@1x.png b/Tests/ReferenceImages_64/ChartsTests.LineChartTests/testDoesntDrawCircles_tvOS_1920_0_1080_0@1x.png index 733cf574..1f639c58 100644 Binary files a/Tests/ReferenceImages_64/ChartsTests.LineChartTests/testDoesntDrawCircles_tvOS_1920_0_1080_0@1x.png and b/Tests/ReferenceImages_64/ChartsTests.LineChartTests/testDoesntDrawCircles_tvOS_1920_0_1080_0@1x.png differ diff --git a/Tests/ReferenceImages_64/ChartsTests.LineChartTests/testDrawIcons_iOS_375_0_667_0@2x.png b/Tests/ReferenceImages_64/ChartsTests.LineChartTests/testDrawIcons_iOS_375_0_667_0@2x.png index 233cdd31..03d30f79 100644 Binary files a/Tests/ReferenceImages_64/ChartsTests.LineChartTests/testDrawIcons_iOS_375_0_667_0@2x.png and b/Tests/ReferenceImages_64/ChartsTests.LineChartTests/testDrawIcons_iOS_375_0_667_0@2x.png differ diff --git a/Tests/ReferenceImages_64/ChartsTests.LineChartTests/testDrawIcons_tvOS_1920_0_1080_0@1x.png b/Tests/ReferenceImages_64/ChartsTests.LineChartTests/testDrawIcons_tvOS_1920_0_1080_0@1x.png index a42b7e83..09689591 100644 Binary files a/Tests/ReferenceImages_64/ChartsTests.LineChartTests/testDrawIcons_tvOS_1920_0_1080_0@1x.png and b/Tests/ReferenceImages_64/ChartsTests.LineChartTests/testDrawIcons_tvOS_1920_0_1080_0@1x.png differ diff --git a/Tests/ReferenceImages_64/ChartsTests.LineChartTests/testHidesValues_iOS_375_0_667_0@2x.png b/Tests/ReferenceImages_64/ChartsTests.LineChartTests/testHidesValues_iOS_375_0_667_0@2x.png index df7f9637..18b76d8d 100644 Binary files a/Tests/ReferenceImages_64/ChartsTests.LineChartTests/testHidesValues_iOS_375_0_667_0@2x.png and b/Tests/ReferenceImages_64/ChartsTests.LineChartTests/testHidesValues_iOS_375_0_667_0@2x.png differ diff --git a/Tests/ReferenceImages_64/ChartsTests.LineChartTests/testHidesValues_tvOS_1920_0_1080_0@1x.png b/Tests/ReferenceImages_64/ChartsTests.LineChartTests/testHidesValues_tvOS_1920_0_1080_0@1x.png index 4539e71a..3452553e 100644 Binary files a/Tests/ReferenceImages_64/ChartsTests.LineChartTests/testHidesValues_tvOS_1920_0_1080_0@1x.png and b/Tests/ReferenceImages_64/ChartsTests.LineChartTests/testHidesValues_tvOS_1920_0_1080_0@1x.png differ diff --git a/Tests/ReferenceImages_64/ChartsTests.LineChartTests/testIsCubic_iOS_375_0_667_0@2x.png b/Tests/ReferenceImages_64/ChartsTests.LineChartTests/testIsCubic_iOS_375_0_667_0@2x.png index 17ffc30c..cb8c3702 100644 Binary files a/Tests/ReferenceImages_64/ChartsTests.LineChartTests/testIsCubic_iOS_375_0_667_0@2x.png and b/Tests/ReferenceImages_64/ChartsTests.LineChartTests/testIsCubic_iOS_375_0_667_0@2x.png differ diff --git a/Tests/ReferenceImages_64/ChartsTests.LineChartTests/testIsCubic_tvOS_1920_0_1080_0@1x.png b/Tests/ReferenceImages_64/ChartsTests.LineChartTests/testIsCubic_tvOS_1920_0_1080_0@1x.png index a930e41f..ff56ed8c 100644 Binary files a/Tests/ReferenceImages_64/ChartsTests.LineChartTests/testIsCubic_tvOS_1920_0_1080_0@1x.png and b/Tests/ReferenceImages_64/ChartsTests.LineChartTests/testIsCubic_tvOS_1920_0_1080_0@1x.png differ diff --git a/Tests/ReferenceImages_64/ChartsTests.PieChartTests/testDefaultValues_iOS_375_0_667_0@2x.png b/Tests/ReferenceImages_64/ChartsTests.PieChartTests/testDefaultValues_iOS_375_0_667_0@2x.png index 231fbbbe..181877a9 100644 Binary files a/Tests/ReferenceImages_64/ChartsTests.PieChartTests/testDefaultValues_iOS_375_0_667_0@2x.png and b/Tests/ReferenceImages_64/ChartsTests.PieChartTests/testDefaultValues_iOS_375_0_667_0@2x.png differ diff --git a/Tests/ReferenceImages_64/ChartsTests.PieChartTests/testDefaultValues_tvOS_1920_0_1080_0@1x.png b/Tests/ReferenceImages_64/ChartsTests.PieChartTests/testDefaultValues_tvOS_1920_0_1080_0@1x.png index 005701e0..1b200e2d 100644 Binary files a/Tests/ReferenceImages_64/ChartsTests.PieChartTests/testDefaultValues_tvOS_1920_0_1080_0@1x.png and b/Tests/ReferenceImages_64/ChartsTests.PieChartTests/testDefaultValues_tvOS_1920_0_1080_0@1x.png differ diff --git a/Tests/ReferenceImages_64/ChartsTests.PieChartTests/testDrawIcons_iOS_375_0_667_0@2x.png b/Tests/ReferenceImages_64/ChartsTests.PieChartTests/testDrawIcons_iOS_375_0_667_0@2x.png index d9068109..f70a82ff 100644 Binary files a/Tests/ReferenceImages_64/ChartsTests.PieChartTests/testDrawIcons_iOS_375_0_667_0@2x.png and b/Tests/ReferenceImages_64/ChartsTests.PieChartTests/testDrawIcons_iOS_375_0_667_0@2x.png differ diff --git a/Tests/ReferenceImages_64/ChartsTests.PieChartTests/testDrawIcons_tvOS_1920_0_1080_0@1x.png b/Tests/ReferenceImages_64/ChartsTests.PieChartTests/testDrawIcons_tvOS_1920_0_1080_0@1x.png index 4ff0b1af..4ce50976 100644 Binary files a/Tests/ReferenceImages_64/ChartsTests.PieChartTests/testDrawIcons_tvOS_1920_0_1080_0@1x.png and b/Tests/ReferenceImages_64/ChartsTests.PieChartTests/testDrawIcons_tvOS_1920_0_1080_0@1x.png differ diff --git a/Tests/ReferenceImages_64/ChartsTests.PieChartTests/testHideCenterLabel_iOS_375_0_667_0@2x.png b/Tests/ReferenceImages_64/ChartsTests.PieChartTests/testHideCenterLabel_iOS_375_0_667_0@2x.png index d71579a4..a3cbbc06 100644 Binary files a/Tests/ReferenceImages_64/ChartsTests.PieChartTests/testHideCenterLabel_iOS_375_0_667_0@2x.png and b/Tests/ReferenceImages_64/ChartsTests.PieChartTests/testHideCenterLabel_iOS_375_0_667_0@2x.png differ diff --git a/Tests/ReferenceImages_64/ChartsTests.PieChartTests/testHideCenterLabel_tvOS_1920_0_1080_0@1x.png b/Tests/ReferenceImages_64/ChartsTests.PieChartTests/testHideCenterLabel_tvOS_1920_0_1080_0@1x.png index bb58d49f..2b6eed06 100644 Binary files a/Tests/ReferenceImages_64/ChartsTests.PieChartTests/testHideCenterLabel_tvOS_1920_0_1080_0@1x.png and b/Tests/ReferenceImages_64/ChartsTests.PieChartTests/testHideCenterLabel_tvOS_1920_0_1080_0@1x.png differ diff --git a/Tests/ReferenceImages_64/ChartsTests.PieChartTests/testHidesValues_iOS_375_0_667_0@2x.png b/Tests/ReferenceImages_64/ChartsTests.PieChartTests/testHidesValues_iOS_375_0_667_0@2x.png index 9cc8ca4e..727d8dc4 100644 Binary files a/Tests/ReferenceImages_64/ChartsTests.PieChartTests/testHidesValues_iOS_375_0_667_0@2x.png and b/Tests/ReferenceImages_64/ChartsTests.PieChartTests/testHidesValues_iOS_375_0_667_0@2x.png differ diff --git a/Tests/ReferenceImages_64/ChartsTests.PieChartTests/testHidesValues_tvOS_1920_0_1080_0@1x.png b/Tests/ReferenceImages_64/ChartsTests.PieChartTests/testHidesValues_tvOS_1920_0_1080_0@1x.png index 5bf07c7a..0b0a42ee 100644 Binary files a/Tests/ReferenceImages_64/ChartsTests.PieChartTests/testHidesValues_tvOS_1920_0_1080_0@1x.png and b/Tests/ReferenceImages_64/ChartsTests.PieChartTests/testHidesValues_tvOS_1920_0_1080_0@1x.png differ diff --git a/Tests/ReferenceImages_64/ChartsTests.PieChartTests/testHighlightDisabled_iOS_375_0_667_0@2x.png b/Tests/ReferenceImages_64/ChartsTests.PieChartTests/testHighlightDisabled_iOS_375_0_667_0@2x.png index 231fbbbe..181877a9 100644 Binary files a/Tests/ReferenceImages_64/ChartsTests.PieChartTests/testHighlightDisabled_iOS_375_0_667_0@2x.png and b/Tests/ReferenceImages_64/ChartsTests.PieChartTests/testHighlightDisabled_iOS_375_0_667_0@2x.png differ diff --git a/Tests/ReferenceImages_64/ChartsTests.PieChartTests/testHighlightDisabled_tvOS_1920_0_1080_0@1x.png b/Tests/ReferenceImages_64/ChartsTests.PieChartTests/testHighlightDisabled_tvOS_1920_0_1080_0@1x.png index 005701e0..1b200e2d 100644 Binary files a/Tests/ReferenceImages_64/ChartsTests.PieChartTests/testHighlightDisabled_tvOS_1920_0_1080_0@1x.png and b/Tests/ReferenceImages_64/ChartsTests.PieChartTests/testHighlightDisabled_tvOS_1920_0_1080_0@1x.png differ diff --git a/Tests/ReferenceImages_64/ChartsTests.PieChartTests/testHighlightEnabled_iOS_375_0_667_0@2x.png b/Tests/ReferenceImages_64/ChartsTests.PieChartTests/testHighlightEnabled_iOS_375_0_667_0@2x.png index 3d9608c4..1794f680 100644 Binary files a/Tests/ReferenceImages_64/ChartsTests.PieChartTests/testHighlightEnabled_iOS_375_0_667_0@2x.png and b/Tests/ReferenceImages_64/ChartsTests.PieChartTests/testHighlightEnabled_iOS_375_0_667_0@2x.png differ diff --git a/Tests/ReferenceImages_64/ChartsTests.PieChartTests/testHighlightEnabled_tvOS_1920_0_1080_0@1x.png b/Tests/ReferenceImages_64/ChartsTests.PieChartTests/testHighlightEnabled_tvOS_1920_0_1080_0@1x.png index b4adb17e..597709bd 100644 Binary files a/Tests/ReferenceImages_64/ChartsTests.PieChartTests/testHighlightEnabled_tvOS_1920_0_1080_0@1x.png and b/Tests/ReferenceImages_64/ChartsTests.PieChartTests/testHighlightEnabled_tvOS_1920_0_1080_0@1x.png differ diff --git a/carthage.sh b/carthage.sh new file mode 100755 index 00000000..adffae88 --- /dev/null +++ b/carthage.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash + +# carthage.sh +# Usage example: ./carthage.sh build --platform iOS + +set -euo pipefail + +xcconfig=$(mktemp /tmp/static.xcconfig.XXXXXX) +trap 'rm -f "$xcconfig"' INT TERM HUP EXIT + +# For Xcode 12 make sure EXCLUDED_ARCHS is set to arm architectures otherwise +# the build will fail on lipo due to duplicate architectures. +echo 'EXCLUDED_ARCHS__EFFECTIVE_PLATFORM_SUFFIX_simulator__NATIVE_ARCH_64_BIT_x86_64__XCODE_1200 = arm64 arm64e armv7 armv7s armv6 armv8' >> $xcconfig +echo 'EXCLUDED_ARCHS = $(inherited) $(EXCLUDED_ARCHS__EFFECTIVE_PLATFORM_SUFFIX_$(EFFECTIVE_PLATFORM_SUFFIX)__NATIVE_ARCH_64_BIT_$(NATIVE_ARCH_64_BIT)__XCODE_$(XCODE_VERSION_MAJOR))' >> $xcconfig + +export XCODE_XCCONFIG_FILE="$xcconfig" +carthage "$@"