TRAVIS_OS_NAME=osx default= <<<<<< ENV ./ChartDataTests.swift ./Charts.xcworkspace/contents.xcworkspacedata ./Charts.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist ./Cartfile.resolved ./LICENSE ./Source/Charts/Filters/DataApproximator.swift ./Source/Charts/Filters/DataApproximator+N.swift ./Source/Charts/Renderers/RadarChartRenderer.swift ./Source/Charts/Renderers/LegendRenderer.swift ./Source/Charts/Renderers/YAxisRendererHorizontalBarChart.swift ./Source/Charts/Renderers/BubbleChartRenderer.swift ./Source/Charts/Renderers/LineChartRenderer.swift ./Source/Charts/Renderers/AxisRendererBase.swift ./Source/Charts/Renderers/ChartDataRendererBase.swift ./Source/Charts/Renderers/YAxisRenderer.swift ./Source/Charts/Renderers/ScatterChartRenderer.swift ./Source/Charts/Renderers/CombinedChartRenderer.swift ./Source/Charts/Renderers/CandleStickChartRenderer.swift ./Source/Charts/Renderers/BarChartRenderer.swift ./Source/Charts/Renderers/XAxisRenderer.swift ./Source/Charts/Renderers/LineRadarRenderer.swift ./Source/Charts/Renderers/BarLineScatterCandleBubbleRenderer.swift ./Source/Charts/Renderers/Scatter/XShapeRenderer.swift ./Source/Charts/Renderers/Scatter/SquareShapeRenderer.swift ./Source/Charts/Renderers/Scatter/ChevronDownShapeRenderer.swift ./Source/Charts/Renderers/Scatter/IShapeRenderer.swift ./Source/Charts/Renderers/Scatter/CircleShapeRenderer.swift ./Source/Charts/Renderers/Scatter/CrossShapeRenderer.swift ./Source/Charts/Renderers/Scatter/TriangleShapeRenderer.swift ./Source/Charts/Renderers/Scatter/ChevronUpShapeRenderer.swift ./Source/Charts/Renderers/XAxisRendererHorizontalBarChart.swift ./Source/Charts/Renderers/HorizontalBarChartRenderer.swift ./Source/Charts/Renderers/XAxisRendererRadarChart.swift ./Source/Charts/Renderers/YAxisRendererRadarChart.swift ./Source/Charts/Renderers/PieChartRenderer.swift ./Source/Charts/Renderers/Renderer.swift ./Source/Charts/Renderers/LineScatterCandleRadarRenderer.swift ./Source/Charts/Highlight/BarHighlighter.swift ./Source/Charts/Highlight/RadarHighlighter.swift ./Source/Charts/Highlight/Highlight.swift ./Source/Charts/Highlight/PieHighlighter.swift ./Source/Charts/Highlight/HorizontalBarHighlighter.swift ./Source/Charts/Highlight/PieRadarHighlighter.swift ./Source/Charts/Highlight/Range.swift ./Source/Charts/Highlight/ChartHighlighter.swift ./Source/Charts/Highlight/IHighlighter.swift ./Source/Charts/Highlight/CombinedHighlighter.swift ./Source/Charts/Charts/CandleStickChartView.swift ./Source/Charts/Charts/RadarChartView.swift ./Source/Charts/Charts/BarLineChartViewBase.swift ./Source/Charts/Charts/LineChartView.swift ./Source/Charts/Charts/CombinedChartView.swift ./Source/Charts/Charts/HorizontalBarChartView.swift ./Source/Charts/Charts/ChartViewBase.swift ./Source/Charts/Charts/BubbleChartView.swift ./Source/Charts/Charts/PieRadarChartViewBase.swift ./Source/Charts/Charts/BarChartView.swift ./Source/Charts/Charts/ScatterChartView.swift ./Source/Charts/Charts/PieChartView.swift ./Source/Charts/Animation/ChartAnimationEasing.swift ./Source/Charts/Animation/Animator.swift ./Source/Charts/Formatters/IAxisValueFormatter.swift ./Source/Charts/Formatters/DefaultFillFormatter.swift ./Source/Charts/Formatters/DefaultValueFormatter.swift ./Source/Charts/Formatters/DefaultAxisValueFormatter.swift ./Source/Charts/Formatters/IndexAxisValueFormatter.swift ./Source/Charts/Formatters/IFillFormatter.swift ./Source/Charts/Formatters/IValueFormatter.swift ./Source/Charts/Utils/Fill.swift ./Source/Charts/Utils/Transformer.swift ./Source/Charts/Utils/Platform+Touch Handling.swift ./Source/Charts/Utils/ViewPortHandler.swift ./Source/Charts/Utils/Platform+Gestures.swift ./Source/Charts/Utils/Platform+Graphics.swift ./Source/Charts/Utils/Platform+Accessibility.swift ./Source/Charts/Utils/Platform.swift ./Source/Charts/Utils/ChartColorTemplates.swift ./Source/Charts/Utils/TransformerHorizontalBarChart.swift ./Source/Charts/Utils/Platform+Color.swift ./Source/Charts/Utils/ChartUtils.swift ./Source/Charts/Components/Description.swift ./Source/Charts/Components/IMarker.swift ./Source/Charts/Components/MarkerImage.swift ./Source/Charts/Components/Legend.swift ./Source/Charts/Components/LegendEntry.swift ./Source/Charts/Components/YAxis.swift ./Source/Charts/Components/AxisBase.swift ./Source/Charts/Components/XAxis.swift ./Source/Charts/Components/ChartLimitLine.swift ./Source/Charts/Components/MarkerView.swift ./Source/Charts/Components/ComponentBase.swift ./Source/Charts/Jobs/AnimatedZoomViewJob.swift ./Source/Charts/Jobs/ViewPortJob.swift ./Source/Charts/Jobs/MoveViewJob.swift ./Source/Charts/Jobs/ZoomViewJob.swift ./Source/Charts/Jobs/AnimatedViewPortJob.swift ./Source/Charts/Jobs/AnimatedMoveViewJob.swift ./Source/Charts/Data/Implementations/Standard/ChartData.swift ./Source/Charts/Data/Implementations/Standard/BarChartDataEntry.swift ./Source/Charts/Data/Implementations/Standard/BarChartDataSet.swift ./Source/Charts/Data/Implementations/Standard/RadarChartDataEntry.swift ./Source/Charts/Data/Implementations/Standard/BarLineScatterCandleBubbleChartDataSet.swift ./Source/Charts/Data/Implementations/Standard/PieChartDataEntry.swift ./Source/Charts/Data/Implementations/Standard/CandleChartDataEntry.swift ./Source/Charts/Data/Implementations/Standard/CombinedChartData.swift ./Source/Charts/Data/Implementations/Standard/LineChartData.swift ./Source/Charts/Data/Implementations/Standard/RadarChartData.swift ./Source/Charts/Data/Implementations/Standard/CandleChartDataSet.swift ./Source/Charts/Data/Implementations/Standard/LineRadarChartDataSet.swift ./Source/Charts/Data/Implementations/Standard/BarLineScatterCandleBubbleChartData.swift ./Source/Charts/Data/Implementations/Standard/BubbleChartDataEntry.swift ./Source/Charts/Data/Implementations/Standard/ChartDataEntryBase.swift ./Source/Charts/Data/Implementations/Standard/ChartDataEntry.swift ./Source/Charts/Data/Implementations/Standard/PieChartDataSet.swift ./Source/Charts/Data/Implementations/Standard/BubbleChartData.swift ./Source/Charts/Data/Implementations/Standard/ChartDataSet.swift ./Source/Charts/Data/Implementations/Standard/ScatterChartDataSet.swift ./Source/Charts/Data/Implementations/Standard/ScatterChartData.swift ./Source/Charts/Data/Implementations/Standard/PieChartData.swift ./Source/Charts/Data/Implementations/Standard/CandleChartData.swift ./Source/Charts/Data/Implementations/Standard/LineChartDataSet.swift ./Source/Charts/Data/Implementations/Standard/BubbleChartDataSet.swift ./Source/Charts/Data/Implementations/Standard/RadarChartDataSet.swift ./Source/Charts/Data/Implementations/Standard/BarChartData.swift ./Source/Charts/Data/Implementations/Standard/LineScatterCandleRadarChartDataSet.swift ./Source/Charts/Data/Implementations/ChartBaseDataSet.swift ./Source/Charts/Data/Interfaces/IPieChartDataSet.swift ./Source/Charts/Data/Interfaces/IScatterChartDataSet.swift ./Source/Charts/Data/Interfaces/ILineChartDataSet.swift ./Source/Charts/Data/Interfaces/IRadarChartDataSet.swift ./Source/Charts/Data/Interfaces/IBarChartDataSet.swift ./Source/Charts/Data/Interfaces/ILineRadarChartDataSet.swift ./Source/Charts/Data/Interfaces/IChartDataSet.swift ./Source/Charts/Data/Interfaces/ICandleChartDataSet.swift ./Source/Charts/Data/Interfaces/ILineScatterCandleRadarChartDataSet.swift ./Source/Charts/Data/Interfaces/IBubbleChartDataSet.swift ./Source/Charts/Data/Interfaces/IBarLineScatterCandleBubbleChartDataSet.swift ./Source/Charts/Interfaces/BarChartDataProvider.swift ./Source/Charts/Interfaces/ChartDataProvider.swift ./Source/Charts/Interfaces/CandleChartDataProvider.swift ./Source/Charts/Interfaces/CombinedChartDataProvider.swift ./Source/Charts/Interfaces/LineChartDataProvider.swift ./Source/Charts/Interfaces/BarLineScatterCandleBubbleChartDataProvider.swift ./Source/Charts/Interfaces/ScatterChartDataProvider.swift ./Source/Charts/Interfaces/BubbleChartDataProvider.swift ./Source/Supporting Files/Charts.h ./Source/Supporting Files/Info.plist ./.bundle/config ./Tests/Charts/EquatableTests.swift ./Tests/Charts/Snapshot.swift ./Tests/Charts/PieChartTests.swift ./Tests/Charts/LineChartTests.swift ./Tests/Charts/HorizontalBarChartTests.swift ./Tests/Charts/BarChartTests.swift ./Tests/Charts/ChartUtilsTests.swift ./Tests/Charts/CombinedChartTests.swift ./Tests/Supporting Files/Media.xcassets/icon.imageset/Contents.json ./Tests/Supporting Files/Media.xcassets/Contents.json ./Tests/Supporting Files/Info.plist ./ChartsDemo-macOS/ChartsDemo-macOS.xcodeproj/project.pbxproj ./ChartsDemo-macOS/PlaygroundChart.playground/contents.xcplayground ./ChartsDemo-macOS/PlaygroundChart.playground/Contents.o ./ChartsDemo-macOS/PlaygroundChart.playground/Pages/Menu.xcplaygroundpage/Contents.swift ./ChartsDemo-macOS/PlaygroundChart.playground/Pages/HorizontalBarChart.xcplaygroundpage/Contents.swift ./ChartsDemo-macOS/PlaygroundChart.playground/Pages/BarChart.xcplaygroundpage/Contents.swift ./ChartsDemo-macOS/PlaygroundChart.playground/Pages/StackedBarChart.xcplaygroundpage/Contents.swift ./ChartsDemo-macOS/PlaygroundChart.playground/Pages/ScatterChart.xcplaygroundpage/Contents.swift ./ChartsDemo-macOS/PlaygroundChart.playground/Pages/CombinedChart.xcplaygroundpage/Contents.swift ./ChartsDemo-macOS/PlaygroundChart.playground/Pages/RadarChart.xcplaygroundpage/Contents.swift ./ChartsDemo-macOS/PlaygroundChart.playground/Pages/PieChart.xcplaygroundpage/Contents.swift ./ChartsDemo-macOS/PlaygroundChart.playground/Pages/BubbleChart.xcplaygroundpage/Contents.swift ./ChartsDemo-macOS/PlaygroundChart.playground/Pages/CandleChart.xcplaygroundpage/Contents.swift ./ChartsDemo-macOS/PlaygroundChart.playground/Pages/LineChart.xcplaygroundpage/Contents.swift ./ChartsDemo-macOS/ChartsDemo-macOS/Assets.xcassets/AppIcon.appiconset/Contents.json ./ChartsDemo-macOS/ChartsDemo-macOS/Base.lproj/Main.storyboard ./ChartsDemo-macOS/ChartsDemo-macOS/AppDelegate.swift ./ChartsDemo-macOS/ChartsDemo-macOS/Demos/RadarDemoViewController.swift ./ChartsDemo-macOS/ChartsDemo-macOS/Demos/PieDemoViewController.swift ./ChartsDemo-macOS/ChartsDemo-macOS/Demos/BarDemoViewController.swift ./ChartsDemo-macOS/ChartsDemo-macOS/Demos/LineDemoViewController.swift ./ChartsDemo-macOS/ChartsDemo-macOS/Info.plist ./Carthage/Checkouts/ios-snapshot-test-case/FBSnapshotTestCase.xcodeproj/project.pbxproj ./Carthage/Checkouts/ios-snapshot-test-case/FBSnapshotTestCase.xcodeproj/xcshareddata/xcschemes/FBSnapshotTestCase tvOS.xcscheme ./Carthage/Checkouts/ios-snapshot-test-case/FBSnapshotTestCase.xcodeproj/xcshareddata/xcschemes/FBSnapshotTestCase iOS.xcscheme ./Carthage/Checkouts/ios-snapshot-test-case/LICENSE ./Carthage/Checkouts/ios-snapshot-test-case/bin/clang-format ./Carthage/Checkouts/ios-snapshot-test-case/FBSnapshotTestCaseDemo/FBSnapshotTestCaseDemo.xcworkspace/contents.xcworkspacedata ./Carthage/Checkouts/ios-snapshot-test-case/FBSnapshotTestCaseDemo/FBSnapshotTestCaseDemo.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist ./Carthage/Checkouts/ios-snapshot-test-case/FBSnapshotTestCaseDemo/FBSnapshotTestCaseDemo.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings ./Carthage/Checkouts/ios-snapshot-test-case/FBSnapshotTestCaseDemo/FBSnapshotTestCaseDemo.xcodeproj/project.pbxproj ./Carthage/Checkouts/ios-snapshot-test-case/FBSnapshotTestCaseDemo/FBSnapshotTestCaseDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata ./Carthage/Checkouts/ios-snapshot-test-case/FBSnapshotTestCaseDemo/FBSnapshotTestCaseDemo.xcodeproj/xcshareddata/xcschemes/FBSnapshotTestCaseDemo.xcscheme ./Carthage/Checkouts/ios-snapshot-test-case/FBSnapshotTestCaseDemo/FBSnapshotTestCaseDemo.xcodeproj/xcshareddata/xcschemes/FBSnapshotTestCasePreprocessorDemo.xcscheme ./Carthage/Checkouts/ios-snapshot-test-case/FBSnapshotTestCaseDemo/FBSnapshotTestCaseDemo/en.lproj/InfoPlist.strings ./Carthage/Checkouts/ios-snapshot-test-case/FBSnapshotTestCaseDemo/FBSnapshotTestCaseDemo/FBAppDelegate.h ./Carthage/Checkouts/ios-snapshot-test-case/FBSnapshotTestCaseDemo/FBSnapshotTestCaseDemo/FBSnapshotTestCaseDemo-Prefix.pch ./Carthage/Checkouts/ios-snapshot-test-case/FBSnapshotTestCaseDemo/FBSnapshotTestCaseDemo/main.m ./Carthage/Checkouts/ios-snapshot-test-case/FBSnapshotTestCaseDemo/FBSnapshotTestCaseDemo/Images.xcassets/AppIcon.appiconset/Contents.json ./Carthage/Checkouts/ios-snapshot-test-case/FBSnapshotTestCaseDemo/FBSnapshotTestCaseDemo/Images.xcassets/Brand Assets.launchimage/Contents.json ./Carthage/Checkouts/ios-snapshot-test-case/FBSnapshotTestCaseDemo/FBSnapshotTestCaseDemo/Images.xcassets/Contents.json ./Carthage/Checkouts/ios-snapshot-test-case/FBSnapshotTestCaseDemo/FBSnapshotTestCaseDemo/Images.xcassets/LaunchImage.launchimage/Contents.json ./Carthage/Checkouts/ios-snapshot-test-case/FBSnapshotTestCaseDemo/FBSnapshotTestCaseDemo/Launch Screen.storyboard ./Carthage/Checkouts/ios-snapshot-test-case/FBSnapshotTestCaseDemo/FBSnapshotTestCaseDemo/FBAppDelegate.m ./Carthage/Checkouts/ios-snapshot-test-case/FBSnapshotTestCaseDemo/FBSnapshotTestCaseDemo/FBSnapshotTestCaseDemo-Info.plist ./Carthage/Checkouts/ios-snapshot-test-case/FBSnapshotTestCaseDemo/FBSnapshotTestCaseDemoTests/en.lproj/InfoPlist.strings ./Carthage/Checkouts/ios-snapshot-test-case/FBSnapshotTestCaseDemo/FBSnapshotTestCaseDemoTests/FBSnapshotTestCaseDemoTests.m ./Carthage/Checkouts/ios-snapshot-test-case/FBSnapshotTestCaseDemo/FBSnapshotTestCaseDemoTests/FBSnapshotTestCaseDemoTests-Info.plist ./Carthage/Checkouts/ios-snapshot-test-case/FBSnapshotTestCaseDemo/FBSnapshotTestCaseDemoTests/FBSnapshotTestCaseSwiftTests.swift ./Carthage/Checkouts/ios-snapshot-test-case/FBSnapshotTestCaseDemo/Podfile ./Carthage/Checkouts/ios-snapshot-test-case/FBSnapshotTestCaseDemo/Podfile.lock ./Carthage/Checkouts/ios-snapshot-test-case/FBSnapshotTestCase.xcworkspace/contents.xcworkspacedata ./Carthage/Checkouts/ios-snapshot-test-case/FBSnapshotTestCase.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist ./Carthage/Checkouts/ios-snapshot-test-case/iOSSnapshotTestCaseCarthageDemo/Cartfile.resolved ./Carthage/Checkouts/ios-snapshot-test-case/iOSSnapshotTestCaseCarthageDemo/iOSSnapshotTestCaseCarthageDemoSwiftTests/iOSSnapshotTestCaseCarthageDemoSwiftTests.swift ./Carthage/Checkouts/ios-snapshot-test-case/iOSSnapshotTestCaseCarthageDemo/iOSSnapshotTestCaseCarthageDemoSwiftTests/Info.plist ./Carthage/Checkouts/ios-snapshot-test-case/iOSSnapshotTestCaseCarthageDemo/Cartfile ./Carthage/Checkouts/ios-snapshot-test-case/iOSSnapshotTestCaseCarthageDemo/iOSSnapshotTestCaseCarthageDemo/Assets.xcassets/AppIcon.appiconset/Contents.json ./Carthage/Checkouts/ios-snapshot-test-case/iOSSnapshotTestCaseCarthageDemo/iOSSnapshotTestCaseCarthageDemo/Assets.xcassets/Contents.json ./Carthage/Checkouts/ios-snapshot-test-case/iOSSnapshotTestCaseCarthageDemo/iOSSnapshotTestCaseCarthageDemo/Base.lproj/LaunchScreen.storyboard ./Carthage/Checkouts/ios-snapshot-test-case/iOSSnapshotTestCaseCarthageDemo/iOSSnapshotTestCaseCarthageDemo/AppDelegate.swift ./Carthage/Checkouts/ios-snapshot-test-case/iOSSnapshotTestCaseCarthageDemo/iOSSnapshotTestCaseCarthageDemo/Info.plist ./Carthage/Checkouts/ios-snapshot-test-case/iOSSnapshotTestCaseCarthageDemo/iOSSnapshotTestCaseCarthageDemo.xcodeproj/project.pbxproj ./Carthage/Checkouts/ios-snapshot-test-case/iOSSnapshotTestCaseCarthageDemo/iOSSnapshotTestCaseCarthageDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata ./Carthage/Checkouts/ios-snapshot-test-case/iOSSnapshotTestCaseCarthageDemo/iOSSnapshotTestCaseCarthageDemo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist ./Carthage/Checkouts/ios-snapshot-test-case/iOSSnapshotTestCaseCarthageDemo/iOSSnapshotTestCaseCarthageDemo.xcodeproj/xcshareddata/xcschemes/iOSSnapshotTestCaseCarthageDemo.xcscheme ./Carthage/Checkouts/ios-snapshot-test-case/build.sh ./Carthage/Checkouts/ios-snapshot-test-case/SnapshotTest.xctemplate/___FILEBASENAME___.m ./Carthage/Checkouts/ios-snapshot-test-case/SnapshotTest.xctemplate/TemplateInfo.plist ./Carthage/Checkouts/ios-snapshot-test-case/iOSSnapshotTestCase.podspec ./Carthage/Checkouts/ios-snapshot-test-case/.clang-format ./Carthage/Checkouts/ios-snapshot-test-case/FBSnapshotTestCase/FBSnapshotTestCasePlatform.m ./Carthage/Checkouts/ios-snapshot-test-case/FBSnapshotTestCase/FBSnapshotTestCase.h ./Carthage/Checkouts/ios-snapshot-test-case/FBSnapshotTestCase/FBSnapshotTestController.m ./Carthage/Checkouts/ios-snapshot-test-case/FBSnapshotTestCase/SwiftSupport.swift ./Carthage/Checkouts/ios-snapshot-test-case/FBSnapshotTestCase/FBSnapshotTestCase-Info.plist ./Carthage/Checkouts/ios-snapshot-test-case/FBSnapshotTestCase/FBSnapshotTestCase.m ./Carthage/Checkouts/ios-snapshot-test-case/FBSnapshotTestCase/FBSnapshotTestCasePlatform.h ./Carthage/Checkouts/ios-snapshot-test-case/FBSnapshotTestCase/Categories/UIImage+Diff.h ./Carthage/Checkouts/ios-snapshot-test-case/FBSnapshotTestCase/Categories/UIImage+Snapshot.m ./Carthage/Checkouts/ios-snapshot-test-case/FBSnapshotTestCase/Categories/UIImage+Compare.m ./Carthage/Checkouts/ios-snapshot-test-case/FBSnapshotTestCase/Categories/UIImage+Diff.m ./Carthage/Checkouts/ios-snapshot-test-case/FBSnapshotTestCase/Categories/UIImage+Compare.h ./Carthage/Checkouts/ios-snapshot-test-case/FBSnapshotTestCase/Categories/UIImage+Snapshot.h ./Carthage/Checkouts/ios-snapshot-test-case/FBSnapshotTestCase/FBSnapshotTestController.h ./Carthage/Checkouts/ios-snapshot-test-case/FBSnapshotTestCaseTests/FBSnapshotControllerTests.m ./Carthage/Checkouts/ios-snapshot-test-case/FBSnapshotTestCaseTests/FBSnapshotTestCaseTests-Info.plist ./Carthage/Build/.ios-snapshot-test-case.version ./Carthage/Build/tvOS/FBSnapshotTestCase.framework.dSYM/Contents/Resources/DWARF/FBSnapshotTestCase ./Carthage/Build/tvOS/FBSnapshotTestCase.framework.dSYM/Contents/Info.plist ./Carthage/Build/tvOS/FBSnapshotTestCase.framework/_CodeSignature/CodeResources ./Carthage/Build/tvOS/FBSnapshotTestCase.framework/Headers/FBSnapshotTestCase-Swift.h ./Carthage/Build/tvOS/FBSnapshotTestCase.framework/Headers/FBSnapshotTestCase.h ./Carthage/Build/tvOS/FBSnapshotTestCase.framework/Headers/FBSnapshotTestCasePlatform.h ./Carthage/Build/tvOS/FBSnapshotTestCase.framework/Headers/FBSnapshotTestController.h ./Carthage/Build/tvOS/FBSnapshotTestCase.framework/FBSnapshotTestCase ./Carthage/Build/tvOS/FBSnapshotTestCase.framework/Frameworks/libswiftObjectiveC.dylib ./Carthage/Build/tvOS/FBSnapshotTestCase.framework/Frameworks/libswiftCore.dylib ./Carthage/Build/tvOS/FBSnapshotTestCase.framework/Frameworks/libswiftCoreGraphics.dylib ./Carthage/Build/tvOS/FBSnapshotTestCase.framework/Frameworks/libswiftDispatch.dylib ./Carthage/Build/tvOS/FBSnapshotTestCase.framework/Frameworks/libswiftCoreFoundation.dylib ./Carthage/Build/tvOS/FBSnapshotTestCase.framework/Frameworks/libswiftDarwin.dylib ./Carthage/Build/tvOS/FBSnapshotTestCase.framework/Frameworks/libswiftFoundation.dylib ./Carthage/Build/tvOS/FBSnapshotTestCase.framework/Modules/module.modulemap ./Carthage/Build/tvOS/FBSnapshotTestCase.framework/Modules/FBSnapshotTestCase.swiftmodule/x86_64.swiftdoc ./Carthage/Build/tvOS/FBSnapshotTestCase.framework/Modules/FBSnapshotTestCase.swiftmodule/x86_64-apple-tvos-simulator.swiftmodule ./Carthage/Build/tvOS/FBSnapshotTestCase.framework/Modules/FBSnapshotTestCase.swiftmodule/x86_64-apple-tvos-simulator.swiftdoc ./Carthage/Build/tvOS/FBSnapshotTestCase.framework/Modules/FBSnapshotTestCase.swiftmodule/x86_64.swiftmodule ./Carthage/Build/tvOS/FBSnapshotTestCase.framework/Info.plist ./Rakefile ./Cartfile.private ./Charts.podspec ./ChartsDemo-iOS/XIBs/RadarMarkerView.xib ./ChartsDemo-iOS/XIBs/DemoListViewController.xib ./ChartsDemo-iOS/XIBs/Demos/SinusBarChartViewController.xib ./ChartsDemo-iOS/XIBs/Demos/BarChartViewController.xib ./ChartsDemo-iOS/XIBs/Demos/ColoredLineChartViewController.xib ./ChartsDemo-iOS/XIBs/Demos/LineChart2ViewController.xib ./ChartsDemo-iOS/XIBs/Demos/PiePolylineChartViewController.xib ./ChartsDemo-iOS/XIBs/Demos/PieChartViewController.xib ./ChartsDemo-iOS/XIBs/Demos/LineChart1ViewController.xib ./ChartsDemo-iOS/XIBs/Demos/MultipleLinesChartViewController.xib ./ChartsDemo-iOS/XIBs/Demos/NegativeStackedBarChartViewController.xib ./ChartsDemo-iOS/XIBs/Demos/MultipleBarChartViewController.xib ./ChartsDemo-iOS/XIBs/Demos/CombinedChartViewController.xib ./ChartsDemo-iOS/XIBs/Demos/StackedBarChartViewController.xib ./ChartsDemo-iOS/XIBs/Demos/HalfPieChartViewController.xib ./ChartsDemo-iOS/XIBs/Demos/HorizontalBarChartViewController.xib ./ChartsDemo-iOS/XIBs/Demos/CandleStickChartViewController.xib ./ChartsDemo-iOS/XIBs/Demos/ScatterChartViewController.xib ./ChartsDemo-iOS/XIBs/Demos/PositiveNegativeBarChartViewController.xib ./ChartsDemo-iOS/XIBs/Demos/CubicLineChartViewController.xib ./ChartsDemo-iOS/XIBs/Demos/LineChartFilledViewController.xib ./ChartsDemo-iOS/XIBs/Demos/RadarChartViewController.xib ./ChartsDemo-iOS/XIBs/Demos/RealmDemosViewController.xib ./ChartsDemo-iOS/XIBs/Demos/AnotherBarChartViewController.xib ./ChartsDemo-iOS/XIBs/Demos/BubbleChartViewController.xib ./ChartsDemo-iOS/XIBs/Demos/LineChartTimeViewController.xib ./ChartsDemo-iOS/Resources/Images.xcassets/icon.imageset/Contents.json ./ChartsDemo-iOS/Resources/Images.xcassets/AppIcon.appiconset/Contents.json ./ChartsDemo-iOS/Resources/Images.xcassets/Contents.json ./ChartsDemo-iOS/Resources/Launch Screen.storyboard ./ChartsDemo-iOS/ChartsDemo-iOS.xcodeproj/project.pbxproj ./ChartsDemo-iOS/Supporting Files/main.m ./ChartsDemo-iOS/Supporting Files/ChartsDemo-Bridging-Header.h ./ChartsDemo-iOS/Supporting Files/Info.plist ./ChartsDemo-iOS/Swift/Formatters/IntAxisValueFormatter.swift ./ChartsDemo-iOS/Swift/Formatters/DayAxisValueFormatter.swift ./ChartsDemo-iOS/Swift/Formatters/DateValueFormatter.swift ./ChartsDemo-iOS/Swift/Formatters/LargeValueFormatter.swift ./ChartsDemo-iOS/Swift/Components/XYMarkerView.swift ./ChartsDemo-iOS/Swift/Components/RadarMarkerView.swift ./ChartsDemo-iOS/Swift/DemoListViewController.swift ./ChartsDemo-iOS/Swift/DemoBaseViewController.swift ./ChartsDemo-iOS/Swift/AppDelegate.swift ./ChartsDemo-iOS/Swift/Demos/MultipleLinesChartViewController.swift ./ChartsDemo-iOS/Swift/Demos/MultipleBarChartViewController.swift ./ChartsDemo-iOS/Swift/Demos/HalfPieChartViewController.swift ./ChartsDemo-iOS/Swift/Demos/LineChartTimeViewController.swift ./ChartsDemo-iOS/Swift/Demos/ColoredLineChartViewController.swift ./ChartsDemo-iOS/Swift/Demos/LineChart2ViewController.swift ./ChartsDemo-iOS/Swift/Demos/LineChart1ViewController.swift ./ChartsDemo-iOS/Swift/Demos/NegativeStackedBarChartViewController.swift ./ChartsDemo-iOS/Swift/Demos/ScatterChartViewController.swift ./ChartsDemo-iOS/Swift/Demos/StackedBarChartViewController.swift ./ChartsDemo-iOS/Swift/Demos/BubbleChartViewController.swift ./ChartsDemo-iOS/Swift/Demos/LineChartFilledViewController.swift ./ChartsDemo-iOS/Swift/Demos/PositiveNegativeBarChartViewController.swift ./ChartsDemo-iOS/Swift/Demos/AnotherBarChartViewController.swift ./ChartsDemo-iOS/Swift/Demos/PieChartViewController.swift ./ChartsDemo-iOS/Swift/Demos/CubicLineChartViewController.swift ./ChartsDemo-iOS/Swift/Demos/RadarChartViewController.swift ./ChartsDemo-iOS/Swift/Demos/HorizontalBarChartViewController.swift ./ChartsDemo-iOS/Swift/Demos/PiePolylineChartViewController.swift ./ChartsDemo-iOS/Swift/Demos/CombinedChartViewController.swift ./ChartsDemo-iOS/Swift/Demos/BarChartViewController.swift ./ChartsDemo-iOS/Swift/Demos/SinusBarChartViewController.swift ./ChartsDemo-iOS/Swift/Demos/CandleStickChartViewController.swift ./ChartsDemo-iOS/Objective-C/DemoBaseViewController.m ./ChartsDemo-iOS/Objective-C/AppDelegate.h ./ChartsDemo-iOS/Objective-C/DemoListViewController.m ./ChartsDemo-iOS/Objective-C/Formatters/DayAxisValueFormatter.h ./ChartsDemo-iOS/Objective-C/Formatters/DateValueFormatter.m ./ChartsDemo-iOS/Objective-C/Formatters/IntAxisValueFormatter.m ./ChartsDemo-iOS/Objective-C/Formatters/DayAxisValueFormatter.m ./ChartsDemo-iOS/Objective-C/Formatters/IntAxisValueFormatter.h ./ChartsDemo-iOS/Objective-C/Formatters/DateValueFormatter.h ./ChartsDemo-iOS/Objective-C/Formatters/LargeValueFormatter.swift ./ChartsDemo-iOS/Objective-C/Components/XYMarkerView.swift ./ChartsDemo-iOS/Objective-C/Components/BalloonMarker.swift ./ChartsDemo-iOS/Objective-C/Components/RadarMarkerView.swift ./ChartsDemo-iOS/Objective-C/AppDelegate.m ./ChartsDemo-iOS/Objective-C/DemoBaseViewController.h ./ChartsDemo-iOS/Objective-C/DemoListViewController.h ./ChartsDemo-iOS/Objective-C/Demos/MultipleLinesChartViewController.h ./ChartsDemo-iOS/Objective-C/Demos/LineChartTimeViewController.m ./ChartsDemo-iOS/Objective-C/Demos/SinusBarChartViewController.m ./ChartsDemo-iOS/Objective-C/Demos/CubicLineChartViewController.m ./ChartsDemo-iOS/Objective-C/Demos/NegativeStackedBarChartViewController.m ./ChartsDemo-iOS/Objective-C/Demos/ScatterChartViewController.m ./ChartsDemo-iOS/Objective-C/Demos/AnotherBarChartViewController.h ./ChartsDemo-iOS/Objective-C/Demos/StackedBarChartViewController.m ./ChartsDemo-iOS/Objective-C/Demos/ColoredLineChartViewController.h ./ChartsDemo-iOS/Objective-C/Demos/HalfPieChartViewController.h ./ChartsDemo-iOS/Objective-C/Demos/BarChartViewController.m ./ChartsDemo-iOS/Objective-C/Demos/RadarChartViewController.m ./ChartsDemo-iOS/Objective-C/Demos/CombinedChartViewController.m ./ChartsDemo-iOS/Objective-C/Demos/PieChartViewController.m ./ChartsDemo-iOS/Objective-C/Demos/MultipleBarChartViewController.h ./ChartsDemo-iOS/Objective-C/Demos/LineChart1ViewController.h ./ChartsDemo-iOS/Objective-C/Demos/PositiveNegativeBarChartViewController.h ./ChartsDemo-iOS/Objective-C/Demos/CandleStickChartViewController.m ./ChartsDemo-iOS/Objective-C/Demos/BubbleChartViewController.m ./ChartsDemo-iOS/Objective-C/Demos/LineChart2ViewController.m ./ChartsDemo-iOS/Objective-C/Demos/HorizontalBarChartViewController.m ./ChartsDemo-iOS/Objective-C/Demos/PiePolylineChartViewController.h ./ChartsDemo-iOS/Objective-C/Demos/LineChartFilledViewController.m ./ChartsDemo-iOS/Objective-C/Demos/NegativeStackedBarChartViewController.h ./ChartsDemo-iOS/Objective-C/Demos/CubicLineChartViewController.h ./ChartsDemo-iOS/Objective-C/Demos/SinusBarChartViewController.h ./ChartsDemo-iOS/Objective-C/Demos/LineChartTimeViewController.h ./ChartsDemo-iOS/Objective-C/Demos/MultipleLinesChartViewController.m ./ChartsDemo-iOS/Objective-C/Demos/ColoredLineChartViewController.m ./ChartsDemo-iOS/Objective-C/Demos/StackedBarChartViewController.h ./ChartsDemo-iOS/Objective-C/Demos/AnotherBarChartViewController.m ./ChartsDemo-iOS/Objective-C/Demos/ScatterChartViewController.h ./ChartsDemo-iOS/Objective-C/Demos/CandleStickChartViewController.h ./ChartsDemo-iOS/Objective-C/Demos/LineChart1ViewController.m ./ChartsDemo-iOS/Objective-C/Demos/PositiveNegativeBarChartViewController.m ./ChartsDemo-iOS/Objective-C/Demos/PieChartViewController.h ./ChartsDemo-iOS/Objective-C/Demos/MultipleBarChartViewController.m ./ChartsDemo-iOS/Objective-C/Demos/CombinedChartViewController.h ./ChartsDemo-iOS/Objective-C/Demos/RadarChartViewController.h ./ChartsDemo-iOS/Objective-C/Demos/BarChartViewController.h ./ChartsDemo-iOS/Objective-C/Demos/HalfPieChartViewController.m ./ChartsDemo-iOS/Objective-C/Demos/LineChartFilledViewController.h ./ChartsDemo-iOS/Objective-C/Demos/PiePolylineChartViewController.m ./ChartsDemo-iOS/Objective-C/Demos/HorizontalBarChartViewController.h ./ChartsDemo-iOS/Objective-C/Demos/LineChart2ViewController.h ./ChartsDemo-iOS/Objective-C/Demos/BubbleChartViewController.h ./scripts/copy-carthage-frameworks.sh ./scripts/build-dependencies.sh ./Package.swift ./Charts.xcodeproj/project.pbxproj ./Charts.xcodeproj/xcshareddata/xcschemes/ChartsTests.xcscheme ./Charts.xcodeproj/xcshareddata/xcschemes/Charts.xcscheme ./Gemfile ./Gemfile.lock ./.git/config ./.git/shallow ./.git/objects/pack/pack-43c06473a96ba43e31d3dd754747dd1ef0ebd62d.pack ./.git/objects/pack/pack-43c06473a96ba43e31d3dd754747dd1ef0ebd62d.idx ./.git/HEAD ./.git/info/exclude ./.git/logs/HEAD ./.git/logs/refs/heads/master ./.git/logs/refs/remotes/origin/HEAD ./.git/description ./.git/hooks/commit-msg.sample ./.git/hooks/pre-rebase.sample ./.git/hooks/pre-commit.sample ./.git/hooks/applypatch-msg.sample ./.git/hooks/fsmonitor-watchman.sample ./.git/hooks/pre-receive.sample ./.git/hooks/prepare-commit-msg.sample ./.git/hooks/post-update.sample ./.git/hooks/pre-merge-commit.sample ./.git/hooks/pre-applypatch.sample ./.git/hooks/pre-push.sample ./.git/hooks/update.sample ./.git/refs/heads/master ./.git/refs/tags/v3.3.0 ./.git/refs/tags/v3.0.0 ./.git/refs/tags/v3.0.1 ./.git/refs/tags/v3.2.2 ./.git/refs/tags/v3.4.0 ./.git/refs/tags/3.0.1 ./.git/refs/tags/3.0.0 ./.git/refs/tags/v3.5.0 ./.git/refs/tags/v3.6.0 ./.git/refs/tags/v3.0.2 ./.git/refs/tags/3.0.2 ./.git/refs/remotes/origin/HEAD ./.git/index ./.git/packed-refs ./vendor/bundle/ruby/2.6.0/specifications/escape-0.0.4.gemspec ./vendor/bundle/ruby/2.6.0/specifications/cocoapods-try-1.1.0.gemspec ./vendor/bundle/ruby/2.6.0/specifications/thread_safe-0.3.6.gemspec ./vendor/bundle/ruby/2.6.0/specifications/cocoapods-downloader-1.3.0.gemspec ./vendor/bundle/ruby/2.6.0/specifications/github_changelog_generator-1.15.2.gemspec ./vendor/bundle/ruby/2.6.0/specifications/xcpretty-0.3.0.gemspec ./vendor/bundle/ruby/2.6.0/specifications/ffi-1.12.2.gemspec ./vendor/bundle/ruby/2.6.0/specifications/algoliasearch-1.27.1.gemspec ./vendor/bundle/ruby/2.6.0/specifications/cocoapods-trunk-1.4.1.gemspec ./vendor/bundle/ruby/2.6.0/specifications/public_suffix-4.0.4.gemspec ./vendor/bundle/ruby/2.6.0/specifications/cocoapods-plugins-1.0.0.gemspec ./vendor/bundle/ruby/2.6.0/specifications/retriable-3.1.2.gemspec ./vendor/bundle/ruby/2.6.0/specifications/claide-1.0.3.gemspec ./vendor/bundle/ruby/2.6.0/specifications/multipart-post-2.1.1.gemspec ./vendor/bundle/ruby/2.6.0/specifications/faraday-http-cache-2.2.0.gemspec ./vendor/bundle/ruby/2.6.0/specifications/ruby-macho-1.4.0.gemspec ./vendor/bundle/ruby/2.6.0/specifications/fuzzy_match-2.0.4.gemspec ./vendor/bundle/ruby/2.6.0/specifications/netrc-0.11.0.gemspec ./vendor/bundle/ruby/2.6.0/specifications/activesupport-4.2.11.1.gemspec ./vendor/bundle/ruby/2.6.0/specifications/i18n-0.9.5.gemspec ./vendor/bundle/ruby/2.6.0/specifications/rainbow-3.0.0.gemspec ./vendor/bundle/ruby/2.6.0/specifications/httpclient-2.8.3.gemspec ./vendor/bundle/ruby/2.6.0/specifications/nap-1.1.0.gemspec ./vendor/bundle/ruby/2.6.0/specifications/rouge-2.0.7.gemspec ./vendor/bundle/ruby/2.6.0/specifications/tzinfo-1.2.7.gemspec ./vendor/bundle/ruby/2.6.0/specifications/cocoapods-search-1.0.0.gemspec ./vendor/bundle/ruby/2.6.0/specifications/minitest-5.14.0.gemspec ./vendor/bundle/ruby/2.6.0/specifications/xcodeproj-1.16.0.gemspec ./vendor/bundle/ruby/2.6.0/specifications/typhoeus-1.3.1.gemspec ./vendor/bundle/ruby/2.6.0/specifications/cocoapods-deintegrate-1.0.4.gemspec ./vendor/bundle/ruby/2.6.0/specifications/sawyer-0.8.2.gemspec ./vendor/bundle/ruby/2.6.0/specifications/json-2.3.0.gemspec ./vendor/bundle/ruby/2.6.0/specifications/faraday-1.0.1.gemspec ./vendor/bundle/ruby/2.6.0/specifications/gh_inspector-1.1.3.gemspec ./vendor/bundle/ruby/2.6.0/specifications/cocoapods-1.9.1.gemspec ./vendor/bundle/ruby/2.6.0/specifications/molinillo-0.6.6.gemspec ./vendor/bundle/ruby/2.6.0/specifications/nanaimo-0.2.6.gemspec ./vendor/bundle/ruby/2.6.0/specifications/fourflusher-2.3.1.gemspec ./vendor/bundle/ruby/2.6.0/specifications/multi_json-1.14.1.gemspec ./vendor/bundle/ruby/2.6.0/specifications/cocoapods-core-1.9.1.gemspec ./vendor/bundle/ruby/2.6.0/specifications/CFPropertyList-3.0.2.gemspec ./vendor/bundle/ruby/2.6.0/specifications/octokit-4.18.0.gemspec ./vendor/bundle/ruby/2.6.0/specifications/cocoapods-stats-1.1.0.gemspec ./vendor/bundle/ruby/2.6.0/specifications/colored2-3.1.2.gemspec ./vendor/bundle/ruby/2.6.0/specifications/rake-13.0.1.gemspec ./vendor/bundle/ruby/2.6.0/specifications/addressable-2.7.0.gemspec ./vendor/bundle/ruby/2.6.0/specifications/atomos-0.1.3.gemspec ./vendor/bundle/ruby/2.6.0/specifications/ethon-0.12.0.gemspec ./vendor/bundle/ruby/2.6.0/specifications/concurrent-ruby-1.1.6.gemspec ./vendor/bundle/ruby/2.6.0/cache/sawyer-0.8.2.gem ./vendor/bundle/ruby/2.6.0/cache/faraday-1.0.1.gem ./vendor/bundle/ruby/2.6.0/cache/cocoapods-downloader-1.3.0.gem ./vendor/bundle/ruby/2.6.0/cache/fourflusher-2.3.1.gem ./vendor/bundle/ruby/2.6.0/cache/rouge-2.0.7.gem ./vendor/bundle/ruby/2.6.0/cache/public_suffix-4.0.4.gem ./vendor/bundle/ruby/2.6.0/cache/cocoapods-deintegrate-1.0.4.gem ./vendor/bundle/ruby/2.6.0/cache/faraday-http-cache-2.2.0.gem ./vendor/bundle/ruby/2.6.0/cache/minitest-5.14.0.gem ./vendor/bundle/ruby/2.6.0/cache/tzinfo-1.2.7.gem ./vendor/bundle/ruby/2.6.0/cache/addressable-2.7.0.gem ./vendor/bundle/ruby/2.6.0/cache/typhoeus-1.3.1.gem ./vendor/bundle/ruby/2.6.0/cache/xcpretty-0.3.0.gem ./vendor/bundle/ruby/2.6.0/cache/fuzzy_match-2.0.4.gem ./vendor/bundle/ruby/2.6.0/cache/cocoapods-try-1.1.0.gem ./vendor/bundle/ruby/2.6.0/cache/json-2.3.0.gem ./vendor/bundle/ruby/2.6.0/cache/ethon-0.12.0.gem ./vendor/bundle/ruby/2.6.0/cache/activesupport-4.2.11.1.gem ./vendor/bundle/ruby/2.6.0/cache/multipart-post-2.1.1.gem ./vendor/bundle/ruby/2.6.0/cache/netrc-0.11.0.gem ./vendor/bundle/ruby/2.6.0/cache/github_changelog_generator-1.15.2.gem ./vendor/bundle/ruby/2.6.0/cache/nap-1.1.0.gem ./vendor/bundle/ruby/2.6.0/cache/cocoapods-stats-1.1.0.gem ./vendor/bundle/ruby/2.6.0/cache/thread_safe-0.3.6.gem ./vendor/bundle/ruby/2.6.0/cache/octokit-4.18.0.gem ./vendor/bundle/ruby/2.6.0/cache/rake-13.0.1.gem ./vendor/bundle/ruby/2.6.0/cache/cocoapods-plugins-1.0.0.gem ./vendor/bundle/ruby/2.6.0/cache/i18n-0.9.5.gem ./vendor/bundle/ruby/2.6.0/cache/rainbow-3.0.0.gem ./vendor/bundle/ruby/2.6.0/cache/nanaimo-0.2.6.gem ./vendor/bundle/ruby/2.6.0/cache/concurrent-ruby-1.1.6.gem ./vendor/bundle/ruby/2.6.0/cache/ruby-macho-1.4.0.gem ./vendor/bundle/ruby/2.6.0/cache/cocoapods-search-1.0.0.gem ./vendor/bundle/ruby/2.6.0/cache/molinillo-0.6.6.gem ./vendor/bundle/ruby/2.6.0/cache/multi_json-1.14.1.gem ./vendor/bundle/ruby/2.6.0/cache/cocoapods-trunk-1.4.1.gem ./vendor/bundle/ruby/2.6.0/cache/atomos-0.1.3.gem ./vendor/bundle/ruby/2.6.0/cache/escape-0.0.4.gem ./vendor/bundle/ruby/2.6.0/cache/colored2-3.1.2.gem ./vendor/bundle/ruby/2.6.0/cache/claide-1.0.3.gem ./vendor/bundle/ruby/2.6.0/cache/httpclient-2.8.3.gem ./vendor/bundle/ruby/2.6.0/cache/retriable-3.1.2.gem ./vendor/bundle/ruby/2.6.0/cache/cocoapods-1.9.1.gem ./vendor/bundle/ruby/2.6.0/cache/algoliasearch-1.27.1.gem ./vendor/bundle/ruby/2.6.0/cache/CFPropertyList-3.0.2.gem ./vendor/bundle/ruby/2.6.0/cache/ffi-1.12.2.gem ./vendor/bundle/ruby/2.6.0/cache/gh_inspector-1.1.3.gem ./vendor/bundle/ruby/2.6.0/cache/xcodeproj-1.16.0.gem ./vendor/bundle/ruby/2.6.0/cache/cocoapods-core-1.9.1.gem ./vendor/bundle/ruby/2.6.0/bin/sandbox-pod ./vendor/bundle/ruby/2.6.0/bin/pod ./vendor/bundle/ruby/2.6.0/bin/httpclient ./vendor/bundle/ruby/2.6.0/bin/xcpretty ./vendor/bundle/ruby/2.6.0/bin/github_changelog_generator ./vendor/bundle/ruby/2.6.0/bin/xcodeproj ./vendor/bundle/ruby/2.6.0/bin/rake ./vendor/bundle/ruby/2.6.0/bin/git-generate-changelog ./vendor/bundle/ruby/2.6.0/bin/rougify ./vendor/bundle/ruby/2.6.0/bin/fuzzy_match ./vendor/bundle/ruby/2.6.0/extensions/x86_64-darwin-18/2.6.0/json-2.3.0/gem_make.out ./vendor/bundle/ruby/2.6.0/extensions/x86_64-darwin-18/2.6.0/json-2.3.0/gem.build_complete ./vendor/bundle/ruby/2.6.0/extensions/x86_64-darwin-18/2.6.0/json-2.3.0/mkmf.log ./vendor/bundle/ruby/2.6.0/extensions/x86_64-darwin-18/2.6.0/json-2.3.0/json/ext/generator.bundle ./vendor/bundle/ruby/2.6.0/extensions/x86_64-darwin-18/2.6.0/json-2.3.0/json/ext/parser.bundle ./vendor/bundle/ruby/2.6.0/extensions/x86_64-darwin-18/2.6.0/ffi-1.12.2/gem_make.out ./vendor/bundle/ruby/2.6.0/extensions/x86_64-darwin-18/2.6.0/ffi-1.12.2/gem.build_complete ./vendor/bundle/ruby/2.6.0/extensions/x86_64-darwin-18/2.6.0/ffi-1.12.2/ffi_c.bundle ./vendor/bundle/ruby/2.6.0/extensions/x86_64-darwin-18/2.6.0/ffi-1.12.2/mkmf.log ./vendor/bundle/ruby/2.6.0/gems/nanaimo-0.2.6/.rspec ./vendor/bundle/ruby/2.6.0/gems/nanaimo-0.2.6/nanaimo.gemspec ./vendor/bundle/ruby/2.6.0/gems/nanaimo-0.2.6/bin/setup ./vendor/bundle/ruby/2.6.0/gems/nanaimo-0.2.6/bin/console ./vendor/bundle/ruby/2.6.0/gems/nanaimo-0.2.6/Rakefile ./vendor/bundle/ruby/2.6.0/gems/nanaimo-0.2.6/lib/nanaimo/unicode/quote_maps.rb ./vendor/bundle/ruby/2.6.0/gems/nanaimo-0.2.6/lib/nanaimo/unicode/next_step_mapping.rb ./vendor/bundle/ruby/2.6.0/gems/nanaimo-0.2.6/lib/nanaimo/writer.rb ./vendor/bundle/ruby/2.6.0/gems/nanaimo-0.2.6/lib/nanaimo/reader.rb ./vendor/bundle/ruby/2.6.0/gems/nanaimo-0.2.6/lib/nanaimo/writer/xml.rb ./vendor/bundle/ruby/2.6.0/gems/nanaimo-0.2.6/lib/nanaimo/writer/pbxproj.rb ./vendor/bundle/ruby/2.6.0/gems/nanaimo-0.2.6/lib/nanaimo/version.rb ./vendor/bundle/ruby/2.6.0/gems/nanaimo-0.2.6/lib/nanaimo/object.rb ./vendor/bundle/ruby/2.6.0/gems/nanaimo-0.2.6/lib/nanaimo/unicode.rb ./vendor/bundle/ruby/2.6.0/gems/nanaimo-0.2.6/lib/nanaimo/plist.rb ./vendor/bundle/ruby/2.6.0/gems/nanaimo-0.2.6/lib/nanaimo.rb ./vendor/bundle/ruby/2.6.0/gems/nanaimo-0.2.6/Gemfile ./vendor/bundle/ruby/2.6.0/gems/nanaimo-0.2.6/Gemfile.lock ./vendor/bundle/ruby/2.6.0/gems/atomos-0.1.3/.rspec ./vendor/bundle/ruby/2.6.0/gems/atomos-0.1.3/atomos.gemspec ./vendor/bundle/ruby/2.6.0/gems/atomos-0.1.3/bin/rake ./vendor/bundle/ruby/2.6.0/gems/atomos-0.1.3/bin/setup ./vendor/bundle/ruby/2.6.0/gems/atomos-0.1.3/bin/rubocop ./vendor/bundle/ruby/2.6.0/gems/atomos-0.1.3/bin/rspec ./vendor/bundle/ruby/2.6.0/gems/atomos-0.1.3/bin/console ./vendor/bundle/ruby/2.6.0/gems/atomos-0.1.3/Rakefile ./vendor/bundle/ruby/2.6.0/gems/atomos-0.1.3/VERSION ./vendor/bundle/ruby/2.6.0/gems/atomos-0.1.3/lib/atomos/version.rb ./vendor/bundle/ruby/2.6.0/gems/atomos-0.1.3/lib/atomos.rb ./vendor/bundle/ruby/2.6.0/gems/atomos-0.1.3/Gemfile ./vendor/bundle/ruby/2.6.0/gems/atomos-0.1.3/Gemfile.lock ./vendor/bundle/ruby/2.6.0/gems/cocoapods-stats-1.1.0/spec/spec_helper.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-stats-1.1.0/spec/env_validator_spec.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-stats-1.1.0/spec/stats_spec.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-stats-1.1.0/spec/target_mapper_spec.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-stats-1.1.0/spec/validator_spec.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-stats-1.1.0/Rakefile ./vendor/bundle/ruby/2.6.0/gems/cocoapods-stats-1.1.0/lib/cocoapods_plugin.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-stats-1.1.0/lib/cocoapods_stats.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-stats-1.1.0/lib/cocoapods_stats/gem_version.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-stats-1.1.0/lib/cocoapods_stats/target_mapper.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-stats-1.1.0/lib/cocoapods_stats/sender.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-stats-1.1.0/Gemfile ./vendor/bundle/ruby/2.6.0/gems/cocoapods-stats-1.1.0/Gemfile.lock ./vendor/bundle/ruby/2.6.0/gems/cocoapods-stats-1.1.0/cocoapods-stats.gemspec ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/LICENSE ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/bin/sandbox-pod ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/bin/pod ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/xcode/xcframework/xcframework_slice.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/xcode/linkage_analyzer.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/xcode/framework_paths.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/xcode/xcframework.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/version_metadata.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/gem_version.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/project.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/open-uri.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/resolver.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/external_sources/downloader_source.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/external_sources/path_source.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/external_sources/podspec_source.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/external_sources/abstract_external_source.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/target/build_settings.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/target/pod_target.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/target/aggregate_target.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/executable.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/sources_manager.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/target.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/podfile.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/sandbox.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/external_sources.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/downloader/response.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/downloader/request.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/downloader/cache.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/installer.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/generator/prefix_header.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/generator/info_plist_file.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/generator/embed_frameworks_script.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/generator/constant.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/generator/copy_resources_script.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/generator/module_map.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/generator/dummy_source.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/generator/acknowledgements/markdown.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/generator/acknowledgements/plist.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/generator/app_target_helper.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/generator/prepare_artifacts_script.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/generator/umbrella_header.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/generator/header.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/generator/acknowledgements.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/generator/bridge_support.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/generator/file_list.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/sandbox/file_accessor.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/sandbox/pod_dir_cleaner.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/sandbox/path_list.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/sandbox/headers_store.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/sandbox/podspec_finder.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/user_interface/error_report.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/user_interface/inspector_reporter.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/core_overrides.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/config.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/command/options/project_directory.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/command/options/repo_update.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/command/outdated.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/command/cache/clean.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/command/cache/list.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/command/install.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/command/init.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/command/repo.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/command/spec/lint.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/command/spec/which.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/command/spec/edit.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/command/spec/cat.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/command/spec/create.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/command/setup.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/command/spec.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/command/cache.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/command/ipc.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/command/lib/lint.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/command/lib/create.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/command/ipc/update_search_index.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/command/ipc/podfile.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/command/ipc/podfile_json.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/command/ipc/spec.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/command/ipc/repl.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/command/ipc/list.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/command/env.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/command/list.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/command/lib.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/command/update.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/command/repo/lint.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/command/repo/push.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/command/repo/add_cdn.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/command/repo/remove.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/command/repo/add.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/command/repo/list.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/command/repo/update.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/command.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/xcode.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/native_target_extension.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/downloader.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/installer/xcode/single_pods_project_generator.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/installer/xcode/pods_project_generator.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/installer/xcode/pods_project_generator_result.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/installer/xcode/pods_project_generator/pod_target_installer.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/installer/xcode/pods_project_generator/pod_target_integrator.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/installer/xcode/pods_project_generator/target_installer.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/installer/xcode/pods_project_generator/aggregate_target_installer.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/installer/xcode/pods_project_generator/target_installer_helper.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/installer/xcode/pods_project_generator/project_generator.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/installer/xcode/pods_project_generator/app_host_installer.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/installer/xcode/pods_project_generator/aggregate_target_dependency_installer.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/installer/xcode/pods_project_generator/pods_project_writer.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/installer/xcode/pods_project_generator/file_references_installer.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/installer/xcode/pods_project_generator/target_installation_result.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/installer/xcode/pods_project_generator/pod_target_dependency_installer.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/installer/xcode/multi_pods_project_generator.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/installer/xcode/target_validator.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/installer/sandbox_header_paths_installer.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/installer/target_uuid_generator.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/installer/sandbox_dir_cleaner.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/installer/pre_install_hooks_context.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/installer/post_install_hooks_context.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/installer/podfile_validator.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/installer/installation_options.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/installer/project_cache/target_metadata.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/installer/project_cache/project_cache.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/installer/project_cache/project_metadata_cache.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/installer/project_cache/project_cache_version.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/installer/project_cache/project_installation_cache.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/installer/project_cache/target_cache_key.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/installer/project_cache/project_cache_analyzer.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/installer/project_cache/project_cache_analysis_result.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/installer/analyzer.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/installer/pod_source_installer.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/installer/user_project_integrator/target_integrator/xcconfig_integrator.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/installer/user_project_integrator/target_integrator.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/installer/xcode.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/installer/source_provider_hooks_context.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/installer/user_project_integrator.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/installer/analyzer/specs_state.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/installer/analyzer/sandbox_analyzer.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/installer/analyzer/podfile_dependency_cache.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/installer/analyzer/locking_dependency_analyzer.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/installer/analyzer/pod_variant_set.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/installer/analyzer/analysis_result.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/installer/analyzer/pod_variant.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/installer/analyzer/target_inspector.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/installer/analyzer/target_inspection_result.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/installer/pod_source_preparer.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/user_interface.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/hooks_manager.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/validator.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/resolver/resolver_specification.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-1.9.1/lib/cocoapods/resolver/lazy_specification.rb ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/tools/diff.sh ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/tools/fuzz.rb ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/tools/server.rb ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/install.rb ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/LICENSE ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/ext/json/Makefile ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/ext/json/ext/fbuffer/fbuffer.h ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/ext/json/ext/parser/parser.h ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/ext/json/ext/parser/Makefile ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/ext/json/ext/parser/parser.o ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/ext/json/ext/parser/parser.rl ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/ext/json/ext/parser/.sitearchdir.-.json.-.ext.time ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/ext/json/ext/parser/parser.bundle ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/ext/json/ext/parser/extconf.rb ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/ext/json/ext/parser/parser.c ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/ext/json/ext/parser/depend ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/ext/json/ext/generator/Makefile ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/ext/json/ext/generator/generator.c ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/ext/json/ext/generator/.sitearchdir.-.json.-.ext.time ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/ext/json/ext/generator/generator.bundle ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/ext/json/ext/generator/extconf.rb ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/ext/json/ext/generator/depend ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/ext/json/ext/generator/generator.h ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/ext/json/ext/generator/generator.o ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/ext/json/extconf.rb ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/diagrams/.keep ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/tests/json_common_interface_test.rb ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/tests/json_addition_test.rb ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/tests/json_fixtures_test.rb ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/tests/json_ext_parser_test.rb ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/tests/json_string_matching_test.rb ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/tests/json_generic_object_test.rb ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/tests/fixtures/fail3.json ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/tests/fixtures/fail12.json ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/tests/fixtures/fail28.json ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/tests/fixtures/pass17.json ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/tests/fixtures/fail24.json ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/tests/fixtures/fail25.json ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/tests/fixtures/pass16.json ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/tests/fixtures/fail13.json ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/tests/fixtures/fail2.json ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/tests/fixtures/fail9.json ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/tests/fixtures/fail18.json ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/tests/fixtures/fail22.json ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/tests/fixtures/fail5.json ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/tests/fixtures/fail14.json ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/tests/fixtures/pass1.json ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/tests/fixtures/obsolete_fail1.json ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/tests/fixtures/pass26.json ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/tests/fixtures/fail4.json ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/tests/fixtures/fail23.json ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/tests/fixtures/fail19.json ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/tests/fixtures/fail8.json ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/tests/fixtures/fail20.json ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/tests/fixtures/pass3.json ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/tests/fixtures/fail7.json ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/tests/fixtures/fail6.json ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/tests/fixtures/pass2.json ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/tests/fixtures/fail21.json ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/tests/fixtures/fail10.json ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/tests/fixtures/pass15.json ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/tests/fixtures/fail27.json ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/tests/fixtures/fail11.json ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/tests/json_generator_test.rb ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/tests/test_helper.rb ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/tests/json_encoding_test.rb ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/tests/json_parser_test.rb ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/java/src/json/ext/Parser.java ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/java/src/json/ext/ByteListTranscoder.java ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/java/src/json/ext/GeneratorService.java ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/java/src/json/ext/Utils.java ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/java/src/json/ext/StringDecoder.java ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/java/src/json/ext/Parser.rl ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/java/src/json/ext/RuntimeInfo.java ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/java/src/json/ext/GeneratorState.java ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/java/src/json/ext/OptionsReader.java ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/java/src/json/ext/ParserService.java ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/java/src/json/ext/GeneratorMethods.java ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/java/src/json/ext/StringEncoder.java ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/java/src/json/ext/Generator.java ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/Rakefile ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/VERSION ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/json-java.gemspec ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/lib/json.rb ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/lib/json/ext.rb ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/lib/json/ext/.keep ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/lib/json/ext/generator.bundle ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/lib/json/ext/parser.bundle ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/lib/json/common.rb ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/lib/json/add/complex.rb ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/lib/json/add/date.rb ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/lib/json/add/struct.rb ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/lib/json/add/bigdecimal.rb ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/lib/json/add/date_time.rb ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/lib/json/add/set.rb ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/lib/json/add/ostruct.rb ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/lib/json/add/regexp.rb ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/lib/json/add/symbol.rb ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/lib/json/add/core.rb ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/lib/json/add/range.rb ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/lib/json/add/rational.rb ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/lib/json/add/time.rb ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/lib/json/add/exception.rb ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/lib/json/pure.rb ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/lib/json/version.rb ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/lib/json/generic_object.rb ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/lib/json/pure/parser.rb ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/lib/json/pure/generator.rb ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/Gemfile ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/json_pure.gemspec ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/json.gemspec ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/LICENSE ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/bin/rougify ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/rouge.gemspec ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/scheme.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/clojure.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/json.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/toml.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/scala.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/groovy.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/rust.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/vue.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/idlang.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/praat.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/php.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/sql.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/ini.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/abap.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/fortran.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/racket.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/haskell.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/julia.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/javascript.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/literate_coffeescript.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/qml.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/protobuf.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/gherkin/keywords.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/http.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/actionscript.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/swift.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/puppet.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/markdown.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/prometheus.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/scss.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/kotlin.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/make.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/viml/keywords.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/diff.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/factor.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/python.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/go.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/viml.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/css.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/yaml.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/pascal.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/turtle.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/vala.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/nasm.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/llvm.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/gradle.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/coffeescript.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/coq.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/csharp.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/c.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/tcl.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/tap.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/eiffel.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/apple_script.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/php/builtins.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/elixir.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/apiblueprint.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/nginx.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/twig.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/lua/builtins.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/nim.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/dart.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/d.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/sass.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/matlab.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/ruby.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/json_doc.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/fsharp.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/xml.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/cpp.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/docker.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/verilog.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/smarty.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/erb.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/jinja.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/shell_session.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/slim.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/vhdl.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/bsl.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/apache.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/jsx.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/prolog.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/matlab/builtins.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/jsonnet.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/ceylon.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/powershell.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/cfscript.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/liquid.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/moonscript.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/perl.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/typescript.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/sed.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/cmake.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/smalltalk.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/io.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/shell.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/html.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/objective_c.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/conf.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/haml.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/handlebars.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/vb.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/erlang.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/tulip.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/ocaml.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/mxml.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/literate_haskell.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/properties.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/tex.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/r.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/sass/common.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/java.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/glsl.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/common_lisp.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/lua.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/biml.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/sml.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/plain_text.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexers/gherkin.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/plugins/redcarpet.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/guesser.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/lexer.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/formatters/html_linewise.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/formatters/terminal256.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/formatters/html_legacy.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/formatters/html_pygments.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/formatters/null.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/formatters/html.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/formatters/html_inline.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/formatters/html_table.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/cli.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/guessers/source.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/guessers/filename.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/guessers/glob_mapping.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/guessers/mimetype.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/guessers/modeline.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/regex_lexer.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/template_lexer.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/text_analyzer.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/util.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/version.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/token.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/theme.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/themes/monokai_sublime.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/themes/github.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/themes/base16.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/themes/thankful_eyes.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/themes/molokai.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/themes/colorful.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/themes/monokai.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/themes/tulip.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/themes/gruvbox.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/ocaml ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/scheme ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/literate_haskell ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/pascal ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/applescript ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/ceylon ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/plaintext ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/prolog ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/haml ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/toml ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/moonscript ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/tex ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/docker ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/go ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/racket ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/nim ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/turtle ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/qml ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/cmake ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/python ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/css ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/clojure ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/elixir ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/sed ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/jinja ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/idlang ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/gherkin ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/dart ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/shell ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/cfscript ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/markdown ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/scss ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/perl ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/typescript ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/smalltalk ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/vue ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/rust ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/viml ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/io ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/erlang ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/llvm ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/fsharp ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/r ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/liquid ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/nasm ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/java ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/diff ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/abap ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/kotlin ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/smarty ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/haskell ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/factor ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/php ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/tap ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/bsl ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/lua ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/praat ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/xml ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/literate_coffeescript ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/gradle ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/vb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/glsl ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/tulip ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/powershell ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/common_lisp ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/vhdl ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/tcl ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/ini ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/json ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/properties ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/verilog ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/handlebars ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/nginx ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/scala ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/http ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/vala ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/cpp ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/swift ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/make ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/matlab ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/jsonnet ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/shell_session ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/fortran ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/sml ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/csharp ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/julia ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/prometheus ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/groovy ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/coffeescript ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/slim ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/javascript ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/twig ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/objective_c ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/mxml ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/eiffel ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/erb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/biml ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/sass ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/conf ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/coq ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/puppet ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/apiblueprint ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/c ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/d ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/jsx ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/apache ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/protobuf ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/ruby ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/actionscript ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/demos/sql ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/lib/rouge/formatter.rb ./vendor/bundle/ruby/2.6.0/gems/rouge-2.0.7/Gemfile ./vendor/bundle/ruby/2.6.0/gems/cocoapods-plugins-1.0.0/LICENSE ./vendor/bundle/ruby/2.6.0/gems/cocoapods-plugins-1.0.0/spec/spec_helper.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-plugins-1.0.0/spec/fixtures/unprefixed.gemspec ./vendor/bundle/ruby/2.6.0/gems/cocoapods-plugins-1.0.0/spec/fixtures/cocoapods-foo2.gemspec ./vendor/bundle/ruby/2.6.0/gems/cocoapods-plugins-1.0.0/spec/fixtures/cocoapods-foo1.gemspec ./vendor/bundle/ruby/2.6.0/gems/cocoapods-plugins-1.0.0/spec/fixtures/plugins.json ./vendor/bundle/ruby/2.6.0/gems/cocoapods-plugins-1.0.0/spec/command/gem_index_cache_spec.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-plugins-1.0.0/spec/command/plugins/list_spec.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-plugins-1.0.0/spec/command/plugins/search_spec.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-plugins-1.0.0/spec/command/plugins/installed_spec.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-plugins-1.0.0/spec/command/plugins/create_spec.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-plugins-1.0.0/spec/command/plugins/publish_spec.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-plugins-1.0.0/spec/command/plugins_helper_spec.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-plugins-1.0.0/spec/command/gem_helper_spec.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-plugins-1.0.0/spec/command/plugins_spec.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-plugins-1.0.0/Rakefile ./vendor/bundle/ruby/2.6.0/gems/cocoapods-plugins-1.0.0/cocoapods-plugins.gemspec ./vendor/bundle/ruby/2.6.0/gems/cocoapods-plugins-1.0.0/lib/pod/command/plugins_helper.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-plugins-1.0.0/lib/pod/command/plugins/publish.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-plugins-1.0.0/lib/pod/command/plugins/installed.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-plugins-1.0.0/lib/pod/command/plugins/search.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-plugins-1.0.0/lib/pod/command/plugins/list.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-plugins-1.0.0/lib/pod/command/plugins/create.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-plugins-1.0.0/lib/pod/command/plugins.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-plugins-1.0.0/lib/pod/command/gem_helper.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-plugins-1.0.0/lib/pod/command/gem_index_cache.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-plugins-1.0.0/lib/cocoapods_plugin.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-plugins-1.0.0/lib/cocoapods_plugins.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-plugins-1.0.0/Gemfile ./vendor/bundle/ruby/2.6.0/gems/cocoapods-plugins-1.0.0/Gemfile.lock ./vendor/bundle/ruby/2.6.0/gems/cocoapods-plugins-1.0.0/plugins.json ./vendor/bundle/ruby/2.6.0/gems/netrc-0.11.0/test/test_netrc.rb ./vendor/bundle/ruby/2.6.0/gems/netrc-0.11.0/test/test_parse.rb ./vendor/bundle/ruby/2.6.0/gems/netrc-0.11.0/test/test_lex.rb ./vendor/bundle/ruby/2.6.0/gems/netrc-0.11.0/lib/netrc.rb ./vendor/bundle/ruby/2.6.0/gems/netrc-0.11.0/data/default_only.netrc ./vendor/bundle/ruby/2.6.0/gems/netrc-0.11.0/data/sample.netrc ./vendor/bundle/ruby/2.6.0/gems/netrc-0.11.0/data/sample_multi.netrc ./vendor/bundle/ruby/2.6.0/gems/netrc-0.11.0/data/newlineless.netrc ./vendor/bundle/ruby/2.6.0/gems/netrc-0.11.0/data/permissive.netrc ./vendor/bundle/ruby/2.6.0/gems/netrc-0.11.0/data/login.netrc ./vendor/bundle/ruby/2.6.0/gems/netrc-0.11.0/data/sample_multi_with_default.netrc ./vendor/bundle/ruby/2.6.0/gems/netrc-0.11.0/data/sample_with_default.netrc ./vendor/bundle/ruby/2.6.0/gems/netrc-0.11.0/data/password.netrc ./vendor/bundle/ruby/2.6.0/gems/cocoapods-downloader-1.3.0/LICENSE ./vendor/bundle/ruby/2.6.0/gems/cocoapods-downloader-1.3.0/README.markdown ./vendor/bundle/ruby/2.6.0/gems/cocoapods-downloader-1.3.0/lib/cocoapods-downloader/base.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-downloader-1.3.0/lib/cocoapods-downloader/scp.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-downloader-1.3.0/lib/cocoapods-downloader/gem_version.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-downloader-1.3.0/lib/cocoapods-downloader/subversion.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-downloader-1.3.0/lib/cocoapods-downloader/http.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-downloader-1.3.0/lib/cocoapods-downloader/api.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-downloader-1.3.0/lib/cocoapods-downloader/bazaar.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-downloader-1.3.0/lib/cocoapods-downloader/api_exposable.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-downloader-1.3.0/lib/cocoapods-downloader/mercurial.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-downloader-1.3.0/lib/cocoapods-downloader/remote_file.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-downloader-1.3.0/lib/cocoapods-downloader/git.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-downloader-1.3.0/lib/cocoapods-downloader.rb ./vendor/bundle/ruby/2.6.0/gems/ethon-0.12.0/Guardfile ./vendor/bundle/ruby/2.6.0/gems/ethon-0.12.0/.rspec ./vendor/bundle/ruby/2.6.0/gems/ethon-0.12.0/LICENSE ./vendor/bundle/ruby/2.6.0/gems/ethon-0.12.0/spec/spec_helper.rb ./vendor/bundle/ruby/2.6.0/gems/ethon-0.12.0/spec/ethon/easy/operations_spec.rb ./vendor/bundle/ruby/2.6.0/gems/ethon-0.12.0/spec/ethon/easy/response_callbacks_spec.rb ./vendor/bundle/ruby/2.6.0/gems/ethon-0.12.0/spec/ethon/easy/features_spec.rb ./vendor/bundle/ruby/2.6.0/gems/ethon-0.12.0/spec/ethon/easy/options_spec.rb ./vendor/bundle/ruby/2.6.0/gems/ethon-0.12.0/spec/ethon/easy/header_spec.rb ./vendor/bundle/ruby/2.6.0/gems/ethon-0.12.0/spec/ethon/easy/mirror_spec.rb ./vendor/bundle/ruby/2.6.0/gems/ethon-0.12.0/spec/ethon/easy/util_spec.rb ./vendor/bundle/ruby/2.6.0/gems/ethon-0.12.0/spec/ethon/easy/form_spec.rb ./vendor/bundle/ruby/2.6.0/gems/ethon-0.12.0/spec/ethon/easy/http/get_spec.rb ./vendor/bundle/ruby/2.6.0/gems/ethon-0.12.0/spec/ethon/easy/http/delete_spec.rb ./vendor/bundle/ruby/2.6.0/gems/ethon-0.12.0/spec/ethon/easy/http/head_spec.rb ./vendor/bundle/ruby/2.6.0/gems/ethon-0.12.0/spec/ethon/easy/http/options_spec.rb ./vendor/bundle/ruby/2.6.0/gems/ethon-0.12.0/spec/ethon/easy/http/post_spec.rb ./vendor/bundle/ruby/2.6.0/gems/ethon-0.12.0/spec/ethon/easy/http/put_spec.rb ./vendor/bundle/ruby/2.6.0/gems/ethon-0.12.0/spec/ethon/easy/http/custom_spec.rb ./vendor/bundle/ruby/2.6.0/gems/ethon-0.12.0/spec/ethon/easy/http/patch_spec.rb ./vendor/bundle/ruby/2.6.0/gems/ethon-0.12.0/spec/ethon/easy/callbacks_spec.rb ./vendor/bundle/ruby/2.6.0/gems/ethon-0.12.0/spec/ethon/easy/debug_info_spec.rb ./vendor/bundle/ruby/2.6.0/gems/ethon-0.12.0/spec/ethon/easy/informations_spec.rb ./vendor/bundle/ruby/2.6.0/gems/ethon-0.12.0/spec/ethon/easy/queryable_spec.rb ./vendor/bundle/ruby/2.6.0/gems/ethon-0.12.0/spec/ethon/easy/http_spec.rb ./vendor/bundle/ruby/2.6.0/gems/ethon-0.12.0/spec/ethon/curl_spec.rb ./vendor/bundle/ruby/2.6.0/gems/ethon-0.12.0/spec/ethon/loggable_spec.rb ./vendor/bundle/ruby/2.6.0/gems/ethon-0.12.0/spec/ethon/multi/operations_spec.rb ./vendor/bundle/ruby/2.6.0/gems/ethon-0.12.0/spec/ethon/multi/options_spec.rb ./vendor/bundle/ruby/2.6.0/gems/ethon-0.12.0/spec/ethon/multi/stack_spec.rb ./vendor/bundle/ruby/2.6.0/gems/ethon-0.12.0/spec/ethon/multi_spec.rb ./vendor/bundle/ruby/2.6.0/gems/ethon-0.12.0/spec/ethon/easy_spec.rb ./vendor/bundle/ruby/2.6.0/gems/ethon-0.12.0/spec/ethon/libc_spec.rb ./vendor/bundle/ruby/2.6.0/gems/ethon-0.12.0/spec/support/localhost_server.rb ./vendor/bundle/ruby/2.6.0/gems/ethon-0.12.0/spec/support/server.rb ./vendor/bundle/ruby/2.6.0/gems/ethon-0.12.0/Rakefile ./vendor/bundle/ruby/2.6.0/gems/ethon-0.12.0/profile/benchmarks.rb ./vendor/bundle/ruby/2.6.0/gems/ethon-0.12.0/profile/support/os_memory_leak_tracker.rb ./vendor/bundle/ruby/2.6.0/gems/ethon-0.12.0/profile/support/ruby_object_leak_tracker.rb ./vendor/bundle/ruby/2.6.0/gems/ethon-0.12.0/profile/support/memory_test_helpers.rb ./vendor/bundle/ruby/2.6.0/gems/ethon-0.12.0/profile/perf_spec_helper.rb ./vendor/bundle/ruby/2.6.0/gems/ethon-0.12.0/profile/memory_leaks.rb ./vendor/bundle/ruby/2.6.0/gems/ethon-0.12.0/lib/ethon.rb ./vendor/bundle/ruby/2.6.0/gems/ethon-0.12.0/lib/ethon/easy/http.rb ./vendor/bundle/ruby/2.6.0/gems/ethon-0.12.0/lib/ethon/easy/callbacks.rb ./vendor/bundle/ruby/2.6.0/gems/ethon-0.12.0/lib/ethon/easy/operations.rb ./vendor/bundle/ruby/2.6.0/gems/ethon-0.12.0/lib/ethon/easy/form.rb ./vendor/bundle/ruby/2.6.0/gems/ethon-0.12.0/lib/ethon/easy/features.rb ./vendor/bundle/ruby/2.6.0/gems/ethon-0.12.0/lib/ethon/easy/debug_info.rb ./vendor/bundle/ruby/2.6.0/gems/ethon-0.12.0/lib/ethon/easy/queryable.rb ./vendor/bundle/ruby/2.6.0/gems/ethon-0.12.0/lib/ethon/easy/response_callbacks.rb ./vendor/bundle/ruby/2.6.0/gems/ethon-0.12.0/lib/ethon/easy/http/get.rb ./vendor/bundle/ruby/2.6.0/gems/ethon-0.12.0/lib/ethon/easy/http/head.rb ./vendor/bundle/ruby/2.6.0/gems/ethon-0.12.0/lib/ethon/easy/http/postable.rb ./vendor/bundle/ruby/2.6.0/gems/ethon-0.12.0/lib/ethon/easy/http/putable.rb ./vendor/bundle/ruby/2.6.0/gems/ethon-0.12.0/lib/ethon/easy/http/actionable.rb ./vendor/bundle/ruby/2.6.0/gems/ethon-0.12.0/lib/ethon/easy/http/custom.rb ./vendor/bundle/ruby/2.6.0/gems/ethon-0.12.0/lib/ethon/easy/http/options.rb ./vendor/bundle/ruby/2.6.0/gems/ethon-0.12.0/lib/ethon/easy/http/post.rb ./vendor/bundle/ruby/2.6.0/gems/ethon-0.12.0/lib/ethon/easy/http/patch.rb ./vendor/bundle/ruby/2.6.0/gems/ethon-0.12.0/lib/ethon/easy/http/put.rb ./vendor/bundle/ruby/2.6.0/gems/ethon-0.12.0/lib/ethon/easy/http/delete.rb ./vendor/bundle/ruby/2.6.0/gems/ethon-0.12.0/lib/ethon/easy/util.rb ./vendor/bundle/ruby/2.6.0/gems/ethon-0.12.0/lib/ethon/easy/informations.rb ./vendor/bundle/ruby/2.6.0/gems/ethon-0.12.0/lib/ethon/easy/mirror.rb ./vendor/bundle/ruby/2.6.0/gems/ethon-0.12.0/lib/ethon/easy/header.rb ./vendor/bundle/ruby/2.6.0/gems/ethon-0.12.0/lib/ethon/easy/options.rb ./vendor/bundle/ruby/2.6.0/gems/ethon-0.12.0/lib/ethon/easy/params.rb ./vendor/bundle/ruby/2.6.0/gems/ethon-0.12.0/lib/ethon/loggable.rb ./vendor/bundle/ruby/2.6.0/gems/ethon-0.12.0/lib/ethon/errors.rb ./vendor/bundle/ruby/2.6.0/gems/ethon-0.12.0/lib/ethon/curls/classes.rb ./vendor/bundle/ruby/2.6.0/gems/ethon-0.12.0/lib/ethon/curls/form_options.rb ./vendor/bundle/ruby/2.6.0/gems/ethon-0.12.0/lib/ethon/curls/messages.rb ./vendor/bundle/ruby/2.6.0/gems/ethon-0.12.0/lib/ethon/curls/settings.rb ./vendor/bundle/ruby/2.6.0/gems/ethon-0.12.0/lib/ethon/curls/codes.rb ./vendor/bundle/ruby/2.6.0/gems/ethon-0.12.0/lib/ethon/curls/constants.rb ./vendor/bundle/ruby/2.6.0/gems/ethon-0.12.0/lib/ethon/curls/infos.rb ./vendor/bundle/ruby/2.6.0/gems/ethon-0.12.0/lib/ethon/curls/options.rb ./vendor/bundle/ruby/2.6.0/gems/ethon-0.12.0/lib/ethon/curls/functions.rb ./vendor/bundle/ruby/2.6.0/gems/ethon-0.12.0/lib/ethon/multi/stack.rb ./vendor/bundle/ruby/2.6.0/gems/ethon-0.12.0/lib/ethon/multi/operations.rb ./vendor/bundle/ruby/2.6.0/gems/ethon-0.12.0/lib/ethon/multi/options.rb ./vendor/bundle/ruby/2.6.0/gems/ethon-0.12.0/lib/ethon/easy.rb ./vendor/bundle/ruby/2.6.0/gems/ethon-0.12.0/lib/ethon/libc.rb ./vendor/bundle/ruby/2.6.0/gems/ethon-0.12.0/lib/ethon/multi.rb ./vendor/bundle/ruby/2.6.0/gems/ethon-0.12.0/lib/ethon/version.rb ./vendor/bundle/ruby/2.6.0/gems/ethon-0.12.0/lib/ethon/curl.rb ./vendor/bundle/ruby/2.6.0/gems/ethon-0.12.0/lib/ethon/errors/multi_fdset.rb ./vendor/bundle/ruby/2.6.0/gems/ethon-0.12.0/lib/ethon/errors/select.rb ./vendor/bundle/ruby/2.6.0/gems/ethon-0.12.0/lib/ethon/errors/ethon_error.rb ./vendor/bundle/ruby/2.6.0/gems/ethon-0.12.0/lib/ethon/errors/multi_remove.rb ./vendor/bundle/ruby/2.6.0/gems/ethon-0.12.0/lib/ethon/errors/invalid_option.rb ./vendor/bundle/ruby/2.6.0/gems/ethon-0.12.0/lib/ethon/errors/global_init.rb ./vendor/bundle/ruby/2.6.0/gems/ethon-0.12.0/lib/ethon/errors/invalid_value.rb ./vendor/bundle/ruby/2.6.0/gems/ethon-0.12.0/lib/ethon/errors/multi_timeout.rb ./vendor/bundle/ruby/2.6.0/gems/ethon-0.12.0/lib/ethon/errors/multi_add.rb ./vendor/bundle/ruby/2.6.0/gems/ethon-0.12.0/Gemfile ./vendor/bundle/ruby/2.6.0/gems/ethon-0.12.0/ethon.gemspec ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/ext/concurrent-ruby/ConcurrentRubyService.java ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166y/ThreadLocalRandom.java ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/LongAdder.java ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/ConcurrentHashMap.java ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/nounsafe/LongAdder.java ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/nounsafe/ConcurrentHashMapV8.java ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/nounsafe/Striped64.java ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/ConcurrentHashMapV8.java ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/ext/concurrent-ruby/com/concurrent_ruby/ext/jsr166e/Striped64.java ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/ext/concurrent-ruby/com/concurrent_ruby/ext/JRubyMapBackendLibrary.java ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/ext/concurrent-ruby/com/concurrent_ruby/ext/JavaAtomicFixnumLibrary.java ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/ext/concurrent-ruby/com/concurrent_ruby/ext/JavaSemaphoreLibrary.java ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/ext/concurrent-ruby/com/concurrent_ruby/ext/SynchronizationLibrary.java ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/ext/concurrent-ruby/com/concurrent_ruby/ext/JavaAtomicBooleanLibrary.java ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/ext/concurrent-ruby/com/concurrent_ruby/ext/AtomicReferenceLibrary.java ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/Rakefile ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/atomic_reference/numeric_cas_wrapper.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/atomic_reference/mutex_atomic.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/atom.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/ivar.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/collection/ruby_non_concurrent_priority_queue.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/collection/non_concurrent_priority_queue.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/collection/java_non_concurrent_priority_queue.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/collection/copy_on_notify_observer_set.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/collection/map/synchronized_map_backend.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/collection/map/non_concurrent_map_backend.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/collection/map/mri_map_backend.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/collection/map/atomic_reference_map_backend.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/collection/copy_on_write_observer_set.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/collection/lock_free_stack.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/async.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/future.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/mvar.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/errors.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/tvar.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/set.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/array.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/synchronization/abstract_struct.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/synchronization/truffleruby_object.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/synchronization/abstract_lockable_object.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/synchronization/volatile.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/synchronization/mri_object.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/synchronization/lock.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/synchronization/rbx_object.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/synchronization/condition.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/synchronization/jruby_lockable_object.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/synchronization/jruby_object.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/synchronization/rbx_lockable_object.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/synchronization/lockable_object.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/synchronization/abstract_object.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/synchronization/object.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/synchronization/mutex_lockable_object.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/dataflow.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/immutable_struct.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/settable_struct.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/agent.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/delay.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/mutable_struct.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/concern/dereferenceable.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/concern/deprecation.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/concern/observable.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/concern/logging.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/concern/obligation.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/concurrent_ruby.jar ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/executors.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/hash.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/map.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/atomic/count_down_latch.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/atomic/java_count_down_latch.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/atomic/ruby_thread_local_var.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/atomic/atomic_fixnum.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/atomic/java_thread_local_var.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/atomic/thread_local_var.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/atomic/mutex_count_down_latch.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/atomic/read_write_lock.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/atomic/cyclic_barrier.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/atomic/mutex_atomic_boolean.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/atomic/atomic_boolean.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/atomic/atomic_reference.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/atomic/atomic_markable_reference.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/atomic/mutex_atomic_fixnum.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/atomic/semaphore.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/atomic/mutex_semaphore.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/atomic/reentrant_read_write_lock.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/atomic/abstract_thread_local_var.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/atomic/event.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/maybe.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/promises.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/exchanger.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/constants.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/thread_safe/synchronized_delegator.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/thread_safe/util/power_of_two_tuple.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/thread_safe/util/volatile.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/thread_safe/util/adder.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/thread_safe/util/striped64.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/thread_safe/util/data_structures.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/thread_safe/util/cheap_lockable.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/thread_safe/util/xor_shift_random.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/thread_safe/util.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/executor/ruby_executor_service.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/executor/ruby_thread_pool_executor.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/executor/cached_thread_pool.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/executor/immediate_executor.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/executor/serial_executor_service.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/executor/safe_task_executor.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/executor/java_thread_pool_executor.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/executor/serialized_execution.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/executor/executor_service.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/executor/java_executor_service.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/executor/indirect_immediate_executor.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/executor/simple_executor_service.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/executor/timer_set.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/executor/ruby_single_thread_executor.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/executor/thread_pool_executor.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/executor/abstract_executor_service.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/executor/serialized_execution_delegator.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/executor/fixed_thread_pool.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/executor/java_single_thread_executor.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/executor/single_thread_executor.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/version.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/synchronization.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/timer_task.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/re_include.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/atomics.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/options.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/configuration.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/scheduled_task.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/tuple.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/utility/native_integer.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/utility/processor_counter.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/utility/monotonic_time.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/utility/engine.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/utility/native_extension_loader.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent/promise.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent-ruby.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/lib/concurrent-ruby/concurrent.rb ./vendor/bundle/ruby/2.6.0/gems/concurrent-ruby-1.1.6/Gemfile ./vendor/bundle/ruby/2.6.0/gems/github_changelog_generator-1.15.2/man/git-generate-changelog.1 ./vendor/bundle/ruby/2.6.0/gems/github_changelog_generator-1.15.2/LICENSE ./vendor/bundle/ruby/2.6.0/gems/github_changelog_generator-1.15.2/bin/github_changelog_generator ./vendor/bundle/ruby/2.6.0/gems/github_changelog_generator-1.15.2/bin/git-generate-changelog ./vendor/bundle/ruby/2.6.0/gems/github_changelog_generator-1.15.2/spec/spec_helper.rb ./vendor/bundle/ruby/2.6.0/gems/github_changelog_generator-1.15.2/spec/unit/options_spec.rb ./vendor/bundle/ruby/2.6.0/gems/github_changelog_generator-1.15.2/spec/unit/reader_spec.rb ./vendor/bundle/ruby/2.6.0/gems/github_changelog_generator-1.15.2/spec/unit/parser_spec.rb ./vendor/bundle/ruby/2.6.0/gems/github_changelog_generator-1.15.2/spec/unit/generator/generator_processor_spec.rb ./vendor/bundle/ruby/2.6.0/gems/github_changelog_generator-1.15.2/spec/unit/generator/entry_spec.rb ./vendor/bundle/ruby/2.6.0/gems/github_changelog_generator-1.15.2/spec/unit/generator/generator_tags_spec.rb ./vendor/bundle/ruby/2.6.0/gems/github_changelog_generator-1.15.2/spec/unit/octo_fetcher_spec.rb ./vendor/bundle/ruby/2.6.0/gems/github_changelog_generator-1.15.2/spec/unit/parse_file_spec.rb ./vendor/bundle/ruby/2.6.0/gems/github_changelog_generator-1.15.2/spec/install_gem_in_bundler.gemfile ./vendor/bundle/ruby/2.6.0/gems/github_changelog_generator-1.15.2/spec/vcr/GitHubChangelogGenerator_OctoFetcher/_fetch_events_async/when_API_call_is_valid.json ./vendor/bundle/ruby/2.6.0/gems/github_changelog_generator-1.15.2/spec/vcr/GitHubChangelogGenerator_OctoFetcher/_fetch_events_async/when_API_call_is_valid/populates_issues.json ./vendor/bundle/ruby/2.6.0/gems/github_changelog_generator-1.15.2/spec/vcr/GitHubChangelogGenerator_OctoFetcher/_fetch_closed_issues_and_pr/when_API_call_is_valid.json ./vendor/bundle/ruby/2.6.0/gems/github_changelog_generator-1.15.2/spec/vcr/GitHubChangelogGenerator_OctoFetcher/_fetch_closed_issues_and_pr/when_API_call_is_valid/returns_issue_with_proper_key/values.json ./vendor/bundle/ruby/2.6.0/gems/github_changelog_generator-1.15.2/spec/vcr/GitHubChangelogGenerator_OctoFetcher/_fetch_closed_issues_and_pr/when_API_call_is_valid/returns_pull_request_with_proper_key/values.json ./vendor/bundle/ruby/2.6.0/gems/github_changelog_generator-1.15.2/spec/vcr/GitHubChangelogGenerator_OctoFetcher/_fetch_closed_issues_and_pr/when_API_call_is_valid/returns_issues.json ./vendor/bundle/ruby/2.6.0/gems/github_changelog_generator-1.15.2/spec/vcr/GitHubChangelogGenerator_OctoFetcher/_fetch_closed_issues_and_pr/when_API_call_is_valid/returns_pull_requests_with_labels.json ./vendor/bundle/ruby/2.6.0/gems/github_changelog_generator-1.15.2/spec/vcr/GitHubChangelogGenerator_OctoFetcher/_fetch_closed_issues_and_pr/when_API_call_is_valid/returns_issues_with_labels.json ./vendor/bundle/ruby/2.6.0/gems/github_changelog_generator-1.15.2/spec/vcr/GitHubChangelogGenerator_OctoFetcher/_fetch_date_of_tag/when_API_call_is_valid.json ./vendor/bundle/ruby/2.6.0/gems/github_changelog_generator-1.15.2/spec/vcr/GitHubChangelogGenerator_OctoFetcher/_fetch_date_of_tag/when_API_call_is_valid/returns_date.json ./vendor/bundle/ruby/2.6.0/gems/github_changelog_generator-1.15.2/spec/vcr/GitHubChangelogGenerator_OctoFetcher/_fetch_closed_pull_requests/when_API_call_is_valid.json ./vendor/bundle/ruby/2.6.0/gems/github_changelog_generator-1.15.2/spec/vcr/GitHubChangelogGenerator_OctoFetcher/_fetch_closed_pull_requests/when_API_call_is_valid/returns_pull_requests.json ./vendor/bundle/ruby/2.6.0/gems/github_changelog_generator-1.15.2/spec/vcr/GitHubChangelogGenerator_OctoFetcher/_fetch_closed_pull_requests/when_API_call_is_valid/returns_correct_pull_request_keys.json ./vendor/bundle/ruby/2.6.0/gems/github_changelog_generator-1.15.2/spec/vcr/GitHubChangelogGenerator_OctoFetcher/_fetch_commit/when_API_call_is_valid.json ./vendor/bundle/ruby/2.6.0/gems/github_changelog_generator-1.15.2/spec/vcr/GitHubChangelogGenerator_OctoFetcher/_fetch_commit/when_API_call_is_valid/returns_commit.json ./vendor/bundle/ruby/2.6.0/gems/github_changelog_generator-1.15.2/spec/vcr/GitHubChangelogGenerator_OctoFetcher/_github_fetch_tags/when_wrong_token_provided.json ./vendor/bundle/ruby/2.6.0/gems/github_changelog_generator-1.15.2/spec/vcr/GitHubChangelogGenerator_OctoFetcher/_github_fetch_tags/when_API_call_is_valid.json ./vendor/bundle/ruby/2.6.0/gems/github_changelog_generator-1.15.2/spec/vcr/GitHubChangelogGenerator_OctoFetcher/_github_fetch_tags/when_API_call_is_valid/should_return_tags_count.json ./vendor/bundle/ruby/2.6.0/gems/github_changelog_generator-1.15.2/spec/vcr/GitHubChangelogGenerator_OctoFetcher/_github_fetch_tags/when_API_call_is_valid/should_return_tags.json ./vendor/bundle/ruby/2.6.0/gems/github_changelog_generator-1.15.2/spec/vcr/GitHubChangelogGenerator_OctoFetcher/_github_fetch_tags/when_wrong_token_provided/should_raise_Unauthorized_error.json ./vendor/bundle/ruby/2.6.0/gems/github_changelog_generator-1.15.2/spec/vcr/GitHubChangelogGenerator_OctoFetcher/_commits/when_API_is_valid/returns_commits.json ./vendor/bundle/ruby/2.6.0/gems/github_changelog_generator-1.15.2/spec/vcr/GitHubChangelogGenerator_OctoFetcher/_commits_before/when_API_is_valid/returns_commits.json ./vendor/bundle/ruby/2.6.0/gems/github_changelog_generator-1.15.2/Rakefile ./vendor/bundle/ruby/2.6.0/gems/github_changelog_generator-1.15.2/lib/github_changelog_generator/ssl_certs/cacert.pem ./vendor/bundle/ruby/2.6.0/gems/github_changelog_generator-1.15.2/lib/github_changelog_generator/helper.rb ./vendor/bundle/ruby/2.6.0/gems/github_changelog_generator-1.15.2/lib/github_changelog_generator/reader.rb ./vendor/bundle/ruby/2.6.0/gems/github_changelog_generator-1.15.2/lib/github_changelog_generator/parser.rb ./vendor/bundle/ruby/2.6.0/gems/github_changelog_generator-1.15.2/lib/github_changelog_generator/parser_file.rb ./vendor/bundle/ruby/2.6.0/gems/github_changelog_generator-1.15.2/lib/github_changelog_generator/generator/entry.rb ./vendor/bundle/ruby/2.6.0/gems/github_changelog_generator-1.15.2/lib/github_changelog_generator/generator/generator_tags.rb ./vendor/bundle/ruby/2.6.0/gems/github_changelog_generator-1.15.2/lib/github_changelog_generator/generator/generator_fetcher.rb ./vendor/bundle/ruby/2.6.0/gems/github_changelog_generator-1.15.2/lib/github_changelog_generator/generator/generator.rb ./vendor/bundle/ruby/2.6.0/gems/github_changelog_generator-1.15.2/lib/github_changelog_generator/generator/section.rb ./vendor/bundle/ruby/2.6.0/gems/github_changelog_generator-1.15.2/lib/github_changelog_generator/generator/generator_processor.rb ./vendor/bundle/ruby/2.6.0/gems/github_changelog_generator-1.15.2/lib/github_changelog_generator/octo_fetcher.rb ./vendor/bundle/ruby/2.6.0/gems/github_changelog_generator-1.15.2/lib/github_changelog_generator/version.rb ./vendor/bundle/ruby/2.6.0/gems/github_changelog_generator-1.15.2/lib/github_changelog_generator/options.rb ./vendor/bundle/ruby/2.6.0/gems/github_changelog_generator-1.15.2/lib/github_changelog_generator/task.rb ./vendor/bundle/ruby/2.6.0/gems/github_changelog_generator-1.15.2/lib/github_changelog_generator.rb ./vendor/bundle/ruby/2.6.0/gems/retriable-3.1.2/retriable.gemspec ./vendor/bundle/ruby/2.6.0/gems/retriable-3.1.2/.rspec ./vendor/bundle/ruby/2.6.0/gems/retriable-3.1.2/LICENSE ./vendor/bundle/ruby/2.6.0/gems/retriable-3.1.2/spec/spec_helper.rb ./vendor/bundle/ruby/2.6.0/gems/retriable-3.1.2/spec/config_spec.rb ./vendor/bundle/ruby/2.6.0/gems/retriable-3.1.2/spec/support/exceptions.rb ./vendor/bundle/ruby/2.6.0/gems/retriable-3.1.2/spec/retriable_spec.rb ./vendor/bundle/ruby/2.6.0/gems/retriable-3.1.2/spec/exponential_backoff_spec.rb ./vendor/bundle/ruby/2.6.0/gems/retriable-3.1.2/lib/retriable.rb ./vendor/bundle/ruby/2.6.0/gems/retriable-3.1.2/lib/retriable/core_ext/kernel.rb ./vendor/bundle/ruby/2.6.0/gems/retriable-3.1.2/lib/retriable/exponential_backoff.rb ./vendor/bundle/ruby/2.6.0/gems/retriable-3.1.2/lib/retriable/config.rb ./vendor/bundle/ruby/2.6.0/gems/retriable-3.1.2/lib/retriable/version.rb ./vendor/bundle/ruby/2.6.0/gems/retriable-3.1.2/Gemfile ./vendor/bundle/ruby/2.6.0/gems/xcodeproj-1.16.0/LICENSE ./vendor/bundle/ruby/2.6.0/gems/xcodeproj-1.16.0/bin/xcodeproj ./vendor/bundle/ruby/2.6.0/gems/xcodeproj-1.16.0/lib/xcodeproj/scheme.rb ./vendor/bundle/ruby/2.6.0/gems/xcodeproj-1.16.0/lib/xcodeproj/scheme/build_action.rb ./vendor/bundle/ruby/2.6.0/gems/xcodeproj-1.16.0/lib/xcodeproj/scheme/test_action.rb ./vendor/bundle/ruby/2.6.0/gems/xcodeproj-1.16.0/lib/xcodeproj/scheme/command_line_arguments.rb ./vendor/bundle/ruby/2.6.0/gems/xcodeproj-1.16.0/lib/xcodeproj/scheme/analyze_action.rb ./vendor/bundle/ruby/2.6.0/gems/xcodeproj-1.16.0/lib/xcodeproj/scheme/archive_action.rb ./vendor/bundle/ruby/2.6.0/gems/xcodeproj-1.16.0/lib/xcodeproj/scheme/profile_action.rb ./vendor/bundle/ruby/2.6.0/gems/xcodeproj-1.16.0/lib/xcodeproj/scheme/buildable_product_runnable.rb ./vendor/bundle/ruby/2.6.0/gems/xcodeproj-1.16.0/lib/xcodeproj/scheme/xml_element_wrapper.rb ./vendor/bundle/ruby/2.6.0/gems/xcodeproj-1.16.0/lib/xcodeproj/scheme/environment_variables.rb ./vendor/bundle/ruby/2.6.0/gems/xcodeproj-1.16.0/lib/xcodeproj/scheme/remote_runnable.rb ./vendor/bundle/ruby/2.6.0/gems/xcodeproj-1.16.0/lib/xcodeproj/scheme/macro_expansion.rb ./vendor/bundle/ruby/2.6.0/gems/xcodeproj-1.16.0/lib/xcodeproj/scheme/launch_action.rb ./vendor/bundle/ruby/2.6.0/gems/xcodeproj-1.16.0/lib/xcodeproj/scheme/abstract_scheme_action.rb ./vendor/bundle/ruby/2.6.0/gems/xcodeproj-1.16.0/lib/xcodeproj/scheme/buildable_reference.rb ./vendor/bundle/ruby/2.6.0/gems/xcodeproj-1.16.0/lib/xcodeproj/gem_version.rb ./vendor/bundle/ruby/2.6.0/gems/xcodeproj-1.16.0/lib/xcodeproj/project.rb ./vendor/bundle/ruby/2.6.0/gems/xcodeproj-1.16.0/lib/xcodeproj/workspace.rb ./vendor/bundle/ruby/2.6.0/gems/xcodeproj-1.16.0/lib/xcodeproj/xcodebuild_helper.rb ./vendor/bundle/ruby/2.6.0/gems/xcodeproj-1.16.0/lib/xcodeproj/config/other_linker_flags_parser.rb ./vendor/bundle/ruby/2.6.0/gems/xcodeproj-1.16.0/lib/xcodeproj/helper.rb ./vendor/bundle/ruby/2.6.0/gems/xcodeproj-1.16.0/lib/xcodeproj/workspace/file_reference.rb ./vendor/bundle/ruby/2.6.0/gems/xcodeproj-1.16.0/lib/xcodeproj/workspace/reference.rb ./vendor/bundle/ruby/2.6.0/gems/xcodeproj-1.16.0/lib/xcodeproj/workspace/group_reference.rb ./vendor/bundle/ruby/2.6.0/gems/xcodeproj-1.16.0/lib/xcodeproj/project/case_converter.rb ./vendor/bundle/ruby/2.6.0/gems/xcodeproj-1.16.0/lib/xcodeproj/project/project_helper.rb ./vendor/bundle/ruby/2.6.0/gems/xcodeproj-1.16.0/lib/xcodeproj/project/uuid_generator.rb ./vendor/bundle/ruby/2.6.0/gems/xcodeproj-1.16.0/lib/xcodeproj/project/object_attributes.rb ./vendor/bundle/ruby/2.6.0/gems/xcodeproj-1.16.0/lib/xcodeproj/project/object_list.rb ./vendor/bundle/ruby/2.6.0/gems/xcodeproj-1.16.0/lib/xcodeproj/project/object/configuration_list.rb ./vendor/bundle/ruby/2.6.0/gems/xcodeproj-1.16.0/lib/xcodeproj/project/object/target_dependency.rb ./vendor/bundle/ruby/2.6.0/gems/xcodeproj-1.16.0/lib/xcodeproj/project/object/swift_package_product_dependency.rb ./vendor/bundle/ruby/2.6.0/gems/xcodeproj-1.16.0/lib/xcodeproj/project/object/swift_package_remote_reference.rb ./vendor/bundle/ruby/2.6.0/gems/xcodeproj-1.16.0/lib/xcodeproj/project/object/file_reference.rb ./vendor/bundle/ruby/2.6.0/gems/xcodeproj-1.16.0/lib/xcodeproj/project/object/build_file.rb ./vendor/bundle/ruby/2.6.0/gems/xcodeproj-1.16.0/lib/xcodeproj/project/object/build_rule.rb ./vendor/bundle/ruby/2.6.0/gems/xcodeproj-1.16.0/lib/xcodeproj/project/object/root_object.rb ./vendor/bundle/ruby/2.6.0/gems/xcodeproj-1.16.0/lib/xcodeproj/project/object/group.rb ./vendor/bundle/ruby/2.6.0/gems/xcodeproj-1.16.0/lib/xcodeproj/project/object/reference_proxy.rb ./vendor/bundle/ruby/2.6.0/gems/xcodeproj-1.16.0/lib/xcodeproj/project/object/native_target.rb ./vendor/bundle/ruby/2.6.0/gems/xcodeproj-1.16.0/lib/xcodeproj/project/object/build_phase.rb ./vendor/bundle/ruby/2.6.0/gems/xcodeproj-1.16.0/lib/xcodeproj/project/object/build_configuration.rb ./vendor/bundle/ruby/2.6.0/gems/xcodeproj-1.16.0/lib/xcodeproj/project/object/helpers/groupable_helper.rb ./vendor/bundle/ruby/2.6.0/gems/xcodeproj-1.16.0/lib/xcodeproj/project/object/helpers/build_settings_array_settings_by_object_version.rb ./vendor/bundle/ruby/2.6.0/gems/xcodeproj-1.16.0/lib/xcodeproj/project/object/helpers/file_references_factory.rb ./vendor/bundle/ruby/2.6.0/gems/xcodeproj-1.16.0/lib/xcodeproj/project/object/container_item_proxy.rb ./vendor/bundle/ruby/2.6.0/gems/xcodeproj-1.16.0/lib/xcodeproj/project/object_dictionary.rb ./vendor/bundle/ruby/2.6.0/gems/xcodeproj-1.16.0/lib/xcodeproj/project/object.rb ./vendor/bundle/ruby/2.6.0/gems/xcodeproj-1.16.0/lib/xcodeproj/differ.rb ./vendor/bundle/ruby/2.6.0/gems/xcodeproj-1.16.0/lib/xcodeproj/constants.rb ./vendor/bundle/ruby/2.6.0/gems/xcodeproj-1.16.0/lib/xcodeproj/config.rb ./vendor/bundle/ruby/2.6.0/gems/xcodeproj-1.16.0/lib/xcodeproj/command/target_diff.rb ./vendor/bundle/ruby/2.6.0/gems/xcodeproj-1.16.0/lib/xcodeproj/command/sort.rb ./vendor/bundle/ruby/2.6.0/gems/xcodeproj-1.16.0/lib/xcodeproj/command/config_dump.rb ./vendor/bundle/ruby/2.6.0/gems/xcodeproj-1.16.0/lib/xcodeproj/command/project_diff.rb ./vendor/bundle/ruby/2.6.0/gems/xcodeproj-1.16.0/lib/xcodeproj/command/show.rb ./vendor/bundle/ruby/2.6.0/gems/xcodeproj-1.16.0/lib/xcodeproj/command.rb ./vendor/bundle/ruby/2.6.0/gems/xcodeproj-1.16.0/lib/xcodeproj/user_interface.rb ./vendor/bundle/ruby/2.6.0/gems/xcodeproj-1.16.0/lib/xcodeproj/plist.rb ./vendor/bundle/ruby/2.6.0/gems/xcodeproj-1.16.0/lib/xcodeproj.rb ./vendor/bundle/ruby/2.6.0/gems/addressable-2.7.0/tasks/rspec.rake ./vendor/bundle/ruby/2.6.0/gems/addressable-2.7.0/tasks/git.rake ./vendor/bundle/ruby/2.6.0/gems/addressable-2.7.0/tasks/clobber.rake ./vendor/bundle/ruby/2.6.0/gems/addressable-2.7.0/tasks/gem.rake ./vendor/bundle/ruby/2.6.0/gems/addressable-2.7.0/tasks/metrics.rake ./vendor/bundle/ruby/2.6.0/gems/addressable-2.7.0/tasks/yard.rake ./vendor/bundle/ruby/2.6.0/gems/addressable-2.7.0/spec/spec_helper.rb ./vendor/bundle/ruby/2.6.0/gems/addressable-2.7.0/spec/addressable/rack_mount_compat_spec.rb ./vendor/bundle/ruby/2.6.0/gems/addressable-2.7.0/spec/addressable/idna_spec.rb ./vendor/bundle/ruby/2.6.0/gems/addressable-2.7.0/spec/addressable/template_spec.rb ./vendor/bundle/ruby/2.6.0/gems/addressable-2.7.0/spec/addressable/security_spec.rb ./vendor/bundle/ruby/2.6.0/gems/addressable-2.7.0/spec/addressable/uri_spec.rb ./vendor/bundle/ruby/2.6.0/gems/addressable-2.7.0/spec/addressable/net_http_compat_spec.rb ./vendor/bundle/ruby/2.6.0/gems/addressable-2.7.0/Rakefile ./vendor/bundle/ruby/2.6.0/gems/addressable-2.7.0/lib/addressable/uri.rb ./vendor/bundle/ruby/2.6.0/gems/addressable-2.7.0/lib/addressable/template.rb ./vendor/bundle/ruby/2.6.0/gems/addressable-2.7.0/lib/addressable/idna/native.rb ./vendor/bundle/ruby/2.6.0/gems/addressable-2.7.0/lib/addressable/idna/pure.rb ./vendor/bundle/ruby/2.6.0/gems/addressable-2.7.0/lib/addressable/version.rb ./vendor/bundle/ruby/2.6.0/gems/addressable-2.7.0/lib/addressable/idna.rb ./vendor/bundle/ruby/2.6.0/gems/addressable-2.7.0/lib/addressable.rb ./vendor/bundle/ruby/2.6.0/gems/addressable-2.7.0/Gemfile ./vendor/bundle/ruby/2.6.0/gems/addressable-2.7.0/data/unicode.data ./vendor/bundle/ruby/2.6.0/gems/i18n-0.9.5/test/run_all.rb ./vendor/bundle/ruby/2.6.0/gems/i18n-0.9.5/test/locale/fallbacks_test.rb ./vendor/bundle/ruby/2.6.0/gems/i18n-0.9.5/test/locale/tag/rfc4646_test.rb ./vendor/bundle/ruby/2.6.0/gems/i18n-0.9.5/test/locale/tag/simple_test.rb ./vendor/bundle/ruby/2.6.0/gems/i18n-0.9.5/test/core_ext/hash_test.rb ./vendor/bundle/ruby/2.6.0/gems/i18n-0.9.5/test/i18n_test.rb ./vendor/bundle/ruby/2.6.0/gems/i18n-0.9.5/test/test_data/locales/de.po ./vendor/bundle/ruby/2.6.0/gems/i18n-0.9.5/test/test_data/locales/en.rb ./vendor/bundle/ruby/2.6.0/gems/i18n-0.9.5/test/test_data/locales/plurals.rb ./vendor/bundle/ruby/2.6.0/gems/i18n-0.9.5/test/backend/exceptions_test.rb ./vendor/bundle/ruby/2.6.0/gems/i18n-0.9.5/test/backend/metadata_test.rb ./vendor/bundle/ruby/2.6.0/gems/i18n-0.9.5/test/backend/key_value_test.rb ./vendor/bundle/ruby/2.6.0/gems/i18n-0.9.5/test/backend/memoize_test.rb ./vendor/bundle/ruby/2.6.0/gems/i18n-0.9.5/test/backend/cascade_test.rb ./vendor/bundle/ruby/2.6.0/gems/i18n-0.9.5/test/backend/fallbacks_test.rb ./vendor/bundle/ruby/2.6.0/gems/i18n-0.9.5/test/backend/simple_test.rb ./vendor/bundle/ruby/2.6.0/gems/i18n-0.9.5/test/backend/chain_test.rb ./vendor/bundle/ruby/2.6.0/gems/i18n-0.9.5/test/backend/pluralization_test.rb ./vendor/bundle/ruby/2.6.0/gems/i18n-0.9.5/test/backend/interpolation_compiler_test.rb ./vendor/bundle/ruby/2.6.0/gems/i18n-0.9.5/test/backend/transliterator_test.rb ./vendor/bundle/ruby/2.6.0/gems/i18n-0.9.5/test/backend/cache_test.rb ./vendor/bundle/ruby/2.6.0/gems/i18n-0.9.5/test/gettext/api_test.rb ./vendor/bundle/ruby/2.6.0/gems/i18n-0.9.5/test/gettext/backend_test.rb ./vendor/bundle/ruby/2.6.0/gems/i18n-0.9.5/test/api/key_value_test.rb ./vendor/bundle/ruby/2.6.0/gems/i18n-0.9.5/test/api/memoize_test.rb ./vendor/bundle/ruby/2.6.0/gems/i18n-0.9.5/test/api/cascade_test.rb ./vendor/bundle/ruby/2.6.0/gems/i18n-0.9.5/test/api/fallbacks_test.rb ./vendor/bundle/ruby/2.6.0/gems/i18n-0.9.5/test/api/simple_test.rb ./vendor/bundle/ruby/2.6.0/gems/i18n-0.9.5/test/api/chain_test.rb ./vendor/bundle/ruby/2.6.0/gems/i18n-0.9.5/test/api/override_test.rb ./vendor/bundle/ruby/2.6.0/gems/i18n-0.9.5/test/api/pluralization_test.rb ./vendor/bundle/ruby/2.6.0/gems/i18n-0.9.5/test/api/all_features_test.rb ./vendor/bundle/ruby/2.6.0/gems/i18n-0.9.5/test/test_helper.rb ./vendor/bundle/ruby/2.6.0/gems/i18n-0.9.5/test/i18n/exceptions_test.rb ./vendor/bundle/ruby/2.6.0/gems/i18n-0.9.5/test/i18n/gettext_plural_keys_test.rb ./vendor/bundle/ruby/2.6.0/gems/i18n-0.9.5/test/i18n/load_path_test.rb ./vendor/bundle/ruby/2.6.0/gems/i18n-0.9.5/test/i18n/middleware_test.rb ./vendor/bundle/ruby/2.6.0/gems/i18n-0.9.5/test/i18n/interpolate_test.rb ./vendor/bundle/ruby/2.6.0/gems/i18n-0.9.5/gemfiles/Gemfile.rails-5.0.x ./vendor/bundle/ruby/2.6.0/gems/i18n-0.9.5/gemfiles/Gemfile.rails-4.0.x ./vendor/bundle/ruby/2.6.0/gems/i18n-0.9.5/gemfiles/Gemfile.rails-5.1.x ./vendor/bundle/ruby/2.6.0/gems/i18n-0.9.5/gemfiles/Gemfile.rails-4.1.x ./vendor/bundle/ruby/2.6.0/gems/i18n-0.9.5/gemfiles/Gemfile.rails-master ./vendor/bundle/ruby/2.6.0/gems/i18n-0.9.5/gemfiles/Gemfile.rails-3.2.x ./vendor/bundle/ruby/2.6.0/gems/i18n-0.9.5/gemfiles/Gemfile.rails-4.2.x ./vendor/bundle/ruby/2.6.0/gems/i18n-0.9.5/lib/i18n.rb ./vendor/bundle/ruby/2.6.0/gems/i18n-0.9.5/lib/i18n/middleware.rb ./vendor/bundle/ruby/2.6.0/gems/i18n-0.9.5/lib/i18n/locale/tag.rb ./vendor/bundle/ruby/2.6.0/gems/i18n-0.9.5/lib/i18n/locale/fallbacks.rb ./vendor/bundle/ruby/2.6.0/gems/i18n-0.9.5/lib/i18n/locale/tag/simple.rb ./vendor/bundle/ruby/2.6.0/gems/i18n-0.9.5/lib/i18n/locale/tag/parents.rb ./vendor/bundle/ruby/2.6.0/gems/i18n-0.9.5/lib/i18n/locale/tag/rfc4646.rb ./vendor/bundle/ruby/2.6.0/gems/i18n-0.9.5/lib/i18n/tests.rb ./vendor/bundle/ruby/2.6.0/gems/i18n-0.9.5/lib/i18n/core_ext/hash.rb ./vendor/bundle/ruby/2.6.0/gems/i18n-0.9.5/lib/i18n/core_ext/string/interpolate.rb ./vendor/bundle/ruby/2.6.0/gems/i18n-0.9.5/lib/i18n/core_ext/kernel/suppress_warnings.rb ./vendor/bundle/ruby/2.6.0/gems/i18n-0.9.5/lib/i18n/exceptions.rb ./vendor/bundle/ruby/2.6.0/gems/i18n-0.9.5/lib/i18n/locale.rb ./vendor/bundle/ruby/2.6.0/gems/i18n-0.9.5/lib/i18n/tests/procs.rb ./vendor/bundle/ruby/2.6.0/gems/i18n-0.9.5/lib/i18n/tests/defaults.rb ./vendor/bundle/ruby/2.6.0/gems/i18n-0.9.5/lib/i18n/tests/basics.rb ./vendor/bundle/ruby/2.6.0/gems/i18n-0.9.5/lib/i18n/tests/localization.rb ./vendor/bundle/ruby/2.6.0/gems/i18n-0.9.5/lib/i18n/tests/pluralization.rb ./vendor/bundle/ruby/2.6.0/gems/i18n-0.9.5/lib/i18n/tests/lookup.rb ./vendor/bundle/ruby/2.6.0/gems/i18n-0.9.5/lib/i18n/tests/interpolation.rb ./vendor/bundle/ruby/2.6.0/gems/i18n-0.9.5/lib/i18n/tests/link.rb ./vendor/bundle/ruby/2.6.0/gems/i18n-0.9.5/lib/i18n/tests/localization/date.rb ./vendor/bundle/ruby/2.6.0/gems/i18n-0.9.5/lib/i18n/tests/localization/procs.rb ./vendor/bundle/ruby/2.6.0/gems/i18n-0.9.5/lib/i18n/tests/localization/date_time.rb ./vendor/bundle/ruby/2.6.0/gems/i18n-0.9.5/lib/i18n/tests/localization/time.rb ./vendor/bundle/ruby/2.6.0/gems/i18n-0.9.5/lib/i18n/backend/base.rb ./vendor/bundle/ruby/2.6.0/gems/i18n-0.9.5/lib/i18n/backend/interpolation_compiler.rb ./vendor/bundle/ruby/2.6.0/gems/i18n-0.9.5/lib/i18n/backend/cascade.rb ./vendor/bundle/ruby/2.6.0/gems/i18n-0.9.5/lib/i18n/backend/simple.rb ./vendor/bundle/ruby/2.6.0/gems/i18n-0.9.5/lib/i18n/backend/transliterator.rb ./vendor/bundle/ruby/2.6.0/gems/i18n-0.9.5/lib/i18n/backend/fallbacks.rb ./vendor/bundle/ruby/2.6.0/gems/i18n-0.9.5/lib/i18n/backend/pluralization.rb ./vendor/bundle/ruby/2.6.0/gems/i18n-0.9.5/lib/i18n/backend/cache.rb ./vendor/bundle/ruby/2.6.0/gems/i18n-0.9.5/lib/i18n/backend/chain.rb ./vendor/bundle/ruby/2.6.0/gems/i18n-0.9.5/lib/i18n/backend/flatten.rb ./vendor/bundle/ruby/2.6.0/gems/i18n-0.9.5/lib/i18n/backend/metadata.rb ./vendor/bundle/ruby/2.6.0/gems/i18n-0.9.5/lib/i18n/backend/key_value.rb ./vendor/bundle/ruby/2.6.0/gems/i18n-0.9.5/lib/i18n/backend/gettext.rb ./vendor/bundle/ruby/2.6.0/gems/i18n-0.9.5/lib/i18n/backend/memoize.rb ./vendor/bundle/ruby/2.6.0/gems/i18n-0.9.5/lib/i18n/gettext/helpers.rb ./vendor/bundle/ruby/2.6.0/gems/i18n-0.9.5/lib/i18n/gettext/po_parser.rb ./vendor/bundle/ruby/2.6.0/gems/i18n-0.9.5/lib/i18n/interpolate/ruby.rb ./vendor/bundle/ruby/2.6.0/gems/i18n-0.9.5/lib/i18n/config.rb ./vendor/bundle/ruby/2.6.0/gems/i18n-0.9.5/lib/i18n/version.rb ./vendor/bundle/ruby/2.6.0/gems/i18n-0.9.5/lib/i18n/backend.rb ./vendor/bundle/ruby/2.6.0/gems/i18n-0.9.5/lib/i18n/gettext.rb ./vendor/bundle/ruby/2.6.0/gems/i18n-0.9.5/MIT-LICENSE ./vendor/bundle/ruby/2.6.0/gems/rainbow-3.0.0/Guardfile ./vendor/bundle/ruby/2.6.0/gems/rainbow-3.0.0/LICENSE ./vendor/bundle/ruby/2.6.0/gems/rainbow-3.0.0/spec/spec_helper.rb ./vendor/bundle/ruby/2.6.0/gems/rainbow-3.0.0/spec/unit/null_presenter_spec.rb ./vendor/bundle/ruby/2.6.0/gems/rainbow-3.0.0/spec/unit/string_utils_spec.rb ./vendor/bundle/ruby/2.6.0/gems/rainbow-3.0.0/spec/unit/presenter_spec.rb ./vendor/bundle/ruby/2.6.0/gems/rainbow-3.0.0/spec/unit/color_spec.rb ./vendor/bundle/ruby/2.6.0/gems/rainbow-3.0.0/spec/unit/wrapper_spec.rb ./vendor/bundle/ruby/2.6.0/gems/rainbow-3.0.0/spec/integration/rainbow_spec.rb ./vendor/bundle/ruby/2.6.0/gems/rainbow-3.0.0/spec/integration/instance_spec.rb ./vendor/bundle/ruby/2.6.0/gems/rainbow-3.0.0/spec/integration/uncolor_spec.rb ./vendor/bundle/ruby/2.6.0/gems/rainbow-3.0.0/spec/integration/refinement_spec.rb ./vendor/bundle/ruby/2.6.0/gems/rainbow-3.0.0/spec/integration/string_spec.rb ./vendor/bundle/ruby/2.6.0/gems/rainbow-3.0.0/spec/support/presenter_shared_examples.rb ./vendor/bundle/ruby/2.6.0/gems/rainbow-3.0.0/Rakefile ./vendor/bundle/ruby/2.6.0/gems/rainbow-3.0.0/rainbow.gemspec ./vendor/bundle/ruby/2.6.0/gems/rainbow-3.0.0/README.markdown ./vendor/bundle/ruby/2.6.0/gems/rainbow-3.0.0/lib/rainbow.rb ./vendor/bundle/ruby/2.6.0/gems/rainbow-3.0.0/lib/rainbow/x11_color_names.rb ./vendor/bundle/ruby/2.6.0/gems/rainbow-3.0.0/lib/rainbow/ext/string.rb ./vendor/bundle/ruby/2.6.0/gems/rainbow-3.0.0/lib/rainbow/string_utils.rb ./vendor/bundle/ruby/2.6.0/gems/rainbow-3.0.0/lib/rainbow/refinement.rb ./vendor/bundle/ruby/2.6.0/gems/rainbow-3.0.0/lib/rainbow/null_presenter.rb ./vendor/bundle/ruby/2.6.0/gems/rainbow-3.0.0/lib/rainbow/version.rb ./vendor/bundle/ruby/2.6.0/gems/rainbow-3.0.0/lib/rainbow/color.rb ./vendor/bundle/ruby/2.6.0/gems/rainbow-3.0.0/lib/rainbow/global.rb ./vendor/bundle/ruby/2.6.0/gems/rainbow-3.0.0/lib/rainbow/wrapper.rb ./vendor/bundle/ruby/2.6.0/gems/rainbow-3.0.0/lib/rainbow/presenter.rb ./vendor/bundle/ruby/2.6.0/gems/rainbow-3.0.0/Gemfile ./vendor/bundle/ruby/2.6.0/gems/minitest-5.14.0/History.rdoc ./vendor/bundle/ruby/2.6.0/gems/minitest-5.14.0/test/minitest/test_minitest_benchmark.rb ./vendor/bundle/ruby/2.6.0/gems/minitest-5.14.0/test/minitest/test_minitest_reporter.rb ./vendor/bundle/ruby/2.6.0/gems/minitest-5.14.0/test/minitest/test_minitest_mock.rb ./vendor/bundle/ruby/2.6.0/gems/minitest-5.14.0/test/minitest/metametameta.rb ./vendor/bundle/ruby/2.6.0/gems/minitest-5.14.0/test/minitest/test_minitest_test.rb ./vendor/bundle/ruby/2.6.0/gems/minitest-5.14.0/test/minitest/test_minitest_assertions.rb ./vendor/bundle/ruby/2.6.0/gems/minitest-5.14.0/test/minitest/test_minitest_spec.rb ./vendor/bundle/ruby/2.6.0/gems/minitest-5.14.0/Rakefile ./vendor/bundle/ruby/2.6.0/gems/minitest-5.14.0/design_rationale.rb ./vendor/bundle/ruby/2.6.0/gems/minitest-5.14.0/lib/hoe/minitest.rb ./vendor/bundle/ruby/2.6.0/gems/minitest-5.14.0/lib/minitest/mock.rb ./vendor/bundle/ruby/2.6.0/gems/minitest-5.14.0/lib/minitest/hell.rb ./vendor/bundle/ruby/2.6.0/gems/minitest-5.14.0/lib/minitest/pride.rb ./vendor/bundle/ruby/2.6.0/gems/minitest-5.14.0/lib/minitest/parallel.rb ./vendor/bundle/ruby/2.6.0/gems/minitest-5.14.0/lib/minitest/unit.rb ./vendor/bundle/ruby/2.6.0/gems/minitest-5.14.0/lib/minitest/expectations.rb ./vendor/bundle/ruby/2.6.0/gems/minitest-5.14.0/lib/minitest/pride_plugin.rb ./vendor/bundle/ruby/2.6.0/gems/minitest-5.14.0/lib/minitest/spec.rb ./vendor/bundle/ruby/2.6.0/gems/minitest-5.14.0/lib/minitest/assertions.rb ./vendor/bundle/ruby/2.6.0/gems/minitest-5.14.0/lib/minitest/test.rb ./vendor/bundle/ruby/2.6.0/gems/minitest-5.14.0/lib/minitest/autorun.rb ./vendor/bundle/ruby/2.6.0/gems/minitest-5.14.0/lib/minitest/benchmark.rb ./vendor/bundle/ruby/2.6.0/gems/minitest-5.14.0/lib/minitest.rb ./vendor/bundle/ruby/2.6.0/gems/minitest-5.14.0/.autotest ./vendor/bundle/ruby/2.6.0/gems/minitest-5.14.0/README.rdoc ./vendor/bundle/ruby/2.6.0/gems/thread_safe-0.3.6/.yardopts ./vendor/bundle/ruby/2.6.0/gems/thread_safe-0.3.6/thread_safe.gemspec ./vendor/bundle/ruby/2.6.0/gems/thread_safe-0.3.6/.rspec ./vendor/bundle/ruby/2.6.0/gems/thread_safe-0.3.6/tasks/update_doc.rake ./vendor/bundle/ruby/2.6.0/gems/thread_safe-0.3.6/LICENSE ./vendor/bundle/ruby/2.6.0/gems/thread_safe-0.3.6/ext/org/jruby/ext/thread_safe/jsr166y/ThreadLocalRandom.java ./vendor/bundle/ruby/2.6.0/gems/thread_safe-0.3.6/ext/org/jruby/ext/thread_safe/jsr166e/LongAdder.java ./vendor/bundle/ruby/2.6.0/gems/thread_safe-0.3.6/ext/org/jruby/ext/thread_safe/jsr166e/ConcurrentHashMap.java ./vendor/bundle/ruby/2.6.0/gems/thread_safe-0.3.6/ext/org/jruby/ext/thread_safe/jsr166e/nounsafe/LongAdder.java ./vendor/bundle/ruby/2.6.0/gems/thread_safe-0.3.6/ext/org/jruby/ext/thread_safe/jsr166e/nounsafe/ConcurrentHashMapV8.java ./vendor/bundle/ruby/2.6.0/gems/thread_safe-0.3.6/ext/org/jruby/ext/thread_safe/jsr166e/nounsafe/Striped64.java ./vendor/bundle/ruby/2.6.0/gems/thread_safe-0.3.6/ext/org/jruby/ext/thread_safe/jsr166e/ConcurrentHashMapV8.java ./vendor/bundle/ruby/2.6.0/gems/thread_safe-0.3.6/ext/org/jruby/ext/thread_safe/jsr166e/Striped64.java ./vendor/bundle/ruby/2.6.0/gems/thread_safe-0.3.6/ext/org/jruby/ext/thread_safe/JRubyCacheBackendLibrary.java ./vendor/bundle/ruby/2.6.0/gems/thread_safe-0.3.6/ext/thread_safe/JrubyCacheBackendService.java ./vendor/bundle/ruby/2.6.0/gems/thread_safe-0.3.6/spec/spec_helper.rb ./vendor/bundle/ruby/2.6.0/gems/thread_safe-0.3.6/spec/support/threadsafe_test.rb ./vendor/bundle/ruby/2.6.0/gems/thread_safe-0.3.6/spec/support/threads.rb ./vendor/bundle/ruby/2.6.0/gems/thread_safe-0.3.6/spec/thread_safe/synchronized_delegator_spec.rb ./vendor/bundle/ruby/2.6.0/gems/thread_safe-0.3.6/spec/thread_safe/array_spec.rb ./vendor/bundle/ruby/2.6.0/gems/thread_safe-0.3.6/spec/thread_safe/hash_spec.rb ./vendor/bundle/ruby/2.6.0/gems/thread_safe-0.3.6/spec/thread_safe/no_unsafe_spec.rb ./vendor/bundle/ruby/2.6.0/gems/thread_safe-0.3.6/spec/thread_safe/cache_loops_spec.rb ./vendor/bundle/ruby/2.6.0/gems/thread_safe-0.3.6/spec/thread_safe/cache_spec.rb ./vendor/bundle/ruby/2.6.0/gems/thread_safe-0.3.6/spec/src/thread_safe/SecurityManager.java ./vendor/bundle/ruby/2.6.0/gems/thread_safe-0.3.6/Rakefile ./vendor/bundle/ruby/2.6.0/gems/thread_safe-0.3.6/examples/bench_cache.rb ./vendor/bundle/ruby/2.6.0/gems/thread_safe-0.3.6/lib/thread_safe.rb ./vendor/bundle/ruby/2.6.0/gems/thread_safe-0.3.6/lib/thread_safe/synchronized_delegator.rb ./vendor/bundle/ruby/2.6.0/gems/thread_safe-0.3.6/lib/thread_safe/mri_cache_backend.rb ./vendor/bundle/ruby/2.6.0/gems/thread_safe-0.3.6/lib/thread_safe/synchronized_cache_backend.rb ./vendor/bundle/ruby/2.6.0/gems/thread_safe-0.3.6/lib/thread_safe/util/volatile_tuple.rb ./vendor/bundle/ruby/2.6.0/gems/thread_safe-0.3.6/lib/thread_safe/util/power_of_two_tuple.rb ./vendor/bundle/ruby/2.6.0/gems/thread_safe-0.3.6/lib/thread_safe/util/volatile.rb ./vendor/bundle/ruby/2.6.0/gems/thread_safe-0.3.6/lib/thread_safe/util/adder.rb ./vendor/bundle/ruby/2.6.0/gems/thread_safe-0.3.6/lib/thread_safe/util/striped64.rb ./vendor/bundle/ruby/2.6.0/gems/thread_safe-0.3.6/lib/thread_safe/util/cheap_lockable.rb ./vendor/bundle/ruby/2.6.0/gems/thread_safe-0.3.6/lib/thread_safe/util/atomic_reference.rb ./vendor/bundle/ruby/2.6.0/gems/thread_safe-0.3.6/lib/thread_safe/util/xor_shift_random.rb ./vendor/bundle/ruby/2.6.0/gems/thread_safe-0.3.6/lib/thread_safe/non_concurrent_cache_backend.rb ./vendor/bundle/ruby/2.6.0/gems/thread_safe-0.3.6/lib/thread_safe/cache.rb ./vendor/bundle/ruby/2.6.0/gems/thread_safe-0.3.6/lib/thread_safe/atomic_reference_cache_backend.rb ./vendor/bundle/ruby/2.6.0/gems/thread_safe-0.3.6/lib/thread_safe/util.rb ./vendor/bundle/ruby/2.6.0/gems/thread_safe-0.3.6/lib/thread_safe/version.rb ./vendor/bundle/ruby/2.6.0/gems/thread_safe-0.3.6/Gemfile ./vendor/bundle/ruby/2.6.0/gems/thread_safe-0.3.6/yard-template/default/layout/html/footer.erb ./vendor/bundle/ruby/2.6.0/gems/thread_safe-0.3.6/yard-template/default/fulldoc/html/css/common.css ./vendor/bundle/ruby/2.6.0/gems/nap-1.1.0/LICENSE ./vendor/bundle/ruby/2.6.0/gems/nap-1.1.0/support/cacert.pem ./vendor/bundle/ruby/2.6.0/gems/nap-1.1.0/lib/rest.rb ./vendor/bundle/ruby/2.6.0/gems/nap-1.1.0/lib/rest/response.rb ./vendor/bundle/ruby/2.6.0/gems/nap-1.1.0/lib/rest/request.rb ./vendor/bundle/ruby/2.6.0/gems/nap-1.1.0/lib/rest/error.rb ./vendor/bundle/ruby/2.6.0/gems/colored2-3.1.2/LICENSE ./vendor/bundle/ruby/2.6.0/gems/colored2-3.1.2/spec/spec_helper.rb ./vendor/bundle/ruby/2.6.0/gems/colored2-3.1.2/spec/colored2_spec.rb ./vendor/bundle/ruby/2.6.0/gems/colored2-3.1.2/spec/colored2/numbers_spec.rb ./vendor/bundle/ruby/2.6.0/gems/colored2-3.1.2/spec/colored2/object_spec.rb ./vendor/bundle/ruby/2.6.0/gems/colored2-3.1.2/spec/colored2/strings_spec.rb ./vendor/bundle/ruby/2.6.0/gems/colored2-3.1.2/Rakefile ./vendor/bundle/ruby/2.6.0/gems/colored2-3.1.2/lib/colored2/strings.rb ./vendor/bundle/ruby/2.6.0/gems/colored2-3.1.2/lib/colored2/numbers.rb ./vendor/bundle/ruby/2.6.0/gems/colored2-3.1.2/lib/colored2/codes.rb ./vendor/bundle/ruby/2.6.0/gems/colored2-3.1.2/lib/colored2/version.rb ./vendor/bundle/ruby/2.6.0/gems/colored2-3.1.2/lib/colored2/object.rb ./vendor/bundle/ruby/2.6.0/gems/colored2-3.1.2/lib/colored2/ascii_decorator.rb ./vendor/bundle/ruby/2.6.0/gems/colored2-3.1.2/lib/colored2.rb ./vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/.yardopts ./vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/LICENSE ./vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/tzinfo.gemspec ./vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/test/tc_ruby_country_info.rb ./vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/test/tc_zoneinfo_timezone_info.rb ./vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/test/zoneinfo/right/Europe/London ./vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/test/zoneinfo/posix/Europe/London ./vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/test/zoneinfo/leapseconds ./vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/test/zoneinfo/zone1970.tab ./vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/test/zoneinfo/iso3166.tab ./vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/test/zoneinfo/America/New_York ./vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/test/zoneinfo/America/Argentina/Buenos_Aires ./vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/test/zoneinfo/Australia/Melbourne ./vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/test/zoneinfo/Etc/UTC ./vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/test/zoneinfo/Europe/Paris ./vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/test/zoneinfo/Europe/London ./vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/test/zoneinfo/Europe/Andorra ./vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/test/zoneinfo/Europe/Prague ./vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/test/zoneinfo/Europe/Amsterdam ./vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/test/zoneinfo/posixrules ./vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/test/zoneinfo/EST ./vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/test/zoneinfo/zone.tab ./vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/test/zoneinfo/Factory ./vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/test/tc_data_timezone.rb ./vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/test/tc_country_info.rb ./vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/test/tc_timezone.rb ./vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/test/tc_timezone_proxy.rb ./vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/test/ts_all_ruby.rb ./vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/test/tc_zoneinfo_country_info.rb ./vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/test/ts_all.rb ./vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/test/tc_ruby_core_support.rb ./vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/test/tc_country_index_definition.rb ./vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/test/tc_country.rb ./vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/test/tc_time_or_datetime.rb ./vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/test/tc_timezone_info.rb ./vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/test/tc_data_timezone_info.rb ./vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/test/tc_info_timezone.rb ./vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/test/tc_timezone_utc.rb ./vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/test/tc_timezone_offset.rb ./vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/test/tzinfo-data/tzinfo/data.rb ./vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/test/tzinfo-data/tzinfo/data/version.rb ./vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/test/tzinfo-data/tzinfo/data/definitions/UTC.rb ./vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/test/tzinfo-data/tzinfo/data/definitions/America/Argentina/Buenos_Aires.rb ./vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/test/tzinfo-data/tzinfo/data/definitions/America/New_York.rb ./vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/test/tzinfo-data/tzinfo/data/definitions/Australia/Melbourne.rb ./vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/test/tzinfo-data/tzinfo/data/definitions/Etc/UTC.rb ./vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/test/tzinfo-data/tzinfo/data/definitions/Etc/GMT__m__1.rb ./vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/test/tzinfo-data/tzinfo/data/definitions/Etc/GMT__p__1.rb ./vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/test/tzinfo-data/tzinfo/data/definitions/Europe/Andorra.rb ./vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/test/tzinfo-data/tzinfo/data/definitions/Europe/Prague.rb ./vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/test/tzinfo-data/tzinfo/data/definitions/Europe/London.rb ./vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/test/tzinfo-data/tzinfo/data/definitions/Europe/Paris.rb ./vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/test/tzinfo-data/tzinfo/data/definitions/Europe/Amsterdam.rb ./vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/test/tzinfo-data/tzinfo/data/definitions/EST.rb ./vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/test/tzinfo-data/tzinfo/data/indexes/timezones.rb ./vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/test/tzinfo-data/tzinfo/data/indexes/countries.rb ./vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/test/tc_timezone_transition.rb ./vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/test/tc_linked_timezone.rb ./vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/test/tc_timezone_definition.rb ./vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/test/tc_timezone_period.rb ./vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/test/tc_timezone_new_york.rb ./vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/test/tc_timezone_melbourne.rb ./vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/test/tc_offset_rationals.rb ./vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/test/ts_all_zoneinfo.rb ./vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/test/tc_timezone_london.rb ./vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/test/tc_linked_timezone_info.rb ./vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/test/tc_ruby_data_source.rb ./vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/test/tc_transition_data_timezone_info.rb ./vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/test/tc_country_timezone.rb ./vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/test/tc_zoneinfo_data_source.rb ./vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/test/tc_data_source.rb ./vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/test/tc_timezone_transition_definition.rb ./vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/test/test_utils.rb ./vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/test/tc_timezone_index_definition.rb ./vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/Rakefile ./vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/lib/tzinfo/ruby_data_source.rb ./vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/lib/tzinfo/country_timezone.rb ./vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/lib/tzinfo/linked_timezone.rb ./vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/lib/tzinfo/ruby_core_support.rb ./vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/lib/tzinfo/zoneinfo_country_info.rb ./vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/lib/tzinfo/timezone_offset.rb ./vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/lib/tzinfo/zoneinfo_timezone_info.rb ./vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/lib/tzinfo/timezone_index_definition.rb ./vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/lib/tzinfo/ruby_country_info.rb ./vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/lib/tzinfo/timezone.rb ./vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/lib/tzinfo/timezone_transition_definition.rb ./vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/lib/tzinfo/country_index_definition.rb ./vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/lib/tzinfo/timezone_proxy.rb ./vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/lib/tzinfo/data_timezone_info.rb ./vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/lib/tzinfo/offset_rationals.rb ./vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/lib/tzinfo/country.rb ./vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/lib/tzinfo/timezone_definition.rb ./vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/lib/tzinfo/time_or_datetime.rb ./vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/lib/tzinfo/country_info.rb ./vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/lib/tzinfo/timezone_transition.rb ./vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/lib/tzinfo/data_timezone.rb ./vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/lib/tzinfo/info_timezone.rb ./vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/lib/tzinfo/timezone_info.rb ./vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/lib/tzinfo/timezone_period.rb ./vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/lib/tzinfo/zoneinfo_data_source.rb ./vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/lib/tzinfo/transition_data_timezone_info.rb ./vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/lib/tzinfo/data_source.rb ./vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/lib/tzinfo/linked_timezone_info.rb ./vendor/bundle/ruby/2.6.0/gems/tzinfo-1.2.7/lib/tzinfo.rb ./vendor/bundle/ruby/2.6.0/gems/CFPropertyList-3.0.2/LICENSE ./vendor/bundle/ruby/2.6.0/gems/CFPropertyList-3.0.2/lib/cfpropertylist.rb ./vendor/bundle/ruby/2.6.0/gems/CFPropertyList-3.0.2/lib/cfpropertylist/rbCFPlistError.rb ./vendor/bundle/ruby/2.6.0/gems/CFPropertyList-3.0.2/lib/cfpropertylist/rbLibXMLParser.rb ./vendor/bundle/ruby/2.6.0/gems/CFPropertyList-3.0.2/lib/cfpropertylist/rbNokogiriParser.rb ./vendor/bundle/ruby/2.6.0/gems/CFPropertyList-3.0.2/lib/cfpropertylist/rbBinaryCFPropertyList.rb ./vendor/bundle/ruby/2.6.0/gems/CFPropertyList-3.0.2/lib/cfpropertylist/rbREXMLParser.rb ./vendor/bundle/ruby/2.6.0/gems/CFPropertyList-3.0.2/lib/cfpropertylist/rbCFTypes.rb ./vendor/bundle/ruby/2.6.0/gems/CFPropertyList-3.0.2/lib/cfpropertylist/rbCFPropertyList.rb ./vendor/bundle/ruby/2.6.0/gems/CFPropertyList-3.0.2/lib/cfpropertylist/rbPlainCFPropertyList.rb ./vendor/bundle/ruby/2.6.0/gems/CFPropertyList-3.0.2/THANKS ./vendor/bundle/ruby/2.6.0/gems/CFPropertyList-3.0.2/README.rdoc ./vendor/bundle/ruby/2.6.0/gems/cocoapods-core-1.9.1/LICENSE ./vendor/bundle/ruby/2.6.0/gems/cocoapods-core-1.9.1/lib/cocoapods-core.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-core-1.9.1/lib/cocoapods-core/source.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-core-1.9.1/lib/cocoapods-core/gem_version.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-core-1.9.1/lib/cocoapods-core/trunk_source.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-core-1.9.1/lib/cocoapods-core/core_ui.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-core-1.9.1/lib/cocoapods-core/yaml_helper.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-core-1.9.1/lib/cocoapods-core/github.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-core-1.9.1/lib/cocoapods-core/http.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-core-1.9.1/lib/cocoapods-core/dependency.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-core-1.9.1/lib/cocoapods-core/cdn_source.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-core-1.9.1/lib/cocoapods-core/specification.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-core-1.9.1/lib/cocoapods-core/source/manager.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-core-1.9.1/lib/cocoapods-core/source/health_reporter.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-core-1.9.1/lib/cocoapods-core/source/metadata.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-core-1.9.1/lib/cocoapods-core/source/acceptor.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-core-1.9.1/lib/cocoapods-core/source/aggregate.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-core-1.9.1/lib/cocoapods-core/podfile.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-core-1.9.1/lib/cocoapods-core/platform.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-core-1.9.1/lib/cocoapods-core/specification/linter.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-core-1.9.1/lib/cocoapods-core/specification/json.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-core-1.9.1/lib/cocoapods-core/specification/set.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-core-1.9.1/lib/cocoapods-core/specification/linter/result.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-core-1.9.1/lib/cocoapods-core/specification/linter/analyzer.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-core-1.9.1/lib/cocoapods-core/specification/consumer.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-core-1.9.1/lib/cocoapods-core/specification/root_attribute_accessors.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-core-1.9.1/lib/cocoapods-core/specification/set/presenter.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-core-1.9.1/lib/cocoapods-core/specification/dsl/attribute_support.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-core-1.9.1/lib/cocoapods-core/specification/dsl/deprecations.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-core-1.9.1/lib/cocoapods-core/specification/dsl/platform_proxy.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-core-1.9.1/lib/cocoapods-core/specification/dsl/attribute.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-core-1.9.1/lib/cocoapods-core/specification/dsl.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-core-1.9.1/lib/cocoapods-core/build_type.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-core-1.9.1/lib/cocoapods-core/standard_error.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-core-1.9.1/lib/cocoapods-core/version.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-core-1.9.1/lib/cocoapods-core/podfile/target_definition.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-core-1.9.1/lib/cocoapods-core/podfile/dsl.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-core-1.9.1/lib/cocoapods-core/requirement.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-core-1.9.1/lib/cocoapods-core/lockfile.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-core-1.9.1/lib/cocoapods-core/vendor.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-core-1.9.1/lib/cocoapods-core/vendor/version.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-core-1.9.1/lib/cocoapods-core/vendor/requirement.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-core-1.9.1/lib/cocoapods-core/metrics.rb ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/.yardopts ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/LICENSE ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/Type.h ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/Type.o ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/rbffi_endian.h ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/MappedType.h ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/MappedType.o ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/Thread.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/Buffer.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi.gnu.mk ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi.vc.mk ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/StructLayout.o ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/Types.h ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi.mk ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/Types.o ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi.darwin.mk ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/LastError.h ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/Makefile ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/LastError.o ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/ArrayType.o ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/ArrayType.h ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/DynamicLibrary.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/extconf.h ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/Variadic.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/ffi_c.bundle ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/StructByValue.h ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/StructByValue.o ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/AbstractMemory.h ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/ffi.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/AbstractMemory.o ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/ClosurePool.h ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/FunctionInfo.o ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/Pointer.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/ClosurePool.o ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/MemoryPointer.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/Call.h ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/Platform.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/Call.o ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/LongDouble.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/.sitearchdir.time ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/MethodHandle.h ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi-x86_64-darwin18/man/Makefile ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi-x86_64-darwin18/libtool ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi-x86_64-darwin18/local.exp ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi-x86_64-darwin18/libffi.la ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi-x86_64-darwin18/Makefile ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi-x86_64-darwin18/include/ffitarget.h ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi-x86_64-darwin18/include/Makefile ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi-x86_64-darwin18/include/ffi.h ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi-x86_64-darwin18/testsuite/Makefile ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi-x86_64-darwin18/stamp-h1 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi-x86_64-darwin18/fficonfig.h ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi-x86_64-darwin18/config.status ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi-x86_64-darwin18/libffi.pc ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi-x86_64-darwin18/doc/Makefile ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi-x86_64-darwin18/config.log ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi-x86_64-darwin18/.libs/libffi_convenience.a ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi-x86_64-darwin18/.libs/libffi.lai ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi-x86_64-darwin18/.libs/libffi.7.dylib ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi-x86_64-darwin18/libffi_convenience.la ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi-x86_64-darwin18/src/prep_cif.lo ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi-x86_64-darwin18/src/raw_api.lo ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi-x86_64-darwin18/src/x86/win64.lo ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi-x86_64-darwin18/src/x86/ffi64.lo ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi-x86_64-darwin18/src/x86/ffiw64.lo ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi-x86_64-darwin18/src/x86/.deps/.dirstamp ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi-x86_64-darwin18/src/x86/.libs/unix64.o ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi-x86_64-darwin18/src/x86/.libs/win64.o ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi-x86_64-darwin18/src/x86/.libs/ffi64.o ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi-x86_64-darwin18/src/x86/.libs/ffiw64.o ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi-x86_64-darwin18/src/x86/.dirstamp ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi-x86_64-darwin18/src/x86/unix64.lo ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi-x86_64-darwin18/src/closures.lo ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi-x86_64-darwin18/src/types.lo ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi-x86_64-darwin18/src/java_raw_api.lo ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi-x86_64-darwin18/src/.deps/.dirstamp ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi-x86_64-darwin18/src/.libs/types.o ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi-x86_64-darwin18/src/.libs/raw_api.o ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi-x86_64-darwin18/src/.libs/java_raw_api.o ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi-x86_64-darwin18/src/.libs/closures.o ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi-x86_64-darwin18/src/.libs/prep_cif.o ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi-x86_64-darwin18/src/.dirstamp ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/Function.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/MethodHandle.o ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/Struct.o ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/Struct.h ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/rbffi.h ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/Buffer.o ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/Thread.h ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/Thread.o ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/MappedType.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/Type.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi.vc64.mk ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/Types.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/compat.h ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/extconf.rb ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/StructLayout.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi.bsd.mk ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/DynamicLibrary.h ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/DynamicLibrary.o ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/ArrayType.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/win32/stdbool.h ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/win32/stdint.h ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/LastError.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/Struct.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/Platform.h ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/Call.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/Platform.o ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/Function.o ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/LongDouble.o ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/Function.h ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/MethodHandle.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/LongDouble.h ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/AbstractMemory.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/ffi.o ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/MemoryPointer.h ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/LICENSE-BUILDTOOLS ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/man/ffi_call.3 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/man/ffi_prep_cif_var.3 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/man/ffi_prep_cif.3 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/man/ffi.3 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/man/Makefile.am ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/man/Makefile.in ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/acinclude.m4 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/stamp-h.in ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/install-sh ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/configure.ac ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/ltmain.sh ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/LICENSE ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/configure ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/msvcc.sh ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/make_sunver.pl ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/include/ffi_common.h ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/include/ffi.h.in ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/include/Makefile.am ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/include/ffi_cfi.h ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/include/Makefile.in ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.call/err_bad_typedef.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.call/float3.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.call/strlen4.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.call/call.exp ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.call/many2.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.call/return_fl3.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.call/struct5.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.call/struct1.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.call/struct10.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.call/align_stdcall.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.call/align_mixed.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.call/ffitest.h ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.call/strlen3.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.call/va_struct3.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.call/float4.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.call/struct6.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.call/return_uc.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.call/strlen.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.call/pyobjc-tc.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.call/return_sl.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.call/struct8.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.call/struct2.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.call/return_ll1.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.call/return_ldl.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.call/float1.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.call/return_ll.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.call/return_dbl.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.call/return_dbl2.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.call/many.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.call/many_mixed.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.call/va_struct2.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.call/strlen2.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.call/offsets.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.call/struct7.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.call/negint.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.call/return_sc.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.call/float_va.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.call/pr1172638.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.call/return_fl1.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.call/float.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.call/struct3.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.call/return_ul.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.call/struct9.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.call/return_fl.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.call/va_1.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.call/float2.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.call/va_struct1.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.call/return_dbl1.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.call/return_fl2.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.call/promotion.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.call/struct4.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.call/uninitialized.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.call/many_double.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/config/default.exp ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.complex/complex_defs_float.inc ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.complex/return_complex_float.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.complex/return_complex1_float.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.complex/complex_defs_double.inc ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.complex/complex.inc ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.complex/cls_align_complex_double.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.complex/cls_complex_va_longdouble.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.complex/return_complex2_longdouble.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.complex/complex_float.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.complex/return_complex.inc ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.complex/ffitest.h ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.complex/return_complex1_double.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.complex/cls_complex_struct_longdouble.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.complex/cls_align_complex_longdouble.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.complex/cls_complex_struct_double.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.complex/return_complex2_float.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.complex/cls_complex_va_double.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.complex/cls_complex_float.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.complex/complex_int.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.complex/cls_align_complex_float.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.complex/many_complex.inc ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.complex/many_complex_longdouble.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.complex/cls_align_complex.inc ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.complex/cls_complex_struct_float.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.complex/many_complex_double.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.complex/complex_double.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.complex/complex_longdouble.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.complex/cls_complex_va.inc ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.complex/cls_complex_struct.inc ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.complex/complex_defs_longdouble.inc ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.complex/cls_complex_longdouble.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.complex/return_complex1.inc ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.complex/many_complex_float.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.complex/cls_complex_va_float.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.complex/return_complex_double.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.complex/return_complex2.inc ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.complex/cls_complex_double.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.complex/return_complex_longdouble.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.complex/return_complex2_double.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.complex/complex.exp ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.complex/return_complex1_longdouble.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.complex/cls_complex.inc ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/Makefile.am ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/nested_struct9.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_struct_va1.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_4byte.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_align_uint32.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_20byte.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_3float.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/nested_struct3.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_7_1_byte.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/err_bad_abi.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_6_1_byte.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_ulong_va.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_ushort.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_4_1byte.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/nested_struct7.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_schar.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_6byte.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_sint.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_2byte.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/closure_fn2.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/closure_fn6.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_multi_sshortchar.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_align_float.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/nested_struct.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_24byte.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_uchar.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_19byte.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/nested_struct10.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_7byte.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_sshort.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_double.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/ffitest.h ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/nested_struct4.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_5byte.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_64byte.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/unwindtest_ffi_call.cc ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_align_sint32.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/huge_struct.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/problem1.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/stret_large2.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/closure_fn1.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_18byte.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_align_pointer.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_uint.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/unwindtest.cc ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/closure_fn5.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_20byte1.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_9byte2.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/closure_loc_fn0.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_longdouble.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_double_va.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_16byte.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_3_1byte.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/nested_struct1.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/nested_struct11.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_align_longdouble_split.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_align_sint16.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_3byte1.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/nested_struct5.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_multi_sshort.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/closure.exp ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/stret_medium2.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/closure_fn0.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_float.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_longdouble_va.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/stret_medium.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_align_uint64.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_12byte.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_5_1_byte.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_dbls_struct.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_align_longdouble_split2.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/testclosure.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/closure_fn4.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/nested_struct2.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/nested_struct8.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/stret_large.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_multi_uchar.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_uchar_va.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_9byte1.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_multi_ushort.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_align_uint16.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_many_mixed_float_double.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_align_longdouble.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/nested_struct6.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_3byte2.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_uint_va.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_many_mixed_args.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_multi_ushortchar.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_align_sint64.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/closure_fn3.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_ushort_va.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_pointer_stack.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_multi_schar.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_1_1byte.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/closure_simple.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_align_double.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_pointer.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_ulonglong.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_8byte.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/lib/wrapper.exp ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/lib/target-libpath.exp ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/lib/libffi.exp ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.go/static-chain.h ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.go/go.exp ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.go/closure1.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.go/ffitest.h ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.go/aa-direct.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.bhaible/test-call.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.bhaible/alignof.h ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.bhaible/bhaible.exp ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.bhaible/Makefile ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.bhaible/test-callback.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.bhaible/README ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.bhaible/testcases.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/Makefile.in ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/libtool-ldflags ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/fficonfig.h.in ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/config.guess ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/libffi.map.in ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/missing ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/libffi.xcodeproj/project.pbxproj ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/generate-darwin-source-and-headers.py ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/Makefile.am ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/config.sub ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/libtool-version ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/.gitattributes ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/m4/ax_gcc_x86_cpuid.m4 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/m4/ax_enable_builddir.m4 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/m4/ax_compiler_vendor.m4 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/m4/ax_check_compile_flag.m4 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/m4/ax_cflags_warn_all.m4 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/m4/ax_gcc_archflag.m4 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/m4/ax_configure_args.m4 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/m4/ax_require_defined.m4 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/m4/asmcfi.m4 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/m4/ax_append_flag.m4 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/m4/ax_cc_maxopt.m4 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/doc/version.texi ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/doc/libffi.texi ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/doc/Makefile.am ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/doc/Makefile.in ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/.travis/m32r-sim.exp ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/.travis/moxie-sim.exp ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/.travis/build-cross-in-container.sh ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/.travis/ar-lib ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/.travis/bfin-sim.exp ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/.travis/install.sh ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/.travis/site.exp ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/.travis/wine-sim.exp ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/.travis/build-in-container.sh ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/.travis/powerpc-eabisim.exp ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/.travis/build.sh ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/.travis/compile ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/.travis/or1k-sim.exp ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/msvc_build/aarch64/aarch64_include/fficonfig.h ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/msvc_build/aarch64/aarch64_include/ffi.h ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/msvc_build/aarch64/Ffi_staticLib.vcxproj.filters ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/msvc_build/aarch64/Ffi_staticLib.vcxproj.user ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/msvc_build/aarch64/Ffi_staticLib.vcxproj ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/msvc_build/aarch64/Ffi_staticLib.sln ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/Makefile.in ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/ChangeLog.old ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/libffi.pc.in ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/configure.host ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/autogen.sh ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/m68k/ffitarget.h ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/m68k/sysv.S ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/m68k/ffi.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/moxie/ffitarget.h ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/moxie/ffi.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/moxie/eabi.S ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/avr32/ffitarget.h ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/avr32/sysv.S ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/avr32/ffi.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/m88k/obsd.S ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/m88k/ffitarget.h ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/m88k/ffi.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/ia64/ffitarget.h ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/ia64/ia64_flags.h ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/ia64/ffi.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/ia64/unix.S ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/xtensa/ffitarget.h ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/xtensa/sysv.S ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/xtensa/ffi.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/closures.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/powerpc/ffi_sysv.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/powerpc/ffitarget.h ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/powerpc/ffi_linux64.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/powerpc/ffi_powerpc.h ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/powerpc/linux64_closure.S ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/powerpc/sysv.S ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/powerpc/ffi.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/powerpc/asm.h ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/powerpc/aix_closure.S ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/powerpc/ffi_darwin.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/powerpc/darwin_closure.S ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/powerpc/darwin.S ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/powerpc/aix.S ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/powerpc/ppc_closure.S ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/powerpc/linux64.S ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/m32r/ffitarget.h ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/m32r/sysv.S ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/m32r/ffi.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/or1k/ffitarget.h ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/or1k/sysv.S ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/or1k/ffi.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/tile/ffitarget.h ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/tile/tile.S ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/tile/ffi.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/s390/ffitarget.h ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/s390/internal.h ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/s390/sysv.S ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/s390/ffi.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/prep_cif.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/cris/ffitarget.h ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/cris/sysv.S ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/cris/ffi.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/debug.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/mips/ffitarget.h ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/mips/n32.S ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/mips/o32.S ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/mips/ffi.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/sh/ffitarget.h ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/sh/sysv.S ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/sh/ffi.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/sh64/ffitarget.h ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/sh64/sysv.S ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/sh64/ffi.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/frv/ffitarget.h ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/frv/ffi.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/frv/eabi.S ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/pa/ffitarget.h ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/pa/linux.S ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/pa/ffi.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/pa/hpux32.S ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/metag/ffitarget.h ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/metag/sysv.S ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/metag/ffi.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/x86/sysv_intel.S ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/x86/ffitarget.h ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/x86/unix64.S ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/x86/internal.h ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/x86/win64_intel.S ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/x86/ffi64.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/x86/sysv.S ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/x86/ffi.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/x86/ffiw64.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/x86/asmnames.h ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/x86/win64.S ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/x86/internal64.h ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/types.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/microblaze/ffitarget.h ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/microblaze/sysv.S ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/microblaze/ffi.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/arm/ffitarget.h ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/arm/internal.h ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/arm/sysv.S ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/arm/ffi.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/arm/sysv_msvc_arm32.S ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/arc/ffitarget.h ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/arc/ffi.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/arc/arcompact.S ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/riscv/ffitarget.h ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/riscv/sysv.S ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/riscv/ffi.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/dlmalloc.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/alpha/ffitarget.h ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/alpha/internal.h ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/alpha/osf.S ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/alpha/ffi.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/aarch64/ffitarget.h ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/aarch64/internal.h ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/aarch64/sysv.S ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/aarch64/ffi.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/aarch64/win64_armasm.S ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/sparc/ffitarget.h ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/sparc/internal.h ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/sparc/v8.S ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/sparc/ffi64.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/sparc/ffi.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/sparc/v9.S ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/java_raw_api.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/vax/elfbsd.S ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/vax/ffitarget.h ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/vax/ffi.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/bfin/ffitarget.h ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/bfin/sysv.S ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/bfin/ffi.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/raw_api.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/nios2/ffitarget.h ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/nios2/sysv.S ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/nios2/ffi.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/Pointer.o ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/FunctionInfo.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/Pointer.h ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/MemoryPointer.o ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/ClosurePool.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/Variadic.o ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/StructByValue.c ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ffi.gemspec ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/LICENSE.SPECS ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/.gitmodules ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/samples/qsort.rb ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/samples/getpid.rb ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/samples/sample_helper.rb ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/samples/getlogin.rb ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/samples/pty.rb ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/samples/gettimeofday.rb ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/samples/inotify.rb ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/samples/hello.rb ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/Rakefile ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/COPYING ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/lib/ffi.rb ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/lib/ffi_c.bundle ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/lib/ffi/ffi.rb ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/lib/ffi/struct.rb ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/lib/ffi/union.rb ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/lib/ffi/tools/types_generator.rb ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/lib/ffi/tools/struct_generator.rb ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/lib/ffi/tools/generator_task.rb ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/lib/ffi/tools/generator.rb ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/lib/ffi/tools/const_generator.rb ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/lib/ffi/enum.rb ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/lib/ffi/pointer.rb ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/lib/ffi/buffer.rb ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/lib/ffi/platform/mips64-linux/types.conf ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/lib/ffi/platform/s390-linux/types.conf ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/lib/ffi/platform/sparc-solaris/types.conf ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/lib/ffi/platform/ia64-linux/types.conf ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/lib/ffi/platform/i386-netbsd/types.conf ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/lib/ffi/platform/powerpc-linux/types.conf ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/lib/ffi/platform/arm-freebsd12/types.conf ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/lib/ffi/platform/i386-freebsd12/types.conf ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/lib/ffi/platform/arm-freebsd/types.conf ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/lib/ffi/platform/sparc-linux/types.conf ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/lib/ffi/platform/arm-linux/types.conf ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/lib/ffi/platform/mipsisa64r6-linux/types.conf ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/lib/ffi/platform/mipsisa32r6-linux/types.conf ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/lib/ffi/platform/i386-gnu/types.conf ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/lib/ffi/platform/powerpc-darwin/types.conf ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/lib/ffi/platform/i386-linux/types.conf ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/lib/ffi/platform/x86_64-netbsd/types.conf ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/lib/ffi/platform/powerpc64-linux/types.conf ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/lib/ffi/platform/mipsisa64r6el-linux/types.conf ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/lib/ffi/platform/mipsisa32r6el-linux/types.conf ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/lib/ffi/platform/x86_64-dragonflybsd/types.conf ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/lib/ffi/platform/i386-darwin/types.conf ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/lib/ffi/platform/sparc64-linux/types.conf ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/lib/ffi/platform/x86_64-linux/types.conf ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/lib/ffi/platform/aarch64-freebsd12/types.conf ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/lib/ffi/platform/x86_64-freebsd12/types.conf ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/lib/ffi/platform/i386-windows/types.conf ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/lib/ffi/platform/i386-solaris/types.conf ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/lib/ffi/platform/powerpc-aix/types.conf ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/lib/ffi/platform/x86_64-solaris/types.conf ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/lib/ffi/platform/x86_64-windows/types.conf ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/lib/ffi/platform/mips-linux/types.conf ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/lib/ffi/platform/aarch64-freebsd/types.conf ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/lib/ffi/platform/i386-cygwin/types.conf ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/lib/ffi/platform/x86_64-openbsd/types.conf ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/lib/ffi/platform/i386-openbsd/types.conf ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/lib/ffi/platform/x86_64-cygwin/types.conf ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/lib/ffi/platform/sparcv9-solaris/types.conf ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/lib/ffi/platform/i386-freebsd/types.conf ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/lib/ffi/platform/aarch64-linux/types.conf ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/lib/ffi/platform/mips64el-linux/types.conf ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/lib/ffi/platform/x86_64-freebsd/types.conf ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/lib/ffi/platform/s390x-linux/types.conf ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/lib/ffi/platform/mipsel-linux/types.conf ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/lib/ffi/platform/x86_64-darwin/types.conf ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/lib/ffi/platform.rb ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/lib/ffi/struct_layout.rb ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/lib/ffi/struct_layout_builder.rb ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/lib/ffi/types.rb ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/lib/ffi/io.rb ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/lib/ffi/struct_by_reference.rb ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/lib/ffi/library.rb ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/lib/ffi/autopointer.rb ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/lib/ffi/version.rb ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/lib/ffi/data_converter.rb ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/lib/ffi/variadic.rb ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/lib/ffi/managedstruct.rb ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/lib/ffi/errno.rb ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/lib/ffi/callback.rb ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/lib/ffi/memorypointer.rb ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/Gemfile ./vendor/bundle/ruby/2.6.0/gems/cocoapods-trunk-1.4.1/spec/spec_helper.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-trunk-1.4.1/spec/fixtures/BananaLib.podspec ./vendor/bundle/ruby/2.6.0/gems/cocoapods-trunk-1.4.1/spec/command/trunk_spec.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-trunk-1.4.1/spec/command/trunk/addowner_spec.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-trunk-1.4.1/spec/command/trunk/remove_owner_spec.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-trunk-1.4.1/spec/command/trunk/delete_spec.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-trunk-1.4.1/spec/command/trunk/register_spec.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-trunk-1.4.1/spec/command/trunk/me_spec.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-trunk-1.4.1/spec/command/trunk/info_spec.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-trunk-1.4.1/spec/command/trunk/push_spec.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-trunk-1.4.1/spec/command/trunk/deprecate_spec.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-trunk-1.4.1/.kick ./vendor/bundle/ruby/2.6.0/gems/cocoapods-trunk-1.4.1/Rakefile ./vendor/bundle/ruby/2.6.0/gems/cocoapods-trunk-1.4.1/cocoapods-trunk.gemspec ./vendor/bundle/ruby/2.6.0/gems/cocoapods-trunk-1.4.1/lib/pod/command/trunk.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-trunk-1.4.1/lib/pod/command/trunk/push.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-trunk-1.4.1/lib/pod/command/trunk/info.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-trunk-1.4.1/lib/pod/command/trunk/remove_owner.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-trunk-1.4.1/lib/pod/command/trunk/me.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-trunk-1.4.1/lib/pod/command/trunk/add_owner.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-trunk-1.4.1/lib/pod/command/trunk/register.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-trunk-1.4.1/lib/pod/command/trunk/deprecate.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-trunk-1.4.1/lib/pod/command/trunk/delete.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-trunk-1.4.1/lib/cocoapods_plugin.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-trunk-1.4.1/lib/cocoapods_trunk.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-trunk-1.4.1/Gemfile ./vendor/bundle/ruby/2.6.0/gems/cocoapods-trunk-1.4.1/Gemfile.lock ./vendor/bundle/ruby/2.6.0/gems/multipart-post-2.1.1/.yardopts ./vendor/bundle/ruby/2.6.0/gems/multipart-post-2.1.1/.rspec ./vendor/bundle/ruby/2.6.0/gems/multipart-post-2.1.1/LICENSE ./vendor/bundle/ruby/2.6.0/gems/multipart-post-2.1.1/spec/spec_helper.rb ./vendor/bundle/ruby/2.6.0/gems/multipart-post-2.1.1/spec/net/http/post/multipart_spec.rb ./vendor/bundle/ruby/2.6.0/gems/multipart-post-2.1.1/spec/parts_spec.rb ./vendor/bundle/ruby/2.6.0/gems/multipart-post-2.1.1/spec/composite_io_spec.rb ./vendor/bundle/ruby/2.6.0/gems/multipart-post-2.1.1/Rakefile ./vendor/bundle/ruby/2.6.0/gems/multipart-post-2.1.1/lib/net/http/post/multipart.rb ./vendor/bundle/ruby/2.6.0/gems/multipart-post-2.1.1/lib/parts.rb ./vendor/bundle/ruby/2.6.0/gems/multipart-post-2.1.1/lib/composite_io.rb ./vendor/bundle/ruby/2.6.0/gems/multipart-post-2.1.1/lib/multipart_post.rb ./vendor/bundle/ruby/2.6.0/gems/multipart-post-2.1.1/lib/multipartable.rb ./vendor/bundle/ruby/2.6.0/gems/multipart-post-2.1.1/Gemfile ./vendor/bundle/ruby/2.6.0/gems/multipart-post-2.1.1/multipart-post.gemspec ./vendor/bundle/ruby/2.6.0/gems/sawyer-0.8.2/script/bootstrap ./vendor/bundle/ruby/2.6.0/gems/sawyer-0.8.2/script/test ./vendor/bundle/ruby/2.6.0/gems/sawyer-0.8.2/script/release ./vendor/bundle/ruby/2.6.0/gems/sawyer-0.8.2/script/package ./vendor/bundle/ruby/2.6.0/gems/sawyer-0.8.2/script/console ./vendor/bundle/ruby/2.6.0/gems/sawyer-0.8.2/Rakefile ./vendor/bundle/ruby/2.6.0/gems/sawyer-0.8.2/sawyer.gemspec ./vendor/bundle/ruby/2.6.0/gems/sawyer-0.8.2/lib/sawyer.rb ./vendor/bundle/ruby/2.6.0/gems/sawyer-0.8.2/lib/sawyer/agent.rb ./vendor/bundle/ruby/2.6.0/gems/sawyer-0.8.2/lib/sawyer/serializer.rb ./vendor/bundle/ruby/2.6.0/gems/sawyer-0.8.2/lib/sawyer/link_parsers/simple.rb ./vendor/bundle/ruby/2.6.0/gems/sawyer-0.8.2/lib/sawyer/link_parsers/hal.rb ./vendor/bundle/ruby/2.6.0/gems/sawyer-0.8.2/lib/sawyer/response.rb ./vendor/bundle/ruby/2.6.0/gems/sawyer-0.8.2/lib/sawyer/resource.rb ./vendor/bundle/ruby/2.6.0/gems/sawyer-0.8.2/lib/sawyer/relation.rb ./vendor/bundle/ruby/2.6.0/gems/sawyer-0.8.2/Gemfile ./vendor/bundle/ruby/2.6.0/gems/cocoapods-deintegrate-1.0.4/LICENSE ./vendor/bundle/ruby/2.6.0/gems/cocoapods-deintegrate-1.0.4/lib/cocoapods_plugin.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-deintegrate-1.0.4/lib/cocoapods_deintegrate.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-deintegrate-1.0.4/lib/cocoapods/deintegrate/gem_version.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-deintegrate-1.0.4/lib/cocoapods/deintegrator.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-deintegrate-1.0.4/lib/cocoapods/command/deintegrate.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-http-cache-2.2.0/LICENSE ./vendor/bundle/ruby/2.6.0/gems/faraday-http-cache-2.2.0/spec/spec_helper.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-http-cache-2.2.0/spec/validation_spec.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-http-cache-2.2.0/spec/json_spec.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-http-cache-2.2.0/spec/instrumentation_spec.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-http-cache-2.2.0/spec/storage_spec.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-http-cache-2.2.0/spec/http_cache_spec.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-http-cache-2.2.0/spec/binary_spec.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-http-cache-2.2.0/spec/support/test_app.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-http-cache-2.2.0/spec/support/test_server.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-http-cache-2.2.0/spec/request_spec.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-http-cache-2.2.0/spec/cache_control_spec.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-http-cache-2.2.0/spec/response_spec.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-http-cache-2.2.0/lib/faraday/http_cache.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-http-cache-2.2.0/lib/faraday/http_cache/storage.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-http-cache-2.2.0/lib/faraday/http_cache/cache_control.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-http-cache-2.2.0/lib/faraday/http_cache/response.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-http-cache-2.2.0/lib/faraday/http_cache/request.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-http-cache-2.2.0/lib/faraday-http-cache.rb ./vendor/bundle/ruby/2.6.0/gems/algoliasearch-1.27.1/.rspec ./vendor/bundle/ruby/2.6.0/gems/algoliasearch-1.27.1/LICENSE ./vendor/bundle/ruby/2.6.0/gems/algoliasearch-1.27.1/resources/ca-bundle.crt ./vendor/bundle/ruby/2.6.0/gems/algoliasearch-1.27.1/spec/mock_spec.rb ./vendor/bundle/ruby/2.6.0/gems/algoliasearch-1.27.1/spec/spec_helper.rb ./vendor/bundle/ruby/2.6.0/gems/algoliasearch-1.27.1/spec/client_spec.rb ./vendor/bundle/ruby/2.6.0/gems/algoliasearch-1.27.1/spec/account_client_spec.rb ./vendor/bundle/ruby/2.6.0/gems/algoliasearch-1.27.1/spec/stub_spec.rb ./vendor/bundle/ruby/2.6.0/gems/algoliasearch-1.27.1/Rakefile ./vendor/bundle/ruby/2.6.0/gems/algoliasearch-1.27.1/lib/algolia/analytics.rb ./vendor/bundle/ruby/2.6.0/gems/algoliasearch-1.27.1/lib/algolia/insights.rb ./vendor/bundle/ruby/2.6.0/gems/algoliasearch-1.27.1/lib/algolia/webmock.rb ./vendor/bundle/ruby/2.6.0/gems/algoliasearch-1.27.1/lib/algolia/protocol.rb ./vendor/bundle/ruby/2.6.0/gems/algoliasearch-1.27.1/lib/algolia/client.rb ./vendor/bundle/ruby/2.6.0/gems/algoliasearch-1.27.1/lib/algolia/version.rb ./vendor/bundle/ruby/2.6.0/gems/algoliasearch-1.27.1/lib/algolia/error.rb ./vendor/bundle/ruby/2.6.0/gems/algoliasearch-1.27.1/lib/algolia/index.rb ./vendor/bundle/ruby/2.6.0/gems/algoliasearch-1.27.1/lib/algolia/account_client.rb ./vendor/bundle/ruby/2.6.0/gems/algoliasearch-1.27.1/lib/algoliasearch.rb ./vendor/bundle/ruby/2.6.0/gems/algoliasearch-1.27.1/Gemfile ./vendor/bundle/ruby/2.6.0/gems/algoliasearch-1.27.1/Gemfile.lock ./vendor/bundle/ruby/2.6.0/gems/algoliasearch-1.27.1/algoliasearch.gemspec ./vendor/bundle/ruby/2.6.0/gems/algoliasearch-1.27.1/contacts.json ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/i18n_railtie.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/json.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/security_utils.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/gem_version.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/dependencies.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/ordered_options.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/cache/mem_cache_store.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/cache/null_store.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/cache/memory_store.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/cache/file_store.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/cache/strategy/local_cache.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/cache/strategy/local_cache_middleware.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/ordered_hash.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/string_inquirer.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/date.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/struct.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/string.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/date_time.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/module.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/name_error.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/array.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/file/atomic.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/hash/except.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/hash/deep_merge.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/hash/indifferent_access.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/hash/reverse_merge.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/hash/keys.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/hash/compact.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/hash/transform_values.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/hash/conversions.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/hash/slice.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/array/extract_options.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/array/wrap.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/array/access.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/array/prepend_and_append.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/array/grouping.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/array/conversions.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/class.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/numeric.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/load_error.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/uri.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/module/concerning.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/module/attr_internal.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/module/delegation.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/module/introspection.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/module/qualified_const.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/module/aliasing.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/module/reachable.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/module/method_transplanting.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/module/deprecation.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/module/anonymous.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/module/remove_method.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/module/attribute_accessors.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/digest/uuid.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/date/zones.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/date/calculations.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/date/conversions.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/date/acts_like.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/integer.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/hash.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/date_time/zones.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/date_time/calculations.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/date_time/conversions.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/date_time/acts_like.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/date_time/compatibility.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/file.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/regexp.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/time/zones.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/time/calculations.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/time/conversions.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/time/acts_like.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/time/marshal.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/time/compatibility.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/numeric/bytes.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/numeric/conversions.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/numeric/time.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/object/blank.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/object/to_query.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/object/json.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/object/with_options.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/object/inclusion.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/object/to_param.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/object/deep_dup.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/object/duplicable.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/object/conversions.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/object/acts_like.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/object/try.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/object/instance_variables.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/object/itself.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/class/delegating_attributes.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/class/subclasses.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/class/attribute.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/class/attribute_accessors.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/integer/multiple.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/integer/inflections.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/integer/time.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/big_decimal/yaml_conversions.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/big_decimal/conversions.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/range.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/kernel.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/benchmark.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/string/filters.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/string/strip.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/string/indent.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/string/zones.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/string/starts_ends_with.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/string/exclude.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/string/access.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/string/conversions.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/string/inquiry.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/string/output_safety.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/string/inflections.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/string/multibyte.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/string/behavior.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/thread.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/object.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/date_and_time/zones.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/date_and_time/calculations.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/date_and_time/compatibility.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/range/conversions.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/range/overlaps.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/range/include_range.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/range/each.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/marshal.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/time.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/enumerable.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/kernel/reporting.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/kernel/singleton_class.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/kernel/agnostics.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/kernel/debugger.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/kernel/concern.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/core_ext/big_decimal.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/message_verifier.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/callbacks.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/log_subscriber/test_helper.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/rails.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/option_merger.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/i18n.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/notifications.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/descendants_tracker.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/per_thread_registry.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/inflector/transliterate.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/inflector/methods.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/inflector/inflections.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/values/unicode_tables.dat ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/values/time_zone.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/test_case.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/dependencies/autoload.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/tagged_logging.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/builder.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/time_with_zone.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/hash_with_indifferent_access.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/number_helper/number_to_phone_converter.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/number_helper/number_to_human_converter.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/number_helper/number_converter.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/number_helper/number_to_percentage_converter.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/number_helper/number_to_delimited_converter.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/number_helper/number_to_currency_converter.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/number_helper/number_to_human_size_converter.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/number_helper/number_to_rounded_converter.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/concern.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/testing/declarative.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/testing/constant_lookup.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/testing/setup_and_teardown.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/testing/tagged_logging.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/testing/time_helpers.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/testing/assertions.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/testing/autorun.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/testing/deprecation.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/testing/isolation.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/concurrency/latch.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/file_update_checker.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/cache.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/backtrace_cleaner.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/railtie.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/json/decoding.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/json/encoding.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/logger.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/all.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/deprecation.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/deprecation/reporting.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/deprecation/proxy_wrappers.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/deprecation/method_wrappers.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/deprecation/behaviors.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/deprecation/instance_delegator.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/subscriber.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/logger_silence.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/logger_thread_safe_level.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/inflector.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/duration.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/key_generator.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/lazy_load_hooks.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/proxy_object.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/configurable.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/benchmarkable.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/version.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/multibyte/chars.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/multibyte/unicode.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/rescuable.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/message_encryptor.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/inflections.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/multibyte.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/number_helper.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/time.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/xml_mini.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/xml_mini/rexml.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/xml_mini/libxmlsax.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/xml_mini/nokogiri.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/xml_mini/jdom.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/xml_mini/nokogirisax.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/xml_mini/libxml.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/notifications/fanout.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/notifications/instrumenter.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/log_subscriber.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support/gzip.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/lib/active_support.rb ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/MIT-LICENSE ./vendor/bundle/ruby/2.6.0/gems/activesupport-4.2.11.1/README.rdoc ./vendor/bundle/ruby/2.6.0/gems/httpclient-2.8.3/test/server.cert ./vendor/bundle/ruby/2.6.0/gems/httpclient-2.8.3/test/test_hexdump.rb ./vendor/bundle/ruby/2.6.0/gems/httpclient-2.8.3/test/test_httpclient.rb ./vendor/bundle/ruby/2.6.0/gems/httpclient-2.8.3/test/test_webagent-cookie.rb ./vendor/bundle/ruby/2.6.0/gems/httpclient-2.8.3/test/server.key ./vendor/bundle/ruby/2.6.0/gems/httpclient-2.8.3/test/htdigest ./vendor/bundle/ruby/2.6.0/gems/httpclient-2.8.3/test/ca-chain.pem ./vendor/bundle/ruby/2.6.0/gems/httpclient-2.8.3/test/sslsvr.rb ./vendor/bundle/ruby/2.6.0/gems/httpclient-2.8.3/test/helper.rb ./vendor/bundle/ruby/2.6.0/gems/httpclient-2.8.3/test/test_jsonclient.rb ./vendor/bundle/ruby/2.6.0/gems/httpclient-2.8.3/test/test_include_client.rb ./vendor/bundle/ruby/2.6.0/gems/httpclient-2.8.3/test/jruby_ssl_socket/test_pemutils.rb ./vendor/bundle/ruby/2.6.0/gems/httpclient-2.8.3/test/test_ssl.rb ./vendor/bundle/ruby/2.6.0/gems/httpclient-2.8.3/test/test_http-access2.rb ./vendor/bundle/ruby/2.6.0/gems/httpclient-2.8.3/test/ca.cert ./vendor/bundle/ruby/2.6.0/gems/httpclient-2.8.3/test/htpasswd ./vendor/bundle/ruby/2.6.0/gems/httpclient-2.8.3/test/test_auth.rb ./vendor/bundle/ruby/2.6.0/gems/httpclient-2.8.3/test/client.cert ./vendor/bundle/ruby/2.6.0/gems/httpclient-2.8.3/test/subca.cert ./vendor/bundle/ruby/2.6.0/gems/httpclient-2.8.3/test/client-pass.key ./vendor/bundle/ruby/2.6.0/gems/httpclient-2.8.3/test/test_cookie.rb ./vendor/bundle/ruby/2.6.0/gems/httpclient-2.8.3/test/runner.rb ./vendor/bundle/ruby/2.6.0/gems/httpclient-2.8.3/test/client.key ./vendor/bundle/ruby/2.6.0/gems/httpclient-2.8.3/bin/httpclient ./vendor/bundle/ruby/2.6.0/gems/httpclient-2.8.3/bin/jsonclient ./vendor/bundle/ruby/2.6.0/gems/httpclient-2.8.3/sample/howto.rb ./vendor/bundle/ruby/2.6.0/gems/httpclient-2.8.3/sample/oauth_friendfeed.rb ./vendor/bundle/ruby/2.6.0/gems/httpclient-2.8.3/sample/dav.rb ./vendor/bundle/ruby/2.6.0/gems/httpclient-2.8.3/sample/ssl/1000key.pem ./vendor/bundle/ruby/2.6.0/gems/httpclient-2.8.3/sample/ssl/0key.pem ./vendor/bundle/ruby/2.6.0/gems/httpclient-2.8.3/sample/ssl/webrick_httpsd.rb ./vendor/bundle/ruby/2.6.0/gems/httpclient-2.8.3/sample/ssl/1000cert.pem ./vendor/bundle/ruby/2.6.0/gems/httpclient-2.8.3/sample/ssl/ssl_client.rb ./vendor/bundle/ruby/2.6.0/gems/httpclient-2.8.3/sample/ssl/0cert.pem ./vendor/bundle/ruby/2.6.0/gems/httpclient-2.8.3/sample/async.rb ./vendor/bundle/ruby/2.6.0/gems/httpclient-2.8.3/sample/oauth_twitter.rb ./vendor/bundle/ruby/2.6.0/gems/httpclient-2.8.3/sample/cookie.rb ./vendor/bundle/ruby/2.6.0/gems/httpclient-2.8.3/sample/jsonclient.rb ./vendor/bundle/ruby/2.6.0/gems/httpclient-2.8.3/sample/stream.rb ./vendor/bundle/ruby/2.6.0/gems/httpclient-2.8.3/sample/wcat.rb ./vendor/bundle/ruby/2.6.0/gems/httpclient-2.8.3/sample/oauth_buzz.rb ./vendor/bundle/ruby/2.6.0/gems/httpclient-2.8.3/sample/thread.rb ./vendor/bundle/ruby/2.6.0/gems/httpclient-2.8.3/sample/auth.rb ./vendor/bundle/ruby/2.6.0/gems/httpclient-2.8.3/lib/httpclient/ssl_socket.rb ./vendor/bundle/ruby/2.6.0/gems/httpclient-2.8.3/lib/httpclient/jruby_ssl_socket.rb ./vendor/bundle/ruby/2.6.0/gems/httpclient-2.8.3/lib/httpclient/http.rb ./vendor/bundle/ruby/2.6.0/gems/httpclient-2.8.3/lib/httpclient/connection.rb ./vendor/bundle/ruby/2.6.0/gems/httpclient-2.8.3/lib/httpclient/cookie.rb ./vendor/bundle/ruby/2.6.0/gems/httpclient-2.8.3/lib/httpclient/cacert1024.pem ./vendor/bundle/ruby/2.6.0/gems/httpclient-2.8.3/lib/httpclient/timeout.rb ./vendor/bundle/ruby/2.6.0/gems/httpclient-2.8.3/lib/httpclient/session.rb ./vendor/bundle/ruby/2.6.0/gems/httpclient-2.8.3/lib/httpclient/webagent-cookie.rb ./vendor/bundle/ruby/2.6.0/gems/httpclient-2.8.3/lib/httpclient/util.rb ./vendor/bundle/ruby/2.6.0/gems/httpclient-2.8.3/lib/httpclient/include_client.rb ./vendor/bundle/ruby/2.6.0/gems/httpclient-2.8.3/lib/httpclient/cacert.pem ./vendor/bundle/ruby/2.6.0/gems/httpclient-2.8.3/lib/httpclient/version.rb ./vendor/bundle/ruby/2.6.0/gems/httpclient-2.8.3/lib/httpclient/ssl_config.rb ./vendor/bundle/ruby/2.6.0/gems/httpclient-2.8.3/lib/httpclient/auth.rb ./vendor/bundle/ruby/2.6.0/gems/httpclient-2.8.3/lib/http-access2/http.rb ./vendor/bundle/ruby/2.6.0/gems/httpclient-2.8.3/lib/http-access2/cookie.rb ./vendor/bundle/ruby/2.6.0/gems/httpclient-2.8.3/lib/hexdump.rb ./vendor/bundle/ruby/2.6.0/gems/httpclient-2.8.3/lib/http-access2.rb ./vendor/bundle/ruby/2.6.0/gems/httpclient-2.8.3/lib/oauthclient.rb ./vendor/bundle/ruby/2.6.0/gems/httpclient-2.8.3/lib/jsonclient.rb ./vendor/bundle/ruby/2.6.0/gems/httpclient-2.8.3/lib/httpclient.rb ./vendor/bundle/ruby/2.6.0/gems/xcpretty-0.3.0/xcpretty.gemspec ./vendor/bundle/ruby/2.6.0/gems/xcpretty-0.3.0/bin/xcpretty ./vendor/bundle/ruby/2.6.0/gems/xcpretty-0.3.0/features/xcpretty.feature ./vendor/bundle/ruby/2.6.0/gems/xcpretty-0.3.0/features/tap_format.feature ./vendor/bundle/ruby/2.6.0/gems/xcpretty-0.3.0/features/custom_reporter.feature ./vendor/bundle/ruby/2.6.0/gems/xcpretty-0.3.0/features/json_compilation_database_report.feature ./vendor/bundle/ruby/2.6.0/gems/xcpretty-0.3.0/features/test_format.feature ./vendor/bundle/ruby/2.6.0/gems/xcpretty-0.3.0/features/custom_formatter.feature ./vendor/bundle/ruby/2.6.0/gems/xcpretty-0.3.0/features/steps/junit_steps.rb ./vendor/bundle/ruby/2.6.0/gems/xcpretty-0.3.0/features/steps/html_steps.rb ./vendor/bundle/ruby/2.6.0/gems/xcpretty-0.3.0/features/steps/report_steps.rb ./vendor/bundle/ruby/2.6.0/gems/xcpretty-0.3.0/features/steps/custom_reporter_steps.rb ./vendor/bundle/ruby/2.6.0/gems/xcpretty-0.3.0/features/steps/formatting_steps.rb ./vendor/bundle/ruby/2.6.0/gems/xcpretty-0.3.0/features/steps/json_steps.rb ./vendor/bundle/ruby/2.6.0/gems/xcpretty-0.3.0/features/steps/xcpretty_steps.rb ./vendor/bundle/ruby/2.6.0/gems/xcpretty-0.3.0/features/knock_format.feature ./vendor/bundle/ruby/2.6.0/gems/xcpretty-0.3.0/features/support/env.rb ./vendor/bundle/ruby/2.6.0/gems/xcpretty-0.3.0/features/fixtures/xcodebuild.log ./vendor/bundle/ruby/2.6.0/gems/xcpretty-0.3.0/features/junit_report.feature ./vendor/bundle/ruby/2.6.0/gems/xcpretty-0.3.0/features/simple_format.feature ./vendor/bundle/ruby/2.6.0/gems/xcpretty-0.3.0/features/html_report.feature ./vendor/bundle/ruby/2.6.0/gems/xcpretty-0.3.0/spec/spec_helper.rb ./vendor/bundle/ruby/2.6.0/gems/xcpretty-0.3.0/spec/xcpretty/syntax_spec.rb ./vendor/bundle/ruby/2.6.0/gems/xcpretty-0.3.0/spec/xcpretty/term_spec.rb ./vendor/bundle/ruby/2.6.0/gems/xcpretty-0.3.0/spec/xcpretty/ansi_spec.rb ./vendor/bundle/ruby/2.6.0/gems/xcpretty-0.3.0/spec/xcpretty/formatters/formatter_spec.rb ./vendor/bundle/ruby/2.6.0/gems/xcpretty-0.3.0/spec/xcpretty/formatters/simple_spec.rb ./vendor/bundle/ruby/2.6.0/gems/xcpretty-0.3.0/spec/xcpretty/formatters/rspec_spec.rb ./vendor/bundle/ruby/2.6.0/gems/xcpretty-0.3.0/spec/xcpretty/snippet_spec.rb ./vendor/bundle/ruby/2.6.0/gems/xcpretty-0.3.0/spec/xcpretty/parser_spec.rb ./vendor/bundle/ruby/2.6.0/gems/xcpretty-0.3.0/spec/xcpretty/printer_spec.rb ./vendor/bundle/ruby/2.6.0/gems/xcpretty-0.3.0/spec/xcpretty/reporters/junit_spec.rb ./vendor/bundle/ruby/2.6.0/gems/xcpretty-0.3.0/spec/xcpretty/reporters/reporter_spec.rb ./vendor/bundle/ruby/2.6.0/gems/xcpretty-0.3.0/spec/support/matchers/colors.rb ./vendor/bundle/ruby/2.6.0/gems/xcpretty-0.3.0/spec/fixtures/custom_reporter.rb ./vendor/bundle/ruby/2.6.0/gems/xcpretty-0.3.0/spec/fixtures/NSStringTests.m ./vendor/bundle/ruby/2.6.0/gems/xcpretty-0.3.0/spec/fixtures/custom_formatter.rb ./vendor/bundle/ruby/2.6.0/gems/xcpretty-0.3.0/spec/fixtures/constants.rb ./vendor/bundle/ruby/2.6.0/gems/xcpretty-0.3.0/spec/fixtures/oneliner.m ./vendor/bundle/ruby/2.6.0/gems/xcpretty-0.3.0/.kick ./vendor/bundle/ruby/2.6.0/gems/xcpretty-0.3.0/Rakefile ./vendor/bundle/ruby/2.6.0/gems/xcpretty-0.3.0/lib/xcpretty/printer.rb ./vendor/bundle/ruby/2.6.0/gems/xcpretty-0.3.0/lib/xcpretty/ansi.rb ./vendor/bundle/ruby/2.6.0/gems/xcpretty-0.3.0/lib/xcpretty/syntax.rb ./vendor/bundle/ruby/2.6.0/gems/xcpretty-0.3.0/lib/xcpretty/formatters/simple.rb ./vendor/bundle/ruby/2.6.0/gems/xcpretty-0.3.0/lib/xcpretty/formatters/tap.rb ./vendor/bundle/ruby/2.6.0/gems/xcpretty-0.3.0/lib/xcpretty/formatters/rspec.rb ./vendor/bundle/ruby/2.6.0/gems/xcpretty-0.3.0/lib/xcpretty/formatters/knock.rb ./vendor/bundle/ruby/2.6.0/gems/xcpretty-0.3.0/lib/xcpretty/formatters/formatter.rb ./vendor/bundle/ruby/2.6.0/gems/xcpretty-0.3.0/lib/xcpretty/parser.rb ./vendor/bundle/ruby/2.6.0/gems/xcpretty-0.3.0/lib/xcpretty/snippet.rb ./vendor/bundle/ruby/2.6.0/gems/xcpretty-0.3.0/lib/xcpretty/term.rb ./vendor/bundle/ruby/2.6.0/gems/xcpretty-0.3.0/lib/xcpretty/version.rb ./vendor/bundle/ruby/2.6.0/gems/xcpretty-0.3.0/lib/xcpretty/reporters/junit.rb ./vendor/bundle/ruby/2.6.0/gems/xcpretty-0.3.0/lib/xcpretty/reporters/reporter.rb ./vendor/bundle/ruby/2.6.0/gems/xcpretty-0.3.0/lib/xcpretty/reporters/html.rb ./vendor/bundle/ruby/2.6.0/gems/xcpretty-0.3.0/lib/xcpretty/reporters/json_compilation_database.rb ./vendor/bundle/ruby/2.6.0/gems/xcpretty-0.3.0/lib/xcpretty.rb ./vendor/bundle/ruby/2.6.0/gems/xcpretty-0.3.0/Gemfile ./vendor/bundle/ruby/2.6.0/gems/xcpretty-0.3.0/assets/report.html.erb ./vendor/bundle/ruby/2.6.0/gems/gh_inspector-1.1.3/.rspec ./vendor/bundle/ruby/2.6.0/gems/gh_inspector-1.1.3/LICENSE ./vendor/bundle/ruby/2.6.0/gems/gh_inspector-1.1.3/bin/setup ./vendor/bundle/ruby/2.6.0/gems/gh_inspector-1.1.3/bin/console ./vendor/bundle/ruby/2.6.0/gems/gh_inspector-1.1.3/Rakefile ./vendor/bundle/ruby/2.6.0/gems/gh_inspector-1.1.3/gh_inspector.gemspec ./vendor/bundle/ruby/2.6.0/gems/gh_inspector-1.1.3/lib/gh_inspector.rb ./vendor/bundle/ruby/2.6.0/gems/gh_inspector-1.1.3/lib/gh_inspector/evidence.rb ./vendor/bundle/ruby/2.6.0/gems/gh_inspector-1.1.3/lib/gh_inspector/exception_hound.rb ./vendor/bundle/ruby/2.6.0/gems/gh_inspector-1.1.3/lib/gh_inspector/sidekick.rb ./vendor/bundle/ruby/2.6.0/gems/gh_inspector-1.1.3/lib/gh_inspector/inspector.rb ./vendor/bundle/ruby/2.6.0/gems/gh_inspector-1.1.3/lib/gh_inspector/version.rb ./vendor/bundle/ruby/2.6.0/gems/gh_inspector-1.1.3/Gemfile ./vendor/bundle/ruby/2.6.0/gems/molinillo-0.6.6/LICENSE ./vendor/bundle/ruby/2.6.0/gems/molinillo-0.6.6/lib/molinillo.rb ./vendor/bundle/ruby/2.6.0/gems/molinillo-0.6.6/lib/molinillo/state.rb ./vendor/bundle/ruby/2.6.0/gems/molinillo-0.6.6/lib/molinillo/gem_metadata.rb ./vendor/bundle/ruby/2.6.0/gems/molinillo-0.6.6/lib/molinillo/errors.rb ./vendor/bundle/ruby/2.6.0/gems/molinillo-0.6.6/lib/molinillo/resolution.rb ./vendor/bundle/ruby/2.6.0/gems/molinillo-0.6.6/lib/molinillo/resolver.rb ./vendor/bundle/ruby/2.6.0/gems/molinillo-0.6.6/lib/molinillo/dependency_graph.rb ./vendor/bundle/ruby/2.6.0/gems/molinillo-0.6.6/lib/molinillo/delegates/resolution_state.rb ./vendor/bundle/ruby/2.6.0/gems/molinillo-0.6.6/lib/molinillo/delegates/specification_provider.rb ./vendor/bundle/ruby/2.6.0/gems/molinillo-0.6.6/lib/molinillo/modules/specification_provider.rb ./vendor/bundle/ruby/2.6.0/gems/molinillo-0.6.6/lib/molinillo/modules/ui.rb ./vendor/bundle/ruby/2.6.0/gems/molinillo-0.6.6/lib/molinillo/dependency_graph/tag.rb ./vendor/bundle/ruby/2.6.0/gems/molinillo-0.6.6/lib/molinillo/dependency_graph/delete_edge.rb ./vendor/bundle/ruby/2.6.0/gems/molinillo-0.6.6/lib/molinillo/dependency_graph/add_vertex.rb ./vendor/bundle/ruby/2.6.0/gems/molinillo-0.6.6/lib/molinillo/dependency_graph/vertex.rb ./vendor/bundle/ruby/2.6.0/gems/molinillo-0.6.6/lib/molinillo/dependency_graph/add_edge_no_circular.rb ./vendor/bundle/ruby/2.6.0/gems/molinillo-0.6.6/lib/molinillo/dependency_graph/set_payload.rb ./vendor/bundle/ruby/2.6.0/gems/molinillo-0.6.6/lib/molinillo/dependency_graph/action.rb ./vendor/bundle/ruby/2.6.0/gems/molinillo-0.6.6/lib/molinillo/dependency_graph/detach_vertex_named.rb ./vendor/bundle/ruby/2.6.0/gems/molinillo-0.6.6/lib/molinillo/dependency_graph/log.rb ./vendor/bundle/ruby/2.6.0/gems/molinillo-0.6.6/lib/molinillo/compatibility.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-search-1.0.0/spec/spec_helper.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-search-1.0.0/spec/spec_helper/temporary_repos.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-search-1.0.0/spec/spec_helper/command.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-search-1.0.0/spec/spec_helper/pre_flight.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-search-1.0.0/spec/spec_helper/user_interface.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-search-1.0.0/spec/spec_helper/fixture.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-search-1.0.0/spec/fixtures/spec-repos/test_repo/OrangeFramework/0.1.0/OrangeFramework.podspec ./vendor/bundle/ruby/2.6.0/gems/cocoapods-search-1.0.0/spec/fixtures/spec-repos/test_repo/BananaLib/1.0/BananaLib.podspec ./vendor/bundle/ruby/2.6.0/gems/cocoapods-search-1.0.0/spec/fixtures/spec-repos/test_repo/monkey/1.0.2/monkey.podspec ./vendor/bundle/ruby/2.6.0/gems/cocoapods-search-1.0.0/spec/fixtures/spec-repos/test_repo/Pod+With+Plus+Signs/1.0/Pod+With+Plus+Signs.podspec ./vendor/bundle/ruby/2.6.0/gems/cocoapods-search-1.0.0/spec/fixtures/spec-repos/test_repo/JSONKit/1.4/JSONKit.podspec ./vendor/bundle/ruby/2.6.0/gems/cocoapods-search-1.0.0/spec/fixtures/spec-repos/test_repo/JSONKit/999.999.999/JSONKit.podspec ./vendor/bundle/ruby/2.6.0/gems/cocoapods-search-1.0.0/spec/fixtures/spec-repos/test_repo/Realm/0.94/Realm.podspec ./vendor/bundle/ruby/2.6.0/gems/cocoapods-search-1.0.0/spec/command/search_spec.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-search-1.0.0/.gitmodules ./vendor/bundle/ruby/2.6.0/gems/cocoapods-search-1.0.0/Rakefile ./vendor/bundle/ruby/2.6.0/gems/cocoapods-search-1.0.0/lib/cocoapods_plugin.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-search-1.0.0/lib/cocoapods-search.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-search-1.0.0/lib/cocoapods-search/gem_version.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-search-1.0.0/lib/cocoapods-search/command/search.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-search-1.0.0/lib/cocoapods-search/command.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-search-1.0.0/Gemfile ./vendor/bundle/ruby/2.6.0/gems/cocoapods-search-1.0.0/Gemfile.lock ./vendor/bundle/ruby/2.6.0/gems/cocoapods-search-1.0.0/cocoapods-search.gemspec ./vendor/bundle/ruby/2.6.0/gems/rake-13.0.1/History.rdoc ./vendor/bundle/ruby/2.6.0/gems/rake-13.0.1/CONTRIBUTING.rdoc ./vendor/bundle/ruby/2.6.0/gems/rake-13.0.1/bin/rake ./vendor/bundle/ruby/2.6.0/gems/rake-13.0.1/bin/setup ./vendor/bundle/ruby/2.6.0/gems/rake-13.0.1/bin/bundle ./vendor/bundle/ruby/2.6.0/gems/rake-13.0.1/bin/rubocop ./vendor/bundle/ruby/2.6.0/gems/rake-13.0.1/bin/rdoc ./vendor/bundle/ruby/2.6.0/gems/rake-13.0.1/bin/console ./vendor/bundle/ruby/2.6.0/gems/rake-13.0.1/Rakefile ./vendor/bundle/ruby/2.6.0/gems/rake-13.0.1/lib/rake/thread_history_display.rb ./vendor/bundle/ruby/2.6.0/gems/rake-13.0.1/lib/rake/scope.rb ./vendor/bundle/ruby/2.6.0/gems/rake-13.0.1/lib/rake/late_time.rb ./vendor/bundle/ruby/2.6.0/gems/rake-13.0.1/lib/rake/cloneable.rb ./vendor/bundle/ruby/2.6.0/gems/rake-13.0.1/lib/rake/backtrace.rb ./vendor/bundle/ruby/2.6.0/gems/rake-13.0.1/lib/rake/trace_output.rb ./vendor/bundle/ruby/2.6.0/gems/rake-13.0.1/lib/rake/packagetask.rb ./vendor/bundle/ruby/2.6.0/gems/rake-13.0.1/lib/rake/rule_recursion_overflow_error.rb ./vendor/bundle/ruby/2.6.0/gems/rake-13.0.1/lib/rake/task_manager.rb ./vendor/bundle/ruby/2.6.0/gems/rake-13.0.1/lib/rake/dsl_definition.rb ./vendor/bundle/ruby/2.6.0/gems/rake-13.0.1/lib/rake/file_utils.rb ./vendor/bundle/ruby/2.6.0/gems/rake-13.0.1/lib/rake/ext/string.rb ./vendor/bundle/ruby/2.6.0/gems/rake-13.0.1/lib/rake/ext/core.rb ./vendor/bundle/ruby/2.6.0/gems/rake-13.0.1/lib/rake/task_arguments.rb ./vendor/bundle/ruby/2.6.0/gems/rake-13.0.1/lib/rake/application.rb ./vendor/bundle/ruby/2.6.0/gems/rake-13.0.1/lib/rake/tasklib.rb ./vendor/bundle/ruby/2.6.0/gems/rake-13.0.1/lib/rake/rake_module.rb ./vendor/bundle/ruby/2.6.0/gems/rake-13.0.1/lib/rake/testtask.rb ./vendor/bundle/ruby/2.6.0/gems/rake-13.0.1/lib/rake/invocation_exception_mixin.rb ./vendor/bundle/ruby/2.6.0/gems/rake-13.0.1/lib/rake/pseudo_status.rb ./vendor/bundle/ruby/2.6.0/gems/rake-13.0.1/lib/rake/private_reader.rb ./vendor/bundle/ruby/2.6.0/gems/rake-13.0.1/lib/rake/rake_test_loader.rb ./vendor/bundle/ruby/2.6.0/gems/rake-13.0.1/lib/rake/win32.rb ./vendor/bundle/ruby/2.6.0/gems/rake-13.0.1/lib/rake/thread_pool.rb ./vendor/bundle/ruby/2.6.0/gems/rake-13.0.1/lib/rake/task_argument_error.rb ./vendor/bundle/ruby/2.6.0/gems/rake-13.0.1/lib/rake/cpu_counter.rb ./vendor/bundle/ruby/2.6.0/gems/rake-13.0.1/lib/rake/invocation_chain.rb ./vendor/bundle/ruby/2.6.0/gems/rake-13.0.1/lib/rake/file_utils_ext.rb ./vendor/bundle/ruby/2.6.0/gems/rake-13.0.1/lib/rake/early_time.rb ./vendor/bundle/ruby/2.6.0/gems/rake-13.0.1/lib/rake/linked_list.rb ./vendor/bundle/ruby/2.6.0/gems/rake-13.0.1/lib/rake/clean.rb ./vendor/bundle/ruby/2.6.0/gems/rake-13.0.1/lib/rake/version.rb ./vendor/bundle/ruby/2.6.0/gems/rake-13.0.1/lib/rake/name_space.rb ./vendor/bundle/ruby/2.6.0/gems/rake-13.0.1/lib/rake/default_loader.rb ./vendor/bundle/ruby/2.6.0/gems/rake-13.0.1/lib/rake/file_task.rb ./vendor/bundle/ruby/2.6.0/gems/rake-13.0.1/lib/rake/loaders/makefile.rb ./vendor/bundle/ruby/2.6.0/gems/rake-13.0.1/lib/rake/file_list.rb ./vendor/bundle/ruby/2.6.0/gems/rake-13.0.1/lib/rake/file_creation_task.rb ./vendor/bundle/ruby/2.6.0/gems/rake-13.0.1/lib/rake/phony.rb ./vendor/bundle/ruby/2.6.0/gems/rake-13.0.1/lib/rake/multi_task.rb ./vendor/bundle/ruby/2.6.0/gems/rake-13.0.1/lib/rake/promise.rb ./vendor/bundle/ruby/2.6.0/gems/rake-13.0.1/lib/rake/task.rb ./vendor/bundle/ruby/2.6.0/gems/rake-13.0.1/lib/rake.rb ./vendor/bundle/ruby/2.6.0/gems/rake-13.0.1/Gemfile ./vendor/bundle/ruby/2.6.0/gems/rake-13.0.1/doc/glossary.rdoc ./vendor/bundle/ruby/2.6.0/gems/rake-13.0.1/doc/proto_rake.rdoc ./vendor/bundle/ruby/2.6.0/gems/rake-13.0.1/doc/rational.rdoc ./vendor/bundle/ruby/2.6.0/gems/rake-13.0.1/doc/example/Rakefile1 ./vendor/bundle/ruby/2.6.0/gems/rake-13.0.1/doc/example/a.c ./vendor/bundle/ruby/2.6.0/gems/rake-13.0.1/doc/example/main.c ./vendor/bundle/ruby/2.6.0/gems/rake-13.0.1/doc/example/Rakefile2 ./vendor/bundle/ruby/2.6.0/gems/rake-13.0.1/doc/example/b.c ./vendor/bundle/ruby/2.6.0/gems/rake-13.0.1/doc/rake.1 ./vendor/bundle/ruby/2.6.0/gems/rake-13.0.1/doc/command_line_usage.rdoc ./vendor/bundle/ruby/2.6.0/gems/rake-13.0.1/doc/rakefile.rdoc ./vendor/bundle/ruby/2.6.0/gems/rake-13.0.1/doc/jamis.rb ./vendor/bundle/ruby/2.6.0/gems/rake-13.0.1/MIT-LICENSE ./vendor/bundle/ruby/2.6.0/gems/rake-13.0.1/exe/rake ./vendor/bundle/ruby/2.6.0/gems/rake-13.0.1/rake.gemspec ./vendor/bundle/ruby/2.6.0/gems/rake-13.0.1/README.rdoc ./vendor/bundle/ruby/2.6.0/gems/octokit-4.18.0/octokit.gemspec ./vendor/bundle/ruby/2.6.0/gems/octokit-4.18.0/Rakefile ./vendor/bundle/ruby/2.6.0/gems/octokit-4.18.0/lib/octokit.rb ./vendor/bundle/ruby/2.6.0/gems/octokit-4.18.0/lib/ext/sawyer/relation.rb ./vendor/bundle/ruby/2.6.0/gems/octokit-4.18.0/lib/octokit/middleware/follow_redirects.rb ./vendor/bundle/ruby/2.6.0/gems/octokit-4.18.0/lib/octokit/response/feed_parser.rb ./vendor/bundle/ruby/2.6.0/gems/octokit-4.18.0/lib/octokit/response/raise_error.rb ./vendor/bundle/ruby/2.6.0/gems/octokit-4.18.0/lib/octokit/repository.rb ./vendor/bundle/ruby/2.6.0/gems/octokit-4.18.0/lib/octokit/authentication.rb ./vendor/bundle/ruby/2.6.0/gems/octokit-4.18.0/lib/octokit/gist.rb ./vendor/bundle/ruby/2.6.0/gems/octokit-4.18.0/lib/octokit/enterprise_admin_client/search_indexing.rb ./vendor/bundle/ruby/2.6.0/gems/octokit-4.18.0/lib/octokit/enterprise_admin_client/admin_stats.rb ./vendor/bundle/ruby/2.6.0/gems/octokit-4.18.0/lib/octokit/enterprise_admin_client/license.rb ./vendor/bundle/ruby/2.6.0/gems/octokit-4.18.0/lib/octokit/enterprise_admin_client/orgs.rb ./vendor/bundle/ruby/2.6.0/gems/octokit-4.18.0/lib/octokit/enterprise_admin_client/users.rb ./vendor/bundle/ruby/2.6.0/gems/octokit-4.18.0/lib/octokit/rate_limit.rb ./vendor/bundle/ruby/2.6.0/gems/octokit-4.18.0/lib/octokit/default.rb ./vendor/bundle/ruby/2.6.0/gems/octokit-4.18.0/lib/octokit/connection.rb ./vendor/bundle/ruby/2.6.0/gems/octokit-4.18.0/lib/octokit/enterprise_management_console_client.rb ./vendor/bundle/ruby/2.6.0/gems/octokit-4.18.0/lib/octokit/enterprise_management_console_client/management_console.rb ./vendor/bundle/ruby/2.6.0/gems/octokit-4.18.0/lib/octokit/arguments.rb ./vendor/bundle/ruby/2.6.0/gems/octokit-4.18.0/lib/octokit/enterprise_admin_client.rb ./vendor/bundle/ruby/2.6.0/gems/octokit-4.18.0/lib/octokit/repo_arguments.rb ./vendor/bundle/ruby/2.6.0/gems/octokit-4.18.0/lib/octokit/organization.rb ./vendor/bundle/ruby/2.6.0/gems/octokit-4.18.0/lib/octokit/client.rb ./vendor/bundle/ruby/2.6.0/gems/octokit-4.18.0/lib/octokit/configurable.rb ./vendor/bundle/ruby/2.6.0/gems/octokit-4.18.0/lib/octokit/version.rb ./vendor/bundle/ruby/2.6.0/gems/octokit-4.18.0/lib/octokit/error.rb ./vendor/bundle/ruby/2.6.0/gems/octokit-4.18.0/lib/octokit/preview.rb ./vendor/bundle/ruby/2.6.0/gems/octokit-4.18.0/lib/octokit/warnable.rb ./vendor/bundle/ruby/2.6.0/gems/octokit-4.18.0/lib/octokit/client/commit_branches.rb ./vendor/bundle/ruby/2.6.0/gems/octokit-4.18.0/lib/octokit/client/gists.rb ./vendor/bundle/ruby/2.6.0/gems/octokit-4.18.0/lib/octokit/client/meta.rb ./vendor/bundle/ruby/2.6.0/gems/octokit-4.18.0/lib/octokit/client/source_import.rb ./vendor/bundle/ruby/2.6.0/gems/octokit-4.18.0/lib/octokit/client/community_profile.rb ./vendor/bundle/ruby/2.6.0/gems/octokit-4.18.0/lib/octokit/client/oauth_applications.rb ./vendor/bundle/ruby/2.6.0/gems/octokit-4.18.0/lib/octokit/client/licenses.rb ./vendor/bundle/ruby/2.6.0/gems/octokit-4.18.0/lib/octokit/client/pull_requests.rb ./vendor/bundle/ruby/2.6.0/gems/octokit-4.18.0/lib/octokit/client/projects.rb ./vendor/bundle/ruby/2.6.0/gems/octokit-4.18.0/lib/octokit/client/pub_sub_hubbub.rb ./vendor/bundle/ruby/2.6.0/gems/octokit-4.18.0/lib/octokit/client/objects.rb ./vendor/bundle/ruby/2.6.0/gems/octokit-4.18.0/lib/octokit/client/stats.rb ./vendor/bundle/ruby/2.6.0/gems/octokit-4.18.0/lib/octokit/client/organizations.rb ./vendor/bundle/ruby/2.6.0/gems/octokit-4.18.0/lib/octokit/client/statuses.rb ./vendor/bundle/ruby/2.6.0/gems/octokit-4.18.0/lib/octokit/client/repository_invitations.rb ./vendor/bundle/ruby/2.6.0/gems/octokit-4.18.0/lib/octokit/client/markdown.rb ./vendor/bundle/ruby/2.6.0/gems/octokit-4.18.0/lib/octokit/client/traffic.rb ./vendor/bundle/ruby/2.6.0/gems/octokit-4.18.0/lib/octokit/client/search.rb ./vendor/bundle/ruby/2.6.0/gems/octokit-4.18.0/lib/octokit/client/refs.rb ./vendor/bundle/ruby/2.6.0/gems/octokit-4.18.0/lib/octokit/client/notifications.rb ./vendor/bundle/ruby/2.6.0/gems/octokit-4.18.0/lib/octokit/client/marketplace.rb ./vendor/bundle/ruby/2.6.0/gems/octokit-4.18.0/lib/octokit/client/rate_limit.rb ./vendor/bundle/ruby/2.6.0/gems/octokit-4.18.0/lib/octokit/client/repositories.rb ./vendor/bundle/ruby/2.6.0/gems/octokit-4.18.0/lib/octokit/client/deployments.rb ./vendor/bundle/ruby/2.6.0/gems/octokit-4.18.0/lib/octokit/client/releases.rb ./vendor/bundle/ruby/2.6.0/gems/octokit-4.18.0/lib/octokit/client/gitignore.rb ./vendor/bundle/ruby/2.6.0/gems/octokit-4.18.0/lib/octokit/client/authorizations.rb ./vendor/bundle/ruby/2.6.0/gems/octokit-4.18.0/lib/octokit/client/pages.rb ./vendor/bundle/ruby/2.6.0/gems/octokit-4.18.0/lib/octokit/client/apps.rb ./vendor/bundle/ruby/2.6.0/gems/octokit-4.18.0/lib/octokit/client/emojis.rb ./vendor/bundle/ruby/2.6.0/gems/octokit-4.18.0/lib/octokit/client/downloads.rb ./vendor/bundle/ruby/2.6.0/gems/octokit-4.18.0/lib/octokit/client/legacy_search.rb ./vendor/bundle/ruby/2.6.0/gems/octokit-4.18.0/lib/octokit/client/service_status.rb ./vendor/bundle/ruby/2.6.0/gems/octokit-4.18.0/lib/octokit/client/reactions.rb ./vendor/bundle/ruby/2.6.0/gems/octokit-4.18.0/lib/octokit/client/events.rb ./vendor/bundle/ruby/2.6.0/gems/octokit-4.18.0/lib/octokit/client/milestones.rb ./vendor/bundle/ruby/2.6.0/gems/octokit-4.18.0/lib/octokit/client/say.rb ./vendor/bundle/ruby/2.6.0/gems/octokit-4.18.0/lib/octokit/client/checks.rb ./vendor/bundle/ruby/2.6.0/gems/octokit-4.18.0/lib/octokit/client/feeds.rb ./vendor/bundle/ruby/2.6.0/gems/octokit-4.18.0/lib/octokit/client/commits.rb ./vendor/bundle/ruby/2.6.0/gems/octokit-4.18.0/lib/octokit/client/users.rb ./vendor/bundle/ruby/2.6.0/gems/octokit-4.18.0/lib/octokit/client/contents.rb ./vendor/bundle/ruby/2.6.0/gems/octokit-4.18.0/lib/octokit/client/commit_comments.rb ./vendor/bundle/ruby/2.6.0/gems/octokit-4.18.0/lib/octokit/client/issues.rb ./vendor/bundle/ruby/2.6.0/gems/octokit-4.18.0/lib/octokit/client/hooks.rb ./vendor/bundle/ruby/2.6.0/gems/octokit-4.18.0/lib/octokit/client/reviews.rb ./vendor/bundle/ruby/2.6.0/gems/octokit-4.18.0/lib/octokit/client/commit_pulls.rb ./vendor/bundle/ruby/2.6.0/gems/octokit-4.18.0/lib/octokit/client/labels.rb ./vendor/bundle/ruby/2.6.0/gems/octokit-4.18.0/lib/octokit/user.rb ./vendor/bundle/ruby/2.6.0/gems/octokit-4.18.0/.document ./vendor/bundle/ruby/2.6.0/gems/ruby-macho-1.4.0/.yardopts ./vendor/bundle/ruby/2.6.0/gems/ruby-macho-1.4.0/LICENSE ./vendor/bundle/ruby/2.6.0/gems/ruby-macho-1.4.0/lib/macho/headers.rb ./vendor/bundle/ruby/2.6.0/gems/ruby-macho-1.4.0/lib/macho/exceptions.rb ./vendor/bundle/ruby/2.6.0/gems/ruby-macho-1.4.0/lib/macho/structure.rb ./vendor/bundle/ruby/2.6.0/gems/ruby-macho-1.4.0/lib/macho/fat_file.rb ./vendor/bundle/ruby/2.6.0/gems/ruby-macho-1.4.0/lib/macho/utils.rb ./vendor/bundle/ruby/2.6.0/gems/ruby-macho-1.4.0/lib/macho/view.rb ./vendor/bundle/ruby/2.6.0/gems/ruby-macho-1.4.0/lib/macho/macho_file.rb ./vendor/bundle/ruby/2.6.0/gems/ruby-macho-1.4.0/lib/macho/load_commands.rb ./vendor/bundle/ruby/2.6.0/gems/ruby-macho-1.4.0/lib/macho/tools.rb ./vendor/bundle/ruby/2.6.0/gems/ruby-macho-1.4.0/lib/macho/sections.rb ./vendor/bundle/ruby/2.6.0/gems/ruby-macho-1.4.0/lib/macho.rb ./vendor/bundle/ruby/2.6.0/gems/typhoeus-1.3.1/Guardfile ./vendor/bundle/ruby/2.6.0/gems/typhoeus-1.3.1/.rspec ./vendor/bundle/ruby/2.6.0/gems/typhoeus-1.3.1/LICENSE ./vendor/bundle/ruby/2.6.0/gems/typhoeus-1.3.1/typhoeus.gemspec ./vendor/bundle/ruby/2.6.0/gems/typhoeus-1.3.1/spec/spec_helper.rb ./vendor/bundle/ruby/2.6.0/gems/typhoeus-1.3.1/spec/support/localhost_server.rb ./vendor/bundle/ruby/2.6.0/gems/typhoeus-1.3.1/spec/support/memory_cache.rb ./vendor/bundle/ruby/2.6.0/gems/typhoeus-1.3.1/spec/support/server.rb ./vendor/bundle/ruby/2.6.0/gems/typhoeus-1.3.1/spec/rack/typhoeus/middleware/params_decoder/helper_spec.rb ./vendor/bundle/ruby/2.6.0/gems/typhoeus-1.3.1/spec/rack/typhoeus/middleware/params_decoder_spec.rb ./vendor/bundle/ruby/2.6.0/gems/typhoeus-1.3.1/spec/typhoeus/pool_spec.rb ./vendor/bundle/ruby/2.6.0/gems/typhoeus-1.3.1/spec/typhoeus/config_spec.rb ./vendor/bundle/ruby/2.6.0/gems/typhoeus-1.3.1/spec/typhoeus/response/header_spec.rb ./vendor/bundle/ruby/2.6.0/gems/typhoeus-1.3.1/spec/typhoeus/response/status_spec.rb ./vendor/bundle/ruby/2.6.0/gems/typhoeus-1.3.1/spec/typhoeus/response/informations_spec.rb ./vendor/bundle/ruby/2.6.0/gems/typhoeus-1.3.1/spec/typhoeus/cache/dalli_spec.rb ./vendor/bundle/ruby/2.6.0/gems/typhoeus-1.3.1/spec/typhoeus/cache/redis_spec.rb ./vendor/bundle/ruby/2.6.0/gems/typhoeus-1.3.1/spec/typhoeus/easy_factory_spec.rb ./vendor/bundle/ruby/2.6.0/gems/typhoeus-1.3.1/spec/typhoeus/adapters/faraday_spec.rb ./vendor/bundle/ruby/2.6.0/gems/typhoeus-1.3.1/spec/typhoeus/request_spec.rb ./vendor/bundle/ruby/2.6.0/gems/typhoeus-1.3.1/spec/typhoeus/response_spec.rb ./vendor/bundle/ruby/2.6.0/gems/typhoeus-1.3.1/spec/typhoeus/hydra_spec.rb ./vendor/bundle/ruby/2.6.0/gems/typhoeus-1.3.1/spec/typhoeus/request/block_connection_spec.rb ./vendor/bundle/ruby/2.6.0/gems/typhoeus-1.3.1/spec/typhoeus/request/marshal_spec.rb ./vendor/bundle/ruby/2.6.0/gems/typhoeus-1.3.1/spec/typhoeus/request/operations_spec.rb ./vendor/bundle/ruby/2.6.0/gems/typhoeus-1.3.1/spec/typhoeus/request/before_spec.rb ./vendor/bundle/ruby/2.6.0/gems/typhoeus-1.3.1/spec/typhoeus/request/actions_spec.rb ./vendor/bundle/ruby/2.6.0/gems/typhoeus-1.3.1/spec/typhoeus/request/cacheable_spec.rb ./vendor/bundle/ruby/2.6.0/gems/typhoeus-1.3.1/spec/typhoeus/request/responseable_spec.rb ./vendor/bundle/ruby/2.6.0/gems/typhoeus-1.3.1/spec/typhoeus/request/memoizable_spec.rb ./vendor/bundle/ruby/2.6.0/gems/typhoeus-1.3.1/spec/typhoeus/request/callbacks_spec.rb ./vendor/bundle/ruby/2.6.0/gems/typhoeus-1.3.1/spec/typhoeus/request/stubbable_spec.rb ./vendor/bundle/ruby/2.6.0/gems/typhoeus-1.3.1/spec/typhoeus/errors/no_stub_spec.rb ./vendor/bundle/ruby/2.6.0/gems/typhoeus-1.3.1/spec/typhoeus/expectation_spec.rb ./vendor/bundle/ruby/2.6.0/gems/typhoeus-1.3.1/spec/typhoeus/hydra/block_connection_spec.rb ./vendor/bundle/ruby/2.6.0/gems/typhoeus-1.3.1/spec/typhoeus/hydra/before_spec.rb ./vendor/bundle/ruby/2.6.0/gems/typhoeus-1.3.1/spec/typhoeus/hydra/cacheable_spec.rb ./vendor/bundle/ruby/2.6.0/gems/typhoeus-1.3.1/spec/typhoeus/hydra/runnable_spec.rb ./vendor/bundle/ruby/2.6.0/gems/typhoeus-1.3.1/spec/typhoeus/hydra/queueable_spec.rb ./vendor/bundle/ruby/2.6.0/gems/typhoeus-1.3.1/spec/typhoeus/hydra/memoizable_spec.rb ./vendor/bundle/ruby/2.6.0/gems/typhoeus-1.3.1/spec/typhoeus/hydra/addable_spec.rb ./vendor/bundle/ruby/2.6.0/gems/typhoeus-1.3.1/spec/typhoeus/hydra/stubbable_spec.rb ./vendor/bundle/ruby/2.6.0/gems/typhoeus-1.3.1/spec/typhoeus_spec.rb ./vendor/bundle/ruby/2.6.0/gems/typhoeus-1.3.1/Rakefile ./vendor/bundle/ruby/2.6.0/gems/typhoeus-1.3.1/lib/typhoeus.rb ./vendor/bundle/ruby/2.6.0/gems/typhoeus-1.3.1/lib/rack/typhoeus.rb ./vendor/bundle/ruby/2.6.0/gems/typhoeus-1.3.1/lib/rack/typhoeus/middleware/params_decoder/helper.rb ./vendor/bundle/ruby/2.6.0/gems/typhoeus-1.3.1/lib/rack/typhoeus/middleware/params_decoder.rb ./vendor/bundle/ruby/2.6.0/gems/typhoeus-1.3.1/lib/typhoeus/response/status.rb ./vendor/bundle/ruby/2.6.0/gems/typhoeus-1.3.1/lib/typhoeus/response/informations.rb ./vendor/bundle/ruby/2.6.0/gems/typhoeus-1.3.1/lib/typhoeus/response/cacheable.rb ./vendor/bundle/ruby/2.6.0/gems/typhoeus-1.3.1/lib/typhoeus/response/header.rb ./vendor/bundle/ruby/2.6.0/gems/typhoeus-1.3.1/lib/typhoeus/cache/dalli.rb ./vendor/bundle/ruby/2.6.0/gems/typhoeus-1.3.1/lib/typhoeus/cache/rails.rb ./vendor/bundle/ruby/2.6.0/gems/typhoeus-1.3.1/lib/typhoeus/cache/redis.rb ./vendor/bundle/ruby/2.6.0/gems/typhoeus-1.3.1/lib/typhoeus/errors.rb ./vendor/bundle/ruby/2.6.0/gems/typhoeus-1.3.1/lib/typhoeus/pool.rb ./vendor/bundle/ruby/2.6.0/gems/typhoeus-1.3.1/lib/typhoeus/easy_factory.rb ./vendor/bundle/ruby/2.6.0/gems/typhoeus-1.3.1/lib/typhoeus/hydra.rb ./vendor/bundle/ruby/2.6.0/gems/typhoeus-1.3.1/lib/typhoeus/response.rb ./vendor/bundle/ruby/2.6.0/gems/typhoeus-1.3.1/lib/typhoeus/request.rb ./vendor/bundle/ruby/2.6.0/gems/typhoeus-1.3.1/lib/typhoeus/adapters/faraday.rb ./vendor/bundle/ruby/2.6.0/gems/typhoeus-1.3.1/lib/typhoeus/railtie.rb ./vendor/bundle/ruby/2.6.0/gems/typhoeus-1.3.1/lib/typhoeus/request/stubbable.rb ./vendor/bundle/ruby/2.6.0/gems/typhoeus-1.3.1/lib/typhoeus/request/callbacks.rb ./vendor/bundle/ruby/2.6.0/gems/typhoeus-1.3.1/lib/typhoeus/request/operations.rb ./vendor/bundle/ruby/2.6.0/gems/typhoeus-1.3.1/lib/typhoeus/request/actions.rb ./vendor/bundle/ruby/2.6.0/gems/typhoeus-1.3.1/lib/typhoeus/request/memoizable.rb ./vendor/bundle/ruby/2.6.0/gems/typhoeus-1.3.1/lib/typhoeus/request/streamable.rb ./vendor/bundle/ruby/2.6.0/gems/typhoeus-1.3.1/lib/typhoeus/request/responseable.rb ./vendor/bundle/ruby/2.6.0/gems/typhoeus-1.3.1/lib/typhoeus/request/cacheable.rb ./vendor/bundle/ruby/2.6.0/gems/typhoeus-1.3.1/lib/typhoeus/request/marshal.rb ./vendor/bundle/ruby/2.6.0/gems/typhoeus-1.3.1/lib/typhoeus/request/block_connection.rb ./vendor/bundle/ruby/2.6.0/gems/typhoeus-1.3.1/lib/typhoeus/request/before.rb ./vendor/bundle/ruby/2.6.0/gems/typhoeus-1.3.1/lib/typhoeus/config.rb ./vendor/bundle/ruby/2.6.0/gems/typhoeus-1.3.1/lib/typhoeus/version.rb ./vendor/bundle/ruby/2.6.0/gems/typhoeus-1.3.1/lib/typhoeus/expectation.rb ./vendor/bundle/ruby/2.6.0/gems/typhoeus-1.3.1/lib/typhoeus/errors/typhoeus_error.rb ./vendor/bundle/ruby/2.6.0/gems/typhoeus-1.3.1/lib/typhoeus/errors/no_stub.rb ./vendor/bundle/ruby/2.6.0/gems/typhoeus-1.3.1/lib/typhoeus/hydra/stubbable.rb ./vendor/bundle/ruby/2.6.0/gems/typhoeus-1.3.1/lib/typhoeus/hydra/runnable.rb ./vendor/bundle/ruby/2.6.0/gems/typhoeus-1.3.1/lib/typhoeus/hydra/queueable.rb ./vendor/bundle/ruby/2.6.0/gems/typhoeus-1.3.1/lib/typhoeus/hydra/memoizable.rb ./vendor/bundle/ruby/2.6.0/gems/typhoeus-1.3.1/lib/typhoeus/hydra/cacheable.rb ./vendor/bundle/ruby/2.6.0/gems/typhoeus-1.3.1/lib/typhoeus/hydra/addable.rb ./vendor/bundle/ruby/2.6.0/gems/typhoeus-1.3.1/lib/typhoeus/hydra/block_connection.rb ./vendor/bundle/ruby/2.6.0/gems/typhoeus-1.3.1/lib/typhoeus/hydra/before.rb ./vendor/bundle/ruby/2.6.0/gems/typhoeus-1.3.1/Gemfile ./vendor/bundle/ruby/2.6.0/gems/typhoeus-1.3.1/perf/vs_nethttp.rb ./vendor/bundle/ruby/2.6.0/gems/typhoeus-1.3.1/perf/profile.rb ./vendor/bundle/ruby/2.6.0/gems/fuzzy_match-2.0.4/benchmark/memory.rb ./vendor/bundle/ruby/2.6.0/gems/fuzzy_match-2.0.4/.rspec ./vendor/bundle/ruby/2.6.0/gems/fuzzy_match-2.0.4/LICENSE ./vendor/bundle/ruby/2.6.0/gems/fuzzy_match-2.0.4/THANKS-WILLIAM-JAMES.rb ./vendor/bundle/ruby/2.6.0/gems/fuzzy_match-2.0.4/bin/fuzzy_match ./vendor/bundle/ruby/2.6.0/gems/fuzzy_match-2.0.4/CHANGELOG ./vendor/bundle/ruby/2.6.0/gems/fuzzy_match-2.0.4/fuzzy_match.gemspec ./vendor/bundle/ruby/2.6.0/gems/fuzzy_match-2.0.4/spec/foo.rb ./vendor/bundle/ruby/2.6.0/gems/fuzzy_match-2.0.4/spec/spec_helper.rb ./vendor/bundle/ruby/2.6.0/gems/fuzzy_match-2.0.4/spec/grouping_spec.rb ./vendor/bundle/ruby/2.6.0/gems/fuzzy_match-2.0.4/spec/identity_spec.rb ./vendor/bundle/ruby/2.6.0/gems/fuzzy_match-2.0.4/spec/amatch_spec.rb ./vendor/bundle/ruby/2.6.0/gems/fuzzy_match-2.0.4/spec/record_spec.rb ./vendor/bundle/ruby/2.6.0/gems/fuzzy_match-2.0.4/spec/fuzzy_match_spec.rb ./vendor/bundle/ruby/2.6.0/gems/fuzzy_match-2.0.4/spec/cache_spec.rb ./vendor/bundle/ruby/2.6.0/gems/fuzzy_match-2.0.4/Rakefile ./vendor/bundle/ruby/2.6.0/gems/fuzzy_match-2.0.4/README.markdown ./vendor/bundle/ruby/2.6.0/gems/fuzzy_match-2.0.4/highlevel.graffle ./vendor/bundle/ruby/2.6.0/gems/fuzzy_match-2.0.4/lib/fuzzy_match.rb ./vendor/bundle/ruby/2.6.0/gems/fuzzy_match-2.0.4/lib/fuzzy_match/score.rb ./vendor/bundle/ruby/2.6.0/gems/fuzzy_match-2.0.4/lib/fuzzy_match/cached_result.rb ./vendor/bundle/ruby/2.6.0/gems/fuzzy_match-2.0.4/lib/fuzzy_match/record.rb ./vendor/bundle/ruby/2.6.0/gems/fuzzy_match-2.0.4/lib/fuzzy_match/result.rb ./vendor/bundle/ruby/2.6.0/gems/fuzzy_match-2.0.4/lib/fuzzy_match/rule.rb ./vendor/bundle/ruby/2.6.0/gems/fuzzy_match-2.0.4/lib/fuzzy_match/rule/identity.rb ./vendor/bundle/ruby/2.6.0/gems/fuzzy_match-2.0.4/lib/fuzzy_match/rule/grouping.rb ./vendor/bundle/ruby/2.6.0/gems/fuzzy_match-2.0.4/lib/fuzzy_match/score/pure_ruby.rb ./vendor/bundle/ruby/2.6.0/gems/fuzzy_match-2.0.4/lib/fuzzy_match/score/amatch.rb ./vendor/bundle/ruby/2.6.0/gems/fuzzy_match-2.0.4/lib/fuzzy_match/version.rb ./vendor/bundle/ruby/2.6.0/gems/fuzzy_match-2.0.4/lib/fuzzy_match/similarity.rb ./vendor/bundle/ruby/2.6.0/gems/fuzzy_match-2.0.4/Gemfile ./vendor/bundle/ruby/2.6.0/gems/fourflusher-2.3.1/bin/setup ./vendor/bundle/ruby/2.6.0/gems/fourflusher-2.3.1/bin/console ./vendor/bundle/ruby/2.6.0/gems/fourflusher-2.3.1/Rakefile ./vendor/bundle/ruby/2.6.0/gems/fourflusher-2.3.1/fourflusher.gemspec ./vendor/bundle/ruby/2.6.0/gems/fourflusher-2.3.1/lib/fourflusher/simctl.rb ./vendor/bundle/ruby/2.6.0/gems/fourflusher-2.3.1/lib/fourflusher/executable.rb ./vendor/bundle/ruby/2.6.0/gems/fourflusher-2.3.1/lib/fourflusher/find.rb ./vendor/bundle/ruby/2.6.0/gems/fourflusher-2.3.1/lib/fourflusher/xcodebuild.rb ./vendor/bundle/ruby/2.6.0/gems/fourflusher-2.3.1/lib/fourflusher/compat.rb ./vendor/bundle/ruby/2.6.0/gems/fourflusher-2.3.1/lib/fourflusher/version.rb ./vendor/bundle/ruby/2.6.0/gems/fourflusher-2.3.1/lib/fourflusher.rb ./vendor/bundle/ruby/2.6.0/gems/fourflusher-2.3.1/Gemfile ./vendor/bundle/ruby/2.6.0/gems/fourflusher-2.3.1/Gemfile.lock ./vendor/bundle/ruby/2.6.0/gems/escape-0.0.4/doc_include/template/qualitysmith.rb ./vendor/bundle/ruby/2.6.0/gems/escape-0.0.4/Readme ./vendor/bundle/ruby/2.6.0/gems/escape-0.0.4/lib/escape.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-1.0.1/spec/spec_helper.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-1.0.1/spec/faraday_spec.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-1.0.1/spec/faraday/error_spec.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-1.0.1/spec/faraday/composite_read_io_spec.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-1.0.1/spec/faraday/options/request_options_spec.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-1.0.1/spec/faraday/options/proxy_options_spec.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-1.0.1/spec/faraday/options/options_spec.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-1.0.1/spec/faraday/options/env_spec.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-1.0.1/spec/faraday/response/raise_error_spec.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-1.0.1/spec/faraday/response/logger_spec.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-1.0.1/spec/faraday/response/middleware_spec.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-1.0.1/spec/faraday/params_encoders/nested_spec.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-1.0.1/spec/faraday/params_encoders/flat_spec.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-1.0.1/spec/faraday/rack_builder_spec.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-1.0.1/spec/faraday/utils/headers_spec.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-1.0.1/spec/faraday/adapter/patron_spec.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-1.0.1/spec/faraday/adapter/net_http_spec.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-1.0.1/spec/faraday/adapter/net_http_persistent_spec.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-1.0.1/spec/faraday/adapter/em_http_spec.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-1.0.1/spec/faraday/adapter/rack_spec.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-1.0.1/spec/faraday/adapter/excon_spec.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-1.0.1/spec/faraday/adapter/httpclient_spec.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-1.0.1/spec/faraday/adapter/typhoeus_spec.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-1.0.1/spec/faraday/adapter/em_synchrony_spec.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-1.0.1/spec/faraday/middleware_spec.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-1.0.1/spec/faraday/adapter_spec.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-1.0.1/spec/faraday/request_spec.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-1.0.1/spec/faraday/adapter_registry_spec.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-1.0.1/spec/faraday/connection_spec.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-1.0.1/spec/faraday/response_spec.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-1.0.1/spec/faraday/request/authorization_spec.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-1.0.1/spec/faraday/request/instrumentation_spec.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-1.0.1/spec/faraday/request/url_encoded_spec.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-1.0.1/spec/faraday/request/multipart_spec.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-1.0.1/spec/faraday/request/retry_spec.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-1.0.1/spec/faraday/utils_spec.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-1.0.1/spec/support/helper_methods.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-1.0.1/spec/support/disabling_stub.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-1.0.1/spec/support/streaming_response_checker.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-1.0.1/spec/support/shared_examples/request_method.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-1.0.1/spec/support/shared_examples/params_encoder.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-1.0.1/spec/support/shared_examples/adapter.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-1.0.1/spec/support/fake_safe_buffer.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-1.0.1/spec/support/webmock_rack_app.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-1.0.1/spec/external_adapters/faraday_specs_setup.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-1.0.1/Rakefile ./vendor/bundle/ruby/2.6.0/gems/faraday-1.0.1/examples/client_test.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-1.0.1/examples/client_spec.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-1.0.1/lib/faraday/options/request_options.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-1.0.1/lib/faraday/options/proxy_options.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-1.0.1/lib/faraday/options/connection_options.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-1.0.1/lib/faraday/options/env.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-1.0.1/lib/faraday/options/ssl_options.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-1.0.1/lib/faraday/middleware.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-1.0.1/lib/faraday/dependency_loader.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-1.0.1/lib/faraday/file_part.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-1.0.1/lib/faraday/response/logger.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-1.0.1/lib/faraday/response/raise_error.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-1.0.1/lib/faraday/middleware_registry.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-1.0.1/lib/faraday/param_part.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-1.0.1/lib/faraday/parameters.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-1.0.1/lib/faraday/connection.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-1.0.1/lib/faraday/utils/headers.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-1.0.1/lib/faraday/utils/params_hash.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-1.0.1/lib/faraday/adapter/em_http_ssl_patch.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-1.0.1/lib/faraday/adapter/typhoeus.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-1.0.1/lib/faraday/adapter/net_http.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-1.0.1/lib/faraday/adapter/net_http_persistent.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-1.0.1/lib/faraday/adapter/excon.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-1.0.1/lib/faraday/adapter/test.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-1.0.1/lib/faraday/adapter/em_synchrony/parallel_manager.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-1.0.1/lib/faraday/adapter/patron.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-1.0.1/lib/faraday/adapter/httpclient.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-1.0.1/lib/faraday/adapter/em_synchrony.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-1.0.1/lib/faraday/adapter/rack.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-1.0.1/lib/faraday/adapter/em_http.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-1.0.1/lib/faraday/utils.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-1.0.1/lib/faraday/adapter_registry.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-1.0.1/lib/faraday/autoload.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-1.0.1/lib/faraday/response.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-1.0.1/lib/faraday/request.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-1.0.1/lib/faraday/adapter.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-1.0.1/lib/faraday/encoders/nested_params_encoder.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-1.0.1/lib/faraday/encoders/flat_params_encoder.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-1.0.1/lib/faraday/rack_builder.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-1.0.1/lib/faraday/request/basic_authentication.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-1.0.1/lib/faraday/request/retry.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-1.0.1/lib/faraday/request/url_encoded.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-1.0.1/lib/faraday/request/authorization.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-1.0.1/lib/faraday/request/token_authentication.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-1.0.1/lib/faraday/request/multipart.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-1.0.1/lib/faraday/request/instrumentation.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-1.0.1/lib/faraday/error.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-1.0.1/lib/faraday/options.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-1.0.1/lib/faraday/logging/formatter.rb ./vendor/bundle/ruby/2.6.0/gems/faraday-1.0.1/lib/faraday.rb ./vendor/bundle/ruby/2.6.0/gems/claide-1.0.3/.yardopts ./vendor/bundle/ruby/2.6.0/gems/claide-1.0.3/claide.gemspec ./vendor/bundle/ruby/2.6.0/gems/claide-1.0.3/LICENSE ./vendor/bundle/ruby/2.6.0/gems/claide-1.0.3/.kick ./vendor/bundle/ruby/2.6.0/gems/claide-1.0.3/Rakefile ./vendor/bundle/ruby/2.6.0/gems/claide-1.0.3/README.markdown ./vendor/bundle/ruby/2.6.0/gems/claide-1.0.3/lib/claide.rb ./vendor/bundle/ruby/2.6.0/gems/claide-1.0.3/lib/claide/informative_error.rb ./vendor/bundle/ruby/2.6.0/gems/claide-1.0.3/lib/claide/ansi.rb ./vendor/bundle/ruby/2.6.0/gems/claide-1.0.3/lib/claide/help.rb ./vendor/bundle/ruby/2.6.0/gems/claide-1.0.3/lib/claide/ansi/cursor.rb ./vendor/bundle/ruby/2.6.0/gems/claide-1.0.3/lib/claide/ansi/string_escaper.rb ./vendor/bundle/ruby/2.6.0/gems/claide-1.0.3/lib/claide/ansi/graphics.rb ./vendor/bundle/ruby/2.6.0/gems/claide-1.0.3/lib/claide/argv.rb ./vendor/bundle/ruby/2.6.0/gems/claide-1.0.3/lib/claide/command/banner.rb ./vendor/bundle/ruby/2.6.0/gems/claide-1.0.3/lib/claide/command/plugin_manager.rb ./vendor/bundle/ruby/2.6.0/gems/claide-1.0.3/lib/claide/command/argument_suggester.rb ./vendor/bundle/ruby/2.6.0/gems/claide-1.0.3/lib/claide/command.rb ./vendor/bundle/ruby/2.6.0/gems/claide-1.0.3/lib/claide/argument.rb ./vendor/bundle/ruby/2.6.0/gems/claide-1.0.3/Gemfile ./vendor/bundle/ruby/2.6.0/gems/claide-1.0.3/Gemfile.lock ./vendor/bundle/ruby/2.6.0/gems/cocoapods-try-1.1.0/LICENSE ./vendor/bundle/ruby/2.6.0/gems/cocoapods-try-1.1.0/spec/spec_helper.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-try-1.1.0/spec/command/try_spec.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-try-1.1.0/spec/command/try_settings_spec.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-try-1.1.0/Rakefile ./vendor/bundle/ruby/2.6.0/gems/cocoapods-try-1.1.0/lib/pod/try_settings.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-try-1.1.0/lib/pod/command/try.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-try-1.1.0/lib/cocoapods_plugin.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-try-1.1.0/lib/cocoapods_try.rb ./vendor/bundle/ruby/2.6.0/gems/cocoapods-try-1.1.0/Gemfile ./vendor/bundle/ruby/2.6.0/gems/cocoapods-try-1.1.0/Gemfile.lock ./vendor/bundle/ruby/2.6.0/gems/cocoapods-try-1.1.0/cocoapods-try.gemspec ./vendor/bundle/ruby/2.6.0/gems/multi_json-1.14.1/lib/multi_json.rb ./vendor/bundle/ruby/2.6.0/gems/multi_json-1.14.1/lib/multi_json/parse_error.rb ./vendor/bundle/ruby/2.6.0/gems/multi_json-1.14.1/lib/multi_json/adapter_error.rb ./vendor/bundle/ruby/2.6.0/gems/multi_json-1.14.1/lib/multi_json/adapters/ok_json.rb ./vendor/bundle/ruby/2.6.0/gems/multi_json-1.14.1/lib/multi_json/adapters/json_common.rb ./vendor/bundle/ruby/2.6.0/gems/multi_json-1.14.1/lib/multi_json/adapters/nsjsonserialization.rb ./vendor/bundle/ruby/2.6.0/gems/multi_json-1.14.1/lib/multi_json/adapters/jr_jackson.rb ./vendor/bundle/ruby/2.6.0/gems/multi_json-1.14.1/lib/multi_json/adapters/yajl.rb ./vendor/bundle/ruby/2.6.0/gems/multi_json-1.14.1/lib/multi_json/adapters/json_pure.rb ./vendor/bundle/ruby/2.6.0/gems/multi_json-1.14.1/lib/multi_json/adapters/gson.rb ./vendor/bundle/ruby/2.6.0/gems/multi_json-1.14.1/lib/multi_json/adapters/oj.rb ./vendor/bundle/ruby/2.6.0/gems/multi_json-1.14.1/lib/multi_json/adapters/json_gem.rb ./vendor/bundle/ruby/2.6.0/gems/multi_json-1.14.1/lib/multi_json/options_cache.rb ./vendor/bundle/ruby/2.6.0/gems/multi_json-1.14.1/lib/multi_json/adapter.rb ./vendor/bundle/ruby/2.6.0/gems/multi_json-1.14.1/lib/multi_json/version.rb ./vendor/bundle/ruby/2.6.0/gems/multi_json-1.14.1/lib/multi_json/options.rb ./vendor/bundle/ruby/2.6.0/gems/multi_json-1.14.1/lib/multi_json/convertible_hash_keys.rb ./vendor/bundle/ruby/2.6.0/gems/multi_json-1.14.1/lib/multi_json/vendor/okjson.rb ./vendor/bundle/ruby/2.6.0/gems/public_suffix-4.0.4/.yardopts ./vendor/bundle/ruby/2.6.0/gems/public_suffix-4.0.4/test/acceptance_test.rb ./vendor/bundle/ruby/2.6.0/gems/public_suffix-4.0.4/test/unit/list_test.rb ./vendor/bundle/ruby/2.6.0/gems/public_suffix-4.0.4/test/unit/rule_test.rb ./vendor/bundle/ruby/2.6.0/gems/public_suffix-4.0.4/test/unit/domain_test.rb ./vendor/bundle/ruby/2.6.0/gems/public_suffix-4.0.4/test/unit/public_suffix_test.rb ./vendor/bundle/ruby/2.6.0/gems/public_suffix-4.0.4/test/unit/errors_test.rb ./vendor/bundle/ruby/2.6.0/gems/public_suffix-4.0.4/test/profilers/find_profiler_jp.rb ./vendor/bundle/ruby/2.6.0/gems/public_suffix-4.0.4/test/profilers/list_profsize.rb ./vendor/bundle/ruby/2.6.0/gems/public_suffix-4.0.4/test/profilers/initialization_profiler.rb ./vendor/bundle/ruby/2.6.0/gems/public_suffix-4.0.4/test/profilers/domain_profiler.rb ./vendor/bundle/ruby/2.6.0/gems/public_suffix-4.0.4/test/profilers/object_binsize.rb ./vendor/bundle/ruby/2.6.0/gems/public_suffix-4.0.4/test/profilers/find_profiler.rb ./vendor/bundle/ruby/2.6.0/gems/public_suffix-4.0.4/test/benchmarks/bm_select_incremental.rb ./vendor/bundle/ruby/2.6.0/gems/public_suffix-4.0.4/test/benchmarks/bm_valid.rb ./vendor/bundle/ruby/2.6.0/gems/public_suffix-4.0.4/test/benchmarks/bm_find.rb ./vendor/bundle/ruby/2.6.0/gems/public_suffix-4.0.4/test/benchmarks/bm_names.rb ./vendor/bundle/ruby/2.6.0/gems/public_suffix-4.0.4/test/benchmarks/bm_find_all.rb ./vendor/bundle/ruby/2.6.0/gems/public_suffix-4.0.4/test/benchmarks/bm_select.rb ./vendor/bundle/ruby/2.6.0/gems/public_suffix-4.0.4/test/test_helper.rb ./vendor/bundle/ruby/2.6.0/gems/public_suffix-4.0.4/test/psl_test.rb ./vendor/bundle/ruby/2.6.0/gems/public_suffix-4.0.4/test/.empty ./vendor/bundle/ruby/2.6.0/gems/public_suffix-4.0.4/bin/console ./vendor/bundle/ruby/2.6.0/gems/public_suffix-4.0.4/public_suffix.gemspec ./vendor/bundle/ruby/2.6.0/gems/public_suffix-4.0.4/Rakefile ./vendor/bundle/ruby/2.6.0/gems/public_suffix-4.0.4/lib/public_suffix.rb ./vendor/bundle/ruby/2.6.0/gems/public_suffix-4.0.4/lib/public_suffix/errors.rb ./vendor/bundle/ruby/2.6.0/gems/public_suffix-4.0.4/lib/public_suffix/rule.rb ./vendor/bundle/ruby/2.6.0/gems/public_suffix-4.0.4/lib/public_suffix/version.rb ./vendor/bundle/ruby/2.6.0/gems/public_suffix-4.0.4/lib/public_suffix/list.rb ./vendor/bundle/ruby/2.6.0/gems/public_suffix-4.0.4/lib/public_suffix/domain.rb ./vendor/bundle/ruby/2.6.0/gems/public_suffix-4.0.4/Gemfile <<<<<< network # path=./Charts.framework.coverage.txt /Users/travis/build/danielgindi/Charts/Source/Charts/Animation/Animator.swift: 1| |// 2| |// Animator.swift 3| |// Charts 4| |// 5| |// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda 6| |// A port of MPAndroidChart for iOS 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| | 12| |import Foundation 13| |import CoreGraphics 14| |import QuartzCore 15| | 16| |@objc(ChartAnimatorDelegate) 17| |public protocol AnimatorDelegate 18| |{ 19| | /// Called when the Animator has stepped. 20| | func animatorUpdated(_ animator: Animator) 21| | 22| | /// Called when the Animator has stopped. 23| | func animatorStopped(_ animator: Animator) 24| |} 25| | 26| |@objc(ChartAnimator) 27| |open class Animator: NSObject 28| |{ 29| | @objc open weak var delegate: AnimatorDelegate? 30| | @objc open var updateBlock: (() -> Void)? 31| | @objc open var stopBlock: (() -> Void)? 32| | 33| | /// the phase that is animated and influences the drawn values on the x-axis 34| | @objc open var phaseX: Double = 1.0 35| | 36| | /// the phase that is animated and influences the drawn values on the y-axis 37| | @objc open var phaseY: Double = 1.0 38| | 39| | private var _startTimeX: TimeInterval = 0.0 40| | private var _startTimeY: TimeInterval = 0.0 41| | private var _displayLink: NSUIDisplayLink? 42| | 43| | private var _durationX: TimeInterval = 0.0 44| | private var _durationY: TimeInterval = 0.0 45| | 46| | private var _endTimeX: TimeInterval = 0.0 47| | private var _endTimeY: TimeInterval = 0.0 48| | private var _endTime: TimeInterval = 0.0 49| | 50| | private var _enabledX: Bool = false 51| | private var _enabledY: Bool = false 52| | 53| | private var _easingX: ChartEasingFunctionBlock? 54| | private var _easingY: ChartEasingFunctionBlock? 55| | 56| | public override init() 57| 52| { 58| 52| super.init() 59| 52| } 60| | 61| | deinit 62| 37| { 63| 37| stop() 64| 37| } 65| | 66| | @objc open func stop() 67| 37| { 68| 37| guard _displayLink != nil else { return } 69| 0| 70| 0| _displayLink?.remove(from: .main, forMode: RunLoop.Mode.common) 71| 0| _displayLink = nil 72| 0| 73| 0| _enabledX = false 74| 0| _enabledY = false 75| 0| 76| 0| // If we stopped an animation in the middle, we do not want to leave it like this 77| 0| if phaseX != 1.0 || phaseY != 1.0 78| 0| { 79| 0| phaseX = 1.0 80| 0| phaseY = 1.0 81| 0| 82| 0| delegate?.animatorUpdated(self) 83| 0| updateBlock?() 84| 0| } 85| 0| 86| 0| delegate?.animatorStopped(self) 87| 0| stopBlock?() 88| 0| } 89| | 90| | private func updateAnimationPhases(_ currentTime: TimeInterval) 91| 0| { 92| 0| if _enabledX 93| 0| { 94| 0| let elapsedTime: TimeInterval = currentTime - _startTimeX 95| 0| let duration: TimeInterval = _durationX 96| 0| var elapsed: TimeInterval = elapsedTime 97| 0| if elapsed > duration 98| 0| { 99| 0| elapsed = duration 100| 0| } 101| 0| 102| 0| phaseX = _easingX?(elapsed, duration) ?? elapsed / duration 103| 0| } 104| 0| 105| 0| if _enabledY 106| 0| { 107| 0| let elapsedTime: TimeInterval = currentTime - _startTimeY 108| 0| let duration: TimeInterval = _durationY 109| 0| var elapsed: TimeInterval = elapsedTime 110| 0| if elapsed > duration 111| 0| { 112| 0| elapsed = duration 113| 0| } 114| 0| 115| 0| phaseY = _easingY?(elapsed, duration) ?? elapsed / duration 116| 0| } 117| 0| } 118| | 119| | @objc private func animationLoop() 120| 0| { 121| 0| let currentTime: TimeInterval = CACurrentMediaTime() 122| 0| 123| 0| updateAnimationPhases(currentTime) 124| 0| 125| 0| delegate?.animatorUpdated(self) 126| 0| updateBlock?() 127| 0| 128| 0| if currentTime >= _endTime 129| 0| { 130| 0| stop() 131| 0| } 132| 0| } 133| | 134| | /// Animates the drawing / rendering of the chart on both x- and y-axis with the specified animation time. 135| | /// If `animate(...)` is called, no further calling of `invalidate()` is necessary to refresh the chart. 136| | /// 137| | /// - Parameters: 138| | /// - xAxisDuration: duration for animating the x axis 139| | /// - yAxisDuration: duration for animating the y axis 140| | /// - easingX: an easing function for the animation on the x axis 141| | /// - easingY: an easing function for the animation on the y axis 142| | @objc open func animate(xAxisDuration: TimeInterval, yAxisDuration: TimeInterval, easingX: ChartEasingFunctionBlock?, easingY: ChartEasingFunctionBlock?) 143| 0| { 144| 0| stop() 145| 0| 146| 0| _startTimeX = CACurrentMediaTime() 147| 0| _startTimeY = _startTimeX 148| 0| _durationX = xAxisDuration 149| 0| _durationY = yAxisDuration 150| 0| _endTimeX = _startTimeX + xAxisDuration 151| 0| _endTimeY = _startTimeY + yAxisDuration 152| 0| _endTime = _endTimeX > _endTimeY ? _endTimeX : _endTimeY 153| 0| _enabledX = xAxisDuration > 0.0 154| 0| _enabledY = yAxisDuration > 0.0 155| 0| 156| 0| _easingX = easingX 157| 0| _easingY = easingY 158| 0| 159| 0| // Take care of the first frame if rendering is already scheduled... 160| 0| updateAnimationPhases(_startTimeX) 161| 0| 162| 0| if _enabledX || _enabledY 163| 0| { 164| 0| _displayLink = NSUIDisplayLink(target: self, selector: #selector(animationLoop)) 165| 0| _displayLink?.add(to: RunLoop.main, forMode: RunLoop.Mode.common) 166| 0| } 167| 0| } 168| | 169| | /// Animates the drawing / rendering of the chart on both x- and y-axis with the specified animation time. 170| | /// If `animate(...)` is called, no further calling of `invalidate()` is necessary to refresh the chart. 171| | /// 172| | /// - Parameters: 173| | /// - xAxisDuration: duration for animating the x axis 174| | /// - yAxisDuration: duration for animating the y axis 175| | /// - easingOptionX: the easing function for the animation on the x axis 176| | /// - easingOptionY: the easing function for the animation on the y axis 177| | @objc open func animate(xAxisDuration: TimeInterval, yAxisDuration: TimeInterval, easingOptionX: ChartEasingOption, easingOptionY: ChartEasingOption) 178| 0| { 179| 0| animate(xAxisDuration: xAxisDuration, yAxisDuration: yAxisDuration, easingX: easingFunctionFromOption(easingOptionX), easingY: easingFunctionFromOption(easingOptionY)) 180| 0| } 181| | 182| | /// Animates the drawing / rendering of the chart on both x- and y-axis with the specified animation time. 183| | /// If `animate(...)` is called, no further calling of `invalidate()` is necessary to refresh the chart. 184| | /// 185| | /// - Parameters: 186| | /// - xAxisDuration: duration for animating the x axis 187| | /// - yAxisDuration: duration for animating the y axis 188| | /// - easing: an easing function for the animation 189| | @objc open func animate(xAxisDuration: TimeInterval, yAxisDuration: TimeInterval, easing: ChartEasingFunctionBlock?) 190| 0| { 191| 0| animate(xAxisDuration: xAxisDuration, yAxisDuration: yAxisDuration, easingX: easing, easingY: easing) 192| 0| } 193| | 194| | /// Animates the drawing / rendering of the chart on both x- and y-axis with the specified animation time. 195| | /// If `animate(...)` is called, no further calling of `invalidate()` is necessary to refresh the chart. 196| | /// 197| | /// - Parameters: 198| | /// - xAxisDuration: duration for animating the x axis 199| | /// - yAxisDuration: duration for animating the y axis 200| | /// - easingOption: the easing function for the animation 201| | @objc open func animate(xAxisDuration: TimeInterval, yAxisDuration: TimeInterval, easingOption: ChartEasingOption = .easeInOutSine) 202| 0| { 203| 0| animate(xAxisDuration: xAxisDuration, yAxisDuration: yAxisDuration, easing: easingFunctionFromOption(easingOption)) 204| 0| } 205| | 206| | /// Animates the drawing / rendering of the chart the x-axis with the specified animation time. 207| | /// If `animate(...)` is called, no further calling of `invalidate()` is necessary to refresh the chart. 208| | /// 209| | /// - Parameters: 210| | /// - xAxisDuration: duration for animating the x axis 211| | /// - easing: an easing function for the animation 212| | @objc open func animate(xAxisDuration: TimeInterval, easing: ChartEasingFunctionBlock?) 213| 0| { 214| 0| _startTimeX = CACurrentMediaTime() 215| 0| _durationX = xAxisDuration 216| 0| _endTimeX = _startTimeX + xAxisDuration 217| 0| _endTime = _endTimeX > _endTimeY ? _endTimeX : _endTimeY 218| 0| _enabledX = xAxisDuration > 0.0 219| 0| 220| 0| _easingX = easing 221| 0| 222| 0| // Take care of the first frame if rendering is already scheduled... 223| 0| updateAnimationPhases(_startTimeX) 224| 0| 225| 0| if _enabledX || _enabledY, 226| 0| _displayLink == nil 227| 0| { 228| 0| _displayLink = NSUIDisplayLink(target: self, selector: #selector(animationLoop)) 229| 0| _displayLink?.add(to: .main, forMode: RunLoop.Mode.common) 230| 0| } 231| 0| } 232| | 233| | /// Animates the drawing / rendering of the chart the x-axis with the specified animation time. 234| | /// If `animate(...)` is called, no further calling of `invalidate()` is necessary to refresh the chart. 235| | /// 236| | /// - Parameters: 237| | /// - xAxisDuration: duration for animating the x axis 238| | /// - easingOption: the easing function for the animation 239| | @objc open func animate(xAxisDuration: TimeInterval, easingOption: ChartEasingOption = .easeInOutSine) 240| 0| { 241| 0| animate(xAxisDuration: xAxisDuration, easing: easingFunctionFromOption(easingOption)) 242| 0| } 243| | 244| | /// Animates the drawing / rendering of the chart the y-axis with the specified animation time. 245| | /// If `animate(...)` is called, no further calling of `invalidate()` is necessary to refresh the chart. 246| | /// 247| | /// - Parameters: 248| | /// - yAxisDuration: duration for animating the y axis 249| | /// - easing: an easing function for the animation 250| | @objc open func animate(yAxisDuration: TimeInterval, easing: ChartEasingFunctionBlock?) 251| 0| { 252| 0| _startTimeY = CACurrentMediaTime() 253| 0| _durationY = yAxisDuration 254| 0| _endTimeY = _startTimeY + yAxisDuration 255| 0| _endTime = _endTimeX > _endTimeY ? _endTimeX : _endTimeY 256| 0| _enabledY = yAxisDuration > 0.0 257| 0| 258| 0| _easingY = easing 259| 0| 260| 0| // Take care of the first frame if rendering is already scheduled... 261| 0| updateAnimationPhases(_startTimeY) 262| 0| 263| 0| if _enabledX || _enabledY, 264| 0| _displayLink == nil 265| 0| { 266| 0| _displayLink = NSUIDisplayLink(target: self, selector: #selector(animationLoop)) 267| 0| _displayLink?.add(to: .main, forMode: RunLoop.Mode.common) 268| 0| } 269| 0| } 270| | 271| | /// Animates the drawing / rendering of the chart the y-axis with the specified animation time. 272| | /// If `animate(...)` is called, no further calling of `invalidate()` is necessary to refresh the chart. 273| | /// 274| | /// - Parameters: 275| | /// - yAxisDuration: duration for animating the y axis 276| | /// - easingOption: the easing function for the animation 277| | @objc open func animate(yAxisDuration: TimeInterval, easingOption: ChartEasingOption = .easeInOutSine) 278| 0| { 279| 0| animate(yAxisDuration: yAxisDuration, easing: easingFunctionFromOption(easingOption)) 280| 0| } 281| |} /Users/travis/build/danielgindi/Charts/Source/Charts/Animation/ChartAnimationEasing.swift: 1| |// 2| |// ChartAnimationUtils.swift 3| |// Charts 4| |// 5| |// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda 6| |// A port of MPAndroidChart for iOS 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| | 12| |import Foundation 13| |import CoreGraphics 14| | 15| |@objc 16| |public enum ChartEasingOption: Int 17| |{ 18| | case linear 19| | case easeInQuad 20| | case easeOutQuad 21| | case easeInOutQuad 22| | case easeInCubic 23| | case easeOutCubic 24| | case easeInOutCubic 25| | case easeInQuart 26| | case easeOutQuart 27| | case easeInOutQuart 28| | case easeInQuint 29| | case easeOutQuint 30| | case easeInOutQuint 31| | case easeInSine 32| | case easeOutSine 33| | case easeInOutSine 34| | case easeInExpo 35| | case easeOutExpo 36| | case easeInOutExpo 37| | case easeInCirc 38| | case easeOutCirc 39| | case easeInOutCirc 40| | case easeInElastic 41| | case easeOutElastic 42| | case easeInOutElastic 43| | case easeInBack 44| | case easeOutBack 45| | case easeInOutBack 46| | case easeInBounce 47| | case easeOutBounce 48| | case easeInOutBounce 49| |} 50| | 51| |public typealias ChartEasingFunctionBlock = ((_ elapsed: TimeInterval, _ duration: TimeInterval) -> Double) 52| | 53| |internal func easingFunctionFromOption(_ easing: ChartEasingOption) -> ChartEasingFunctionBlock 54| 0|{ 55| 0| switch easing 56| 0| { 57| 0| case .linear: 58| 0| return EasingFunctions.Linear 59| 0| case .easeInQuad: 60| 0| return EasingFunctions.EaseInQuad 61| 0| case .easeOutQuad: 62| 0| return EasingFunctions.EaseOutQuad 63| 0| case .easeInOutQuad: 64| 0| return EasingFunctions.EaseInOutQuad 65| 0| case .easeInCubic: 66| 0| return EasingFunctions.EaseInCubic 67| 0| case .easeOutCubic: 68| 0| return EasingFunctions.EaseOutCubic 69| 0| case .easeInOutCubic: 70| 0| return EasingFunctions.EaseInOutCubic 71| 0| case .easeInQuart: 72| 0| return EasingFunctions.EaseInQuart 73| 0| case .easeOutQuart: 74| 0| return EasingFunctions.EaseOutQuart 75| 0| case .easeInOutQuart: 76| 0| return EasingFunctions.EaseInOutQuart 77| 0| case .easeInQuint: 78| 0| return EasingFunctions.EaseInQuint 79| 0| case .easeOutQuint: 80| 0| return EasingFunctions.EaseOutQuint 81| 0| case .easeInOutQuint: 82| 0| return EasingFunctions.EaseInOutQuint 83| 0| case .easeInSine: 84| 0| return EasingFunctions.EaseInSine 85| 0| case .easeOutSine: 86| 0| return EasingFunctions.EaseOutSine 87| 0| case .easeInOutSine: 88| 0| return EasingFunctions.EaseInOutSine 89| 0| case .easeInExpo: 90| 0| return EasingFunctions.EaseInExpo 91| 0| case .easeOutExpo: 92| 0| return EasingFunctions.EaseOutExpo 93| 0| case .easeInOutExpo: 94| 0| return EasingFunctions.EaseInOutExpo 95| 0| case .easeInCirc: 96| 0| return EasingFunctions.EaseInCirc 97| 0| case .easeOutCirc: 98| 0| return EasingFunctions.EaseOutCirc 99| 0| case .easeInOutCirc: 100| 0| return EasingFunctions.EaseInOutCirc 101| 0| case .easeInElastic: 102| 0| return EasingFunctions.EaseInElastic 103| 0| case .easeOutElastic: 104| 0| return EasingFunctions.EaseOutElastic 105| 0| case .easeInOutElastic: 106| 0| return EasingFunctions.EaseInOutElastic 107| 0| case .easeInBack: 108| 0| return EasingFunctions.EaseInBack 109| 0| case .easeOutBack: 110| 0| return EasingFunctions.EaseOutBack 111| 0| case .easeInOutBack: 112| 0| return EasingFunctions.EaseInOutBack 113| 0| case .easeInBounce: 114| 0| return EasingFunctions.EaseInBounce 115| 0| case .easeOutBounce: 116| 0| return EasingFunctions.EaseOutBounce 117| 0| case .easeInOutBounce: 118| 0| return EasingFunctions.EaseInOutBounce 119| 0| } 120| 0|} 121| | 122| |internal struct EasingFunctions 123| |{ 124| 0| internal static let Linear = { (elapsed: TimeInterval, duration: TimeInterval) -> Double in return Double(elapsed / duration) } 125| | 126| 0| internal static let EaseInQuad = { (elapsed: TimeInterval, duration: TimeInterval) -> Double in 127| 0| var position = Double(elapsed / duration) 128| 0| return position * position 129| 0| } 130| | 131| 0| internal static let EaseOutQuad = { (elapsed: TimeInterval, duration: TimeInterval) -> Double in 132| 0| var position = Double(elapsed / duration) 133| 0| return -position * (position - 2.0) 134| 0| } 135| | 136| 0| internal static let EaseInOutQuad = { (elapsed: TimeInterval, duration: TimeInterval) -> Double in 137| 0| var position = Double(elapsed / (duration / 2.0)) 138| 0| if position < 1.0 139| 0| { 140| 0| return 0.5 * position * position 141| 0| } 142| 0| 143| 0| return -0.5 * ((position - 1.0) * (position - 3.0) - 1.0) 144| 0| } 145| | 146| 0| internal static let EaseInCubic = { (elapsed: TimeInterval, duration: TimeInterval) -> Double in 147| 0| var position = Double(elapsed / duration) 148| 0| return position * position * position 149| 0| } 150| | 151| 0| internal static let EaseOutCubic = { (elapsed: TimeInterval, duration: TimeInterval) -> Double in 152| 0| var position = Double(elapsed / duration) 153| 0| position -= 1.0 154| 0| return (position * position * position + 1.0) 155| 0| } 156| | 157| 0| internal static let EaseInOutCubic = { (elapsed: TimeInterval, duration: TimeInterval) -> Double in 158| 0| var position = Double(elapsed / (duration / 2.0)) 159| 0| if position < 1.0 160| 0| { 161| 0| return 0.5 * position * position * position 162| 0| } 163| 0| position -= 2.0 164| 0| return 0.5 * (position * position * position + 2.0) 165| 0| } 166| | 167| 0| internal static let EaseInQuart = { (elapsed: TimeInterval, duration: TimeInterval) -> Double in 168| 0| var position = Double(elapsed / duration) 169| 0| return position * position * position * position 170| 0| } 171| | 172| 0| internal static let EaseOutQuart = { (elapsed: TimeInterval, duration: TimeInterval) -> Double in 173| 0| var position = Double(elapsed / duration) 174| 0| position -= 1.0 175| 0| return -(position * position * position * position - 1.0) 176| 0| } 177| | 178| 0| internal static let EaseInOutQuart = { (elapsed: TimeInterval, duration: TimeInterval) -> Double in 179| 0| var position = Double(elapsed / (duration / 2.0)) 180| 0| if position < 1.0 181| 0| { 182| 0| return 0.5 * position * position * position * position 183| 0| } 184| 0| position -= 2.0 185| 0| return -0.5 * (position * position * position * position - 2.0) 186| 0| } 187| | 188| 0| internal static let EaseInQuint = { (elapsed: TimeInterval, duration: TimeInterval) -> Double in 189| 0| var position = Double(elapsed / duration) 190| 0| return position * position * position * position * position 191| 0| } 192| | 193| 0| internal static let EaseOutQuint = { (elapsed: TimeInterval, duration: TimeInterval) -> Double in 194| 0| var position = Double(elapsed / duration) 195| 0| position -= 1.0 196| 0| return (position * position * position * position * position + 1.0) 197| 0| } 198| | 199| 0| internal static let EaseInOutQuint = { (elapsed: TimeInterval, duration: TimeInterval) -> Double in 200| 0| var position = Double(elapsed / (duration / 2.0)) 201| 0| if position < 1.0 202| 0| { 203| 0| return 0.5 * position * position * position * position * position 204| 0| } 205| 0| else 206| 0| { 207| 0| position -= 2.0 208| 0| return 0.5 * (position * position * position * position * position + 2.0) 209| 0| } 210| 0| } 211| | 212| 0| internal static let EaseInSine = { (elapsed: TimeInterval, duration: TimeInterval) -> Double in 213| 0| var position: TimeInterval = elapsed / duration 214| 0| return Double( -cos(position * Double.pi / 2) + 1.0 ) 215| 0| } 216| | 217| 0| internal static let EaseOutSine = { (elapsed: TimeInterval, duration: TimeInterval) -> Double in 218| 0| var position: TimeInterval = elapsed / duration 219| 0| return Double( sin(position * Double.pi / 2) ) 220| 0| } 221| | 222| 0| internal static let EaseInOutSine = { (elapsed: TimeInterval, duration: TimeInterval) -> Double in 223| 0| var position: TimeInterval = elapsed / duration 224| 0| return Double( -0.5 * (cos(Double.pi * position) - 1.0) ) 225| 0| } 226| | 227| 0| internal static let EaseInExpo = { (elapsed: TimeInterval, duration: TimeInterval) -> Double in 228| 0| return (elapsed == 0) ? 0.0 : Double(pow(2.0, 10.0 * (elapsed / duration - 1.0))) 229| 0| } 230| | 231| 0| internal static let EaseOutExpo = { (elapsed: TimeInterval, duration: TimeInterval) -> Double in 232| 0| return (elapsed == duration) ? 1.0 : (-Double(pow(2.0, -10.0 * elapsed / duration)) + 1.0) 233| 0| } 234| | 235| 0| internal static let EaseInOutExpo = { (elapsed: TimeInterval, duration: TimeInterval) -> Double in 236| 0| if elapsed == 0 237| 0| { 238| 0| return 0.0 239| 0| } 240| 0| if elapsed == duration 241| 0| { 242| 0| return 1.0 243| 0| } 244| 0| 245| 0| var position: TimeInterval = elapsed / (duration / 2.0) 246| 0| if position < 1.0 247| 0| { 248| 0| return Double( 0.5 * pow(2.0, 10.0 * (position - 1.0)) ) 249| 0| } 250| 0| 251| 0| position = position - 1.0 252| 0| return Double( 0.5 * (-pow(2.0, -10.0 * position) + 2.0) ) 253| 0| } 254| | 255| 0| internal static let EaseInCirc = { (elapsed: TimeInterval, duration: TimeInterval) -> Double in 256| 0| var position = Double(elapsed / duration) 257| 0| return -(Double(sqrt(1.0 - position * position)) - 1.0) 258| 0| } 259| | 260| 0| internal static let EaseOutCirc = { (elapsed: TimeInterval, duration: TimeInterval) -> Double in 261| 0| var position = Double(elapsed / duration) 262| 0| position -= 1.0 263| 0| return Double( sqrt(1 - position * position) ) 264| 0| } 265| | 266| 0| internal static let EaseInOutCirc = { (elapsed: TimeInterval, duration: TimeInterval) -> Double in 267| 0| var position: TimeInterval = elapsed / (duration / 2.0) 268| 0| if position < 1.0 269| 0| { 270| 0| return Double( -0.5 * (sqrt(1.0 - position * position) - 1.0) ) 271| 0| } 272| 0| position -= 2.0 273| 0| return Double( 0.5 * (sqrt(1.0 - position * position) + 1.0) ) 274| 0| } 275| | 276| 0| internal static let EaseInElastic = { (elapsed: TimeInterval, duration: TimeInterval) -> Double in 277| 0| if elapsed == 0.0 278| 0| { 279| 0| return 0.0 280| 0| } 281| 0| 282| 0| var position: TimeInterval = elapsed / duration 283| 0| if position == 1.0 284| 0| { 285| 0| return 1.0 286| 0| } 287| 0| 288| 0| var p = duration * 0.3 289| 0| var s = p / (2.0 * Double.pi) * asin(1.0) 290| 0| position -= 1.0 291| 0| return Double( -(pow(2.0, 10.0 * position) * sin((position * duration - s) * (2.0 * Double.pi) / p)) ) 292| 0| } 293| | 294| 0| internal static let EaseOutElastic = { (elapsed: TimeInterval, duration: TimeInterval) -> Double in 295| 0| if elapsed == 0.0 296| 0| { 297| 0| return 0.0 298| 0| } 299| 0| 300| 0| var position: TimeInterval = elapsed / duration 301| 0| if position == 1.0 302| 0| { 303| 0| return 1.0 304| 0| } 305| 0| 306| 0| var p = duration * 0.3 307| 0| var s = p / (2.0 * Double.pi) * asin(1.0) 308| 0| return Double( pow(2.0, -10.0 * position) * sin((position * duration - s) * (2.0 * Double.pi) / p) + 1.0 ) 309| 0| } 310| | 311| 0| internal static let EaseInOutElastic = { (elapsed: TimeInterval, duration: TimeInterval) -> Double in 312| 0| if elapsed == 0.0 313| 0| { 314| 0| return 0.0 315| 0| } 316| 0| 317| 0| var position: TimeInterval = elapsed / (duration / 2.0) 318| 0| if position == 2.0 319| 0| { 320| 0| return 1.0 321| 0| } 322| 0| 323| 0| var p = duration * (0.3 * 1.5) 324| 0| var s = p / (2.0 * Double.pi) * asin(1.0) 325| 0| if position < 1.0 326| 0| { 327| 0| position -= 1.0 328| 0| return Double( -0.5 * (pow(2.0, 10.0 * position) * sin((position * duration - s) * (2.0 * Double.pi) / p)) ) 329| 0| } 330| 0| position -= 1.0 331| 0| return Double( pow(2.0, -10.0 * position) * sin((position * duration - s) * (2.0 * Double.pi) / p) * 0.5 + 1.0 ) 332| 0| } 333| | 334| 0| internal static let EaseInBack = { (elapsed: TimeInterval, duration: TimeInterval) -> Double in 335| 0| let s: TimeInterval = 1.70158 336| 0| var position: TimeInterval = elapsed / duration 337| 0| return Double( position * position * ((s + 1.0) * position - s) ) 338| 0| } 339| | 340| 0| internal static let EaseOutBack = { (elapsed: TimeInterval, duration: TimeInterval) -> Double in 341| 0| let s: TimeInterval = 1.70158 342| 0| var position: TimeInterval = elapsed / duration 343| 0| position -= 1.0 344| 0| return Double( position * position * ((s + 1.0) * position + s) + 1.0 ) 345| 0| } 346| | 347| 0| internal static let EaseInOutBack = { (elapsed: TimeInterval, duration: TimeInterval) -> Double in 348| 0| var s: TimeInterval = 1.70158 349| 0| var position: TimeInterval = elapsed / (duration / 2.0) 350| 0| if position < 1.0 351| 0| { 352| 0| s *= 1.525 353| 0| return Double( 0.5 * (position * position * ((s + 1.0) * position - s)) ) 354| 0| } 355| 0| s *= 1.525 356| 0| position -= 2.0 357| 0| return Double( 0.5 * (position * position * ((s + 1.0) * position + s) + 2.0) ) 358| 0| } 359| | 360| 0| internal static let EaseInBounce = { (elapsed: TimeInterval, duration: TimeInterval) -> Double in 361| 0| return 1.0 - EaseOutBounce(duration - elapsed, duration) 362| 0| } 363| | 364| 0| internal static let EaseOutBounce = { (elapsed: TimeInterval, duration: TimeInterval) -> Double in 365| 0| var position: TimeInterval = elapsed / duration 366| 0| if position < (1.0 / 2.75) 367| 0| { 368| 0| return Double( 7.5625 * position * position ) 369| 0| } 370| 0| else if position < (2.0 / 2.75) 371| 0| { 372| 0| position -= (1.5 / 2.75) 373| 0| return Double( 7.5625 * position * position + 0.75 ) 374| 0| } 375| 0| else if position < (2.5 / 2.75) 376| 0| { 377| 0| position -= (2.25 / 2.75) 378| 0| return Double( 7.5625 * position * position + 0.9375 ) 379| 0| } 380| 0| else 381| 0| { 382| 0| position -= (2.625 / 2.75) 383| 0| return Double( 7.5625 * position * position + 0.984375 ) 384| 0| } 385| 0| } 386| | 387| 0| internal static let EaseInOutBounce = { (elapsed: TimeInterval, duration: TimeInterval) -> Double in 388| 0| if elapsed < (duration / 2.0) 389| 0| { 390| 0| return EaseInBounce(elapsed * 2.0, duration) * 0.5 391| 0| } 392| 0| return EaseOutBounce(elapsed * 2.0 - duration, duration) * 0.5 + 0.5 393| 0| } 394| |} /Users/travis/build/danielgindi/Charts/Source/Charts/Charts/BarChartView.swift: 1| |// 2| |// BarChartView.swift 3| |// Charts 4| |// 5| |// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda 6| |// A port of MPAndroidChart for iOS 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| | 12| |import Foundation 13| |import CoreGraphics 14| | 15| |/// Chart that draws bars. 16| |open class BarChartView: BarLineChartViewBase, BarChartDataProvider 17| |{ 18| | /// if set to true, all values are drawn above their bars, instead of below their top 19| | private var _drawValueAboveBarEnabled = true 20| | 21| | /// if set to true, a grey area is drawn behind each bar that indicates the maximum value 22| | private var _drawBarShadowEnabled = false 23| | 24| | internal override func initialize() 25| 37| { 26| 37| super.initialize() 27| 37| 28| 37| renderer = BarChartRenderer(dataProvider: self, animator: _animator, viewPortHandler: _viewPortHandler) 29| 37| 30| 37| self.highlighter = BarHighlighter(chart: self) 31| 37| 32| 37| self.xAxis.spaceMin = 0.5 33| 37| self.xAxis.spaceMax = 0.5 34| 37| } 35| | 36| | internal override func calcMinMax() 37| 68| { 38| 68| guard let data = self.data as? BarChartData 39| 68| else { return } 40| 68| 41| 68| if fitBars 42| 68| { 43| 0| _xAxis.calculate( 44| 0| min: data.xMin - data.barWidth / 2.0, 45| 0| max: data.xMax + data.barWidth / 2.0) 46| 68| } 47| 68| else 48| 68| { 49| 68| _xAxis.calculate(min: data.xMin, max: data.xMax) 50| 68| } 51| 68| 52| 68| // calculate axis range (min / max) according to provided data 53| 68| leftAxis.calculate( 54| 68| min: data.getYMin(axis: .left), 55| 68| max: data.getYMax(axis: .left)) 56| 68| rightAxis.calculate( 57| 68| min: data.getYMin(axis: .right), 58| 68| max: data.getYMax(axis: .right)) 59| 68| } 60| | 61| | /// - Returns: The Highlight object (contains x-index and DataSet index) of the selected value at the given touch point inside the BarChart. 62| | open override func getHighlightByTouchPoint(_ pt: CGPoint) -> Highlight? 63| 0| { 64| 0| if _data === nil 65| 0| { 66| 0| Swift.print("Can't select by touch. No data set.") 67| 0| return nil 68| 0| } 69| 0| 70| 0| guard let h = self.highlighter?.getHighlight(x: pt.x, y: pt.y) 71| 0| else { return nil } 72| 0| 73| 0| if !isHighlightFullBarEnabled { return h } 74| 0| 75| 0| // For isHighlightFullBarEnabled, remove stackIndex 76| 0| return Highlight( 77| 0| x: h.x, y: h.y, 78| 0| xPx: h.xPx, yPx: h.yPx, 79| 0| dataIndex: h.dataIndex, 80| 0| dataSetIndex: h.dataSetIndex, 81| 0| stackIndex: -1, 82| 0| axis: h.axis) 83| 0| } 84| | 85| | /// - Returns: The bounding box of the specified Entry in the specified DataSet. Returns null if the Entry could not be found in the charts data. 86| | @objc open func getBarBounds(entry e: BarChartDataEntry) -> CGRect 87| 0| { 88| 0| guard let 89| 0| data = _data as? BarChartData, 90| 0| let set = data.getDataSetForEntry(e) as? IBarChartDataSet 91| 0| else { return CGRect.null } 92| 0| 93| 0| let y = e.y 94| 0| let x = e.x 95| 0| 96| 0| let barWidth = data.barWidth 97| 0| 98| 0| let left = x - barWidth / 2.0 99| 0| let right = x + barWidth / 2.0 100| 0| let top = y >= 0.0 ? y : 0.0 101| 0| let bottom = y <= 0.0 ? y : 0.0 102| 0| 103| 0| var bounds = CGRect(x: left, y: top, width: right - left, height: bottom - top) 104| 0| 105| 0| getTransformer(forAxis: set.axisDependency).rectValueToPixel(&bounds) 106| 0| 107| 0| return bounds 108| 0| } 109| | 110| | /// Groups all BarDataSet objects this data object holds together by modifying the x-value of their entries. 111| | /// Previously set x-values of entries will be overwritten. Leaves space between bars and groups as specified by the parameters. 112| | /// Calls `notifyDataSetChanged()` afterwards. 113| | /// 114| | /// - Parameters: 115| | /// - fromX: the starting point on the x-axis where the grouping should begin 116| | /// - groupSpace: the space between groups of bars in values (not pixels) e.g. 0.8f for bar width 1f 117| | /// - barSpace: the space between individual bars in values (not pixels) e.g. 0.1f for bar width 1f 118| | @objc open func groupBars(fromX: Double, groupSpace: Double, barSpace: Double) 119| 0| { 120| 0| guard let barData = self.barData 121| 0| else 122| 0| { 123| 0| Swift.print("You need to set data for the chart before grouping bars.", terminator: "\n") 124| 0| return 125| 0| } 126| 0| 127| 0| barData.groupBars(fromX: fromX, groupSpace: groupSpace, barSpace: barSpace) 128| 0| notifyDataSetChanged() 129| 0| } 130| | 131| | /// Highlights the value at the given x-value in the given DataSet. Provide -1 as the dataSetIndex to undo all highlighting. 132| | /// 133| | /// - Parameters: 134| | /// - x: 135| | /// - dataSetIndex: 136| | /// - stackIndex: the index inside the stack - only relevant for stacked entries 137| | @objc open func highlightValue(x: Double, dataSetIndex: Int, stackIndex: Int) 138| 0| { 139| 0| highlightValue(Highlight(x: x, dataSetIndex: dataSetIndex, stackIndex: stackIndex)) 140| 0| } 141| | 142| | // MARK: Accessors 143| | 144| | /// if set to true, all values are drawn above their bars, instead of below their top 145| | @objc open var drawValueAboveBarEnabled: Bool 146| | { 147| 37| get { return _drawValueAboveBarEnabled } 148| | set 149| 4| { 150| 4| _drawValueAboveBarEnabled = newValue 151| 4| setNeedsDisplay() 152| 4| } 153| | } 154| | 155| | /// if set to true, a grey area is drawn behind each bar that indicates the maximum value 156| | @objc open var drawBarShadowEnabled: Bool 157| | { 158| 68| get { return _drawBarShadowEnabled } 159| | set 160| 0| { 161| 0| _drawBarShadowEnabled = newValue 162| 0| setNeedsDisplay() 163| 0| } 164| | } 165| | 166| | /// Adds half of the bar width to each side of the x-axis range in order to allow the bars of the barchart to be fully displayed. 167| | /// **default**: false 168| | @objc open var fitBars = false 169| | 170| | /// Set this to `true` to make the highlight operation full-bar oriented, `false` to make it highlight single values (relevant only for stacked). 171| | /// If enabled, highlighting operations will highlight the whole bar, even if only a single stack entry was tapped. 172| | @objc open var highlightFullBarEnabled: Bool = false 173| | 174| | /// `true` the highlight is be full-bar oriented, `false` ifsingle-value 175| 0| open var isHighlightFullBarEnabled: Bool { return highlightFullBarEnabled } 176| | 177| | // MARK: - BarChartDataProvider 178| | 179| 1.25k| open var barData: BarChartData? { return _data as? BarChartData } 180| | 181| | /// `true` if drawing values above bars is enabled, `false` ifnot 182| 37| open var isDrawValueAboveBarEnabled: Bool { return drawValueAboveBarEnabled } 183| | 184| | /// `true` if drawing shadows (maxvalue) for each bar is enabled, `false` ifnot 185| 68| open var isDrawBarShadowEnabled: Bool { return drawBarShadowEnabled } 186| |} /Users/travis/build/danielgindi/Charts/Source/Charts/Charts/BarLineChartViewBase.swift: 1| |// 2| |// BarLineChartViewBase.swift 3| |// Charts 4| |// 5| |// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda 6| |// A port of MPAndroidChart for iOS 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| | 12| |import Foundation 13| |import CoreGraphics 14| | 15| |#if canImport(UIKit) 16| | import UIKit 17| |#endif 18| | 19| |#if canImport(Cocoa) 20| |import Cocoa 21| |#endif 22| | 23| |/// Base-class of LineChart, BarChart, ScatterChart and CandleStickChart. 24| |open class BarLineChartViewBase: ChartViewBase, BarLineScatterCandleBubbleChartDataProvider, NSUIGestureRecognizerDelegate 25| |{ 26| | /// the maximum number of entries to which values will be drawn 27| | /// (entry numbers greater than this value will cause value-labels to disappear) 28| | internal var _maxVisibleCount = 100 29| | 30| | /// flag that indicates if auto scaling on the y axis is enabled 31| | private var _autoScaleMinMaxEnabled = false 32| | 33| | private var _pinchZoomEnabled = false 34| | private var _doubleTapToZoomEnabled = true 35| | private var _dragXEnabled = true 36| | private var _dragYEnabled = true 37| | 38| | private var _scaleXEnabled = true 39| | private var _scaleYEnabled = true 40| | 41| | /// the color for the background of the chart-drawing area (everything behind the grid lines). 42| | @objc open var gridBackgroundColor = NSUIColor(red: 240/255.0, green: 240/255.0, blue: 240/255.0, alpha: 1.0) 43| | 44| | @objc open var borderColor = NSUIColor.black 45| | @objc open var borderLineWidth: CGFloat = 1.0 46| | 47| | /// flag indicating if the grid background should be drawn or not 48| | @objc open var drawGridBackgroundEnabled = false 49| | 50| | /// When enabled, the borders rectangle will be rendered. 51| | /// If this is enabled, there is no point drawing the axis-lines of x- and y-axis. 52| | @objc open var drawBordersEnabled = false 53| | 54| | /// When enabled, the values will be clipped to contentRect, otherwise they can bleed outside the content rect. 55| | @objc open var clipValuesToContentEnabled: Bool = false 56| | 57| | /// When disabled, the data and/or highlights will not be clipped to contentRect. Disabling this option can 58| | /// be useful, when the data lies fully within the content rect, but is drawn in such a way (such as thick lines) 59| | /// that there is unwanted clipping. 60| | @objc open var clipDataToContentEnabled: Bool = true 61| | 62| | /// Sets the minimum offset (padding) around the chart, defaults to 10 63| | @objc open var minOffset = CGFloat(10.0) 64| | 65| | /// Sets whether the chart should keep its position (zoom / scroll) after a rotation (orientation change) 66| | /// **default**: false 67| | @objc open var keepPositionOnRotation: Bool = false 68| | 69| | /// The left y-axis object. In the horizontal bar-chart, this is the 70| | /// top axis. 71| | @objc open internal(set) var leftAxis = YAxis(position: .left) 72| | 73| | /// The right y-axis object. In the horizontal bar-chart, this is the 74| | /// bottom axis. 75| | @objc open internal(set) var rightAxis = YAxis(position: .right) 76| | 77| | /// The left Y axis renderer. This is a read-write property so you can set your own custom renderer here. 78| | /// **default**: An instance of YAxisRenderer 79| | @objc open lazy var leftYAxisRenderer = YAxisRenderer(viewPortHandler: _viewPortHandler, yAxis: leftAxis, transformer: _leftAxisTransformer) 80| | 81| | /// The right Y axis renderer. This is a read-write property so you can set your own custom renderer here. 82| | /// **default**: An instance of YAxisRenderer 83| | @objc open lazy var rightYAxisRenderer = YAxisRenderer(viewPortHandler: _viewPortHandler, yAxis: rightAxis, transformer: _rightAxisTransformer) 84| | 85| | internal var _leftAxisTransformer: Transformer! 86| | internal var _rightAxisTransformer: Transformer! 87| | 88| | /// The X axis renderer. This is a read-write property so you can set your own custom renderer here. 89| | /// **default**: An instance of XAxisRenderer 90| | @objc open lazy var xAxisRenderer = XAxisRenderer(viewPortHandler: _viewPortHandler, xAxis: _xAxis, transformer: _leftAxisTransformer) 91| | 92| | internal var _tapGestureRecognizer: NSUITapGestureRecognizer! 93| | internal var _doubleTapGestureRecognizer: NSUITapGestureRecognizer! 94| | #if !os(tvOS) 95| | internal var _pinchGestureRecognizer: NSUIPinchGestureRecognizer! 96| | #endif 97| | internal var _panGestureRecognizer: NSUIPanGestureRecognizer! 98| | 99| | /// flag that indicates if a custom viewport offset has been set 100| | private var _customViewPortEnabled = false 101| | 102| | public override init(frame: CGRect) 103| 46| { 104| 46| super.init(frame: frame) 105| 46| } 106| | 107| | public required init?(coder aDecoder: NSCoder) 108| 0| { 109| 0| super.init(coder: aDecoder) 110| 0| } 111| | 112| | deinit 113| 37| { 114| 37| stopDeceleration() 115| 37| } 116| | 117| | internal override func initialize() 118| 46| { 119| 46| super.initialize() 120| 46| 121| 46| _leftAxisTransformer = Transformer(viewPortHandler: _viewPortHandler) 122| 46| _rightAxisTransformer = Transformer(viewPortHandler: _viewPortHandler) 123| 46| 124| 46| self.highlighter = ChartHighlighter(chart: self) 125| 46| 126| 46| _tapGestureRecognizer = NSUITapGestureRecognizer(target: self, action: #selector(tapGestureRecognized(_:))) 127| 46| _doubleTapGestureRecognizer = NSUITapGestureRecognizer(target: self, action: #selector(doubleTapGestureRecognized(_:))) 128| 46| _doubleTapGestureRecognizer.nsuiNumberOfTapsRequired = 2 129| 46| _panGestureRecognizer = NSUIPanGestureRecognizer(target: self, action: #selector(panGestureRecognized(_:))) 130| 46| 131| 46| _panGestureRecognizer.delegate = self 132| 46| 133| 46| self.addGestureRecognizer(_tapGestureRecognizer) 134| 46| self.addGestureRecognizer(_doubleTapGestureRecognizer) 135| 46| self.addGestureRecognizer(_panGestureRecognizer) 136| 46| 137| 46| _doubleTapGestureRecognizer.isEnabled = _doubleTapToZoomEnabled 138| 46| _panGestureRecognizer.isEnabled = _dragXEnabled || _dragYEnabled 139| 46| 140| 46| #if !os(tvOS) 141| 46| _pinchGestureRecognizer = NSUIPinchGestureRecognizer(target: self, action: #selector(BarLineChartViewBase.pinchGestureRecognized(_:))) 142| 46| _pinchGestureRecognizer.delegate = self 143| 46| self.addGestureRecognizer(_pinchGestureRecognizer) 144| 46| _pinchGestureRecognizer.isEnabled = _pinchZoomEnabled || _scaleXEnabled || _scaleYEnabled 145| 46| #endif 146| 46| } 147| | 148| | open override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) 149| 0| { 150| 0| // Saving current position of chart. 151| 0| var oldPoint: CGPoint? 152| 0| if (keepPositionOnRotation && (keyPath == "frame" || keyPath == "bounds")) 153| 0| { 154| 0| oldPoint = viewPortHandler.contentRect.origin 155| 0| getTransformer(forAxis: .left).pixelToValues(&oldPoint!) 156| 0| } 157| 0| 158| 0| // Superclass transforms chart. 159| 0| super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context) 160| 0| 161| 0| // Restoring old position of chart 162| 0| if var newPoint = oldPoint , keepPositionOnRotation 163| 0| { 164| 0| getTransformer(forAxis: .left).pointValueToPixel(&newPoint) 165| 0| viewPortHandler.centerViewPort(pt: newPoint, chart: self) 166| 0| } 167| 0| else 168| 0| { 169| 0| viewPortHandler.refresh(newMatrix: viewPortHandler.touchMatrix, chart: self, invalidate: true) 170| 0| } 171| 0| } 172| | 173| | open override func draw(_ rect: CGRect) 174| 46| { 175| 46| super.draw(rect) 176| 46| 177| 46| guard data != nil, let renderer = renderer else { return } 178| 46| 179| 46| let optionalContext = NSUIGraphicsGetCurrentContext() 180| 46| guard let context = optionalContext else { return } 181| 46| 182| 46| // execute all drawing commands 183| 46| drawGridBackground(context: context) 184| 46| 185| 46| 186| 46| if _autoScaleMinMaxEnabled 187| 46| { 188| 0| autoScale() 189| 46| } 190| 46| 191| 46| if leftAxis.isEnabled 192| 46| { 193| 45| leftYAxisRenderer.computeAxis(min: leftAxis._axisMinimum, max: leftAxis._axisMaximum, inverted: leftAxis.isInverted) 194| 46| } 195| 46| 196| 46| if rightAxis.isEnabled 197| 46| { 198| 45| rightYAxisRenderer.computeAxis(min: rightAxis._axisMinimum, max: rightAxis._axisMaximum, inverted: rightAxis.isInverted) 199| 46| } 200| 46| 201| 46| if _xAxis.isEnabled 202| 46| { 203| 46| xAxisRenderer.computeAxis(min: _xAxis._axisMinimum, max: _xAxis._axisMaximum, inverted: false) 204| 46| } 205| 46| 206| 46| xAxisRenderer.renderAxisLine(context: context) 207| 46| leftYAxisRenderer.renderAxisLine(context: context) 208| 46| rightYAxisRenderer.renderAxisLine(context: context) 209| 46| 210| 46| // The renderers are responsible for clipping, to account for line-width center etc. 211| 46| if xAxis.drawGridLinesBehindDataEnabled 212| 46| { 213| 46| xAxisRenderer.renderGridLines(context: context) 214| 46| leftYAxisRenderer.renderGridLines(context: context) 215| 46| rightYAxisRenderer.renderGridLines(context: context) 216| 46| } 217| 46| 218| 46| if _xAxis.isEnabled && _xAxis.isDrawLimitLinesBehindDataEnabled 219| 46| { 220| 0| xAxisRenderer.renderLimitLines(context: context) 221| 46| } 222| 46| 223| 46| if leftAxis.isEnabled && leftAxis.isDrawLimitLinesBehindDataEnabled 224| 46| { 225| 0| leftYAxisRenderer.renderLimitLines(context: context) 226| 46| } 227| 46| 228| 46| if rightAxis.isEnabled && rightAxis.isDrawLimitLinesBehindDataEnabled 229| 46| { 230| 0| rightYAxisRenderer.renderLimitLines(context: context) 231| 46| } 232| 46| 233| 46| context.saveGState() 234| 46| // make sure the data cannot be drawn outside the content-rect 235| 46| if clipDataToContentEnabled { 236| 46| context.clip(to: _viewPortHandler.contentRect) 237| 46| } 238| 46| renderer.drawData(context: context) 239| 46| 240| 46| // The renderers are responsible for clipping, to account for line-width center etc. 241| 46| if !xAxis.drawGridLinesBehindDataEnabled 242| 46| { 243| 0| xAxisRenderer.renderGridLines(context: context) 244| 0| leftYAxisRenderer.renderGridLines(context: context) 245| 0| rightYAxisRenderer.renderGridLines(context: context) 246| 46| } 247| 46| 248| 46| // if highlighting is enabled 249| 46| if (valuesToHighlight()) 250| 46| { 251| 0| renderer.drawHighlighted(context: context, indices: _indicesToHighlight) 252| 46| } 253| 46| 254| 46| context.restoreGState() 255| 46| 256| 46| renderer.drawExtras(context: context) 257| 46| 258| 46| if _xAxis.isEnabled && !_xAxis.isDrawLimitLinesBehindDataEnabled 259| 46| { 260| 46| xAxisRenderer.renderLimitLines(context: context) 261| 46| } 262| 46| 263| 46| if leftAxis.isEnabled && !leftAxis.isDrawLimitLinesBehindDataEnabled 264| 46| { 265| 45| leftYAxisRenderer.renderLimitLines(context: context) 266| 46| } 267| 46| 268| 46| if rightAxis.isEnabled && !rightAxis.isDrawLimitLinesBehindDataEnabled 269| 46| { 270| 45| rightYAxisRenderer.renderLimitLines(context: context) 271| 46| } 272| 46| 273| 46| xAxisRenderer.renderAxisLabels(context: context) 274| 46| leftYAxisRenderer.renderAxisLabels(context: context) 275| 46| rightYAxisRenderer.renderAxisLabels(context: context) 276| 46| 277| 46| if clipValuesToContentEnabled 278| 46| { 279| 1| context.saveGState() 280| 1| context.clip(to: _viewPortHandler.contentRect) 281| 1| 282| 1| renderer.drawValues(context: context) 283| 1| 284| 1| context.restoreGState() 285| 46| } 286| 46| else 287| 46| { 288| 45| renderer.drawValues(context: context) 289| 46| } 290| 46| 291| 46| _legendRenderer.renderLegend(context: context) 292| 46| 293| 46| drawDescription(context: context) 294| 46| 295| 46| drawMarkers(context: context) 296| 46| } 297| | 298| | private var _autoScaleLastLowestVisibleX: Double? 299| | private var _autoScaleLastHighestVisibleX: Double? 300| | 301| | /// Performs auto scaling of the axis by recalculating the minimum and maximum y-values based on the entries currently in view. 302| | internal func autoScale() 303| 0| { 304| 0| guard let data = _data 305| 0| else { return } 306| 0| 307| 0| data.calcMinMaxY(fromX: self.lowestVisibleX, toX: self.highestVisibleX) 308| 0| 309| 0| _xAxis.calculate(min: data.xMin, max: data.xMax) 310| 0| 311| 0| // calculate axis range (min / max) according to provided data 312| 0| 313| 0| if leftAxis.isEnabled 314| 0| { 315| 0| leftAxis.calculate(min: data.getYMin(axis: .left), max: data.getYMax(axis: .left)) 316| 0| } 317| 0| 318| 0| if rightAxis.isEnabled 319| 0| { 320| 0| rightAxis.calculate(min: data.getYMin(axis: .right), max: data.getYMax(axis: .right)) 321| 0| } 322| 0| 323| 0| calculateOffsets() 324| 0| } 325| | 326| | internal func prepareValuePxMatrix() 327| 108| { 328| 108| _rightAxisTransformer.prepareMatrixValuePx(chartXMin: _xAxis._axisMinimum, deltaX: CGFloat(xAxis.axisRange), deltaY: CGFloat(rightAxis.axisRange), chartYMin: rightAxis._axisMinimum) 329| 108| _leftAxisTransformer.prepareMatrixValuePx(chartXMin: xAxis._axisMinimum, deltaX: CGFloat(xAxis.axisRange), deltaY: CGFloat(leftAxis.axisRange), chartYMin: leftAxis._axisMinimum) 330| 108| } 331| | 332| | internal func prepareOffsetMatrix() 333| 125| { 334| 125| _rightAxisTransformer.prepareMatrixOffset(inverted: rightAxis.isInverted) 335| 125| _leftAxisTransformer.prepareMatrixOffset(inverted: leftAxis.isInverted) 336| 125| } 337| | 338| | open override func notifyDataSetChanged() 339| 79| { 340| 79| renderer?.initBuffers() 341| 79| 342| 79| calcMinMax() 343| 79| 344| 79| leftYAxisRenderer.computeAxis(min: leftAxis._axisMinimum, max: leftAxis._axisMaximum, inverted: leftAxis.isInverted) 345| 79| rightYAxisRenderer.computeAxis(min: rightAxis._axisMinimum, max: rightAxis._axisMaximum, inverted: rightAxis.isInverted) 346| 79| 347| 79| if let data = _data 348| 79| { 349| 79| xAxisRenderer.computeAxis( 350| 79| min: _xAxis._axisMinimum, 351| 79| max: _xAxis._axisMaximum, 352| 79| inverted: false) 353| 79| 354| 79| if _legend !== nil 355| 79| { 356| 79| legendRenderer?.computeLegend(data: data) 357| 79| } 358| 79| } 359| 79| 360| 79| calculateOffsets() 361| 79| 362| 79| setNeedsDisplay() 363| 79| } 364| | 365| | internal override func calcMinMax() 366| 11| { 367| 11| // calculate / set x-axis range 368| 11| _xAxis.calculate(min: _data?.xMin ?? 0.0, max: _data?.xMax ?? 0.0) 369| 11| 370| 11| // calculate axis range (min / max) according to provided data 371| 11| leftAxis.calculate(min: _data?.getYMin(axis: .left) ?? 0.0, max: _data?.getYMax(axis: .left) ?? 0.0) 372| 11| rightAxis.calculate(min: _data?.getYMin(axis: .right) ?? 0.0, max: _data?.getYMax(axis: .right) ?? 0.0) 373| 11| } 374| | 375| | internal func calculateLegendOffsets(offsetLeft: inout CGFloat, offsetTop: inout CGFloat, offsetRight: inout CGFloat, offsetBottom: inout CGFloat) 376| 108| { 377| 108| // setup offsets for legend 378| 108| if _legend !== nil && _legend.isEnabled && !_legend.drawInside 379| 108| { 380| 108| switch _legend.orientation 381| 108| { 382| 108| case .vertical: 383| 0| 384| 0| switch _legend.horizontalAlignment 385| 0| { 386| 0| case .left: 387| 0| offsetLeft += min(_legend.neededWidth, _viewPortHandler.chartWidth * _legend.maxSizePercent) + _legend.xOffset 388| 0| 389| 0| case .right: 390| 0| offsetRight += min(_legend.neededWidth, _viewPortHandler.chartWidth * _legend.maxSizePercent) + _legend.xOffset 391| 0| 392| 0| case .center: 393| 0| 394| 0| switch _legend.verticalAlignment 395| 0| { 396| 0| case .top: 397| 0| offsetTop += min(_legend.neededHeight, _viewPortHandler.chartHeight * _legend.maxSizePercent) + _legend.yOffset 398| 0| 399| 0| case .bottom: 400| 0| offsetBottom += min(_legend.neededHeight, _viewPortHandler.chartHeight * _legend.maxSizePercent) + _legend.yOffset 401| 0| 402| 0| default: 403| 0| break 404| 0| } 405| 108| } 406| 108| 407| 108| case .horizontal: 408| 108| 409| 108| switch _legend.verticalAlignment 410| 108| { 411| 108| case .top: 412| 0| offsetTop += min(_legend.neededHeight, _viewPortHandler.chartHeight * _legend.maxSizePercent) + _legend.yOffset 413| 108| 414| 108| case .bottom: 415| 108| offsetBottom += min(_legend.neededHeight, _viewPortHandler.chartHeight * _legend.maxSizePercent) + _legend.yOffset 416| 108| 417| 108| default: 418| 0| break 419| 108| } 420| 108| } 421| 108| } 422| 108| } 423| | 424| | internal override func calculateOffsets() 425| 108| { 426| 108| if !_customViewPortEnabled 427| 108| { 428| 108| var offsetLeft = CGFloat(0.0) 429| 108| var offsetRight = CGFloat(0.0) 430| 108| var offsetTop = CGFloat(0.0) 431| 108| var offsetBottom = CGFloat(0.0) 432| 108| 433| 108| calculateLegendOffsets(offsetLeft: &offsetLeft, 434| 108| offsetTop: &offsetTop, 435| 108| offsetRight: &offsetRight, 436| 108| offsetBottom: &offsetBottom) 437| 108| 438| 108| // offsets for y-labels 439| 108| if leftAxis.needsOffset 440| 108| { 441| 106| offsetLeft += leftAxis.requiredSize().width 442| 108| } 443| 108| 444| 108| if rightAxis.needsOffset 445| 108| { 446| 106| offsetRight += rightAxis.requiredSize().width 447| 108| } 448| 108| 449| 108| if xAxis.isEnabled && xAxis.isDrawLabelsEnabled 450| 108| { 451| 108| let xlabelheight = xAxis.labelRotatedHeight + xAxis.yOffset 452| 108| 453| 108| // offsets for x-labels 454| 108| if xAxis.labelPosition == .bottom 455| 108| { 456| 0| offsetBottom += xlabelheight 457| 108| } 458| 108| else if xAxis.labelPosition == .top 459| 108| { 460| 108| offsetTop += xlabelheight 461| 108| } 462| 108| else if xAxis.labelPosition == .bothSided 463| 108| { 464| 0| offsetBottom += xlabelheight 465| 0| offsetTop += xlabelheight 466| 108| } 467| 108| } 468| 108| 469| 108| offsetTop += self.extraTopOffset 470| 108| offsetRight += self.extraRightOffset 471| 108| offsetBottom += self.extraBottomOffset 472| 108| offsetLeft += self.extraLeftOffset 473| 108| 474| 108| _viewPortHandler.restrainViewPort( 475| 108| offsetLeft: max(self.minOffset, offsetLeft), 476| 108| offsetTop: max(self.minOffset, offsetTop), 477| 108| offsetRight: max(self.minOffset, offsetRight), 478| 108| offsetBottom: max(self.minOffset, offsetBottom)) 479| 108| } 480| 108| 481| 108| prepareOffsetMatrix() 482| 108| prepareValuePxMatrix() 483| 108| } 484| | 485| | /// draws the grid background 486| | internal func drawGridBackground(context: CGContext) 487| 46| { 488| 46| if drawGridBackgroundEnabled || drawBordersEnabled 489| 46| { 490| 0| context.saveGState() 491| 46| } 492| 46| 493| 46| if drawGridBackgroundEnabled 494| 46| { 495| 0| // draw the grid background 496| 0| context.setFillColor(gridBackgroundColor.cgColor) 497| 0| context.fill(_viewPortHandler.contentRect) 498| 46| } 499| 46| 500| 46| if drawBordersEnabled 501| 46| { 502| 0| context.setLineWidth(borderLineWidth) 503| 0| context.setStrokeColor(borderColor.cgColor) 504| 0| context.stroke(_viewPortHandler.contentRect) 505| 46| } 506| 46| 507| 46| if drawGridBackgroundEnabled || drawBordersEnabled 508| 46| { 509| 0| context.restoreGState() 510| 46| } 511| 46| } 512| | 513| | // MARK: - Gestures 514| | 515| | private enum GestureScaleAxis 516| | { 517| | case both 518| | case x 519| | case y 520| | } 521| | 522| | private var _isDragging = false 523| | private var _isScaling = false 524| | private var _gestureScaleAxis = GestureScaleAxis.both 525| | private var _closestDataSetToTouch: IChartDataSet! 526| | private var _panGestureReachedEdge: Bool = false 527| | private weak var _outerScrollView: NSUIScrollView? 528| | 529| | private var _lastPanPoint = CGPoint() /// This is to prevent using setTranslation which resets velocity 530| | 531| | private var _decelerationLastTime: TimeInterval = 0.0 532| | private var _decelerationDisplayLink: NSUIDisplayLink! 533| | private var _decelerationVelocity = CGPoint() 534| | 535| | @objc private func tapGestureRecognized(_ recognizer: NSUITapGestureRecognizer) 536| 0| { 537| 0| if _data === nil 538| 0| { 539| 0| return 540| 0| } 541| 0| 542| 0| if recognizer.state == NSUIGestureRecognizerState.ended 543| 0| { 544| 0| if !isHighLightPerTapEnabled { return } 545| 0| 546| 0| let h = getHighlightByTouchPoint(recognizer.location(in: self)) 547| 0| 548| 0| if h === nil || h == self.lastHighlighted 549| 0| { 550| 0| lastHighlighted = nil 551| 0| highlightValue(nil, callDelegate: true) 552| 0| } 553| 0| else 554| 0| { 555| 0| lastHighlighted = h 556| 0| highlightValue(h, callDelegate: true) 557| 0| } 558| 0| } 559| 0| } 560| | 561| | @objc private func doubleTapGestureRecognized(_ recognizer: NSUITapGestureRecognizer) 562| 0| { 563| 0| if _data === nil 564| 0| { 565| 0| return 566| 0| } 567| 0| 568| 0| if recognizer.state == NSUIGestureRecognizerState.ended 569| 0| { 570| 0| if _data !== nil && _doubleTapToZoomEnabled && (data?.entryCount ?? 0) > 0 571| 0| { 572| 0| var location = recognizer.location(in: self) 573| 0| location.x = location.x - _viewPortHandler.offsetLeft 574| 0| 575| 0| if isTouchInverted() 576| 0| { 577| 0| location.y = -(location.y - _viewPortHandler.offsetTop) 578| 0| } 579| 0| else 580| 0| { 581| 0| location.y = -(self.bounds.size.height - location.y - _viewPortHandler.offsetBottom) 582| 0| } 583| 0| 584| 0| let scaleX: CGFloat = isScaleXEnabled ? 1.4 : 1.0 585| 0| let scaleY: CGFloat = isScaleYEnabled ? 1.4 : 1.0 586| 0| 587| 0| self.zoom(scaleX: scaleX, scaleY: scaleY, x: location.x, y: location.y) 588| 0| delegate?.chartScaled?(self, scaleX: scaleX, scaleY: scaleY) 589| 0| } 590| 0| } 591| 0| } 592| | 593| | #if !os(tvOS) 594| | @objc private func pinchGestureRecognized(_ recognizer: NSUIPinchGestureRecognizer) 595| | { 596| | if recognizer.state == NSUIGestureRecognizerState.began 597| | { 598| | stopDeceleration() 599| | 600| | if _data !== nil && 601| | (_pinchZoomEnabled || _scaleXEnabled || _scaleYEnabled) 602| | { 603| | _isScaling = true 604| | 605| | if _pinchZoomEnabled 606| | { 607| | _gestureScaleAxis = .both 608| | } 609| | else 610| | { 611| | let x = abs(recognizer.location(in: self).x - recognizer.nsuiLocationOfTouch(1, inView: self).x) 612| | let y = abs(recognizer.location(in: self).y - recognizer.nsuiLocationOfTouch(1, inView: self).y) 613| | 614| | if _scaleXEnabled != _scaleYEnabled 615| | { 616| | _gestureScaleAxis = _scaleXEnabled ? .x : .y 617| | } 618| | else 619| | { 620| | _gestureScaleAxis = x > y ? .x : .y 621| | } 622| | } 623| | } 624| | } 625| | else if recognizer.state == NSUIGestureRecognizerState.ended || 626| | recognizer.state == NSUIGestureRecognizerState.cancelled 627| | { 628| | if _isScaling 629| | { 630| | _isScaling = false 631| | 632| | // 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. 633| | calculateOffsets() 634| | setNeedsDisplay() 635| | } 636| | } 637| | else if recognizer.state == NSUIGestureRecognizerState.changed 638| | { 639| | let isZoomingOut = (recognizer.nsuiScale < 1) 640| | var canZoomMoreX = isZoomingOut ? _viewPortHandler.canZoomOutMoreX : _viewPortHandler.canZoomInMoreX 641| | var canZoomMoreY = isZoomingOut ? _viewPortHandler.canZoomOutMoreY : _viewPortHandler.canZoomInMoreY 642| | 643| | if _isScaling 644| | { 645| | canZoomMoreX = canZoomMoreX && _scaleXEnabled && (_gestureScaleAxis == .both || _gestureScaleAxis == .x) 646| | canZoomMoreY = canZoomMoreY && _scaleYEnabled && (_gestureScaleAxis == .both || _gestureScaleAxis == .y) 647| | if canZoomMoreX || canZoomMoreY 648| | { 649| | var location = recognizer.location(in: self) 650| | location.x = location.x - _viewPortHandler.offsetLeft 651| | 652| | if isTouchInverted() 653| | { 654| | location.y = -(location.y - _viewPortHandler.offsetTop) 655| | } 656| | else 657| | { 658| | location.y = -(_viewPortHandler.chartHeight - location.y - _viewPortHandler.offsetBottom) 659| | } 660| | 661| | let scaleX = canZoomMoreX ? recognizer.nsuiScale : 1.0 662| | let scaleY = canZoomMoreY ? recognizer.nsuiScale : 1.0 663| | 664| | var matrix = CGAffineTransform(translationX: location.x, y: location.y) 665| | matrix = matrix.scaledBy(x: scaleX, y: scaleY) 666| | matrix = matrix.translatedBy(x: -location.x, y: -location.y) 667| | 668| | matrix = _viewPortHandler.touchMatrix.concatenating(matrix) 669| | 670| | _viewPortHandler.refresh(newMatrix: matrix, chart: self, invalidate: true) 671| | 672| | if delegate !== nil 673| | { 674| | delegate?.chartScaled?(self, scaleX: scaleX, scaleY: scaleY) 675| | } 676| | } 677| | 678| | recognizer.nsuiScale = 1.0 679| | } 680| | } 681| | } 682| | #endif 683| | 684| | @objc private func panGestureRecognized(_ recognizer: NSUIPanGestureRecognizer) 685| 0| { 686| 0| if recognizer.state == NSUIGestureRecognizerState.began && recognizer.nsuiNumberOfTouches() > 0 687| 0| { 688| 0| stopDeceleration() 689| 0| 690| 0| if _data === nil || !self.isDragEnabled 691| 0| { // If we have no data, we have nothing to pan and no data to highlight 692| 0| return 693| 0| } 694| 0| 695| 0| // If drag is enabled and we are in a position where there's something to drag: 696| 0| // * If we're zoomed in, then obviously we have something to drag. 697| 0| // * If we have a drag offset - we always have something to drag 698| 0| if !self.hasNoDragOffset || !self.isFullyZoomedOut 699| 0| { 700| 0| _isDragging = true 701| 0| 702| 0| _closestDataSetToTouch = getDataSetByTouchPoint(point: recognizer.nsuiLocationOfTouch(0, inView: self)) 703| 0| 704| 0| var translation = recognizer.translation(in: self) 705| 0| if !self.dragXEnabled 706| 0| { 707| 0| translation.x = 0.0 708| 0| } 709| 0| else if !self.dragYEnabled 710| 0| { 711| 0| translation.y = 0.0 712| 0| } 713| 0| 714| 0| let didUserDrag = translation.x != 0.0 || translation.y != 0.0 715| 0| 716| 0| // Check to see if user dragged at all and if so, can the chart be dragged by the given amount 717| 0| if didUserDrag && !performPanChange(translation: translation) 718| 0| { 719| 0| if _outerScrollView !== nil 720| 0| { 721| 0| // We can stop dragging right now, and let the scroll view take control 722| 0| _outerScrollView = nil 723| 0| _isDragging = false 724| 0| } 725| 0| } 726| 0| else 727| 0| { 728| 0| if _outerScrollView !== nil 729| 0| { 730| 0| // Prevent the parent scroll view from scrolling 731| 0| _outerScrollView?.nsuiIsScrollEnabled = false 732| 0| } 733| 0| } 734| 0| 735| 0| _lastPanPoint = recognizer.translation(in: self) 736| 0| } 737| 0| else if self.isHighlightPerDragEnabled 738| 0| { 739| 0| // We will only handle highlights on NSUIGestureRecognizerState.Changed 740| 0| 741| 0| _isDragging = false 742| 0| } 743| 0| } 744| 0| else if recognizer.state == NSUIGestureRecognizerState.changed 745| 0| { 746| 0| if _isDragging 747| 0| { 748| 0| let originalTranslation = recognizer.translation(in: self) 749| 0| var translation = CGPoint(x: originalTranslation.x - _lastPanPoint.x, y: originalTranslation.y - _lastPanPoint.y) 750| 0| 751| 0| if !self.dragXEnabled 752| 0| { 753| 0| translation.x = 0.0 754| 0| } 755| 0| else if !self.dragYEnabled 756| 0| { 757| 0| translation.y = 0.0 758| 0| } 759| 0| 760| 0| let _ = performPanChange(translation: translation) 761| 0| 762| 0| _lastPanPoint = originalTranslation 763| 0| } 764| 0| else if isHighlightPerDragEnabled 765| 0| { 766| 0| let h = getHighlightByTouchPoint(recognizer.location(in: self)) 767| 0| 768| 0| let lastHighlighted = self.lastHighlighted 769| 0| 770| 0| if h != lastHighlighted 771| 0| { 772| 0| self.lastHighlighted = h 773| 0| self.highlightValue(h, callDelegate: true) 774| 0| } 775| 0| } 776| 0| } 777| 0| else if recognizer.state == NSUIGestureRecognizerState.ended || recognizer.state == NSUIGestureRecognizerState.cancelled 778| 0| { 779| 0| if _isDragging 780| 0| { 781| 0| if recognizer.state == NSUIGestureRecognizerState.ended && isDragDecelerationEnabled 782| 0| { 783| 0| stopDeceleration() 784| 0| 785| 0| _decelerationLastTime = CACurrentMediaTime() 786| 0| _decelerationVelocity = recognizer.velocity(in: self) 787| 0| 788| 0| _decelerationDisplayLink = NSUIDisplayLink(target: self, selector: #selector(BarLineChartViewBase.decelerationLoop)) 789| 0| _decelerationDisplayLink.add(to: RunLoop.main, forMode: RunLoop.Mode.common) 790| 0| } 791| 0| 792| 0| _isDragging = false 793| 0| 794| 0| delegate?.chartViewDidEndPanning?(self) 795| 0| } 796| 0| 797| 0| if _outerScrollView !== nil 798| 0| { 799| 0| _outerScrollView?.nsuiIsScrollEnabled = true 800| 0| _outerScrollView = nil 801| 0| } 802| 0| } 803| 0| } 804| | 805| | private func performPanChange(translation: CGPoint) -> Bool 806| 0| { 807| 0| var translation = translation 808| 0| 809| 0| if isTouchInverted() 810| 0| { 811| 0| if self is HorizontalBarChartView 812| 0| { 813| 0| translation.x = -translation.x 814| 0| } 815| 0| else 816| 0| { 817| 0| translation.y = -translation.y 818| 0| } 819| 0| } 820| 0| 821| 0| let originalMatrix = _viewPortHandler.touchMatrix 822| 0| 823| 0| var matrix = CGAffineTransform(translationX: translation.x, y: translation.y) 824| 0| matrix = originalMatrix.concatenating(matrix) 825| 0| 826| 0| matrix = _viewPortHandler.refresh(newMatrix: matrix, chart: self, invalidate: true) 827| 0| 828| 0| if matrix != originalMatrix 829| 0| { 830| 0| delegate?.chartTranslated?(self, dX: translation.x, dY: translation.y) 831| 0| } 832| 0| 833| 0| // Did we managed to actually drag or did we reach the edge? 834| 0| return matrix.tx != originalMatrix.tx || matrix.ty != originalMatrix.ty 835| 0| } 836| | 837| | private func isTouchInverted() -> Bool 838| 0| { 839| 0| return isAnyAxisInverted && 840| 0| _closestDataSetToTouch !== nil && 841| 0| getAxis(_closestDataSetToTouch.axisDependency).isInverted 842| 0| } 843| | 844| | @objc open func stopDeceleration() 845| 37| { 846| 37| if _decelerationDisplayLink !== nil 847| 37| { 848| 0| _decelerationDisplayLink.remove(from: RunLoop.main, forMode: RunLoop.Mode.common) 849| 0| _decelerationDisplayLink = nil 850| 37| } 851| 37| } 852| | 853| | @objc private func decelerationLoop() 854| 0| { 855| 0| let currentTime = CACurrentMediaTime() 856| 0| 857| 0| _decelerationVelocity.x *= self.dragDecelerationFrictionCoef 858| 0| _decelerationVelocity.y *= self.dragDecelerationFrictionCoef 859| 0| 860| 0| let timeInterval = CGFloat(currentTime - _decelerationLastTime) 861| 0| 862| 0| let distance = CGPoint( 863| 0| x: _decelerationVelocity.x * timeInterval, 864| 0| y: _decelerationVelocity.y * timeInterval 865| 0| ) 866| 0| 867| 0| if !performPanChange(translation: distance) 868| 0| { 869| 0| // We reached the edge, stop 870| 0| _decelerationVelocity.x = 0.0 871| 0| _decelerationVelocity.y = 0.0 872| 0| } 873| 0| 874| 0| _decelerationLastTime = currentTime 875| 0| 876| 0| if abs(_decelerationVelocity.x) < 0.001 && abs(_decelerationVelocity.y) < 0.001 877| 0| { 878| 0| stopDeceleration() 879| 0| 880| 0| // 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. 881| 0| calculateOffsets() 882| 0| setNeedsDisplay() 883| 0| } 884| 0| } 885| | 886| | private func nsuiGestureRecognizerShouldBegin(_ gestureRecognizer: NSUIGestureRecognizer) -> Bool 887| 0| { 888| 0| if gestureRecognizer == _panGestureRecognizer 889| 0| { 890| 0| let velocity = _panGestureRecognizer.velocity(in: self) 891| 0| if _data === nil || !isDragEnabled || 892| 0| (self.hasNoDragOffset && self.isFullyZoomedOut && !self.isHighlightPerDragEnabled) || 893| 0| (!_dragYEnabled && abs(velocity.y) > abs(velocity.x)) || 894| 0| (!_dragXEnabled && abs(velocity.y) < abs(velocity.x)) 895| 0| { 896| 0| return false 897| 0| } 898| 0| } 899| 0| else 900| 0| { 901| 0| #if !os(tvOS) 902| 0| if gestureRecognizer == _pinchGestureRecognizer 903| 0| { 904| 0| if _data === nil || (!_pinchZoomEnabled && !_scaleXEnabled && !_scaleYEnabled) 905| 0| { 906| 0| return false 907| 0| } 908| 0| } 909| 0| #endif 910| 0| } 911| 0| 912| 0| return true 913| 0| } 914| | 915| | #if !os(OSX) 916| | open override func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool 917| 0| { 918| 0| if !super.gestureRecognizerShouldBegin(gestureRecognizer) 919| 0| { 920| 0| return false 921| 0| } 922| 0| 923| 0| return nsuiGestureRecognizerShouldBegin(gestureRecognizer) 924| 0| } 925| | #endif 926| | 927| | #if os(OSX) 928| | public func gestureRecognizerShouldBegin(gestureRecognizer: NSGestureRecognizer) -> Bool 929| | { 930| | return nsuiGestureRecognizerShouldBegin(gestureRecognizer) 931| | } 932| | #endif 933| | 934| | open func gestureRecognizer(_ gestureRecognizer: NSUIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: NSUIGestureRecognizer) -> Bool 935| 0| { 936| 0| #if !os(tvOS) 937| 0| if ((gestureRecognizer is NSUIPinchGestureRecognizer && otherGestureRecognizer is NSUIPanGestureRecognizer) || 938| 0| (gestureRecognizer is NSUIPanGestureRecognizer && otherGestureRecognizer is NSUIPinchGestureRecognizer)) 939| 0| { 940| 0| return true 941| 0| } 942| 0| #endif 943| 0| 944| 0| if gestureRecognizer is NSUIPanGestureRecognizer, 945| 0| otherGestureRecognizer is NSUIPanGestureRecognizer, 946| 0| gestureRecognizer == _panGestureRecognizer 947| 0| { 948| 0| var scrollView = self.superview 949| 0| while scrollView != nil && !(scrollView is NSUIScrollView) 950| 0| { 951| 0| scrollView = scrollView?.superview 952| 0| } 953| 0| 954| 0| // If there is two scrollview together, we pick the superview of the inner scrollview. 955| 0| // In the case of UITableViewWrepperView, the superview will be UITableView 956| 0| if let superViewOfScrollView = scrollView?.superview, 957| 0| superViewOfScrollView is NSUIScrollView 958| 0| { 959| 0| scrollView = superViewOfScrollView 960| 0| } 961| 0| 962| 0| var foundScrollView = scrollView as? NSUIScrollView 963| 0| 964| 0| if !(foundScrollView?.nsuiIsScrollEnabled ?? true) 965| 0| { 966| 0| foundScrollView = nil 967| 0| } 968| 0| 969| 0| let scrollViewPanGestureRecognizer = foundScrollView?.nsuiGestureRecognizers?.first { 970| 0| $0 is NSUIPanGestureRecognizer 971| 0| } 972| 0| 973| 0| if otherGestureRecognizer === scrollViewPanGestureRecognizer 974| 0| { 975| 0| _outerScrollView = foundScrollView 976| 0| 977| 0| return true 978| 0| } 979| 0| } 980| 0| 981| 0| return false 982| 0| } 983| | 984| | /// MARK: Viewport modifiers 985| | 986| | /// Zooms in by 1.4, into the charts center. 987| | @objc open func zoomIn() 988| 0| { 989| 0| let center = _viewPortHandler.contentCenter 990| 0| 991| 0| let matrix = _viewPortHandler.zoomIn(x: center.x, y: -center.y) 992| 0| _viewPortHandler.refresh(newMatrix: matrix, chart: self, invalidate: false) 993| 0| 994| 0| // 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. 995| 0| calculateOffsets() 996| 0| setNeedsDisplay() 997| 0| } 998| | 999| | /// Zooms out by 0.7, from the charts center. 1000| | @objc open func zoomOut() 1001| 0| { 1002| 0| let center = _viewPortHandler.contentCenter 1003| 0| 1004| 0| let matrix = _viewPortHandler.zoomOut(x: center.x, y: -center.y) 1005| 0| _viewPortHandler.refresh(newMatrix: matrix, chart: self, invalidate: false) 1006| 0| 1007| 0| // 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. 1008| 0| calculateOffsets() 1009| 0| setNeedsDisplay() 1010| 0| } 1011| | 1012| | /// Zooms out to original size. 1013| | @objc open func resetZoom() 1014| 0| { 1015| 0| let matrix = _viewPortHandler.resetZoom() 1016| 0| _viewPortHandler.refresh(newMatrix: matrix, chart: self, invalidate: false) 1017| 0| 1018| 0| // 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. 1019| 0| calculateOffsets() 1020| 0| setNeedsDisplay() 1021| 0| } 1022| | 1023| | /// Zooms in or out by the given scale factor. x and y are the coordinates 1024| | /// (in pixels) of the zoom center. 1025| | /// 1026| | /// - Parameters: 1027| | /// - scaleX: if < 1 --> zoom out, if > 1 --> zoom in 1028| | /// - scaleY: if < 1 --> zoom out, if > 1 --> zoom in 1029| | /// - x: 1030| | /// - y: 1031| | @objc open func zoom( 1032| | scaleX: CGFloat, 1033| | scaleY: CGFloat, 1034| | x: CGFloat, 1035| | y: CGFloat) 1036| 0| { 1037| 0| let matrix = _viewPortHandler.zoom(scaleX: scaleX, scaleY: scaleY, x: x, y: -y) 1038| 0| _viewPortHandler.refresh(newMatrix: matrix, chart: self, invalidate: false) 1039| 0| 1040| 0| // 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. 1041| 0| calculateOffsets() 1042| 0| setNeedsDisplay() 1043| 0| } 1044| | 1045| | /// Zooms in or out by the given scale factor. 1046| | /// x and y are the values (**not pixels**) of the zoom center. 1047| | /// 1048| | /// - Parameters: 1049| | /// - scaleX: if < 1 --> zoom out, if > 1 --> zoom in 1050| | /// - scaleY: if < 1 --> zoom out, if > 1 --> zoom in 1051| | /// - xValue: 1052| | /// - yValue: 1053| | /// - axis: 1054| | @objc open func zoom( 1055| | scaleX: CGFloat, 1056| | scaleY: CGFloat, 1057| | xValue: Double, 1058| | yValue: Double, 1059| | axis: YAxis.AxisDependency) 1060| 0| { 1061| 0| let job = ZoomViewJob( 1062| 0| viewPortHandler: viewPortHandler, 1063| 0| scaleX: scaleX, 1064| 0| scaleY: scaleY, 1065| 0| xValue: xValue, 1066| 0| yValue: yValue, 1067| 0| transformer: getTransformer(forAxis: axis), 1068| 0| axis: axis, 1069| 0| view: self) 1070| 0| addViewportJob(job) 1071| 0| } 1072| | 1073| | /// Zooms to the center of the chart with the given scale factor. 1074| | /// 1075| | /// - Parameters: 1076| | /// - scaleX: if < 1 --> zoom out, if > 1 --> zoom in 1077| | /// - scaleY: if < 1 --> zoom out, if > 1 --> zoom in 1078| | /// - xValue: 1079| | /// - yValue: 1080| | /// - axis: 1081| | @objc open func zoomToCenter( 1082| | scaleX: CGFloat, 1083| | scaleY: CGFloat) 1084| 0| { 1085| 0| let center = centerOffsets 1086| 0| let matrix = viewPortHandler.zoom( 1087| 0| scaleX: scaleX, 1088| 0| scaleY: scaleY, 1089| 0| x: center.x, 1090| 0| y: -center.y) 1091| 0| viewPortHandler.refresh(newMatrix: matrix, chart: self, invalidate: false) 1092| 0| } 1093| | 1094| | /// Zooms by the specified scale factor to the specified values on the specified axis. 1095| | /// 1096| | /// - Parameters: 1097| | /// - scaleX: 1098| | /// - scaleY: 1099| | /// - xValue: 1100| | /// - yValue: 1101| | /// - axis: which axis should be used as a reference for the y-axis 1102| | /// - duration: the duration of the animation in seconds 1103| | /// - easing: 1104| | @objc open func zoomAndCenterViewAnimated( 1105| | scaleX: CGFloat, 1106| | scaleY: CGFloat, 1107| | xValue: Double, 1108| | yValue: Double, 1109| | axis: YAxis.AxisDependency, 1110| | duration: TimeInterval, 1111| | easing: ChartEasingFunctionBlock?) 1112| 0| { 1113| 0| let origin = valueForTouchPoint( 1114| 0| point: CGPoint(x: viewPortHandler.contentLeft, y: viewPortHandler.contentTop), 1115| 0| axis: axis) 1116| 0| 1117| 0| let job = AnimatedZoomViewJob( 1118| 0| viewPortHandler: viewPortHandler, 1119| 0| transformer: getTransformer(forAxis: axis), 1120| 0| view: self, 1121| 0| yAxis: getAxis(axis), 1122| 0| xAxisRange: _xAxis.axisRange, 1123| 0| scaleX: scaleX, 1124| 0| scaleY: scaleY, 1125| 0| xOrigin: viewPortHandler.scaleX, 1126| 0| yOrigin: viewPortHandler.scaleY, 1127| 0| zoomCenterX: CGFloat(xValue), 1128| 0| zoomCenterY: CGFloat(yValue), 1129| 0| zoomOriginX: origin.x, 1130| 0| zoomOriginY: origin.y, 1131| 0| duration: duration, 1132| 0| easing: easing) 1133| 0| 1134| 0| addViewportJob(job) 1135| 0| } 1136| | 1137| | /// Zooms by the specified scale factor to the specified values on the specified axis. 1138| | /// 1139| | /// - Parameters: 1140| | /// - scaleX: 1141| | /// - scaleY: 1142| | /// - xValue: 1143| | /// - yValue: 1144| | /// - axis: which axis should be used as a reference for the y-axis 1145| | /// - duration: the duration of the animation in seconds 1146| | /// - easing: 1147| | @objc open func zoomAndCenterViewAnimated( 1148| | scaleX: CGFloat, 1149| | scaleY: CGFloat, 1150| | xValue: Double, 1151| | yValue: Double, 1152| | axis: YAxis.AxisDependency, 1153| | duration: TimeInterval, 1154| | easingOption: ChartEasingOption) 1155| 0| { 1156| 0| zoomAndCenterViewAnimated(scaleX: scaleX, scaleY: scaleY, xValue: xValue, yValue: yValue, axis: axis, duration: duration, easing: easingFunctionFromOption(easingOption)) 1157| 0| } 1158| | 1159| | /// Zooms by the specified scale factor to the specified values on the specified axis. 1160| | /// 1161| | /// - Parameters: 1162| | /// - scaleX: 1163| | /// - scaleY: 1164| | /// - xValue: 1165| | /// - yValue: 1166| | /// - axis: which axis should be used as a reference for the y-axis 1167| | /// - duration: the duration of the animation in seconds 1168| | /// - easing: 1169| | @objc open func zoomAndCenterViewAnimated( 1170| | scaleX: CGFloat, 1171| | scaleY: CGFloat, 1172| | xValue: Double, 1173| | yValue: Double, 1174| | axis: YAxis.AxisDependency, 1175| | duration: TimeInterval) 1176| 0| { 1177| 0| zoomAndCenterViewAnimated(scaleX: scaleX, scaleY: scaleY, xValue: xValue, yValue: yValue, axis: axis, duration: duration, easingOption: .easeInOutSine) 1178| 0| } 1179| | 1180| | /// Resets all zooming and dragging and makes the chart fit exactly it's bounds. 1181| | @objc open func fitScreen() 1182| 0| { 1183| 0| let matrix = _viewPortHandler.fitScreen() 1184| 0| _viewPortHandler.refresh(newMatrix: matrix, chart: self, invalidate: false) 1185| 0| 1186| 0| calculateOffsets() 1187| 0| setNeedsDisplay() 1188| 0| } 1189| | 1190| | /// Sets the minimum scale value to which can be zoomed out. 1 = fitScreen 1191| | @objc open func setScaleMinima(_ scaleX: CGFloat, scaleY: CGFloat) 1192| 0| { 1193| 0| _viewPortHandler.setMinimumScaleX(scaleX) 1194| 0| _viewPortHandler.setMinimumScaleY(scaleY) 1195| 0| } 1196| | 1197| | @objc open var visibleXRange: Double 1198| 0| { 1199| 0| return abs(highestVisibleX - lowestVisibleX) 1200| 0| } 1201| | 1202| | /// Sets the size of the area (range on the x-axis) that should be maximum visible at once (no further zooming out allowed). 1203| | /// 1204| | /// If this is e.g. set to 10, no more than a range of 10 values on the x-axis can be viewed at once without scrolling. 1205| | /// 1206| | /// If you call this method, chart must have data or it has no effect. 1207| | @objc open func setVisibleXRangeMaximum(_ maxXRange: Double) 1208| 0| { 1209| 0| let xScale = _xAxis.axisRange / maxXRange 1210| 0| _viewPortHandler.setMinimumScaleX(CGFloat(xScale)) 1211| 0| } 1212| | 1213| | /// Sets the size of the area (range on the x-axis) that should be minimum visible at once (no further zooming in allowed). 1214| | /// 1215| | /// If this is e.g. set to 10, no less than a range of 10 values on the x-axis can be viewed at once without scrolling. 1216| | /// 1217| | /// If you call this method, chart must have data or it has no effect. 1218| | @objc open func setVisibleXRangeMinimum(_ minXRange: Double) 1219| 0| { 1220| 0| let xScale = _xAxis.axisRange / minXRange 1221| 0| _viewPortHandler.setMaximumScaleX(CGFloat(xScale)) 1222| 0| } 1223| | 1224| | /// Limits the maximum and minimum value count that can be visible by pinching and zooming. 1225| | /// 1226| | /// e.g. minRange=10, maxRange=100 no less than 10 values and no more that 100 values can be viewed 1227| | /// at once without scrolling. 1228| | /// 1229| | /// If you call this method, chart must have data or it has no effect. 1230| | @objc open func setVisibleXRange(minXRange: Double, maxXRange: Double) 1231| 0| { 1232| 0| let minScale = _xAxis.axisRange / maxXRange 1233| 0| let maxScale = _xAxis.axisRange / minXRange 1234| 0| _viewPortHandler.setMinMaxScaleX( 1235| 0| minScaleX: CGFloat(minScale), 1236| 0| maxScaleX: CGFloat(maxScale)) 1237| 0| } 1238| | 1239| | /// Sets the size of the area (range on the y-axis) that should be maximum visible at once. 1240| | /// 1241| | /// - Parameters: 1242| | /// - yRange: 1243| | /// - axis: - the axis for which this limit should apply 1244| | @objc open func setVisibleYRangeMaximum(_ maxYRange: Double, axis: YAxis.AxisDependency) 1245| 0| { 1246| 0| let yScale = getAxisRange(axis: axis) / maxYRange 1247| 0| _viewPortHandler.setMinimumScaleY(CGFloat(yScale)) 1248| 0| } 1249| | 1250| | /// Sets the size of the area (range on the y-axis) that should be minimum visible at once, no further zooming in possible. 1251| | /// 1252| | /// - Parameters: 1253| | /// - yRange: 1254| | /// - axis: - the axis for which this limit should apply 1255| | @objc open func setVisibleYRangeMinimum(_ minYRange: Double, axis: YAxis.AxisDependency) 1256| 0| { 1257| 0| let yScale = getAxisRange(axis: axis) / minYRange 1258| 0| _viewPortHandler.setMaximumScaleY(CGFloat(yScale)) 1259| 0| } 1260| | 1261| | /// Limits the maximum and minimum y range that can be visible by pinching and zooming. 1262| | /// 1263| | /// - Parameters: 1264| | /// - minYRange: 1265| | /// - maxYRange: 1266| | /// - axis: 1267| | @objc open func setVisibleYRange(minYRange: Double, maxYRange: Double, axis: YAxis.AxisDependency) 1268| 0| { 1269| 0| let minScale = getAxisRange(axis: axis) / minYRange 1270| 0| let maxScale = getAxisRange(axis: axis) / maxYRange 1271| 0| _viewPortHandler.setMinMaxScaleY(minScaleY: CGFloat(minScale), maxScaleY: CGFloat(maxScale)) 1272| 0| } 1273| | 1274| | /// Moves the left side of the current viewport to the specified x-value. 1275| | /// This also refreshes the chart by calling setNeedsDisplay(). 1276| | @objc open func moveViewToX(_ xValue: Double) 1277| 0| { 1278| 0| let job = MoveViewJob( 1279| 0| viewPortHandler: viewPortHandler, 1280| 0| xValue: xValue, 1281| 0| yValue: 0.0, 1282| 0| transformer: getTransformer(forAxis: .left), 1283| 0| view: self) 1284| 0| 1285| 0| addViewportJob(job) 1286| 0| } 1287| | 1288| | /// Centers the viewport to the specified y-value on the y-axis. 1289| | /// This also refreshes the chart by calling setNeedsDisplay(). 1290| | /// 1291| | /// - Parameters: 1292| | /// - yValue: 1293| | /// - axis: - which axis should be used as a reference for the y-axis 1294| | @objc open func moveViewToY(_ yValue: Double, axis: YAxis.AxisDependency) 1295| 0| { 1296| 0| let yInView = getAxisRange(axis: axis) / Double(_viewPortHandler.scaleY) 1297| 0| 1298| 0| let job = MoveViewJob( 1299| 0| viewPortHandler: viewPortHandler, 1300| 0| xValue: 0.0, 1301| 0| yValue: yValue + yInView / 2.0, 1302| 0| transformer: getTransformer(forAxis: axis), 1303| 0| view: self) 1304| 0| 1305| 0| addViewportJob(job) 1306| 0| } 1307| | 1308| | /// This will move the left side of the current viewport to the specified x-value on the x-axis, and center the viewport to the specified y-value on the y-axis. 1309| | /// This also refreshes the chart by calling setNeedsDisplay(). 1310| | /// 1311| | /// - Parameters: 1312| | /// - xValue: 1313| | /// - yValue: 1314| | /// - axis: - which axis should be used as a reference for the y-axis 1315| | @objc open func moveViewTo(xValue: Double, yValue: Double, axis: YAxis.AxisDependency) 1316| 0| { 1317| 0| let yInView = getAxisRange(axis: axis) / Double(_viewPortHandler.scaleY) 1318| 0| 1319| 0| let job = MoveViewJob( 1320| 0| viewPortHandler: viewPortHandler, 1321| 0| xValue: xValue, 1322| 0| yValue: yValue + yInView / 2.0, 1323| 0| transformer: getTransformer(forAxis: axis), 1324| 0| view: self) 1325| 0| 1326| 0| addViewportJob(job) 1327| 0| } 1328| | 1329| | /// This will move the left side of the current viewport to the specified x-position and center the viewport to the specified y-position animated. 1330| | /// This also refreshes the chart by calling setNeedsDisplay(). 1331| | /// 1332| | /// - Parameters: 1333| | /// - xValue: 1334| | /// - yValue: 1335| | /// - axis: which axis should be used as a reference for the y-axis 1336| | /// - duration: the duration of the animation in seconds 1337| | /// - easing: 1338| | @objc open func moveViewToAnimated( 1339| | xValue: Double, 1340| | yValue: Double, 1341| | axis: YAxis.AxisDependency, 1342| | duration: TimeInterval, 1343| | easing: ChartEasingFunctionBlock?) 1344| 0| { 1345| 0| let bounds = valueForTouchPoint( 1346| 0| point: CGPoint(x: viewPortHandler.contentLeft, y: viewPortHandler.contentTop), 1347| 0| axis: axis) 1348| 0| 1349| 0| let yInView = getAxisRange(axis: axis) / Double(_viewPortHandler.scaleY) 1350| 0| 1351| 0| let job = AnimatedMoveViewJob( 1352| 0| viewPortHandler: viewPortHandler, 1353| 0| xValue: xValue, 1354| 0| yValue: yValue + yInView / 2.0, 1355| 0| transformer: getTransformer(forAxis: axis), 1356| 0| view: self, 1357| 0| xOrigin: bounds.x, 1358| 0| yOrigin: bounds.y, 1359| 0| duration: duration, 1360| 0| easing: easing) 1361| 0| 1362| 0| addViewportJob(job) 1363| 0| } 1364| | 1365| | /// This will move the left side of the current viewport to the specified x-position and center the viewport to the specified y-position animated. 1366| | /// This also refreshes the chart by calling setNeedsDisplay(). 1367| | /// 1368| | /// - Parameters: 1369| | /// - xValue: 1370| | /// - yValue: 1371| | /// - axis: which axis should be used as a reference for the y-axis 1372| | /// - duration: the duration of the animation in seconds 1373| | /// - easing: 1374| | @objc open func moveViewToAnimated( 1375| | xValue: Double, 1376| | yValue: Double, 1377| | axis: YAxis.AxisDependency, 1378| | duration: TimeInterval, 1379| | easingOption: ChartEasingOption) 1380| 0| { 1381| 0| moveViewToAnimated(xValue: xValue, yValue: yValue, axis: axis, duration: duration, easing: easingFunctionFromOption(easingOption)) 1382| 0| } 1383| | 1384| | /// This will move the left side of the current viewport to the specified x-position and center the viewport to the specified y-position animated. 1385| | /// This also refreshes the chart by calling setNeedsDisplay(). 1386| | /// 1387| | /// - Parameters: 1388| | /// - xValue: 1389| | /// - yValue: 1390| | /// - axis: which axis should be used as a reference for the y-axis 1391| | /// - duration: the duration of the animation in seconds 1392| | /// - easing: 1393| | @objc open func moveViewToAnimated( 1394| | xValue: Double, 1395| | yValue: Double, 1396| | axis: YAxis.AxisDependency, 1397| | duration: TimeInterval) 1398| 0| { 1399| 0| moveViewToAnimated(xValue: xValue, yValue: yValue, axis: axis, duration: duration, easingOption: .easeInOutSine) 1400| 0| } 1401| | 1402| | /// This will move the center of the current viewport to the specified x-value and y-value. 1403| | /// This also refreshes the chart by calling setNeedsDisplay(). 1404| | /// 1405| | /// - Parameters: 1406| | /// - xValue: 1407| | /// - yValue: 1408| | /// - axis: - which axis should be used as a reference for the y-axis 1409| | @objc open func centerViewTo( 1410| | xValue: Double, 1411| | yValue: Double, 1412| | axis: YAxis.AxisDependency) 1413| 0| { 1414| 0| let yInView = getAxisRange(axis: axis) / Double(_viewPortHandler.scaleY) 1415| 0| let xInView = xAxis.axisRange / Double(_viewPortHandler.scaleX) 1416| 0| 1417| 0| let job = MoveViewJob( 1418| 0| viewPortHandler: viewPortHandler, 1419| 0| xValue: xValue - xInView / 2.0, 1420| 0| yValue: yValue + yInView / 2.0, 1421| 0| transformer: getTransformer(forAxis: axis), 1422| 0| view: self) 1423| 0| 1424| 0| addViewportJob(job) 1425| 0| } 1426| | 1427| | /// This will move the center of the current viewport to the specified x-value and y-value animated. 1428| | /// 1429| | /// - Parameters: 1430| | /// - xValue: 1431| | /// - yValue: 1432| | /// - axis: which axis should be used as a reference for the y-axis 1433| | /// - duration: the duration of the animation in seconds 1434| | /// - easing: 1435| | @objc open func centerViewToAnimated( 1436| | xValue: Double, 1437| | yValue: Double, 1438| | axis: YAxis.AxisDependency, 1439| | duration: TimeInterval, 1440| | easing: ChartEasingFunctionBlock?) 1441| 0| { 1442| 0| let bounds = valueForTouchPoint( 1443| 0| point: CGPoint(x: viewPortHandler.contentLeft, y: viewPortHandler.contentTop), 1444| 0| axis: axis) 1445| 0| 1446| 0| let yInView = getAxisRange(axis: axis) / Double(_viewPortHandler.scaleY) 1447| 0| let xInView = xAxis.axisRange / Double(_viewPortHandler.scaleX) 1448| 0| 1449| 0| let job = AnimatedMoveViewJob( 1450| 0| viewPortHandler: viewPortHandler, 1451| 0| xValue: xValue - xInView / 2.0, 1452| 0| yValue: yValue + yInView / 2.0, 1453| 0| transformer: getTransformer(forAxis: axis), 1454| 0| view: self, 1455| 0| xOrigin: bounds.x, 1456| 0| yOrigin: bounds.y, 1457| 0| duration: duration, 1458| 0| easing: easing) 1459| 0| 1460| 0| addViewportJob(job) 1461| 0| } 1462| | 1463| | /// This will move the center of the current viewport to the specified x-value and y-value animated. 1464| | /// 1465| | /// - Parameters: 1466| | /// - xValue: 1467| | /// - yValue: 1468| | /// - axis: which axis should be used as a reference for the y-axis 1469| | /// - duration: the duration of the animation in seconds 1470| | /// - easing: 1471| | @objc open func centerViewToAnimated( 1472| | xValue: Double, 1473| | yValue: Double, 1474| | axis: YAxis.AxisDependency, 1475| | duration: TimeInterval, 1476| | easingOption: ChartEasingOption) 1477| 0| { 1478| 0| centerViewToAnimated(xValue: xValue, yValue: yValue, axis: axis, duration: duration, easing: easingFunctionFromOption(easingOption)) 1479| 0| } 1480| | 1481| | /// This will move the center of the current viewport to the specified x-value and y-value animated. 1482| | /// 1483| | /// - Parameters: 1484| | /// - xValue: 1485| | /// - yValue: 1486| | /// - axis: which axis should be used as a reference for the y-axis 1487| | /// - duration: the duration of the animation in seconds 1488| | /// - easing: 1489| | @objc open func centerViewToAnimated( 1490| | xValue: Double, 1491| | yValue: Double, 1492| | axis: YAxis.AxisDependency, 1493| | duration: TimeInterval) 1494| 0| { 1495| 0| centerViewToAnimated(xValue: xValue, yValue: yValue, axis: axis, duration: duration, easingOption: .easeInOutSine) 1496| 0| } 1497| | 1498| | /// Sets custom offsets for the current `ChartViewPort` (the offsets on the sides of the actual chart window). Setting this will prevent the chart from automatically calculating it's offsets. Use `resetViewPortOffsets()` to undo this. 1499| | /// ONLY USE THIS WHEN YOU KNOW WHAT YOU ARE DOING, else use `setExtraOffsets(...)`. 1500| | @objc open func setViewPortOffsets(left: CGFloat, top: CGFloat, right: CGFloat, bottom: CGFloat) 1501| 0| { 1502| 0| _customViewPortEnabled = true 1503| 0| 1504| 0| if Thread.isMainThread 1505| 0| { 1506| 0| self._viewPortHandler.restrainViewPort(offsetLeft: left, offsetTop: top, offsetRight: right, offsetBottom: bottom) 1507| 0| prepareOffsetMatrix() 1508| 0| prepareValuePxMatrix() 1509| 0| } 1510| 0| else 1511| 0| { 1512| 0| DispatchQueue.main.async(execute: { 1513| 0| self.setViewPortOffsets(left: left, top: top, right: right, bottom: bottom) 1514| 0| }) 1515| 0| } 1516| 0| } 1517| | 1518| | /// Resets all custom offsets set via `setViewPortOffsets(...)` method. Allows the chart to again calculate all offsets automatically. 1519| | @objc open func resetViewPortOffsets() 1520| 0| { 1521| 0| _customViewPortEnabled = false 1522| 0| calculateOffsets() 1523| 0| } 1524| | 1525| | // MARK: - Accessors 1526| | 1527| | /// - Returns: The range of the specified axis. 1528| | @objc open func getAxisRange(axis: YAxis.AxisDependency) -> Double 1529| 0| { 1530| 0| if axis == .left 1531| 0| { 1532| 0| return leftAxis.axisRange 1533| 0| } 1534| 0| else 1535| 0| { 1536| 0| return rightAxis.axisRange 1537| 0| } 1538| 0| } 1539| | 1540| | /// - Returns: The position (in pixels) the provided Entry has inside the chart view 1541| | @objc open func getPosition(entry e: ChartDataEntry, axis: YAxis.AxisDependency) -> CGPoint 1542| 0| { 1543| 0| var vals = CGPoint(x: CGFloat(e.x), y: CGFloat(e.y)) 1544| 0| 1545| 0| getTransformer(forAxis: axis).pointValueToPixel(&vals) 1546| 0| 1547| 0| return vals 1548| 0| } 1549| | 1550| | /// is dragging enabled? (moving the chart with the finger) for the chart (this does not affect scaling). 1551| | @objc open var dragEnabled: Bool 1552| | { 1553| | get 1554| 0| { 1555| 0| return _dragXEnabled || _dragYEnabled 1556| 0| } 1557| | set 1558| 0| { 1559| 0| _dragYEnabled = newValue 1560| 0| _dragXEnabled = newValue 1561| 0| } 1562| | } 1563| | 1564| | /// is dragging enabled? (moving the chart with the finger) for the chart (this does not affect scaling). 1565| | @objc open var isDragEnabled: Bool 1566| 0| { 1567| 0| return dragEnabled 1568| 0| } 1569| | 1570| | /// is dragging on the X axis enabled? 1571| | @objc open var dragXEnabled: Bool 1572| | { 1573| | get 1574| 0| { 1575| 0| return _dragXEnabled 1576| 0| } 1577| | set 1578| 0| { 1579| 0| _dragXEnabled = newValue 1580| 0| } 1581| | } 1582| | 1583| | /// is dragging on the Y axis enabled? 1584| | @objc open var dragYEnabled: Bool 1585| | { 1586| | get 1587| 0| { 1588| 0| return _dragYEnabled 1589| 0| } 1590| | set 1591| 0| { 1592| 0| _dragYEnabled = newValue 1593| 0| } 1594| | } 1595| | 1596| | /// is scaling enabled? (zooming in and out by gesture) for the chart (this does not affect dragging). 1597| | @objc open func setScaleEnabled(_ enabled: Bool) 1598| 0| { 1599| 0| if _scaleXEnabled != enabled || _scaleYEnabled != enabled 1600| 0| { 1601| 0| _scaleXEnabled = enabled 1602| 0| _scaleYEnabled = enabled 1603| 0| #if !os(tvOS) 1604| 0| _pinchGestureRecognizer.isEnabled = _pinchZoomEnabled || _scaleXEnabled || _scaleYEnabled 1605| 0| #endif 1606| 0| } 1607| 0| } 1608| | 1609| | @objc open var scaleXEnabled: Bool 1610| | { 1611| | get 1612| 0| { 1613| 0| return _scaleXEnabled 1614| 0| } 1615| | set 1616| 0| { 1617| 0| if _scaleXEnabled != newValue 1618| 0| { 1619| 0| _scaleXEnabled = newValue 1620| 0| #if !os(tvOS) 1621| 0| _pinchGestureRecognizer.isEnabled = _pinchZoomEnabled || _scaleXEnabled || _scaleYEnabled 1622| 0| #endif 1623| 0| } 1624| 0| } 1625| | } 1626| | 1627| | @objc open var scaleYEnabled: Bool 1628| | { 1629| | get 1630| 0| { 1631| 0| return _scaleYEnabled 1632| 0| } 1633| | set 1634| 0| { 1635| 0| if _scaleYEnabled != newValue 1636| 0| { 1637| 0| _scaleYEnabled = newValue 1638| 0| #if !os(tvOS) 1639| 0| _pinchGestureRecognizer.isEnabled = _pinchZoomEnabled || _scaleXEnabled || _scaleYEnabled 1640| 0| #endif 1641| 0| } 1642| 0| } 1643| | } 1644| | 1645| 0| @objc open var isScaleXEnabled: Bool { return scaleXEnabled } 1646| 0| @objc open var isScaleYEnabled: Bool { return scaleYEnabled } 1647| | 1648| | /// flag that indicates if double tap zoom is enabled or not 1649| | @objc open var doubleTapToZoomEnabled: Bool 1650| | { 1651| | get 1652| 0| { 1653| 0| return _doubleTapToZoomEnabled 1654| 0| } 1655| | set 1656| 0| { 1657| 0| if _doubleTapToZoomEnabled != newValue 1658| 0| { 1659| 0| _doubleTapToZoomEnabled = newValue 1660| 0| _doubleTapGestureRecognizer.isEnabled = _doubleTapToZoomEnabled 1661| 0| } 1662| 0| } 1663| | } 1664| | 1665| | /// **default**: true 1666| | /// `true` if zooming via double-tap is enabled `false` ifnot. 1667| | @objc open var isDoubleTapToZoomEnabled: Bool 1668| 0| { 1669| 0| return doubleTapToZoomEnabled 1670| 0| } 1671| | 1672| | /// flag that indicates if highlighting per dragging over a fully zoomed out chart is enabled 1673| | @objc open var highlightPerDragEnabled = true 1674| | 1675| | /// If set to true, highlighting per dragging over a fully zoomed out chart is enabled 1676| | /// You might want to disable this when using inside a `NSUIScrollView` 1677| | /// 1678| | /// **default**: true 1679| | @objc open var isHighlightPerDragEnabled: Bool 1680| 0| { 1681| 0| return highlightPerDragEnabled 1682| 0| } 1683| | 1684| | /// **default**: true 1685| | /// `true` if drawing the grid background is enabled, `false` ifnot. 1686| | @objc open var isDrawGridBackgroundEnabled: Bool 1687| 0| { 1688| 0| return drawGridBackgroundEnabled 1689| 0| } 1690| | 1691| | /// **default**: false 1692| | /// `true` if drawing the borders rectangle is enabled, `false` ifnot. 1693| | @objc open var isDrawBordersEnabled: Bool 1694| 0| { 1695| 0| return drawBordersEnabled 1696| 0| } 1697| | 1698| | /// - Returns: The x and y values in the chart at the given touch point 1699| | /// (encapsulated in a `CGPoint`). This method transforms pixel coordinates to 1700| | /// coordinates / values in the chart. This is the opposite method to 1701| | /// `getPixelsForValues(...)`. 1702| | @objc open func valueForTouchPoint(point pt: CGPoint, axis: YAxis.AxisDependency) -> CGPoint 1703| 0| { 1704| 0| return getTransformer(forAxis: axis).valueForTouchPoint(pt) 1705| 0| } 1706| | 1707| | /// Transforms the given chart values into pixels. This is the opposite 1708| | /// method to `valueForTouchPoint(...)`. 1709| | @objc open func pixelForValues(x: Double, y: Double, axis: YAxis.AxisDependency) -> CGPoint 1710| 0| { 1711| 0| return getTransformer(forAxis: axis).pixelForValues(x: x, y: y) 1712| 0| } 1713| | 1714| | /// - Returns: The Entry object displayed at the touched position of the chart 1715| | @objc open func getEntryByTouchPoint(point pt: CGPoint) -> ChartDataEntry! 1716| 0| { 1717| 0| if let h = getHighlightByTouchPoint(pt) 1718| 0| { 1719| 0| return _data!.entryForHighlight(h) 1720| 0| } 1721| 0| return nil 1722| 0| } 1723| | 1724| | /// - Returns: The DataSet object displayed at the touched position of the chart 1725| | @objc open func getDataSetByTouchPoint(point pt: CGPoint) -> IBarLineScatterCandleBubbleChartDataSet? 1726| 0| { 1727| 0| let h = getHighlightByTouchPoint(pt) 1728| 0| if h !== nil 1729| 0| { 1730| 0| return _data?.getDataSetByIndex(h!.dataSetIndex) as? IBarLineScatterCandleBubbleChartDataSet 1731| 0| } 1732| 0| return nil 1733| 0| } 1734| | 1735| | /// The current x-scale factor 1736| | @objc open var scaleX: CGFloat 1737| 0| { 1738| 0| if _viewPortHandler === nil 1739| 0| { 1740| 0| return 1.0 1741| 0| } 1742| 0| return _viewPortHandler.scaleX 1743| 0| } 1744| | 1745| | /// The current y-scale factor 1746| | @objc open var scaleY: CGFloat 1747| 0| { 1748| 0| if _viewPortHandler === nil 1749| 0| { 1750| 0| return 1.0 1751| 0| } 1752| 0| return _viewPortHandler.scaleY 1753| 0| } 1754| | 1755| | /// if the chart is fully zoomed out, return true 1756| 0| @objc open var isFullyZoomedOut: Bool { return _viewPortHandler.isFullyZoomedOut } 1757| | 1758| | /// - Returns: The y-axis object to the corresponding AxisDependency. In the 1759| | /// horizontal bar-chart, LEFT == top, RIGHT == BOTTOM 1760| | @objc open func getAxis(_ axis: YAxis.AxisDependency) -> YAxis 1761| 916| { 1762| 916| if axis == .left 1763| 916| { 1764| 816| return leftAxis 1765| 816| } 1766| 100| else 1767| 100| { 1768| 100| return rightAxis 1769| 100| } 1770| 0| } 1771| | 1772| | /// flag that indicates if pinch-zoom is enabled. if true, both x and y axis can be scaled simultaneously with 2 fingers, if false, x and y axis can be scaled separately 1773| | @objc open var pinchZoomEnabled: Bool 1774| | { 1775| | get 1776| 0| { 1777| 0| return _pinchZoomEnabled 1778| 0| } 1779| | set 1780| 0| { 1781| 0| if _pinchZoomEnabled != newValue 1782| 0| { 1783| 0| _pinchZoomEnabled = newValue 1784| 0| #if !os(tvOS) 1785| 0| _pinchGestureRecognizer.isEnabled = _pinchZoomEnabled || _scaleXEnabled || _scaleYEnabled 1786| 0| #endif 1787| 0| } 1788| 0| } 1789| | } 1790| | 1791| | /// **default**: false 1792| | /// `true` if pinch-zoom is enabled, `false` ifnot 1793| 0| @objc open var isPinchZoomEnabled: Bool { return pinchZoomEnabled } 1794| | 1795| | /// Set an offset in dp that allows the user to drag the chart over it's 1796| | /// bounds on the x-axis. 1797| | @objc open func setDragOffsetX(_ offset: CGFloat) 1798| 0| { 1799| 0| _viewPortHandler.setDragOffsetX(offset) 1800| 0| } 1801| | 1802| | /// Set an offset in dp that allows the user to drag the chart over it's 1803| | /// bounds on the y-axis. 1804| | @objc open func setDragOffsetY(_ offset: CGFloat) 1805| 0| { 1806| 0| _viewPortHandler.setDragOffsetY(offset) 1807| 0| } 1808| | 1809| | /// `true` if both drag offsets (x and y) are zero or smaller. 1810| 0| @objc open var hasNoDragOffset: Bool { return _viewPortHandler.hasNoDragOffset } 1811| | 1812| | open override var chartYMax: Double 1813| 0| { 1814| 0| return max(leftAxis._axisMaximum, rightAxis._axisMaximum) 1815| 0| } 1816| | 1817| | open override var chartYMin: Double 1818| 0| { 1819| 0| return min(leftAxis._axisMinimum, rightAxis._axisMinimum) 1820| 0| } 1821| | 1822| | /// `true` if either the left or the right or both axes are inverted. 1823| | @objc open var isAnyAxisInverted: Bool 1824| 0| { 1825| 0| return leftAxis.isInverted || rightAxis.isInverted 1826| 0| } 1827| | 1828| | /// flag that indicates if auto scaling on the y axis is enabled. 1829| | /// if yes, the y axis automatically adjusts to the min and max y values of the current x axis range whenever the viewport changes 1830| | @objc open var autoScaleMinMaxEnabled: Bool 1831| | { 1832| 0| get { return _autoScaleMinMaxEnabled } 1833| 0| set { _autoScaleMinMaxEnabled = newValue } 1834| | } 1835| | 1836| | /// **default**: false 1837| | /// `true` if auto scaling on the y axis is enabled. 1838| 0| @objc open var isAutoScaleMinMaxEnabled : Bool { return autoScaleMinMaxEnabled } 1839| | 1840| | /// Sets a minimum width to the specified y axis. 1841| | @objc open func setYAxisMinWidth(_ axis: YAxis.AxisDependency, width: CGFloat) 1842| 0| { 1843| 0| if axis == .left 1844| 0| { 1845| 0| leftAxis.minWidth = width 1846| 0| } 1847| 0| else 1848| 0| { 1849| 0| rightAxis.minWidth = width 1850| 0| } 1851| 0| } 1852| | 1853| | /// **default**: 0.0 1854| | /// 1855| | /// - Returns: The (custom) minimum width of the specified Y axis. 1856| | @objc open func getYAxisMinWidth(_ axis: YAxis.AxisDependency) -> CGFloat 1857| 0| { 1858| 0| if axis == .left 1859| 0| { 1860| 0| return leftAxis.minWidth 1861| 0| } 1862| 0| else 1863| 0| { 1864| 0| return rightAxis.minWidth 1865| 0| } 1866| 0| } 1867| | /// Sets a maximum width to the specified y axis. 1868| | /// Zero (0.0) means there's no maximum width 1869| | @objc open func setYAxisMaxWidth(_ axis: YAxis.AxisDependency, width: CGFloat) 1870| 0| { 1871| 0| if axis == .left 1872| 0| { 1873| 0| leftAxis.maxWidth = width 1874| 0| } 1875| 0| else 1876| 0| { 1877| 0| rightAxis.maxWidth = width 1878| 0| } 1879| 0| } 1880| | 1881| | /// Zero (0.0) means there's no maximum width 1882| | /// 1883| | /// **default**: 0.0 (no maximum specified) 1884| | /// 1885| | /// - Returns: The (custom) maximum width of the specified Y axis. 1886| | @objc open func getYAxisMaxWidth(_ axis: YAxis.AxisDependency) -> CGFloat 1887| 0| { 1888| 0| if axis == .left 1889| 0| { 1890| 0| return leftAxis.maxWidth 1891| 0| } 1892| 0| else 1893| 0| { 1894| 0| return rightAxis.maxWidth 1895| 0| } 1896| 0| } 1897| | 1898| | /// - Returns the width of the specified y axis. 1899| | @objc open func getYAxisWidth(_ axis: YAxis.AxisDependency) -> CGFloat 1900| 0| { 1901| 0| if axis == .left 1902| 0| { 1903| 0| return leftAxis.requiredSize().width 1904| 0| } 1905| 0| else 1906| 0| { 1907| 0| return rightAxis.requiredSize().width 1908| 0| } 1909| 0| } 1910| | 1911| | // MARK: - BarLineScatterCandleBubbleChartDataProvider 1912| | 1913| | /// - Returns: The Transformer class that contains all matrices and is 1914| | /// responsible for transforming values into pixels on the screen and 1915| | /// backwards. 1916| | open func getTransformer(forAxis axis: YAxis.AxisDependency) -> Transformer 1917| 154| { 1918| 154| if axis == .left 1919| 154| { 1920| 141| return _leftAxisTransformer 1921| 141| } 1922| 13| else 1923| 13| { 1924| 13| return _rightAxisTransformer 1925| 13| } 1926| 0| } 1927| | 1928| | /// the number of maximum visible drawn values on the chart only active when `drawValuesEnabled` is enabled 1929| | open override var maxVisibleCount: Int 1930| | { 1931| | get 1932| 49| { 1933| 49| return _maxVisibleCount 1934| 49| } 1935| | set 1936| 0| { 1937| 0| _maxVisibleCount = newValue 1938| 0| } 1939| | } 1940| | 1941| | open func isInverted(axis: YAxis.AxisDependency) -> Bool 1942| 76| { 1943| 76| return getAxis(axis).isInverted 1944| 76| } 1945| | 1946| | /// The lowest x-index (value on the x-axis) that is still visible on he chart. 1947| | open var lowestVisibleX: Double 1948| 26| { 1949| 26| var pt = CGPoint( 1950| 26| x: viewPortHandler.contentLeft, 1951| 26| y: viewPortHandler.contentBottom) 1952| 26| 1953| 26| getTransformer(forAxis: .left).pixelToValues(&pt) 1954| 26| 1955| 26| return max(xAxis._axisMinimum, Double(pt.x)) 1956| 26| } 1957| | 1958| | /// The highest x-index (value on the x-axis) that is still visible on the chart. 1959| | open var highestVisibleX: Double 1960| 26| { 1961| 26| var pt = CGPoint( 1962| 26| x: viewPortHandler.contentRight, 1963| 26| y: viewPortHandler.contentBottom) 1964| 26| 1965| 26| getTransformer(forAxis: .left).pixelToValues(&pt) 1966| 26| 1967| 26| return min(xAxis._axisMaximum, Double(pt.x)) 1968| 26| } 1969| |} /Users/travis/build/danielgindi/Charts/Source/Charts/Charts/BubbleChartView.swift: 1| |// 2| |// BubbleChartView.swift 3| |// Charts 4| |// 5| |// Bubble chart implementation: 6| |// Copyright 2015 Pierre-Marc Airoldi 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| | 12| |import Foundation 13| |import CoreGraphics 14| | 15| |open class BubbleChartView: BarLineChartViewBase, BubbleChartDataProvider 16| |{ 17| | open override func initialize() 18| 0| { 19| 0| super.initialize() 20| 0| 21| 0| renderer = BubbleChartRenderer(dataProvider: self, animator: _animator, viewPortHandler: _viewPortHandler) 22| 0| } 23| | 24| | // MARK: - BubbleChartDataProvider 25| | 26| 0| open var bubbleData: BubbleChartData? { return _data as? BubbleChartData } 27| |} /Users/travis/build/danielgindi/Charts/Source/Charts/Charts/CandleStickChartView.swift: 1| |// 2| |// CandleStickChartView.swift 3| |// Charts 4| |// 5| |// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda 6| |// A port of MPAndroidChart for iOS 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| | 12| |import Foundation 13| |import CoreGraphics 14| | 15| |/// Financial chart type that draws candle-sticks. 16| |open class CandleStickChartView: BarLineChartViewBase, CandleChartDataProvider 17| |{ 18| | internal override func initialize() 19| 0| { 20| 0| super.initialize() 21| 0| 22| 0| renderer = CandleStickChartRenderer(dataProvider: self, animator: _animator, viewPortHandler: _viewPortHandler) 23| 0| 24| 0| self.xAxis.spaceMin = 0.5 25| 0| self.xAxis.spaceMax = 0.5 26| 0| } 27| | 28| | // MARK: - CandleChartDataProvider 29| | 30| | open var candleData: CandleChartData? 31| 0| { 32| 0| return _data as? CandleChartData 33| 0| } 34| |} /Users/travis/build/danielgindi/Charts/Source/Charts/Charts/ChartViewBase.swift: 1| |// 2| |// ChartViewBase.swift 3| |// Charts 4| |// 5| |// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda 6| |// A port of MPAndroidChart for iOS 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| |// Based on https://github.com/PhilJay/MPAndroidChart/commit/c42b880 12| | 13| |import Foundation 14| |import CoreGraphics 15| | 16| |#if canImport(UIKit) 17| | import UIKit 18| |#endif 19| | 20| |#if canImport(Cocoa) 21| |import Cocoa 22| |#endif 23| | 24| |@objc 25| |public protocol ChartViewDelegate 26| |{ 27| | /// Called when a value has been selected inside the chart. 28| | /// 29| | /// - Parameters: 30| | /// - entry: The selected Entry. 31| | /// - highlight: The corresponding highlight object that contains information about the highlighted position such as dataSetIndex etc. 32| | @objc optional func chartValueSelected(_ chartView: ChartViewBase, entry: ChartDataEntry, highlight: Highlight) 33| | 34| | /// Called when a user stops panning between values on the chart 35| | @objc optional func chartViewDidEndPanning(_ chartView: ChartViewBase) 36| | 37| | // Called when nothing has been selected or an "un-select" has been made. 38| | @objc optional func chartValueNothingSelected(_ chartView: ChartViewBase) 39| | 40| | // Callbacks when the chart is scaled / zoomed via pinch zoom gesture. 41| | @objc optional func chartScaled(_ chartView: ChartViewBase, scaleX: CGFloat, scaleY: CGFloat) 42| | 43| | // Callbacks when the chart is moved / translated via drag gesture. 44| | @objc optional func chartTranslated(_ chartView: ChartViewBase, dX: CGFloat, dY: CGFloat) 45| | 46| | // Callbacks when Animator stops animating 47| | @objc optional func chartView(_ chartView: ChartViewBase, animatorDidStop animator: Animator) 48| |} 49| | 50| |open class ChartViewBase: NSUIView, ChartDataProvider, AnimatorDelegate 51| |{ 52| | // MARK: - Properties 53| | 54| | /// - Returns: The object representing all x-labels, this method can be used to 55| | /// acquire the XAxis object and modify it (e.g. change the position of the 56| | /// labels) 57| | @objc open var xAxis: XAxis 58| 2.42k| { 59| 2.42k| return _xAxis 60| 2.42k| } 61| | 62| | /// The default IValueFormatter that has been determined by the chart considering the provided minimum and maximum values. 63| | internal var _defaultValueFormatter: IValueFormatter? = DefaultValueFormatter(decimals: 0) 64| | 65| | /// object that holds all data that was originally set for the chart, before it was modified or any filtering algorithms had been applied 66| | internal var _data: ChartData? 67| | 68| | /// Flag that indicates if highlighting per tap (touch) is enabled 69| | private var _highlightPerTapEnabled = true 70| | 71| | /// If set to true, chart continues to scroll after touch up 72| | @objc open var dragDecelerationEnabled = true 73| | 74| | /// 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. 75| | /// 1 is an invalid value, and will be converted to 0.999 automatically. 76| | private var _dragDecelerationFrictionCoef: CGFloat = 0.9 77| | 78| | /// if true, units are drawn next to the values in the chart 79| | internal var _drawUnitInChart = false 80| | 81| | /// The object representing the labels on the x-axis 82| | internal var _xAxis: XAxis! 83| | 84| | /// The `Description` object of the chart. 85| | /// This should have been called just "description", but 86| | @objc open var chartDescription: Description? 87| | 88| | /// The legend object containing all data associated with the legend 89| | internal var _legend: Legend! 90| | 91| | /// delegate to receive chart events 92| | @objc open weak var delegate: ChartViewDelegate? 93| | 94| | /// text that is displayed when the chart is empty 95| | @objc open var noDataText = "No chart data available." 96| | 97| | /// Font to be used for the no data text. 98| | @objc open var noDataFont = NSUIFont.systemFont(ofSize: 12) 99| | 100| | /// color of the no data text 101| | @objc open var noDataTextColor: NSUIColor = .labelOrBlack 102| | 103| | /// alignment of the no data text 104| | @objc open var noDataTextAlignment: NSTextAlignment = .left 105| | 106| | internal var _legendRenderer: LegendRenderer! 107| | 108| | /// object responsible for rendering the data 109| | @objc open var renderer: DataRenderer? 110| | 111| | @objc open var highlighter: IHighlighter? 112| | 113| | /// object that manages the bounds and drawing constraints of the chart 114| | internal var _viewPortHandler: ViewPortHandler! 115| | 116| | /// object responsible for animations 117| | internal var _animator: Animator! 118| | 119| | /// flag that indicates if offsets calculation has already been done or not 120| | private var _offsetsCalculated = false 121| | 122| | /// array of Highlight objects that reference the highlighted slices in the chart 123| | internal var _indicesToHighlight = [Highlight]() 124| | 125| | /// `true` if drawing the marker is enabled when tapping on values 126| | /// (use the `marker` property to specify a marker) 127| | @objc open var drawMarkers = true 128| | 129| | /// - Returns: `true` if drawing the marker is enabled when tapping on values 130| | /// (use the `marker` property to specify a marker) 131| 0| @objc open var isDrawMarkersEnabled: Bool { return drawMarkers } 132| | 133| | /// The marker that is displayed when a value is clicked on the chart 134| | @objc open var marker: IMarker? 135| | 136| | private var _interceptTouchEvents = false 137| | 138| | /// An extra offset to be appended to the viewport's top 139| | @objc open var extraTopOffset: CGFloat = 0.0 140| | 141| | /// An extra offset to be appended to the viewport's right 142| | @objc open var extraRightOffset: CGFloat = 0.0 143| | 144| | /// An extra offset to be appended to the viewport's bottom 145| | @objc open var extraBottomOffset: CGFloat = 0.0 146| | 147| | /// An extra offset to be appended to the viewport's left 148| | @objc open var extraLeftOffset: CGFloat = 0.0 149| | 150| | @objc open func setExtraOffsets(left: CGFloat, top: CGFloat, right: CGFloat, bottom: CGFloat) 151| 0| { 152| 0| extraLeftOffset = left 153| 0| extraTopOffset = top 154| 0| extraRightOffset = right 155| 0| extraBottomOffset = bottom 156| 0| } 157| | 158| | // MARK: - Initializers 159| | 160| | public override init(frame: CGRect) 161| 52| { 162| 52| super.init(frame: frame) 163| 52| initialize() 164| 52| } 165| | 166| | public required init?(coder aDecoder: NSCoder) 167| 0| { 168| 0| super.init(coder: aDecoder) 169| 0| initialize() 170| 0| } 171| | 172| | deinit 173| 37| { 174| 37| self.removeObserver(self, forKeyPath: "bounds") 175| 37| self.removeObserver(self, forKeyPath: "frame") 176| 37| } 177| | 178| | internal func initialize() 179| 52| { 180| 52| #if os(iOS) 181| 52| self.backgroundColor = NSUIColor.clear 182| 52| #endif 183| 52| 184| 52| _animator = Animator() 185| 52| _animator.delegate = self 186| 52| 187| 52| _viewPortHandler = ViewPortHandler(width: bounds.size.width, height: bounds.size.height) 188| 52| 189| 52| chartDescription = Description() 190| 52| 191| 52| _legend = Legend() 192| 52| _legendRenderer = LegendRenderer(viewPortHandler: _viewPortHandler, legend: _legend) 193| 52| 194| 52| _xAxis = XAxis() 195| 52| 196| 52| self.addObserver(self, forKeyPath: "bounds", options: .new, context: nil) 197| 52| self.addObserver(self, forKeyPath: "frame", options: .new, context: nil) 198| 52| } 199| | 200| | // MARK: - ChartViewBase 201| | 202| | /// The data for the chart 203| | open var data: ChartData? 204| | { 205| | get 206| 286| { 207| 286| return _data 208| 286| } 209| | set 210| 52| { 211| 52| _data = newValue 212| 52| _offsetsCalculated = false 213| 52| 214| 52| guard let _data = _data else 215| 52| { 216| 0| setNeedsDisplay() 217| 0| return 218| 52| } 219| 52| 220| 52| // calculate how many digits are needed 221| 52| setupDefaultFormatter(min: _data.getYMin(), max: _data.getYMax()) 222| 52| 223| 52| for set in _data.dataSets 224| 55| { 225| 55| if set.needsFormatter || set.valueFormatter === _defaultValueFormatter 226| 55| { 227| 55| set.valueFormatter = _defaultValueFormatter 228| 55| } 229| 55| } 230| 52| 231| 52| // let the chart know there is new data 232| 52| notifyDataSetChanged() 233| 52| } 234| | } 235| | 236| | /// Clears the chart from all data (sets it to null) and refreshes it (by calling setNeedsDisplay()). 237| | @objc open func clear() 238| 0| { 239| 0| _data = nil 240| 0| _offsetsCalculated = false 241| 0| _indicesToHighlight.removeAll() 242| 0| lastHighlighted = nil 243| 0| 244| 0| setNeedsDisplay() 245| 0| } 246| | 247| | /// Removes all DataSets (and thereby Entries) from the chart. Does not set the data object to nil. Also refreshes the chart by calling setNeedsDisplay(). 248| | @objc open func clearValues() 249| 0| { 250| 0| _data?.clearValues() 251| 0| setNeedsDisplay() 252| 0| } 253| | 254| | /// - Returns: `true` if the chart is empty (meaning it's data object is either null or contains no entries). 255| | @objc open func isEmpty() -> Bool 256| 0| { 257| 0| guard let data = _data else { return true } 258| 0| 259| 0| if data.entryCount <= 0 260| 0| { 261| 0| return true 262| 0| } 263| 0| else 264| 0| { 265| 0| return false 266| 0| } 267| 0| } 268| | 269| | /// Lets the chart know its underlying data has changed and should perform all necessary recalculations. 270| | /// It is crucial that this method is called everytime data is changed dynamically. Not calling this method can lead to crashes or unexpected behaviour. 271| | @objc open func notifyDataSetChanged() 272| 0| { 273| 0| fatalError("notifyDataSetChanged() cannot be called on ChartViewBase") 274| 0| } 275| | 276| | /// Calculates the offsets of the chart to the border depending on the position of an eventual legend or depending on the length of the y-axis and x-axis labels and their position 277| | internal func calculateOffsets() 278| 0| { 279| 0| fatalError("calculateOffsets() cannot be called on ChartViewBase") 280| 0| } 281| | 282| | /// calcualtes the y-min and y-max value and the y-delta and x-delta value 283| | internal func calcMinMax() 284| 0| { 285| 0| fatalError("calcMinMax() cannot be called on ChartViewBase") 286| 0| } 287| | 288| | /// calculates the required number of digits for the values that might be drawn in the chart (if enabled), and creates the default value formatter 289| | internal func setupDefaultFormatter(min: Double, max: Double) 290| 52| { 291| 52| // check if a custom formatter is set or not 292| 52| var reference = Double(0.0) 293| 52| 294| 52| if let data = _data , data.entryCount >= 2 295| 52| { 296| 52| reference = fabs(max - min) 297| 52| } 298| 52| else 299| 52| { 300| 0| let absMin = fabs(min) 301| 0| let absMax = fabs(max) 302| 0| reference = absMin > absMax ? absMin : absMax 303| 52| } 304| 52| 305| 52| 306| 52| if _defaultValueFormatter is DefaultValueFormatter 307| 52| { 308| 52| // setup the formatter with a new number of digits 309| 52| let digits = reference.decimalPlaces 310| 52| 311| 52| (_defaultValueFormatter as? DefaultValueFormatter)?.decimals 312| 52| = digits 313| 52| } 314| 52| } 315| | 316| | open override func draw(_ rect: CGRect) 317| 52| { 318| 52| let optionalContext = NSUIGraphicsGetCurrentContext() 319| 52| guard let context = optionalContext else { return } 320| 52| 321| 52| let frame = self.bounds 322| 52| 323| 52| if _data === nil && noDataText.count > 0 324| 52| { 325| 0| context.saveGState() 326| 0| defer { context.restoreGState() } 327| 0| 328| 0| let paragraphStyle = NSMutableParagraphStyle.default.mutableCopy() as! NSMutableParagraphStyle 329| 0| paragraphStyle.minimumLineHeight = noDataFont.lineHeight 330| 0| paragraphStyle.lineBreakMode = .byWordWrapping 331| 0| paragraphStyle.alignment = noDataTextAlignment 332| 0| 333| 0| ChartUtils.drawMultilineText( 334| 0| context: context, 335| 0| text: noDataText, 336| 0| point: CGPoint(x: frame.width / 2.0, y: frame.height / 2.0), 337| 0| attributes: 338| 0| [.font: noDataFont, 339| 0| .foregroundColor: noDataTextColor, 340| 0| .paragraphStyle: paragraphStyle], 341| 0| constrainedToSize: self.bounds.size, 342| 0| anchor: CGPoint(x: 0.5, y: 0.5), 343| 0| angleRadians: 0.0) 344| 0| 345| 0| return 346| 52| } 347| 52| 348| 52| if !_offsetsCalculated 349| 52| { 350| 52| calculateOffsets() 351| 52| _offsetsCalculated = true 352| 52| } 353| 52| } 354| | 355| | /// Draws the description text in the bottom right corner of the chart (per default) 356| | internal func drawDescription(context: CGContext) 357| 52| { 358| 52| // check if description should be drawn 359| 52| guard 360| 52| let description = chartDescription, 361| 52| description.isEnabled, 362| 52| let descriptionText = description.text, 363| 52| descriptionText.count > 0 364| 52| else { return } 365| 0| 366| 0| let position = description.position ?? CGPoint(x: bounds.width - _viewPortHandler.offsetRight - description.xOffset, 367| 0| y: bounds.height - _viewPortHandler.offsetBottom - description.yOffset - description.font.lineHeight) 368| 0| 369| 0| var attrs = [NSAttributedString.Key : Any]() 370| 0| 371| 0| attrs[NSAttributedString.Key.font] = description.font 372| 0| attrs[NSAttributedString.Key.foregroundColor] = description.textColor 373| 0| 374| 0| ChartUtils.drawText( 375| 0| context: context, 376| 0| text: descriptionText, 377| 0| point: position, 378| 0| align: description.textAlign, 379| 0| attributes: attrs) 380| 0| } 381| | 382| | // MARK: - Accessibility 383| | 384| 0| open override func accessibilityChildren() -> [Any]? { 385| 0| return renderer?.accessibleChartElements 386| 0| } 387| | 388| | // MARK: - Highlighting 389| | 390| | /// The array of currently highlighted values. This might an empty if nothing is highlighted. 391| | @objc open var highlighted: [Highlight] 392| 0| { 393| 0| return _indicesToHighlight 394| 0| } 395| | 396| | /// Set this to false to prevent values from being highlighted by tap gesture. 397| | /// Values can still be highlighted via drag or programmatically. 398| | /// **default**: true 399| | @objc open var highlightPerTapEnabled: Bool 400| | { 401| 0| get { return _highlightPerTapEnabled } 402| 0| set { _highlightPerTapEnabled = newValue } 403| | } 404| | 405| | /// `true` if values can be highlighted via tap gesture, `false` ifnot. 406| | @objc open var isHighLightPerTapEnabled: Bool 407| 0| { 408| 0| return highlightPerTapEnabled 409| 0| } 410| | 411| | /// Checks if the highlight array is null, has a length of zero or if the first object is null. 412| | /// 413| | /// - Returns: `true` if there are values to highlight, `false` ifthere are no values to highlight. 414| | @objc open func valuesToHighlight() -> Bool 415| 52| { 416| 52| return !_indicesToHighlight.isEmpty 417| 52| } 418| | 419| | /// Highlights the values at the given indices in the given DataSets. Provide 420| | /// null or an empty array to undo all highlighting. 421| | /// This should be used to programmatically highlight values. 422| | /// This method *will not* call the delegate. 423| | @objc open func highlightValues(_ highs: [Highlight]?) 424| 0| { 425| 0| // set the indices to highlight 426| 0| _indicesToHighlight = highs ?? [Highlight]() 427| 0| 428| 0| if _indicesToHighlight.isEmpty 429| 0| { 430| 0| self.lastHighlighted = nil 431| 0| } 432| 0| else 433| 0| { 434| 0| self.lastHighlighted = _indicesToHighlight[0] 435| 0| } 436| 0| 437| 0| // redraw the chart 438| 0| setNeedsDisplay() 439| 0| } 440| | 441| | /// Highlights any y-value at the given x-value in the given DataSet. 442| | /// Provide -1 as the dataSetIndex to undo all highlighting. 443| | /// This method will call the delegate. 444| | /// 445| | /// - Parameters: 446| | /// - x: The x-value to highlight 447| | /// - dataSetIndex: The dataset index to search in 448| | /// - dataIndex: The data index to search in (only used in CombinedChartView currently) 449| | @objc open func highlightValue(x: Double, dataSetIndex: Int, dataIndex: Int = -1) 450| 0| { 451| 0| highlightValue(x: x, dataSetIndex: dataSetIndex, dataIndex: dataIndex, callDelegate: true) 452| 0| } 453| | 454| | /// Highlights the value at the given x-value and y-value in the given DataSet. 455| | /// Provide -1 as the dataSetIndex to undo all highlighting. 456| | /// This method will call the delegate. 457| | /// 458| | /// - Parameters: 459| | /// - x: The x-value to highlight 460| | /// - y: The y-value to highlight. Supply `NaN` for "any" 461| | /// - dataSetIndex: The dataset index to search in 462| | /// - dataIndex: The data index to search in (only used in CombinedChartView currently) 463| | @objc open func highlightValue(x: Double, y: Double, dataSetIndex: Int, dataIndex: Int = -1) 464| 0| { 465| 0| highlightValue(x: x, y: y, dataSetIndex: dataSetIndex, dataIndex: dataIndex, callDelegate: true) 466| 0| } 467| | 468| | /// Highlights any y-value at the given x-value in the given DataSet. 469| | /// Provide -1 as the dataSetIndex to undo all highlighting. 470| | /// 471| | /// - Parameters: 472| | /// - x: The x-value to highlight 473| | /// - dataSetIndex: The dataset index to search in 474| | /// - dataIndex: The data index to search in (only used in CombinedChartView currently) 475| | /// - callDelegate: Should the delegate be called for this change 476| | @objc open func highlightValue(x: Double, dataSetIndex: Int, dataIndex: Int = -1, callDelegate: Bool) 477| 2| { 478| 2| highlightValue(x: x, y: .nan, dataSetIndex: dataSetIndex, dataIndex: dataIndex, callDelegate: callDelegate) 479| 2| } 480| | 481| | /// Highlights the value at the given x-value and y-value in the given DataSet. 482| | /// Provide -1 as the dataSetIndex to undo all highlighting. 483| | /// 484| | /// - Parameters: 485| | /// - x: The x-value to highlight 486| | /// - y: The y-value to highlight. Supply `NaN` for "any" 487| | /// - dataSetIndex: The dataset index to search in 488| | /// - dataIndex: The data index to search in (only used in CombinedChartView currently) 489| | /// - callDelegate: Should the delegate be called for this change 490| | @objc open func highlightValue(x: Double, y: Double, dataSetIndex: Int, dataIndex: Int = -1, callDelegate: Bool) 491| 2| { 492| 2| guard let data = _data else 493| 2| { 494| 0| Swift.print("Value not highlighted because data is nil") 495| 0| return 496| 2| } 497| 2| 498| 2| if dataSetIndex < 0 || dataSetIndex >= data.dataSetCount 499| 2| { 500| 0| highlightValue(nil, callDelegate: callDelegate) 501| 2| } 502| 2| else 503| 2| { 504| 2| highlightValue(Highlight(x: x, y: y, dataSetIndex: dataSetIndex, dataIndex: dataIndex), callDelegate: callDelegate) 505| 2| } 506| 2| } 507| | 508| | /// Highlights the values represented by the provided Highlight object 509| | /// This method *will not* call the delegate. 510| | /// 511| | /// - Parameters: 512| | /// - highlight: contains information about which entry should be highlighted 513| | @objc open func highlightValue(_ highlight: Highlight?) 514| 0| { 515| 0| highlightValue(highlight, callDelegate: false) 516| 0| } 517| | 518| | /// Highlights the value selected by touch gesture. 519| | @objc open func highlightValue(_ highlight: Highlight?, callDelegate: Bool) 520| 2| { 521| 2| var entry: ChartDataEntry? 522| 2| var h = highlight 523| 2| 524| 2| if h == nil 525| 2| { 526| 0| self.lastHighlighted = nil 527| 0| _indicesToHighlight.removeAll(keepingCapacity: false) 528| 2| } 529| 2| else 530| 2| { 531| 2| // set the indices to highlight 532| 2| entry = _data?.entryForHighlight(h!) 533| 2| if entry == nil 534| 2| { 535| 0| h = nil 536| 0| _indicesToHighlight.removeAll(keepingCapacity: false) 537| 2| } 538| 2| else 539| 2| { 540| 2| _indicesToHighlight = [h!] 541| 2| } 542| 2| } 543| 2| 544| 2| if callDelegate, let delegate = delegate 545| 2| { 546| 0| if let h = h 547| 0| { 548| 0| // notify the listener 549| 0| delegate.chartValueSelected?(self, entry: entry!, highlight: h) 550| 0| } 551| 0| else 552| 0| { 553| 0| delegate.chartValueNothingSelected?(self) 554| 0| } 555| 2| } 556| 2| 557| 2| // redraw the chart 558| 2| setNeedsDisplay() 559| 2| } 560| | 561| | /// - Returns: The Highlight object (contains x-index and DataSet index) of the 562| | /// selected value at the given touch point inside the Line-, Scatter-, or 563| | /// CandleStick-Chart. 564| | @objc open func getHighlightByTouchPoint(_ pt: CGPoint) -> Highlight? 565| 0| { 566| 0| if _data === nil 567| 0| { 568| 0| Swift.print("Can't select by touch. No data set.") 569| 0| return nil 570| 0| } 571| 0| 572| 0| return self.highlighter?.getHighlight(x: pt.x, y: pt.y) 573| 0| } 574| | 575| | /// The last value that was highlighted via touch. 576| | @objc open var lastHighlighted: Highlight? 577| | 578| | // MARK: - Markers 579| | 580| | /// draws all MarkerViews on the highlighted positions 581| | internal func drawMarkers(context: CGContext) 582| 49| { 583| 49| // if there is no marker view or drawing marker is disabled 584| 49| guard 585| 49| let marker = marker 586| 49| , isDrawMarkersEnabled && 587| 49| valuesToHighlight() 588| 49| else { return } 589| 0| 590| 0| for i in 0 ..< _indicesToHighlight.count 591| 0| { 592| 0| let highlight = _indicesToHighlight[i] 593| 0| 594| 0| guard let 595| 0| set = data?.getDataSetByIndex(highlight.dataSetIndex), 596| 0| let e = _data?.entryForHighlight(highlight) 597| 0| else { continue } 598| 0| 599| 0| let entryIndex = set.entryIndex(entry: e) 600| 0| if entryIndex > Int(Double(set.entryCount) * _animator.phaseX) 601| 0| { 602| 0| continue 603| 0| } 604| 0| 605| 0| let pos = getMarkerPosition(highlight: highlight) 606| 0| 607| 0| // check bounds 608| 0| if !_viewPortHandler.isInBounds(x: pos.x, y: pos.y) 609| 0| { 610| 0| continue 611| 0| } 612| 0| 613| 0| // callbacks to update the content 614| 0| marker.refreshContent(entry: e, highlight: highlight) 615| 0| 616| 0| // draw the marker 617| 0| marker.draw(context: context, point: pos) 618| 0| } 619| 0| } 620| | 621| | /// - Returns: The actual position in pixels of the MarkerView for the given Entry in the given DataSet. 622| | @objc open func getMarkerPosition(highlight: Highlight) -> CGPoint 623| 0| { 624| 0| return CGPoint(x: highlight.drawX, y: highlight.drawY) 625| 0| } 626| | 627| | // MARK: - Animation 628| | 629| | /// The animator responsible for animating chart values. 630| | @objc open var chartAnimator: Animator! 631| 0| { 632| 0| return _animator 633| 0| } 634| | 635| | /// Animates the drawing / rendering of the chart on both x- and y-axis with the specified animation time. 636| | /// If `animate(...)` is called, no further calling of `invalidate()` is necessary to refresh the chart. 637| | /// 638| | /// - Parameters: 639| | /// - xAxisDuration: duration for animating the x axis 640| | /// - yAxisDuration: duration for animating the y axis 641| | /// - easingX: an easing function for the animation on the x axis 642| | /// - easingY: an easing function for the animation on the y axis 643| | @objc open func animate(xAxisDuration: TimeInterval, yAxisDuration: TimeInterval, easingX: ChartEasingFunctionBlock?, easingY: ChartEasingFunctionBlock?) 644| 0| { 645| 0| _animator.animate(xAxisDuration: xAxisDuration, yAxisDuration: yAxisDuration, easingX: easingX, easingY: easingY) 646| 0| } 647| | 648| | /// Animates the drawing / rendering of the chart on both x- and y-axis with the specified animation time. 649| | /// If `animate(...)` is called, no further calling of `invalidate()` is necessary to refresh the chart. 650| | /// 651| | /// - Parameters: 652| | /// - xAxisDuration: duration for animating the x axis 653| | /// - yAxisDuration: duration for animating the y axis 654| | /// - easingOptionX: the easing function for the animation on the x axis 655| | /// - easingOptionY: the easing function for the animation on the y axis 656| | @objc open func animate(xAxisDuration: TimeInterval, yAxisDuration: TimeInterval, easingOptionX: ChartEasingOption, easingOptionY: ChartEasingOption) 657| 0| { 658| 0| _animator.animate(xAxisDuration: xAxisDuration, yAxisDuration: yAxisDuration, easingOptionX: easingOptionX, easingOptionY: easingOptionY) 659| 0| } 660| | 661| | /// Animates the drawing / rendering of the chart on both x- and y-axis with the specified animation time. 662| | /// If `animate(...)` is called, no further calling of `invalidate()` is necessary to refresh the chart. 663| | /// 664| | /// - Parameters: 665| | /// - xAxisDuration: duration for animating the x axis 666| | /// - yAxisDuration: duration for animating the y axis 667| | /// - easing: an easing function for the animation 668| | @objc open func animate(xAxisDuration: TimeInterval, yAxisDuration: TimeInterval, easing: ChartEasingFunctionBlock?) 669| 0| { 670| 0| _animator.animate(xAxisDuration: xAxisDuration, yAxisDuration: yAxisDuration, easing: easing) 671| 0| } 672| | 673| | /// Animates the drawing / rendering of the chart on both x- and y-axis with the specified animation time. 674| | /// If `animate(...)` is called, no further calling of `invalidate()` is necessary to refresh the chart. 675| | /// 676| | /// - Parameters: 677| | /// - xAxisDuration: duration for animating the x axis 678| | /// - yAxisDuration: duration for animating the y axis 679| | /// - easingOption: the easing function for the animation 680| | @objc open func animate(xAxisDuration: TimeInterval, yAxisDuration: TimeInterval, easingOption: ChartEasingOption) 681| 0| { 682| 0| _animator.animate(xAxisDuration: xAxisDuration, yAxisDuration: yAxisDuration, easingOption: easingOption) 683| 0| } 684| | 685| | /// Animates the drawing / rendering of the chart on both x- and y-axis with the specified animation time. 686| | /// If `animate(...)` is called, no further calling of `invalidate()` is necessary to refresh the chart. 687| | /// 688| | /// - Parameters: 689| | /// - xAxisDuration: duration for animating the x axis 690| | /// - yAxisDuration: duration for animating the y axis 691| | @objc open func animate(xAxisDuration: TimeInterval, yAxisDuration: TimeInterval) 692| 0| { 693| 0| _animator.animate(xAxisDuration: xAxisDuration, yAxisDuration: yAxisDuration) 694| 0| } 695| | 696| | /// Animates the drawing / rendering of the chart the x-axis with the specified animation time. 697| | /// If `animate(...)` is called, no further calling of `invalidate()` is necessary to refresh the chart. 698| | /// 699| | /// - Parameters: 700| | /// - xAxisDuration: duration for animating the x axis 701| | /// - easing: an easing function for the animation 702| | @objc open func animate(xAxisDuration: TimeInterval, easing: ChartEasingFunctionBlock?) 703| 0| { 704| 0| _animator.animate(xAxisDuration: xAxisDuration, easing: easing) 705| 0| } 706| | 707| | /// Animates the drawing / rendering of the chart the x-axis with the specified animation time. 708| | /// If `animate(...)` is called, no further calling of `invalidate()` is necessary to refresh the chart. 709| | /// 710| | /// - Parameters: 711| | /// - xAxisDuration: duration for animating the x axis 712| | /// - easingOption: the easing function for the animation 713| | @objc open func animate(xAxisDuration: TimeInterval, easingOption: ChartEasingOption) 714| 0| { 715| 0| _animator.animate(xAxisDuration: xAxisDuration, easingOption: easingOption) 716| 0| } 717| | 718| | /// Animates the drawing / rendering of the chart the x-axis with the specified animation time. 719| | /// If `animate(...)` is called, no further calling of `invalidate()` is necessary to refresh the chart. 720| | /// 721| | /// - Parameters: 722| | /// - xAxisDuration: duration for animating the x axis 723| | @objc open func animate(xAxisDuration: TimeInterval) 724| 0| { 725| 0| _animator.animate(xAxisDuration: xAxisDuration) 726| 0| } 727| | 728| | /// Animates the drawing / rendering of the chart the y-axis with the specified animation time. 729| | /// If `animate(...)` is called, no further calling of `invalidate()` is necessary to refresh the chart. 730| | /// 731| | /// - Parameters: 732| | /// - yAxisDuration: duration for animating the y axis 733| | /// - easing: an easing function for the animation 734| | @objc open func animate(yAxisDuration: TimeInterval, easing: ChartEasingFunctionBlock?) 735| 0| { 736| 0| _animator.animate(yAxisDuration: yAxisDuration, easing: easing) 737| 0| } 738| | 739| | /// Animates the drawing / rendering of the chart the y-axis with the specified animation time. 740| | /// If `animate(...)` is called, no further calling of `invalidate()` is necessary to refresh the chart. 741| | /// 742| | /// - Parameters: 743| | /// - yAxisDuration: duration for animating the y axis 744| | /// - easingOption: the easing function for the animation 745| | @objc open func animate(yAxisDuration: TimeInterval, easingOption: ChartEasingOption) 746| 0| { 747| 0| _animator.animate(yAxisDuration: yAxisDuration, easingOption: easingOption) 748| 0| } 749| | 750| | /// Animates the drawing / rendering of the chart the y-axis with the specified animation time. 751| | /// If `animate(...)` is called, no further calling of `invalidate()` is necessary to refresh the chart. 752| | /// 753| | /// - Parameters: 754| | /// - yAxisDuration: duration for animating the y axis 755| | @objc open func animate(yAxisDuration: TimeInterval) 756| 0| { 757| 0| _animator.animate(yAxisDuration: yAxisDuration) 758| 0| } 759| | 760| | // MARK: - Accessors 761| | 762| | /// The current y-max value across all DataSets 763| | open var chartYMax: Double 764| 0| { 765| 0| return _data?.yMax ?? 0.0 766| 0| } 767| | 768| | /// The current y-min value across all DataSets 769| | open var chartYMin: Double 770| 0| { 771| 0| return _data?.yMin ?? 0.0 772| 0| } 773| | 774| | open var chartXMax: Double 775| 0| { 776| 0| return _xAxis._axisMaximum 777| 0| } 778| | 779| | open var chartXMin: Double 780| 0| { 781| 0| return _xAxis._axisMinimum 782| 0| } 783| | 784| | open var xRange: Double 785| 0| { 786| 0| return _xAxis.axisRange 787| 0| } 788| | 789| | /// - 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)* 790| | /// The center point of the chart (the whole View) in pixels. 791| | @objc open var midPoint: CGPoint 792| 0| { 793| 0| let bounds = self.bounds 794| 0| return CGPoint(x: bounds.origin.x + bounds.size.width / 2.0, y: bounds.origin.y + bounds.size.height / 2.0) 795| 0| } 796| | 797| | /// The center of the chart taking offsets under consideration. (returns the center of the content rectangle) 798| | open var centerOffsets: CGPoint 799| 12| { 800| 12| return _viewPortHandler.contentCenter 801| 12| } 802| | 803| | /// 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. 804| | @objc open var legend: Legend 805| 0| { 806| 0| return _legend 807| 0| } 808| | 809| | /// The renderer object responsible for rendering / drawing the Legend. 810| | @objc open var legendRenderer: LegendRenderer! 811| 91| { 812| 91| return _legendRenderer 813| 91| } 814| | 815| | /// The rectangle that defines the borders of the chart-value surface (into which the actual values are drawn). 816| | @objc open var contentRect: CGRect 817| 0| { 818| 0| return _viewPortHandler.contentRect 819| 0| } 820| | 821| | /// - Returns: The ViewPortHandler of the chart that is responsible for the 822| | /// content area of the chart and its offsets and dimensions. 823| | @objc open var viewPortHandler: ViewPortHandler! 824| 104| { 825| 104| return _viewPortHandler 826| 104| } 827| | 828| | /// - Returns: The bitmap that represents the chart. 829| | @objc open func getChartImage(transparent: Bool) -> NSUIImage? 830| 0| { 831| 0| NSUIGraphicsBeginImageContextWithOptions(bounds.size, isOpaque || !transparent, NSUIScreen.nsuiMain?.nsuiScale ?? 1.0) 832| 0| 833| 0| guard let context = NSUIGraphicsGetCurrentContext() 834| 0| else { return nil } 835| 0| 836| 0| let rect = CGRect(origin: CGPoint(x: 0, y: 0), size: bounds.size) 837| 0| 838| 0| if isOpaque || !transparent 839| 0| { 840| 0| // Background color may be partially transparent, we must fill with white if we want to output an opaque image 841| 0| context.setFillColor(NSUIColor.white.cgColor) 842| 0| context.fill(rect) 843| 0| 844| 0| if let backgroundColor = self.backgroundColor 845| 0| { 846| 0| context.setFillColor(backgroundColor.cgColor) 847| 0| context.fill(rect) 848| 0| } 849| 0| } 850| 0| 851| 0| nsuiLayer?.render(in: context) 852| 0| 853| 0| let image = NSUIGraphicsGetImageFromCurrentImageContext() 854| 0| 855| 0| NSUIGraphicsEndImageContext() 856| 0| 857| 0| return image 858| 0| } 859| | 860| | public enum ImageFormat 861| | { 862| | case jpeg 863| | case png 864| | } 865| | 866| | /// Saves the current chart state with the given name to the given path on 867| | /// the sdcard leaving the path empty "" will put the saved file directly on 868| | /// the SD card chart is saved as a PNG image, example: 869| | /// saveToPath("myfilename", "foldername1/foldername2") 870| | /// 871| | /// - Parameters: 872| | /// - to: path to the image to save 873| | /// - format: the format to save 874| | /// - compressionQuality: compression quality for lossless formats (JPEG) 875| | /// - Returns: `true` if the image was saved successfully 876| | open func save(to path: String, format: ImageFormat, compressionQuality: Double) -> Bool 877| 0| { 878| 0| guard let image = getChartImage(transparent: format != .jpeg) else { return false } 879| 0| 880| 0| let imageData: Data? 881| 0| switch (format) 882| 0| { 883| 0| case .png: imageData = NSUIImagePNGRepresentation(image) 884| 0| case .jpeg: imageData = NSUIImageJPEGRepresentation(image, CGFloat(compressionQuality)) 885| 0| } 886| 0| 887| 0| guard let data = imageData else { return false } 888| 0| 889| 0| do 890| 0| { 891| 0| try data.write(to: URL(fileURLWithPath: path), options: .atomic) 892| 0| } 893| 0| catch 894| 0| { 895| 0| return false 896| 0| } 897| 0| 898| 0| return true 899| 0| } 900| | 901| | internal var _viewportJobs = [ViewPortJob]() 902| | 903| | open override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) 904| 0| { 905| 0| if keyPath == "bounds" || keyPath == "frame" 906| 0| { 907| 0| let bounds = self.bounds 908| 0| 909| 0| if (_viewPortHandler !== nil && 910| 0| (bounds.size.width != _viewPortHandler.chartWidth || 911| 0| bounds.size.height != _viewPortHandler.chartHeight)) 912| 0| { 913| 0| _viewPortHandler.setChartDimens(width: bounds.size.width, height: bounds.size.height) 914| 0| 915| 0| // This may cause the chart view to mutate properties affecting the view port -- lets do this 916| 0| // before we try to run any pending jobs on the view port itself 917| 0| notifyDataSetChanged() 918| 0| 919| 0| // Finish any pending viewport changes 920| 0| while (!_viewportJobs.isEmpty) 921| 0| { 922| 0| let job = _viewportJobs.remove(at: 0) 923| 0| job.doJob() 924| 0| } 925| 0| } 926| 0| } 927| 0| } 928| | 929| | @objc open func removeViewportJob(_ job: ViewPortJob) 930| 0| { 931| 0| if let index = _viewportJobs.firstIndex(where: { $0 === job }) 932| 0| { 933| 0| _viewportJobs.remove(at: index) 934| 0| } 935| 0| } 936| | 937| | @objc open func clearAllViewportJobs() 938| 0| { 939| 0| _viewportJobs.removeAll(keepingCapacity: false) 940| 0| } 941| | 942| | @objc open func addViewportJob(_ job: ViewPortJob) 943| 0| { 944| 0| if _viewPortHandler.hasChartDimens 945| 0| { 946| 0| job.doJob() 947| 0| } 948| 0| else 949| 0| { 950| 0| _viewportJobs.append(job) 951| 0| } 952| 0| } 953| | 954| | /// **default**: true 955| | /// `true` if chart continues to scroll after touch up, `false` ifnot. 956| | @objc open var isDragDecelerationEnabled: Bool 957| 0| { 958| 0| return dragDecelerationEnabled 959| 0| } 960| | 961| | /// 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. 962| | /// 1 is an invalid value, and will be converted to 0.999 automatically. 963| | /// 964| | /// **default**: true 965| | @objc open var dragDecelerationFrictionCoef: CGFloat 966| | { 967| | get 968| 0| { 969| 0| return _dragDecelerationFrictionCoef 970| 0| } 971| | set 972| 0| { 973| 0| var val = newValue 974| 0| if val < 0.0 975| 0| { 976| 0| val = 0.0 977| 0| } 978| 0| if val >= 1.0 979| 0| { 980| 0| val = 0.999 981| 0| } 982| 0| 983| 0| _dragDecelerationFrictionCoef = val 984| 0| } 985| | } 986| | 987| | /// The maximum distance in screen pixels away from an entry causing it to highlight. 988| | /// **default**: 500.0 989| | open var maxHighlightDistance: CGFloat = 500.0 990| | 991| | /// the number of maximum visible drawn values on the chart only active when `drawValuesEnabled` is enabled 992| | open var maxVisibleCount: Int 993| 0| { 994| 0| return Int(INT_MAX) 995| 0| } 996| | 997| | // MARK: - AnimatorDelegate 998| | 999| | open func animatorUpdated(_ chartAnimator: Animator) 1000| 0| { 1001| 0| setNeedsDisplay() 1002| 0| } 1003| | 1004| | open func animatorStopped(_ chartAnimator: Animator) 1005| 0| { 1006| 0| delegate?.chartView?(self, animatorDidStop: chartAnimator) 1007| 0| } 1008| | 1009| | // MARK: - Touches 1010| | 1011| | open override func nsuiTouchesBegan(_ touches: Set, withEvent event: NSUIEvent?) 1012| 0| { 1013| 0| if !_interceptTouchEvents 1014| 0| { 1015| 0| super.nsuiTouchesBegan(touches, withEvent: event) 1016| 0| } 1017| 0| } 1018| | 1019| | open override func nsuiTouchesMoved(_ touches: Set, withEvent event: NSUIEvent?) 1020| 0| { 1021| 0| if !_interceptTouchEvents 1022| 0| { 1023| 0| super.nsuiTouchesMoved(touches, withEvent: event) 1024| 0| } 1025| 0| } 1026| | 1027| | open override func nsuiTouchesEnded(_ touches: Set, withEvent event: NSUIEvent?) 1028| 0| { 1029| 0| if !_interceptTouchEvents 1030| 0| { 1031| 0| super.nsuiTouchesEnded(touches, withEvent: event) 1032| 0| } 1033| 0| } 1034| | 1035| | open override func nsuiTouchesCancelled(_ touches: Set?, withEvent event: NSUIEvent?) 1036| 0| { 1037| 0| if !_interceptTouchEvents 1038| 0| { 1039| 0| super.nsuiTouchesCancelled(touches, withEvent: event) 1040| 0| } 1041| 0| } 1042| |} /Users/travis/build/danielgindi/Charts/Source/Charts/Charts/CombinedChartView.swift: 1| |// 2| |// CombinedChartView.swift 3| |// Charts 4| |// 5| |// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda 6| |// A port of MPAndroidChart for iOS 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| | 12| |import Foundation 13| |import CoreGraphics 14| | 15| |/// This chart class allows the combination of lines, bars, scatter and candle data all displayed in one chart area. 16| |open class CombinedChartView: BarLineChartViewBase, CombinedChartDataProvider 17| |{ 18| | /// the fill-formatter used for determining the position of the fill-line 19| | internal var _fillFormatter: IFillFormatter! 20| | 21| | /// enum that allows to specify the order in which the different data objects for the combined-chart are drawn 22| | @objc(CombinedChartDrawOrder) 23| | public enum DrawOrder: Int 24| | { 25| | case bar 26| | case bubble 27| | case line 28| | case candle 29| | case scatter 30| | } 31| | 32| | open override func initialize() 33| 3| { 34| 3| super.initialize() 35| 3| 36| 3| self.highlighter = CombinedHighlighter(chart: self, barDataProvider: self) 37| 3| 38| 3| // Old default behaviour 39| 3| self.highlightFullBarEnabled = true 40| 3| 41| 3| _fillFormatter = DefaultFillFormatter() 42| 3| 43| 3| renderer = CombinedChartRenderer(chart: self, animator: _animator, viewPortHandler: _viewPortHandler) 44| 3| } 45| | 46| | open override var data: ChartData? 47| | { 48| | get 49| 14| { 50| 14| return super.data 51| 14| } 52| | set 53| 3| { 54| 3| super.data = newValue 55| 3| 56| 3| self.highlighter = CombinedHighlighter(chart: self, barDataProvider: self) 57| 3| 58| 3| (renderer as? CombinedChartRenderer)?.createRenderers() 59| 3| renderer?.initBuffers() 60| 3| } 61| | } 62| | 63| | @objc open var fillFormatter: IFillFormatter 64| | { 65| | get 66| 0| { 67| 0| return _fillFormatter 68| 0| } 69| | set 70| 0| { 71| 0| _fillFormatter = newValue 72| 0| if _fillFormatter == nil 73| 0| { 74| 0| _fillFormatter = DefaultFillFormatter() 75| 0| } 76| 0| } 77| | } 78| | 79| | /// - Returns: The Highlight object (contains x-index and DataSet index) of the selected value at the given touch point inside the CombinedChart. 80| | open override func getHighlightByTouchPoint(_ pt: CGPoint) -> Highlight? 81| 0| { 82| 0| if _data === nil 83| 0| { 84| 0| Swift.print("Can't select by touch. No data set.") 85| 0| return nil 86| 0| } 87| 0| 88| 0| guard let h = self.highlighter?.getHighlight(x: pt.x, y: pt.y) 89| 0| else { return nil } 90| 0| 91| 0| if !isHighlightFullBarEnabled { return h } 92| 0| 93| 0| // For isHighlightFullBarEnabled, remove stackIndex 94| 0| return Highlight( 95| 0| x: h.x, y: h.y, 96| 0| xPx: h.xPx, yPx: h.yPx, 97| 0| dataIndex: h.dataIndex, 98| 0| dataSetIndex: h.dataSetIndex, 99| 0| stackIndex: -1, 100| 0| axis: h.axis) 101| 0| } 102| | 103| | // MARK: - CombinedChartDataProvider 104| | 105| | open var combinedData: CombinedChartData? 106| | { 107| | get 108| 59| { 109| 59| return _data as? CombinedChartData 110| 59| } 111| | } 112| | 113| | // MARK: - LineChartDataProvider 114| | 115| | open var lineData: LineChartData? 116| | { 117| | get 118| 15| { 119| 15| return combinedData?.lineData 120| 15| } 121| | } 122| | 123| | // MARK: - BarChartDataProvider 124| | 125| | open var barData: BarChartData? 126| | { 127| | get 128| 26| { 129| 26| return combinedData?.barData 130| 26| } 131| | } 132| | 133| | // MARK: - ScatterChartDataProvider 134| | 135| | open var scatterData: ScatterChartData? 136| | { 137| | get 138| 6| { 139| 6| return combinedData?.scatterData 140| 6| } 141| | } 142| | 143| | // MARK: - CandleChartDataProvider 144| | 145| | open var candleData: CandleChartData? 146| | { 147| | get 148| 6| { 149| 6| return combinedData?.candleData 150| 6| } 151| | } 152| | 153| | // MARK: - BubbleChartDataProvider 154| | 155| | open var bubbleData: BubbleChartData? 156| | { 157| | get 158| 6| { 159| 6| return combinedData?.bubbleData 160| 6| } 161| | } 162| | 163| | // MARK: - Accessors 164| | 165| | /// if set to true, all values are drawn above their bars, instead of below their top 166| | @objc open var drawValueAboveBarEnabled: Bool 167| | { 168| 0| get { return (renderer as! CombinedChartRenderer).drawValueAboveBarEnabled } 169| 0| set { (renderer as! CombinedChartRenderer).drawValueAboveBarEnabled = newValue } 170| | } 171| | 172| | /// if set to true, a grey area is drawn behind each bar that indicates the maximum value 173| | @objc open var drawBarShadowEnabled: Bool 174| | { 175| 0| get { return (renderer as! CombinedChartRenderer).drawBarShadowEnabled } 176| 0| set { (renderer as! CombinedChartRenderer).drawBarShadowEnabled = newValue } 177| | } 178| | 179| | /// `true` if drawing values above bars is enabled, `false` ifnot 180| 3| open var isDrawValueAboveBarEnabled: Bool { return (renderer as! CombinedChartRenderer).drawValueAboveBarEnabled } 181| | 182| | /// `true` if drawing shadows (maxvalue) for each bar is enabled, `false` ifnot 183| 6| open var isDrawBarShadowEnabled: Bool { return (renderer as! CombinedChartRenderer).drawBarShadowEnabled } 184| | 185| | /// the order in which the provided data objects should be drawn. 186| | /// The earlier you place them in the provided array, the further they will be in the background. 187| | /// e.g. if you provide [DrawOrder.Bar, DrawOrder.Line], the bars will be drawn behind the lines. 188| | @objc open var drawOrder: [Int] 189| | { 190| | get 191| 0| { 192| 0| return (renderer as! CombinedChartRenderer).drawOrder.map { $0.rawValue } 193| 0| } 194| | set 195| 0| { 196| 0| (renderer as! CombinedChartRenderer).drawOrder = newValue.map { DrawOrder(rawValue: $0)! } 197| 0| } 198| | } 199| | 200| | /// Set this to `true` to make the highlight operation full-bar oriented, `false` to make it highlight single values 201| | @objc open var highlightFullBarEnabled: Bool = false 202| | 203| | /// `true` the highlight is be full-bar oriented, `false` ifsingle-value 204| 0| open var isHighlightFullBarEnabled: Bool { return highlightFullBarEnabled } 205| | 206| | // MARK: - ChartViewBase 207| | 208| | /// draws all MarkerViews on the highlighted positions 209| | override func drawMarkers(context: CGContext) 210| 3| { 211| 3| guard 212| 3| let marker = marker, 213| 3| isDrawMarkersEnabled && valuesToHighlight() 214| 3| else { return } 215| 0| 216| 0| for i in 0 ..< _indicesToHighlight.count 217| 0| { 218| 0| let highlight = _indicesToHighlight[i] 219| 0| 220| 0| guard 221| 0| let set = combinedData?.getDataSetByHighlight(highlight), 222| 0| let e = _data?.entryForHighlight(highlight) 223| 0| else { continue } 224| 0| 225| 0| let entryIndex = set.entryIndex(entry: e) 226| 0| if entryIndex > Int(Double(set.entryCount) * _animator.phaseX) 227| 0| { 228| 0| continue 229| 0| } 230| 0| 231| 0| let pos = getMarkerPosition(highlight: highlight) 232| 0| 233| 0| // check bounds 234| 0| if !_viewPortHandler.isInBounds(x: pos.x, y: pos.y) 235| 0| { 236| 0| continue 237| 0| } 238| 0| 239| 0| // callbacks to update the content 240| 0| marker.refreshContent(entry: e, highlight: highlight) 241| 0| 242| 0| // draw the marker 243| 0| marker.draw(context: context, point: pos) 244| 0| } 245| 0| } 246| |} /Users/travis/build/danielgindi/Charts/Source/Charts/Charts/HorizontalBarChartView.swift: 1| |// 2| |// HorizontalBarChartView.swift 3| |// Charts 4| |// 5| |// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda 6| |// A port of MPAndroidChart for iOS 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| | 12| |import Foundation 13| |import CoreGraphics 14| | 15| |/// BarChart with horizontal bar orientation. In this implementation, x- and y-axis are switched. 16| |open class HorizontalBarChartView: BarChartView 17| |{ 18| | internal override func initialize() 19| 6| { 20| 6| super.initialize() 21| 6| 22| 6| _leftAxisTransformer = TransformerHorizontalBarChart(viewPortHandler: _viewPortHandler) 23| 6| _rightAxisTransformer = TransformerHorizontalBarChart(viewPortHandler: _viewPortHandler) 24| 6| 25| 6| renderer = HorizontalBarChartRenderer(dataProvider: self, animator: _animator, viewPortHandler: _viewPortHandler) 26| 6| leftYAxisRenderer = YAxisRendererHorizontalBarChart(viewPortHandler: _viewPortHandler, yAxis: leftAxis, transformer: _leftAxisTransformer) 27| 6| rightYAxisRenderer = YAxisRendererHorizontalBarChart(viewPortHandler: _viewPortHandler, yAxis: rightAxis, transformer: _rightAxisTransformer) 28| 6| xAxisRenderer = XAxisRendererHorizontalBarChart(viewPortHandler: _viewPortHandler, xAxis: _xAxis, transformer: _leftAxisTransformer, chart: self) 29| 6| 30| 6| self.highlighter = HorizontalBarHighlighter(chart: self) 31| 6| } 32| | 33| | internal override func calculateLegendOffsets(offsetLeft: inout CGFloat, offsetTop: inout CGFloat, offsetRight: inout CGFloat, offsetBottom: inout CGFloat) 34| 17| { 35| 17| guard 36| 17| let legend = _legend, 37| 17| legend.isEnabled, 38| 17| !legend.drawInside 39| 17| else { return } 40| 17| 41| 17| // setup offsets for legend 42| 17| switch legend.orientation 43| 17| { 44| 17| case .vertical: 45| 0| switch legend.horizontalAlignment 46| 0| { 47| 0| case .left: 48| 0| offsetLeft += min(legend.neededWidth, _viewPortHandler.chartWidth * legend.maxSizePercent) + legend.xOffset 49| 0| 50| 0| case .right: 51| 0| offsetRight += min(legend.neededWidth, _viewPortHandler.chartWidth * legend.maxSizePercent) + legend.xOffset 52| 0| 53| 0| case .center: 54| 0| 55| 0| switch legend.verticalAlignment 56| 0| { 57| 0| case .top: 58| 0| offsetTop += min(legend.neededHeight, _viewPortHandler.chartHeight * legend.maxSizePercent) + legend.yOffset 59| 0| 60| 0| case .bottom: 61| 0| offsetBottom += min(legend.neededHeight, _viewPortHandler.chartHeight * legend.maxSizePercent) + legend.yOffset 62| 0| 63| 0| default: 64| 0| break 65| 0| } 66| 17| } 67| 17| 68| 17| case .horizontal: 69| 17| switch legend.verticalAlignment 70| 17| { 71| 17| case .top: 72| 0| offsetTop += min(legend.neededHeight, _viewPortHandler.chartHeight * legend.maxSizePercent) + legend.yOffset 73| 0| 74| 0| // left axis equals the top x-axis in a horizontal chart 75| 0| if leftAxis.isEnabled && leftAxis.isDrawLabelsEnabled 76| 0| { 77| 0| offsetTop += leftAxis.getRequiredHeightSpace() 78| 17| } 79| 17| 80| 17| case .bottom: 81| 17| offsetBottom += min(legend.neededHeight, _viewPortHandler.chartHeight * legend.maxSizePercent) + legend.yOffset 82| 17| 83| 17| // right axis equals the bottom x-axis in a horizontal chart 84| 17| if rightAxis.isEnabled && rightAxis.isDrawLabelsEnabled 85| 17| { 86| 17| offsetBottom += rightAxis.getRequiredHeightSpace() 87| 17| } 88| 17| default: 89| 0| break 90| 17| } 91| 17| } 92| 17| } 93| | 94| | internal override func calculateOffsets() 95| 17| { 96| 17| var offsetLeft: CGFloat = 0.0, 97| 17| offsetRight: CGFloat = 0.0, 98| 17| offsetTop: CGFloat = 0.0, 99| 17| offsetBottom: CGFloat = 0.0 100| 17| 101| 17| calculateLegendOffsets(offsetLeft: &offsetLeft, 102| 17| offsetTop: &offsetTop, 103| 17| offsetRight: &offsetRight, 104| 17| offsetBottom: &offsetBottom) 105| 17| 106| 17| // offsets for y-labels 107| 17| if leftAxis.needsOffset 108| 17| { 109| 17| offsetTop += leftAxis.getRequiredHeightSpace() 110| 17| } 111| 17| 112| 17| if rightAxis.needsOffset 113| 17| { 114| 17| offsetBottom += rightAxis.getRequiredHeightSpace() 115| 17| } 116| 17| 117| 17| let xlabelwidth = _xAxis.labelRotatedWidth 118| 17| 119| 17| if _xAxis.isEnabled 120| 17| { 121| 17| // offsets for x-labels 122| 17| if _xAxis.labelPosition == .bottom 123| 17| { 124| 0| offsetLeft += xlabelwidth 125| 17| } 126| 17| else if _xAxis.labelPosition == .top 127| 17| { 128| 17| offsetRight += xlabelwidth 129| 17| } 130| 17| else if _xAxis.labelPosition == .bothSided 131| 17| { 132| 0| offsetLeft += xlabelwidth 133| 0| offsetRight += xlabelwidth 134| 17| } 135| 17| } 136| 17| 137| 17| offsetTop += self.extraTopOffset 138| 17| offsetRight += self.extraRightOffset 139| 17| offsetBottom += self.extraBottomOffset 140| 17| offsetLeft += self.extraLeftOffset 141| 17| 142| 17| _viewPortHandler.restrainViewPort( 143| 17| offsetLeft: max(self.minOffset, offsetLeft), 144| 17| offsetTop: max(self.minOffset, offsetTop), 145| 17| offsetRight: max(self.minOffset, offsetRight), 146| 17| offsetBottom: max(self.minOffset, offsetBottom)) 147| 17| 148| 17| prepareOffsetMatrix() 149| 17| prepareValuePxMatrix() 150| 17| } 151| | 152| | internal override func prepareValuePxMatrix() 153| 17| { 154| 17| _rightAxisTransformer.prepareMatrixValuePx(chartXMin: rightAxis._axisMinimum, deltaX: CGFloat(rightAxis.axisRange), deltaY: CGFloat(_xAxis.axisRange), chartYMin: _xAxis._axisMinimum) 155| 17| _leftAxisTransformer.prepareMatrixValuePx(chartXMin: leftAxis._axisMinimum, deltaX: CGFloat(leftAxis.axisRange), deltaY: CGFloat(_xAxis.axisRange), chartYMin: _xAxis._axisMinimum) 156| 17| } 157| | 158| | open override func getMarkerPosition(highlight: Highlight) -> CGPoint 159| 0| { 160| 0| return CGPoint(x: highlight.drawY, y: highlight.drawX) 161| 0| } 162| | 163| | open override func getBarBounds(entry e: BarChartDataEntry) -> CGRect 164| 0| { 165| 0| guard 166| 0| let data = _data as? BarChartData, 167| 0| let set = data.getDataSetForEntry(e) as? IBarChartDataSet 168| 0| else { return CGRect.null } 169| 0| 170| 0| let y = e.y 171| 0| let x = e.x 172| 0| 173| 0| let barWidth = data.barWidth 174| 0| 175| 0| let top = x - 0.5 + barWidth / 2.0 176| 0| let bottom = x + 0.5 - barWidth / 2.0 177| 0| let left = y >= 0.0 ? y : 0.0 178| 0| let right = y <= 0.0 ? y : 0.0 179| 0| 180| 0| var bounds = CGRect(x: left, y: top, width: right - left, height: bottom - top) 181| 0| 182| 0| getTransformer(forAxis: set.axisDependency).rectValueToPixel(&bounds) 183| 0| 184| 0| return bounds 185| 0| } 186| | 187| | open override func getPosition(entry e: ChartDataEntry, axis: YAxis.AxisDependency) -> CGPoint 188| 0| { 189| 0| var vals = CGPoint(x: CGFloat(e.y), y: CGFloat(e.x)) 190| 0| 191| 0| getTransformer(forAxis: axis).pointValueToPixel(&vals) 192| 0| 193| 0| return vals 194| 0| } 195| | 196| | open override func getHighlightByTouchPoint(_ pt: CGPoint) -> Highlight? 197| 0| { 198| 0| if _data === nil 199| 0| { 200| 0| Swift.print("Can't select by touch. No data set.", terminator: "\n") 201| 0| return nil 202| 0| } 203| 0| 204| 0| return self.highlighter?.getHighlight(x: pt.y, y: pt.x) 205| 0| } 206| | 207| | /// The lowest x-index (value on the x-axis) that is still visible on he chart. 208| | open override var lowestVisibleX: Double 209| 0| { 210| 0| var pt = CGPoint( 211| 0| x: viewPortHandler.contentLeft, 212| 0| y: viewPortHandler.contentBottom) 213| 0| 214| 0| getTransformer(forAxis: .left).pixelToValues(&pt) 215| 0| 216| 0| return max(xAxis._axisMinimum, Double(pt.y)) 217| 0| } 218| | 219| | /// The highest x-index (value on the x-axis) that is still visible on the chart. 220| | open override var highestVisibleX: Double 221| 0| { 222| 0| var pt = CGPoint( 223| 0| x: viewPortHandler.contentLeft, 224| 0| y: viewPortHandler.contentTop) 225| 0| 226| 0| getTransformer(forAxis: .left).pixelToValues(&pt) 227| 0| 228| 0| return min(xAxis._axisMaximum, Double(pt.y)) 229| 0| } 230| | 231| | // MARK: - Viewport 232| | 233| | open override func setVisibleXRangeMaximum(_ maxXRange: Double) 234| 0| { 235| 0| let xScale = xAxis.axisRange / maxXRange 236| 0| viewPortHandler.setMinimumScaleY(CGFloat(xScale)) 237| 0| } 238| | 239| | open override func setVisibleXRangeMinimum(_ minXRange: Double) 240| 0| { 241| 0| let xScale = xAxis.axisRange / minXRange 242| 0| viewPortHandler.setMaximumScaleY(CGFloat(xScale)) 243| 0| } 244| | 245| | open override func setVisibleXRange(minXRange: Double, maxXRange: Double) 246| 0| { 247| 0| let minScale = xAxis.axisRange / minXRange 248| 0| let maxScale = xAxis.axisRange / maxXRange 249| 0| viewPortHandler.setMinMaxScaleY(minScaleY: CGFloat(minScale), maxScaleY: CGFloat(maxScale)) 250| 0| } 251| | 252| | open override func setVisibleYRangeMaximum(_ maxYRange: Double, axis: YAxis.AxisDependency) 253| 0| { 254| 0| let yScale = getAxisRange(axis: axis) / maxYRange 255| 0| viewPortHandler.setMinimumScaleX(CGFloat(yScale)) 256| 0| } 257| | 258| | open override func setVisibleYRangeMinimum(_ minYRange: Double, axis: YAxis.AxisDependency) 259| 0| { 260| 0| let yScale = getAxisRange(axis: axis) / minYRange 261| 0| viewPortHandler.setMaximumScaleX(CGFloat(yScale)) 262| 0| } 263| | 264| | open override func setVisibleYRange(minYRange: Double, maxYRange: Double, axis: YAxis.AxisDependency) 265| 0| { 266| 0| let minScale = getAxisRange(axis: axis) / minYRange 267| 0| let maxScale = getAxisRange(axis: axis) / maxYRange 268| 0| viewPortHandler.setMinMaxScaleX(minScaleX: CGFloat(minScale), maxScaleX: CGFloat(maxScale)) 269| 0| } 270| |} /Users/travis/build/danielgindi/Charts/Source/Charts/Charts/LineChartView.swift: 1| |// 2| |// LineChartView.swift 3| |// Charts 4| |// 5| |// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda 6| |// A port of MPAndroidChart for iOS 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| | 12| |import Foundation 13| |import CoreGraphics 14| | 15| |/// Chart that draws lines, surfaces, circles, ... 16| |open class LineChartView: BarLineChartViewBase, LineChartDataProvider 17| |{ 18| | internal override func initialize() 19| 6| { 20| 6| super.initialize() 21| 6| 22| 6| renderer = LineChartRenderer(dataProvider: self, animator: _animator, viewPortHandler: _viewPortHandler) 23| 6| } 24| | 25| | // MARK: - LineChartDataProvider 26| | 27| 174| open var lineData: LineChartData? { return _data as? LineChartData } 28| |} /Users/travis/build/danielgindi/Charts/Source/Charts/Charts/PieChartView.swift: 1| |// 2| |// PieChartView.swift 3| |// Charts 4| |// 5| |// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda 6| |// A port of MPAndroidChart for iOS 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| | 12| |import Foundation 13| |import CoreGraphics 14| | 15| |#if canImport(UIKit) 16| | import UIKit 17| |#endif 18| | 19| |#if canImport(Cocoa) 20| |import Cocoa 21| |#endif 22| | 23| |/// View that represents a pie chart. Draws cake like slices. 24| |open class PieChartView: PieRadarChartViewBase 25| |{ 26| | /// rect object that represents the bounds of the piechart, needed for drawing the circle 27| | private var _circleBox = CGRect() 28| | 29| | /// flag indicating if entry labels should be drawn or not 30| | private var _drawEntryLabelsEnabled = true 31| | 32| | /// array that holds the width of each pie-slice in degrees 33| | private var _drawAngles = [CGFloat]() 34| | 35| | /// array that holds the absolute angle in degrees of each slice 36| | private var _absoluteAngles = [CGFloat]() 37| | 38| | /// if true, the hole inside the chart will be drawn 39| | private var _drawHoleEnabled = true 40| | 41| | private var _holeColor: NSUIColor? = NSUIColor.white 42| | 43| | /// Sets the color the entry labels are drawn with. 44| | private var _entryLabelColor: NSUIColor? = NSUIColor.white 45| | 46| | /// Sets the font the entry labels are drawn with. 47| | private var _entryLabelFont: NSUIFont? = NSUIFont(name: "HelveticaNeue", size: 13.0) 48| | 49| | /// if true, the hole will see-through to the inner tips of the slices 50| | private var _drawSlicesUnderHoleEnabled = false 51| | 52| | /// if true, the values inside the piechart are drawn as percent values 53| | private var _usePercentValuesEnabled = false 54| | 55| | /// variable for the text that is drawn in the center of the pie-chart 56| | private var _centerAttributedText: NSAttributedString? 57| | 58| | /// the offset on the x- and y-axis the center text has in dp. 59| | private var _centerTextOffset: CGPoint = CGPoint() 60| | 61| | /// indicates the size of the hole in the center of the piechart 62| | /// 63| | /// **default**: `0.5` 64| | private var _holeRadiusPercent = CGFloat(0.5) 65| | 66| | private var _transparentCircleColor: NSUIColor? = NSUIColor(white: 1.0, alpha: 105.0/255.0) 67| | 68| | /// the radius of the transparent circle next to the chart-hole in the center 69| | private var _transparentCircleRadiusPercent = CGFloat(0.55) 70| | 71| | /// if enabled, centertext is drawn 72| | private var _drawCenterTextEnabled = true 73| | 74| | private var _centerTextRadiusPercent: CGFloat = 1.0 75| | 76| | /// maximum angle for this pie 77| | private var _maxAngle: CGFloat = 360.0 78| | 79| | public override init(frame: CGRect) 80| 6| { 81| 6| super.init(frame: frame) 82| 6| } 83| | 84| | public required init?(coder aDecoder: NSCoder) 85| 0| { 86| 0| super.init(coder: aDecoder) 87| 0| } 88| | 89| | internal override func initialize() 90| 6| { 91| 6| super.initialize() 92| 6| 93| 6| renderer = PieChartRenderer(chart: self, animator: _animator, viewPortHandler: _viewPortHandler) 94| 6| _xAxis = nil 95| 6| 96| 6| self.highlighter = PieHighlighter(chart: self) 97| 6| } 98| | 99| | open override func draw(_ rect: CGRect) 100| 6| { 101| 6| super.draw(rect) 102| 6| 103| 6| if _data === nil 104| 6| { 105| 0| return 106| 6| } 107| 6| 108| 6| let optionalContext = NSUIGraphicsGetCurrentContext() 109| 6| guard let context = optionalContext, let renderer = renderer else 110| 6| { 111| 0| return 112| 6| } 113| 6| 114| 6| renderer.drawData(context: context) 115| 6| 116| 6| if (valuesToHighlight()) 117| 6| { 118| 2| renderer.drawHighlighted(context: context, indices: _indicesToHighlight) 119| 6| } 120| 6| 121| 6| renderer.drawExtras(context: context) 122| 6| 123| 6| renderer.drawValues(context: context) 124| 6| 125| 6| legendRenderer.renderLegend(context: context) 126| 6| 127| 6| drawDescription(context: context) 128| 6| 129| 6| drawMarkers(context: context) 130| 6| } 131| | 132| | /// if width is larger than height 133| | private var widthLarger: Bool 134| 0| { 135| 0| return _viewPortHandler.contentRect.orientation == .landscape 136| 0| } 137| | 138| | /// adjusted radius. Use diameter when it's half pie and width is larger 139| | private var adjustedRadius: CGFloat 140| 12| { 141| 12| return maxAngle <= 180 && widthLarger ? diameter : diameter / 2.0 142| 12| } 143| | 144| | /// true centerOffsets considering half pie & width is larger 145| | private func adjustedCenterOffsets() -> CGPoint 146| 12| { 147| 12| var c = self.centerOffsets 148| 12| c.y = maxAngle <= 180 && widthLarger ? c.y + adjustedRadius / 2 : c.y 149| 12| return c 150| 12| } 151| | 152| | internal override func calculateOffsets() 153| 12| { 154| 12| super.calculateOffsets() 155| 12| 156| 12| // prevent nullpointer when no data set 157| 12| if _data === nil 158| 12| { 159| 0| return 160| 12| } 161| 12| 162| 12| let radius = adjustedRadius 163| 12| 164| 12| let c = adjustedCenterOffsets() 165| 12| 166| 12| let shift = (data as? PieChartData)?.dataSet?.selectionShift ?? 0.0 167| 12| 168| 12| // create the circle box that will contain the pie-chart (the bounds of the pie-chart) 169| 12| _circleBox.origin.x = (c.x - radius) + shift 170| 12| _circleBox.origin.y = (c.y - radius) + shift 171| 12| _circleBox.size.width = radius * 2 - shift * 2.0 172| 12| _circleBox.size.height = radius * 2 - shift * 2.0 173| 12| 174| 12| } 175| | 176| | internal override func calcMinMax() 177| 6| { 178| 6| calcAngles() 179| 6| } 180| | 181| | @objc open override func angleForPoint(x: CGFloat, y: CGFloat) -> CGFloat 182| 0| { 183| 0| let c = adjustedCenterOffsets() 184| 0| 185| 0| let tx = Double(x - c.x) 186| 0| let ty = Double(y - c.y) 187| 0| let length = sqrt(tx * tx + ty * ty) 188| 0| let r = acos(ty / length) 189| 0| 190| 0| var angle = r.RAD2DEG 191| 0| 192| 0| if x > c.x 193| 0| { 194| 0| angle = 360.0 - angle 195| 0| } 196| 0| 197| 0| // add 90° because chart starts EAST 198| 0| angle = angle + 90.0 199| 0| 200| 0| // neutralize overflow 201| 0| if angle > 360.0 202| 0| { 203| 0| angle = angle - 360.0 204| 0| } 205| 0| 206| 0| return CGFloat(angle) 207| 0| } 208| | 209| | /// - Returns: The distance of a certain point on the chart to the center of the chart. 210| | @objc open override func distanceToCenter(x: CGFloat, y: CGFloat) -> CGFloat 211| 0| { 212| 0| let c = adjustedCenterOffsets() 213| 0| 214| 0| var dist = CGFloat(0.0) 215| 0| 216| 0| var xDist = CGFloat(0.0) 217| 0| var yDist = CGFloat(0.0) 218| 0| 219| 0| if x > c.x 220| 0| { 221| 0| xDist = x - c.x 222| 0| } 223| 0| else 224| 0| { 225| 0| xDist = c.x - x 226| 0| } 227| 0| 228| 0| if y > c.y 229| 0| { 230| 0| yDist = y - c.y 231| 0| } 232| 0| else 233| 0| { 234| 0| yDist = c.y - y 235| 0| } 236| 0| 237| 0| // pythagoras 238| 0| dist = sqrt(pow(xDist, 2.0) + pow(yDist, 2.0)) 239| 0| 240| 0| return dist 241| 0| } 242| | 243| | open override func getMarkerPosition(highlight: Highlight) -> CGPoint 244| 0| { 245| 0| let center = self.centerCircleBox 246| 0| var r = self.radius 247| 0| 248| 0| var off = r / 10.0 * 3.6 249| 0| 250| 0| if self.isDrawHoleEnabled 251| 0| { 252| 0| off = (r - (r * self.holeRadiusPercent)) / 2.0 253| 0| } 254| 0| 255| 0| r -= off // offset to keep things inside the chart 256| 0| 257| 0| let rotationAngle = self.rotationAngle 258| 0| 259| 0| let entryIndex = Int(highlight.x) 260| 0| 261| 0| // offset needed to center the drawn text in the slice 262| 0| let offset = drawAngles[entryIndex] / 2.0 263| 0| 264| 0| // calculate the text position 265| 0| let x: CGFloat = (r * cos(((rotationAngle + absoluteAngles[entryIndex] - offset) * CGFloat(_animator.phaseY)).DEG2RAD) + center.x) 266| 0| let y: CGFloat = (r * sin(((rotationAngle + absoluteAngles[entryIndex] - offset) * CGFloat(_animator.phaseY)).DEG2RAD) + center.y) 267| 0| 268| 0| return CGPoint(x: x, y: y) 269| 0| } 270| | 271| | /// calculates the needed angles for the chart slices 272| | private func calcAngles() 273| 6| { 274| 6| _drawAngles = [CGFloat]() 275| 6| _absoluteAngles = [CGFloat]() 276| 6| 277| 6| guard let data = _data else { return } 278| 6| 279| 6| let entryCount = data.entryCount 280| 6| 281| 6| _drawAngles.reserveCapacity(entryCount) 282| 6| _absoluteAngles.reserveCapacity(entryCount) 283| 6| 284| 6| let yValueSum = (_data as! PieChartData).yValueSum 285| 6| 286| 6| var cnt = 0 287| 6| 288| 6| for set in data.dataSets 289| 6| { 290| 6| for j in 0 ..< set.entryCount 291| 42| { 292| 42| guard let e = set.entryForIndex(j) else { continue } 293| 42| 294| 42| _drawAngles.append(calcAngle(value: abs(e.y), yValueSum: yValueSum)) 295| 42| 296| 42| if cnt == 0 297| 42| { 298| 6| _absoluteAngles.append(_drawAngles[cnt]) 299| 42| } 300| 42| else 301| 42| { 302| 36| _absoluteAngles.append(_absoluteAngles[cnt - 1] + _drawAngles[cnt]) 303| 42| } 304| 42| 305| 42| cnt += 1 306| 42| } 307| 6| } 308| 6| } 309| | 310| | /// Checks if the given index is set to be highlighted. 311| | @objc open func needsHighlight(index: Int) -> Bool 312| 35| { 313| 35| return _indicesToHighlight.contains { Int($0.x) == index } 314| 35| } 315| | 316| | /// calculates the needed angle for a given value 317| | private func calcAngle(_ value: Double) -> CGFloat 318| 0| { 319| 0| return calcAngle(value: value, yValueSum: (_data as! PieChartData).yValueSum) 320| 0| } 321| | 322| | /// calculates the needed angle for a given value 323| | private func calcAngle(value: Double, yValueSum: Double) -> CGFloat 324| 42| { 325| 42| return CGFloat(value) / CGFloat(yValueSum) * _maxAngle 326| 42| } 327| | 328| | /// This will throw an exception, PieChart has no XAxis object. 329| | open override var xAxis: XAxis 330| 0| { 331| 0| fatalError("PieChart has no XAxis") 332| 0| } 333| | 334| | open override func indexForAngle(_ angle: CGFloat) -> Int 335| 0| { 336| 0| // TODO: Return nil instead of -1 337| 0| // take the current angle of the chart into consideration 338| 0| let a = (angle - self.rotationAngle).normalizedAngle 339| 0| return _absoluteAngles.firstIndex { $0 > a } ?? -1 340| 0| } 341| | 342| | /// - Returns: The index of the DataSet this x-index belongs to. 343| | @objc open func dataSetIndexForIndex(_ xValue: Double) -> Int 344| 0| { 345| 0| // TODO: Return nil instead of -1 346| 0| return _data?.dataSets.firstIndex { 347| 0| $0.entryForXValue(xValue, closestToY: .nan) != nil 348| 0| } ?? -1 349| 0| } 350| | 351| | /// - Returns: An integer array of all the different angles the chart slices 352| | /// have the angles in the returned array determine how much space (of 360°) 353| | /// each slice takes 354| | @objc open var drawAngles: [CGFloat] 355| 14| { 356| 14| return _drawAngles 357| 14| } 358| | 359| | /// - Returns: The absolute angles of the different chart slices (where the 360| | /// slices end) 361| | @objc open var absoluteAngles: [CGFloat] 362| 8| { 363| 8| return _absoluteAngles 364| 8| } 365| | 366| | /// The color for the hole that is drawn in the center of the PieChart (if enabled). 367| | /// 368| | /// - Note: Use holeTransparent with holeColor = nil to make the hole transparent.* 369| | @objc open var holeColor: NSUIColor? 370| | { 371| | get 372| 12| { 373| 12| return _holeColor 374| 12| } 375| | set 376| 0| { 377| 0| _holeColor = newValue 378| 0| setNeedsDisplay() 379| 0| } 380| | } 381| | 382| | /// if true, the hole will see-through to the inner tips of the slices 383| | /// 384| | /// **default**: `false` 385| | @objc open var drawSlicesUnderHoleEnabled: Bool 386| | { 387| | get 388| 13| { 389| 13| return _drawSlicesUnderHoleEnabled 390| 13| } 391| | set 392| 0| { 393| 0| _drawSlicesUnderHoleEnabled = newValue 394| 0| setNeedsDisplay() 395| 0| } 396| | } 397| | 398| | /// `true` if the inner tips of the slices are visible behind the hole, `false` if not. 399| | @objc open var isDrawSlicesUnderHoleEnabled: Bool 400| 0| { 401| 0| return drawSlicesUnderHoleEnabled 402| 0| } 403| | 404| | /// `true` if the hole in the center of the pie-chart is set to be visible, `false` ifnot 405| | @objc open var drawHoleEnabled: Bool 406| | { 407| | get 408| 25| { 409| 25| return _drawHoleEnabled 410| 25| } 411| | set 412| 0| { 413| 0| _drawHoleEnabled = newValue 414| 0| setNeedsDisplay() 415| 0| } 416| | } 417| | 418| | /// `true` if the hole in the center of the pie-chart is set to be visible, `false` ifnot 419| | @objc open var isDrawHoleEnabled: Bool 420| | { 421| | get 422| 0| { 423| 0| return drawHoleEnabled 424| 0| } 425| | } 426| | 427| | /// the text that is displayed in the center of the pie-chart 428| | @objc open var centerText: String? 429| | { 430| | get 431| 0| { 432| 0| return self.centerAttributedText?.string 433| 0| } 434| | set 435| 6| { 436| 6| var attrString: NSMutableAttributedString? 437| 6| if newValue == nil 438| 6| { 439| 0| attrString = nil 440| 6| } 441| 6| else 442| 6| { 443| 6| let paragraphStyle = NSParagraphStyle.default.mutableCopy() as! NSMutableParagraphStyle 444| 6| paragraphStyle.lineBreakMode = .byTruncatingTail 445| 6| paragraphStyle.alignment = .center 446| 6| 447| 6| attrString = NSMutableAttributedString(string: newValue!) 448| 6| attrString?.setAttributes([ 449| 6| .foregroundColor: NSUIColor.labelOrBlack, 450| 6| .font: NSUIFont.systemFont(ofSize: 12.0), 451| 6| .paragraphStyle: paragraphStyle 452| 6| ], range: NSMakeRange(0, attrString!.length)) 453| 6| } 454| 6| self.centerAttributedText = attrString 455| 6| } 456| | } 457| | 458| | /// the text that is displayed in the center of the pie-chart 459| | @objc open var centerAttributedText: NSAttributedString? 460| | { 461| | get 462| 6| { 463| 6| return _centerAttributedText 464| 6| } 465| | set 466| 6| { 467| 6| _centerAttributedText = newValue 468| 6| setNeedsDisplay() 469| 6| } 470| | } 471| | 472| | /// Sets the offset the center text should have from it's original position in dp. Default x = 0, y = 0 473| | @objc open var centerTextOffset: CGPoint 474| | { 475| | get 476| 5| { 477| 5| return _centerTextOffset 478| 5| } 479| | set 480| 0| { 481| 0| _centerTextOffset = newValue 482| 0| setNeedsDisplay() 483| 0| } 484| | } 485| | 486| | /// `true` if drawing the center text is enabled 487| | @objc open var drawCenterTextEnabled: Bool 488| | { 489| | get 490| 6| { 491| 6| return _drawCenterTextEnabled 492| 6| } 493| | set 494| 1| { 495| 1| _drawCenterTextEnabled = newValue 496| 1| setNeedsDisplay() 497| 1| } 498| | } 499| | 500| | /// `true` if drawing the center text is enabled 501| | @objc open var isDrawCenterTextEnabled: Bool 502| | { 503| | get 504| 0| { 505| 0| return drawCenterTextEnabled 506| 0| } 507| | } 508| | 509| | internal override var requiredLegendOffset: CGFloat 510| 12| { 511| 12| return _legend.font.pointSize * 2.0 512| 12| } 513| | 514| | internal override var requiredBaseOffset: CGFloat 515| 60| { 516| 60| return 0.0 517| 60| } 518| | 519| | open override var radius: CGFloat 520| 25| { 521| 25| return _circleBox.width / 2.0 522| 25| } 523| | 524| | /// The circlebox, the boundingbox of the pie-chart slices 525| | @objc open var circleBox: CGRect 526| 0| { 527| 0| return _circleBox 528| 0| } 529| | 530| | /// The center of the circlebox 531| | @objc open var centerCircleBox: CGPoint 532| 25| { 533| 25| return CGPoint(x: _circleBox.midX, y: _circleBox.midY) 534| 25| } 535| | 536| | /// the radius of the hole in the center of the piechart in percent of the maximum radius (max = the radius of the whole chart) 537| | /// 538| | /// **default**: 0.5 (50%) (half the pie) 539| | @objc open var holeRadiusPercent: CGFloat 540| | { 541| | get 542| 31| { 543| 31| return _holeRadiusPercent 544| 31| } 545| | set 546| 0| { 547| 0| _holeRadiusPercent = newValue 548| 0| setNeedsDisplay() 549| 0| } 550| | } 551| | 552| | /// The color that the transparent-circle should have. 553| | /// 554| | /// **default**: `nil` 555| | @objc open var transparentCircleColor: NSUIColor? 556| | { 557| | get 558| 6| { 559| 6| return _transparentCircleColor 560| 6| } 561| | set 562| 0| { 563| 0| _transparentCircleColor = newValue 564| 0| setNeedsDisplay() 565| 0| } 566| | } 567| | 568| | /// the radius of the transparent circle that is drawn next to the hole in the piechart in percent of the maximum radius (max = the radius of the whole chart) 569| | /// 570| | /// **default**: 0.55 (55%) -> means 5% larger than the center-hole by default 571| | @objc open var transparentCircleRadiusPercent: CGFloat 572| | { 573| | get 574| 12| { 575| 12| return _transparentCircleRadiusPercent 576| 12| } 577| | set 578| 0| { 579| 0| _transparentCircleRadiusPercent = newValue 580| 0| setNeedsDisplay() 581| 0| } 582| | } 583| | 584| | /// The color the entry labels are drawn with. 585| | @objc open var entryLabelColor: NSUIColor? 586| | { 587| 42| get { return _entryLabelColor } 588| | set 589| 0| { 590| 0| _entryLabelColor = newValue 591| 0| setNeedsDisplay() 592| 0| } 593| | } 594| | 595| | /// The font the entry labels are drawn with. 596| | @objc open var entryLabelFont: NSUIFont? 597| | { 598| 6| get { return _entryLabelFont } 599| | set 600| 0| { 601| 0| _entryLabelFont = newValue 602| 0| setNeedsDisplay() 603| 0| } 604| | } 605| | 606| | /// Set this to true to draw the enrty labels into the pie slices 607| | @objc open var drawEntryLabelsEnabled: Bool 608| | { 609| | get 610| 6| { 611| 6| return _drawEntryLabelsEnabled 612| 6| } 613| | set 614| 0| { 615| 0| _drawEntryLabelsEnabled = newValue 616| 0| setNeedsDisplay() 617| 0| } 618| | } 619| | 620| | /// `true` if drawing entry labels is enabled, `false` ifnot 621| | @objc open var isDrawEntryLabelsEnabled: Bool 622| | { 623| | get 624| 6| { 625| 6| return drawEntryLabelsEnabled 626| 6| } 627| | } 628| | 629| | /// If this is enabled, values inside the PieChart are drawn in percent and not with their original value. Values provided for the ValueFormatter to format are then provided in percent. 630| | @objc open var usePercentValuesEnabled: Bool 631| | { 632| | get 633| 48| { 634| 48| return _usePercentValuesEnabled 635| 48| } 636| | set 637| 0| { 638| 0| _usePercentValuesEnabled = newValue 639| 0| setNeedsDisplay() 640| 0| } 641| | } 642| | 643| | /// `true` if drawing x-values is enabled, `false` ifnot 644| | @objc open var isUsePercentValuesEnabled: Bool 645| | { 646| | get 647| 0| { 648| 0| return usePercentValuesEnabled 649| 0| } 650| | } 651| | 652| | /// the rectangular radius of the bounding box for the center text, as a percentage of the pie hole 653| | @objc open var centerTextRadiusPercent: CGFloat 654| | { 655| | get 656| 15| { 657| 15| return _centerTextRadiusPercent 658| 15| } 659| | set 660| 0| { 661| 0| _centerTextRadiusPercent = newValue 662| 0| setNeedsDisplay() 663| 0| } 664| | } 665| | 666| | /// The max angle that is used for calculating the pie-circle. 667| | /// 360 means it's a full pie-chart, 180 results in a half-pie-chart. 668| | /// **default**: 360.0 669| | @objc open var maxAngle: CGFloat 670| | { 671| | get 672| 24| { 673| 24| return _maxAngle 674| 24| } 675| | set 676| 0| { 677| 0| _maxAngle = newValue 678| 0| 679| 0| if _maxAngle > 360.0 680| 0| { 681| 0| _maxAngle = 360.0 682| 0| } 683| 0| 684| 0| if _maxAngle < 90.0 685| 0| { 686| 0| _maxAngle = 90.0 687| 0| } 688| 0| } 689| | } 690| |} /Users/travis/build/danielgindi/Charts/Source/Charts/Charts/PieRadarChartViewBase.swift: 1| |// 2| |// PieRadarChartViewBase.swift 3| |// Charts 4| |// 5| |// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda 6| |// A port of MPAndroidChart for iOS 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| | 12| |import Foundation 13| |import CoreGraphics 14| |import QuartzCore 15| | 16| |#if canImport(AppKit) 17| |import AppKit 18| |#endif 19| | 20| | 21| |/// Base class of PieChartView and RadarChartView. 22| |open class PieRadarChartViewBase: ChartViewBase 23| |{ 24| | /// holds the normalized version of the current rotation angle of the chart 25| | private var _rotationAngle = CGFloat(270.0) 26| | 27| | /// holds the raw version of the current rotation angle of the chart 28| | private var _rawRotationAngle = CGFloat(270.0) 29| | 30| | /// flag that indicates if rotation is enabled or not 31| | @objc open var rotationEnabled = true 32| | 33| | /// Sets the minimum offset (padding) around the chart, defaults to 0.0 34| | @objc open var minOffset = CGFloat(0.0) 35| | 36| | /// iOS && OSX only: Enabled multi-touch rotation using two fingers. 37| | private var _rotationWithTwoFingers = false 38| | 39| | private var _tapGestureRecognizer: NSUITapGestureRecognizer! 40| | #if !os(tvOS) 41| | private var _rotationGestureRecognizer: NSUIRotationGestureRecognizer! 42| | #endif 43| | 44| | public override init(frame: CGRect) 45| 6| { 46| 6| super.init(frame: frame) 47| 6| } 48| | 49| | public required init?(coder aDecoder: NSCoder) 50| 0| { 51| 0| super.init(coder: aDecoder) 52| 0| } 53| | 54| | deinit 55| 0| { 56| 0| stopDeceleration() 57| 0| } 58| | 59| | internal override func initialize() 60| 6| { 61| 6| super.initialize() 62| 6| 63| 6| _tapGestureRecognizer = NSUITapGestureRecognizer(target: self, action: #selector(tapGestureRecognized(_:))) 64| 6| 65| 6| self.addGestureRecognizer(_tapGestureRecognizer) 66| 6| 67| 6| #if !os(tvOS) 68| 6| _rotationGestureRecognizer = NSUIRotationGestureRecognizer(target: self, action: #selector(rotationGestureRecognized(_:))) 69| 6| self.addGestureRecognizer(_rotationGestureRecognizer) 70| 6| _rotationGestureRecognizer.isEnabled = rotationWithTwoFingers 71| 6| #endif 72| 6| } 73| | 74| | internal override func calcMinMax() 75| 0| { 76| 0| /*_xAxis.axisRange = Double((_data?.xVals.count ?? 0) - 1)*/ 77| 0| } 78| | 79| | open override var maxVisibleCount: Int 80| | { 81| | get 82| 0| { 83| 0| return data?.entryCount ?? 0 84| 0| } 85| | } 86| | 87| | open override func notifyDataSetChanged() 88| 6| { 89| 6| calcMinMax() 90| 6| 91| 6| if let data = _data , _legend !== nil 92| 6| { 93| 6| legendRenderer.computeLegend(data: data) 94| 6| } 95| 6| 96| 6| calculateOffsets() 97| 6| 98| 6| setNeedsDisplay() 99| 6| } 100| | 101| | internal override func calculateOffsets() 102| 12| { 103| 12| var legendLeft = CGFloat(0.0) 104| 12| var legendRight = CGFloat(0.0) 105| 12| var legendBottom = CGFloat(0.0) 106| 12| var legendTop = CGFloat(0.0) 107| 12| 108| 12| if _legend != nil && _legend.enabled && !_legend.drawInside 109| 12| { 110| 12| let fullLegendWidth = min(_legend.neededWidth, _viewPortHandler.chartWidth * _legend.maxSizePercent) 111| 12| 112| 12| switch _legend.orientation 113| 12| { 114| 12| case .vertical: 115| 0| 116| 0| var xLegendOffset: CGFloat = 0.0 117| 0| 118| 0| if _legend.horizontalAlignment == .left 119| 0| || _legend.horizontalAlignment == .right 120| 0| { 121| 0| if _legend.verticalAlignment == .center 122| 0| { 123| 0| // this is the space between the legend and the chart 124| 0| let spacing = CGFloat(13.0) 125| 0| 126| 0| xLegendOffset = fullLegendWidth + spacing 127| 0| } 128| 0| else 129| 0| { 130| 0| // this is the space between the legend and the chart 131| 0| let spacing = CGFloat(8.0) 132| 0| 133| 0| let legendWidth = fullLegendWidth + spacing 134| 0| let legendHeight = _legend.neededHeight + _legend.textHeightMax 135| 0| 136| 0| let c = self.midPoint 137| 0| 138| 0| let bottomX = _legend.horizontalAlignment == .right 139| 0| ? self.bounds.width - legendWidth + 15.0 140| 0| : legendWidth - 15.0 141| 0| let bottomY = legendHeight + 15 142| 0| let distLegend = distanceToCenter(x: bottomX, y: bottomY) 143| 0| 144| 0| let reference = getPosition(center: c, dist: self.radius, 145| 0| angle: angleForPoint(x: bottomX, y: bottomY)) 146| 0| 147| 0| let distReference = distanceToCenter(x: reference.x, y: reference.y) 148| 0| let minOffset = CGFloat(5.0) 149| 0| 150| 0| if bottomY >= c.y 151| 0| && self.bounds.height - legendWidth > self.bounds.width 152| 0| { 153| 0| xLegendOffset = legendWidth 154| 0| } 155| 0| else if distLegend < distReference 156| 0| { 157| 0| let diff = distReference - distLegend 158| 0| xLegendOffset = minOffset + diff 159| 0| } 160| 0| } 161| 0| } 162| 0| 163| 0| switch _legend.horizontalAlignment 164| 0| { 165| 0| case .left: 166| 0| legendLeft = xLegendOffset 167| 0| 168| 0| case .right: 169| 0| legendRight = xLegendOffset 170| 0| 171| 0| case .center: 172| 0| 173| 0| switch _legend.verticalAlignment 174| 0| { 175| 0| case .top: 176| 0| legendTop = min(_legend.neededHeight, _viewPortHandler.chartHeight * _legend.maxSizePercent) 177| 0| 178| 0| case .bottom: 179| 0| legendBottom = min(_legend.neededHeight, _viewPortHandler.chartHeight * _legend.maxSizePercent) 180| 0| 181| 0| default: 182| 0| break 183| 0| } 184| 12| } 185| 12| 186| 12| case .horizontal: 187| 12| 188| 12| var yLegendOffset: CGFloat = 0.0 189| 12| 190| 12| if _legend.verticalAlignment == .top 191| 12| || _legend.verticalAlignment == .bottom 192| 12| { 193| 12| // It's possible that we do not need this offset anymore as it 194| 12| // is available through the extraOffsets, but changing it can mean 195| 12| // changing default visibility for existing apps. 196| 12| let yOffset = self.requiredLegendOffset 197| 12| 198| 12| yLegendOffset = min( 199| 12| _legend.neededHeight + yOffset, 200| 12| _viewPortHandler.chartHeight * _legend.maxSizePercent) 201| 12| } 202| 12| 203| 12| switch _legend.verticalAlignment 204| 12| { 205| 12| case .top: 206| 0| 207| 0| legendTop = yLegendOffset 208| 12| 209| 12| case .bottom: 210| 12| 211| 12| legendBottom = yLegendOffset 212| 12| 213| 12| default: 214| 0| break 215| 12| } 216| 12| } 217| 12| 218| 12| legendLeft += self.requiredBaseOffset 219| 12| legendRight += self.requiredBaseOffset 220| 12| legendTop += self.requiredBaseOffset 221| 12| legendBottom += self.requiredBaseOffset 222| 12| } 223| 12| 224| 12| legendTop += self.extraTopOffset 225| 12| legendRight += self.extraRightOffset 226| 12| legendBottom += self.extraBottomOffset 227| 12| legendLeft += self.extraLeftOffset 228| 12| 229| 12| var minOffset = self.minOffset 230| 12| 231| 12| if self is RadarChartView 232| 12| { 233| 0| let x = self.xAxis 234| 0| 235| 0| if x.isEnabled && x.drawLabelsEnabled 236| 0| { 237| 0| minOffset = max(minOffset, x.labelRotatedWidth) 238| 0| } 239| 12| } 240| 12| 241| 12| let offsetLeft = max(minOffset, legendLeft) 242| 12| let offsetTop = max(minOffset, legendTop) 243| 12| let offsetRight = max(minOffset, legendRight) 244| 12| let offsetBottom = max(minOffset, max(self.requiredBaseOffset, legendBottom)) 245| 12| 246| 12| _viewPortHandler.restrainViewPort(offsetLeft: offsetLeft, offsetTop: offsetTop, offsetRight: offsetRight, offsetBottom: offsetBottom) 247| 12| } 248| | 249| | /// - Returns: The angle relative to the chart center for the given point on the chart in degrees. 250| | /// The angle is always between 0 and 360°, 0° is NORTH, 90° is EAST, ... 251| | @objc open func angleForPoint(x: CGFloat, y: CGFloat) -> CGFloat 252| 0| { 253| 0| let c = centerOffsets 254| 0| 255| 0| let tx = Double(x - c.x) 256| 0| let ty = Double(y - c.y) 257| 0| let length = sqrt(tx * tx + ty * ty) 258| 0| let r = acos(ty / length) 259| 0| 260| 0| var angle = r.RAD2DEG 261| 0| 262| 0| if x > c.x 263| 0| { 264| 0| angle = 360.0 - angle 265| 0| } 266| 0| 267| 0| // add 90° because chart starts EAST 268| 0| angle = angle + 90.0 269| 0| 270| 0| // neutralize overflow 271| 0| if angle > 360.0 272| 0| { 273| 0| angle = angle - 360.0 274| 0| } 275| 0| 276| 0| return CGFloat(angle) 277| 0| } 278| | 279| | /// Calculates the position around a center point, depending on the distance 280| | /// from the center, and the angle of the position around the center. 281| | @objc open func getPosition(center: CGPoint, dist: CGFloat, angle: CGFloat) -> CGPoint 282| 0| { 283| 0| return CGPoint(x: center.x + dist * cos(angle.DEG2RAD), 284| 0| y: center.y + dist * sin(angle.DEG2RAD)) 285| 0| } 286| | 287| | /// - Returns: The distance of a certain point on the chart to the center of the chart. 288| | @objc open func distanceToCenter(x: CGFloat, y: CGFloat) -> CGFloat 289| 0| { 290| 0| let c = self.centerOffsets 291| 0| 292| 0| var dist = CGFloat(0.0) 293| 0| 294| 0| var xDist = CGFloat(0.0) 295| 0| var yDist = CGFloat(0.0) 296| 0| 297| 0| if x > c.x 298| 0| { 299| 0| xDist = x - c.x 300| 0| } 301| 0| else 302| 0| { 303| 0| xDist = c.x - x 304| 0| } 305| 0| 306| 0| if y > c.y 307| 0| { 308| 0| yDist = y - c.y 309| 0| } 310| 0| else 311| 0| { 312| 0| yDist = c.y - y 313| 0| } 314| 0| 315| 0| // pythagoras 316| 0| dist = sqrt(pow(xDist, 2.0) + pow(yDist, 2.0)) 317| 0| 318| 0| return dist 319| 0| } 320| | 321| | /// - Returns: The xIndex for the given angle around the center of the chart. 322| | /// -1 if not found / outofbounds. 323| | @objc open func indexForAngle(_ angle: CGFloat) -> Int 324| 0| { 325| 0| fatalError("indexForAngle() cannot be called on PieRadarChartViewBase") 326| 0| } 327| | 328| | /// current rotation angle of the pie chart 329| | /// 330| | /// **default**: 270 --> top (NORTH) 331| | /// Will always return a normalized value, which will be between 0.0 < 360.0 332| | @objc open var rotationAngle: CGFloat 333| | { 334| | get 335| 14| { 336| 14| return _rotationAngle 337| 14| } 338| | set 339| 0| { 340| 0| _rawRotationAngle = newValue 341| 0| _rotationAngle = newValue.normalizedAngle 342| 0| setNeedsDisplay() 343| 0| } 344| | } 345| | 346| | /// gets the raw version of the current rotation angle of the pie chart the returned value could be any value, negative or positive, outside of the 360 degrees. 347| | /// this is used when working with rotation direction, mainly by gestures and animations. 348| | @objc open var rawRotationAngle: CGFloat 349| 0| { 350| 0| return _rawRotationAngle 351| 0| } 352| | 353| | /// The diameter of the pie- or radar-chart 354| | @objc open var diameter: CGFloat 355| 12| { 356| 12| var content = _viewPortHandler.contentRect 357| 12| content.origin.x += extraLeftOffset 358| 12| content.origin.y += extraTopOffset 359| 12| content.size.width -= extraLeftOffset + extraRightOffset 360| 12| content.size.height -= extraTopOffset + extraBottomOffset 361| 12| return min(content.width, content.height) 362| 12| } 363| | 364| | /// The radius of the chart in pixels. 365| | @objc open var radius: CGFloat 366| 0| { 367| 0| fatalError("radius cannot be called on PieRadarChartViewBase") 368| 0| } 369| | 370| | /// The required offset for the chart legend. 371| | internal var requiredLegendOffset: CGFloat 372| 0| { 373| 0| fatalError("requiredLegendOffset cannot be called on PieRadarChartViewBase") 374| 0| } 375| | 376| | /// - Returns: The base offset needed for the chart without calculating the 377| | /// legend size. 378| | internal var requiredBaseOffset: CGFloat 379| 0| { 380| 0| fatalError("requiredBaseOffset cannot be called on PieRadarChartViewBase") 381| 0| } 382| | 383| | open override var chartYMax: Double 384| 0| { 385| 0| return 0.0 386| 0| } 387| | 388| | open override var chartYMin: Double 389| 0| { 390| 0| return 0.0 391| 0| } 392| | 393| 0| @objc open var isRotationEnabled: Bool { return rotationEnabled } 394| | 395| | /// flag that indicates if rotation is done with two fingers or one. 396| | /// when the chart is inside a scrollview, you need a two-finger rotation because a one-finger rotation eats up all touch events. 397| | /// 398| | /// On iOS this will disable one-finger rotation. 399| | /// On OSX this will keep two-finger multitouch rotation, and one-pointer mouse rotation. 400| | /// 401| | /// **default**: false 402| | @objc open var rotationWithTwoFingers: Bool 403| | { 404| | get 405| 0| { 406| 0| return _rotationWithTwoFingers 407| 0| } 408| | set 409| 0| { 410| 0| _rotationWithTwoFingers = newValue 411| 0| #if !os(tvOS) 412| 0| _rotationGestureRecognizer.isEnabled = _rotationWithTwoFingers 413| 0| #endif 414| 0| } 415| | } 416| | 417| | /// flag that indicates if rotation is done with two fingers or one. 418| | /// when the chart is inside a scrollview, you need a two-finger rotation because a one-finger rotation eats up all touch events. 419| | /// 420| | /// On iOS this will disable one-finger rotation. 421| | /// On OSX this will keep two-finger multitouch rotation, and one-pointer mouse rotation. 422| | /// 423| | /// **default**: false 424| | @objc open var isRotationWithTwoFingers: Bool 425| 0| { 426| 0| return _rotationWithTwoFingers 427| 0| } 428| | 429| | // MARK: - Animation 430| | 431| | private var _spinAnimator: Animator! 432| | 433| | /// Applys a spin animation to the Chart. 434| | @objc open func spin(duration: TimeInterval, fromAngle: CGFloat, toAngle: CGFloat, easing: ChartEasingFunctionBlock?) 435| 0| { 436| 0| if _spinAnimator != nil 437| 0| { 438| 0| _spinAnimator.stop() 439| 0| } 440| 0| 441| 0| _spinAnimator = Animator() 442| 0| _spinAnimator.updateBlock = { 443| 0| self.rotationAngle = (toAngle - fromAngle) * CGFloat(self._spinAnimator.phaseX) + fromAngle 444| 0| } 445| 0| _spinAnimator.stopBlock = { self._spinAnimator = nil } 446| 0| 447| 0| _spinAnimator.animate(xAxisDuration: duration, easing: easing) 448| 0| } 449| | 450| | @objc open func spin(duration: TimeInterval, fromAngle: CGFloat, toAngle: CGFloat, easingOption: ChartEasingOption) 451| 0| { 452| 0| spin(duration: duration, fromAngle: fromAngle, toAngle: toAngle, easing: easingFunctionFromOption(easingOption)) 453| 0| } 454| | 455| | @objc open func spin(duration: TimeInterval, fromAngle: CGFloat, toAngle: CGFloat) 456| 0| { 457| 0| spin(duration: duration, fromAngle: fromAngle, toAngle: toAngle, easing: nil) 458| 0| } 459| | 460| | @objc open func stopSpinAnimation() 461| 0| { 462| 0| if _spinAnimator != nil 463| 0| { 464| 0| _spinAnimator.stop() 465| 0| } 466| 0| } 467| | 468| | // MARK: - Gestures 469| | 470| | private var _rotationGestureStartPoint: CGPoint! 471| | private var _isRotating = false 472| | private var _startAngle = CGFloat(0.0) 473| | 474| | private struct AngularVelocitySample 475| | { 476| | var time: TimeInterval 477| | var angle: CGFloat 478| | } 479| | 480| | private var velocitySamples = [AngularVelocitySample]() 481| | 482| | private var _decelerationLastTime: TimeInterval = 0.0 483| | private var _decelerationDisplayLink: NSUIDisplayLink! 484| | private var _decelerationAngularVelocity: CGFloat = 0.0 485| | 486| | internal final func processRotationGestureBegan(location: CGPoint) 487| 0| { 488| 0| self.resetVelocity() 489| 0| 490| 0| if rotationEnabled 491| 0| { 492| 0| self.sampleVelocity(touchLocation: location) 493| 0| } 494| 0| 495| 0| self.setGestureStartAngle(x: location.x, y: location.y) 496| 0| 497| 0| _rotationGestureStartPoint = location 498| 0| } 499| | 500| | internal final func processRotationGestureMoved(location: CGPoint) 501| 0| { 502| 0| if isDragDecelerationEnabled 503| 0| { 504| 0| sampleVelocity(touchLocation: location) 505| 0| } 506| 0| 507| 0| if !_isRotating && 508| 0| distance( 509| 0| eventX: location.x, 510| 0| startX: _rotationGestureStartPoint.x, 511| 0| eventY: location.y, 512| 0| startY: _rotationGestureStartPoint.y) > CGFloat(8.0) 513| 0| { 514| 0| _isRotating = true 515| 0| } 516| 0| else 517| 0| { 518| 0| self.updateGestureRotation(x: location.x, y: location.y) 519| 0| setNeedsDisplay() 520| 0| } 521| 0| } 522| | 523| | internal final func processRotationGestureEnded(location: CGPoint) 524| 0| { 525| 0| if isDragDecelerationEnabled 526| 0| { 527| 0| stopDeceleration() 528| 0| 529| 0| sampleVelocity(touchLocation: location) 530| 0| 531| 0| _decelerationAngularVelocity = calculateVelocity() 532| 0| 533| 0| if _decelerationAngularVelocity != 0.0 534| 0| { 535| 0| _decelerationLastTime = CACurrentMediaTime() 536| 0| _decelerationDisplayLink = NSUIDisplayLink(target: self, selector: #selector(PieRadarChartViewBase.decelerationLoop)) 537| 0| _decelerationDisplayLink.add(to: RunLoop.main, forMode: RunLoop.Mode.common) 538| 0| } 539| 0| } 540| 0| } 541| | 542| | internal final func processRotationGestureCancelled() 543| 0| { 544| 0| if _isRotating 545| 0| { 546| 0| _isRotating = false 547| 0| } 548| 0| } 549| | 550| | #if !os(OSX) 551| | open override func nsuiTouchesBegan(_ touches: Set, withEvent event: NSUIEvent?) 552| 0| { 553| 0| // if rotation by touch is enabled 554| 0| if rotationEnabled 555| 0| { 556| 0| stopDeceleration() 557| 0| 558| 0| if !rotationWithTwoFingers, let touchLocation = touches.first?.location(in: self) 559| 0| { 560| 0| processRotationGestureBegan(location: touchLocation) 561| 0| } 562| 0| } 563| 0| 564| 0| if !_isRotating 565| 0| { 566| 0| super.nsuiTouchesBegan(touches, withEvent: event) 567| 0| } 568| 0| } 569| | 570| | open override func nsuiTouchesMoved(_ touches: Set, withEvent event: NSUIEvent?) 571| 0| { 572| 0| if rotationEnabled && !rotationWithTwoFingers, let touch = touches.first 573| 0| { 574| 0| let touchLocation = touch.location(in: self) 575| 0| processRotationGestureMoved(location: touchLocation) 576| 0| } 577| 0| 578| 0| if !_isRotating 579| 0| { 580| 0| super.nsuiTouchesMoved(touches, withEvent: event) 581| 0| } 582| 0| } 583| | 584| | open override func nsuiTouchesEnded(_ touches: Set, withEvent event: NSUIEvent?) 585| 0| { 586| 0| if !_isRotating 587| 0| { 588| 0| super.nsuiTouchesEnded(touches, withEvent: event) 589| 0| } 590| 0| 591| 0| if rotationEnabled && !rotationWithTwoFingers, let touch = touches.first 592| 0| { 593| 0| let touchLocation = touch.location(in: self) 594| 0| processRotationGestureEnded(location: touchLocation) 595| 0| } 596| 0| 597| 0| if _isRotating 598| 0| { 599| 0| _isRotating = false 600| 0| } 601| 0| } 602| | 603| | open override func nsuiTouchesCancelled(_ touches: Set?, withEvent event: NSUIEvent?) 604| 0| { 605| 0| super.nsuiTouchesCancelled(touches, withEvent: event) 606| 0| 607| 0| processRotationGestureCancelled() 608| 0| } 609| | #endif 610| | 611| | #if os(OSX) 612| | open override func mouseDown(with theEvent: NSEvent) 613| | { 614| | // if rotation by touch is enabled 615| | if rotationEnabled 616| | { 617| | stopDeceleration() 618| | 619| | let location = self.convert(theEvent.locationInWindow, from: nil) 620| | 621| | processRotationGestureBegan(location: location) 622| | } 623| | 624| | if !_isRotating 625| | { 626| | super.mouseDown(with: theEvent) 627| | } 628| | } 629| | 630| | open override func mouseDragged(with theEvent: NSEvent) 631| | { 632| | if rotationEnabled 633| | { 634| | let location = self.convert(theEvent.locationInWindow, from: nil) 635| | 636| | processRotationGestureMoved(location: location) 637| | } 638| | 639| | if !_isRotating 640| | { 641| | super.mouseDragged(with: theEvent) 642| | } 643| | } 644| | 645| | open override func mouseUp(with theEvent: NSEvent) 646| | { 647| | if !_isRotating 648| | { 649| | super.mouseUp(with: theEvent) 650| | } 651| | 652| | if rotationEnabled 653| | { 654| | let location = self.convert(theEvent.locationInWindow, from: nil) 655| | 656| | processRotationGestureEnded(location: location) 657| | } 658| | 659| | if _isRotating 660| | { 661| | _isRotating = false 662| | } 663| | } 664| | #endif 665| | 666| | private func resetVelocity() 667| 0| { 668| 0| velocitySamples.removeAll(keepingCapacity: false) 669| 0| } 670| | 671| | private func sampleVelocity(touchLocation: CGPoint) 672| 0| { 673| 0| let currentSample: AngularVelocitySample = { 674| 0| let time = CACurrentMediaTime() 675| 0| let angle = angleForPoint(x: touchLocation.x, y: touchLocation.y) 676| 0| return AngularVelocitySample(time: time, angle: angle) 677| 0| }() 678| 0| 679| 0| // Remove samples older than our sample time - 1 seconds 680| 0| // while keeping at least one sample 681| 0| 682| 0| var i = 0, count = velocitySamples.count 683| 0| while (i < count - 2) 684| 0| { 685| 0| if currentSample.time - velocitySamples[i].time > 1.0 686| 0| { 687| 0| velocitySamples.remove(at: 0) 688| 0| i -= 1 689| 0| count -= 1 690| 0| } 691| 0| else 692| 0| { 693| 0| break 694| 0| } 695| 0| 696| 0| i += 1 697| 0| } 698| 0| 699| 0| velocitySamples.append(currentSample) 700| 0| } 701| | 702| | private func calculateVelocity() -> CGFloat 703| 0| { 704| 0| guard var firstSample = velocitySamples.first, 705| 0| var lastSample = velocitySamples.last 706| 0| else { return 0 } 707| 0| 708| 0| // Look for a sample that's closest to the latest sample, but not the same, so we can deduce the direction 709| 0| let beforeLastSample = velocitySamples.last { $0.angle != lastSample.angle } 710| 0| ?? firstSample 711| 0| 712| 0| // Calculate the sampling time 713| 0| let timeDelta: CGFloat = { 714| 0| let delta = CGFloat(lastSample.time - firstSample.time) 715| 0| return delta == 0 ? 0.1 : delta 716| 0| }() 717| 0| 718| 0| // Calculate clockwise/ccw by choosing two values that should be closest to each other, 719| 0| // so if the angles are two far from each other we know they are inverted "for sure" 720| 0| let isClockwise: Bool = { 721| 0| let isClockwise = lastSample.angle >= beforeLastSample.angle 722| 0| let isInverted = abs(lastSample.angle - beforeLastSample.angle) > 270.0 723| 0| return isInverted ? !isClockwise : isClockwise 724| 0| }() 725| 0| 726| 0| // Now if the "gesture" is over a too big of an angle - then we know the angles are inverted, and we need to move them closer to each other from both sides of the 360.0 wrapping point 727| 0| if lastSample.angle - firstSample.angle > 180.0 728| 0| { 729| 0| firstSample.angle += 360.0 730| 0| } 731| 0| else if firstSample.angle - lastSample.angle > 180.0 732| 0| { 733| 0| lastSample.angle += 360.0 734| 0| } 735| 0| 736| 0| // The velocity 737| 0| let velocity = abs((lastSample.angle - firstSample.angle) / timeDelta) 738| 0| return isClockwise ? velocity : -velocity 739| 0| } 740| | 741| | /// sets the starting angle of the rotation, this is only used by the touch listener, x and y is the touch position 742| | private func setGestureStartAngle(x: CGFloat, y: CGFloat) 743| 0| { 744| 0| _startAngle = angleForPoint(x: x, y: y) 745| 0| 746| 0| // take the current angle into consideration when starting a new drag 747| 0| _startAngle -= _rotationAngle 748| 0| } 749| | 750| | /// updates the view rotation depending on the given touch position, also takes the starting angle into consideration 751| | private func updateGestureRotation(x: CGFloat, y: CGFloat) 752| 0| { 753| 0| self.rotationAngle = angleForPoint(x: x, y: y) - _startAngle 754| 0| } 755| | 756| | @objc open func stopDeceleration() 757| 0| { 758| 0| if _decelerationDisplayLink !== nil 759| 0| { 760| 0| _decelerationDisplayLink.remove(from: RunLoop.main, forMode: RunLoop.Mode.common) 761| 0| _decelerationDisplayLink = nil 762| 0| } 763| 0| } 764| | 765| | @objc private func decelerationLoop() 766| 0| { 767| 0| let currentTime = CACurrentMediaTime() 768| 0| 769| 0| _decelerationAngularVelocity *= self.dragDecelerationFrictionCoef 770| 0| 771| 0| let timeInterval = CGFloat(currentTime - _decelerationLastTime) 772| 0| 773| 0| self.rotationAngle += _decelerationAngularVelocity * timeInterval 774| 0| 775| 0| _decelerationLastTime = currentTime 776| 0| 777| 0| if(abs(_decelerationAngularVelocity) < 0.001) 778| 0| { 779| 0| stopDeceleration() 780| 0| } 781| 0| } 782| | 783| | /// - Returns: The distance between two points 784| | private func distance(eventX: CGFloat, startX: CGFloat, eventY: CGFloat, startY: CGFloat) -> CGFloat 785| 0| { 786| 0| let dx = eventX - startX 787| 0| let dy = eventY - startY 788| 0| return sqrt(dx * dx + dy * dy) 789| 0| } 790| | 791| | /// - Returns: The distance between two points 792| | private func distance(from: CGPoint, to: CGPoint) -> CGFloat 793| 0| { 794| 0| let dx = from.x - to.x 795| 0| let dy = from.y - to.y 796| 0| return sqrt(dx * dx + dy * dy) 797| 0| } 798| | 799| | /// reference to the last highlighted object 800| | private var _lastHighlight: Highlight! 801| | 802| | @objc private func tapGestureRecognized(_ recognizer: NSUITapGestureRecognizer) 803| 0| { 804| 0| if recognizer.state == NSUIGestureRecognizerState.ended 805| 0| { 806| 0| if !self.isHighLightPerTapEnabled { return } 807| 0| 808| 0| let location = recognizer.location(in: self) 809| 0| 810| 0| let high = self.getHighlightByTouchPoint(location) 811| 0| self.highlightValue(high, callDelegate: true) 812| 0| } 813| 0| } 814| | 815| | #if !os(tvOS) 816| | @objc private func rotationGestureRecognized(_ recognizer: NSUIRotationGestureRecognizer) 817| | { 818| | if recognizer.state == NSUIGestureRecognizerState.began 819| | { 820| | stopDeceleration() 821| | 822| | _startAngle = self.rawRotationAngle 823| | } 824| | 825| | if recognizer.state == NSUIGestureRecognizerState.began || recognizer.state == NSUIGestureRecognizerState.changed 826| | { 827| | let angle = recognizer.nsuiRotation.RAD2DEG 828| | 829| | self.rotationAngle = _startAngle + angle 830| | setNeedsDisplay() 831| | } 832| | else if recognizer.state == NSUIGestureRecognizerState.ended 833| | { 834| | let angle = recognizer.nsuiRotation.RAD2DEG 835| | 836| | self.rotationAngle = _startAngle + angle 837| | setNeedsDisplay() 838| | 839| | if isDragDecelerationEnabled 840| | { 841| | stopDeceleration() 842| | 843| | _decelerationAngularVelocity = recognizer.velocity.RAD2DEG 844| | 845| | if _decelerationAngularVelocity != 0.0 846| | { 847| | _decelerationLastTime = CACurrentMediaTime() 848| | _decelerationDisplayLink = NSUIDisplayLink(target: self, selector: #selector(PieRadarChartViewBase.decelerationLoop)) 849| | _decelerationDisplayLink.add(to: RunLoop.main, forMode: RunLoop.Mode.common) 850| | } 851| | } 852| | } 853| | } 854| | #endif 855| |} /Users/travis/build/danielgindi/Charts/Source/Charts/Charts/RadarChartView.swift: 1| |// 2| |// RadarChartView.swift 3| |// Charts 4| |// 5| |// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda 6| |// A port of MPAndroidChart for iOS 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| | 12| |import Foundation 13| |import CoreGraphics 14| | 15| | 16| |/// Implementation of the RadarChart, a "spidernet"-like chart. It works best 17| |/// when displaying 5-10 entries per DataSet. 18| |open class RadarChartView: PieRadarChartViewBase 19| |{ 20| | /// width of the web lines that come from the center. 21| | @objc open var webLineWidth = CGFloat(1.5) 22| | 23| | /// width of the web lines that are in between the lines coming from the center 24| | @objc open var innerWebLineWidth = CGFloat(0.75) 25| | 26| | /// color for the web lines that come from the center 27| | @objc open var webColor = NSUIColor(red: 122/255.0, green: 122/255.0, blue: 122.0/255.0, alpha: 1.0) 28| | 29| | /// color for the web lines in between the lines that come from the center. 30| | @objc open var innerWebColor = NSUIColor(red: 122/255.0, green: 122/255.0, blue: 122.0/255.0, alpha: 1.0) 31| | 32| | /// transparency the grid is drawn with (0.0 - 1.0) 33| | @objc open var webAlpha: CGFloat = 150.0 / 255.0 34| | 35| | /// flag indicating if the web lines should be drawn or not 36| | @objc open var drawWeb = true 37| | 38| | /// modulus that determines how many labels and web-lines are skipped before the next is drawn 39| | private var _skipWebLineCount = 0 40| | 41| | /// the object reprsenting the y-axis labels 42| | private var _yAxis: YAxis! 43| | 44| | internal var _yAxisRenderer: YAxisRendererRadarChart! 45| | internal var _xAxisRenderer: XAxisRendererRadarChart! 46| | 47| | public override init(frame: CGRect) 48| 0| { 49| 0| super.init(frame: frame) 50| 0| } 51| | 52| | public required init?(coder aDecoder: NSCoder) 53| 0| { 54| 0| super.init(coder: aDecoder) 55| 0| } 56| | 57| | internal override func initialize() 58| 0| { 59| 0| super.initialize() 60| 0| 61| 0| _yAxis = YAxis(position: .left) 62| 0| _yAxis.labelXOffset = 10.0 63| 0| 64| 0| renderer = RadarChartRenderer(chart: self, animator: _animator, viewPortHandler: _viewPortHandler) 65| 0| 66| 0| _yAxisRenderer = YAxisRendererRadarChart(viewPortHandler: _viewPortHandler, yAxis: _yAxis, chart: self) 67| 0| _xAxisRenderer = XAxisRendererRadarChart(viewPortHandler: _viewPortHandler, xAxis: _xAxis, chart: self) 68| 0| 69| 0| self.highlighter = RadarHighlighter(chart: self) 70| 0| } 71| | 72| | internal override func calcMinMax() 73| 0| { 74| 0| super.calcMinMax() 75| 0| 76| 0| guard let data = _data else { return } 77| 0| 78| 0| _yAxis.calculate(min: data.getYMin(axis: .left), max: data.getYMax(axis: .left)) 79| 0| _xAxis.calculate(min: 0.0, max: Double(data.maxEntryCountSet?.entryCount ?? 0)) 80| 0| } 81| | 82| | open override func notifyDataSetChanged() 83| 0| { 84| 0| calcMinMax() 85| 0| 86| 0| _yAxisRenderer?.computeAxis(min: _yAxis._axisMinimum, max: _yAxis._axisMaximum, inverted: _yAxis.isInverted) 87| 0| _xAxisRenderer?.computeAxis(min: _xAxis._axisMinimum, max: _xAxis._axisMaximum, inverted: false) 88| 0| 89| 0| if let data = _data, 90| 0| let legend = _legend, 91| 0| !legend.isLegendCustom 92| 0| { 93| 0| legendRenderer?.computeLegend(data: data) 94| 0| } 95| 0| 96| 0| calculateOffsets() 97| 0| 98| 0| setNeedsDisplay() 99| 0| } 100| | 101| | open override func draw(_ rect: CGRect) 102| 0| { 103| 0| super.draw(rect) 104| 0| 105| 0| guard data != nil, let renderer = renderer else { return } 106| 0| 107| 0| let optionalContext = NSUIGraphicsGetCurrentContext() 108| 0| guard let context = optionalContext else { return } 109| 0| 110| 0| if _xAxis.isEnabled 111| 0| { 112| 0| _xAxisRenderer.computeAxis(min: _xAxis._axisMinimum, max: _xAxis._axisMaximum, inverted: false) 113| 0| } 114| 0| 115| 0| _xAxisRenderer?.renderAxisLabels(context: context) 116| 0| 117| 0| if drawWeb 118| 0| { 119| 0| renderer.drawExtras(context: context) 120| 0| } 121| 0| 122| 0| if _yAxis.isEnabled && _yAxis.isDrawLimitLinesBehindDataEnabled 123| 0| { 124| 0| _yAxisRenderer.renderLimitLines(context: context) 125| 0| } 126| 0| 127| 0| renderer.drawData(context: context) 128| 0| 129| 0| if valuesToHighlight() 130| 0| { 131| 0| renderer.drawHighlighted(context: context, indices: _indicesToHighlight) 132| 0| } 133| 0| 134| 0| if _yAxis.isEnabled && !_yAxis.isDrawLimitLinesBehindDataEnabled 135| 0| { 136| 0| _yAxisRenderer.renderLimitLines(context: context) 137| 0| } 138| 0| 139| 0| _yAxisRenderer.renderAxisLabels(context: context) 140| 0| 141| 0| renderer.drawValues(context: context) 142| 0| 143| 0| legendRenderer.renderLegend(context: context) 144| 0| 145| 0| drawDescription(context: context) 146| 0| 147| 0| drawMarkers(context: context) 148| 0| } 149| | 150| | /// The factor that is needed to transform values into pixels. 151| | @objc open var factor: CGFloat 152| 0| { 153| 0| let content = _viewPortHandler.contentRect 154| 0| return min(content.width / 2.0, content.height / 2.0) 155| 0| / CGFloat(_yAxis.axisRange) 156| 0| } 157| | 158| | /// The angle that each slice in the radar chart occupies. 159| | @objc open var sliceAngle: CGFloat 160| 0| { 161| 0| return 360.0 / CGFloat(_data?.maxEntryCountSet?.entryCount ?? 0) 162| 0| } 163| | 164| | open override func indexForAngle(_ angle: CGFloat) -> Int 165| 0| { 166| 0| // take the current angle of the chart into consideration 167| 0| let a = (angle - self.rotationAngle).normalizedAngle 168| 0| 169| 0| let sliceAngle = self.sliceAngle 170| 0| 171| 0| let max = _data?.maxEntryCountSet?.entryCount ?? 0 172| 0| return (0.. a 174| 0| } ?? max 175| 0| } 176| | 177| | /// The object that represents all y-labels of the RadarChart. 178| | @objc open var yAxis: YAxis 179| 0| { 180| 0| return _yAxis 181| 0| } 182| | 183| | /// Sets the number of web-lines that should be skipped on chart web before the next one is drawn. This targets the lines that come from the center of the RadarChart. 184| | /// if count = 1 -> 1 line is skipped in between 185| | @objc open var skipWebLineCount: Int 186| | { 187| | get 188| 0| { 189| 0| return _skipWebLineCount 190| 0| } 191| | set 192| 0| { 193| 0| _skipWebLineCount = max(0, newValue) 194| 0| } 195| | } 196| | 197| | internal override var requiredLegendOffset: CGFloat 198| 0| { 199| 0| return _legend.font.pointSize * 4.0 200| 0| } 201| | 202| | internal override var requiredBaseOffset: CGFloat 203| 0| { 204| 0| return _xAxis.isEnabled && _xAxis.isDrawLabelsEnabled ? _xAxis.labelRotatedWidth : 10.0 205| 0| } 206| | 207| | open override var radius: CGFloat 208| 0| { 209| 0| let content = _viewPortHandler.contentRect 210| 0| return min(content.width / 2.0, content.height / 2.0) 211| 0| } 212| | 213| | /// The maximum value this chart can display on it's y-axis. 214| 0| open override var chartYMax: Double { return _yAxis._axisMaximum } 215| | 216| | /// The minimum value this chart can display on it's y-axis. 217| 0| open override var chartYMin: Double { return _yAxis._axisMinimum } 218| | 219| | /// The range of y-values this chart can display. 220| 0| @objc open var yRange: Double { return _yAxis.axisRange } 221| |} /Users/travis/build/danielgindi/Charts/Source/Charts/Charts/ScatterChartView.swift: 1| |// 2| |// ScatterChartView.swift 3| |// Charts 4| |// 5| |// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda 6| |// A port of MPAndroidChart for iOS 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| | 12| |import Foundation 13| |import CoreGraphics 14| | 15| |/// The ScatterChart. Draws dots, triangles, squares and custom shapes into the chartview. 16| |open class ScatterChartView: BarLineChartViewBase, ScatterChartDataProvider 17| |{ 18| | open override func initialize() 19| 0| { 20| 0| super.initialize() 21| 0| 22| 0| renderer = ScatterChartRenderer(dataProvider: self, animator: _animator, viewPortHandler: _viewPortHandler) 23| 0| 24| 0| xAxis.spaceMin = 0.5 25| 0| xAxis.spaceMax = 0.5 26| 0| } 27| | 28| | // MARK: - ScatterChartDataProvider 29| | 30| 0| open var scatterData: ScatterChartData? { return _data as? ScatterChartData } 31| |} /Users/travis/build/danielgindi/Charts/Source/Charts/Components/AxisBase.swift: 1| |// 2| |// AxisBase.swift 3| |// Charts 4| |// 5| |// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda 6| |// A port of MPAndroidChart for iOS 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| | 12| |import Foundation 13| |import CoreGraphics 14| | 15| |/// Base class for all axes 16| |@objc(ChartAxisBase) 17| |open class AxisBase: ComponentBase 18| |{ 19| | public override init() 20| 144| { 21| 144| super.init() 22| 144| } 23| | 24| | /// Custom formatter that is used instead of the auto-formatter if set 25| | private var _axisValueFormatter: IAxisValueFormatter? 26| | 27| | @objc open var labelFont = NSUIFont.systemFont(ofSize: 10.0) 28| | @objc open var labelTextColor = NSUIColor.labelOrBlack 29| | 30| | @objc open var axisLineColor = NSUIColor.gray 31| | @objc open var axisLineWidth = CGFloat(0.5) 32| | @objc open var axisLineDashPhase = CGFloat(0.0) 33| | @objc open var axisLineDashLengths: [CGFloat]! 34| | 35| | @objc open var gridColor = NSUIColor.gray.withAlphaComponent(0.9) 36| | @objc open var gridLineWidth = CGFloat(0.5) 37| | @objc open var gridLineDashPhase = CGFloat(0.0) 38| | @objc open var gridLineDashLengths: [CGFloat]! 39| | @objc open var gridLineCap = CGLineCap.butt 40| | 41| | @objc open var drawGridLinesEnabled = true 42| | @objc open var drawAxisLineEnabled = true 43| | 44| | /// flag that indicates of the labels of this axis should be drawn or not 45| | @objc open var drawLabelsEnabled = true 46| | 47| | private var _centerAxisLabelsEnabled = false 48| | 49| | /// Centers the axis labels instead of drawing them at their original position. 50| | /// This is useful especially for grouped BarChart. 51| | @objc open var centerAxisLabelsEnabled: Bool 52| | { 53| 1.16k| get { return _centerAxisLabelsEnabled && entryCount > 0 } 54| 0| set { _centerAxisLabelsEnabled = newValue } 55| | } 56| | 57| | @objc open var isCenterAxisLabelsEnabled: Bool 58| | { 59| 46| get { return centerAxisLabelsEnabled } 60| | } 61| | 62| | /// array of limitlines that can be set for the axis 63| | private var _limitLines = [ChartLimitLine]() 64| | 65| | /// Are the LimitLines drawn behind the data or in front of the data? 66| | /// 67| | /// **default**: false 68| | @objc open var drawLimitLinesBehindDataEnabled = false 69| | 70| | /// Are the grid lines drawn behind the data or in front of the data? 71| | /// 72| | /// **default**: true 73| | @objc open var drawGridLinesBehindDataEnabled = true 74| | 75| | /// the flag can be used to turn off the antialias for grid lines 76| | @objc open var gridAntialiasEnabled = true 77| | 78| | /// the actual array of entries 79| | @objc open var entries = [Double]() 80| | 81| | /// axis label entries only used for centered labels 82| | @objc open var centeredEntries = [Double]() 83| | 84| | /// the number of entries the legend contains 85| 452| @objc open var entryCount: Int { return entries.count } 86| | 87| | /// the number of label entries the axis should have 88| | /// 89| | /// **default**: 6 90| | private var _labelCount = Int(6) 91| | 92| | /// the number of decimal digits to use (for the default formatter 93| | @objc open var decimals: Int = 0 94| | 95| | /// When true, axis labels are controlled by the `granularity` property. 96| | /// When false, axis values could possibly be repeated. 97| | /// This could happen if two adjacent axis values are rounded to same value. 98| | /// If using granularity this could be avoided by having fewer axis values visible. 99| | @objc open var granularityEnabled = false 100| | 101| | private var _granularity = Double(1.0) 102| | 103| | /// The minimum interval between axis values. 104| | /// This can be used to avoid label duplicating when zooming in. 105| | /// 106| | /// **default**: 1.0 107| | @objc open var granularity: Double 108| | { 109| | get 110| 0| { 111| 0| return _granularity 112| 0| } 113| | set 114| 0| { 115| 0| _granularity = newValue 116| 0| 117| 0| // set this to `true` if it was disabled, as it makes no sense to set this property with granularity disabled 118| 0| granularityEnabled = true 119| 0| } 120| | } 121| | 122| | /// The minimum interval between axis values. 123| | @objc open var isGranularityEnabled: Bool 124| | { 125| | get 126| 0| { 127| 0| return granularityEnabled 128| 0| } 129| | } 130| | 131| | /// if true, the set number of y-labels will be forced 132| | @objc open var forceLabelsEnabled = false 133| | 134| | @objc open func getLongestLabel() -> String 135| 388| { 136| 388| var longest = "" 137| 388| 138| 388| for i in 0 ..< entries.count 139| 2.29k| { 140| 2.29k| let text = getFormattedLabel(i) 141| 2.29k| 142| 2.29k| if longest.count < text.count 143| 2.29k| { 144| 653| longest = text 145| 2.29k| } 146| 2.29k| } 147| 388| 148| 388| return longest 149| 388| } 150| | 151| | /// - Returns: The formatted label at the specified index. This will either use the auto-formatter or the custom formatter (if one is set). 152| | @objc open func getFormattedLabel(_ index: Int) -> String 153| 2.82k| { 154| 2.82k| if index < 0 || index >= entries.count 155| 2.82k| { 156| 0| return "" 157| 2.82k| } 158| 2.82k| 159| 2.82k| return valueFormatter?.stringForValue(entries[index], axis: self) ?? "" 160| 2.82k| } 161| | 162| | /// Sets the formatter to be used for formatting the axis labels. 163| | /// 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. 164| | /// Use `nil` to use the formatter calculated by the chart. 165| | @objc open var valueFormatter: IAxisValueFormatter? 166| | { 167| | get 168| 4.33k| { 169| 4.33k| if _axisValueFormatter == nil 170| 4.33k| { 171| 138| _axisValueFormatter = DefaultAxisValueFormatter(decimals: decimals) 172| 4.33k| } 173| 4.33k| else if _axisValueFormatter is DefaultAxisValueFormatter && 174| 4.33k| (_axisValueFormatter as! DefaultAxisValueFormatter).hasAutoDecimals && 175| 4.33k| (_axisValueFormatter as! DefaultAxisValueFormatter).decimals != decimals 176| 4.33k| { 177| 2| (self._axisValueFormatter as! DefaultAxisValueFormatter).decimals = self.decimals 178| 4.33k| } 179| 4.33k| 180| 4.33k| return _axisValueFormatter 181| 4.33k| } 182| | set 183| 0| { 184| 0| _axisValueFormatter = newValue ?? DefaultAxisValueFormatter(decimals: decimals) 185| 0| } 186| | } 187| | 188| 46| @objc open var isDrawGridLinesEnabled: Bool { return drawGridLinesEnabled } 189| | 190| 46| @objc open var isDrawAxisLineEnabled: Bool { return drawAxisLineEnabled } 191| | 192| 507| @objc open var isDrawLabelsEnabled: Bool { return drawLabelsEnabled } 193| | 194| | /// Are the LimitLines drawn behind the data or in front of the data? 195| | /// 196| | /// **default**: false 197| 272| @objc open var isDrawLimitLinesBehindDataEnabled: Bool { return drawLimitLinesBehindDataEnabled } 198| | 199| | /// Are the grid lines drawn behind the data or in front of the data? 200| | /// 201| | /// **default**: true 202| 0| @objc open var isDrawGridLinesBehindDataEnabled: Bool { return drawGridLinesBehindDataEnabled } 203| | 204| | /// Extra spacing for `axisMinimum` to be added to automatically calculated `axisMinimum` 205| | @objc open var spaceMin: Double = 0.0 206| | 207| | /// Extra spacing for `axisMaximum` to be added to automatically calculated `axisMaximum` 208| | @objc open var spaceMax: Double = 0.0 209| | 210| | /// Flag indicating that the axis-min value has been customized 211| | internal var _customAxisMin: Bool = false 212| | 213| | /// Flag indicating that the axis-max value has been customized 214| | internal var _customAxisMax: Bool = false 215| | 216| | /// Do not touch this directly, instead, use axisMinimum. 217| | /// This is automatically calculated to represent the real min value, 218| | /// and is used when calculating the effective minimum. 219| | internal var _axisMinimum = Double(0) 220| | 221| | /// Do not touch this directly, instead, use axisMaximum. 222| | /// This is automatically calculated to represent the real max value, 223| | /// and is used when calculating the effective maximum. 224| | internal var _axisMaximum = Double(0) 225| | 226| | /// the total range of values this axis covers 227| | @objc open var axisRange = Double(0) 228| | 229| | /// The minumum number of labels on the axis 230| | @objc open var axisMinLabels = Int(2) { 231| 0| didSet { axisMinLabels = axisMinLabels > 0 ? axisMinLabels : oldValue } 232| | } 233| | 234| | /// The maximum number of labels on the axis 235| | @objc open var axisMaxLabels = Int(25) { 236| 0| didSet { axisMaxLabels = axisMaxLabels > 0 ? axisMaxLabels : oldValue } 237| | } 238| | 239| | /// the number of label entries the axis should have 240| | /// max = 25, 241| | /// min = 2, 242| | /// default = 6, 243| | /// be aware that this number is not fixed and can only be approximated 244| | @objc open var labelCount: Int 245| | { 246| | get 247| 373| { 248| 373| return _labelCount 249| 373| } 250| | set 251| 0| { 252| 0| let range = axisMinLabels...axisMaxLabels as ClosedRange 253| 0| _labelCount = newValue.clamped(to: range) 254| 0| 255| 0| forceLabelsEnabled = false 256| 0| } 257| | } 258| | 259| | @objc open func setLabelCount(_ count: Int, force: Bool) 260| 0| { 261| 0| self.labelCount = count 262| 0| forceLabelsEnabled = force 263| 0| } 264| | 265| | /// `true` if focing the y-label count is enabled. Default: false 266| 373| @objc open var isForceLabelsEnabled: Bool { return forceLabelsEnabled } 267| | 268| | /// Adds a new ChartLimitLine to this axis. 269| | @objc open func addLimitLine(_ line: ChartLimitLine) 270| 0| { 271| 0| _limitLines.append(line) 272| 0| } 273| | 274| | /// Removes the specified ChartLimitLine from the axis. 275| | @objc open func removeLimitLine(_ line: ChartLimitLine) 276| 0| { 277| 0| guard let i = _limitLines.firstIndex(of: line) else { return } 278| 0| _limitLines.remove(at: i) 279| 0| } 280| | 281| | /// Removes all LimitLines from the axis. 282| | @objc open func removeAllLimitLines() 283| 0| { 284| 0| _limitLines.removeAll(keepingCapacity: false) 285| 0| } 286| | 287| | /// The LimitLines of this axis. 288| | @objc open var limitLines : [ChartLimitLine] 289| 136| { 290| 136| return _limitLines 291| 136| } 292| | 293| | // MARK: Custom axis ranges 294| | 295| | /// By calling this method, any custom minimum value that has been previously set is reseted, and the calculation is done automatically. 296| | @objc open func resetCustomAxisMin() 297| 0| { 298| 0| _customAxisMin = false 299| 0| } 300| | 301| 0| @objc open var isAxisMinCustom: Bool { return _customAxisMin } 302| | 303| | /// By calling this method, any custom maximum value that has been previously set is reseted, and the calculation is done automatically. 304| | @objc open func resetCustomAxisMax() 305| 0| { 306| 0| _customAxisMax = false 307| 0| } 308| | 309| 0| @objc open var isAxisMaxCustom: Bool { return _customAxisMax } 310| | 311| | /// The minimum value for this axis. 312| | /// If set, this value will not be calculated automatically depending on the provided data. 313| | /// Use `resetCustomAxisMin()` to undo this. 314| | @objc open var axisMinimum: Double 315| | { 316| | get 317| 960| { 318| 960| return _axisMinimum 319| 960| } 320| | set 321| 24| { 322| 24| _customAxisMin = true 323| 24| _axisMinimum = newValue 324| 24| axisRange = abs(_axisMaximum - newValue) 325| 24| } 326| | } 327| | 328| | /// The maximum value for this axis. 329| | /// If set, this value will not be calculated automatically depending on the provided data. 330| | /// Use `resetCustomAxisMax()` to undo this. 331| | @objc open var axisMaximum: Double 332| | { 333| | get 334| 916| { 335| 916| return _axisMaximum 336| 916| } 337| | set 338| 6| { 339| 6| _customAxisMax = true 340| 6| _axisMaximum = newValue 341| 6| axisRange = abs(newValue - _axisMinimum) 342| 6| } 343| | } 344| | 345| | /// Calculates the minimum, maximum and range values of the YAxis with the given minimum and maximum values from the chart data. 346| | /// 347| | /// - Parameters: 348| | /// - dataMin: the y-min value according to chart data 349| | /// - dataMax: the y-max value according to chart 350| | @objc open func calculate(min dataMin: Double, max dataMax: Double) 351| 79| { 352| 79| // if custom, use value as is, else use data value 353| 79| var min = _customAxisMin ? _axisMinimum : (dataMin - spaceMin) 354| 79| var max = _customAxisMax ? _axisMaximum : (dataMax + spaceMax) 355| 79| 356| 79| // temporary range (before calculations) 357| 79| let range = abs(max - min) 358| 79| 359| 79| // in case all values are equal 360| 79| if range == 0.0 361| 79| { 362| 0| max = max + 1.0 363| 0| min = min - 1.0 364| 79| } 365| 79| 366| 79| _axisMinimum = min 367| 79| _axisMaximum = max 368| 79| 369| 79| // actual range 370| 79| axisRange = abs(max - min) 371| 79| } 372| |} /Users/travis/build/danielgindi/Charts/Source/Charts/Components/ChartLimitLine.swift: 1| |// 2| |// ChartLimitLine.swift 3| |// Charts 4| |// 5| |// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda 6| |// A port of MPAndroidChart for iOS 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| | 12| |import Foundation 13| |import CoreGraphics 14| | 15| | 16| |/// The limit line is an additional feature for all Line, Bar and ScatterCharts. 17| |/// It allows the displaying of an additional line in the chart that marks a certain maximum / limit on the specified axis (x- or y-axis). 18| |open class ChartLimitLine: ComponentBase 19| |{ 20| | @objc(ChartLimitLabelPosition) 21| | public enum LabelPosition: Int 22| | { 23| | case topLeft 24| | case topRight 25| | case bottomLeft 26| | case bottomRight 27| | } 28| | 29| | /// limit / maximum (the y-value or xIndex) 30| | @objc open var limit = Double(0.0) 31| | 32| | private var _lineWidth = CGFloat(2.0) 33| | @objc open var lineColor = NSUIColor(red: 237.0/255.0, green: 91.0/255.0, blue: 91.0/255.0, alpha: 1.0) 34| | @objc open var lineDashPhase = CGFloat(0.0) 35| | @objc open var lineDashLengths: [CGFloat]? 36| | 37| | @objc open var valueTextColor = NSUIColor.labelOrBlack 38| | @objc open var valueFont = NSUIFont.systemFont(ofSize: 13.0) 39| | 40| | @objc open var drawLabelEnabled = true 41| | @objc open var label = "" 42| | @objc open var labelPosition = LabelPosition.topRight 43| | 44| | public override init() 45| 0| { 46| 0| super.init() 47| 0| } 48| | 49| | @objc public init(limit: Double) 50| 0| { 51| 0| super.init() 52| 0| self.limit = limit 53| 0| } 54| | 55| | @objc public init(limit: Double, label: String) 56| 0| { 57| 0| super.init() 58| 0| self.limit = limit 59| 0| self.label = label 60| 0| } 61| | 62| | /// set the line width of the chart (min = 0.2, max = 12); default 2 63| | @objc open var lineWidth: CGFloat 64| | { 65| | get 66| 0| { 67| 0| return _lineWidth 68| 0| } 69| | set 70| 0| { 71| 0| _lineWidth = newValue.clamped(to: 0.2...12) 72| 0| } 73| | } 74| |} /Users/travis/build/danielgindi/Charts/Source/Charts/Components/ComponentBase.swift: 1| |// 2| |// ComponentBase.swift 3| |// Charts 4| |// 5| |// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda 6| |// A port of MPAndroidChart for iOS 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| | 12| |import Foundation 13| |import CoreGraphics 14| | 15| | 16| |/// This class encapsulates everything both Axis, Legend and LimitLines have in common 17| |@objc(ChartComponentBase) 18| |open class ComponentBase: NSObject 19| |{ 20| | /// flag that indicates if this component is enabled or not 21| | @objc open var enabled = true 22| | 23| | /// The offset this component has on the x-axis 24| | /// **default**: 5.0 25| | @objc open var xOffset = CGFloat(5.0) 26| | 27| | /// The offset this component has on the x-axis 28| | /// **default**: 5.0 (or 0.0 on ChartYAxis) 29| | @objc open var yOffset = CGFloat(5.0) 30| | 31| | public override init() 32| 248| { 33| 248| super.init() 34| 248| } 35| | 36| 1.39k| @objc open var isEnabled: Bool { return enabled } 37| |} /Users/travis/build/danielgindi/Charts/Source/Charts/Components/Description.swift: 1| |// 2| |// Description.swift 3| |// Charts 4| |// 5| |// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda 6| |// A port of MPAndroidChart for iOS 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| | 12| |import Foundation 13| |import CoreGraphics 14| | 15| |#if canImport(UIKit) 16| | import UIKit 17| |#endif 18| | 19| |#if canImport(Cocoa) 20| |import Cocoa 21| |#endif 22| | 23| |@objc(ChartDescription) 24| |open class Description: ComponentBase 25| |{ 26| | public override init() 27| 52| { 28| 52| #if os(tvOS) 29| 52| // 23 is the smallest recommended font size on the TV 30| 52| font = .systemFont(ofSize: 23) 31| 52| #elseif os(OSX) 32| 52| font = .systemFont(ofSize: NSUIFont.systemFontSize) 33| 52| #else 34| 52| font = .systemFont(ofSize: 8.0) 35| 52| #endif 36| 52| 37| 52| super.init() 38| 52| } 39| | 40| | /// The text to be shown as the description. 41| | @objc open var text: String? 42| | 43| | /// Custom position for the description text in pixels on the screen. 44| | open var position: CGPoint? = nil 45| | 46| | /// The text alignment of the description text. Default RIGHT. 47| | @objc open var textAlign: NSTextAlignment = NSTextAlignment.right 48| | 49| | /// Font object used for drawing the description text. 50| | @objc open var font: NSUIFont 51| | 52| | /// Text color used for drawing the description text 53| | @objc open var textColor = NSUIColor.labelOrBlack 54| |} /Users/travis/build/danielgindi/Charts/Source/Charts/Components/Legend.swift: 1| |// 2| |// Legend.swift 3| |// Charts 4| |// 5| |// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda 6| |// A port of MPAndroidChart for iOS 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| | 12| |import Foundation 13| |import CoreGraphics 14| | 15| |@objc(ChartLegend) 16| |open class Legend: ComponentBase 17| |{ 18| | @objc(ChartLegendForm) 19| | public enum Form: Int 20| | { 21| | /// Avoid drawing a form 22| | case none 23| | 24| | /// Do not draw the a form, but leave space for it 25| | case empty 26| | 27| | /// Use default (default dataset's form to the legend's form) 28| | case `default` 29| | 30| | /// Draw a square 31| | case square 32| | 33| | /// Draw a circle 34| | case circle 35| | 36| | /// Draw a horizontal line 37| | case line 38| | } 39| | 40| | @objc(ChartLegendHorizontalAlignment) 41| | public enum HorizontalAlignment: Int 42| | { 43| | case left 44| | case center 45| | case right 46| | } 47| | 48| | @objc(ChartLegendVerticalAlignment) 49| | public enum VerticalAlignment: Int 50| | { 51| | case top 52| | case center 53| | case bottom 54| | } 55| | 56| | @objc(ChartLegendOrientation) 57| | public enum Orientation: Int 58| | { 59| | case horizontal 60| | case vertical 61| | } 62| | 63| | @objc(ChartLegendDirection) 64| | public enum Direction: Int 65| | { 66| | case leftToRight 67| | case rightToLeft 68| | } 69| | 70| | /// The legend entries array 71| | @objc open var entries = [LegendEntry]() 72| | 73| | /// Entries that will be appended to the end of the auto calculated entries after calculating the legend. 74| | /// (if the legend has already been calculated, you will need to call notifyDataSetChanged() to let the changes take effect) 75| | @objc open var extraEntries = [LegendEntry]() 76| | 77| | /// Are the legend labels/colors a custom value or auto calculated? If false, then it's auto, if true, then custom. 78| | /// 79| | /// **default**: false (automatic legend) 80| | private var _isLegendCustom = false 81| | 82| | /// The horizontal alignment of the legend 83| | @objc open var horizontalAlignment: HorizontalAlignment = HorizontalAlignment.left 84| | 85| | /// The vertical alignment of the legend 86| | @objc open var verticalAlignment: VerticalAlignment = VerticalAlignment.bottom 87| | 88| | /// The orientation of the legend 89| | @objc open var orientation: Orientation = Orientation.horizontal 90| | 91| | /// Flag indicating whether the legend will draw inside the chart or outside 92| | @objc open var drawInside: Bool = false 93| | 94| | /// Flag indicating whether the legend will draw inside the chart or outside 95| 0| @objc open var isDrawInsideEnabled: Bool { return drawInside } 96| | 97| | /// The text direction of the legend 98| | @objc open var direction: Direction = Direction.leftToRight 99| | 100| | @objc open var font: NSUIFont = NSUIFont.systemFont(ofSize: 10.0) 101| | @objc open var textColor = NSUIColor.labelOrBlack 102| | 103| | /// The form/shape of the legend forms 104| | @objc open var form = Form.square 105| | 106| | /// The size of the legend forms 107| | @objc open var formSize = CGFloat(8.0) 108| | 109| | /// The line width for forms that consist of lines 110| | @objc open var formLineWidth = CGFloat(3.0) 111| | 112| | /// Line dash configuration for shapes that consist of lines. 113| | /// 114| | /// This is how much (in pixels) into the dash pattern are we starting from. 115| | @objc open var formLineDashPhase: CGFloat = 0.0 116| | 117| | /// Line dash configuration for shapes that consist of lines. 118| | /// 119| | /// This is the actual dash pattern. 120| | /// I.e. [2, 3] will paint [-- -- ] 121| | /// [1, 3, 4, 2] will paint [- ---- - ---- ] 122| | @objc open var formLineDashLengths: [CGFloat]? 123| | 124| | @objc open var xEntrySpace = CGFloat(6.0) 125| | @objc open var yEntrySpace = CGFloat(0.0) 126| | @objc open var formToTextSpace = CGFloat(5.0) 127| | @objc open var stackSpace = CGFloat(3.0) 128| | 129| | @objc open var calculatedLabelSizes = [CGSize]() 130| | @objc open var calculatedLabelBreakPoints = [Bool]() 131| | @objc open var calculatedLineSizes = [CGSize]() 132| | 133| | public override init() 134| 52| { 135| 52| super.init() 136| 52| 137| 52| self.xOffset = 5.0 138| 52| self.yOffset = 3.0 139| 52| } 140| | 141| | @objc public init(entries: [LegendEntry]) 142| 0| { 143| 0| super.init() 144| 0| 145| 0| self.entries = entries 146| 0| } 147| | 148| | @objc open func getMaximumEntrySize(withFont font: NSUIFont) -> CGSize 149| 85| { 150| 85| var maxW = CGFloat(0.0) 151| 85| var maxH = CGFloat(0.0) 152| 85| 153| 85| var maxFormSize: CGFloat = 0.0 154| 85| 155| 85| for entry in entries 156| 180| { 157| 180| let formSize = entry.formSize.isNaN ? self.formSize : entry.formSize 158| 180| if formSize > maxFormSize 159| 180| { 160| 85| maxFormSize = formSize 161| 180| } 162| 180| 163| 180| guard let label = entry.label 164| 180| else { continue } 165| 90| 166| 90| let size = (label as NSString).size(withAttributes: [.font: font]) 167| 90| 168| 90| if size.width > maxW 169| 90| { 170| 85| maxW = size.width 171| 90| } 172| 90| if size.height > maxH 173| 90| { 174| 85| maxH = size.height 175| 90| } 176| 90| } 177| 85| 178| 85| return CGSize( 179| 85| width: maxW + maxFormSize + formToTextSpace, 180| 85| height: maxH 181| 85| ) 182| 85| } 183| | 184| | @objc open var neededWidth = CGFloat(0.0) 185| | @objc open var neededHeight = CGFloat(0.0) 186| | @objc open var textWidthMax = CGFloat(0.0) 187| | @objc open var textHeightMax = CGFloat(0.0) 188| | 189| | /// flag that indicates if word wrapping is enabled 190| | /// this is currently supported only for `orientation == Horizontal`. 191| | /// you may want to set maxSizePercent when word wrapping, to set the point where the text wraps. 192| | /// 193| | /// **default**: true 194| | @objc open var wordWrapEnabled = true 195| | 196| | /// if this is set, then word wrapping the legend is enabled. 197| 0| @objc open var isWordWrapEnabled: Bool { return wordWrapEnabled } 198| | 199| | /// The maximum relative size out of the whole chart view in percent. 200| | /// If the legend is to the right/left of the chart, then this affects the width of the legend. 201| | /// If the legend is to the top/bottom of the chart, then this affects the height of the legend. 202| | /// 203| | /// **default**: 0.95 (95%) 204| | @objc open var maxSizePercent: CGFloat = 0.95 205| | 206| | @objc open func calculateDimensions(labelFont: NSUIFont, viewPortHandler: ViewPortHandler) 207| 85| { 208| 85| let maxEntrySize = getMaximumEntrySize(withFont: labelFont) 209| 85| let defaultFormSize = self.formSize 210| 85| let stackSpace = self.stackSpace 211| 85| let formToTextSpace = self.formToTextSpace 212| 85| let xEntrySpace = self.xEntrySpace 213| 85| let yEntrySpace = self.yEntrySpace 214| 85| let wordWrapEnabled = self.wordWrapEnabled 215| 85| let entries = self.entries 216| 85| let entryCount = entries.count 217| 85| 218| 85| textWidthMax = maxEntrySize.width 219| 85| textHeightMax = maxEntrySize.height 220| 85| 221| 85| switch orientation 222| 85| { 223| 85| case .vertical: 224| 0| 225| 0| var maxWidth = CGFloat(0.0) 226| 0| var width = CGFloat(0.0) 227| 0| var maxHeight = CGFloat(0.0) 228| 0| let labelLineHeight = labelFont.lineHeight 229| 0| 230| 0| var wasStacked = false 231| 0| 232| 0| for i in 0 ..< entryCount 233| 0| { 234| 0| let e = entries[i] 235| 0| let drawingForm = e.form != .none 236| 0| let formSize = e.formSize.isNaN ? defaultFormSize : e.formSize 237| 0| let label = e.label 238| 0| 239| 0| if !wasStacked 240| 0| { 241| 0| width = 0.0 242| 0| } 243| 0| 244| 0| if drawingForm 245| 0| { 246| 0| if wasStacked 247| 0| { 248| 0| width += stackSpace 249| 0| } 250| 0| width += formSize 251| 0| } 252| 0| 253| 0| if label != nil 254| 0| { 255| 0| let size = (label! as NSString).size(withAttributes: [.font: labelFont]) 256| 0| 257| 0| if drawingForm && !wasStacked 258| 0| { 259| 0| width += formToTextSpace 260| 0| } 261| 0| else if wasStacked 262| 0| { 263| 0| maxWidth = max(maxWidth, width) 264| 0| maxHeight += labelLineHeight + yEntrySpace 265| 0| width = 0.0 266| 0| wasStacked = false 267| 0| } 268| 0| 269| 0| width += size.width 270| 0| maxHeight += labelLineHeight + yEntrySpace 271| 0| } 272| 0| else 273| 0| { 274| 0| wasStacked = true 275| 0| width += formSize 276| 0| 277| 0| if i < entryCount - 1 278| 0| { 279| 0| width += stackSpace 280| 0| } 281| 0| } 282| 0| 283| 0| maxWidth = max(maxWidth, width) 284| 0| } 285| 0| 286| 0| neededWidth = maxWidth 287| 0| neededHeight = maxHeight 288| 85| 289| 85| case .horizontal: 290| 85| 291| 85| let labelLineHeight = labelFont.lineHeight 292| 85| 293| 85| let contentWidth: CGFloat = viewPortHandler.contentWidth * maxSizePercent 294| 85| 295| 85| // Prepare arrays for calculated layout 296| 85| if calculatedLabelSizes.count != entryCount 297| 85| { 298| 52| calculatedLabelSizes = [CGSize](repeating: CGSize(), count: entryCount) 299| 85| } 300| 85| 301| 85| if calculatedLabelBreakPoints.count != entryCount 302| 85| { 303| 52| calculatedLabelBreakPoints = [Bool](repeating: false, count: entryCount) 304| 85| } 305| 85| 306| 85| calculatedLineSizes.removeAll(keepingCapacity: true) 307| 85| 308| 85| // Start calculating layout 309| 85| 310| 85| let labelAttrs = [NSAttributedString.Key.font: labelFont] 311| 85| var maxLineWidth: CGFloat = 0.0 312| 85| var currentLineWidth: CGFloat = 0.0 313| 85| var requiredWidth: CGFloat = 0.0 314| 85| var stackedStartIndex: Int = -1 315| 85| 316| 85| for i in 0 ..< entryCount 317| 180| { 318| 180| let e = entries[i] 319| 180| let drawingForm = e.form != .none 320| 180| let label = e.label 321| 180| 322| 180| calculatedLabelBreakPoints[i] = false 323| 180| 324| 180| if stackedStartIndex == -1 325| 180| { 326| 90| // we are not stacking, so required width is for this label only 327| 90| requiredWidth = 0.0 328| 180| } 329| 180| else 330| 180| { 331| 90| // add the spacing appropriate for stacked labels/forms 332| 90| requiredWidth += stackSpace 333| 180| } 334| 180| 335| 180| // grouped forms have null labels 336| 180| if label != nil 337| 180| { 338| 90| calculatedLabelSizes[i] = (label! as NSString).size(withAttributes: labelAttrs) 339| 90| requiredWidth += drawingForm ? formToTextSpace + formSize : 0.0 340| 90| requiredWidth += calculatedLabelSizes[i].width 341| 180| } 342| 180| else 343| 180| { 344| 90| calculatedLabelSizes[i] = CGSize() 345| 90| requiredWidth += drawingForm ? formSize : 0.0 346| 90| 347| 90| if stackedStartIndex == -1 348| 90| { 349| 18| // mark this index as we might want to break here later 350| 18| stackedStartIndex = i 351| 90| } 352| 180| } 353| 180| 354| 180| if label != nil || i == entryCount - 1 355| 180| { 356| 90| let requiredSpacing = currentLineWidth == 0.0 ? 0.0 : xEntrySpace 357| 90| 358| 90| if (!wordWrapEnabled || // No word wrapping, it must fit. 359| 90| currentLineWidth == 0.0 || // The line is empty, it must fit. 360| 90| (contentWidth - currentLineWidth >= requiredSpacing + requiredWidth)) // It simply fits 361| 90| { 362| 90| // Expand current line 363| 90| currentLineWidth += requiredSpacing + requiredWidth 364| 90| } 365| 90| else 366| 90| { // It doesn't fit, we need to wrap a line 367| 0| 368| 0| // Add current line size to array 369| 0| calculatedLineSizes.append(CGSize(width: currentLineWidth, height: labelLineHeight)) 370| 0| maxLineWidth = max(maxLineWidth, currentLineWidth) 371| 0| 372| 0| // Start a new line 373| 0| calculatedLabelBreakPoints[stackedStartIndex > -1 ? stackedStartIndex : i] = true 374| 0| currentLineWidth = requiredWidth 375| 90| } 376| 90| 377| 90| if i == entryCount - 1 378| 90| { // Add last line size to array 379| 85| calculatedLineSizes.append(CGSize(width: currentLineWidth, height: labelLineHeight)) 380| 85| maxLineWidth = max(maxLineWidth, currentLineWidth) 381| 90| } 382| 180| } 383| 180| 384| 180| stackedStartIndex = label != nil ? -1 : stackedStartIndex 385| 180| } 386| 85| 387| 85| neededWidth = maxLineWidth 388| 85| neededHeight = labelLineHeight * CGFloat(calculatedLineSizes.count) + 389| 85| yEntrySpace * CGFloat(calculatedLineSizes.count == 0 ? 0 : (calculatedLineSizes.count - 1)) 390| 85| } 391| 85| 392| 85| neededWidth += xOffset 393| 85| neededHeight += yOffset 394| 85| } 395| | 396| | /// MARK: - Custom legend 397| | 398| | /// Sets a custom legend's entries array. 399| | /// * A nil label will start a group. 400| | /// This will disable the feature that automatically calculates the legend entries from the datasets. 401| | /// Call `resetCustom(...)` to re-enable automatic calculation (and then `notifyDataSetChanged()` is needed). 402| | @objc open func setCustom(entries: [LegendEntry]) 403| 0| { 404| 0| self.entries = entries 405| 0| _isLegendCustom = true 406| 0| } 407| | 408| | /// Calling this will disable the custom legend entries (set by `setLegend(...)`). Instead, the entries will again be calculated automatically (after `notifyDataSetChanged()` is called). 409| | @objc open func resetCustom() 410| 0| { 411| 0| _isLegendCustom = false 412| 0| } 413| | 414| | /// **default**: false (automatic legend) 415| | /// `true` if a custom legend entries has been set 416| | @objc open var isLegendCustom: Bool 417| 85| { 418| 85| return _isLegendCustom 419| 85| } 420| |} /Users/travis/build/danielgindi/Charts/Source/Charts/Components/LegendEntry.swift: 1| |// 2| |// LegendEntry.swift 3| |// Charts 4| |// 5| |// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda 6| |// A port of MPAndroidChart for iOS 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| | 12| |import Foundation 13| |import CoreGraphics 14| | 15| |@objc(ChartLegendEntry) 16| |open class LegendEntry: NSObject 17| |{ 18| | public override init() 19| 0| { 20| 0| super.init() 21| 0| } 22| | 23| | /// - Parameters: 24| | /// - label: The legend entry text. 25| | /// A `nil` label will start a group. 26| | /// - form: The form to draw for this entry. 27| | /// - formSize: Set to NaN to use the legend's default. 28| | /// - formLineWidth: Set to NaN to use the legend's default. 29| | /// - formLineDashPhase: Line dash configuration. 30| | /// - formLineDashLengths: Line dash configurationas NaN to use the legend's default. 31| | /// - formColor: The color for drawing the form. 32| | @objc public init(label: String?, 33| | form: Legend.Form, 34| | formSize: CGFloat, 35| | formLineWidth: CGFloat, 36| | formLineDashPhase: CGFloat, 37| | formLineDashLengths: [CGFloat]?, 38| | formColor: NSUIColor?) 39| 180| { 40| 180| self.label = label 41| 180| self.form = form 42| 180| self.formSize = formSize 43| 180| self.formLineWidth = formLineWidth 44| 180| self.formLineDashPhase = formLineDashPhase 45| 180| self.formLineDashLengths = formLineDashLengths 46| 180| self.formColor = formColor 47| 180| } 48| | 49| | /// The legend entry text. 50| | /// A `nil` label will start a group. 51| | @objc open var label: String? 52| | 53| | /// The form to draw for this entry. 54| | /// 55| | /// `None` will avoid drawing a form, and any related space. 56| | /// `Empty` will avoid drawing a form, but keep its space. 57| | /// `Default` will use the Legend's default. 58| | @objc open var form: Legend.Form = .default 59| | 60| | /// Form size will be considered except for when .None is used 61| | /// 62| | /// Set as NaN to use the legend's default 63| | @objc open var formSize: CGFloat = CGFloat.nan 64| | 65| | /// Line width used for shapes that consist of lines. 66| | /// 67| | /// Set to NaN to use the legend's default. 68| | @objc open var formLineWidth: CGFloat = CGFloat.nan 69| | 70| | /// Line dash configuration for shapes that consist of lines. 71| | /// 72| | /// This is how much (in pixels) into the dash pattern are we starting from. 73| | /// 74| | /// Set to NaN to use the legend's default. 75| | @objc open var formLineDashPhase: CGFloat = 0.0 76| | 77| | /// Line dash configuration for shapes that consist of lines. 78| | /// 79| | /// This is the actual dash pattern. 80| | /// I.e. [2, 3] will paint [-- -- ] 81| | /// [1, 3, 4, 2] will paint [- ---- - ---- ] 82| | /// 83| | /// Set to nil to use the legend's default. 84| | @objc open var formLineDashLengths: [CGFloat]? 85| | 86| | /// The color for drawing the form 87| | @objc open var formColor: NSUIColor? 88| |} /Users/travis/build/danielgindi/Charts/Source/Charts/Components/MarkerImage.swift: 1| |// 2| |// ChartMarkerImage.swift 3| |// Charts 4| |// 5| |// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda 6| |// A port of MPAndroidChart for iOS 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| | 12| |import Foundation 13| |import CoreGraphics 14| | 15| |@objc(ChartMarkerImage) 16| |open class MarkerImage: NSObject, IMarker 17| |{ 18| | /// The marker image to render 19| | @objc open var image: NSUIImage? 20| | 21| | open var offset: CGPoint = CGPoint() 22| | 23| | @objc open weak var chartView: ChartViewBase? 24| | 25| | /// As long as size is 0.0/0.0 - it will default to the image's size 26| | @objc open var size: CGSize = CGSize() 27| | 28| | public override init() 29| 0| { 30| 0| super.init() 31| 0| } 32| | 33| | open func offsetForDrawing(atPoint point: CGPoint) -> CGPoint 34| 0| { 35| 0| var offset = self.offset 36| 0| 37| 0| let chart = self.chartView 38| 0| 39| 0| var size = self.size 40| 0| 41| 0| if size.width == 0.0 && image != nil 42| 0| { 43| 0| size.width = image?.size.width ?? 0.0 44| 0| } 45| 0| if size.height == 0.0 && image != nil 46| 0| { 47| 0| size.height = image?.size.height ?? 0.0 48| 0| } 49| 0| 50| 0| let width = size.width 51| 0| let height = size.height 52| 0| 53| 0| if point.x + offset.x < 0.0 54| 0| { 55| 0| offset.x = -point.x 56| 0| } 57| 0| else if chart != nil && point.x + width + offset.x > chart!.bounds.size.width 58| 0| { 59| 0| offset.x = chart!.bounds.size.width - point.x - width 60| 0| } 61| 0| 62| 0| if point.y + offset.y < 0 63| 0| { 64| 0| offset.y = -point.y 65| 0| } 66| 0| else if chart != nil && point.y + height + offset.y > chart!.bounds.size.height 67| 0| { 68| 0| offset.y = chart!.bounds.size.height - point.y - height 69| 0| } 70| 0| 71| 0| return offset 72| 0| } 73| | 74| | open func refreshContent(entry: ChartDataEntry, highlight: Highlight) 75| 0| { 76| 0| // Do nothing here... 77| 0| } 78| | 79| | open func draw(context: CGContext, point: CGPoint) 80| 0| { 81| 0| guard let image = image else { return } 82| 0| 83| 0| let offset = offsetForDrawing(atPoint: point) 84| 0| 85| 0| var size = self.size 86| 0| 87| 0| if size.width == 0.0 88| 0| { 89| 0| size.width = image.size.width 90| 0| } 91| 0| if size.height == 0.0 92| 0| { 93| 0| size.height = image.size.height 94| 0| } 95| 0| 96| 0| let rect = CGRect( 97| 0| x: point.x + offset.x, 98| 0| y: point.y + offset.y, 99| 0| width: size.width, 100| 0| height: size.height) 101| 0| 102| 0| NSUIGraphicsPushContext(context) 103| 0| image.draw(in: rect) 104| 0| NSUIGraphicsPopContext() 105| 0| } 106| |} /Users/travis/build/danielgindi/Charts/Source/Charts/Components/MarkerView.swift: 1| |// 2| |// ChartMarkerView.swift 3| |// Charts 4| |// 5| |// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda 6| |// A port of MPAndroidChart for iOS 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| | 12| |import Foundation 13| |import CoreGraphics 14| | 15| |#if canImport(AppKit) 16| |import AppKit 17| |#endif 18| | 19| |@objc(ChartMarkerView) 20| |open class MarkerView: NSUIView, IMarker 21| |{ 22| | open var offset: CGPoint = CGPoint() 23| | 24| | @objc open weak var chartView: ChartViewBase? 25| | 26| | open func offsetForDrawing(atPoint point: CGPoint) -> CGPoint 27| 0| { 28| 0| guard let chart = chartView else { return self.offset } 29| 0| 30| 0| var offset = self.offset 31| 0| 32| 0| let width = self.bounds.size.width 33| 0| let height = self.bounds.size.height 34| 0| 35| 0| if point.x + offset.x < 0.0 36| 0| { 37| 0| offset.x = -point.x 38| 0| } 39| 0| else if point.x + width + offset.x > chart.bounds.size.width 40| 0| { 41| 0| offset.x = chart.bounds.size.width - point.x - width 42| 0| } 43| 0| 44| 0| if point.y + offset.y < 0 45| 0| { 46| 0| offset.y = -point.y 47| 0| } 48| 0| else if point.y + height + offset.y > chart.bounds.size.height 49| 0| { 50| 0| offset.y = chart.bounds.size.height - point.y - height 51| 0| } 52| 0| 53| 0| return offset 54| 0| } 55| | 56| | open func refreshContent(entry: ChartDataEntry, highlight: Highlight) 57| 0| { 58| 0| // Do nothing here... 59| 0| } 60| | 61| | open func draw(context: CGContext, point: CGPoint) 62| 0| { 63| 0| let offset = self.offsetForDrawing(atPoint: point) 64| 0| 65| 0| context.saveGState() 66| 0| context.translateBy(x: point.x + offset.x, 67| 0| y: point.y + offset.y) 68| 0| NSUIGraphicsPushContext(context) 69| 0| self.nsuiLayer?.render(in: context) 70| 0| NSUIGraphicsPopContext() 71| 0| context.restoreGState() 72| 0| } 73| | 74| | @objc 75| | open class func viewFromXib(in bundle: Bundle = .main) -> MarkerView? 76| 0| { 77| 0| #if !os(OSX) 78| 0| 79| 0| return bundle.loadNibNamed( 80| 0| String(describing: self), 81| 0| owner: nil, 82| 0| options: nil)?[0] as? MarkerView 83| 0| #else 84| 0| 85| 0| var loadedObjects = NSArray() 86| 0| let loadedObjectsPointer = AutoreleasingUnsafeMutablePointer(&loadedObjects) 87| 0| 88| 0| if bundle.loadNibNamed( 89| 0| NSNib.Name(String(describing: self)), 90| 0| owner: nil, 91| 0| topLevelObjects: loadedObjectsPointer) 92| 0| { 93| 0| return loadedObjects[0] as? MarkerView 94| 0| } 95| 0| 96| 0| return nil 97| 0| #endif 98| 0| } 99| | 100| |} /Users/travis/build/danielgindi/Charts/Source/Charts/Components/XAxis.swift: 1| |// 2| |// XAxis.swift 3| |// Charts 4| |// 5| |// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda 6| |// A port of MPAndroidChart for iOS 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| | 12| |import Foundation 13| |import CoreGraphics 14| | 15| |@objc(ChartXAxis) 16| |open class XAxis: AxisBase 17| |{ 18| | @objc(XAxisLabelPosition) 19| | public enum LabelPosition: Int 20| | { 21| | case top 22| | case bottom 23| | case bothSided 24| | case topInside 25| | case bottomInside 26| | } 27| | 28| | /// width of the x-axis labels in pixels - this is automatically calculated by the `computeSize()` methods in the renderers 29| | @objc open var labelWidth = CGFloat(1.0) 30| | 31| | /// height of the x-axis labels in pixels - this is automatically calculated by the `computeSize()` methods in the renderers 32| | @objc open var labelHeight = CGFloat(1.0) 33| | 34| | /// width of the (rotated) x-axis labels in pixels - this is automatically calculated by the `computeSize()` methods in the renderers 35| | @objc open var labelRotatedWidth = CGFloat(1.0) 36| | 37| | /// height of the (rotated) x-axis labels in pixels - this is automatically calculated by the `computeSize()` methods in the renderers 38| | @objc open var labelRotatedHeight = CGFloat(1.0) 39| | 40| | /// This is the angle for drawing the X axis labels (in degrees) 41| | @objc open var labelRotationAngle = CGFloat(0.0) 42| | 43| | /// if set to true, the chart will avoid that the first and last label entry in the chart "clip" off the edge of the chart 44| | @objc open var avoidFirstLastClippingEnabled = false 45| | 46| | /// the position of the x-labels relative to the chart 47| | @objc open var labelPosition = LabelPosition.top 48| | 49| | /// if set to true, word wrapping the labels will be enabled. 50| | /// word wrapping is done using `(value width * labelRotatedWidth)` 51| | /// 52| | /// - Note: currently supports all charts except pie/radar/horizontal-bar* 53| | @objc open var wordWrapEnabled = false 54| | 55| | /// `true` if word wrapping the labels is enabled 56| 40| @objc open var isWordWrapEnabled: Bool { return wordWrapEnabled } 57| | 58| | /// the width for wrapping the labels, as percentage out of one value width. 59| | /// used only when isWordWrapEnabled = true. 60| | /// 61| | /// **default**: 1.0 62| | @objc open var wordWrapWidthPercent: CGFloat = 1.0 63| | 64| | public override init() 65| 52| { 66| 52| super.init() 67| 52| 68| 52| self.yOffset = 4.0 69| 52| } 70| | 71| | @objc open var isAvoidFirstLastClippingEnabled: Bool 72| 240| { 73| 240| return avoidFirstLastClippingEnabled 74| 240| } 75| |} /Users/travis/build/danielgindi/Charts/Source/Charts/Components/YAxis.swift: 1| |// 2| |// YAxis.swift 3| |// Charts 4| |// 5| |// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda 6| |// A port of MPAndroidChart for iOS 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| | 12| |import Foundation 13| |import CoreGraphics 14| | 15| |#if canImport(UIKit) 16| | import UIKit 17| |#endif 18| | 19| |#if canImport(Cocoa) 20| |import Cocoa 21| |#endif 22| | 23| | 24| |/// Class representing the y-axis labels settings and its entries. 25| |/// Be aware that not all features the YLabels class provides are suitable for the RadarChart. 26| |/// Customizations that affect the value range of the axis need to be applied before setting data for the chart. 27| |@objc(ChartYAxis) 28| |open class YAxis: AxisBase 29| |{ 30| | @objc(YAxisLabelPosition) 31| | public enum LabelPosition: Int 32| | { 33| | case outsideChart 34| | case insideChart 35| | } 36| | 37| | /// Enum that specifies the axis a DataSet should be plotted against, either Left or Right. 38| | @objc 39| | public enum AxisDependency: Int 40| | { 41| | case left 42| | case right 43| | } 44| | 45| | /// indicates if the bottom y-label entry is drawn or not 46| | @objc open var drawBottomYLabelEntryEnabled = true 47| | 48| | /// indicates if the top y-label entry is drawn or not 49| | @objc open var drawTopYLabelEntryEnabled = true 50| | 51| | /// flag that indicates if the axis is inverted or not 52| | @objc open var inverted = false 53| | 54| | /// flag that indicates if the zero-line should be drawn regardless of other grid lines 55| | @objc open var drawZeroLineEnabled = false 56| | 57| | /// Color of the zero line 58| | @objc open var zeroLineColor: NSUIColor? = NSUIColor.gray 59| | 60| | /// Width of the zero line 61| | @objc open var zeroLineWidth: CGFloat = 1.0 62| | 63| | /// This is how much (in pixels) into the dash pattern are we starting from. 64| | @objc open var zeroLineDashPhase = CGFloat(0.0) 65| | 66| | /// This is the actual dash pattern. 67| | /// I.e. [2, 3] will paint [-- -- ] 68| | /// [1, 3, 4, 2] will paint [- ---- - ---- ] 69| | @objc open var zeroLineDashLengths: [CGFloat]? 70| | 71| | /// axis space from the largest value to the top in percent of the total axis range 72| | @objc open var spaceTop = CGFloat(0.1) 73| | 74| | /// axis space from the smallest value to the bottom in percent of the total axis range 75| | @objc open var spaceBottom = CGFloat(0.1) 76| | 77| | /// the position of the y-labels relative to the chart 78| | @objc open var labelPosition = LabelPosition.outsideChart 79| | 80| | /// the alignment of the text in the y-label 81| | @objc open var labelAlignment: NSTextAlignment = .left 82| | 83| | /// the horizontal offset of the y-label 84| | @objc open var labelXOffset: CGFloat = 0.0 85| | 86| | /// the side this axis object represents 87| | private var _axisDependency = AxisDependency.left 88| | 89| | /// the minimum width that the axis should take 90| | /// 91| | /// **default**: 0.0 92| | @objc open var minWidth = CGFloat(0) 93| | 94| | /// the maximum width that the axis can take. 95| | /// use Infinity for disabling the maximum. 96| | /// 97| | /// **default**: CGFloat.infinity 98| | @objc open var maxWidth = CGFloat(CGFloat.infinity) 99| | 100| | public override init() 101| 0| { 102| 0| super.init() 103| 0| 104| 0| self.yOffset = 0.0 105| 0| } 106| | 107| | @objc public init(position: AxisDependency) 108| 92| { 109| 92| super.init() 110| 92| 111| 92| _axisDependency = position 112| 92| 113| 92| self.yOffset = 0.0 114| 92| } 115| | 116| | @objc open var axisDependency: AxisDependency 117| 180| { 118| 180| return _axisDependency 119| 180| } 120| | 121| | @objc open func requiredSize() -> CGSize 122| 263| { 123| 263| let label = getLongestLabel() as NSString 124| 263| var size = label.size(withAttributes: [NSAttributedString.Key.font: labelFont]) 125| 263| size.width += xOffset * 2.0 126| 263| size.height += yOffset * 2.0 127| 263| size.width = max(minWidth, min(size.width, maxWidth > 0.0 ? maxWidth : size.width)) 128| 263| return size 129| 263| } 130| | 131| | @objc open func getRequiredHeightSpace() -> CGFloat 132| 51| { 133| 51| return requiredSize().height 134| 51| } 135| | 136| | /// `true` if this axis needs horizontal offset, `false` ifno offset is needed. 137| | @objc open var needsOffset: Bool 138| 250| { 139| 250| if isEnabled && isDrawLabelsEnabled && labelPosition == .outsideChart 140| 250| { 141| 246| return true 142| 246| } 143| 4| else 144| 4| { 145| 4| return false 146| 4| } 147| 0| } 148| | 149| 574| @objc open var isInverted: Bool { return inverted } 150| | 151| | open override func calculate(min dataMin: Double, max dataMax: Double) 152| 158| { 153| 158| // if custom, use value as is, else use data value 154| 158| var min = _customAxisMin ? _axisMinimum : dataMin 155| 158| var max = _customAxisMax ? _axisMaximum : dataMax 156| 158| 157| 158| // Make sure max is greater than min 158| 158| // Discussion: https://github.com/danielgindi/Charts/pull/3650#discussion_r221409991 159| 158| if min > max 160| 158| { 161| 4| switch(_customAxisMax, _customAxisMin) 162| 4| { 163| 4| case(true, true): 164| 0| (min, max) = (max, min) 165| 4| case(true, false): 166| 2| min = max < 0 ? max * 1.5 : max * 0.5 167| 4| case(false, true): 168| 2| max = min < 0 ? min * 0.5 : min * 1.5 169| 4| case(false, false): 170| 0| break 171| 4| } 172| 158| } 173| 158| 174| 158| // temporary range (before calculations) 175| 158| let range = abs(max - min) 176| 158| 177| 158| // in case all values are equal 178| 158| if range == 0.0 179| 158| { 180| 2| max = max + 1.0 181| 2| min = min - 1.0 182| 158| } 183| 158| 184| 158| // bottom-space only effects non-custom min 185| 158| if !_customAxisMin 186| 158| { 187| 130| let bottomSpace = range * Double(spaceBottom) 188| 130| _axisMinimum = (min - bottomSpace) 189| 158| } 190| 158| 191| 158| // top-space only effects non-custom max 192| 158| if !_customAxisMax 193| 158| { 194| 152| let topSpace = range * Double(spaceTop) 195| 152| _axisMaximum = (max + topSpace) 196| 158| } 197| 158| 198| 158| // calc actual range 199| 158| axisRange = abs(_axisMaximum - _axisMinimum) 200| 158| } 201| | 202| 90| @objc open var isDrawBottomYLabelEntryEnabled: Bool { return drawBottomYLabelEntryEnabled } 203| | 204| 90| @objc open var isDrawTopYLabelEntryEnabled: Bool { return drawTopYLabelEntryEnabled } 205| | 206| |} /Users/travis/build/danielgindi/Charts/Source/Charts/Data/Implementations/ChartBaseDataSet.swift: 1| |// 2| |// BaseDataSet.swift 3| |// Charts 4| |// 5| |// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda 6| |// A port of MPAndroidChart for iOS 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| | 12| |import Foundation 13| |import CoreGraphics 14| | 15| | 16| |open class ChartBaseDataSet: NSObject, IChartDataSet, NSCopying 17| |{ 18| | public required override init() 19| 0| { 20| 0| super.init() 21| 0| 22| 0| // default color 23| 0| colors.append(NSUIColor(red: 140.0/255.0, green: 234.0/255.0, blue: 255.0/255.0, alpha: 1.0)) 24| 0| valueColors.append(.labelOrBlack) 25| 0| } 26| | 27| | @objc public init(label: String?) 28| 64| { 29| 64| super.init() 30| 64| 31| 64| // default color 32| 64| colors.append(NSUIColor(red: 140.0/255.0, green: 234.0/255.0, blue: 255.0/255.0, alpha: 1.0)) 33| 64| valueColors.append(.labelOrBlack) 34| 64| 35| 64| self.label = label 36| 64| } 37| | 38| | // MARK: - Data functions and accessors 39| | 40| | /// Use this method to tell the data set that the underlying data has changed 41| | open func notifyDataSetChanged() 42| 0| { 43| 0| calcMinMax() 44| 0| } 45| | 46| | open func calcMinMax() 47| 0| { 48| 0| fatalError("calcMinMax is not implemented in ChartBaseDataSet") 49| 0| } 50| | 51| | open func calcMinMaxY(fromX: Double, toX: Double) 52| 0| { 53| 0| fatalError("calcMinMaxY(fromX:, toX:) is not implemented in ChartBaseDataSet") 54| 0| } 55| | 56| | open var yMin: Double 57| 0| { 58| 0| fatalError("yMin is not implemented in ChartBaseDataSet") 59| 0| } 60| | 61| | open var yMax: Double 62| 0| { 63| 0| fatalError("yMax is not implemented in ChartBaseDataSet") 64| 0| } 65| | 66| | open var xMin: Double 67| 0| { 68| 0| fatalError("xMin is not implemented in ChartBaseDataSet") 69| 0| } 70| | 71| | open var xMax: Double 72| 0| { 73| 0| fatalError("xMax is not implemented in ChartBaseDataSet") 74| 0| } 75| | 76| | open var entryCount: Int 77| 0| { 78| 0| fatalError("entryCount is not implemented in ChartBaseDataSet") 79| 0| } 80| | 81| | open func entryForIndex(_ i: Int) -> ChartDataEntry? 82| 0| { 83| 0| fatalError("entryForIndex is not implemented in ChartBaseDataSet") 84| 0| } 85| | 86| | open func entryForXValue( 87| | _ x: Double, 88| | closestToY y: Double, 89| | rounding: ChartDataSetRounding) -> ChartDataEntry? 90| 0| { 91| 0| fatalError("entryForXValue(x, closestToY, rounding) is not implemented in ChartBaseDataSet") 92| 0| } 93| | 94| | open func entryForXValue( 95| | _ x: Double, 96| | closestToY y: Double) -> ChartDataEntry? 97| 0| { 98| 0| fatalError("entryForXValue(x, closestToY) is not implemented in ChartBaseDataSet") 99| 0| } 100| | 101| | open func entriesForXValue(_ x: Double) -> [ChartDataEntry] 102| 0| { 103| 0| fatalError("entriesForXValue is not implemented in ChartBaseDataSet") 104| 0| } 105| | 106| | open func entryIndex( 107| | x xValue: Double, 108| | closestToY y: Double, 109| | rounding: ChartDataSetRounding) -> Int 110| 0| { 111| 0| fatalError("entryIndex(x, closestToY, rounding) is not implemented in ChartBaseDataSet") 112| 0| } 113| | 114| | open func entryIndex(entry e: ChartDataEntry) -> Int 115| 0| { 116| 0| fatalError("entryIndex(entry) is not implemented in ChartBaseDataSet") 117| 0| } 118| | 119| | open func addEntry(_ e: ChartDataEntry) -> Bool 120| 0| { 121| 0| fatalError("addEntry is not implemented in ChartBaseDataSet") 122| 0| } 123| | 124| | open func addEntryOrdered(_ e: ChartDataEntry) -> Bool 125| 0| { 126| 0| fatalError("addEntryOrdered is not implemented in ChartBaseDataSet") 127| 0| } 128| | 129| | @discardableResult open func removeEntry(_ entry: ChartDataEntry) -> Bool 130| 0| { 131| 0| fatalError("removeEntry is not implemented in ChartBaseDataSet") 132| 0| } 133| | 134| | @discardableResult open func removeEntry(index: Int) -> Bool 135| 0| { 136| 0| if let entry = entryForIndex(index) 137| 0| { 138| 0| return removeEntry(entry) 139| 0| } 140| 0| return false 141| 0| } 142| | 143| | @discardableResult open func removeEntry(x: Double) -> Bool 144| 0| { 145| 0| if let entry = entryForXValue(x, closestToY: Double.nan) 146| 0| { 147| 0| return removeEntry(entry) 148| 0| } 149| 0| return false 150| 0| } 151| | 152| | @discardableResult open func removeFirst() -> Bool 153| 0| { 154| 0| if entryCount > 0 155| 0| { 156| 0| if let entry = entryForIndex(0) 157| 0| { 158| 0| return removeEntry(entry) 159| 0| } 160| 0| } 161| 0| return false 162| 0| } 163| | 164| | @discardableResult open func removeLast() -> Bool 165| 0| { 166| 0| if entryCount > 0 167| 0| { 168| 0| if let entry = entryForIndex(entryCount - 1) 169| 0| { 170| 0| return removeEntry(entry) 171| 0| } 172| 0| } 173| 0| return false 174| 0| } 175| | 176| | open func contains(_ e: ChartDataEntry) -> Bool 177| 0| { 178| 0| fatalError("removeEntry is not implemented in ChartBaseDataSet") 179| 0| } 180| | 181| | open func clear() 182| 0| { 183| 0| fatalError("clear is not implemented in ChartBaseDataSet") 184| 0| } 185| | 186| | // MARK: - Styling functions and accessors 187| | 188| | /// All the colors that are used for this DataSet. 189| | /// Colors are reused as soon as the number of Entries the DataSet represents is higher than the size of the colors array. 190| | open var colors = [NSUIColor]() 191| | 192| | /// List representing all colors that are used for drawing the actual values for this DataSet 193| | open var valueColors = [NSUIColor]() 194| | 195| | /// The label string that describes the DataSet. 196| | open var label: String? = "DataSet" 197| | 198| | /// The axis this DataSet should be plotted against. 199| | open var axisDependency = YAxis.AxisDependency.left 200| | 201| | /// - Returns: The color at the given index of the DataSet's color array. 202| | /// This prevents out-of-bounds by performing a modulus on the color index, so colours will repeat themselves. 203| | open func color(atIndex index: Int) -> NSUIColor 204| 458| { 205| 458| var index = index 206| 458| if index < 0 207| 458| { 208| 0| index = 0 209| 458| } 210| 458| return colors[index % colors.count] 211| 458| } 212| | 213| | /// Resets all colors of this DataSet and recreates the colors array. 214| | open func resetColors() 215| 0| { 216| 0| colors.removeAll(keepingCapacity: false) 217| 0| } 218| | 219| | /// Adds a new color to the colors array of the DataSet. 220| | /// 221| | /// - Parameters: 222| | /// - color: the color to add 223| | open func addColor(_ color: NSUIColor) 224| 0| { 225| 0| colors.append(color) 226| 0| } 227| | 228| | /// Sets the one and **only** color that should be used for this DataSet. 229| | /// Internally, this recreates the colors array and adds the specified color. 230| | /// 231| | /// - Parameters: 232| | /// - color: the color to set 233| | open func setColor(_ color: NSUIColor) 234| 0| { 235| 0| colors.removeAll(keepingCapacity: false) 236| 0| colors.append(color) 237| 0| } 238| | 239| | /// Sets colors to a single color a specific alpha value. 240| | /// 241| | /// - Parameters: 242| | /// - color: the color to set 243| | /// - alpha: alpha to apply to the set `color` 244| | @objc open func setColor(_ color: NSUIColor, alpha: CGFloat) 245| 0| { 246| 0| setColor(color.withAlphaComponent(alpha)) 247| 0| } 248| | 249| | /// Sets colors with a specific alpha value. 250| | /// 251| | /// - Parameters: 252| | /// - colors: the colors to set 253| | /// - alpha: alpha to apply to the set `colors` 254| | @objc open func setColors(_ colors: [NSUIColor], alpha: CGFloat) 255| 0| { 256| 0| self.colors = colors.map { $0.withAlphaComponent(alpha) } 257| 0| } 258| | 259| | /// Sets colors with a specific alpha value. 260| | /// 261| | /// - Parameters: 262| | /// - colors: the colors to set 263| | /// - alpha: alpha to apply to the set `colors` 264| | open func setColors(_ colors: NSUIColor...) 265| 0| { 266| 0| self.colors = colors 267| 0| } 268| | 269| | /// if true, value highlighting is enabled 270| | open var highlightEnabled = true 271| | 272| | /// `true` if value highlighting is enabled for this dataset 273| 44| open var isHighlightEnabled: Bool { return highlightEnabled } 274| | 275| | /// Custom formatter that is used instead of the auto-formatter if set 276| | internal var _valueFormatter: IValueFormatter? 277| | 278| | /// Custom formatter that is used instead of the auto-formatter if set 279| | open var valueFormatter: IValueFormatter? 280| | { 281| | get 282| 1.47k| { 283| 1.47k| if needsFormatter 284| 1.47k| { 285| 0| return ChartUtils.defaultValueFormatter() 286| 1.47k| } 287| 1.47k| 288| 1.47k| return _valueFormatter 289| 1.47k| } 290| | set 291| 55| { 292| 55| if newValue == nil { return } 293| 55| 294| 55| _valueFormatter = newValue 295| 55| } 296| | } 297| | 298| | open var needsFormatter: Bool 299| 1.52k| { 300| 1.52k| return _valueFormatter == nil 301| 1.52k| } 302| | 303| | /// Sets/get a single color for value text. 304| | /// Setting the color clears the colors array and adds a single color. 305| | /// Getting will return the first color in the array. 306| | open var valueTextColor: NSUIColor 307| | { 308| | get 309| 0| { 310| 0| return valueColors[0] 311| 0| } 312| | set 313| 6| { 314| 6| valueColors.removeAll(keepingCapacity: false) 315| 6| valueColors.append(newValue) 316| 6| } 317| | } 318| | 319| | /// - Returns: The color at the specified index that is used for drawing the values inside the chart. Uses modulus internally. 320| | open func valueTextColorAt(_ index: Int) -> NSUIColor 321| 1.28k| { 322| 1.28k| var index = index 323| 1.28k| if index < 0 324| 1.28k| { 325| 0| index = 0 326| 1.28k| } 327| 1.28k| return valueColors[index % valueColors.count] 328| 1.28k| } 329| | 330| | /// the font for the value-text labels 331| | open var valueFont: NSUIFont = NSUIFont.systemFont(ofSize: 7.0) 332| | 333| | /// The form to draw for this dataset in the legend. 334| | open var form = Legend.Form.default 335| | 336| | /// The form size to draw for this dataset in the legend. 337| | /// 338| | /// Return `NaN` to use the default legend form size. 339| | open var formSize: CGFloat = CGFloat.nan 340| | 341| | /// The line width for drawing the form of this dataset in the legend 342| | /// 343| | /// Return `NaN` to use the default legend form line width. 344| | open var formLineWidth: CGFloat = CGFloat.nan 345| | 346| | /// Line dash configuration for legend shapes that consist of lines. 347| | /// 348| | /// This is how much (in pixels) into the dash pattern are we starting from. 349| | open var formLineDashPhase: CGFloat = 0.0 350| | 351| | /// Line dash configuration for legend shapes that consist of lines. 352| | /// 353| | /// This is the actual dash pattern. 354| | /// I.e. [2, 3] will paint [-- -- ] 355| | /// [1, 3, 4, 2] will paint [- ---- - ---- ] 356| | open var formLineDashLengths: [CGFloat]? = nil 357| | 358| | /// Set this to true to draw y-values on the chart. 359| | /// 360| | /// - Note: For bar and line charts: if `maxVisibleCount` is reached, no values will be drawn even if this is enabled. 361| | open var drawValuesEnabled = true 362| | 363| | /// `true` if y-value drawing is enabled, `false` ifnot 364| | open var isDrawValuesEnabled: Bool 365| 1.29k| { 366| 1.29k| return drawValuesEnabled 367| 1.29k| } 368| | 369| | /// Set this to true to draw y-icons on the chart. 370| | /// 371| | /// - Note: For bar and line charts: if `maxVisibleCount` is reached, no icons will be drawn even if this is enabled. 372| | open var drawIconsEnabled = true 373| | 374| | /// Returns true if y-icon drawing is enabled, false if not 375| | open var isDrawIconsEnabled: Bool 376| 1.18k| { 377| 1.18k| return drawIconsEnabled 378| 1.18k| } 379| | 380| | /// Offset of icons drawn on the chart. 381| | /// 382| | /// For all charts except Pie and Radar it will be ordinary (x offset, y offset). 383| | /// 384| | /// For Pie and Radar chart it will be (y offset, distance from center offset); so if you want icon to be rendered under value, you should increase X component of CGPoint, and if you want icon to be rendered closet to center, you should decrease height component of CGPoint. 385| | open var iconsOffset = CGPoint(x: 0, y: 0) 386| | 387| | /// Set the visibility of this DataSet. If not visible, the DataSet will not be drawn to the chart upon refreshing it. 388| | open var visible = true 389| | 390| | /// `true` if this DataSet is visible inside the chart, or `false` ifit is currently hidden. 391| | open var isVisible: Bool 392| 113| { 393| 113| return visible 394| 113| } 395| | 396| | // MARK: - NSObject 397| | 398| | open override var description: String 399| 0| { 400| 0| return String(format: "%@, label: %@, %i entries", arguments: [NSStringFromClass(type(of: self)), self.label ?? "", self.entryCount]) 401| 0| } 402| | 403| | open override var debugDescription: String 404| 0| { 405| 0| return (0.. Any 413| 0| { 414| 0| let copy = type(of: self).init() 415| 0| 416| 0| copy.colors = colors 417| 0| copy.valueColors = valueColors 418| 0| copy.label = label 419| 0| copy.axisDependency = axisDependency 420| 0| copy.highlightEnabled = highlightEnabled 421| 0| copy._valueFormatter = _valueFormatter 422| 0| copy.valueFont = valueFont 423| 0| copy.form = form 424| 0| copy.formSize = formSize 425| 0| copy.formLineWidth = formLineWidth 426| 0| copy.formLineDashPhase = formLineDashPhase 427| 0| copy.formLineDashLengths = formLineDashLengths 428| 0| copy.drawValuesEnabled = drawValuesEnabled 429| 0| copy.drawValuesEnabled = drawValuesEnabled 430| 0| copy.iconsOffset = iconsOffset 431| 0| copy.visible = visible 432| 0| 433| 0| return copy 434| 0| } 435| |} /Users/travis/build/danielgindi/Charts/Source/Charts/Data/Implementations/Standard/BarChartData.swift: 1| |// 2| |// BarChartData.swift 3| |// Charts 4| |// 5| |// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda 6| |// A port of MPAndroidChart for iOS 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| | 12| |import Foundation 13| |import CoreGraphics 14| | 15| |open class BarChartData: BarLineScatterCandleBubbleChartData 16| |{ 17| | public override init() 18| 0| { 19| 0| super.init() 20| 0| } 21| | 22| | public override init(dataSets: [IChartDataSet]?) 23| 40| { 24| 40| super.init(dataSets: dataSets) 25| 40| } 26| | 27| | /// The width of the bars on the x-axis, in values (not pixels) 28| | /// 29| | /// **default**: 0.85 30| | @objc open var barWidth = Double(0.85) 31| | 32| | /// Groups all BarDataSet objects this data object holds together by modifying the x-value of their entries. 33| | /// Previously set x-values of entries will be overwritten. Leaves space between bars and groups as specified by the parameters. 34| | /// Do not forget to call notifyDataSetChanged() on your BarChart object after calling this method. 35| | /// 36| | /// - Parameters: 37| | /// - fromX: the starting point on the x-axis where the grouping should begin 38| | /// - groupSpace: The space between groups of bars in values (not pixels) e.g. 0.8f for bar width 1f 39| | /// - barSpace: The space between individual bars in values (not pixels) e.g. 0.1f for bar width 1f 40| | @objc open func groupBars(fromX: Double, groupSpace: Double, barSpace: Double) 41| 0| { 42| 0| let setCount = _dataSets.count 43| 0| if setCount <= 1 44| 0| { 45| 0| print("BarData needs to hold at least 2 BarDataSets to allow grouping.", terminator: "\n") 46| 0| return 47| 0| } 48| 0| 49| 0| let max = maxEntryCountSet 50| 0| let maxEntryCount = max?.entryCount ?? 0 51| 0| 52| 0| let groupSpaceWidthHalf = groupSpace / 2.0 53| 0| let barSpaceHalf = barSpace / 2.0 54| 0| let barWidthHalf = self.barWidth / 2.0 55| 0| 56| 0| var fromX = fromX 57| 0| 58| 0| let interval = groupWidth(groupSpace: groupSpace, barSpace: barSpace) 59| 0| 60| 0| for i in stride(from: 0, to: maxEntryCount, by: 1) 61| 0| { 62| 0| let start = fromX 63| 0| fromX += groupSpaceWidthHalf 64| 0| 65| 0| (_dataSets as? [IBarChartDataSet])?.forEach { set in 66| 0| fromX += barSpaceHalf 67| 0| fromX += barWidthHalf 68| 0| 69| 0| if i < set.entryCount 70| 0| { 71| 0| if let entry = set.entryForIndex(i) 72| 0| { 73| 0| entry.x = fromX 74| 0| } 75| 0| } 76| 0| 77| 0| fromX += barWidthHalf 78| 0| fromX += barSpaceHalf 79| 0| } 80| 0| 81| 0| fromX += groupSpaceWidthHalf 82| 0| let end = fromX 83| 0| let innerInterval = end - start 84| 0| let diff = interval - innerInterval 85| 0| 86| 0| // correct rounding errors 87| 0| if diff > 0 || diff < 0 88| 0| { 89| 0| fromX += diff 90| 0| } 91| 0| 92| 0| } 93| 0| 94| 0| notifyDataChanged() 95| 0| } 96| | 97| | /// In case of grouped bars, this method returns the space an individual group of bar needs on the x-axis. 98| | /// 99| | /// - Parameters: 100| | /// - groupSpace: 101| | /// - barSpace: 102| | @objc open func groupWidth(groupSpace: Double, barSpace: Double) -> Double 103| 0| { 104| 0| return Double(_dataSets.count) * (self.barWidth + barSpace) + groupSpace 105| 0| } 106| | 107| |} /Users/travis/build/danielgindi/Charts/Source/Charts/Data/Implementations/Standard/BarChartDataEntry.swift: 1| |// 2| |// BarChartDataEntry.swift 3| |// Charts 4| |// 5| |// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda 6| |// A port of MPAndroidChart for iOS 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| | 12| |import Foundation 13| | 14| |open class BarChartDataEntry: ChartDataEntry 15| |{ 16| | /// the values the stacked barchart holds 17| | private var _yVals: [Double]? 18| | 19| | /// the ranges for the individual stack values - automatically calculated 20| | private var _ranges: [Range]? 21| | 22| | /// the sum of all negative values this entry (if stacked) contains 23| | private var _negativeSum: Double = 0.0 24| | 25| | /// the sum of all positive values this entry (if stacked) contains 26| | private var _positiveSum: Double = 0.0 27| | 28| | public required init() 29| 0| { 30| 0| super.init() 31| 0| } 32| | 33| | /// Constructor for normal bars (not stacked). 34| | public override init(x: Double, y: Double) 35| 1.02k| { 36| 1.02k| super.init(x: x, y: y) 37| 1.02k| } 38| | 39| | /// Constructor for normal bars (not stacked). 40| | public convenience init(x: Double, y: Double, data: Any?) 41| 0| { 42| 0| self.init(x: x, y: y) 43| 0| self.data = data 44| 0| } 45| | 46| | /// Constructor for normal bars (not stacked). 47| | public convenience init(x: Double, y: Double, icon: NSUIImage?) 48| 1.02k| { 49| 1.02k| self.init(x: x, y: y) 50| 1.02k| self.icon = icon 51| 1.02k| } 52| | 53| | /// Constructor for normal bars (not stacked). 54| | public convenience init(x: Double, y: Double, icon: NSUIImage?, data: Any?) 55| 0| { 56| 0| self.init(x: x, y: y) 57| 0| self.icon = icon 58| 0| self.data = data 59| 0| } 60| | 61| | /// Constructor for stacked bar entries. 62| | @objc public init(x: Double, yValues: [Double]) 63| 30| { 64| 30| super.init(x: x, y: BarChartDataEntry.calcSum(values: yValues)) 65| 30| self._yVals = yValues 66| 30| calcPosNegSum() 67| 30| calcRanges() 68| 30| } 69| | 70| | /// Constructor for stacked bar entries. One data object for whole stack 71| | @objc public convenience init(x: Double, yValues: [Double], icon: NSUIImage?) 72| 30| { 73| 30| self.init(x: x, yValues: yValues) 74| 30| self.icon = icon 75| 30| } 76| | 77| | /// Constructor for stacked bar entries. One data object for whole stack 78| | @objc public convenience init(x: Double, yValues: [Double], data: Any?) 79| 0| { 80| 0| self.init(x: x, yValues: yValues) 81| 0| self.data = data 82| 0| } 83| | 84| | /// Constructor for stacked bar entries. One data object for whole stack 85| | @objc public convenience init(x: Double, yValues: [Double], icon: NSUIImage?, data: Any?) 86| 0| { 87| 0| self.init(x: x, yValues: yValues) 88| 0| self.icon = icon 89| 0| self.data = data 90| 0| } 91| | 92| | @objc open func sumBelow(stackIndex :Int) -> Double 93| 0| { 94| 0| guard let yVals = _yVals else 95| 0| { 96| 0| return 0 97| 0| } 98| 0| 99| 0| var remainder: Double = 0.0 100| 0| var index = yVals.count - 1 101| 0| 102| 0| while (index > stackIndex && index >= 0) 103| 0| { 104| 0| remainder += yVals[index] 105| 0| index -= 1 106| 0| } 107| 0| 108| 0| return remainder 109| 0| } 110| | 111| | /// The sum of all negative values this entry (if stacked) contains. (this is a positive number) 112| | @objc open var negativeSum: Double 113| 128| { 114| 128| return _negativeSum 115| 128| } 116| | 117| | /// The sum of all positive values this entry (if stacked) contains. 118| | @objc open var positiveSum: Double 119| 42| { 120| 42| return _positiveSum 121| 42| } 122| | 123| | @objc open func calcPosNegSum() 124| 30| { 125| 150| (_negativeSum, _positiveSum) = _yVals?.reduce(into: (0,0)) { (result, y) in 126| 150| if y < 0 127| 150| { 128| 60| result.0 += -y 129| 150| } 130| 150| else 131| 150| { 132| 90| result.1 += y 133| 150| } 134| 150| } ?? (0,0) 135| 30| } 136| | 137| | /// Splits up the stack-values of the given bar-entry into Range objects. 138| | /// 139| | /// - Parameters: 140| | /// - entry: 141| | /// - Returns: 142| | @objc open func calcRanges() 143| 30| { 144| 30| guard let values = yValues, !values.isEmpty else { return } 145| 30| 146| 30| if _ranges == nil 147| 30| { 148| 30| _ranges = [Range]() 149| 30| } 150| 30| else 151| 30| { 152| 0| _ranges!.removeAll() 153| 30| } 154| 30| 155| 30| _ranges!.reserveCapacity(values.count) 156| 30| 157| 30| var negRemain = -negativeSum 158| 30| var posRemain: Double = 0.0 159| 30| 160| 30| for value in values 161| 150| { 162| 150| if value < 0 163| 150| { 164| 60| _ranges!.append(Range(from: negRemain, to: negRemain - value)) 165| 60| negRemain -= value 166| 150| } 167| 150| else 168| 150| { 169| 90| _ranges!.append(Range(from: posRemain, to: posRemain + value)) 170| 90| posRemain += value 171| 150| } 172| 150| } 173| 30| } 174| | 175| | // MARK: Accessors 176| | 177| | /// the values the stacked barchart holds 178| 0| @objc open var isStacked: Bool { return _yVals != nil } 179| | 180| | /// the values the stacked barchart holds 181| | @objc open var yValues: [Double]? 182| | { 183| 4.40k| get { return self._yVals } 184| | set 185| 0| { 186| 0| self.y = BarChartDataEntry.calcSum(values: newValue) 187| 0| self._yVals = newValue 188| 0| calcPosNegSum() 189| 0| calcRanges() 190| 0| } 191| | } 192| | 193| | /// The ranges of the individual stack-entries. Will return null if this entry is not stacked. 194| | @objc open var ranges: [Range]? 195| 0| { 196| 0| return _ranges 197| 0| } 198| | 199| | // MARK: NSCopying 200| | 201| | open override func copy(with zone: NSZone? = nil) -> Any 202| 0| { 203| 0| let copy = super.copy(with: zone) as! BarChartDataEntry 204| 0| copy._yVals = _yVals 205| 0| copy.y = y 206| 0| copy._negativeSum = _negativeSum 207| 0| copy._positiveSum = _positiveSum 208| 0| return copy 209| 0| } 210| | 211| | /// Calculates the sum across all values of the given stack. 212| | /// 213| | /// - Parameters: 214| | /// - vals: 215| | /// - Returns: 216| | private static func calcSum(values: [Double]?) -> Double 217| 30| { 218| 30| guard let values = values 219| 30| else { return 0.0 } 220| 30| 221| 30| var sum = 0.0 222| 30| 223| 30| for f in values 224| 150| { 225| 150| sum += f 226| 150| } 227| 30| 228| 30| return sum 229| 30| } 230| |} /Users/travis/build/danielgindi/Charts/Source/Charts/Data/Implementations/Standard/BarChartDataSet.swift: 1| |// 2| |// BarChartDataSet.swift 3| |// Charts 4| |// 5| |// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda 6| |// A port of MPAndroidChart for iOS 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| | 12| |import Foundation 13| |import CoreGraphics 14| | 15| | 16| |open class BarChartDataSet: BarLineScatterCandleBubbleChartDataSet, IBarChartDataSet 17| |{ 18| | private func initialize() 19| 40| { 20| 40| self.highlightColor = NSUIColor.black 21| 40| 22| 40| self.calcStackSize(entries: entries as! [BarChartDataEntry]) 23| 40| self.calcEntryCountIncludingStacks(entries: entries as! [BarChartDataEntry]) 24| 40| } 25| | 26| | public required init() 27| 0| { 28| 0| super.init() 29| 0| initialize() 30| 0| } 31| | 32| | public override init(entries: [ChartDataEntry]?, label: String?) 33| 40| { 34| 40| super.init(entries: entries, label: label) 35| 40| initialize() 36| 40| } 37| | 38| | // MARK: - Data functions and accessors 39| | 40| | /// the maximum number of bars that are stacked upon each other, this value 41| | /// is calculated from the Entries that are added to the DataSet 42| | private var _stackSize = 1 43| | 44| | /// the overall entry count, including counting each stack-value individually 45| | private var _entryCountStacks = 0 46| | 47| | /// Calculates the total number of entries this DataSet represents, including 48| | /// stacks. All values belonging to a stack are calculated separately. 49| | private func calcEntryCountIncludingStacks(entries: [BarChartDataEntry]) 50| 40| { 51| 40| _entryCountStacks = 0 52| 40| 53| 40| for i in 0 ..< entries.count 54| 1.05k| { 55| 1.05k| if let vals = entries[i].yValues 56| 1.05k| { 57| 30| _entryCountStacks += vals.count 58| 1.05k| } 59| 1.05k| else 60| 1.05k| { 61| 1.02k| _entryCountStacks += 1 62| 1.05k| } 63| 1.05k| } 64| 40| } 65| | 66| | /// calculates the maximum stacksize that occurs in the Entries array of this DataSet 67| | private func calcStackSize(entries: [BarChartDataEntry]) 68| 40| { 69| 40| for i in 0 ..< entries.count 70| 1.05k| { 71| 1.05k| if let vals = entries[i].yValues 72| 1.05k| { 73| 30| if vals.count > _stackSize 74| 30| { 75| 6| _stackSize = vals.count 76| 30| } 77| 1.05k| } 78| 1.05k| } 79| 40| } 80| | 81| | open override func calcMinMax(entry e: ChartDataEntry) 82| 1.05k| { 83| 1.05k| guard let e = e as? BarChartDataEntry 84| 1.05k| else { return } 85| 1.05k| 86| 1.05k| if !e.y.isNaN 87| 1.05k| { 88| 1.05k| if e.yValues == nil 89| 1.05k| { 90| 1.02k| if e.y < _yMin 91| 1.02k| { 92| 78| _yMin = e.y 93| 1.02k| } 94| 1.02k| 95| 1.02k| if e.y > _yMax 96| 1.02k| { 97| 84| _yMax = e.y 98| 1.02k| } 99| 1.05k| } 100| 1.05k| else 101| 1.05k| { 102| 30| if -e.negativeSum < _yMin 103| 30| { 104| 18| _yMin = -e.negativeSum 105| 30| } 106| 30| 107| 30| if e.positiveSum > _yMax 108| 30| { 109| 12| _yMax = e.positiveSum 110| 30| } 111| 1.05k| } 112| 1.05k| 113| 1.05k| calcMinMaxX(entry: e) 114| 1.05k| } 115| 1.05k| } 116| | 117| | /// The maximum number of bars that can be stacked upon another in this DataSet. 118| | open var stackSize: Int 119| 30| { 120| 30| return _stackSize 121| 30| } 122| | 123| | /// `true` if this DataSet is stacked (stacksize > 1) or not. 124| | open var isStacked: Bool 125| 1.34k| { 126| 1.34k| return _stackSize > 1 ? true : false 127| 1.34k| } 128| | 129| | /// The overall entry count, including counting each stack-value individually 130| | @objc open var entryCountStacks: Int 131| 0| { 132| 0| return _entryCountStacks 133| 0| } 134| | 135| | /// array of labels used to describe the different values of the stacked bars 136| | open var stackLabels: [String] = [] 137| | 138| | // MARK: - Styling functions and accessors 139| | 140| | /// the color used for drawing the bar-shadows. The bar shadows is a surface behind the bar that indicates the maximum value 141| | open var barShadowColor = NSUIColor(red: 215.0/255.0, green: 215.0/255.0, blue: 215.0/255.0, alpha: 1.0) 142| | 143| | /// the width used for drawing borders around the bars. If borderWidth == 0, no border will be drawn. 144| | open var barBorderWidth : CGFloat = 0.0 145| | 146| | /// the color drawing borders around the bars. 147| | open var barBorderColor = NSUIColor.black 148| | 149| | /// the alpha value (transparency) that is used for drawing the highlight indicator bar. min = 0.0 (fully transparent), max = 1.0 (fully opaque) 150| | open var highlightAlpha = CGFloat(120.0 / 255.0) 151| | 152| | // MARK: - NSCopying 153| | 154| | open override func copy(with zone: NSZone? = nil) -> Any 155| 0| { 156| 0| let copy = super.copy(with: zone) as! BarChartDataSet 157| 0| copy._stackSize = _stackSize 158| 0| copy._entryCountStacks = _entryCountStacks 159| 0| copy.stackLabels = stackLabels 160| 0| 161| 0| copy.barShadowColor = barShadowColor 162| 0| copy.barBorderWidth = barBorderWidth 163| 0| copy.barBorderColor = barBorderColor 164| 0| copy.highlightAlpha = highlightAlpha 165| 0| return copy 166| 0| } 167| |} /Users/travis/build/danielgindi/Charts/Source/Charts/Data/Implementations/Standard/BarLineScatterCandleBubbleChartData.swift: 1| |// 2| |// BarLineScatterCandleBubbleChartData.swift 3| |// Charts 4| |// 5| |// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda 6| |// A port of MPAndroidChart for iOS 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| | 12| |import Foundation 13| | 14| |open class BarLineScatterCandleBubbleChartData: ChartData 15| |{ 16| | public override init() 17| 3| { 18| 3| super.init() 19| 3| } 20| | 21| | public override init(dataSets: [IChartDataSet]?) 22| 43| { 23| 43| super.init(dataSets: dataSets) 24| 43| } 25| |} /Users/travis/build/danielgindi/Charts/Source/Charts/Data/Implementations/Standard/BarLineScatterCandleBubbleChartDataSet.swift: 1| |// 2| |// BarLineScatterCandleBubbleChartDataSet.swift 3| |// Charts 4| |// 5| |// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda 6| |// A port of MPAndroidChart for iOS 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| | 12| |import Foundation 13| |import CoreGraphics 14| | 15| | 16| |open class BarLineScatterCandleBubbleChartDataSet: ChartDataSet, IBarLineScatterCandleBubbleChartDataSet 17| |{ 18| | // MARK: - Data functions and accessors 19| | 20| | // MARK: - Styling functions and accessors 21| | 22| | open var highlightColor = NSUIColor(red: 255.0/255.0, green: 187.0/255.0, blue: 115.0/255.0, alpha: 1.0) 23| | open var highlightLineWidth = CGFloat(0.5) 24| | open var highlightLineDashPhase = CGFloat(0.0) 25| | open var highlightLineDashLengths: [CGFloat]? 26| | 27| | // MARK: - NSCopying 28| | 29| | open override func copy(with zone: NSZone? = nil) -> Any 30| 0| { 31| 0| let copy = super.copy(with: zone) as! BarLineScatterCandleBubbleChartDataSet 32| 0| copy.highlightColor = highlightColor 33| 0| copy.highlightLineWidth = highlightLineWidth 34| 0| copy.highlightLineDashPhase = highlightLineDashPhase 35| 0| copy.highlightLineDashLengths = highlightLineDashLengths 36| 0| return copy 37| 0| } 38| |} /Users/travis/build/danielgindi/Charts/Source/Charts/Data/Implementations/Standard/BubbleChartData.swift: 1| |// 2| |// BubbleChartData.swift 3| |// Charts 4| |// 5| |// Bubble chart implementation: 6| |// Copyright 2015 Pierre-Marc Airoldi 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| | 12| |import Foundation 13| |import CoreGraphics 14| | 15| |open class BubbleChartData: BarLineScatterCandleBubbleChartData 16| |{ 17| | public override init() 18| 0| { 19| 0| super.init() 20| 0| } 21| | 22| | public override init(dataSets: [IChartDataSet]?) 23| 0| { 24| 0| super.init(dataSets: dataSets) 25| 0| } 26| | 27| | /// Sets the width of the circle that surrounds the bubble when highlighted for all DataSet objects this data object contains 28| | @objc open func setHighlightCircleWidth(_ width: CGFloat) 29| 0| { 30| 0| (_dataSets as? [IBubbleChartDataSet])?.forEach { $0.highlightCircleWidth = width } 31| 0| } 32| |} /Users/travis/build/danielgindi/Charts/Source/Charts/Data/Implementations/Standard/BubbleChartDataEntry.swift: 1| |// 2| |// BubbleDataEntry.swift 3| |// Charts 4| |// 5| |// Bubble chart implementation: 6| |// Copyright 2015 Pierre-Marc Airoldi 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| | 12| |import Foundation 13| |import CoreGraphics 14| | 15| |open class BubbleChartDataEntry: ChartDataEntry 16| |{ 17| | /// The size of the bubble. 18| | @objc open var size = CGFloat(0.0) 19| | 20| | public required init() 21| 0| { 22| 0| super.init() 23| 0| } 24| | 25| | /// - Parameters: 26| | /// - x: The index on the x-axis. 27| | /// - y: The value on the y-axis. 28| | /// - size: The size of the bubble. 29| | @objc public init(x: Double, y: Double, size: CGFloat) 30| 0| { 31| 0| super.init(x: x, y: y) 32| 0| 33| 0| self.size = size 34| 0| } 35| | 36| | /// - Parameters: 37| | /// - x: The index on the x-axis. 38| | /// - y: The value on the y-axis. 39| | /// - size: The size of the bubble. 40| | /// - data: Spot for additional data this Entry represents. 41| | @objc public convenience init(x: Double, y: Double, size: CGFloat, data: Any?) 42| 0| { 43| 0| self.init(x: x, y: y, size: size) 44| 0| self.data = data 45| 0| } 46| | 47| | /// - Parameters: 48| | /// - x: The index on the x-axis. 49| | /// - y: The value on the y-axis. 50| | /// - size: The size of the bubble. 51| | /// - icon: icon image 52| | @objc public convenience init(x: Double, y: Double, size: CGFloat, icon: NSUIImage?) 53| 0| { 54| 0| self.init(x: x, y: y, size: size) 55| 0| self.icon = icon 56| 0| } 57| | 58| | /// - Parameters: 59| | /// - x: The index on the x-axis. 60| | /// - y: The value on the y-axis. 61| | /// - size: The size of the bubble. 62| | /// - icon: icon image 63| | /// - data: Spot for additional data this Entry represents. 64| | @objc public convenience init(x: Double, y: Double, size: CGFloat, icon: NSUIImage?, data: Any?) 65| 0| { 66| 0| self.init(x: x, y: y, size: size) 67| 0| self.icon = icon 68| 0| self.data = data 69| 0| } 70| | 71| | // MARK: NSCopying 72| | 73| | open override func copy(with zone: NSZone? = nil) -> Any 74| 0| { 75| 0| let copy = super.copy(with: zone) as! BubbleChartDataEntry 76| 0| copy.size = size 77| 0| return copy 78| 0| } 79| |} /Users/travis/build/danielgindi/Charts/Source/Charts/Data/Implementations/Standard/BubbleChartDataSet.swift: 1| |// 2| |// BubbleChartDataSet.swift 3| |// Charts 4| |// 5| |// Bubble chart implementation: 6| |// Copyright 2015 Pierre-Marc Airoldi 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| | 12| |import Foundation 13| |import CoreGraphics 14| | 15| | 16| |open class BubbleChartDataSet: BarLineScatterCandleBubbleChartDataSet, IBubbleChartDataSet 17| |{ 18| | // MARK: - Data functions and accessors 19| | 20| | internal var _maxSize = CGFloat(0.0) 21| | 22| 0| open var maxSize: CGFloat { return _maxSize } 23| | @objc open var normalizeSizeEnabled: Bool = true 24| 0| open var isNormalizeSizeEnabled: Bool { return normalizeSizeEnabled } 25| | 26| | open override func calcMinMax(entry e: ChartDataEntry) 27| 0| { 28| 0| guard let e = e as? BubbleChartDataEntry 29| 0| else { return } 30| 0| 31| 0| super.calcMinMax(entry: e) 32| 0| 33| 0| let size = e.size 34| 0| 35| 0| if size > _maxSize 36| 0| { 37| 0| _maxSize = size 38| 0| } 39| 0| } 40| | 41| | // MARK: - Styling functions and accessors 42| | 43| | /// Sets/gets the width of the circle that surrounds the bubble when highlighted 44| | open var highlightCircleWidth: CGFloat = 2.5 45| | 46| | // MARK: - NSCopying 47| | 48| | open override func copy(with zone: NSZone? = nil) -> Any 49| 0| { 50| 0| let copy = super.copy(with: zone) as! BubbleChartDataSet 51| 0| copy._xMin = _xMin 52| 0| copy._xMax = _xMax 53| 0| copy._maxSize = _maxSize 54| 0| copy.normalizeSizeEnabled = normalizeSizeEnabled 55| 0| copy.highlightCircleWidth = highlightCircleWidth 56| 0| return copy 57| 0| } 58| |} /Users/travis/build/danielgindi/Charts/Source/Charts/Data/Implementations/Standard/CandleChartData.swift: 1| |// 2| |// CandleChartData.swift 3| |// Charts 4| |// 5| |// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda 6| |// A port of MPAndroidChart for iOS 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| | 12| |import Foundation 13| | 14| |open class CandleChartData: BarLineScatterCandleBubbleChartData 15| |{ 16| | public override init() 17| 0| { 18| 0| super.init() 19| 0| } 20| | 21| | public override init(dataSets: [IChartDataSet]?) 22| 0| { 23| 0| super.init(dataSets: dataSets) 24| 0| } 25| |} /Users/travis/build/danielgindi/Charts/Source/Charts/Data/Implementations/Standard/CandleChartDataEntry.swift: 1| |// 2| |// CandleChartDataEntry.swift 3| |// Charts 4| |// 5| |// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda 6| |// A port of MPAndroidChart for iOS 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| | 12| |import Foundation 13| | 14| |open class CandleChartDataEntry: ChartDataEntry 15| |{ 16| | /// shadow-high value 17| | @objc open var high = Double(0.0) 18| | 19| | /// shadow-low value 20| | @objc open var low = Double(0.0) 21| | 22| | /// close value 23| | @objc open var close = Double(0.0) 24| | 25| | /// open value 26| | @objc open var open = Double(0.0) 27| | 28| | public required init() 29| 0| { 30| 0| super.init() 31| 0| } 32| | 33| | @objc public init(x: Double, shadowH: Double, shadowL: Double, open: Double, close: Double) 34| 0| { 35| 0| super.init(x: x, y: (shadowH + shadowL) / 2.0) 36| 0| 37| 0| self.high = shadowH 38| 0| self.low = shadowL 39| 0| self.open = open 40| 0| self.close = close 41| 0| } 42| | 43| | @objc public convenience init(x: Double, shadowH: Double, shadowL: Double, open: Double, close: Double, icon: NSUIImage?) 44| 0| { 45| 0| self.init(x: x, shadowH: shadowH, shadowL: shadowL, open: open, close: close) 46| 0| self.icon = icon 47| 0| } 48| | 49| | @objc public convenience init(x: Double, shadowH: Double, shadowL: Double, open: Double, close: Double, data: Any?) 50| 0| { 51| 0| self.init(x: x, shadowH: shadowH, shadowL: shadowL, open: open, close: close) 52| 0| self.data = data 53| 0| } 54| | 55| | @objc public convenience init(x: Double, shadowH: Double, shadowL: Double, open: Double, close: Double, icon: NSUIImage?, data: Any?) 56| 0| { 57| 0| self.init(x: x, shadowH: shadowH, shadowL: shadowL, open: open, close: close) 58| 0| self.icon = icon 59| 0| self.data = data 60| 0| } 61| | 62| | /// The overall range (difference) between shadow-high and shadow-low. 63| | @objc open var shadowRange: Double 64| 0| { 65| 0| return abs(high - low) 66| 0| } 67| | 68| | /// The body size (difference between open and close). 69| | @objc open var bodyRange: Double 70| 0| { 71| 0| return abs(open - close) 72| 0| } 73| | 74| | /// the center value of the candle. (Middle value between high and low) 75| | open override var y: Double 76| | { 77| | get 78| 0| { 79| 0| return super.y 80| 0| } 81| | set 82| 0| { 83| 0| super.y = (high + low) / 2.0 84| 0| } 85| | } 86| | 87| | // MARK: NSCopying 88| | 89| | open override func copy(with zone: NSZone? = nil) -> Any 90| 0| { 91| 0| let copy = super.copy(with: zone) as! CandleChartDataEntry 92| 0| copy.high = high 93| 0| copy.low = low 94| 0| copy.open = open 95| 0| copy.close = close 96| 0| return copy 97| 0| } 98| |} /Users/travis/build/danielgindi/Charts/Source/Charts/Data/Implementations/Standard/CandleChartDataSet.swift: 1| |// 2| |// CandleChartDataSet.swift 3| |// Charts 4| |// 5| |// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda 6| |// A port of MPAndroidChart for iOS 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| | 12| |import Foundation 13| |import CoreGraphics 14| | 15| | 16| |open class CandleChartDataSet: LineScatterCandleRadarChartDataSet, ICandleChartDataSet 17| |{ 18| | 19| | public required init() 20| 0| { 21| 0| super.init() 22| 0| } 23| | 24| | public override init(entries: [ChartDataEntry]?, label: String?) 25| 0| { 26| 0| super.init(entries: entries, label: label) 27| 0| } 28| | 29| | // MARK: - Data functions and accessors 30| | 31| | open override func calcMinMax(entry e: ChartDataEntry) 32| 0| { 33| 0| guard let e = e as? CandleChartDataEntry 34| 0| else { return } 35| 0| 36| 0| if e.low < _yMin 37| 0| { 38| 0| _yMin = e.low 39| 0| } 40| 0| 41| 0| if e.high > _yMax 42| 0| { 43| 0| _yMax = e.high 44| 0| } 45| 0| 46| 0| calcMinMaxX(entry: e) 47| 0| } 48| | 49| | open override func calcMinMaxY(entry e: ChartDataEntry) 50| 0| { 51| 0| guard let e = e as? CandleChartDataEntry 52| 0| else { return } 53| 0| 54| 0| if e.high < _yMin 55| 0| { 56| 0| _yMin = e.high 57| 0| } 58| 0| if e.high > _yMax 59| 0| { 60| 0| _yMax = e.high 61| 0| } 62| 0| 63| 0| if e.low < _yMin 64| 0| { 65| 0| _yMin = e.low 66| 0| } 67| 0| if e.low > _yMax 68| 0| { 69| 0| _yMax = e.low 70| 0| } 71| 0| } 72| | 73| | // MARK: - Styling functions and accessors 74| | 75| | /// the space between the candle entries 76| | /// 77| | /// **default**: 0.1 (10%) 78| | private var _barSpace = CGFloat(0.1) 79| | 80| | /// the space that is left out on the left and right side of each candle, 81| | /// **default**: 0.1 (10%), max 0.45, min 0.0 82| | open var barSpace: CGFloat 83| | { 84| | get 85| 0| { 86| 0| return _barSpace 87| 0| } 88| | set 89| 0| { 90| 0| _barSpace = newValue.clamped(to: 0...0.45) 91| 0| } 92| | } 93| | 94| | /// should the candle bars show? 95| | /// when false, only "ticks" will show 96| | /// 97| | /// **default**: true 98| | open var showCandleBar: Bool = true 99| | 100| | /// the width of the candle-shadow-line in pixels. 101| | /// 102| | /// **default**: 1.5 103| | open var shadowWidth = CGFloat(1.5) 104| | 105| | /// the color of the shadow line 106| | open var shadowColor: NSUIColor? 107| | 108| | /// use candle color for the shadow 109| | open var shadowColorSameAsCandle = false 110| | 111| | /// Is the shadow color same as the candle color? 112| 0| open var isShadowColorSameAsCandle: Bool { return shadowColorSameAsCandle } 113| | 114| | /// color for open == close 115| | open var neutralColor: NSUIColor? 116| | 117| | /// color for open > close 118| | open var increasingColor: NSUIColor? 119| | 120| | /// color for open < close 121| | open var decreasingColor: NSUIColor? 122| | 123| | /// Are increasing values drawn as filled? 124| | /// increasing candlesticks are traditionally hollow 125| | open var increasingFilled = false 126| | 127| | /// Are increasing values drawn as filled? 128| 0| open var isIncreasingFilled: Bool { return increasingFilled } 129| | 130| | /// Are decreasing values drawn as filled? 131| | /// descreasing candlesticks are traditionally filled 132| | open var decreasingFilled = true 133| | 134| | /// Are decreasing values drawn as filled? 135| 0| open var isDecreasingFilled: Bool { return decreasingFilled } 136| |} /Users/travis/build/danielgindi/Charts/Source/Charts/Data/Implementations/Standard/ChartData.swift: 1| |// 2| |// ChartData.swift 3| |// Charts 4| |// 5| |// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda 6| |// A port of MPAndroidChart for iOS 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| | 12| |import Foundation 13| | 14| |open class ChartData: NSObject 15| |{ 16| | internal var _yMax: Double = -Double.greatestFiniteMagnitude 17| | internal var _yMin: Double = Double.greatestFiniteMagnitude 18| | internal var _xMax: Double = -Double.greatestFiniteMagnitude 19| | internal var _xMin: Double = Double.greatestFiniteMagnitude 20| | internal var _leftAxisMax: Double = -Double.greatestFiniteMagnitude 21| | internal var _leftAxisMin: Double = Double.greatestFiniteMagnitude 22| | internal var _rightAxisMax: Double = -Double.greatestFiniteMagnitude 23| | internal var _rightAxisMin: Double = Double.greatestFiniteMagnitude 24| | 25| | internal var _dataSets = [IChartDataSet]() 26| | 27| | public override init() 28| 3| { 29| 3| super.init() 30| 3| 31| 3| _dataSets = [IChartDataSet]() 32| 3| } 33| | 34| | @objc public init(dataSets: [IChartDataSet]?) 35| 58| { 36| 58| super.init() 37| 58| 38| 58| _dataSets = dataSets ?? [IChartDataSet]() 39| 58| 40| 58| self.initialize(dataSets: _dataSets) 41| 58| } 42| | 43| | @objc public convenience init(dataSet: IChartDataSet?) 44| 18| { 45| 18| self.init(dataSets: dataSet === nil ? nil : [dataSet!]) 46| 18| } 47| | 48| | internal func initialize(dataSets: [IChartDataSet]) 49| 58| { 50| 58| notifyDataChanged() 51| 58| } 52| | 53| | /// Call this method to let the ChartData know that the underlying data has changed. 54| | /// Calling this performs all necessary recalculations needed when the contained data has changed. 55| | @objc open func notifyDataChanged() 56| 79| { 57| 79| calcMinMax() 58| 79| } 59| | 60| | @objc open func calcMinMaxY(fromX: Double, toX: Double) 61| 0| { 62| 0| _dataSets.forEach { $0.calcMinMaxY(fromX: fromX, toX: toX) } 63| 0| // apply the new data 64| 0| calcMinMax() 65| 0| } 66| | 67| | /// calc minimum and maximum y value over all datasets 68| | @objc open func calcMinMax() 69| 84| { 70| 84| _yMax = -Double.greatestFiniteMagnitude 71| 84| _yMin = Double.greatestFiniteMagnitude 72| 84| _xMax = -Double.greatestFiniteMagnitude 73| 84| _xMin = Double.greatestFiniteMagnitude 74| 84| 75| 90| _dataSets.forEach { calcMinMax(dataSet: $0) } 76| 84| 77| 84| _leftAxisMax = -Double.greatestFiniteMagnitude 78| 84| _leftAxisMin = Double.greatestFiniteMagnitude 79| 84| _rightAxisMax = -Double.greatestFiniteMagnitude 80| 84| _rightAxisMin = Double.greatestFiniteMagnitude 81| 84| 82| 84| // left axis 83| 84| let firstLeft = getFirstLeft(dataSets: dataSets) 84| 84| 85| 84| if firstLeft !== nil 86| 84| { 87| 75| _leftAxisMax = firstLeft!.yMax 88| 75| _leftAxisMin = firstLeft!.yMin 89| 75| 90| 75| for dataSet in _dataSets 91| 81| { 92| 81| if dataSet.axisDependency == .left 93| 81| { 94| 81| if dataSet.yMin < _leftAxisMin 95| 81| { 96| 3| _leftAxisMin = dataSet.yMin 97| 81| } 98| 81| 99| 81| if dataSet.yMax > _leftAxisMax 100| 81| { 101| 1| _leftAxisMax = dataSet.yMax 102| 81| } 103| 81| } 104| 81| } 105| 84| } 106| 84| 107| 84| // right axis 108| 84| let firstRight = getFirstRight(dataSets: dataSets) 109| 84| 110| 84| if firstRight !== nil 111| 84| { 112| 9| _rightAxisMax = firstRight!.yMax 113| 9| _rightAxisMin = firstRight!.yMin 114| 9| 115| 9| for dataSet in _dataSets 116| 9| { 117| 9| if dataSet.axisDependency == .right 118| 9| { 119| 9| if dataSet.yMin < _rightAxisMin 120| 9| { 121| 0| _rightAxisMin = dataSet.yMin 122| 9| } 123| 9| 124| 9| if dataSet.yMax > _rightAxisMax 125| 9| { 126| 0| _rightAxisMax = dataSet.yMax 127| 9| } 128| 9| } 129| 9| } 130| 84| } 131| 84| } 132| | 133| | /// Adjusts the current minimum and maximum values based on the provided Entry object. 134| | @objc open func calcMinMax(entry e: ChartDataEntry, axis: YAxis.AxisDependency) 135| 0| { 136| 0| if _yMax < e.y 137| 0| { 138| 0| _yMax = e.y 139| 0| } 140| 0| 141| 0| if _yMin > e.y 142| 0| { 143| 0| _yMin = e.y 144| 0| } 145| 0| 146| 0| if _xMax < e.x 147| 0| { 148| 0| _xMax = e.x 149| 0| } 150| 0| 151| 0| if _xMin > e.x 152| 0| { 153| 0| _xMin = e.x 154| 0| } 155| 0| 156| 0| if axis == .left 157| 0| { 158| 0| if _leftAxisMax < e.y 159| 0| { 160| 0| _leftAxisMax = e.y 161| 0| } 162| 0| 163| 0| if _leftAxisMin > e.y 164| 0| { 165| 0| _leftAxisMin = e.y 166| 0| } 167| 0| } 168| 0| else 169| 0| { 170| 0| if _rightAxisMax < e.y 171| 0| { 172| 0| _rightAxisMax = e.y 173| 0| } 174| 0| 175| 0| if _rightAxisMin > e.y 176| 0| { 177| 0| _rightAxisMin = e.y 178| 0| } 179| 0| } 180| 0| } 181| | 182| | /// Adjusts the minimum and maximum values based on the given DataSet. 183| | @objc open func calcMinMax(dataSet d: IChartDataSet) 184| 90| { 185| 90| if _yMax < d.yMax 186| 90| { 187| 85| _yMax = d.yMax 188| 90| } 189| 90| 190| 90| if _yMin > d.yMin 191| 90| { 192| 87| _yMin = d.yMin 193| 90| } 194| 90| 195| 90| if _xMax < d.xMax 196| 90| { 197| 78| _xMax = d.xMax 198| 90| } 199| 90| 200| 90| if _xMin > d.xMin 201| 90| { 202| 78| _xMin = d.xMin 203| 90| } 204| 90| 205| 90| if d.axisDependency == .left 206| 90| { 207| 81| if _leftAxisMax < d.yMax 208| 81| { 209| 56| _leftAxisMax = d.yMax 210| 81| } 211| 81| 212| 81| if _leftAxisMin > d.yMin 213| 81| { 214| 58| _leftAxisMin = d.yMin 215| 81| } 216| 90| } 217| 90| else 218| 90| { 219| 9| if _rightAxisMax < d.yMax 220| 9| { 221| 6| _rightAxisMax = d.yMax 222| 9| } 223| 9| 224| 9| if _rightAxisMin > d.yMin 225| 9| { 226| 6| _rightAxisMin = d.yMin 227| 9| } 228| 90| } 229| 90| } 230| | 231| | /// The number of LineDataSets this object contains 232| | @objc open var dataSetCount: Int 233| 1.67k| { 234| 1.67k| return _dataSets.count 235| 1.67k| } 236| | 237| | /// The smallest y-value the data object contains. 238| | @objc open var yMin: Double 239| 21| { 240| 21| return _yMin 241| 21| } 242| | 243| | @nonobjc 244| | open func getYMin() -> Double 245| 52| { 246| 52| return _yMin 247| 52| } 248| | 249| | @objc open func getYMin(axis: YAxis.AxisDependency) -> Double 250| 158| { 251| 158| if axis == .left 252| 158| { 253| 79| if _leftAxisMin == Double.greatestFiniteMagnitude 254| 79| { 255| 7| return _rightAxisMin 256| 72| } 257| 72| else 258| 72| { 259| 72| return _leftAxisMin 260| 72| } 261| 79| } 262| 79| else 263| 79| { 264| 79| if _rightAxisMin == Double.greatestFiniteMagnitude 265| 79| { 266| 71| return _leftAxisMin 267| 71| } 268| 8| else 269| 8| { 270| 8| return _rightAxisMin 271| 8| } 272| 0| } 273| 0| } 274| | 275| | /// The greatest y-value the data object contains. 276| | @objc open var yMax: Double 277| 21| { 278| 21| return _yMax 279| 21| } 280| | 281| | @nonobjc 282| | open func getYMax() -> Double 283| 52| { 284| 52| return _yMax 285| 52| } 286| | 287| | @objc open func getYMax(axis: YAxis.AxisDependency) -> Double 288| 158| { 289| 158| if axis == .left 290| 158| { 291| 79| if _leftAxisMax == -Double.greatestFiniteMagnitude 292| 79| { 293| 7| return _rightAxisMax 294| 72| } 295| 72| else 296| 72| { 297| 72| return _leftAxisMax 298| 72| } 299| 79| } 300| 79| else 301| 79| { 302| 79| if _rightAxisMax == -Double.greatestFiniteMagnitude 303| 79| { 304| 71| return _leftAxisMax 305| 71| } 306| 8| else 307| 8| { 308| 8| return _rightAxisMax 309| 8| } 310| 0| } 311| 0| } 312| | 313| | /// The minimum x-value the data object contains. 314| | @objc open var xMin: Double 315| 100| { 316| 100| return _xMin 317| 100| } 318| | /// The maximum x-value the data object contains. 319| | @objc open var xMax: Double 320| 100| { 321| 100| return _xMax 322| 100| } 323| | 324| | /// All DataSet objects this ChartData object holds. 325| | @objc open var dataSets: [IChartDataSet] 326| | { 327| | get 328| 665| { 329| 665| return _dataSets 330| 665| } 331| | set 332| 0| { 333| 0| _dataSets = newValue 334| 0| notifyDataChanged() 335| 0| } 336| | } 337| | 338| | /// Retrieve the index of a ChartDataSet with a specific label from the ChartData. Search can be case sensitive or not. 339| | /// 340| | /// **IMPORTANT: This method does calculations at runtime, do not over-use in performance critical situations.** 341| | /// 342| | /// - Parameters: 343| | /// - dataSets: the DataSet array to search 344| | /// - type: 345| | /// - ignorecase: if true, the search is not case-sensitive 346| | /// - Returns: The index of the DataSet Object with the given label. Sensitive or not. 347| | internal func getDataSetIndexByLabel(_ label: String, ignorecase: Bool) -> Int 348| 12| { 349| 12| // TODO: Return nil instead of -1 350| 12| if ignorecase 351| 12| { 352| 15| return dataSets.firstIndex { $0.label?.caseInsensitiveCompare(label) == .orderedSame } 353| 7| ?? -1 354| 7| } 355| 5| else 356| 5| { 357| 12| return dataSets.firstIndex { $0.label == label } 358| 5| ?? -1 359| 5| } 360| 0| } 361| | 362| | /// Get the Entry for a corresponding highlight object 363| | /// 364| | /// - Parameters: 365| | /// - highlight: 366| | /// - Returns: The entry that is highlighted 367| | @objc open func entryForHighlight(_ highlight: Highlight) -> ChartDataEntry? 368| 0| { 369| 0| if highlight.dataSetIndex >= dataSets.count 370| 0| { 371| 0| return nil 372| 0| } 373| 0| else 374| 0| { 375| 0| return dataSets[highlight.dataSetIndex].entryForXValue(highlight.x, closestToY: highlight.y) 376| 0| } 377| 0| } 378| | 379| | /// **IMPORTANT: This method does calculations at runtime. Use with care in performance critical situations.** 380| | /// 381| | /// - Parameters: 382| | /// - label: 383| | /// - ignorecase: 384| | /// - Returns: The DataSet Object with the given label. Sensitive or not. 385| | @objc open func getDataSetByLabel(_ label: String, ignorecase: Bool) -> IChartDataSet? 386| 12| { 387| 12| let index = getDataSetIndexByLabel(label, ignorecase: ignorecase) 388| 12| 389| 12| if index < 0 || index >= _dataSets.count 390| 12| { 391| 3| return nil 392| 9| } 393| 9| else 394| 9| { 395| 9| return _dataSets[index] 396| 9| } 397| 0| } 398| | 399| | @objc open func getDataSetByIndex(_ index: Int) -> IChartDataSet! 400| 150| { 401| 150| if index < 0 || index >= _dataSets.count 402| 150| { 403| 0| return nil 404| 150| } 405| 150| 406| 150| return _dataSets[index] 407| 150| } 408| | 409| | @objc open func addDataSet(_ dataSet: IChartDataSet!) 410| 0| { 411| 0| calcMinMax(dataSet: dataSet) 412| 0| 413| 0| _dataSets.append(dataSet) 414| 0| } 415| | 416| | /// Removes the given DataSet from this data object. 417| | /// Also recalculates all minimum and maximum values. 418| | /// 419| | /// - Returns: `true` if a DataSet was removed, `false` ifno DataSet could be removed. 420| | @objc @discardableResult open func removeDataSet(_ dataSet: IChartDataSet) -> Bool 421| 0| { 422| 0| guard let i = _dataSets.firstIndex(where: { $0 === dataSet }) else { return false } 423| 0| return removeDataSetByIndex(i) 424| 0| } 425| | 426| | /// Removes the DataSet at the given index in the DataSet array from the data object. 427| | /// Also recalculates all minimum and maximum values. 428| | /// 429| | /// - Returns: `true` if a DataSet was removed, `false` ifno DataSet could be removed. 430| | @objc @discardableResult open func removeDataSetByIndex(_ index: Int) -> Bool 431| 0| { 432| 0| if index >= _dataSets.count || index < 0 433| 0| { 434| 0| return false 435| 0| } 436| 0| 437| 0| _dataSets.remove(at: index) 438| 0| 439| 0| calcMinMax() 440| 0| 441| 0| return true 442| 0| } 443| | 444| | /// Adds an Entry to the DataSet at the specified index. Entries are added to the end of the list. 445| | @objc open func addEntry(_ e: ChartDataEntry, dataSetIndex: Int) 446| 0| { 447| 0| if _dataSets.count > dataSetIndex && dataSetIndex >= 0 448| 0| { 449| 0| let set = _dataSets[dataSetIndex] 450| 0| 451| 0| if !set.addEntry(e) { return } 452| 0| 453| 0| calcMinMax(entry: e, axis: set.axisDependency) 454| 0| } 455| 0| else 456| 0| { 457| 0| print("ChartData.addEntry() - Cannot add Entry because dataSetIndex too high or too low.", terminator: "\n") 458| 0| } 459| 0| } 460| | 461| | /// Removes the given Entry object from the DataSet at the specified index. 462| | @objc @discardableResult open func removeEntry(_ entry: ChartDataEntry, dataSetIndex: Int) -> Bool 463| 0| { 464| 0| // entry outofbounds 465| 0| if dataSetIndex >= _dataSets.count 466| 0| { 467| 0| return false 468| 0| } 469| 0| 470| 0| // remove the entry from the dataset 471| 0| let removed = _dataSets[dataSetIndex].removeEntry(entry) 472| 0| 473| 0| if removed 474| 0| { 475| 0| calcMinMax() 476| 0| } 477| 0| 478| 0| return removed 479| 0| } 480| | 481| | /// Removes the Entry object closest to the given xIndex from the ChartDataSet at the 482| | /// specified index. 483| | /// 484| | /// - Returns: `true` if an entry was removed, `false` ifno Entry was found that meets the specified requirements. 485| | @objc @discardableResult open func removeEntry(xValue: Double, dataSetIndex: Int) -> Bool 486| 0| { 487| 0| if dataSetIndex >= _dataSets.count 488| 0| { 489| 0| return false 490| 0| } 491| 0| 492| 0| if let entry = _dataSets[dataSetIndex].entryForXValue(xValue, closestToY: Double.nan) 493| 0| { 494| 0| return removeEntry(entry, dataSetIndex: dataSetIndex) 495| 0| } 496| 0| 497| 0| return false 498| 0| } 499| | 500| | /// - Returns: The DataSet that contains the provided Entry, or null, if no DataSet contains this entry. 501| | @objc open func getDataSetForEntry(_ e: ChartDataEntry) -> IChartDataSet? 502| 0| { 503| 0| return _dataSets.first { $0.entryForXValue(e.x, closestToY: e.y) === e } 504| 0| } 505| | 506| | /// - Returns: The index of the provided DataSet in the DataSet array of this data object, or -1 if it does not exist. 507| | @objc open func indexOfDataSet(_ dataSet: IChartDataSet) -> Int 508| 0| { 509| 0| // TODO: Return nil instead of -1 510| 0| return _dataSets.firstIndex { $0 === dataSet } ?? -1 511| 0| } 512| | 513| | /// - 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. 514| | @objc open func getFirstLeft(dataSets: [IChartDataSet]) -> IChartDataSet? 515| 84| { 516| 84| return dataSets.first { $0.axisDependency == .left } 517| 84| } 518| | 519| | /// - 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. 520| | @objc open func getFirstRight(dataSets: [IChartDataSet]) -> IChartDataSet? 521| 84| { 522| 90| return dataSets.first { $0.axisDependency == .right } 523| 84| } 524| | 525| | /// - Returns: All colors used across all DataSet objects this object represents. 526| | @objc open func getColors() -> [NSUIColor]? 527| 0| { 528| 0| // TODO: Don't return nil 529| 0| return _dataSets.flatMap { $0.colors } 530| 0| } 531| | 532| | /// Sets a custom IValueFormatter for all DataSets this data object contains. 533| | @objc open func setValueFormatter(_ formatter: IValueFormatter) 534| 0| { 535| 0| dataSets.forEach { $0.valueFormatter = formatter } 536| 0| } 537| | 538| | /// Sets the color of the value-text (color in which the value-labels are drawn) for all DataSets this data object contains. 539| | @objc open func setValueTextColor(_ color: NSUIColor) 540| 0| { 541| 0| dataSets.forEach { $0.valueTextColor = color } 542| 0| } 543| | 544| | /// Sets the font for all value-labels for all DataSets this data object contains. 545| | @objc open func setValueFont(_ font: NSUIFont) 546| 0| { 547| 0| dataSets.forEach { $0.valueFont = font } 548| 0| } 549| | 550| | /// Enables / disables drawing values (value-text) for all DataSets this data object contains. 551| | @objc open func setDrawValues(_ enabled: Bool) 552| 0| { 553| 0| dataSets.forEach { $0.drawValuesEnabled = enabled } 554| 0| } 555| | 556| | /// Enables / disables highlighting values for all DataSets this data object contains. 557| | /// If set to true, this means that values can be highlighted programmatically or by touch gesture. 558| | @objc open var highlightEnabled: Bool 559| | { 560| 0| get { return dataSets.allSatisfy { $0.highlightEnabled } } 561| 0| set { dataSets.forEach { $0.highlightEnabled = newValue } } 562| | } 563| | 564| | /// if true, value highlightning is enabled 565| 0| @objc open var isHighlightEnabled: Bool { return highlightEnabled } 566| | 567| | /// Clears this data object from all DataSets and removes all Entries. 568| | /// Don't forget to invalidate the chart after this. 569| | @objc open func clearValues() 570| 0| { 571| 0| dataSets.removeAll(keepingCapacity: false) 572| 0| notifyDataChanged() 573| 0| } 574| | 575| | /// Checks if this data object contains the specified DataSet. 576| | /// 577| | /// - Returns: `true` if so, `false` ifnot. 578| | @objc open func contains(dataSet: IChartDataSet) -> Bool 579| 0| { 580| 0| return dataSets.contains { $0 === dataSet } 581| 0| } 582| | 583| | /// The total entry count across all DataSet objects this data object contains. 584| | @objc open var entryCount: Int 585| 149| { 586| 158| return _dataSets.reduce(0) { $0 + $1.entryCount } 587| 149| } 588| | 589| | /// The DataSet object with the maximum number of entries or null if there are no DataSets. 590| | @objc open var maxEntryCountSet: IChartDataSet? 591| 37| { 592| 37| return dataSets.max { $0.entryCount < $1.entryCount } 593| 37| } 594| | 595| | // MARK: - Accessibility 596| | 597| | /// When the data entry labels are generated identifiers, set this property to prepend a string before each identifier 598| | /// 599| | /// For example, if a label is "#3", settings this property to "Item" allows it to be spoken as "Item #3" 600| | @objc open var accessibilityEntryLabelPrefix: String? 601| | 602| | /// When the data entry value requires a unit, use this property to append the string representation of the unit to the value 603| | /// 604| | /// For example, if a value is "44.1", setting this property to "m" allows it to be spoken as "44.1 m" 605| | @objc open var accessibilityEntryLabelSuffix: String? 606| | 607| | /// If the data entry value is a count, set this to true to allow plurals and other grammatical changes 608| | /// **default**: false 609| | @objc open var accessibilityEntryLabelSuffixIsCount: Bool = false 610| |} /Users/travis/build/danielgindi/Charts/Source/Charts/Data/Implementations/Standard/ChartDataEntry.swift: 1| |// 2| |// ChartDataEntry.swift 3| |// Charts 4| |// 5| |// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda 6| |// A port of MPAndroidChart for iOS 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| | 12| |import Foundation 13| | 14| |open class ChartDataEntry: ChartDataEntryBase, NSCopying 15| |{ 16| | /// the x value 17| | @objc open var x = 0.0 18| | 19| | public required init() 20| 0| { 21| 0| super.init() 22| 0| } 23| | 24| | /// An Entry represents one single entry in the chart. 25| | /// 26| | /// - Parameters: 27| | /// - x: the x value 28| | /// - y: the y value (the actual value of the entry) 29| | @objc public init(x: Double, y: Double) 30| 1.41k| { 31| 1.41k| super.init(y: y) 32| 1.41k| self.x = x 33| 1.41k| } 34| | 35| | /// An Entry represents one single entry in the chart. 36| | /// 37| | /// - Parameters: 38| | /// - x: the x value 39| | /// - y: the y value (the actual value of the entry) 40| | /// - data: Space for additional data this Entry represents. 41| | 42| | @objc public convenience init(x: Double, y: Double, data: Any?) 43| 0| { 44| 0| self.init(x: x, y: y) 45| 0| self.data = data 46| 0| } 47| | 48| | /// An Entry represents one single entry in the chart. 49| | /// 50| | /// - Parameters: 51| | /// - x: the x value 52| | /// - y: the y value (the actual value of the entry) 53| | /// - icon: icon image 54| | 55| | @objc public convenience init(x: Double, y: Double, icon: NSUIImage?) 56| 270| { 57| 270| self.init(x: x, y: y) 58| 270| self.icon = icon 59| 270| } 60| | 61| | /// An Entry represents one single entry in the chart. 62| | /// 63| | /// - Parameters: 64| | /// - x: the x value 65| | /// - y: the y value (the actual value of the entry) 66| | /// - icon: icon image 67| | /// - data: Space for additional data this Entry represents. 68| | 69| | @objc public convenience init(x: Double, y: Double, icon: NSUIImage?, data: Any?) 70| 4| { 71| 4| self.init(x: x, y: y) 72| 4| self.icon = icon 73| 4| self.data = data 74| 4| } 75| | 76| | // MARK: NSObject 77| | 78| | open override var description: String 79| 0| { 80| 0| return "ChartDataEntry, x: \(x), y \(y)" 81| 0| } 82| | 83| | // MARK: NSCopying 84| | 85| | open func copy(with zone: NSZone? = nil) -> Any 86| 0| { 87| 0| let copy = type(of: self).init() 88| 0| 89| 0| copy.x = x 90| 0| copy.y = y 91| 0| copy.data = data 92| 0| 93| 0| return copy 94| 0| } 95| |} 96| | 97| |// MARK: Equatable 98| |extension ChartDataEntry/*: Equatable*/ { 99| 808| open override func isEqual(_ object: Any?) -> Bool { 100| 808| guard let object = object as? ChartDataEntry else { return false } 101| 808| 102| 808| if self === object 103| 808| { 104| 52| return true 105| 756| } 106| 756| 107| 756| return y == object.y 108| 756| && x == object.x 109| 808| } 110| |} /Users/travis/build/danielgindi/Charts/Source/Charts/Data/Implementations/Standard/ChartDataEntryBase.swift: 1| |// 2| |// ChartDataEntryBase.swift 3| |// Charts 4| |// 5| |// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda 6| |// A port of MPAndroidChart for iOS 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| | 12| |import Foundation 13| | 14| |open class ChartDataEntryBase: NSObject 15| |{ 16| | /// the y value 17| | @objc open var y = 0.0 18| | 19| | /// optional spot for additional data this Entry represents 20| | @objc open var data: Any? 21| | 22| | /// optional icon image 23| | @objc open var icon: NSUIImage? 24| | 25| | public override required init() 26| 0| { 27| 0| super.init() 28| 0| } 29| | 30| | /// An Entry represents one single entry in the chart. 31| | /// 32| | /// - Parameters: 33| | /// - y: the y value (the actual value of the entry) 34| | @objc public init(y: Double) 35| 1.41k| { 36| 1.41k| super.init() 37| 1.41k| 38| 1.41k| self.y = y 39| 1.41k| } 40| | 41| | /// - Parameters: 42| | /// - y: the y value (the actual value of the entry) 43| | /// - data: Space for additional data this Entry represents. 44| | 45| | @objc public convenience init(y: Double, data: Any?) 46| 0| { 47| 0| self.init(y: y) 48| 0| 49| 0| self.data = data 50| 0| } 51| | 52| | /// - Parameters: 53| | /// - y: the y value (the actual value of the entry) 54| | /// - icon: icon image 55| | 56| | @objc public convenience init(y: Double, icon: NSUIImage?) 57| 0| { 58| 0| self.init(y: y) 59| 0| 60| 0| self.icon = icon 61| 0| } 62| | 63| | /// - Parameters: 64| | /// - y: the y value (the actual value of the entry) 65| | /// - icon: icon image 66| | /// - data: Space for additional data this Entry represents. 67| | 68| | @objc public convenience init(y: Double, icon: NSUIImage?, data: Any?) 69| 0| { 70| 0| self.init(y: y) 71| 0| 72| 0| self.icon = icon 73| 0| self.data = data 74| 0| } 75| | 76| | // MARK: NSObject 77| | 78| | open override var description: String 79| 0| { 80| 0| return "ChartDataEntryBase, y \(y)" 81| 0| } 82| |} 83| | 84| |// MARK: Equatable 85| |extension ChartDataEntryBase/*: Equatable*/ { 86| 0| open override func isEqual(_ object: Any?) -> Bool { 87| 0| guard let object = object as? ChartDataEntryBase else { return false } 88| 0| 89| 0| if self === object 90| 0| { 91| 0| return true 92| 0| } 93| 0| 94| 0| return y == object.y 95| 0| } 96| |} /Users/travis/build/danielgindi/Charts/Source/Charts/Data/Implementations/Standard/ChartDataSet.swift: 1| |// 2| |// ChartDataSet.swift 3| |// Charts 4| |// 5| |// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda 6| |// A port of MPAndroidChart for iOS 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| | 12| |import Foundation 13| | 14| |/// Determines how to round DataSet index values for `ChartDataSet.entryIndex(x, rounding)` when an exact x-value is not found. 15| |@objc 16| |public enum ChartDataSetRounding: Int 17| |{ 18| | case up = 0 19| | case down = 1 20| | case closest = 2 21| |} 22| | 23| |/// The DataSet class represents one group or type of entries (Entry) in the Chart that belong together. 24| |/// It is designed to logically separate different groups of values inside the Chart (e.g. the values for a specific line in the LineChart, or the values of a specific group of bars in the BarChart). 25| |open class ChartDataSet: ChartBaseDataSet 26| |{ 27| | public required init() 28| 0| { 29| 0| entries = [] 30| 0| 31| 0| super.init() 32| 0| } 33| | 34| | public override convenience init(label: String?) 35| 0| { 36| 0| self.init(entries: nil, label: label) 37| 0| } 38| | 39| | @objc public init(entries: [ChartDataEntry]?, label: String?) 40| 64| { 41| 64| self.entries = entries ?? [] 42| 64| 43| 64| super.init(label: label) 44| 64| 45| 64| self.calcMinMax() 46| 64| } 47| | 48| | @objc public convenience init(entries: [ChartDataEntry]?) 49| 1| { 50| 1| self.init(entries: entries, label: "DataSet") 51| 1| } 52| | 53| | // MARK: - Data functions and accessors 54| | 55| | /// - Note: Calls `notifyDataSetChanged()` after setting a new value. 56| | /// - Returns: The array of y-values that this DataSet represents. 57| | /// the entries that this dataset represents / holds together 58| | @available(*, unavailable, renamed: "entries") 59| | @objc 60| 0| open var values: [ChartDataEntry] { return entries } 61| | 62| | @objc 63| | open private(set) var entries: [ChartDataEntry] 64| | 65| | /// Used to replace all entries of a data set while retaining styling properties. 66| | /// This is a separate method from a setter on `entries` to encourage usage 67| | /// of `Collection` conformances. 68| | /// 69| | /// - Parameter entries: new entries to replace existing entries in the dataset 70| | @objc 71| 0| public func replaceEntries(_ entries: [ChartDataEntry]) { 72| 0| self.entries = entries 73| 0| notifyDataSetChanged() 74| 0| } 75| | 76| | /// maximum y-value in the value array 77| | internal var _yMax: Double = -Double.greatestFiniteMagnitude 78| | 79| | /// minimum y-value in the value array 80| | internal var _yMin: Double = Double.greatestFiniteMagnitude 81| | 82| | /// maximum x-value in the value array 83| | internal var _xMax: Double = -Double.greatestFiniteMagnitude 84| | 85| | /// minimum x-value in the value array 86| | internal var _xMin: Double = Double.greatestFiniteMagnitude 87| | 88| | open override func calcMinMax() 89| 64| { 90| 64| _yMax = -Double.greatestFiniteMagnitude 91| 64| _yMin = Double.greatestFiniteMagnitude 92| 64| _xMax = -Double.greatestFiniteMagnitude 93| 64| _xMin = Double.greatestFiniteMagnitude 94| 64| 95| 64| guard !isEmpty else { return } 96| 64| 97| 64| forEach(calcMinMax) 98| 64| } 99| | 100| | open override func calcMinMaxY(fromX: Double, toX: Double) 101| 0| { 102| 0| _yMax = -Double.greatestFiniteMagnitude 103| 0| _yMin = Double.greatestFiniteMagnitude 104| 0| 105| 0| guard !isEmpty else { return } 106| 0| 107| 0| let indexFrom = entryIndex(x: fromX, closestToY: Double.nan, rounding: .down) 108| 0| let indexTo = entryIndex(x: toX, closestToY: Double.nan, rounding: .up) 109| 0| 110| 0| guard !(indexTo < indexFrom) else { return } 111| 0| // only recalculate y 112| 0| self[indexFrom...indexTo].forEach(calcMinMaxY) 113| 0| } 114| | 115| | @objc open func calcMinMaxX(entry e: ChartDataEntry) 116| 1.36k| { 117| 1.36k| if e.x < _xMin 118| 1.36k| { 119| 58| _xMin = e.x 120| 1.36k| } 121| 1.36k| if e.x > _xMax 122| 1.36k| { 123| 1.36k| _xMax = e.x 124| 1.36k| } 125| 1.36k| } 126| | 127| | @objc open func calcMinMaxY(entry e: ChartDataEntry) 128| 357| { 129| 357| if e.y < _yMin 130| 357| { 131| 33| _yMin = e.y 132| 357| } 133| 357| if e.y > _yMax 134| 357| { 135| 75| _yMax = e.y 136| 357| } 137| 357| } 138| | 139| | /// Updates the min and max x and y value of this DataSet based on the given Entry. 140| | /// 141| | /// - Parameters: 142| | /// - e: 143| | internal func calcMinMax(entry e: ChartDataEntry) 144| 315| { 145| 315| calcMinMaxX(entry: e) 146| 315| calcMinMaxY(entry: e) 147| 315| } 148| | 149| | /// The minimum y-value this DataSet holds 150| 530| open override var yMin: Double { return _yMin } 151| | 152| | /// The maximum y-value this DataSet holds 153| 524| open override var yMax: Double { return _yMax } 154| | 155| | /// The minimum x-value this DataSet holds 156| 168| open override var xMin: Double { return _xMin } 157| | 158| | /// The maximum x-value this DataSet holds 159| 168| open override var xMax: Double { return _xMax } 160| | 161| | /// The number of y-values this DataSet represents 162| | @available(*, deprecated, message: "Use `count` instead") 163| 566| open override var entryCount: Int { return count } 164| | 165| | /// - Throws: out of bounds 166| | /// if `i` is out of bounds, it may throw an out-of-bounds exception 167| | /// - Returns: The entry object found at the given index (not x-value!) 168| | @available(*, deprecated, message: "Use `subscript(index:)` instead.") 169| | open override func entryForIndex(_ i: Int) -> ChartDataEntry? 170| 4.65k| { 171| 4.65k| guard i >= startIndex, i < endIndex else { 172| 0| return nil 173| 4.65k| } 174| 4.65k| return self[i] 175| 4.65k| } 176| | 177| | /// - Parameters: 178| | /// - xValue: the x-value 179| | /// - closestToY: If there are multiple y-values for the specified x-value, 180| | /// - rounding: determine whether to round up/down/closest if there is no Entry matching the provided x-value 181| | /// - Returns: The first Entry object found at the given x-value with binary search. 182| | /// If the no Entry at the specified x-value is found, this method returns the Entry at the closest x-value according to the rounding. 183| | /// nil if no Entry object at that x-value. 184| | open override func entryForXValue( 185| | _ xValue: Double, 186| | closestToY yValue: Double, 187| | rounding: ChartDataSetRounding) -> ChartDataEntry? 188| 52| { 189| 52| let index = entryIndex(x: xValue, closestToY: yValue, rounding: rounding) 190| 52| if index > -1 191| 52| { 192| 52| return self[index] 193| 52| } 194| 0| return nil 195| 52| } 196| | 197| | /// - Parameters: 198| | /// - xValue: the x-value 199| | /// - closestToY: If there are multiple y-values for the specified x-value, 200| | /// - Returns: The first Entry object found at the given x-value with binary search. 201| | /// If the no Entry at the specified x-value is found, this method returns the Entry at the closest x-value. 202| | /// nil if no Entry object at that x-value. 203| | open override func entryForXValue( 204| | _ xValue: Double, 205| | closestToY yValue: Double) -> ChartDataEntry? 206| 0| { 207| 0| return entryForXValue(xValue, closestToY: yValue, rounding: .closest) 208| 0| } 209| | 210| | /// - Returns: All Entry objects found at the given xIndex with binary search. 211| | /// An empty array if no Entry object at that index. 212| | open override func entriesForXValue(_ xValue: Double) -> [ChartDataEntry] 213| 0| { 214| 0| var entries = [ChartDataEntry]() 215| 0| 216| 0| var low = startIndex 217| 0| var high = endIndex - 1 218| 0| 219| 0| while low <= high 220| 0| { 221| 0| var m = (high + low) / 2 222| 0| var entry = self[m] 223| 0| 224| 0| // if we have a match 225| 0| if xValue == entry.x 226| 0| { 227| 0| while m > 0 && self[m - 1].x == xValue 228| 0| { 229| 0| m -= 1 230| 0| } 231| 0| 232| 0| high = endIndex 233| 0| 234| 0| // loop over all "equal" entries 235| 0| while m < high 236| 0| { 237| 0| entry = self[m] 238| 0| if entry.x == xValue 239| 0| { 240| 0| entries.append(entry) 241| 0| } 242| 0| else 243| 0| { 244| 0| break 245| 0| } 246| 0| 247| 0| m += 1 248| 0| } 249| 0| 250| 0| break 251| 0| } 252| 0| else 253| 0| { 254| 0| if xValue > entry.x 255| 0| { 256| 0| low = m + 1 257| 0| } 258| 0| else 259| 0| { 260| 0| high = m - 1 261| 0| } 262| 0| } 263| 0| } 264| 0| 265| 0| return entries 266| 0| } 267| | 268| | /// - Parameters: 269| | /// - xValue: x-value of the entry to search for 270| | /// - closestToY: If there are multiple y-values for the specified x-value, 271| | /// - rounding: Rounding method if exact value was not found 272| | /// - Returns: The array-index of the specified entry. 273| | /// If the no Entry at the specified x-value is found, this method returns the index of the Entry at the closest x-value according to the rounding. 274| | open override func entryIndex( 275| | x xValue: Double, 276| | closestToY yValue: Double, 277| | rounding: ChartDataSetRounding) -> Int 278| 52| { 279| 52| var low = startIndex 280| 52| var high = endIndex - 1 281| 52| var closest = high 282| 52| 283| 286| while low < high 284| 234| { 285| 234| let m = (low + high) / 2 286| 234| 287| 234| let d1 = self[m].x - xValue 288| 234| let d2 = self[m + 1].x - xValue 289| 234| let ad1 = abs(d1), ad2 = abs(d2) 290| 234| 291| 234| if ad2 < ad1 292| 234| { 293| 104| // [m + 1] is closer to xValue 294| 104| // Search in an higher place 295| 104| low = m + 1 296| 234| } 297| 234| else if ad1 < ad2 298| 234| { 299| 130| // [m] is closer to xValue 300| 130| // Search in a lower place 301| 130| high = m 302| 234| } 303| 234| else 304| 234| { 305| 104| // We have multiple sequential x-value with same distance 306| 104| 307| 104| if d1 >= 0.0 308| 104| { 309| 0| // Search in a lower place 310| 0| high = m 311| 104| } 312| 104| else if d1 < 0.0 313| 104| { 314| 0| // Search in an higher place 315| 0| low = m + 1 316| 104| } 317| 234| } 318| 234| 319| 234| closest = high 320| 234| } 321| 52| 322| 52| if closest != -1 323| 52| { 324| 52| let closestXValue = self[closest].x 325| 52| 326| 52| if rounding == .up 327| 52| { 328| 26| // If rounding up, and found x-value is lower than specified x, and we can go upper... 329| 26| if closestXValue < xValue && closest < endIndex - 1 330| 26| { 331| 0| closest += 1 332| 26| } 333| 52| } 334| 52| else if rounding == .down 335| 52| { 336| 26| // If rounding down, and found x-value is upper than specified x, and we can go lower... 337| 26| if closestXValue > xValue && closest > 0 338| 26| { 339| 0| closest -= 1 340| 26| } 341| 52| } 342| 52| 343| 52| // Search by closest to y-value 344| 52| if !yValue.isNaN 345| 52| { 346| 0| while closest > 0 && self[closest - 1].x == closestXValue 347| 0| { 348| 0| closest -= 1 349| 0| } 350| 0| 351| 0| var closestYValue = self[closest].y 352| 0| var closestYIndex = closest 353| 0| 354| 0| while true 355| 0| { 356| 0| closest += 1 357| 0| if closest >= endIndex { break } 358| 0| 359| 0| let value = self[closest] 360| 0| 361| 0| if value.x != closestXValue { break } 362| 0| if abs(value.y - yValue) <= abs(closestYValue - yValue) 363| 0| { 364| 0| closestYValue = yValue 365| 0| closestYIndex = closest 366| 0| } 367| 0| } 368| 0| 369| 0| closest = closestYIndex 370| 52| } 371| 52| } 372| 52| 373| 52| return closest 374| 52| } 375| | 376| | /// - Parameters: 377| | /// - e: the entry to search for 378| | /// - Returns: The array-index of the specified entry 379| | @available(*, deprecated, message: "Use `firstIndex(of:)` or `lastIndex(of:)`") 380| | open override func entryIndex(entry e: ChartDataEntry) -> Int 381| 52| { 382| 52| return firstIndex(of: e) ?? -1 383| 52| } 384| | 385| | /// Adds an Entry to the DataSet dynamically. 386| | /// Entries are added to the end of the list. 387| | /// This will also recalculate the current minimum and maximum values of the DataSet and the value-sum. 388| | /// 389| | /// - Parameters: 390| | /// - e: the entry to add 391| | /// - Returns: True 392| | @available(*, deprecated, message: "Use `append(_:)` instead") 393| | open override func addEntry(_ e: ChartDataEntry) -> Bool 394| 0| { 395| 0| append(e) 396| 0| return true 397| 0| } 398| | 399| | /// Adds an Entry to the DataSet dynamically. 400| | /// Entries are added to their appropriate index respective to it's x-index. 401| | /// This will also recalculate the current minimum and maximum values of the DataSet and the value-sum. 402| | /// 403| | /// - Parameters: 404| | /// - e: the entry to add 405| | /// - Returns: True 406| | open override func addEntryOrdered(_ e: ChartDataEntry) -> Bool 407| 0| { 408| 0| calcMinMax(entry: e) 409| 0| 410| 0| if let last = last, last.x > e.x 411| 0| { 412| 0| var closestIndex = entryIndex(x: e.x, closestToY: e.y, rounding: .up) 413| 0| while self[closestIndex].x < e.x 414| 0| { 415| 0| closestIndex += 1 416| 0| } 417| 0| entries.insert(e, at: closestIndex) 418| 0| } 419| 0| else 420| 0| { 421| 0| append(e) 422| 0| } 423| 0| 424| 0| return true 425| 0| } 426| | 427| | @available(*, renamed: "remove(_:)") 428| | open override func removeEntry(_ entry: ChartDataEntry) -> Bool 429| 0| { 430| 0| return remove(entry) 431| 0| } 432| | 433| | /// Removes an Entry from the DataSet dynamically. 434| | /// This will also recalculate the current minimum and maximum values of the DataSet and the value-sum. 435| | /// 436| | /// - Parameters: 437| | /// - entry: the entry to remove 438| | /// - Returns: `true` if the entry was removed successfully, else if the entry does not exist 439| | open func remove(_ entry: ChartDataEntry) -> Bool 440| 0| { 441| 0| guard let index = firstIndex(of: entry) else { return false } 442| 0| _ = remove(at: index) 443| 0| return true 444| 0| } 445| | 446| | /// Removes the first Entry (at index 0) of this DataSet from the entries array. 447| | /// 448| | /// - Returns: `true` if successful, `false` if not. 449| | @available(*, deprecated, message: "Use `func removeFirst() -> ChartDataEntry` instead.") 450| | open override func removeFirst() -> Bool 451| 0| { 452| 0| let entry: ChartDataEntry? = isEmpty ? nil : removeFirst() 453| 0| return entry != nil 454| 0| } 455| | 456| | /// Removes the last Entry (at index size-1) of this DataSet from the entries array. 457| | /// 458| | /// - Returns: `true` if successful, `false` if not. 459| | @available(*, deprecated, message: "Use `func removeLast() -> ChartDataEntry` instead.") 460| | open override func removeLast() -> Bool 461| 0| { 462| 0| let entry: ChartDataEntry? = isEmpty ? nil : removeLast() 463| 0| return entry != nil 464| 0| } 465| | 466| | /// Removes all values from this DataSet and recalculates min and max value. 467| | @available(*, deprecated, message: "Use `removeAll(keepingCapacity:)` instead.") 468| | open override func clear() 469| 0| { 470| 0| removeAll(keepingCapacity: true) 471| 0| } 472| | 473| | // MARK: - Data functions and accessors 474| | 475| | // MARK: - NSCopying 476| | 477| | open override func copy(with zone: NSZone? = nil) -> Any 478| 0| { 479| 0| let copy = super.copy(with: zone) as! ChartDataSet 480| 0| 481| 0| copy.entries = entries 482| 0| copy._yMax = _yMax 483| 0| copy._yMin = _yMin 484| 0| copy._xMax = _xMax 485| 0| copy._xMin = _xMin 486| 0| 487| 0| return copy 488| 0| } 489| |} 490| | 491| |// MARK: MutableCollection 492| |extension ChartDataSet: MutableCollection { 493| | public typealias Index = Int 494| | public typealias Element = ChartDataEntry 495| | 496| 6.58k| public var startIndex: Index { 497| 6.58k| return entries.startIndex 498| 6.58k| } 499| | 500| 8.74k| public var endIndex: Index { 501| 8.74k| return entries.endIndex 502| 8.74k| } 503| | 504| 2.16k| public func index(after: Index) -> Index { 505| 2.16k| return entries.index(after: after) 506| 2.16k| } 507| | 508| | @objc 509| | public subscript(position: Index) -> Element { 510| 7.43k| get { 511| 7.43k| // This is intentionally not a safe subscript to mirror 512| 7.43k| // the behaviour of the built in Swift Collection Types 513| 7.43k| return entries[position] 514| 7.43k| } 515| 0| set { 516| 0| calcMinMax(entry: newValue) 517| 0| entries[position] = newValue 518| 0| } 519| | } 520| |} 521| | 522| |// MARK: RandomAccessCollection 523| |extension ChartDataSet: RandomAccessCollection { 524| 0| public func index(before: Index) -> Index { 525| 0| return entries.index(before: before) 526| 0| } 527| |} 528| | 529| |// MARK: RangeReplaceableCollection 530| |extension ChartDataSet: RangeReplaceableCollection { 531| 0| public func append(_ newElement: Element) { 532| 0| calcMinMax(entry: newElement) 533| 0| entries.append(newElement) 534| 0| } 535| | 536| 0| public func remove(at position: Index) -> Element { 537| 0| let element = entries.remove(at: position) 538| 0| notifyDataSetChanged() 539| 0| return element 540| 0| } 541| | 542| 0| public func removeFirst() -> Element { 543| 0| let element = entries.removeFirst() 544| 0| notifyDataSetChanged() 545| 0| return element 546| 0| } 547| | 548| 0| public func removeFirst(_ n: Int) { 549| 0| entries.removeFirst(n) 550| 0| notifyDataSetChanged() 551| 0| } 552| | 553| 0| public func removeLast() -> Element { 554| 0| let element = entries.removeLast() 555| 0| notifyDataSetChanged() 556| 0| return element 557| 0| } 558| | 559| 0| public func removeLast(_ n: Int) { 560| 0| entries.removeLast(n) 561| 0| notifyDataSetChanged() 562| 0| } 563| | 564| 0| public func removeSubrange(_ bounds: R) where R : RangeExpression, Index == R.Bound { 565| 0| entries.removeSubrange(bounds) 566| 0| notifyDataSetChanged() 567| 0| } 568| | 569| | @objc 570| 0| public func removeAll(keepingCapacity keepCapacity: Bool) { 571| 0| entries.removeAll(keepingCapacity: keepCapacity) 572| 0| notifyDataSetChanged() 573| 0| } 574| |} /Users/travis/build/danielgindi/Charts/Source/Charts/Data/Implementations/Standard/CombinedChartData.swift: 1| |// 2| |// CombinedChartData.swift 3| |// Charts 4| |// 5| |// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda 6| |// A port of MPAndroidChart for iOS 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| | 12| |import Foundation 13| | 14| |open class CombinedChartData: BarLineScatterCandleBubbleChartData 15| |{ 16| | private var _lineData: LineChartData! 17| | private var _barData: BarChartData! 18| | private var _scatterData: ScatterChartData! 19| | private var _candleData: CandleChartData! 20| | private var _bubbleData: BubbleChartData! 21| | 22| | public override init() 23| 3| { 24| 3| super.init() 25| 3| } 26| | 27| | public override init(dataSets: [IChartDataSet]?) 28| 0| { 29| 0| super.init(dataSets: dataSets) 30| 0| } 31| | 32| | @objc open var lineData: LineChartData! 33| | { 34| | get 35| 25| { 36| 25| return _lineData 37| 25| } 38| | set 39| 3| { 40| 3| _lineData = newValue 41| 3| notifyDataChanged() 42| 3| } 43| | } 44| | 45| | @objc open var barData: BarChartData! 46| | { 47| | get 48| 36| { 49| 36| return _barData 50| 36| } 51| | set 52| 3| { 53| 3| _barData = newValue 54| 3| notifyDataChanged() 55| 3| } 56| | } 57| | 58| | @objc open var scatterData: ScatterChartData! 59| | { 60| | get 61| 11| { 62| 11| return _scatterData 63| 11| } 64| | set 65| 0| { 66| 0| _scatterData = newValue 67| 0| notifyDataChanged() 68| 0| } 69| | } 70| | 71| | @objc open var candleData: CandleChartData! 72| | { 73| | get 74| 11| { 75| 11| return _candleData 76| 11| } 77| | set 78| 0| { 79| 0| _candleData = newValue 80| 0| notifyDataChanged() 81| 0| } 82| | } 83| | 84| | @objc open var bubbleData: BubbleChartData! 85| | { 86| | get 87| 11| { 88| 11| return _bubbleData 89| 11| } 90| | set 91| 0| { 92| 0| _bubbleData = newValue 93| 0| notifyDataChanged() 94| 0| } 95| | } 96| | 97| | open override func calcMinMax() 98| 8| { 99| 8| _dataSets.removeAll() 100| 8| 101| 8| _yMax = -Double.greatestFiniteMagnitude 102| 8| _yMin = Double.greatestFiniteMagnitude 103| 8| _xMax = -Double.greatestFiniteMagnitude 104| 8| _xMin = Double.greatestFiniteMagnitude 105| 8| 106| 8| _leftAxisMax = -Double.greatestFiniteMagnitude 107| 8| _leftAxisMin = Double.greatestFiniteMagnitude 108| 8| _rightAxisMax = -Double.greatestFiniteMagnitude 109| 8| _rightAxisMin = Double.greatestFiniteMagnitude 110| 8| 111| 8| let allData = self.allData 112| 8| 113| 8| for data in allData 114| 13| { 115| 13| data.calcMinMax() 116| 13| 117| 13| let sets = data.dataSets 118| 13| _dataSets.append(contentsOf: sets) 119| 13| 120| 13| if data.yMax > _yMax 121| 13| { 122| 8| _yMax = data.yMax 123| 13| } 124| 13| 125| 13| if data.yMin < _yMin 126| 13| { 127| 8| _yMin = data.yMin 128| 13| } 129| 13| 130| 13| if data.xMax > _xMax 131| 13| { 132| 8| _xMax = data.xMax 133| 13| } 134| 13| 135| 13| if data.xMin < _xMin 136| 13| { 137| 8| _xMin = data.xMin 138| 13| } 139| 13| 140| 13| for dataset in sets 141| 13| { 142| 13| if dataset.axisDependency == .left 143| 13| { 144| 10| if dataset.yMax > _leftAxisMax 145| 10| { 146| 7| _leftAxisMax = dataset.yMax 147| 10| } 148| 10| if dataset.yMin < _leftAxisMin 149| 10| { 150| 7| _leftAxisMin = dataset.yMin 151| 10| } 152| 13| } 153| 13| else 154| 13| { 155| 3| if dataset.yMax > _rightAxisMax 156| 3| { 157| 2| _rightAxisMax = dataset.yMax 158| 3| } 159| 3| if dataset.yMin < _rightAxisMin 160| 3| { 161| 2| _rightAxisMin = dataset.yMin 162| 3| } 163| 13| } 164| 13| } 165| 13| } 166| 8| } 167| | 168| | /// All data objects in row: line-bar-scatter-candle-bubble if not null. 169| | @objc open var allData: [ChartData] 170| 8| { 171| 8| var data = [ChartData]() 172| 8| 173| 8| if lineData !== nil 174| 8| { 175| 5| data.append(lineData) 176| 8| } 177| 8| if barData !== nil 178| 8| { 179| 8| data.append(barData) 180| 8| } 181| 8| if scatterData !== nil 182| 8| { 183| 0| data.append(scatterData) 184| 8| } 185| 8| if candleData !== nil 186| 8| { 187| 0| data.append(candleData) 188| 8| } 189| 8| if bubbleData !== nil 190| 8| { 191| 0| data.append(bubbleData) 192| 8| } 193| 8| 194| 8| return data 195| 8| } 196| | 197| | @objc open func dataByIndex(_ index: Int) -> ChartData 198| 0| { 199| 0| return allData[index] 200| 0| } 201| | 202| | open func dataIndex(_ data: ChartData) -> Int? 203| 0| { 204| 0| return allData.firstIndex(of: data) 205| 0| } 206| | 207| | open override func removeDataSet(_ dataSet: IChartDataSet) -> Bool 208| 0| { 209| 0| return allData.contains { $0.removeDataSet(dataSet) } 210| 0| } 211| | 212| | open override func removeDataSetByIndex(_ index: Int) -> Bool 213| 0| { 214| 0| print("removeDataSet(index) not supported for CombinedData", terminator: "\n") 215| 0| return false 216| 0| } 217| | 218| | open override func removeEntry(_ entry: ChartDataEntry, dataSetIndex: Int) -> Bool 219| 0| { 220| 0| print("removeEntry(entry, dataSetIndex) not supported for CombinedData", terminator: "\n") 221| 0| return false 222| 0| } 223| | 224| | open override func removeEntry(xValue: Double, dataSetIndex: Int) -> Bool 225| 0| { 226| 0| print("removeEntry(xValue, dataSetIndex) not supported for CombinedData", terminator: "\n") 227| 0| return false 228| 0| } 229| | 230| | open override func notifyDataChanged() 231| 8| { 232| 8| if _lineData !== nil 233| 8| { 234| 5| _lineData.notifyDataChanged() 235| 8| } 236| 8| if _barData !== nil 237| 8| { 238| 8| _barData.notifyDataChanged() 239| 8| } 240| 8| if _scatterData !== nil 241| 8| { 242| 0| _scatterData.notifyDataChanged() 243| 8| } 244| 8| if _candleData !== nil 245| 8| { 246| 0| _candleData.notifyDataChanged() 247| 8| } 248| 8| if _bubbleData !== nil 249| 8| { 250| 0| _bubbleData.notifyDataChanged() 251| 8| } 252| 8| 253| 8| super.notifyDataChanged() // recalculate everything 254| 8| } 255| | 256| | /// Get the Entry for a corresponding highlight object 257| | /// 258| | /// - Parameters: 259| | /// - highlight: 260| | /// - Returns: The entry that is highlighted 261| | open override func entryForHighlight(_ highlight: Highlight) -> ChartDataEntry? 262| 0| { 263| 0| if highlight.dataIndex >= allData.count 264| 0| { 265| 0| return nil 266| 0| } 267| 0| 268| 0| let data = dataByIndex(highlight.dataIndex) 269| 0| 270| 0| if highlight.dataSetIndex >= data.dataSetCount 271| 0| { 272| 0| return nil 273| 0| } 274| 0| 275| 0| // The value of the highlighted entry could be NaN - if we are not interested in highlighting a specific value. 276| 0| let entries = data.getDataSetByIndex(highlight.dataSetIndex).entriesForXValue(highlight.x) 277| 0| return entries.first { $0.y == highlight.y || highlight.y.isNaN } 278| 0| } 279| | 280| | /// Get dataset for highlight 281| | /// 282| | /// - Parameters: 283| | /// - highlight: current highlight 284| | /// - Returns: dataset related to highlight 285| | @objc open func getDataSetByHighlight(_ highlight: Highlight) -> IChartDataSet! 286| 0| { 287| 0| if highlight.dataIndex >= allData.count 288| 0| { 289| 0| return nil 290| 0| } 291| 0| 292| 0| let data = dataByIndex(highlight.dataIndex) 293| 0| 294| 0| if highlight.dataSetIndex >= data.dataSetCount 295| 0| { 296| 0| return nil 297| 0| } 298| 0| 299| 0| return data.dataSets[highlight.dataSetIndex] 300| 0| } 301| |} /Users/travis/build/danielgindi/Charts/Source/Charts/Data/Implementations/Standard/LineChartData.swift: 1| |// 2| |// LineChartData.swift 3| |// Charts 4| |// 5| |// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda 6| |// A port of MPAndroidChart for iOS 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| | 12| |import Foundation 13| | 14| |/// Data object that encapsulates all data associated with a LineChart. 15| |open class LineChartData: ChartData 16| |{ 17| | public override init() 18| 0| { 19| 0| super.init() 20| 0| } 21| | 22| | public override init(dataSets: [IChartDataSet]?) 23| 9| { 24| 9| super.init(dataSets: dataSets) 25| 9| } 26| |} /Users/travis/build/danielgindi/Charts/Source/Charts/Data/Implementations/Standard/LineChartDataSet.swift: 1| |// 2| |// LineChartDataSet.swift 3| |// Charts 4| |// 5| |// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda 6| |// A port of MPAndroidChart for iOS 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| | 12| |import Foundation 13| |import CoreGraphics 14| | 15| | 16| |open class LineChartDataSet: LineRadarChartDataSet, ILineChartDataSet 17| |{ 18| | @objc(LineChartMode) 19| | public enum Mode: Int 20| | { 21| | case linear 22| | case stepped 23| | case cubicBezier 24| | case horizontalBezier 25| | } 26| | 27| | private func initialize() 28| 9| { 29| 9| // default color 30| 9| circleColors.append(NSUIColor(red: 140.0/255.0, green: 234.0/255.0, blue: 255.0/255.0, alpha: 1.0)) 31| 9| } 32| | 33| | public required init() 34| 0| { 35| 0| super.init() 36| 0| initialize() 37| 0| } 38| | 39| | public override init(entries: [ChartDataEntry]?, label: String?) 40| 9| { 41| 9| super.init(entries: entries, label: label) 42| 9| initialize() 43| 9| } 44| | 45| | // MARK: - Data functions and accessors 46| | 47| | // MARK: - Styling functions and accessors 48| | 49| | /// The drawing mode for this line dataset 50| | /// 51| | /// **default**: Linear 52| | open var mode: Mode = Mode.linear 53| | 54| | private var _cubicIntensity = CGFloat(0.2) 55| | 56| | /// Intensity for cubic lines (min = 0.05, max = 1) 57| | /// 58| | /// **default**: 0.2 59| | open var cubicIntensity: CGFloat 60| | { 61| | get 62| 1| { 63| 1| return _cubicIntensity 64| 1| } 65| | set 66| 0| { 67| 0| _cubicIntensity = newValue.clamped(to: 0.05...1) 68| 0| } 69| | } 70| | 71| | /// The radius of the drawn circles. 72| | open var circleRadius = CGFloat(8.0) 73| | 74| | /// The hole radius of the drawn circles 75| | open var circleHoleRadius = CGFloat(4.0) 76| | 77| | open var circleColors = [NSUIColor]() 78| | 79| | /// - Returns: The color at the given index of the DataSet's circle-color array. 80| | /// Performs a IndexOutOfBounds check by modulus. 81| | open func getCircleColor(atIndex index: Int) -> NSUIColor? 82| 240| { 83| 240| let size = circleColors.count 84| 240| let index = index % size 85| 240| if index >= size 86| 240| { 87| 0| return nil 88| 240| } 89| 240| return circleColors[index] 90| 240| } 91| | 92| | /// Sets the one and ONLY color that should be used for this DataSet. 93| | /// Internally, this recreates the colors array and adds the specified color. 94| | open func setCircleColor(_ color: NSUIColor) 95| 0| { 96| 0| circleColors.removeAll(keepingCapacity: false) 97| 0| circleColors.append(color) 98| 0| } 99| | 100| | open func setCircleColors(_ colors: NSUIColor...) 101| 0| { 102| 0| circleColors.removeAll(keepingCapacity: false) 103| 0| circleColors.append(contentsOf: colors) 104| 0| } 105| | 106| | /// Resets the circle-colors array and creates a new one 107| | open func resetCircleColors(_ index: Int) 108| 0| { 109| 0| circleColors.removeAll(keepingCapacity: false) 110| 0| } 111| | 112| | /// If true, drawing circles is enabled 113| | open var drawCirclesEnabled = true 114| | 115| | /// `true` if drawing circles for this DataSet is enabled, `false` ifnot 116| 278| open var isDrawCirclesEnabled: Bool { return drawCirclesEnabled } 117| | 118| | /// The color of the inner circle (the circle-hole). 119| | open var circleHoleColor: NSUIColor? = NSUIColor.white 120| | 121| | /// `true` if drawing circles for this DataSet is enabled, `false` ifnot 122| | open var drawCircleHoleEnabled = true 123| | 124| | /// `true` if drawing the circle-holes is enabled, `false` ifnot. 125| 9| open var isDrawCircleHoleEnabled: Bool { return drawCircleHoleEnabled } 126| | 127| | /// This is how much (in pixels) into the dash pattern are we starting from. 128| | open var lineDashPhase = CGFloat(0.0) 129| | 130| | /// This is the actual dash pattern. 131| | /// I.e. [2, 3] will paint [-- -- ] 132| | /// [1, 3, 4, 2] will paint [- ---- - ---- ] 133| | open var lineDashLengths: [CGFloat]? 134| | 135| | /// Line cap type, default is CGLineCap.Butt 136| | open var lineCapType = CGLineCap.butt 137| | 138| | /// formatter for customizing the position of the fill-line 139| | private var _fillFormatter: IFillFormatter = DefaultFillFormatter() 140| | 141| | /// 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. 142| | open var fillFormatter: IFillFormatter? 143| | { 144| | get 145| 0| { 146| 0| return _fillFormatter 147| 0| } 148| | set 149| 0| { 150| 0| _fillFormatter = newValue ?? DefaultFillFormatter() 151| 0| } 152| | } 153| | 154| | // MARK: NSCopying 155| | 156| | open override func copy(with zone: NSZone? = nil) -> Any 157| 0| { 158| 0| let copy = super.copy(with: zone) as! LineChartDataSet 159| 0| copy.circleColors = circleColors 160| 0| copy.circleHoleColor = circleHoleColor 161| 0| copy.circleRadius = circleRadius 162| 0| copy.circleHoleRadius = circleHoleRadius 163| 0| copy.cubicIntensity = cubicIntensity 164| 0| copy.lineDashPhase = lineDashPhase 165| 0| copy.lineDashLengths = lineDashLengths 166| 0| copy.lineCapType = lineCapType 167| 0| copy.drawCirclesEnabled = drawCirclesEnabled 168| 0| copy.drawCircleHoleEnabled = drawCircleHoleEnabled 169| 0| copy.mode = mode 170| 0| copy._fillFormatter = _fillFormatter 171| 0| return copy 172| 0| } 173| |} /Users/travis/build/danielgindi/Charts/Source/Charts/Data/Implementations/Standard/LineRadarChartDataSet.swift: 1| |// 2| |// LineRadarChartDataSet.swift 3| |// Charts 4| |// 5| |// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda 6| |// A port of MPAndroidChart for iOS 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| | 12| |import Foundation 13| |import CoreGraphics 14| | 15| | 16| |open class LineRadarChartDataSet: LineScatterCandleRadarChartDataSet, ILineRadarChartDataSet 17| |{ 18| | // MARK: - Data functions and accessors 19| | 20| | // MARK: - Styling functions and accessors 21| | 22| | /// The color that is used for filling the line surface area. 23| | private var _fillColor = NSUIColor(red: 140.0/255.0, green: 234.0/255.0, blue: 255.0/255.0, alpha: 1.0) 24| | 25| | /// The color that is used for filling the line surface area. 26| | open var fillColor: NSUIColor 27| | { 28| 0| get { return _fillColor } 29| | set 30| 0| { 31| 0| _fillColor = newValue 32| 0| fill = nil 33| 0| } 34| | } 35| | 36| | /// The object that is used for filling the area below the line. 37| | /// **default**: nil 38| | open var fill: Fill? 39| | 40| | /// The alpha value that is used for filling the line surface, 41| | /// **default**: 0.33 42| | open var fillAlpha = CGFloat(0.33) 43| | 44| | private var _lineWidth = CGFloat(1.0) 45| | 46| | /// line width of the chart (min = 0.0, max = 10) 47| | /// 48| | /// **default**: 1 49| | open var lineWidth: CGFloat 50| | { 51| | get 52| 9| { 53| 9| return _lineWidth 54| 9| } 55| | set 56| 0| { 57| 0| _lineWidth = newValue.clamped(to: 0...10) 58| 0| } 59| | } 60| | 61| | /// Set to `true` if the DataSet should be drawn filled (surface), and not just as a line. 62| | /// Disabling this will give great performance boost. 63| | /// Please note that this method uses the path clipping for drawing the filled area (with images, gradients and layers). 64| | open var drawFilledEnabled = false 65| | 66| | /// `true` if filled drawing is enabled, `false` ifnot 67| | open var isDrawFilledEnabled: Bool 68| 9| { 69| 9| return drawFilledEnabled 70| 9| } 71| | 72| | // MARK: NSCopying 73| | 74| | open override func copy(with zone: NSZone? = nil) -> Any 75| 0| { 76| 0| let copy = super.copy(with: zone) as! LineRadarChartDataSet 77| 0| copy.fill = fill 78| 0| copy.fillAlpha = fillAlpha 79| 0| copy._fillColor = _fillColor 80| 0| copy._lineWidth = _lineWidth 81| 0| copy.drawFilledEnabled = drawFilledEnabled 82| 0| return copy 83| 0| } 84| | 85| |} /Users/travis/build/danielgindi/Charts/Source/Charts/Data/Implementations/Standard/LineScatterCandleRadarChartDataSet.swift: 1| |// 2| |// LineScatterCandleRadarChartDataSet.swift 3| |// Charts 4| |// 5| |// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda 6| |// A port of MPAndroidChart for iOS 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| | 12| |import Foundation 13| | 14| | 15| |open class LineScatterCandleRadarChartDataSet: BarLineScatterCandleBubbleChartDataSet, ILineScatterCandleRadarChartDataSet 16| |{ 17| | // MARK: - Data functions and accessors 18| | 19| | // MARK: - Styling functions and accessors 20| | 21| | /// Enables / disables the horizontal highlight-indicator. If disabled, the indicator is not drawn. 22| | open var drawHorizontalHighlightIndicatorEnabled = true 23| | 24| | /// Enables / disables the vertical highlight-indicator. If disabled, the indicator is not drawn. 25| | open var drawVerticalHighlightIndicatorEnabled = true 26| | 27| | /// `true` if horizontal highlight indicator lines are enabled (drawn) 28| 0| open var isHorizontalHighlightIndicatorEnabled: Bool { return drawHorizontalHighlightIndicatorEnabled } 29| | 30| | /// `true` if vertical highlight indicator lines are enabled (drawn) 31| 0| open var isVerticalHighlightIndicatorEnabled: Bool { return drawVerticalHighlightIndicatorEnabled } 32| | 33| | /// Enables / disables both vertical and horizontal highlight-indicators. 34| | /// :param: enabled 35| | open func setDrawHighlightIndicators(_ enabled: Bool) 36| 0| { 37| 0| drawHorizontalHighlightIndicatorEnabled = enabled 38| 0| drawVerticalHighlightIndicatorEnabled = enabled 39| 0| } 40| | 41| | // MARK: NSCopying 42| | 43| | open override func copy(with zone: NSZone? = nil) -> Any 44| 0| { 45| 0| let copy = super.copy(with: zone) as! LineScatterCandleRadarChartDataSet 46| 0| copy.drawHorizontalHighlightIndicatorEnabled = drawHorizontalHighlightIndicatorEnabled 47| 0| copy.drawVerticalHighlightIndicatorEnabled = drawVerticalHighlightIndicatorEnabled 48| 0| return copy 49| 0| } 50| | 51| |} /Users/travis/build/danielgindi/Charts/Source/Charts/Data/Implementations/Standard/PieChartData.swift: 1| |// 2| |// PieData.swift 3| |// Charts 4| |// 5| |// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda 6| |// A port of MPAndroidChart for iOS 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| | 12| |import Foundation 13| | 14| |open class PieChartData: ChartData 15| |{ 16| | public override init() 17| 0| { 18| 0| super.init() 19| 0| } 20| | 21| | public override init(dataSets: [IChartDataSet]?) 22| 6| { 23| 6| super.init(dataSets: dataSets) 24| 6| } 25| | 26| | /// All DataSet objects this ChartData object holds. 27| | @objc open override var dataSets: [IChartDataSet] 28| | { 29| | get 30| 89| { 31| 89| assert(super.dataSets.count <= 1, "Found multiple data sets while pie chart only allows one") 32| 89| return super.dataSets 33| 89| } 34| | set 35| 0| { 36| 0| super.dataSets = newValue 37| 0| } 38| | } 39| | 40| | @objc var dataSet: IPieChartDataSet? 41| | { 42| | get 43| 26| { 44| 26| return dataSets.count > 0 ? dataSets[0] as? IPieChartDataSet : nil 45| 26| } 46| | set 47| 0| { 48| 0| if let newValue = newValue 49| 0| { 50| 0| dataSets = [newValue] 51| 0| } 52| 0| else 53| 0| { 54| 0| dataSets = [] 55| 0| } 56| 0| } 57| | } 58| | 59| | open override func getDataSetByIndex(_ index: Int) -> IChartDataSet? 60| 8| { 61| 8| if index != 0 62| 8| { 63| 0| return nil 64| 8| } 65| 8| return super.getDataSetByIndex(index) 66| 8| } 67| | 68| | open override func getDataSetByLabel(_ label: String, ignorecase: Bool) -> IChartDataSet? 69| 0| { 70| 0| if dataSets.count == 0 || dataSets[0].label == nil 71| 0| { 72| 0| return nil 73| 0| } 74| 0| 75| 0| if ignorecase 76| 0| { 77| 0| if let label = dataSets[0].label, label.caseInsensitiveCompare(label) == .orderedSame 78| 0| { 79| 0| return dataSets[0] 80| 0| } 81| 0| } 82| 0| else 83| 0| { 84| 0| if label == dataSets[0].label 85| 0| { 86| 0| return dataSets[0] 87| 0| } 88| 0| } 89| 0| return nil 90| 0| } 91| | 92| | open override func entryForHighlight(_ highlight: Highlight) -> ChartDataEntry? 93| 2| { 94| 2| return dataSet?.entryForIndex(Int(highlight.x)) 95| 2| } 96| | 97| | open override func addDataSet(_ d: IChartDataSet!) 98| 0| { 99| 0| super.addDataSet(d) 100| 0| } 101| | 102| | /// Removes the DataSet at the given index in the DataSet array from the data object. 103| | /// Also recalculates all minimum and maximum values. 104| | /// 105| | /// - Returns: `true` if a DataSet was removed, `false` ifno DataSet could be removed. 106| | open override func removeDataSetByIndex(_ index: Int) -> Bool 107| 0| { 108| 0| if index >= _dataSets.count || index < 0 109| 0| { 110| 0| return false 111| 0| } 112| 0| 113| 0| return false 114| 0| } 115| | 116| | /// The total y-value sum across all DataSet objects the this object represents. 117| | @objc open var yValueSum: Double 118| 12| { 119| 12| guard let dataSet = dataSet else { return 0.0 } 120| 84| return (0.. Any 114| 0| { 115| 0| let copy = super.copy(with: zone) as! PieChartDataEntry 116| 0| copy.label = label 117| 0| return copy 118| 0| } 119| |} /Users/travis/build/danielgindi/Charts/Source/Charts/Data/Implementations/Standard/PieChartDataSet.swift: 1| |// 2| |// PieChartDataSet.swift 3| |// Charts 4| |// 5| |// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda 6| |// A port of MPAndroidChart for iOS 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| | 12| |import Foundation 13| |import CoreGraphics 14| | 15| |open class PieChartDataSet: ChartDataSet, IPieChartDataSet 16| |{ 17| | @objc(PieChartValuePosition) 18| | public enum ValuePosition: Int 19| | { 20| | case insideSlice 21| | case outsideSlice 22| | } 23| | 24| | private func initialize() 25| 6| { 26| 6| self.valueTextColor = NSUIColor.white 27| 6| self.valueFont = NSUIFont.systemFont(ofSize: 13.0) 28| 6| } 29| | 30| | public required init() 31| 0| { 32| 0| super.init() 33| 0| initialize() 34| 0| } 35| | 36| | public override init(entries: [ChartDataEntry]?, label: String?) 37| 6| { 38| 6| super.init(entries: entries, label: label) 39| 6| initialize() 40| 6| } 41| | 42| | internal override func calcMinMax(entry e: ChartDataEntry) 43| 42| { 44| 42| calcMinMaxY(entry: e) 45| 42| } 46| | 47| | // MARK: - Styling functions and accessors 48| | 49| | private var _sliceSpace = CGFloat(0.0) 50| | 51| | /// the space in pixels between the pie-slices 52| | /// **default**: 0 53| | /// **maximum**: 20 54| | open var sliceSpace: CGFloat 55| | { 56| | get 57| 49| { 58| 49| return _sliceSpace 59| 49| } 60| | set 61| 0| { 62| 0| var space = newValue 63| 0| if space > 20.0 64| 0| { 65| 0| space = 20.0 66| 0| } 67| 0| if space < 0.0 68| 0| { 69| 0| space = 0.0 70| 0| } 71| 0| _sliceSpace = space 72| 0| } 73| | } 74| | 75| | /// When enabled, slice spacing will be 0.0 when the smallest value is going to be smaller than the slice spacing itself. 76| | open var automaticallyDisableSliceSpacing: Bool = false 77| | 78| | /// indicates the selection distance of a pie slice 79| | open var selectionShift = CGFloat(18.0) 80| | 81| | open var xValuePosition: ValuePosition = .insideSlice 82| | open var yValuePosition: ValuePosition = .insideSlice 83| | 84| | /// When valuePosition is OutsideSlice, indicates line color 85| | open var valueLineColor: NSUIColor? = NSUIColor.black 86| | 87| | /// When valuePosition is OutsideSlice and enabled, line will have the same color as the slice 88| | open var useValueColorForLine: Bool = false 89| | 90| | /// When valuePosition is OutsideSlice, indicates line width 91| | open var valueLineWidth: CGFloat = 1.0 92| | 93| | /// When valuePosition is OutsideSlice, indicates offset as percentage out of the slice size 94| | open var valueLinePart1OffsetPercentage: CGFloat = 0.75 95| | 96| | /// When valuePosition is OutsideSlice, indicates length of first half of the line 97| | open var valueLinePart1Length: CGFloat = 0.3 98| | 99| | /// When valuePosition is OutsideSlice, indicates length of second half of the line 100| | open var valueLinePart2Length: CGFloat = 0.4 101| | 102| | /// When valuePosition is OutsideSlice, this allows variable line length 103| | open var valueLineVariableLength: Bool = true 104| | 105| | /// the font for the slice-text labels 106| | open var entryLabelFont: NSUIFont? = nil 107| | 108| | /// the color for the slice-text labels 109| | open var entryLabelColor: NSUIColor? = nil 110| | 111| | /// the color for the highlighted sector 112| | open var highlightColor: NSUIColor? = nil 113| | 114| | // MARK: - NSCopying 115| | 116| | open override func copy(with zone: NSZone? = nil) -> Any 117| 0| { 118| 0| let copy = super.copy(with: zone) as! PieChartDataSet 119| 0| copy._sliceSpace = _sliceSpace 120| 0| copy.automaticallyDisableSliceSpacing = automaticallyDisableSliceSpacing 121| 0| copy.selectionShift = selectionShift 122| 0| copy.xValuePosition = xValuePosition 123| 0| copy.yValuePosition = yValuePosition 124| 0| copy.valueLineColor = valueLineColor 125| 0| copy.valueLineWidth = valueLineWidth 126| 0| copy.valueLinePart1OffsetPercentage = valueLinePart1OffsetPercentage 127| 0| copy.valueLinePart1Length = valueLinePart1Length 128| 0| copy.valueLinePart2Length = valueLinePart2Length 129| 0| copy.valueLineVariableLength = valueLineVariableLength 130| 0| copy.entryLabelFont = entryLabelFont 131| 0| copy.entryLabelColor = entryLabelColor 132| 0| copy.highlightColor = highlightColor 133| 0| return copy 134| 0| } 135| |} /Users/travis/build/danielgindi/Charts/Source/Charts/Data/Implementations/Standard/RadarChartData.swift: 1| |// 2| |// RadarChartData.swift 3| |// Charts 4| |// 5| |// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda 6| |// A port of MPAndroidChart for iOS 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| | 12| |import Foundation 13| |import CoreGraphics 14| | 15| | 16| |open class RadarChartData: ChartData 17| |{ 18| | @objc open var highlightColor = NSUIColor(red: 255.0/255.0, green: 187.0/255.0, blue: 115.0/255.0, alpha: 1.0) 19| | @objc open var highlightLineWidth = CGFloat(1.0) 20| | @objc open var highlightLineDashPhase = CGFloat(0.0) 21| | @objc open var highlightLineDashLengths: [CGFloat]? 22| | 23| | /// Sets labels that should be drawn around the RadarChart at the end of each web line. 24| | @objc open var labels = [String]() 25| | 26| | /// Sets the labels that should be drawn around the RadarChart at the end of each web line. 27| | open func setLabels(_ labels: String...) 28| 0| { 29| 0| self.labels = labels 30| 0| } 31| | 32| | public override init() 33| 0| { 34| 0| super.init() 35| 0| } 36| | 37| | public override init(dataSets: [IChartDataSet]?) 38| 0| { 39| 0| super.init(dataSets: dataSets) 40| 0| } 41| | 42| | open override func entryForHighlight(_ highlight: Highlight) -> ChartDataEntry? 43| 0| { 44| 0| return getDataSetByIndex(highlight.dataSetIndex)?.entryForIndex(Int(highlight.x)) 45| 0| } 46| |} /Users/travis/build/danielgindi/Charts/Source/Charts/Data/Implementations/Standard/RadarChartDataEntry.swift: 1| |// 2| |// RadarChartDataEntry.swift 3| |// Charts 4| |// 5| |// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda 6| |// A port of MPAndroidChart for iOS 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| | 12| |import Foundation 13| |import CoreGraphics 14| | 15| |open class RadarChartDataEntry: ChartDataEntry 16| |{ 17| | public required init() 18| 0| { 19| 0| super.init() 20| 0| } 21| | 22| | /// - Parameters: 23| | /// - value: The value on the y-axis. 24| | @objc public init(value: Double) 25| 0| { 26| 0| super.init(x: .nan, y: value) 27| 0| } 28| | 29| | /// - Parameters: 30| | /// - value: The value on the y-axis. 31| | /// - data: Spot for additional data this Entry represents. 32| | @objc public convenience init(value: Double, data: Any?) 33| 0| { 34| 0| self.init(value: value) 35| 0| self.data = data 36| 0| } 37| | 38| | // MARK: Data property accessors 39| | 40| | @objc open var value: Double 41| | { 42| 0| get { return y } 43| 0| set { y = newValue } 44| | } 45| | 46| | // MARK: NSCopying 47| | 48| | open override func copy(with zone: NSZone? = nil) -> Any 49| 0| { 50| 0| let copy = super.copy(with: zone) as! RadarChartDataEntry 51| 0| 52| 0| return copy 53| 0| } 54| |} /Users/travis/build/danielgindi/Charts/Source/Charts/Data/Implementations/Standard/RadarChartDataSet.swift: 1| |// 2| |// RadarChartDataSet.swift 3| |// Charts 4| |// 5| |// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda 6| |// A port of MPAndroidChart for iOS 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| | 12| |import Foundation 13| |import CoreGraphics 14| | 15| | 16| |open class RadarChartDataSet: LineRadarChartDataSet, IRadarChartDataSet 17| |{ 18| | private func initialize() 19| 0| { 20| 0| self.valueFont = NSUIFont.systemFont(ofSize: 13.0) 21| 0| } 22| | 23| | public required init() 24| 0| { 25| 0| super.init() 26| 0| initialize() 27| 0| } 28| | 29| | public required override init(entries: [ChartDataEntry]?, label: String?) 30| 0| { 31| 0| super.init(entries: entries, label: label) 32| 0| initialize() 33| 0| } 34| | 35| | // MARK: - Data functions and accessors 36| | 37| | // MARK: - Styling functions and accessors 38| | 39| | /// flag indicating whether highlight circle should be drawn or not 40| | /// **default**: false 41| | open var drawHighlightCircleEnabled: Bool = false 42| | 43| | /// `true` if highlight circle should be drawn, `false` ifnot 44| 0| open var isDrawHighlightCircleEnabled: Bool { return drawHighlightCircleEnabled } 45| | 46| | open var highlightCircleFillColor: NSUIColor? = NSUIColor.white 47| | 48| | /// The stroke color for highlight circle. 49| | /// If `nil`, the color of the dataset is taken. 50| | open var highlightCircleStrokeColor: NSUIColor? 51| | 52| | open var highlightCircleStrokeAlpha: CGFloat = 0.3 53| | 54| | open var highlightCircleInnerRadius: CGFloat = 3.0 55| | 56| | open var highlightCircleOuterRadius: CGFloat = 4.0 57| | 58| | open var highlightCircleStrokeWidth: CGFloat = 2.0 59| |} /Users/travis/build/danielgindi/Charts/Source/Charts/Data/Implementations/Standard/ScatterChartData.swift: 1| |// 2| |// ScatterChartData.swift 3| |// Charts 4| |// 5| |// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda 6| |// A port of MPAndroidChart for iOS 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| | 12| |import Foundation 13| |import CoreGraphics 14| | 15| |open class ScatterChartData: BarLineScatterCandleBubbleChartData 16| |{ 17| | public override init() 18| 0| { 19| 0| super.init() 20| 0| } 21| | 22| | public override init(dataSets: [IChartDataSet]?) 23| 3| { 24| 3| super.init(dataSets: dataSets) 25| 3| } 26| | 27| | /// - Returns: The maximum shape-size across all DataSets. 28| | @objc open func getGreatestShapeSize() -> CGFloat 29| 0| { 30| 0| return (_dataSets as? [IScatterChartDataSet])? 31| 0| .max { $0.scatterShapeSize < $1.scatterShapeSize }? 32| 0| .scatterShapeSize ?? 0 33| 0| } 34| |} /Users/travis/build/danielgindi/Charts/Source/Charts/Data/Implementations/Standard/ScatterChartDataSet.swift: 1| |// 2| |// ScatterChartDataSet.swift 3| |// Charts 4| |// 5| |// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda 6| |// A port of MPAndroidChart for iOS 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| | 12| |import Foundation 13| |import CoreGraphics 14| | 15| |open class ScatterChartDataSet: LineScatterCandleRadarChartDataSet, IScatterChartDataSet 16| |{ 17| | 18| | @objc(ScatterShape) 19| | public enum Shape: Int 20| | { 21| | case square 22| | case circle 23| | case triangle 24| | case cross 25| | case x 26| | case chevronUp 27| | case chevronDown 28| | } 29| | 30| | /// The size the scatter shape will have 31| | open var scatterShapeSize = CGFloat(10.0) 32| | 33| | /// The radius of the hole in the shape (applies to Square, Circle and Triangle) 34| | /// **default**: 0.0 35| | open var scatterShapeHoleRadius: CGFloat = 0.0 36| | 37| | /// Color for the hole in the shape. Setting to `nil` will behave as transparent. 38| | /// **default**: nil 39| | open var scatterShapeHoleColor: NSUIColor? = nil 40| | 41| | /// Sets the ScatterShape this DataSet should be drawn with. 42| | /// This will search for an available IShapeRenderer and set this renderer for the DataSet 43| | @objc open func setScatterShape(_ shape: Shape) 44| 0| { 45| 0| self.shapeRenderer = ScatterChartDataSet.renderer(forShape: shape) 46| 0| } 47| | 48| | /// The IShapeRenderer responsible for rendering this DataSet. 49| | /// This can also be used to set a custom IShapeRenderer aside from the default ones. 50| | /// **default**: `SquareShapeRenderer` 51| | open var shapeRenderer: IShapeRenderer? = SquareShapeRenderer() 52| | 53| | @objc open class func renderer(forShape shape: Shape) -> IShapeRenderer 54| 0| { 55| 0| switch shape 56| 0| { 57| 0| case .square: return SquareShapeRenderer() 58| 0| case .circle: return CircleShapeRenderer() 59| 0| case .triangle: return TriangleShapeRenderer() 60| 0| case .cross: return CrossShapeRenderer() 61| 0| case .x: return XShapeRenderer() 62| 0| case .chevronUp: return ChevronUpShapeRenderer() 63| 0| case .chevronDown: return ChevronDownShapeRenderer() 64| 0| } 65| 0| } 66| | 67| | // MARK: NSCopying 68| | 69| | open override func copy(with zone: NSZone? = nil) -> Any 70| 0| { 71| 0| let copy = super.copy(with: zone) as! ScatterChartDataSet 72| 0| copy.scatterShapeSize = scatterShapeSize 73| 0| copy.scatterShapeHoleRadius = scatterShapeHoleRadius 74| 0| copy.scatterShapeHoleColor = scatterShapeHoleColor 75| 0| copy.shapeRenderer = shapeRenderer 76| 0| return copy 77| 0| } 78| |} /Users/travis/build/danielgindi/Charts/Source/Charts/Filters/DataApproximator+N.swift: 1| |// 2| |// DataApproximator+N.swift 3| |// Charts 4| |// 5| |// Created by M Ivaniushchenko on 9/6/17. 6| |// Licensed under Apache License 2.0 7| |// 8| |// https://github.com/danielgindi/Charts 9| |// 10| | 11| |import Foundation 12| |import CoreGraphics 13| | 14| |extension CGPoint { 15| 0| fileprivate func distanceToLine(from linePoint1: CGPoint, to linePoint2: CGPoint) -> CGFloat { 16| 0| let dx = linePoint2.x - linePoint1.x 17| 0| let dy = linePoint2.y - linePoint1.y 18| 0| 19| 0| let dividend = abs(dy * self.x - dx * self.y - linePoint1.x * linePoint2.y + linePoint2.x * linePoint1.y) 20| 0| let divisor = sqrt(dx * dx + dy * dy) 21| 0| 22| 0| return dividend / divisor 23| 0| } 24| |} 25| | 26| |private struct LineAlt { 27| | let start: Int 28| | let end: Int 29| | 30| | var distance: CGFloat = 0 31| | var index: Int = 0 32| | 33| 0| init(start: Int, end: Int, points: [CGPoint]) { 34| 0| self.start = start 35| 0| self.end = end 36| 0| 37| 0| let startPoint = points[start] 38| 0| let endPoint = points[end] 39| 0| 40| 0| guard (end > start + 1) else { 41| 0| return 42| 0| } 43| 0| 44| 0| for i in start + 1 ..< end { 45| 0| let currentPoint = points[i] 46| 0| 47| 0| let distance = currentPoint.distanceToLine(from: startPoint, to: endPoint) 48| 0| 49| 0| if distance > self.distance { 50| 0| self.index = i 51| 0| self.distance = distance 52| 0| } 53| 0| } 54| 0| } 55| |} 56| | 57| |extension LineAlt: Comparable { 58| 0| static func ==(lhs: LineAlt, rhs: LineAlt) -> Bool { 59| 0| return (lhs.start == rhs.start) && (lhs.end == rhs.end) && (lhs.index == rhs.index) 60| 0| } 61| | 62| 0| static func <(lhs: LineAlt, rhs: LineAlt) -> Bool { 63| 0| return lhs.distance < rhs.distance 64| 0| } 65| |} 66| | 67| | 68| |extension DataApproximator { 69| | /// uses the douglas peuker algorithm to reduce the given arraylist of entries to given number of points 70| | /// More algorithm details here - http://psimpl.sourceforge.net/douglas-peucker.html 71| | @objc open class func reduceWithDouglasPeukerN(_ points: [CGPoint], resultCount: Int) -> [CGPoint] 72| 0| { 73| 0| // if a shape has 2 or less points it cannot be reduced 74| 0| if resultCount <= 2 || resultCount >= points.count 75| 0| { 76| 0| return points 77| 0| } 78| 0| var keep = [Bool](repeating: false, count: points.count) 79| 0| 80| 0| // first and last always stay 81| 0| keep[0] = true 82| 0| keep[points.count - 1] = true 83| 0| var currentStoredPoints = 2 84| 0| 85| 0| var queue = [LineAlt]() 86| 0| let line = LineAlt(start: 0, end: points.count - 1, points: points) 87| 0| queue.append(line) 88| 0| 89| 0| repeat { 90| 0| let line = queue.popLast()! 91| 0| 92| 0| // store the key 93| 0| keep[line.index] = true 94| 0| 95| 0| // check point count tolerance 96| 0| currentStoredPoints += 1 97| 0| 98| 0| if (currentStoredPoints == resultCount) { 99| 0| break; 100| 0| } 101| 0| 102| 0| // split the polyline at the key and recurse 103| 0| let left = LineAlt(start: line.start, end: line.index, points: points) 104| 0| if (left.index > 0) { 105| 0| self.insertLine(left, into: &queue) 106| 0| } 107| 0| 108| 0| let right = LineAlt(start: line.index, end: line.end, points: points) 109| 0| if (right.index > 0) { 110| 0| self.insertLine(right, into: &queue) 111| 0| } 112| 0| 113| 0| } while !queue.isEmpty 114| 0| 115| 0| // create a new array with series, only take the kept ones 116| 0| let reducedEntries = points.enumerated().compactMap { (index: Int, point: CGPoint) -> CGPoint? in 117| 0| return keep[index] ? point : nil 118| 0| } 119| 0| 120| 0| return reducedEntries 121| 0| } 122| | 123| | // Keeps array sorted 124| 0| private static func insertLine(_ line: LineAlt, into array: inout [LineAlt]) { 125| 0| let insertionIndex = self.insertionIndex(for: line, into: &array) 126| 0| array.insert(line, at: insertionIndex) 127| 0| } 128| | 129| 0| private static func insertionIndex(for line: LineAlt, into array: inout [LineAlt]) -> Int { 130| 0| var indices = array.indices 131| 0| 132| 0| while !indices.isEmpty { 133| 0| let midIndex = indices.lowerBound.advanced(by: indices.count / 2) 134| 0| let midLine = array[midIndex] 135| 0| 136| 0| if midLine == line { 137| 0| return midIndex 138| 0| } 139| 0| else if (line < midLine) { 140| 0| // perform search in left half 141| 0| indices = indices.lowerBound.. [CGPoint] 20| 0| { 21| 0| // if a shape has 2 or less points it cannot be reduced 22| 0| if tolerance <= 0 || points.count < 3 23| 0| { 24| 0| return points 25| 0| } 26| 0| 27| 0| var keep = [Bool](repeating: false, count: points.count) 28| 0| 29| 0| // first and last always stay 30| 0| keep[0] = true 31| 0| keep[points.count - 1] = true 32| 0| 33| 0| // first and last entry are entry point to recursion 34| 0| reduceWithDouglasPeuker(points: points, 35| 0| tolerance: tolerance, 36| 0| start: 0, 37| 0| end: points.count - 1, 38| 0| keep: &keep) 39| 0| 40| 0| // create a new array with series, only take the kept ones 41| 0| return zip(keep, points).compactMap { $0 ? nil : $1 } 42| 0| } 43| | 44| | /// apply the Douglas-Peucker-Reduction to an array of `CGPoint`s with a given tolerance 45| | /// 46| | /// - Parameters: 47| | /// - points: 48| | /// - tolerance: 49| | /// - start: 50| | /// - end: 51| | open class func reduceWithDouglasPeuker( 52| | points: [CGPoint], 53| | tolerance: CGFloat, 54| | start: Int, 55| | end: Int, 56| | keep: inout [Bool]) 57| 0| { 58| 0| if end <= start + 1 59| 0| { 60| 0| // recursion finished 61| 0| return 62| 0| } 63| 0| 64| 0| var greatestIndex = Int(0) 65| 0| var greatestDistance = CGFloat(0.0) 66| 0| 67| 0| let line = Line(pt1: points[start], pt2: points[end]) 68| 0| 69| 0| for i in start + 1 ..< end 70| 0| { 71| 0| let distance = line.distance(toPoint: points[i]) 72| 0| 73| 0| if distance > greatestDistance 74| 0| { 75| 0| greatestDistance = distance 76| 0| greatestIndex = i 77| 0| } 78| 0| } 79| 0| 80| 0| if greatestDistance > tolerance 81| 0| { 82| 0| // keep max dist point 83| 0| keep[greatestIndex] = true 84| 0| 85| 0| // recursive call 86| 0| reduceWithDouglasPeuker(points: points, tolerance: tolerance, start: start, end: greatestIndex, keep: &keep) 87| 0| reduceWithDouglasPeuker(points: points, tolerance: tolerance, start: greatestIndex, end: end, keep: &keep) 88| 0| } // else don't keep the point... 89| 0| } 90| | 91| | private class Line 92| | { 93| | var sxey: CGFloat 94| | var exsy: CGFloat 95| | 96| | var dx: CGFloat 97| | var dy: CGFloat 98| | 99| | var length: CGFloat 100| | 101| | init(pt1: CGPoint, pt2: CGPoint) 102| 0| { 103| 0| dx = pt1.x - pt2.x 104| 0| dy = pt1.y - pt2.y 105| 0| sxey = pt1.x * pt2.y 106| 0| exsy = pt2.x * pt1.y 107| 0| length = sqrt(dx * dx + dy * dy) 108| 0| } 109| | 110| | func distance(toPoint pt: CGPoint) -> CGFloat 111| 0| { 112| 0| return abs(dy * pt.x - dx * pt.y + sxey - exsy) / length 113| 0| } 114| | } 115| |} /Users/travis/build/danielgindi/Charts/Source/Charts/Formatters/DefaultAxisValueFormatter.swift: 1| |// 2| |// DefaultAxisValueFormatter.swift 3| |// Charts 4| |// 5| |// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda 6| |// A port of MPAndroidChart for iOS 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| | 12| |import Foundation 13| | 14| |@objc(ChartDefaultAxisValueFormatter) 15| |open class DefaultAxisValueFormatter: NSObject, IAxisValueFormatter 16| |{ 17| | public typealias Block = ( 18| | _ value: Double, 19| | _ axis: AxisBase?) -> String 20| | 21| | @objc open var block: Block? 22| | 23| | @objc open var hasAutoDecimals: Bool = false 24| | 25| | private var _formatter: NumberFormatter? 26| | @objc open var formatter: NumberFormatter? 27| | { 28| 4.89k| get { return _formatter } 29| | set 30| 138| { 31| 138| hasAutoDecimals = false 32| 138| _formatter = newValue 33| 138| } 34| | } 35| | 36| | // TODO: Documentation. Especially the nil case 37| | private var _decimals: Int? 38| | open var decimals: Int? 39| | { 40| 4.19k| get { return _decimals } 41| | set 42| 140| { 43| 140| _decimals = newValue 44| 140| 45| 140| if let digits = newValue 46| 140| { 47| 140| self.formatter?.minimumFractionDigits = digits 48| 140| self.formatter?.maximumFractionDigits = digits 49| 140| self.formatter?.usesGroupingSeparator = true 50| 140| } 51| 140| } 52| | } 53| | 54| | public override init() 55| 0| { 56| 0| super.init() 57| 0| 58| 0| self.formatter = NumberFormatter() 59| 0| hasAutoDecimals = true 60| 0| } 61| | 62| | @objc public init(formatter: NumberFormatter) 63| 0| { 64| 0| super.init() 65| 0| 66| 0| self.formatter = formatter 67| 0| } 68| | 69| | @objc public init(decimals: Int) 70| 138| { 71| 138| super.init() 72| 138| 73| 138| self.formatter = NumberFormatter() 74| 138| self.formatter?.usesGroupingSeparator = true 75| 138| self.decimals = decimals 76| 138| hasAutoDecimals = true 77| 138| } 78| | 79| | @objc public init(block: @escaping Block) 80| 0| { 81| 0| super.init() 82| 0| 83| 0| self.block = block 84| 0| } 85| | 86| | @objc public static func with(block: @escaping Block) -> DefaultAxisValueFormatter? 87| 0| { 88| 0| return DefaultAxisValueFormatter(block: block) 89| 0| } 90| | 91| | open func stringForValue(_ value: Double, 92| | axis: AxisBase?) -> String 93| 4.33k| { 94| 4.33k| if let block = block { 95| 0| return block(value, axis) 96| 4.33k| } else { 97| 4.33k| return formatter?.string(from: NSNumber(floatLiteral: value)) ?? "" 98| 4.33k| } 99| 0| } 100| |} /Users/travis/build/danielgindi/Charts/Source/Charts/Formatters/DefaultFillFormatter.swift: 1| |// 2| |// DefaultFillFormatter.swift 3| |// Charts 4| |// 5| |// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda 6| |// A port of MPAndroidChart for iOS 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| | 12| |import Foundation 13| |import CoreGraphics 14| | 15| |/// Default formatter that calculates the position of the filled line. 16| |@objc(ChartDefaultFillFormatter) 17| |open class DefaultFillFormatter: NSObject, IFillFormatter 18| |{ 19| | public typealias Block = ( 20| | _ dataSet: ILineChartDataSet, 21| | _ dataProvider: LineChartDataProvider) -> CGFloat 22| | 23| | @objc open var block: Block? 24| | 25| 12| public override init() { } 26| | 27| | @objc public init(block: @escaping Block) 28| 0| { 29| 0| self.block = block 30| 0| } 31| | 32| | @objc public static func with(block: @escaping Block) -> DefaultFillFormatter? 33| 0| { 34| 0| return DefaultFillFormatter(block: block) 35| 0| } 36| | 37| | open func getFillLinePosition( 38| | dataSet: ILineChartDataSet, 39| | dataProvider: LineChartDataProvider) -> CGFloat 40| 0| { 41| 0| guard block == nil else { return block!(dataSet, dataProvider) } 42| 0| var fillMin: CGFloat = 0.0 43| 0| 44| 0| if dataSet.yMax > 0.0 && dataSet.yMin < 0.0 45| 0| { 46| 0| fillMin = 0.0 47| 0| } 48| 0| else if let data = dataProvider.data 49| 0| { 50| 0| let max = data.yMax > 0.0 ? 0.0 : dataProvider.chartYMax 51| 0| let min = data.yMin < 0.0 ? 0.0 : dataProvider.chartYMin 52| 0| 53| 0| fillMin = CGFloat(dataSet.yMin >= 0.0 ? min : max) 54| 0| } 55| 0| 56| 0| return fillMin 57| 0| } 58| |} /Users/travis/build/danielgindi/Charts/Source/Charts/Formatters/DefaultValueFormatter.swift: 1| |// 2| |// DefaultValueFormatter.swift 3| |// Charts 4| |// 5| |// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda 6| |// A port of MPAndroidChart for iOS 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| | 12| |import Foundation 13| | 14| |@objc(ChartDefaultValueFormatter) 15| |open class DefaultValueFormatter: NSObject, IValueFormatter 16| |{ 17| | public typealias Block = ( 18| | _ value: Double, 19| | _ entry: ChartDataEntry, 20| | _ dataSetIndex: Int, 21| | _ viewPortHandler: ViewPortHandler?) -> String 22| | 23| | @objc open var block: Block? 24| | 25| | @objc open var hasAutoDecimals: Bool = false 26| | 27| | private var _formatter: NumberFormatter? 28| | @objc open var formatter: NumberFormatter? 29| | { 30| 3.06k| get { return _formatter } 31| | set 32| 52| { 33| 52| hasAutoDecimals = false 34| 52| _formatter = newValue 35| 52| } 36| | } 37| | 38| | private var _decimals: Int? 39| | open var decimals: Int? 40| | { 41| 0| get { return _decimals } 42| | set 43| 104| { 44| 104| _decimals = newValue 45| 104| 46| 104| if let digits = newValue 47| 104| { 48| 104| self.formatter?.minimumFractionDigits = digits 49| 104| self.formatter?.maximumFractionDigits = digits 50| 104| self.formatter?.usesGroupingSeparator = true 51| 104| } 52| 104| } 53| | } 54| | 55| | public override init() 56| 0| { 57| 0| super.init() 58| 0| 59| 0| self.formatter = NumberFormatter() 60| 0| hasAutoDecimals = true 61| 0| } 62| | 63| | @objc public init(formatter: NumberFormatter) 64| 0| { 65| 0| super.init() 66| 0| 67| 0| self.formatter = formatter 68| 0| } 69| | 70| | @objc public init(decimals: Int) 71| 52| { 72| 52| super.init() 73| 52| 74| 52| self.formatter = NumberFormatter() 75| 52| self.formatter?.usesGroupingSeparator = true 76| 52| self.decimals = decimals 77| 52| hasAutoDecimals = true 78| 52| } 79| | 80| | @objc public init(block: @escaping Block) 81| 0| { 82| 0| super.init() 83| 0| 84| 0| self.block = block 85| 0| } 86| | 87| | @objc public static func with(block: @escaping Block) -> DefaultValueFormatter? 88| 0| { 89| 0| return DefaultValueFormatter(block: block) 90| 0| } 91| | 92| | open func stringForValue(_ value: Double, 93| | entry: ChartDataEntry, 94| | dataSetIndex: Int, 95| | viewPortHandler: ViewPortHandler?) -> String 96| 2.70k| { 97| 2.70k| if let block = block { 98| 0| return block(value, entry, dataSetIndex, viewPortHandler) 99| 2.70k| } else { 100| 2.70k| return formatter?.string(from: NSNumber(floatLiteral: value)) ?? "" 101| 2.70k| } 102| 0| } 103| |} /Users/travis/build/danielgindi/Charts/Source/Charts/Formatters/IndexAxisValueFormatter.swift: 1| |// 2| |// IndexAxisValueFormatter.swift 3| |// Charts 4| |// 5| |// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda 6| |// A port of MPAndroidChart for iOS 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| | 12| |import Foundation 13| | 14| |/// This formatter is used for passing an array of x-axis labels, on whole x steps. 15| |@objc(ChartIndexAxisValueFormatter) 16| |open class IndexAxisValueFormatter: NSObject, IAxisValueFormatter 17| |{ 18| | private var _values: [String] = [String]() 19| | private var _valueCount: Int = 0 20| | 21| | @objc public var values: [String] 22| | { 23| | get 24| 0| { 25| 0| return _values 26| 0| } 27| | set 28| 0| { 29| 0| _values = newValue 30| 0| _valueCount = _values.count 31| 0| } 32| | } 33| | 34| | public override init() 35| 0| { 36| 0| super.init() 37| 0| 38| 0| } 39| | 40| | @objc public init(values: [String]) 41| 0| { 42| 0| super.init() 43| 0| 44| 0| self.values = values 45| 0| } 46| | 47| | @objc public static func with(values: [String]) -> IndexAxisValueFormatter? 48| 0| { 49| 0| return IndexAxisValueFormatter(values: values) 50| 0| } 51| | 52| | open func stringForValue(_ value: Double, 53| | axis: AxisBase?) -> String 54| 0| { 55| 0| let index = Int(value.rounded()) 56| 0| guard values.indices.contains(index), index == Int(value) else { return "" } 57| 0| return _values[index] 58| 0| } 59| |} /Users/travis/build/danielgindi/Charts/Source/Charts/Highlight/BarHighlighter.swift: 1| |// 2| |// BarHighlighter.swift 3| |// Charts 4| |// 5| |// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda 6| |// A port of MPAndroidChart for iOS 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| | 12| |import Foundation 13| |import CoreGraphics 14| | 15| |@objc(BarChartHighlighter) 16| |open class BarHighlighter: ChartHighlighter 17| |{ 18| | open override func getHighlight(x: CGFloat, y: CGFloat) -> Highlight? 19| 0| { 20| 0| guard 21| 0| let barData = (self.chart as? BarChartDataProvider)?.barData, 22| 0| let high = super.getHighlight(x: x, y: y) 23| 0| else { return nil } 24| 0| 25| 0| let pos = getValsForTouch(x: x, y: y) 26| 0| 27| 0| if let set = barData.getDataSetByIndex(high.dataSetIndex) as? IBarChartDataSet, 28| 0| set.isStacked 29| 0| { 30| 0| return getStackedHighlight(high: high, 31| 0| set: set, 32| 0| xValue: Double(pos.x), 33| 0| yValue: Double(pos.y)) 34| 0| } 35| 0| else 36| 0| { 37| 0| return high 38| 0| } 39| 0| } 40| | 41| | internal override func getDistance(x1: CGFloat, y1: CGFloat, x2: CGFloat, y2: CGFloat) -> CGFloat 42| 0| { 43| 0| return abs(x1 - x2) 44| 0| } 45| | 46| | internal override var data: ChartData? 47| 0| { 48| 0| return (chart as? BarChartDataProvider)?.barData 49| 0| } 50| | 51| | /// This method creates the Highlight object that also indicates which value of a stacked BarEntry has been selected. 52| | /// 53| | /// - Parameters: 54| | /// - high: the Highlight to work with looking for stacked values 55| | /// - set: 56| | /// - xIndex: 57| | /// - yValue: 58| | /// - Returns: 59| | @objc open func getStackedHighlight(high: Highlight, 60| | set: IBarChartDataSet, 61| | xValue: Double, 62| | yValue: Double) -> Highlight? 63| 0| { 64| 0| guard 65| 0| let chart = self.chart as? BarLineScatterCandleBubbleChartDataProvider, 66| 0| let entry = set.entryForXValue(xValue, closestToY: yValue) as? BarChartDataEntry 67| 0| else { return nil } 68| 0| 69| 0| // Not stacked 70| 0| if entry.yValues == nil 71| 0| { 72| 0| return high 73| 0| } 74| 0| 75| 0| guard 76| 0| let ranges = entry.ranges, 77| 0| ranges.count > 0 78| 0| else { return nil } 79| 0| 80| 0| let stackIndex = getClosestStackIndex(ranges: ranges, value: yValue) 81| 0| let pixel = chart 82| 0| .getTransformer(forAxis: set.axisDependency) 83| 0| .pixelForValues(x: high.x, y: ranges[stackIndex].to) 84| 0| 85| 0| return Highlight(x: entry.x, 86| 0| y: entry.y, 87| 0| xPx: pixel.x, 88| 0| yPx: pixel.y, 89| 0| dataSetIndex: high.dataSetIndex, 90| 0| stackIndex: stackIndex, 91| 0| axis: high.axis) 92| 0| } 93| | 94| | /// - Parameters: 95| | /// - entry: 96| | /// - value: 97| | /// - Returns: The index of the closest value inside the values array / ranges (stacked barchart) to the value given as a parameter. 98| | @objc open func getClosestStackIndex(ranges: [Range]?, value: Double) -> Int 99| 0| { 100| 0| guard let ranges = ranges else { return 0 } 101| 0| if let stackIndex = ranges.firstIndex(where: { $0.contains(value) }) { 102| 0| return stackIndex 103| 0| } else { 104| 0| let length = max(ranges.count - 1, 0) 105| 0| return (value > ranges[length].to) ? length : 0 106| 0| } 107| 0| } 108| |} /Users/travis/build/danielgindi/Charts/Source/Charts/Highlight/ChartHighlighter.swift: 1| |// 2| |// ChartHighlighter.swift 3| |// Charts 4| |// 5| |// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda 6| |// A port of MPAndroidChart for iOS 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| | 12| |import Foundation 13| |import CoreGraphics 14| | 15| |open class ChartHighlighter : NSObject, IHighlighter 16| |{ 17| | /// instance of the data-provider 18| | @objc open weak var chart: ChartDataProvider? 19| | 20| | @objc public init(chart: ChartDataProvider) 21| 104| { 22| 104| self.chart = chart 23| 104| } 24| | 25| | open func getHighlight(x: CGFloat, y: CGFloat) -> Highlight? 26| 0| { 27| 0| let xVal = Double(getValsForTouch(x: x, y: y).x) 28| 0| return getHighlight(xValue: xVal, x: x, y: y) 29| 0| } 30| | 31| | /// - Parameters: 32| | /// - x: 33| | /// - Returns: The corresponding x-pos for a given touch-position in pixels. 34| | @objc open func getValsForTouch(x: CGFloat, y: CGFloat) -> CGPoint 35| 0| { 36| 0| guard let chart = self.chart as? BarLineScatterCandleBubbleChartDataProvider else { return .zero } 37| 0| 38| 0| // take any transformer to determine the values 39| 0| return chart.getTransformer(forAxis: .left).valueForTouchPoint(x: x, y: y) 40| 0| } 41| | 42| | /// - Parameters: 43| | /// - xValue: 44| | /// - x: 45| | /// - y: 46| | /// - Returns: The corresponding ChartHighlight for a given x-value and xy-touch position in pixels. 47| | @objc open func getHighlight(xValue xVal: Double, x: CGFloat, y: CGFloat) -> Highlight? 48| 0| { 49| 0| guard let chart = chart else { return nil } 50| 0| 51| 0| let closestValues = getHighlights(xValue: xVal, x: x, y: y) 52| 0| guard !closestValues.isEmpty else { return nil } 53| 0| 54| 0| let leftAxisMinDist = getMinimumDistance(closestValues: closestValues, y: y, axis: .left) 55| 0| let rightAxisMinDist = getMinimumDistance(closestValues: closestValues, y: y, axis: .right) 56| 0| 57| 0| let axis: YAxis.AxisDependency = leftAxisMinDist < rightAxisMinDist ? .left : .right 58| 0| 59| 0| let detail = closestSelectionDetailByPixel(closestValues: closestValues, x: x, y: y, axis: axis, minSelectionDistance: chart.maxHighlightDistance) 60| 0| 61| 0| return detail 62| 0| } 63| | 64| | /// - Parameters: 65| | /// - xValue: the transformed x-value of the x-touch position 66| | /// - x: touch position 67| | /// - y: touch position 68| | /// - Returns: A list of Highlight objects representing the entries closest to the given xVal. 69| | /// The returned list contains two objects per DataSet (closest rounding up, closest rounding down). 70| | @objc open func getHighlights(xValue: Double, x: CGFloat, y: CGFloat) -> [Highlight] 71| 0| { 72| 0| var vals = [Highlight]() 73| 0| 74| 0| guard let data = self.data else { return vals } 75| 0| 76| 0| for i in 0 ..< data.dataSetCount 77| 0| { 78| 0| guard 79| 0| let dataSet = data.getDataSetByIndex(i), 80| 0| dataSet.isHighlightEnabled // don't include datasets that cannot be highlighted 81| 0| else { continue } 82| 0| 83| 0| 84| 0| // extract all y-values from all DataSets at the given x-value. 85| 0| // 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. 86| 0| vals.append(contentsOf: buildHighlights(dataSet: dataSet, dataSetIndex: i, xValue: xValue, rounding: .closest)) 87| 0| } 88| 0| 89| 0| return vals 90| 0| } 91| | 92| | /// - Returns: An array of `Highlight` objects corresponding to the selected xValue and dataSetIndex. 93| | internal func buildHighlights( 94| | dataSet set: IChartDataSet, 95| | dataSetIndex: Int, 96| | xValue: Double, 97| | rounding: ChartDataSetRounding) -> [Highlight] 98| 0| { 99| 0| guard let chart = self.chart as? BarLineScatterCandleBubbleChartDataProvider else { return [] } 100| 0| 101| 0| var entries = set.entriesForXValue(xValue) 102| 0| if entries.count == 0, let closest = set.entryForXValue(xValue, closestToY: .nan, rounding: rounding) 103| 0| { 104| 0| // Try to find closest x-value and take all entries for that x-value 105| 0| entries = set.entriesForXValue(closest.x) 106| 0| } 107| 0| 108| 0| return entries.map { e in 109| 0| let px = chart.getTransformer(forAxis: set.axisDependency) 110| 0| .pixelForValues(x: e.x, y: e.y) 111| 0| 112| 0| return Highlight(x: e.x, y: e.y, xPx: px.x, yPx: px.y, dataSetIndex: dataSetIndex, axis: set.axisDependency) 113| 0| } 114| 0| } 115| | 116| | // - MARK: - Utilities 117| | 118| | /// - Returns: The `ChartHighlight` of the closest value on the x-y cartesian axes 119| | internal func closestSelectionDetailByPixel( 120| | closestValues: [Highlight], 121| | x: CGFloat, 122| | y: CGFloat, 123| | axis: YAxis.AxisDependency?, 124| | minSelectionDistance: CGFloat) -> Highlight? 125| 0| { 126| 0| var distance = minSelectionDistance 127| 0| var closest: Highlight? 128| 0| 129| 0| for high in closestValues 130| 0| { 131| 0| if axis == nil || high.axis == axis 132| 0| { 133| 0| let cDistance = getDistance(x1: x, y1: y, x2: high.xPx, y2: high.yPx) 134| 0| 135| 0| if cDistance < distance 136| 0| { 137| 0| closest = high 138| 0| distance = cDistance 139| 0| } 140| 0| } 141| 0| } 142| 0| 143| 0| return closest 144| 0| } 145| | 146| | /// - Returns: The minimum distance from a touch-y-value (in pixels) to the closest y-value (in pixels) that is displayed in the chart. 147| | internal func getMinimumDistance( 148| | closestValues: [Highlight], 149| | y: CGFloat, 150| | axis: YAxis.AxisDependency 151| 0| ) -> CGFloat { 152| 0| var distance = CGFloat.greatestFiniteMagnitude 153| 0| 154| 0| for high in closestValues where high.axis == axis 155| 0| { 156| 0| let tempDistance = abs(getHighlightPos(high: high) - y) 157| 0| if tempDistance < distance 158| 0| { 159| 0| distance = tempDistance 160| 0| } 161| 0| } 162| 0| 163| 0| return distance 164| 0| } 165| | 166| | internal func getHighlightPos(high: Highlight) -> CGFloat 167| 0| { 168| 0| return high.yPx 169| 0| } 170| | 171| | internal func getDistance(x1: CGFloat, y1: CGFloat, x2: CGFloat, y2: CGFloat) -> CGFloat 172| 0| { 173| 0| return hypot(x1 - x2, y1 - y2) 174| 0| } 175| | 176| | internal var data: ChartData? 177| 0| { 178| 0| return chart?.data 179| 0| } 180| |} /Users/travis/build/danielgindi/Charts/Source/Charts/Highlight/CombinedHighlighter.swift: 1| |// 2| |// CombinedHighlighter.swift 3| |// Charts 4| |// 5| |// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda 6| |// A port of MPAndroidChart for iOS 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| | 12| |import Foundation 13| |import CoreGraphics 14| | 15| |@objc(CombinedChartHighlighter) 16| |open class CombinedHighlighter: ChartHighlighter 17| |{ 18| | /// bar highlighter for supporting stacked highlighting 19| | private var barHighlighter: BarHighlighter? 20| | 21| | @objc public init(chart: CombinedChartDataProvider, barDataProvider: BarChartDataProvider) 22| 6| { 23| 6| super.init(chart: chart) 24| 6| 25| 6| // if there is BarData, create a BarHighlighter 26| 6| self.barHighlighter = barDataProvider.barData == nil ? nil : BarHighlighter(chart: barDataProvider) 27| 6| } 28| | 29| | open override func getHighlights(xValue: Double, x: CGFloat, y: CGFloat) -> [Highlight] 30| 0| { 31| 0| var vals = [Highlight]() 32| 0| 33| 0| guard 34| 0| let chart = self.chart as? CombinedChartDataProvider, 35| 0| let dataObjects = chart.combinedData?.allData 36| 0| else { return vals } 37| 0| 38| 0| for i in 0..= 0 } 163| | 164| | /// Sets the x- and y-position (pixels) where this highlight was last drawn. 165| | @objc open func setDraw(x: CGFloat, y: CGFloat) 166| 0| { 167| 0| self.drawX = x 168| 0| self.drawY = y 169| 0| } 170| | 171| | /// Sets the x- and y-position (pixels) where this highlight was last drawn. 172| | @objc open func setDraw(pt: CGPoint) 173| 0| { 174| 0| self.drawX = pt.x 175| 0| self.drawY = pt.y 176| 0| } 177| | 178| | // MARK: NSObject 179| | 180| | open override var description: String 181| 0| { 182| 0| return "Highlight, x: \(_x), y: \(_y), dataIndex (combined charts): \(dataIndex), dataSetIndex: \(_dataSetIndex), stackIndex (only stacked barentry): \(_stackIndex)" 183| 0| } 184| |} 185| | 186| | 187| |// MARK: Equatable 188| |extension Highlight /*: Equatable*/ { 189| 2| open override func isEqual(_ object: Any?) -> Bool { 190| 2| guard let object = object as? Highlight else { return false } 191| 2| 192| 2| if self === object 193| 2| { 194| 0| return true 195| 2| } 196| 2| 197| 2| return _x == object._x 198| 2| && _y == object._y 199| 2| && dataIndex == object.dataIndex 200| 2| && _dataSetIndex == object._dataSetIndex 201| 2| && _stackIndex == object._stackIndex 202| 2| } 203| |} /Users/travis/build/danielgindi/Charts/Source/Charts/Highlight/HorizontalBarHighlighter.swift: 1| |// 2| |// HorizontalBarHighlighter.swift 3| |// Charts 4| |// 5| |// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda 6| |// A port of MPAndroidChart for iOS 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| | 12| |import Foundation 13| |import CoreGraphics 14| | 15| |@objc(HorizontalBarChartHighlighter) 16| |open class HorizontalBarHighlighter: BarHighlighter 17| |{ 18| | open override func getHighlight(x: CGFloat, y: CGFloat) -> Highlight? 19| 0| { 20| 0| guard let barData = self.chart?.data as? BarChartData else { return nil } 21| 0| 22| 0| let pos = getValsForTouch(x: y, y: x) 23| 0| guard let high = getHighlight(xValue: Double(pos.y), x: y, y: x) else { return nil } 24| 0| 25| 0| if let set = barData.getDataSetByIndex(high.dataSetIndex) as? IBarChartDataSet, 26| 0| set.isStacked 27| 0| { 28| 0| return getStackedHighlight(high: high, 29| 0| set: set, 30| 0| xValue: Double(pos.y), 31| 0| yValue: Double(pos.x)) 32| 0| } 33| 0| 34| 0| return high 35| 0| } 36| | 37| | internal override func buildHighlights( 38| | dataSet set: IChartDataSet, 39| | dataSetIndex: Int, 40| | xValue: Double, 41| | rounding: ChartDataSetRounding) -> [Highlight] 42| 0| { 43| 0| guard let chart = self.chart as? BarLineScatterCandleBubbleChartDataProvider else { return [] } 44| 0| 45| 0| var entries = set.entriesForXValue(xValue) 46| 0| if entries.count == 0, let closest = set.entryForXValue(xValue, closestToY: .nan, rounding: rounding) 47| 0| { 48| 0| // Try to find closest x-value and take all entries for that x-value 49| 0| entries = set.entriesForXValue(closest.x) 50| 0| } 51| 0| 52| 0| return entries.map { e in 53| 0| let px = chart.getTransformer(forAxis: set.axisDependency) 54| 0| .pixelForValues(x: e.y, y: e.x) 55| 0| return Highlight(x: e.x, y: e.y, xPx: px.x, yPx: px.y, dataSetIndex: dataSetIndex, axis: set.axisDependency) 56| 0| } 57| 0| } 58| | 59| | internal override func getDistance(x1: CGFloat, y1: CGFloat, x2: CGFloat, y2: CGFloat) -> CGFloat 60| 0| { 61| 0| return abs(y1 - y2) 62| 0| } 63| |} /Users/travis/build/danielgindi/Charts/Source/Charts/Highlight/PieHighlighter.swift: 1| |// 2| |// PieHighlighter.swift 3| |// Charts 4| |// 5| |// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda 6| |// A port of MPAndroidChart for iOS 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| | 12| |import Foundation 13| |import CoreGraphics 14| | 15| |@objc(PieChartHighlighter) 16| |open class PieHighlighter: PieRadarHighlighter 17| |{ 18| | open override func closestHighlight(index: Int, x: CGFloat, y: CGFloat) -> Highlight? 19| 0| { 20| 0| guard 21| 0| let set = chart?.data?.dataSets[0], 22| 0| let entry = set.entryForIndex(index) 23| 0| else { return nil } 24| 0| 25| 0| return Highlight(x: Double(index), y: entry.y, xPx: x, yPx: y, dataSetIndex: 0, axis: set.axisDependency) 26| 0| } 27| |} /Users/travis/build/danielgindi/Charts/Source/Charts/Highlight/PieRadarHighlighter.swift: 1| |// 2| |// PieRadarHighlighter.swift 3| |// Charts 4| |// 5| |// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda 6| |// A port of MPAndroidChart for iOS 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| | 12| |import Foundation 13| |import CoreGraphics 14| | 15| |@objc(PieRadarChartHighlighter) 16| |open class PieRadarHighlighter: ChartHighlighter 17| |{ 18| | open override func getHighlight(x: CGFloat, y: CGFloat) -> Highlight? 19| 0| { 20| 0| guard let chart = self.chart as? PieRadarChartViewBase else { return nil } 21| 0| 22| 0| let touchDistanceToCenter = chart.distanceToCenter(x: x, y: y) 23| 0| 24| 0| // check if a slice was touched 25| 0| guard touchDistanceToCenter <= chart.radius else 26| 0| { 27| 0| // if no slice was touched, highlight nothing 28| 0| return nil 29| 0| } 30| 0| 31| 0| var angle = chart.angleForPoint(x: x ,y: y) 32| 0| 33| 0| if chart is PieChartView 34| 0| { 35| 0| angle /= CGFloat(chart.chartAnimator.phaseY) 36| 0| } 37| 0| 38| 0| let index = chart.indexForAngle(angle) 39| 0| 40| 0| // check if the index could be found 41| 0| if index < 0 || index >= chart.data?.maxEntryCountSet?.entryCount ?? 0 42| 0| { 43| 0| return nil 44| 0| } 45| 0| else 46| 0| { 47| 0| return closestHighlight(index: index, x: x, y: y) 48| 0| } 49| 0| 50| 0| } 51| | 52| | /// - Parameters: 53| | /// - index: 54| | /// - x: 55| | /// - y: 56| | /// - Returns: The closest Highlight object of the given objects based on the touch position inside the chart. 57| | @objc open func closestHighlight(index: Int, x: CGFloat, y: CGFloat) -> Highlight? 58| 0| { 59| 0| fatalError("closestHighlight(index, x, y) cannot be called on PieRadarChartHighlighter") 60| 0| } 61| |} /Users/travis/build/danielgindi/Charts/Source/Charts/Highlight/RadarHighlighter.swift: 1| |// 2| |// RadarHighlighter.swift 3| |// Charts 4| |// 5| |// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda 6| |// A port of MPAndroidChart for iOS 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| | 12| |import Foundation 13| |import CoreGraphics 14| | 15| |@objc(RadarChartHighlighter) 16| |open class RadarHighlighter: PieRadarHighlighter 17| |{ 18| | open override func closestHighlight(index: Int, x: CGFloat, y: CGFloat) -> Highlight? 19| 0| { 20| 0| guard let chart = self.chart as? RadarChartView else { return nil } 21| 0| 22| 0| let highlights = getHighlights(forIndex: index) 23| 0| 24| 0| let distanceToCenter = Double(chart.distanceToCenter(x: x, y: y) / chart.factor) 25| 0| 26| 0| var closest: Highlight? 27| 0| var distance = Double.greatestFiniteMagnitude 28| 0| 29| 0| for high in highlights 30| 0| { 31| 0| let cdistance = abs(high.y - distanceToCenter) 32| 0| if cdistance < distance 33| 0| { 34| 0| closest = high 35| 0| distance = cdistance 36| 0| } 37| 0| } 38| 0| 39| 0| return closest 40| 0| } 41| | 42| | /// - Parameters: 43| | /// - index: 44| | /// - Returns: An array of Highlight objects for the given index. 45| | /// The Highlight objects give information about the value at the selected index and DataSet it belongs to. 46| | internal func getHighlights(forIndex index: Int) -> [Highlight] 47| 0| { 48| 0| var vals = [Highlight]() 49| 0| 50| 0| guard 51| 0| let chart = self.chart as? RadarChartView, 52| 0| let chartData = chart.data 53| 0| else { return vals } 54| 0| 55| 0| let phaseX = chart.chartAnimator.phaseX 56| 0| let phaseY = chart.chartAnimator.phaseY 57| 0| let sliceangle = chart.sliceAngle 58| 0| let factor = chart.factor 59| 0| 60| 0| for i in chartData.dataSets.indices 61| 0| { 62| 0| guard 63| 0| let dataSet = chartData.getDataSetByIndex(i), 64| 0| let entry = dataSet.entryForIndex(index) 65| 0| else { continue } 66| 0| 67| 0| let y = (entry.y - chart.chartYMin) 68| 0| 69| 0| let p = chart.centerOffsets.moving(distance: CGFloat(y) * factor * CGFloat(phaseY), 70| 0| atAngle: sliceangle * CGFloat(index) * CGFloat(phaseX) + chart.rotationAngle) 71| 0| 72| 0| let highlight = Highlight(x: Double(index), y: entry.y, xPx: p.x, yPx: p.y, dataSetIndex: i, axis: dataSet.axisDependency) 73| 0| vals.append(highlight) 74| 0| } 75| 0| 76| 0| return vals 77| 0| } 78| |} /Users/travis/build/danielgindi/Charts/Source/Charts/Highlight/Range.swift: 1| |// 2| |// Range.swift 3| |// Charts 4| |// 5| |// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda 6| |// A port of MPAndroidChart for iOS 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| | 12| |import Foundation 13| | 14| |@objc(ChartRange) 15| |open class Range: NSObject 16| |{ 17| | @objc open var from: Double 18| | @objc open var to: Double 19| | 20| | @objc public init(from: Double, to: Double) 21| 150| { 22| 150| self.from = from 23| 150| self.to = to 24| 150| 25| 150| super.init() 26| 150| } 27| | 28| | /// - Parameters: 29| | /// - value: 30| | /// - Returns: `true` if this range contains (if the value is in between) the given value, `false` ifnot. 31| | @objc open func contains(_ value: Double) -> Bool 32| 0| { 33| 0| if value > from && value <= to 34| 0| { 35| 0| return true 36| 0| } 37| 0| else 38| 0| { 39| 0| return false 40| 0| } 41| 0| } 42| | 43| | @objc open func isLarger(_ value: Double) -> Bool 44| 0| { 45| 0| return value > to 46| 0| } 47| | 48| | @objc open func isSmaller(_ value: Double) -> Bool 49| 0| { 50| 0| return value < from 51| 0| } 52| |} /Users/travis/build/danielgindi/Charts/Source/Charts/Jobs/AnimatedMoveViewJob.swift: 1| |// 2| |// AnimatedMoveViewJob.swift 3| |// Charts 4| |// 5| |// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda 6| |// A port of MPAndroidChart for iOS 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| | 12| |import Foundation 13| |import CoreGraphics 14| | 15| |open class AnimatedMoveViewJob: AnimatedViewPortJob 16| |{ 17| | internal override func animationUpdate() 18| 0| { 19| 0| guard 20| 0| let viewPortHandler = viewPortHandler, 21| 0| let transformer = transformer, 22| 0| let view = view 23| 0| else { return } 24| 0| 25| 0| var pt = CGPoint( 26| 0| x: xOrigin + (CGFloat(xValue) - xOrigin) * phase, 27| 0| y: yOrigin + (CGFloat(yValue) - yOrigin) * phase 28| 0| ) 29| 0| 30| 0| transformer.pointValueToPixel(&pt) 31| 0| viewPortHandler.centerViewPort(pt: pt, chart: view) 32| 0| } 33| |} /Users/travis/build/danielgindi/Charts/Source/Charts/Jobs/AnimatedViewPortJob.swift: 1| |// 2| |// AnimatedViewPortJob.swift 3| |// Charts 4| |// 5| |// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda 6| |// A port of MPAndroidChart for iOS 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| | 12| |import Foundation 13| |import CoreGraphics 14| |import QuartzCore 15| | 16| |open class AnimatedViewPortJob: ViewPortJob 17| |{ 18| | internal var phase: CGFloat = 1.0 19| | internal var xOrigin: CGFloat = 0.0 20| | internal var yOrigin: CGFloat = 0.0 21| | 22| | private var _startTime: TimeInterval = 0.0 23| | private var _displayLink: NSUIDisplayLink! 24| | private var _duration: TimeInterval = 0.0 25| | private var _endTime: TimeInterval = 0.0 26| | 27| | private var _easing: ChartEasingFunctionBlock? 28| | 29| | @objc public init( 30| | viewPortHandler: ViewPortHandler, 31| | xValue: Double, 32| | yValue: Double, 33| | transformer: Transformer, 34| | view: ChartViewBase, 35| | xOrigin: CGFloat, 36| | yOrigin: CGFloat, 37| | duration: TimeInterval, 38| | easing: ChartEasingFunctionBlock?) 39| 0| { 40| 0| super.init(viewPortHandler: viewPortHandler, 41| 0| xValue: xValue, 42| 0| yValue: yValue, 43| 0| transformer: transformer, 44| 0| view: view) 45| 0| 46| 0| self.xOrigin = xOrigin 47| 0| self.yOrigin = yOrigin 48| 0| self._duration = duration 49| 0| self._easing = easing 50| 0| } 51| | 52| | deinit 53| 0| { 54| 0| stop(finish: false) 55| 0| } 56| | 57| | open override func doJob() 58| 0| { 59| 0| start() 60| 0| } 61| | 62| | @objc open func start() 63| 0| { 64| 0| _startTime = CACurrentMediaTime() 65| 0| _endTime = _startTime + _duration 66| 0| _endTime = _endTime > _endTime ? _endTime : _endTime 67| 0| 68| 0| updateAnimationPhase(_startTime) 69| 0| 70| 0| _displayLink = NSUIDisplayLink(target: self, selector: #selector(animationLoop)) 71| 0| _displayLink.add(to: .main, forMode: RunLoop.Mode.common) 72| 0| } 73| | 74| | @objc open func stop(finish: Bool) 75| 0| { 76| 0| guard _displayLink != nil else { return } 77| 0| 78| 0| _displayLink.remove(from: .main, forMode: RunLoop.Mode.common) 79| 0| _displayLink = nil 80| 0| 81| 0| if finish 82| 0| { 83| 0| if phase != 1.0 84| 0| { 85| 0| phase = 1.0 86| 0| animationUpdate() 87| 0| } 88| 0| 89| 0| animationEnd() 90| 0| } 91| 0| } 92| | 93| | private func updateAnimationPhase(_ currentTime: TimeInterval) 94| 0| { 95| 0| let elapsedTime = currentTime - _startTime 96| 0| let duration = _duration 97| 0| var elapsed = elapsedTime 98| 0| 99| 0| elapsed = min(elapsed, duration) 100| 0| 101| 0| phase = CGFloat(_easing?(elapsed, duration) ?? elapsed / duration) 102| 0| } 103| | 104| | @objc private func animationLoop() 105| 0| { 106| 0| let currentTime: TimeInterval = CACurrentMediaTime() 107| 0| 108| 0| updateAnimationPhase(currentTime) 109| 0| 110| 0| animationUpdate() 111| 0| 112| 0| if currentTime >= _endTime 113| 0| { 114| 0| stop(finish: true) 115| 0| } 116| 0| } 117| | 118| | internal func animationUpdate() 119| 0| { 120| 0| // Override this 121| 0| } 122| | 123| | internal func animationEnd() 124| 0| { 125| 0| // Override this 126| 0| } 127| |} /Users/travis/build/danielgindi/Charts/Source/Charts/Jobs/AnimatedZoomViewJob.swift: 1| |// 2| |// AnimatedZoomViewJob.swift 3| |// Charts 4| |// 5| |// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda 6| |// A port of MPAndroidChart for iOS 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| | 12| |import Foundation 13| |import CoreGraphics 14| | 15| |open class AnimatedZoomViewJob: AnimatedViewPortJob 16| |{ 17| | internal var yAxis: YAxis? 18| | internal var xAxisRange: Double = 0.0 19| | internal var scaleX: CGFloat = 0.0 20| | internal var scaleY: CGFloat = 0.0 21| | internal var zoomOriginX: CGFloat = 0.0 22| | internal var zoomOriginY: CGFloat = 0.0 23| | internal var zoomCenterX: CGFloat = 0.0 24| | internal var zoomCenterY: CGFloat = 0.0 25| | 26| | @objc public init( 27| | viewPortHandler: ViewPortHandler, 28| | transformer: Transformer, 29| | view: ChartViewBase, 30| | yAxis: YAxis, 31| | xAxisRange: Double, 32| | scaleX: CGFloat, 33| | scaleY: CGFloat, 34| | xOrigin: CGFloat, 35| | yOrigin: CGFloat, 36| | zoomCenterX: CGFloat, 37| | zoomCenterY: CGFloat, 38| | zoomOriginX: CGFloat, 39| | zoomOriginY: CGFloat, 40| | duration: TimeInterval, 41| | easing: ChartEasingFunctionBlock?) 42| 0| { 43| 0| super.init(viewPortHandler: viewPortHandler, 44| 0| xValue: 0.0, 45| 0| yValue: 0.0, 46| 0| transformer: transformer, 47| 0| view: view, 48| 0| xOrigin: xOrigin, 49| 0| yOrigin: yOrigin, 50| 0| duration: duration, 51| 0| easing: easing) 52| 0| 53| 0| self.yAxis = yAxis 54| 0| self.xAxisRange = xAxisRange 55| 0| self.scaleX = scaleX 56| 0| self.scaleY = scaleY 57| 0| self.zoomCenterX = zoomCenterX 58| 0| self.zoomCenterY = zoomCenterY 59| 0| self.zoomOriginX = zoomOriginX 60| 0| self.zoomOriginY = zoomOriginY 61| 0| } 62| | 63| | internal override func animationUpdate() 64| 0| { 65| 0| guard 66| 0| let viewPortHandler = viewPortHandler, 67| 0| let transformer = transformer, 68| 0| let view = view 69| 0| else { return } 70| 0| 71| 0| let scaleX = xOrigin + (self.scaleX - xOrigin) * phase 72| 0| let scaleY = yOrigin + (self.scaleY - yOrigin) * phase 73| 0| 74| 0| var matrix = viewPortHandler.setZoom(scaleX: scaleX, scaleY: scaleY) 75| 0| viewPortHandler.refresh(newMatrix: matrix, chart: view, invalidate: false) 76| 0| 77| 0| let valsInView = CGFloat(yAxis?.axisRange ?? 0.0) / viewPortHandler.scaleY 78| 0| let xsInView = CGFloat(xAxisRange) / viewPortHandler.scaleX 79| 0| 80| 0| var pt = CGPoint( 81| 0| x: zoomOriginX + ((zoomCenterX - xsInView / 2.0) - zoomOriginX) * phase, 82| 0| y: zoomOriginY + ((zoomCenterY + valsInView / 2.0) - zoomOriginY) * phase 83| 0| ) 84| 0| 85| 0| transformer.pointValueToPixel(&pt) 86| 0| 87| 0| matrix = viewPortHandler.translate(pt: pt) 88| 0| viewPortHandler.refresh(newMatrix: matrix, chart: view, invalidate: true) 89| 0| } 90| | 91| | internal override func animationEnd() 92| 0| { 93| 0| (view as? BarLineChartViewBase)?.calculateOffsets() 94| 0| view?.setNeedsDisplay() 95| 0| } 96| |} /Users/travis/build/danielgindi/Charts/Source/Charts/Jobs/MoveViewJob.swift: 1| |// 2| |// MoveViewJob.swift 3| |// Charts 4| |// 5| |// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda 6| |// A port of MPAndroidChart for iOS 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| | 12| |import Foundation 13| |import CoreGraphics 14| | 15| |@objc(MoveChartViewJob) 16| |open class MoveViewJob: ViewPortJob 17| |{ 18| | open override func doJob() 19| 0| { 20| 0| guard 21| 0| let viewPortHandler = viewPortHandler, 22| 0| let transformer = transformer, 23| 0| let view = view 24| 0| else { return } 25| 0| 26| 0| var pt = CGPoint( 27| 0| x: xValue, 28| 0| y: yValue 29| 0| ) 30| 0| 31| 0| transformer.pointValueToPixel(&pt) 32| 0| viewPortHandler.centerViewPort(pt: pt, chart: view) 33| 0| } 34| |} /Users/travis/build/danielgindi/Charts/Source/Charts/Jobs/ViewPortJob.swift: 1| |// 2| |// ViewPortJob.swift 3| |// Charts 4| |// 5| |// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda 6| |// A port of MPAndroidChart for iOS 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| | 12| |import Foundation 13| |import CoreGraphics 14| | 15| |// This defines a viewport modification job, used for delaying or animating viewport changes 16| |@objc(ChartViewPortJob) 17| |open class ViewPortJob: NSObject 18| |{ 19| | internal var point: CGPoint = CGPoint() 20| | internal weak var viewPortHandler: ViewPortHandler? 21| | internal var xValue: Double = 0.0 22| | internal var yValue: Double = 0.0 23| | internal weak var transformer: Transformer? 24| | internal weak var view: ChartViewBase? 25| | 26| | @objc public init( 27| | viewPortHandler: ViewPortHandler, 28| | xValue: Double, 29| | yValue: Double, 30| | transformer: Transformer, 31| | view: ChartViewBase) 32| 0| { 33| 0| super.init() 34| 0| 35| 0| self.viewPortHandler = viewPortHandler 36| 0| self.xValue = xValue 37| 0| self.yValue = yValue 38| 0| self.transformer = transformer 39| 0| self.view = view 40| 0| } 41| | 42| | @objc open func doJob() 43| 0| { 44| 0| fatalError("`doJob()` must be overridden by subclasses") 45| 0| } 46| |} /Users/travis/build/danielgindi/Charts/Source/Charts/Jobs/ZoomViewJob.swift: 1| |// 2| |// ZoomViewJob.swift 3| |// Charts 4| |// 5| |// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda 6| |// A port of MPAndroidChart for iOS 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| | 12| |import Foundation 13| |import CoreGraphics 14| | 15| |@objc(ZoomChartViewJob) 16| |open class ZoomViewJob: ViewPortJob 17| |{ 18| | internal var scaleX: CGFloat = 0.0 19| | internal var scaleY: CGFloat = 0.0 20| | internal var axisDependency: YAxis.AxisDependency = .left 21| | 22| | @objc public init( 23| | viewPortHandler: ViewPortHandler, 24| | scaleX: CGFloat, 25| | scaleY: CGFloat, 26| | xValue: Double, 27| | yValue: Double, 28| | transformer: Transformer, 29| | axis: YAxis.AxisDependency, 30| | view: ChartViewBase) 31| 0| { 32| 0| super.init( 33| 0| viewPortHandler: viewPortHandler, 34| 0| xValue: xValue, 35| 0| yValue: yValue, 36| 0| transformer: transformer, 37| 0| view: view) 38| 0| 39| 0| self.scaleX = scaleX 40| 0| self.scaleY = scaleY 41| 0| self.axisDependency = axis 42| 0| } 43| | 44| | open override func doJob() 45| 0| { 46| 0| guard 47| 0| let viewPortHandler = viewPortHandler, 48| 0| let transformer = transformer, 49| 0| let view = view 50| 0| else { return } 51| 0| 52| 0| var matrix = viewPortHandler.setZoom(scaleX: scaleX, scaleY: scaleY) 53| 0| viewPortHandler.refresh(newMatrix: matrix, chart: view, invalidate: false) 54| 0| 55| 0| let yValsInView = (view as! BarLineChartViewBase).getAxis(axisDependency).axisRange / Double(viewPortHandler.scaleY) 56| 0| let xValsInView = (view as! BarLineChartViewBase).xAxis.axisRange / Double(viewPortHandler.scaleX) 57| 0| 58| 0| var pt = CGPoint( 59| 0| x: CGFloat(xValue - xValsInView / 2.0), 60| 0| y: CGFloat(yValue + yValsInView / 2.0) 61| 0| ) 62| 0| 63| 0| transformer.pointValueToPixel(&pt) 64| 0| 65| 0| matrix = viewPortHandler.translate(pt: pt) 66| 0| viewPortHandler.refresh(newMatrix: matrix, chart: view, invalidate: false) 67| 0| 68| 0| (view as! BarLineChartViewBase).calculateOffsets() 69| 0| view.setNeedsDisplay() 70| 0| } 71| |} /Users/travis/build/danielgindi/Charts/Source/Charts/Renderers/AxisRendererBase.swift: 1| |// 2| |// AxisRendererBase.swift 3| |// Charts 4| |// 5| |// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda 6| |// A port of MPAndroidChart for iOS 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| | 12| |import Foundation 13| |import CoreGraphics 14| | 15| |@objc(ChartAxisRendererBase) 16| |open class AxisRendererBase: Renderer 17| |{ 18| | /// base axis this axis renderer works with 19| | @objc open var axis: AxisBase? 20| | 21| | /// transformer to transform values to screen pixels and return 22| | @objc open var transformer: Transformer? 23| | 24| | @objc public init(viewPortHandler: ViewPortHandler, transformer: Transformer?, axis: AxisBase?) 25| 138| { 26| 138| super.init(viewPortHandler: viewPortHandler) 27| 138| 28| 138| self.transformer = transformer 29| 138| self.axis = axis 30| 138| } 31| | 32| | /// Draws the axis labels on the specified context 33| | @objc open func renderAxisLabels(context: CGContext) 34| 0| { 35| 0| fatalError("renderAxisLabels() cannot be called on AxisRendererBase") 36| 0| } 37| | 38| | /// Draws the grid lines belonging to the axis. 39| | @objc open func renderGridLines(context: CGContext) 40| 0| { 41| 0| fatalError("renderGridLines() cannot be called on AxisRendererBase") 42| 0| } 43| | 44| | /// Draws the line that goes alongside the axis. 45| | @objc open func renderAxisLine(context: CGContext) 46| 0| { 47| 0| fatalError("renderAxisLine() cannot be called on AxisRendererBase") 48| 0| } 49| | 50| | /// Draws the LimitLines associated with this axis to the screen. 51| | @objc open func renderLimitLines(context: CGContext) 52| 0| { 53| 0| fatalError("renderLimitLines() cannot be called on AxisRendererBase") 54| 0| } 55| | 56| | /// Computes the axis values. 57| | /// 58| | /// - Parameters: 59| | /// - min: the minimum value in the data object for this axis 60| | /// - max: the maximum value in the data object for this axis 61| | @objc open func computeAxis(min: Double, max: Double, inverted: Bool) 62| 214| { 63| 214| var min = min, max = max 64| 214| 65| 214| if let transformer = self.transformer 66| 214| { 67| 214| // calculate the starting and entry point of the y-labels (depending on zoom / contentrect bounds) 68| 214| if viewPortHandler.contentWidth > 10.0 && !viewPortHandler.isFullyZoomedOutY 69| 214| { 70| 0| let p1 = transformer.valueForTouchPoint(CGPoint(x: viewPortHandler.contentLeft, y: viewPortHandler.contentTop)) 71| 0| let p2 = transformer.valueForTouchPoint(CGPoint(x: viewPortHandler.contentLeft, y: viewPortHandler.contentBottom)) 72| 0| 73| 0| if !inverted 74| 0| { 75| 0| min = Double(p2.y) 76| 0| max = Double(p1.y) 77| 0| } 78| 0| else 79| 0| { 80| 0| min = Double(p1.y) 81| 0| max = Double(p2.y) 82| 0| } 83| 214| } 84| 214| } 85| 214| 86| 214| computeAxisValues(min: min, max: max) 87| 214| } 88| | 89| | /// Sets up the axis values. Computes the desired number of labels between the two given extremes. 90| | @objc open func computeAxisValues(min: Double, max: Double) 91| 373| { 92| 373| guard let axis = self.axis else { return } 93| 373| 94| 373| let yMin = min 95| 373| let yMax = max 96| 373| 97| 373| let labelCount = axis.labelCount 98| 373| let range = abs(yMax - yMin) 99| 373| 100| 373| if labelCount == 0 || range <= 0 || range.isInfinite 101| 373| { 102| 0| axis.entries = [Double]() 103| 0| axis.centeredEntries = [Double]() 104| 0| return 105| 373| } 106| 373| 107| 373| // Find out how much spacing (in y value space) between axis values 108| 373| let rawInterval = range / Double(labelCount) 109| 373| var interval = rawInterval.roundedToNextSignficant() 110| 373| 111| 373| // If granularity is enabled, then do not allow the interval to go below specified granularity. 112| 373| // This is used to avoid repeated values when rounding values for display. 113| 373| if axis.granularityEnabled 114| 373| { 115| 0| interval = interval < axis.granularity ? axis.granularity : interval 116| 373| } 117| 373| 118| 373| // Normalize interval 119| 373| let intervalMagnitude = pow(10.0, Double(Int(log10(interval)))).roundedToNextSignficant() 120| 373| let intervalSigDigit = Int(interval / intervalMagnitude) 121| 373| if intervalSigDigit > 5 122| 373| { 123| 38| // Use one order of magnitude higher, to avoid intervals like 0.9 or 90 124| 38| // if it's 0.0 after floor(), we use the old value 125| 38| interval = floor(10.0 * intervalMagnitude) == 0.0 ? interval : floor(10.0 * intervalMagnitude) 126| 373| } 127| 373| 128| 373| var n = axis.centerAxisLabelsEnabled ? 1 : 0 129| 373| 130| 373| // force label count 131| 373| if axis.isForceLabelsEnabled 132| 373| { 133| 0| interval = Double(range) / Double(labelCount - 1) 134| 0| 135| 0| // Ensure stops contains at least n elements. 136| 0| axis.entries.removeAll(keepingCapacity: true) 137| 0| axis.entries.reserveCapacity(labelCount) 138| 0| 139| 0| var v = yMin 140| 0| 141| 0| for _ in 0 ..< labelCount 142| 0| { 143| 0| axis.entries.append(v) 144| 0| v += interval 145| 0| } 146| 0| 147| 0| n = labelCount 148| 373| } 149| 373| else 150| 373| { 151| 373| // no forced count 152| 373| 153| 373| var first = interval == 0.0 ? 0.0 : ceil(yMin / interval) * interval 154| 373| 155| 373| if axis.centerAxisLabelsEnabled 156| 373| { 157| 0| first -= interval 158| 373| } 159| 373| 160| 373| let last = interval == 0.0 ? 0.0 : (floor(yMax / interval) * interval).nextUp 161| 373| 162| 373| if interval != 0.0 && last != first 163| 373| { 164| 373| for _ in stride(from: first, through: last, by: interval) 165| 2.21k| { 166| 2.21k| n += 1 167| 2.21k| } 168| 373| } 169| 373| else if last == first && n == 0 170| 373| { 171| 0| n = 1 172| 373| } 173| 373| 174| 373| // Ensure stops contains at least n elements. 175| 373| axis.entries.removeAll(keepingCapacity: true) 176| 373| axis.entries.reserveCapacity(labelCount) 177| 373| 178| 373| var f = first 179| 373| var i = 0 180| 2.58k| while i < n 181| 2.21k| { 182| 2.21k| if f == 0.0 183| 2.21k| { 184| 357| // Fix for IEEE negative zero case (Where value == -0.0, and 0.0 == -0.0) 185| 357| f = 0.0 186| 2.21k| } 187| 2.21k| 188| 2.21k| axis.entries.append(Double(f)) 189| 2.21k| 190| 2.21k| f += interval 191| 2.21k| i += 1 192| 2.21k| } 193| 373| } 194| 373| 195| 373| // set decimals 196| 373| if interval < 1 197| 373| { 198| 26| axis.decimals = Int(ceil(-log10(interval))) 199| 373| } 200| 373| else 201| 373| { 202| 347| axis.decimals = 0 203| 373| } 204| 373| 205| 373| if axis.centerAxisLabelsEnabled 206| 373| { 207| 0| axis.centeredEntries.reserveCapacity(n) 208| 0| axis.centeredEntries.removeAll() 209| 0| 210| 0| let offset: Double = interval / 2.0 211| 0| 212| 0| for i in 0 ..< n 213| 0| { 214| 0| axis.centeredEntries.append(axis.entries[i] + offset) 215| 0| } 216| 373| } 217| 373| } 218| |} /Users/travis/build/danielgindi/Charts/Source/Charts/Renderers/BarChartRenderer.swift: 1| |// 2| |// BarChartRenderer.swift 3| |// Charts 4| |// 5| |// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda 6| |// A port of MPAndroidChart for iOS 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| | 12| |import Foundation 13| |import CoreGraphics 14| | 15| |#if canImport(UIKit) 16| | import UIKit 17| |#endif 18| | 19| |#if canImport(Cocoa) 20| |import Cocoa 21| |#endif 22| | 23| |open class BarChartRenderer: BarLineScatterCandleBubbleRenderer 24| |{ 25| | /// A nested array of elements ordered logically (i.e not in visual/drawing order) for use with VoiceOver 26| | /// 27| | /// Its use is apparent when there are multiple data sets, since we want to read bars in left to right order, 28| | /// irrespective of dataset. However, drawing is done per dataset, so using this array and then flattening it prevents us from needing to 29| | /// re-render for the sake of accessibility. 30| | /// 31| | /// In practise, its structure is: 32| | /// 33| | /// ```` 34| | /// [ 35| | /// [dataset1 element1, dataset2 element1], 36| | /// [dataset1 element2, dataset2 element2], 37| | /// [dataset1 element3, dataset2 element3] 38| | /// ... 39| | /// ] 40| | /// ```` 41| | /// This is done to provide numerical inference across datasets to a screenreader user, in the same way that a sighted individual 42| | /// uses a multi-dataset bar chart. 43| | /// 44| | /// The ````internal```` specifier is to allow subclasses (HorizontalBar) to populate the same array 45| | internal lazy var accessibilityOrderedElements: [[NSUIAccessibilityElement]] = accessibilityCreateEmptyOrderedElements() 46| | 47| | private class Buffer 48| | { 49| | var rects = [CGRect]() 50| | } 51| | 52| | @objc open weak var dataProvider: BarChartDataProvider? 53| | 54| | @objc public init(dataProvider: BarChartDataProvider, animator: Animator, viewPortHandler: ViewPortHandler) 55| 46| { 56| 46| super.init(animator: animator, viewPortHandler: viewPortHandler) 57| 46| 58| 46| self.dataProvider = dataProvider 59| 46| } 60| | 61| | // [CGRect] per dataset 62| | private var _buffers = [Buffer]() 63| | 64| | open override func initBuffers() 65| 62| { 66| 62| if let barData = dataProvider?.barData 67| 62| { 68| 62| // Matche buffers count to dataset count 69| 62| if _buffers.count != barData.dataSetCount 70| 62| { 71| 68| while _buffers.count < barData.dataSetCount 72| 34| { 73| 34| _buffers.append(Buffer()) 74| 34| } 75| 34| while _buffers.count > barData.dataSetCount 76| 34| { 77| 0| _buffers.removeLast() 78| 34| } 79| 62| } 80| 62| 81| 62| for i in stride(from: 0, to: barData.dataSetCount, by: 1) 82| 62| { 83| 62| let set = barData.dataSets[i] as! IBarChartDataSet 84| 62| let size = set.entryCount * (set.isStacked ? set.stackSize : 1) 85| 62| if _buffers[i].rects.count != size 86| 62| { 87| 34| _buffers[i].rects = [CGRect](repeating: CGRect(), count: size) 88| 62| } 89| 62| } 90| 62| } 91| 62| else 92| 62| { 93| 0| _buffers.removeAll() 94| 62| } 95| 62| } 96| | 97| | private func prepareBuffer(dataSet: IBarChartDataSet, index: Int) 98| 34| { 99| 34| guard 100| 34| let dataProvider = dataProvider, 101| 34| let barData = dataProvider.barData 102| 34| else { return } 103| 34| 104| 34| let barWidthHalf = barData.barWidth / 2.0 105| 34| 106| 34| let buffer = _buffers[index] 107| 34| var bufferIndex = 0 108| 34| let containsStacks = dataSet.isStacked 109| 34| 110| 34| let isInverted = dataProvider.isInverted(axis: dataSet.axisDependency) 111| 34| let phaseY = animator.phaseY 112| 34| var barRect = CGRect() 113| 34| var x: Double 114| 34| var y: Double 115| 34| 116| 34| 117| 34| for i in stride(from: 0, to: min(Int(ceil(Double(dataSet.entryCount) * animator.phaseX)), dataSet.entryCount), by: 1) 118| 945| { 119| 945| guard let e = dataSet.entryForIndex(i) as? BarChartDataEntry else { continue } 120| 945| 121| 945| let vals = e.yValues 122| 945| 123| 945| x = e.x 124| 945| y = e.y 125| 945| 126| 945| if !containsStacks || vals == nil 127| 945| { 128| 930| let left = CGFloat(x - barWidthHalf) 129| 930| let right = CGFloat(x + barWidthHalf) 130| 930| var top = isInverted 131| 930| ? (y <= 0.0 ? CGFloat(y) : 0) 132| 930| : (y >= 0.0 ? CGFloat(y) : 0) 133| 930| var bottom = isInverted 134| 930| ? (y >= 0.0 ? CGFloat(y) : 0) 135| 930| : (y <= 0.0 ? CGFloat(y) : 0) 136| 930| 137| 930| /* When drawing each bar, the renderer actually draws each bar from 0 to the required value. 138| 930| * This drawn bar is then clipped to the visible chart rect in BarLineChartViewBase's draw(rect:) using clipDataToContent. 139| 930| * While this works fine when calculating the bar rects for drawing, it causes the accessibilityFrames to be oversized in some cases. 140| 930| * This offset attempts to undo that unnecessary drawing when calculating barRects 141| 930| * 142| 930| * +---------------------------------------------------------------+---------------------------------------------------------------+ 143| 930| * | Situation 1: (!inverted && y >= 0) | Situation 3: (inverted && y >= 0) | 144| 930| * | | | 145| 930| * | y -> +--+ <- top | 0 -> ---+--+---+--+------ <- top | 146| 930| * | |//| } topOffset = y - max | | | |//| } topOffset = min | 147| 930| * | max -> +---------+--+----+ <- top - topOffset | min -> +--+--+---+--+----+ <- top + topOffset | 148| 930| * | | +--+ |//| | | | | | |//| | | 149| 930| * | | | | |//| | | | +--+ |//| | | 150| 930| * | | | | |//| | | | |//| | | 151| 930| * | min -> +--+--+---+--+----+ <- bottom + bottomOffset | max -> +---------+--+----+ <- bottom - bottomOffset | 152| 930| * | | | |//| } bottomOffset = min | |//| } bottomOffset = y - max | 153| 930| * | 0 -> ---+--+---+--+----- <- bottom | y -> +--+ <- bottom | 154| 930| * | | | 155| 930| * +---------------------------------------------------------------+---------------------------------------------------------------+ 156| 930| * | Situation 2: (!inverted && y < 0) | Situation 4: (inverted && y < 0) | 157| 930| * | | | 158| 930| * | 0 -> ---+--+---+--+----- <- top | y -> +--+ <- top | 159| 930| * | | | |//| } topOffset = -max | |//| } topOffset = min - y | 160| 930| * | max -> +--+--+---+--+----+ <- top - topOffset | min -> +---------+--+----+ <- top + topOffset | 161| 930| * | | | | |//| | | | +--+ |//| | | 162| 930| * | | +--+ |//| | | | | | |//| | | 163| 930| * | | |//| | | | | | |//| | | 164| 930| * | min -> +---------+--+----+ <- bottom + bottomOffset | max -> +--+--+---+--+----+ <- bottom - bottomOffset | 165| 930| * | |//| } bottomOffset = min - y | | | |//| } bottomOffset = -max | 166| 930| * | y -> +--+ <- bottom | 0 -> ---+--+---+--+------- <- bottom | 167| 930| * | | | 168| 930| * +---------------------------------------------------------------+---------------------------------------------------------------+ 169| 930| */ 170| 930| var topOffset: CGFloat = 0.0 171| 930| var bottomOffset: CGFloat = 0.0 172| 930| if let offsetView = dataProvider as? BarChartView 173| 930| { 174| 840| let offsetAxis = offsetView.getAxis(dataSet.axisDependency) 175| 840| if y >= 0 176| 840| { 177| 490| // situation 1 178| 490| if offsetAxis.axisMaximum < y 179| 490| { 180| 46| topOffset = CGFloat(y - offsetAxis.axisMaximum) 181| 490| } 182| 490| if offsetAxis.axisMinimum > 0 183| 490| { 184| 90| bottomOffset = CGFloat(offsetAxis.axisMinimum) 185| 490| } 186| 840| } 187| 840| else // y < 0 188| 840| { 189| 350| //situation 2 190| 350| if offsetAxis.axisMaximum < 0 191| 350| { 192| 30| topOffset = CGFloat(offsetAxis.axisMaximum * -1) 193| 350| } 194| 350| if offsetAxis.axisMinimum > y 195| 350| { 196| 30| bottomOffset = CGFloat(offsetAxis.axisMinimum - y) 197| 350| } 198| 840| } 199| 840| if isInverted 200| 840| { 201| 180| // situation 3 and 4 202| 180| // exchange topOffset/bottomOffset based on 1 and 2 203| 180| // see diagram above 204| 180| (topOffset, bottomOffset) = (bottomOffset, topOffset) 205| 840| } 206| 930| } 207| 930| //apply offset 208| 930| top = isInverted ? top + topOffset : top - topOffset 209| 930| bottom = isInverted ? bottom - bottomOffset : bottom + bottomOffset 210| 930| 211| 930| // multiply the height of the rect with the phase 212| 930| // explicitly add 0 + topOffset to indicate this is changed after adding accessibility support (#3650, #3520) 213| 930| if top > 0 + topOffset 214| 930| { 215| 417| top *= CGFloat(phaseY) 216| 930| } 217| 930| else 218| 930| { 219| 513| bottom *= CGFloat(phaseY) 220| 930| } 221| 930| 222| 930| barRect.origin.x = left 223| 930| barRect.origin.y = top 224| 930| barRect.size.width = right - left 225| 930| barRect.size.height = bottom - top 226| 930| buffer.rects[bufferIndex] = barRect 227| 930| bufferIndex += 1 228| 945| } 229| 945| else 230| 945| { 231| 15| var posY = 0.0 232| 15| var negY = -e.negativeSum 233| 15| var yStart = 0.0 234| 15| 235| 15| // fill the stack 236| 15| for k in 0 ..< vals!.count 237| 75| { 238| 75| let value = vals![k] 239| 75| 240| 75| if value == 0.0 && (posY == 0.0 || negY == 0.0) 241| 75| { 242| 0| // Take care of the situation of a 0.0 value, which overlaps a non-zero bar 243| 0| y = value 244| 0| yStart = y 245| 75| } 246| 75| else if value >= 0.0 247| 75| { 248| 45| y = posY 249| 45| yStart = posY + value 250| 45| posY = yStart 251| 75| } 252| 75| else 253| 75| { 254| 30| y = negY 255| 30| yStart = negY + abs(value) 256| 30| negY += abs(value) 257| 75| } 258| 75| 259| 75| let left = CGFloat(x - barWidthHalf) 260| 75| let right = CGFloat(x + barWidthHalf) 261| 75| var top = isInverted 262| 75| ? (y <= yStart ? CGFloat(y) : CGFloat(yStart)) 263| 75| : (y >= yStart ? CGFloat(y) : CGFloat(yStart)) 264| 75| var bottom = isInverted 265| 75| ? (y >= yStart ? CGFloat(y) : CGFloat(yStart)) 266| 75| : (y <= yStart ? CGFloat(y) : CGFloat(yStart)) 267| 75| 268| 75| // multiply the height of the rect with the phase 269| 75| top *= CGFloat(phaseY) 270| 75| bottom *= CGFloat(phaseY) 271| 75| 272| 75| barRect.origin.x = left 273| 75| barRect.size.width = right - left 274| 75| barRect.origin.y = top 275| 75| barRect.size.height = bottom - top 276| 75| 277| 75| buffer.rects[bufferIndex] = barRect 278| 75| bufferIndex += 1 279| 75| } 280| 945| } 281| 945| } 282| 34| } 283| | 284| | open override func drawData(context: CGContext) 285| 40| { 286| 40| guard 287| 40| let dataProvider = dataProvider, 288| 40| let barData = dataProvider.barData 289| 40| else { return } 290| 40| 291| 40| // If we redraw the data, remove and repopulate accessible elements to update label values and frames 292| 40| accessibleChartElements.removeAll() 293| 40| accessibilityOrderedElements = accessibilityCreateEmptyOrderedElements() 294| 40| 295| 40| // Make the chart header the first element in the accessible elements array 296| 40| if let chart = dataProvider as? BarChartView { 297| 37| let element = createAccessibleHeader(usingChart: chart, 298| 37| andData: barData, 299| 37| withDefaultDescription: "Bar Chart") 300| 37| accessibleChartElements.append(element) 301| 40| } 302| 40| 303| 40| // Populate logically ordered nested elements into accessibilityOrderedElements in drawDataSet() 304| 40| for i in 0 ..< barData.dataSetCount 305| 40| { 306| 40| guard let set = barData.getDataSetByIndex(i) else { continue } 307| 40| 308| 40| if set.isVisible 309| 40| { 310| 40| if !(set is IBarChartDataSet) 311| 40| { 312| 0| fatalError("Datasets for BarChartRenderer must conform to IBarChartDataset") 313| 40| } 314| 40| 315| 40| drawDataSet(context: context, dataSet: set as! IBarChartDataSet, index: i) 316| 40| } 317| 40| } 318| 40| 319| 40| // Merge nested ordered arrays into the single accessibleChartElements. 320| 960| accessibleChartElements.append(contentsOf: accessibilityOrderedElements.flatMap { $0 } ) 321| 40| accessibilityPostLayoutChangedNotification() 322| 40| } 323| | 324| | private var _barShadowRectBuffer: CGRect = CGRect() 325| | 326| | @objc open func drawDataSet(context: CGContext, dataSet: IBarChartDataSet, index: Int) 327| 34| { 328| 34| guard let dataProvider = dataProvider else { return } 329| 34| 330| 34| let trans = dataProvider.getTransformer(forAxis: dataSet.axisDependency) 331| 34| 332| 34| prepareBuffer(dataSet: dataSet, index: index) 333| 34| trans.rectValuesToPixel(&_buffers[index].rects) 334| 34| 335| 34| let borderWidth = dataSet.barBorderWidth 336| 34| let borderColor = dataSet.barBorderColor 337| 34| let drawBorder = borderWidth > 0.0 338| 34| 339| 34| context.saveGState() 340| 34| 341| 34| // draw the bar shadow before the values 342| 34| if dataProvider.isDrawBarShadowEnabled 343| 34| { 344| 0| guard let barData = dataProvider.barData else { return } 345| 0| 346| 0| let barWidth = barData.barWidth 347| 0| let barWidthHalf = barWidth / 2.0 348| 0| var x: Double = 0.0 349| 0| 350| 0| for i in stride(from: 0, to: min(Int(ceil(Double(dataSet.entryCount) * animator.phaseX)), dataSet.entryCount), by: 1) 351| 0| { 352| 0| guard let e = dataSet.entryForIndex(i) as? BarChartDataEntry else { continue } 353| 0| 354| 0| x = e.x 355| 0| 356| 0| _barShadowRectBuffer.origin.x = CGFloat(x - barWidthHalf) 357| 0| _barShadowRectBuffer.size.width = CGFloat(barWidth) 358| 0| 359| 0| trans.rectValueToPixel(&_barShadowRectBuffer) 360| 0| 361| 0| if !viewPortHandler.isInBoundsLeft(_barShadowRectBuffer.origin.x + _barShadowRectBuffer.size.width) 362| 0| { 363| 0| continue 364| 0| } 365| 0| 366| 0| if !viewPortHandler.isInBoundsRight(_barShadowRectBuffer.origin.x) 367| 0| { 368| 0| break 369| 0| } 370| 0| 371| 0| _barShadowRectBuffer.origin.y = viewPortHandler.contentTop 372| 0| _barShadowRectBuffer.size.height = viewPortHandler.contentHeight 373| 0| 374| 0| context.setFillColor(dataSet.barShadowColor.cgColor) 375| 0| context.fill(_barShadowRectBuffer) 376| 0| } 377| 34| } 378| 34| 379| 34| let buffer = _buffers[index] 380| 34| 381| 34| // draw the bar shadow before the values 382| 34| if dataProvider.isDrawBarShadowEnabled 383| 34| { 384| 0| for j in stride(from: 0, to: buffer.rects.count, by: 1) 385| 0| { 386| 0| let barRect = buffer.rects[j] 387| 0| 388| 0| if (!viewPortHandler.isInBoundsLeft(barRect.origin.x + barRect.size.width)) 389| 0| { 390| 0| continue 391| 0| } 392| 0| 393| 0| if (!viewPortHandler.isInBoundsRight(barRect.origin.x)) 394| 0| { 395| 0| break 396| 0| } 397| 0| 398| 0| context.setFillColor(dataSet.barShadowColor.cgColor) 399| 0| context.fill(barRect) 400| 0| } 401| 34| } 402| 34| 403| 34| let isSingleColor = dataSet.colors.count == 1 404| 34| 405| 34| if isSingleColor 406| 34| { 407| 31| context.setFillColor(dataSet.color(atIndex: 0).cgColor) 408| 34| } 409| 34| 410| 34| // In case the chart is stacked, we need to accomodate individual bars within accessibilityOrdereredElements 411| 34| let isStacked = dataSet.isStacked 412| 34| let stackSize = isStacked ? dataSet.stackSize : 1 413| 34| 414| 34| for j in stride(from: 0, to: buffer.rects.count, by: 1) 415| 1.00k| { 416| 1.00k| let barRect = buffer.rects[j] 417| 1.00k| 418| 1.00k| if (!viewPortHandler.isInBoundsLeft(barRect.origin.x + barRect.size.width)) 419| 1.00k| { 420| 0| continue 421| 1.00k| } 422| 1.00k| 423| 1.00k| if (!viewPortHandler.isInBoundsRight(barRect.origin.x)) 424| 1.00k| { 425| 0| break 426| 1.00k| } 427| 1.00k| 428| 1.00k| if !isSingleColor 429| 1.00k| { 430| 75| // Set the color for the currently drawn value. If the index is out of bounds, reuse colors. 431| 75| context.setFillColor(dataSet.color(atIndex: j).cgColor) 432| 1.00k| } 433| 1.00k| 434| 1.00k| context.fill(barRect) 435| 1.00k| 436| 1.00k| if drawBorder 437| 1.00k| { 438| 0| context.setStrokeColor(borderColor.cgColor) 439| 0| context.setLineWidth(borderWidth) 440| 0| context.stroke(barRect) 441| 1.00k| } 442| 1.00k| 443| 1.00k| // Create and append the corresponding accessibility element to accessibilityOrderedElements 444| 1.00k| if let chart = dataProvider as? BarChartView 445| 1.00k| { 446| 915| let element = createAccessibleElement(withIndex: j, 447| 915| container: chart, 448| 915| dataSet: dataSet, 449| 915| dataSetIndex: index, 450| 915| stackSize: stackSize) 451| 915| { (element) in 452| 915| element.accessibilityFrame = barRect 453| 915| } 454| 915| 455| 915| accessibilityOrderedElements[j/stackSize].append(element) 456| 1.00k| } 457| 1.00k| } 458| 34| 459| 34| context.restoreGState() 460| 34| } 461| | 462| | open func prepareBarHighlight( 463| | x: Double, 464| | y1: Double, 465| | y2: Double, 466| | barWidthHalf: Double, 467| | trans: Transformer, 468| | rect: inout CGRect) 469| 0| { 470| 0| let left = x - barWidthHalf 471| 0| let right = x + barWidthHalf 472| 0| let top = y1 473| 0| let bottom = y2 474| 0| 475| 0| rect.origin.x = CGFloat(left) 476| 0| rect.origin.y = CGFloat(top) 477| 0| rect.size.width = CGFloat(right - left) 478| 0| rect.size.height = CGFloat(bottom - top) 479| 0| 480| 0| trans.rectValueToPixel(&rect, phaseY: animator.phaseY ) 481| 0| } 482| | 483| | open override func drawValues(context: CGContext) 484| 34| { 485| 34| // if values are drawn 486| 34| if isDrawingValuesAllowed(dataProvider: dataProvider) 487| 34| { 488| 34| guard 489| 34| let dataProvider = dataProvider, 490| 34| let barData = dataProvider.barData 491| 34| else { return } 492| 34| 493| 34| let dataSets = barData.dataSets 494| 34| 495| 34| let valueOffsetPlus: CGFloat = 4.5 496| 34| var posOffset: CGFloat 497| 34| var negOffset: CGFloat 498| 34| let drawValueAboveBar = dataProvider.isDrawValueAboveBarEnabled 499| 34| 500| 34| for dataSetIndex in 0 ..< barData.dataSetCount 501| 34| { 502| 34| guard let 503| 34| dataSet = dataSets[dataSetIndex] as? IBarChartDataSet, 504| 34| shouldDrawValues(forDataSet: dataSet) 505| 34| else { continue } 506| 32| 507| 32| let isInverted = dataProvider.isInverted(axis: dataSet.axisDependency) 508| 32| 509| 32| // calculate the correct offset depending on the draw position of the value 510| 32| let valueFont = dataSet.valueFont 511| 32| let valueTextHeight = valueFont.lineHeight 512| 32| posOffset = (drawValueAboveBar ? -(valueTextHeight + valueOffsetPlus) : valueOffsetPlus) 513| 32| negOffset = (drawValueAboveBar ? valueOffsetPlus : -(valueTextHeight + valueOffsetPlus)) 514| 32| 515| 32| if isInverted 516| 32| { 517| 6| posOffset = -posOffset - valueTextHeight 518| 6| negOffset = -negOffset - valueTextHeight 519| 32| } 520| 32| 521| 32| let buffer = _buffers[dataSetIndex] 522| 32| 523| 32| guard let formatter = dataSet.valueFormatter else { continue } 524| 32| 525| 32| let trans = dataProvider.getTransformer(forAxis: dataSet.axisDependency) 526| 32| 527| 32| let phaseY = animator.phaseY 528| 32| 529| 32| let iconsOffset = dataSet.iconsOffset 530| 32| 531| 32| // if only single values are drawn (sum) 532| 32| if !dataSet.isStacked 533| 32| { 534| 30| for j in 0 ..< Int(ceil(Double(dataSet.entryCount) * animator.phaseX)) 535| 900| { 536| 900| guard let e = dataSet.entryForIndex(j) as? BarChartDataEntry else { continue } 537| 900| 538| 900| let rect = buffer.rects[j] 539| 900| 540| 900| let x = rect.origin.x + rect.size.width / 2.0 541| 900| 542| 900| if !viewPortHandler.isInBoundsRight(x) 543| 900| { 544| 0| break 545| 900| } 546| 900| 547| 900| if !viewPortHandler.isInBoundsY(rect.origin.y) 548| 900| || !viewPortHandler.isInBoundsLeft(x) 549| 900| { 550| 60| continue 551| 840| } 552| 840| 553| 840| let val = e.y 554| 840| 555| 840| if dataSet.isDrawValuesEnabled 556| 840| { 557| 840| drawValue( 558| 840| context: context, 559| 840| value: formatter.stringForValue( 560| 840| val, 561| 840| entry: e, 562| 840| dataSetIndex: dataSetIndex, 563| 840| viewPortHandler: viewPortHandler), 564| 840| xPos: x, 565| 840| yPos: val >= 0.0 566| 840| ? (rect.origin.y + posOffset) 567| 840| : (rect.origin.y + rect.size.height + negOffset), 568| 840| font: valueFont, 569| 840| align: .center, 570| 840| color: dataSet.valueTextColorAt(j)) 571| 840| } 572| 840| 573| 840| if let icon = e.icon, dataSet.isDrawIconsEnabled 574| 840| { 575| 30| var px = x 576| 30| var py = val >= 0.0 577| 30| ? (rect.origin.y + posOffset) 578| 30| : (rect.origin.y + rect.size.height + negOffset) 579| 30| 580| 30| px += iconsOffset.x 581| 30| py += iconsOffset.y 582| 30| 583| 30| ChartUtils.drawImage( 584| 30| context: context, 585| 30| image: icon, 586| 30| x: px, 587| 30| y: py, 588| 30| size: icon.size) 589| 840| } 590| 840| } 591| 32| } 592| 32| else 593| 32| { 594| 2| // if we have stacks 595| 2| 596| 2| var bufferIndex = 0 597| 2| 598| 2| for index in 0 ..< Int(ceil(Double(dataSet.entryCount) * animator.phaseX)) 599| 10| { 600| 10| guard let e = dataSet.entryForIndex(index) as? BarChartDataEntry else { continue } 601| 10| 602| 10| let vals = e.yValues 603| 10| 604| 10| let rect = buffer.rects[bufferIndex] 605| 10| 606| 10| let x = rect.origin.x + rect.size.width / 2.0 607| 10| 608| 10| // we still draw stacked bars, but there is one non-stacked in between 609| 10| if vals == nil 610| 10| { 611| 0| if !viewPortHandler.isInBoundsRight(x) 612| 0| { 613| 0| break 614| 0| } 615| 0| 616| 0| if !viewPortHandler.isInBoundsY(rect.origin.y) 617| 0| || !viewPortHandler.isInBoundsLeft(x) 618| 0| { 619| 0| continue 620| 0| } 621| 0| 622| 0| if dataSet.isDrawValuesEnabled 623| 0| { 624| 0| drawValue( 625| 0| context: context, 626| 0| value: formatter.stringForValue( 627| 0| e.y, 628| 0| entry: e, 629| 0| dataSetIndex: dataSetIndex, 630| 0| viewPortHandler: viewPortHandler), 631| 0| xPos: x, 632| 0| yPos: rect.origin.y + 633| 0| (e.y >= 0 ? posOffset : negOffset), 634| 0| font: valueFont, 635| 0| align: .center, 636| 0| color: dataSet.valueTextColorAt(index)) 637| 0| } 638| 0| 639| 0| if let icon = e.icon, dataSet.isDrawIconsEnabled 640| 0| { 641| 0| var px = x 642| 0| var py = rect.origin.y + 643| 0| (e.y >= 0 ? posOffset : negOffset) 644| 0| 645| 0| px += iconsOffset.x 646| 0| py += iconsOffset.y 647| 0| 648| 0| ChartUtils.drawImage( 649| 0| context: context, 650| 0| image: icon, 651| 0| x: px, 652| 0| y: py, 653| 0| size: icon.size) 654| 0| } 655| 10| } 656| 10| else 657| 10| { 658| 10| // draw stack values 659| 10| 660| 10| let vals = vals! 661| 10| var transformed = [CGPoint]() 662| 10| 663| 10| var posY = 0.0 664| 10| var negY = -e.negativeSum 665| 10| 666| 10| for k in 0 ..< vals.count 667| 50| { 668| 50| let value = vals[k] 669| 50| var y: Double 670| 50| 671| 50| if value == 0.0 && (posY == 0.0 || negY == 0.0) 672| 50| { 673| 0| // Take care of the situation of a 0.0 value, which overlaps a non-zero bar 674| 0| y = value 675| 50| } 676| 50| else if value >= 0.0 677| 50| { 678| 30| posY += value 679| 30| y = posY 680| 50| } 681| 50| else 682| 50| { 683| 20| y = negY 684| 20| negY -= value 685| 50| } 686| 50| 687| 50| transformed.append(CGPoint(x: 0.0, y: CGFloat(y * phaseY))) 688| 50| } 689| 10| 690| 10| trans.pointValuesToPixel(&transformed) 691| 10| 692| 10| for k in 0 ..< transformed.count 693| 50| { 694| 50| let val = vals[k] 695| 50| let drawBelow = (val == 0.0 && negY == 0.0 && posY > 0.0) || val < 0.0 696| 50| let y = transformed[k].y + (drawBelow ? negOffset : posOffset) 697| 50| 698| 50| if !viewPortHandler.isInBoundsRight(x) 699| 50| { 700| 0| break 701| 50| } 702| 50| 703| 50| if !viewPortHandler.isInBoundsY(y) || !viewPortHandler.isInBoundsLeft(x) 704| 50| { 705| 0| continue 706| 50| } 707| 50| 708| 50| if dataSet.isDrawValuesEnabled 709| 50| { 710| 50| drawValue( 711| 50| context: context, 712| 50| value: formatter.stringForValue( 713| 50| vals[k], 714| 50| entry: e, 715| 50| dataSetIndex: dataSetIndex, 716| 50| viewPortHandler: viewPortHandler), 717| 50| xPos: x, 718| 50| yPos: y, 719| 50| font: valueFont, 720| 50| align: .center, 721| 50| color: dataSet.valueTextColorAt(index)) 722| 50| } 723| 50| 724| 50| if let icon = e.icon, dataSet.isDrawIconsEnabled 725| 50| { 726| 0| ChartUtils.drawImage( 727| 0| context: context, 728| 0| image: icon, 729| 0| x: x + iconsOffset.x, 730| 0| y: y + iconsOffset.y, 731| 0| size: icon.size) 732| 50| } 733| 50| } 734| 10| } 735| 10| 736| 10| bufferIndex = vals == nil ? (bufferIndex + 1) : (bufferIndex + vals!.count) 737| 10| } 738| 32| } 739| 34| } 740| 34| } 741| 34| } 742| | 743| | /// Draws a value at the specified x and y position. 744| | @objc open func drawValue(context: CGContext, value: String, xPos: CGFloat, yPos: CGFloat, font: NSUIFont, align: NSTextAlignment, color: NSUIColor) 745| 1.00k| { 746| 1.00k| ChartUtils.drawText(context: context, text: value, point: CGPoint(x: xPos, y: yPos), align: align, attributes: [NSAttributedString.Key.font: font, NSAttributedString.Key.foregroundColor: color]) 747| 1.00k| } 748| | 749| | open override func drawExtras(context: CGContext) 750| 40| { 751| 40| 752| 40| } 753| | 754| | open override func drawHighlighted(context: CGContext, indices: [Highlight]) 755| 0| { 756| 0| guard 757| 0| let dataProvider = dataProvider, 758| 0| let barData = dataProvider.barData 759| 0| else { return } 760| 0| 761| 0| context.saveGState() 762| 0| 763| 0| var barRect = CGRect() 764| 0| 765| 0| for high in indices 766| 0| { 767| 0| guard 768| 0| let set = barData.getDataSetByIndex(high.dataSetIndex) as? IBarChartDataSet, 769| 0| set.isHighlightEnabled 770| 0| else { continue } 771| 0| 772| 0| if let e = set.entryForXValue(high.x, closestToY: high.y) as? BarChartDataEntry 773| 0| { 774| 0| if !isInBoundsX(entry: e, dataSet: set) 775| 0| { 776| 0| continue 777| 0| } 778| 0| 779| 0| let trans = dataProvider.getTransformer(forAxis: set.axisDependency) 780| 0| 781| 0| context.setFillColor(set.highlightColor.cgColor) 782| 0| context.setAlpha(set.highlightAlpha) 783| 0| 784| 0| let isStack = high.stackIndex >= 0 && e.isStacked 785| 0| 786| 0| let y1: Double 787| 0| let y2: Double 788| 0| 789| 0| if isStack 790| 0| { 791| 0| if dataProvider.isHighlightFullBarEnabled 792| 0| { 793| 0| y1 = e.positiveSum 794| 0| y2 = -e.negativeSum 795| 0| } 796| 0| else 797| 0| { 798| 0| let range = e.ranges?[high.stackIndex] 799| 0| 800| 0| y1 = range?.from ?? 0.0 801| 0| y2 = range?.to ?? 0.0 802| 0| } 803| 0| } 804| 0| else 805| 0| { 806| 0| y1 = e.y 807| 0| y2 = 0.0 808| 0| } 809| 0| 810| 0| prepareBarHighlight(x: e.x, y1: y1, y2: y2, barWidthHalf: barData.barWidth / 2.0, trans: trans, rect: &barRect) 811| 0| 812| 0| setHighlightDrawPos(highlight: high, barRect: barRect) 813| 0| 814| 0| context.fill(barRect) 815| 0| } 816| 0| } 817| 0| 818| 0| context.restoreGState() 819| 0| } 820| | 821| | /// Sets the drawing position of the highlight object based on the given bar-rect. 822| | internal func setHighlightDrawPos(highlight high: Highlight, barRect: CGRect) 823| 0| { 824| 0| high.setDraw(x: barRect.midX, y: barRect.origin.y) 825| 0| } 826| | 827| | /// Creates a nested array of empty subarrays each of which will be populated with NSUIAccessibilityElements. 828| | /// This is marked internal to support HorizontalBarChartRenderer as well. 829| | internal func accessibilityCreateEmptyOrderedElements() -> [[NSUIAccessibilityElement]] 830| 40| { 831| 40| guard let chart = dataProvider as? BarChartView else { return [] } 832| 37| 833| 37| // Unlike Bubble & Line charts, here we use the maximum entry count to account for stacked bars 834| 37| let maxEntryCount = chart.data?.maxEntryCountSet?.entryCount ?? 0 835| 37| 836| 37| return Array(repeating: [NSUIAccessibilityElement](), 837| 37| count: maxEntryCount) 838| 40| } 839| | 840| | /// Creates an NSUIAccessibleElement representing the smallest meaningful bar of the chart 841| | /// i.e. in case of a stacked chart, this returns each stack, not the combined bar. 842| | /// Note that it is marked internal to support subclass modification in the HorizontalBarChart. 843| | internal func createAccessibleElement(withIndex idx: Int, 844| | container: BarChartView, 845| | dataSet: IBarChartDataSet, 846| | dataSetIndex: Int, 847| | stackSize: Int, 848| | modifier: (NSUIAccessibilityElement) -> ()) -> NSUIAccessibilityElement 849| 1.08k| { 850| 1.08k| let element = NSUIAccessibilityElement(accessibilityContainer: container) 851| 1.08k| let xAxis = container.xAxis 852| 1.08k| 853| 1.08k| guard let e = dataSet.entryForIndex(idx/stackSize) as? BarChartDataEntry else { return element } 854| 1.08k| guard let dataProvider = dataProvider else { return element } 855| 1.08k| 856| 1.08k| // NOTE: The formatter can cause issues when the x-axis labels are consecutive ints. 857| 1.08k| // i.e. due to the Double conversion, if there are more than one data set that are grouped, 858| 1.08k| // there is the possibility of some labels being rounded up. A floor() might fix this, but seems to be a brute force solution. 859| 1.08k| let label = xAxis.valueFormatter?.stringForValue(e.x, axis: xAxis) ?? "\(e.x)" 860| 1.08k| 861| 1.08k| var elementValueText = dataSet.valueFormatter?.stringForValue( 862| 1.08k| e.y, 863| 1.08k| entry: e, 864| 1.08k| dataSetIndex: dataSetIndex, 865| 1.08k| viewPortHandler: viewPortHandler) ?? "\(e.y)" 866| 1.08k| 867| 1.08k| if dataSet.isStacked, let vals = e.yValues 868| 1.08k| { 869| 150| let labelCount = min(dataSet.colors.count, stackSize) 870| 150| 871| 150| let stackLabel: String? 872| 150| if (dataSet.stackLabels.count > 0 && labelCount > 0) { 873| 0| let labelIndex = idx % labelCount 874| 0| stackLabel = dataSet.stackLabels.indices.contains(labelIndex) ? dataSet.stackLabels[labelIndex] : nil 875| 150| } else { 876| 150| stackLabel = nil 877| 150| } 878| 150| 879| 150| //Handles empty array of yValues 880| 150| let yValue = vals.isEmpty ? 0.0 : vals[idx % vals.count] 881| 150| 882| 150| elementValueText = dataSet.valueFormatter?.stringForValue( 883| 150| yValue, 884| 150| entry: e, 885| 150| dataSetIndex: dataSetIndex, 886| 150| viewPortHandler: viewPortHandler) ?? "\(e.y)" 887| 150| 888| 150| if let stackLabel = stackLabel { 889| 0| elementValueText = stackLabel + " \(elementValueText)" 890| 150| } else { 891| 150| elementValueText = "\(elementValueText)" 892| 150| } 893| 1.08k| } 894| 1.08k| 895| 1.08k| let dataSetCount = dataProvider.barData?.dataSetCount ?? -1 896| 1.08k| let doesContainMultipleDataSets = dataSetCount > 1 897| 1.08k| 898| 1.08k| element.accessibilityLabel = "\(doesContainMultipleDataSets ? (dataSet.label ?? "") + ", " : "") \(label): \(elementValueText)" 899| 1.08k| 900| 1.08k| modifier(element) 901| 1.08k| 902| 1.08k| return element 903| 1.08k| } 904| |} /Users/travis/build/danielgindi/Charts/Source/Charts/Renderers/BarLineScatterCandleBubbleRenderer.swift: 1| |// 2| |// BarLineScatterCandleBubbleRenderer.swift 3| |// Charts 4| |// 5| |// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda 6| |// A port of MPAndroidChart for iOS 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| | 12| |import Foundation 13| |import CoreGraphics 14| | 15| |@objc(BarLineScatterCandleBubbleChartRenderer) 16| |open class BarLineScatterCandleBubbleRenderer: DataRenderer 17| |{ 18| | internal var _xBounds = XBounds() // Reusable XBounds object 19| | 20| | public override init(animator: Animator, viewPortHandler: ViewPortHandler) 21| 55| { 22| 55| super.init(animator: animator, viewPortHandler: viewPortHandler) 23| 55| } 24| | 25| | /// Checks if the provided entry object is in bounds for drawing considering the current animation phase. 26| | internal func isInBoundsX(entry e: ChartDataEntry, dataSet: IBarLineScatterCandleBubbleChartDataSet) -> Bool 27| 0| { 28| 0| let entryIndex = dataSet.entryIndex(entry: e) 29| 0| return Double(entryIndex) < Double(dataSet.entryCount) * animator.phaseX 30| 0| } 31| | 32| | /// Calculates and returns the x-bounds for the given DataSet in terms of index in their values array. 33| | /// This includes minimum and maximum visible x, as well as range. 34| | internal func xBounds(chart: BarLineScatterCandleBubbleChartDataProvider, 35| | dataSet: IBarLineScatterCandleBubbleChartDataSet, 36| | animator: Animator?) -> XBounds 37| 0| { 38| 0| return XBounds(chart: chart, dataSet: dataSet, animator: animator) 39| 0| } 40| | 41| | /// - Returns: `true` if the DataSet values should be drawn, `false` if not. 42| | internal func shouldDrawValues(forDataSet set: IChartDataSet) -> Bool 43| 49| { 44| 49| return set.isVisible && (set.isDrawValuesEnabled || set.isDrawIconsEnabled) 45| 49| } 46| | 47| | /// Class representing the bounds of the current viewport in terms of indices in the values array of a DataSet. 48| | open class XBounds 49| | { 50| | /// minimum visible entry index 51| | open var min: Int = 0 52| | 53| | /// maximum visible entry index 54| | open var max: Int = 0 55| | 56| | /// range of visible entry indices 57| | open var range: Int = 0 58| | 59| | public init() 60| 55| { 61| 55| 62| 55| } 63| | 64| | public init(chart: BarLineScatterCandleBubbleChartDataProvider, 65| | dataSet: IBarLineScatterCandleBubbleChartDataSet, 66| | animator: Animator?) 67| 0| { 68| 0| self.set(chart: chart, dataSet: dataSet, animator: animator) 69| 0| } 70| | 71| | /// Calculates the minimum and maximum x values as well as the range between them. 72| | open func set(chart: BarLineScatterCandleBubbleChartDataProvider, 73| | dataSet: IBarLineScatterCandleBubbleChartDataSet, 74| | animator: Animator?) 75| 26| { 76| 26| let phaseX = Swift.max(0.0, Swift.min(1.0, animator?.phaseX ?? 1.0)) 77| 26| 78| 26| let low = chart.lowestVisibleX 79| 26| let high = chart.highestVisibleX 80| 26| 81| 26| let entryFrom = dataSet.entryForXValue(low, closestToY: .nan, rounding: .down) 82| 26| let entryTo = dataSet.entryForXValue(high, closestToY: .nan, rounding: .up) 83| 26| 84| 26| self.min = entryFrom == nil ? 0 : dataSet.entryIndex(entry: entryFrom!) 85| 26| self.max = entryTo == nil ? 0 : dataSet.entryIndex(entry: entryTo!) 86| 26| range = Int(Double(self.max - self.min) * phaseX) 87| 26| } 88| | } 89| |} 90| | 91| |extension BarLineScatterCandleBubbleRenderer.XBounds: RangeExpression { 92| | public func relative(to collection: C) -> Swift.Range 93| | where C : Collection, Bound == C.Index 94| 0| { 95| 0| return Swift.Range(min...min + range) 96| 0| } 97| | 98| 0| public func contains(_ element: Int) -> Bool { 99| 0| return (min...min + range).contains(element) 100| 0| } 101| |} 102| | 103| |extension BarLineScatterCandleBubbleRenderer.XBounds: Sequence { 104| | public struct Iterator: IteratorProtocol { 105| | private var iterator: IndexingIterator> 106| | 107| 26| fileprivate init(min: Int, max: Int) { 108| 26| self.iterator = (min...max).makeIterator() 109| 26| } 110| | 111| 806| public mutating func next() -> Int? { 112| 806| return self.iterator.next() 113| 806| } 114| | } 115| | 116| 26| public func makeIterator() -> Iterator { 117| 26| return Iterator(min: self.min, max: self.min + self.range) 118| 26| } 119| |} 120| | 121| |extension BarLineScatterCandleBubbleRenderer.XBounds: CustomDebugStringConvertible 122| |{ 123| | public var debugDescription: String 124| 0| { 125| 0| return "min:\(self.min), max:\(self.max), range:\(self.range)" 126| 0| } 127| |} /Users/travis/build/danielgindi/Charts/Source/Charts/Renderers/BubbleChartRenderer.swift: 1| |// 2| |// BubbleChartRenderer.swift 3| |// Charts 4| |// 5| |// Bubble chart implementation: 6| |// Copyright 2015 Pierre-Marc Airoldi 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| | 12| |import Foundation 13| |import CoreGraphics 14| | 15| |open class BubbleChartRenderer: BarLineScatterCandleBubbleRenderer 16| |{ 17| | /// A nested array of elements ordered logically (i.e not in visual/drawing order) for use with VoiceOver. 18| | private lazy var accessibilityOrderedElements: [[NSUIAccessibilityElement]] = accessibilityCreateEmptyOrderedElements() 19| | 20| | @objc open weak var dataProvider: BubbleChartDataProvider? 21| | 22| | @objc public init(dataProvider: BubbleChartDataProvider, animator: Animator, viewPortHandler: ViewPortHandler) 23| 0| { 24| 0| super.init(animator: animator, viewPortHandler: viewPortHandler) 25| 0| 26| 0| self.dataProvider = dataProvider 27| 0| } 28| | 29| | open override func drawData(context: CGContext) 30| 0| { 31| 0| guard 32| 0| let dataProvider = dataProvider, 33| 0| let bubbleData = dataProvider.bubbleData 34| 0| else { return } 35| 0| 36| 0| // If we redraw the data, remove and repopulate accessible elements to update label values and frames 37| 0| accessibleChartElements.removeAll() 38| 0| accessibilityOrderedElements = accessibilityCreateEmptyOrderedElements() 39| 0| 40| 0| // Make the chart header the first element in the accessible elements array 41| 0| if let chart = dataProvider as? BubbleChartView { 42| 0| let element = createAccessibleHeader(usingChart: chart, 43| 0| andData: bubbleData, 44| 0| withDefaultDescription: "Bubble Chart") 45| 0| accessibleChartElements.append(element) 46| 0| } 47| 0| 48| 0| for (i, set) in (bubbleData.dataSets as! [IBubbleChartDataSet]).enumerated() where set.isVisible 49| 0| { 50| 0| drawDataSet(context: context, dataSet: set, dataSetIndex: i) 51| 0| } 52| 0| 53| 0| // Merge nested ordered arrays into the single accessibleChartElements. 54| 0| accessibleChartElements.append(contentsOf: accessibilityOrderedElements.flatMap { $0 } ) 55| 0| accessibilityPostLayoutChangedNotification() 56| 0| } 57| | 58| | private func getShapeSize( 59| | entrySize: CGFloat, 60| | maxSize: CGFloat, 61| | reference: CGFloat, 62| | normalizeSize: Bool) -> CGFloat 63| 0| { 64| 0| let factor: CGFloat = normalizeSize 65| 0| ? ((maxSize == 0.0) ? 1.0 : sqrt(entrySize / maxSize)) 66| 0| : entrySize 67| 0| let shapeSize: CGFloat = reference * factor 68| 0| return shapeSize 69| 0| } 70| | 71| | private var _pointBuffer = CGPoint() 72| | private var _sizeBuffer = [CGPoint](repeating: CGPoint(), count: 2) 73| | 74| | @objc open func drawDataSet(context: CGContext, dataSet: IBubbleChartDataSet, dataSetIndex: Int) 75| 0| { 76| 0| guard let dataProvider = dataProvider else { return } 77| 0| 78| 0| let trans = dataProvider.getTransformer(forAxis: dataSet.axisDependency) 79| 0| 80| 0| let phaseY = animator.phaseY 81| 0| 82| 0| _xBounds.set(chart: dataProvider, dataSet: dataSet, animator: animator) 83| 0| 84| 0| let valueToPixelMatrix = trans.valueToPixelMatrix 85| 0| 86| 0| _sizeBuffer[0].x = 0.0 87| 0| _sizeBuffer[0].y = 0.0 88| 0| _sizeBuffer[1].x = 1.0 89| 0| _sizeBuffer[1].y = 0.0 90| 0| 91| 0| trans.pointValuesToPixel(&_sizeBuffer) 92| 0| 93| 0| context.saveGState() 94| 0| defer { context.restoreGState() } 95| 0| 96| 0| let normalizeSize = dataSet.isNormalizeSizeEnabled 97| 0| 98| 0| // calcualte the full width of 1 step on the x-axis 99| 0| let maxBubbleWidth: CGFloat = abs(_sizeBuffer[1].x - _sizeBuffer[0].x) 100| 0| let maxBubbleHeight: CGFloat = abs(viewPortHandler.contentBottom - viewPortHandler.contentTop) 101| 0| let referenceSize: CGFloat = min(maxBubbleHeight, maxBubbleWidth) 102| 0| 103| 0| for j in _xBounds 104| 0| { 105| 0| guard let entry = dataSet.entryForIndex(j) as? BubbleChartDataEntry else { continue } 106| 0| 107| 0| _pointBuffer.x = CGFloat(entry.x) 108| 0| _pointBuffer.y = CGFloat(entry.y * phaseY) 109| 0| _pointBuffer = _pointBuffer.applying(valueToPixelMatrix) 110| 0| 111| 0| let shapeSize = getShapeSize(entrySize: entry.size, maxSize: dataSet.maxSize, reference: referenceSize, normalizeSize: normalizeSize) 112| 0| let shapeHalf = shapeSize / 2.0 113| 0| 114| 0| guard 115| 0| viewPortHandler.isInBoundsTop(_pointBuffer.y + shapeHalf), 116| 0| viewPortHandler.isInBoundsBottom(_pointBuffer.y - shapeHalf), 117| 0| viewPortHandler.isInBoundsLeft(_pointBuffer.x + shapeHalf) 118| 0| else { continue } 119| 0| 120| 0| guard viewPortHandler.isInBoundsRight(_pointBuffer.x - shapeHalf) else { break } 121| 0| 122| 0| let color = dataSet.color(atIndex: j) 123| 0| 124| 0| let rect = CGRect( 125| 0| x: _pointBuffer.x - shapeHalf, 126| 0| y: _pointBuffer.y - shapeHalf, 127| 0| width: shapeSize, 128| 0| height: shapeSize 129| 0| ) 130| 0| 131| 0| context.setFillColor(color.cgColor) 132| 0| context.fillEllipse(in: rect) 133| 0| 134| 0| // Create and append the corresponding accessibility element to accessibilityOrderedElements 135| 0| if let chart = dataProvider as? BubbleChartView 136| 0| { 137| 0| let element = createAccessibleElement(withIndex: j, 138| 0| container: chart, 139| 0| dataSet: dataSet, 140| 0| dataSetIndex: dataSetIndex, 141| 0| shapeSize: shapeSize) 142| 0| { (element) in 143| 0| element.accessibilityFrame = rect 144| 0| } 145| 0| 146| 0| accessibilityOrderedElements[dataSetIndex].append(element) 147| 0| } 148| 0| } 149| 0| } 150| | 151| | open override func drawValues(context: CGContext) 152| 0| { 153| 0| guard let 154| 0| dataProvider = dataProvider, 155| 0| let bubbleData = dataProvider.bubbleData, 156| 0| isDrawingValuesAllowed(dataProvider: dataProvider), 157| 0| let dataSets = bubbleData.dataSets as? [IBubbleChartDataSet] 158| 0| else { return } 159| 0| 160| 0| let phaseX = max(0.0, min(1.0, animator.phaseX)) 161| 0| let phaseY = animator.phaseY 162| 0| 163| 0| var pt = CGPoint() 164| 0| 165| 0| for i in 0.. [[NSUIAccessibilityElement]] 317| 0| { 318| 0| guard let chart = dataProvider as? BubbleChartView else { return [] } 319| 0| 320| 0| let dataSetCount = chart.bubbleData?.dataSetCount ?? 0 321| 0| 322| 0| return Array(repeating: [NSUIAccessibilityElement](), 323| 0| count: dataSetCount) 324| 0| } 325| | 326| | /// Creates an NSUIAccessibleElement representing individual bubbles location and relative size. 327| | private func createAccessibleElement(withIndex idx: Int, 328| | container: BubbleChartView, 329| | dataSet: IBubbleChartDataSet, 330| | dataSetIndex: Int, 331| | shapeSize: CGFloat, 332| | modifier: (NSUIAccessibilityElement) -> ()) -> NSUIAccessibilityElement 333| 0| { 334| 0| let element = NSUIAccessibilityElement(accessibilityContainer: container) 335| 0| let xAxis = container.xAxis 336| 0| 337| 0| guard let e = dataSet.entryForIndex(idx) else { return element } 338| 0| guard let dataProvider = dataProvider else { return element } 339| 0| 340| 0| // NOTE: The formatter can cause issues when the x-axis labels are consecutive ints. 341| 0| // i.e. due to the Double conversion, if there are more than one data set that are grouped, 342| 0| // there is the possibility of some labels being rounded up. A floor() might fix this, but seems to be a brute force solution. 343| 0| let label = xAxis.valueFormatter?.stringForValue(e.x, axis: xAxis) ?? "\(e.x)" 344| 0| 345| 0| let elementValueText = dataSet.valueFormatter?.stringForValue(e.y, 346| 0| entry: e, 347| 0| dataSetIndex: dataSetIndex, 348| 0| viewPortHandler: viewPortHandler) ?? "\(e.y)" 349| 0| 350| 0| let dataSetCount = dataProvider.bubbleData?.dataSetCount ?? -1 351| 0| let doesContainMultipleDataSets = dataSetCount > 1 352| 0| 353| 0| element.accessibilityLabel = "\(doesContainMultipleDataSets ? (dataSet.label ?? "") + ", " : "") \(label): \(elementValueText), bubble size: \(String(format: "%.2f", (shapeSize/dataSet.maxSize) * 100)) %" 354| 0| 355| 0| modifier(element) 356| 0| 357| 0| return element 358| 0| } 359| |} /Users/travis/build/danielgindi/Charts/Source/Charts/Renderers/CandleStickChartRenderer.swift: 1| |// 2| |// CandleStickChartRenderer.swift 3| |// Charts 4| |// 5| |// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda 6| |// A port of MPAndroidChart for iOS 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| | 12| |import Foundation 13| |import CoreGraphics 14| | 15| |open class CandleStickChartRenderer: LineScatterCandleRadarRenderer 16| |{ 17| | @objc open weak var dataProvider: CandleChartDataProvider? 18| | 19| | @objc public init(dataProvider: CandleChartDataProvider, animator: Animator, viewPortHandler: ViewPortHandler) 20| 0| { 21| 0| super.init(animator: animator, viewPortHandler: viewPortHandler) 22| 0| 23| 0| self.dataProvider = dataProvider 24| 0| } 25| | 26| | open override func drawData(context: CGContext) 27| 0| { 28| 0| guard let dataProvider = dataProvider, let candleData = dataProvider.candleData else { return } 29| 0| 30| 0| // If we redraw the data, remove and repopulate accessible elements to update label values and frames 31| 0| accessibleChartElements.removeAll() 32| 0| 33| 0| // Make the chart header the first element in the accessible elements array 34| 0| if let chart = dataProvider as? CandleStickChartView { 35| 0| let element = createAccessibleHeader(usingChart: chart, 36| 0| andData: candleData, 37| 0| withDefaultDescription: "CandleStick Chart") 38| 0| accessibleChartElements.append(element) 39| 0| } 40| 0| 41| 0| for set in candleData.dataSets as! [ICandleChartDataSet] where set.isVisible 42| 0| { 43| 0| drawDataSet(context: context, dataSet: set) 44| 0| } 45| 0| } 46| | 47| | private var _shadowPoints = [CGPoint](repeating: CGPoint(), count: 4) 48| | private var _rangePoints = [CGPoint](repeating: CGPoint(), count: 2) 49| | private var _openPoints = [CGPoint](repeating: CGPoint(), count: 2) 50| | private var _closePoints = [CGPoint](repeating: CGPoint(), count: 2) 51| | private var _bodyRect = CGRect() 52| | private var _lineSegments = [CGPoint](repeating: CGPoint(), count: 2) 53| | 54| | @objc open func drawDataSet(context: CGContext, dataSet: ICandleChartDataSet) 55| 0| { 56| 0| guard 57| 0| let dataProvider = dataProvider 58| 0| else { return } 59| 0| 60| 0| let trans = dataProvider.getTransformer(forAxis: dataSet.axisDependency) 61| 0| 62| 0| let phaseY = animator.phaseY 63| 0| let barSpace = dataSet.barSpace 64| 0| let showCandleBar = dataSet.showCandleBar 65| 0| 66| 0| _xBounds.set(chart: dataProvider, dataSet: dataSet, animator: animator) 67| 0| 68| 0| context.saveGState() 69| 0| 70| 0| context.setLineWidth(dataSet.shadowWidth) 71| 0| 72| 0| for j in _xBounds 73| 0| { 74| 0| // get the entry 75| 0| guard let e = dataSet.entryForIndex(j) as? CandleChartDataEntry else { continue } 76| 0| 77| 0| let xPos = e.x 78| 0| 79| 0| let open = e.open 80| 0| let close = e.close 81| 0| let high = e.high 82| 0| let low = e.low 83| 0| 84| 0| let doesContainMultipleDataSets = (dataProvider.candleData?.dataSets.count ?? 1) > 1 85| 0| var accessibilityMovementDescription = "neutral" 86| 0| var accessibilityRect = CGRect(x: CGFloat(xPos) + 0.5 - barSpace, 87| 0| y: CGFloat(low * phaseY), 88| 0| width: (2 * barSpace) - 1.0, 89| 0| height: (CGFloat(abs(high - low) * phaseY))) 90| 0| trans.rectValueToPixel(&accessibilityRect) 91| 0| 92| 0| if showCandleBar 93| 0| { 94| 0| // calculate the shadow 95| 0| 96| 0| _shadowPoints[0].x = CGFloat(xPos) 97| 0| _shadowPoints[1].x = CGFloat(xPos) 98| 0| _shadowPoints[2].x = CGFloat(xPos) 99| 0| _shadowPoints[3].x = CGFloat(xPos) 100| 0| 101| 0| if open > close 102| 0| { 103| 0| _shadowPoints[0].y = CGFloat(high * phaseY) 104| 0| _shadowPoints[1].y = CGFloat(open * phaseY) 105| 0| _shadowPoints[2].y = CGFloat(low * phaseY) 106| 0| _shadowPoints[3].y = CGFloat(close * phaseY) 107| 0| } 108| 0| else if open < close 109| 0| { 110| 0| _shadowPoints[0].y = CGFloat(high * phaseY) 111| 0| _shadowPoints[1].y = CGFloat(close * phaseY) 112| 0| _shadowPoints[2].y = CGFloat(low * phaseY) 113| 0| _shadowPoints[3].y = CGFloat(open * phaseY) 114| 0| } 115| 0| else 116| 0| { 117| 0| _shadowPoints[0].y = CGFloat(high * phaseY) 118| 0| _shadowPoints[1].y = CGFloat(open * phaseY) 119| 0| _shadowPoints[2].y = CGFloat(low * phaseY) 120| 0| _shadowPoints[3].y = _shadowPoints[1].y 121| 0| } 122| 0| 123| 0| trans.pointValuesToPixel(&_shadowPoints) 124| 0| 125| 0| // draw the shadows 126| 0| 127| 0| var shadowColor: NSUIColor! = nil 128| 0| if dataSet.shadowColorSameAsCandle 129| 0| { 130| 0| if open > close 131| 0| { 132| 0| shadowColor = dataSet.decreasingColor ?? dataSet.color(atIndex: j) 133| 0| } 134| 0| else if open < close 135| 0| { 136| 0| shadowColor = dataSet.increasingColor ?? dataSet.color(atIndex: j) 137| 0| } 138| 0| else 139| 0| { 140| 0| shadowColor = dataSet.neutralColor ?? dataSet.color(atIndex: j) 141| 0| } 142| 0| } 143| 0| 144| 0| if shadowColor === nil 145| 0| { 146| 0| shadowColor = dataSet.shadowColor ?? dataSet.color(atIndex: j) 147| 0| } 148| 0| 149| 0| context.setStrokeColor(shadowColor.cgColor) 150| 0| context.strokeLineSegments(between: _shadowPoints) 151| 0| 152| 0| // calculate the body 153| 0| 154| 0| _bodyRect.origin.x = CGFloat(xPos) - 0.5 + barSpace 155| 0| _bodyRect.origin.y = CGFloat(close * phaseY) 156| 0| _bodyRect.size.width = (CGFloat(xPos) + 0.5 - barSpace) - _bodyRect.origin.x 157| 0| _bodyRect.size.height = CGFloat(open * phaseY) - _bodyRect.origin.y 158| 0| 159| 0| trans.rectValueToPixel(&_bodyRect) 160| 0| 161| 0| // draw body differently for increasing and decreasing entry 162| 0| 163| 0| if open > close 164| 0| { 165| 0| accessibilityMovementDescription = "decreasing" 166| 0| 167| 0| let color = dataSet.decreasingColor ?? dataSet.color(atIndex: j) 168| 0| 169| 0| if dataSet.isDecreasingFilled 170| 0| { 171| 0| context.setFillColor(color.cgColor) 172| 0| context.fill(_bodyRect) 173| 0| } 174| 0| else 175| 0| { 176| 0| context.setStrokeColor(color.cgColor) 177| 0| context.stroke(_bodyRect) 178| 0| } 179| 0| } 180| 0| else if open < close 181| 0| { 182| 0| accessibilityMovementDescription = "increasing" 183| 0| 184| 0| let color = dataSet.increasingColor ?? dataSet.color(atIndex: j) 185| 0| 186| 0| if dataSet.isIncreasingFilled 187| 0| { 188| 0| context.setFillColor(color.cgColor) 189| 0| context.fill(_bodyRect) 190| 0| } 191| 0| else 192| 0| { 193| 0| context.setStrokeColor(color.cgColor) 194| 0| context.stroke(_bodyRect) 195| 0| } 196| 0| } 197| 0| else 198| 0| { 199| 0| let color = dataSet.neutralColor ?? dataSet.color(atIndex: j) 200| 0| 201| 0| context.setStrokeColor(color.cgColor) 202| 0| context.stroke(_bodyRect) 203| 0| } 204| 0| } 205| 0| else 206| 0| { 207| 0| _rangePoints[0].x = CGFloat(xPos) 208| 0| _rangePoints[0].y = CGFloat(high * phaseY) 209| 0| _rangePoints[1].x = CGFloat(xPos) 210| 0| _rangePoints[1].y = CGFloat(low * phaseY) 211| 0| 212| 0| _openPoints[0].x = CGFloat(xPos) - 0.5 + barSpace 213| 0| _openPoints[0].y = CGFloat(open * phaseY) 214| 0| _openPoints[1].x = CGFloat(xPos) 215| 0| _openPoints[1].y = CGFloat(open * phaseY) 216| 0| 217| 0| _closePoints[0].x = CGFloat(xPos) + 0.5 - barSpace 218| 0| _closePoints[0].y = CGFloat(close * phaseY) 219| 0| _closePoints[1].x = CGFloat(xPos) 220| 0| _closePoints[1].y = CGFloat(close * phaseY) 221| 0| 222| 0| trans.pointValuesToPixel(&_rangePoints) 223| 0| trans.pointValuesToPixel(&_openPoints) 224| 0| trans.pointValuesToPixel(&_closePoints) 225| 0| 226| 0| // draw the ranges 227| 0| var barColor: NSUIColor! = nil 228| 0| 229| 0| if open > close 230| 0| { 231| 0| accessibilityMovementDescription = "decreasing" 232| 0| barColor = dataSet.decreasingColor ?? dataSet.color(atIndex: j) 233| 0| } 234| 0| else if open < close 235| 0| { 236| 0| accessibilityMovementDescription = "increasing" 237| 0| barColor = dataSet.increasingColor ?? dataSet.color(atIndex: j) 238| 0| } 239| 0| else 240| 0| { 241| 0| barColor = dataSet.neutralColor ?? dataSet.color(atIndex: j) 242| 0| } 243| 0| 244| 0| context.setStrokeColor(barColor.cgColor) 245| 0| context.strokeLineSegments(between: _rangePoints) 246| 0| context.strokeLineSegments(between: _openPoints) 247| 0| context.strokeLineSegments(between: _closePoints) 248| 0| } 249| 0| 250| 0| let axElement = createAccessibleElement(withIndex: j, 251| 0| container: dataProvider, 252| 0| dataSet: dataSet) 253| 0| { (element) in 254| 0| element.accessibilityLabel = "\(doesContainMultipleDataSets ? "\(dataSet.label ?? "Dataset")" : "") " + "\(xPos) - \(accessibilityMovementDescription). low: \(low), high: \(high), opening: \(open), closing: \(close)" 255| 0| element.accessibilityFrame = accessibilityRect 256| 0| } 257| 0| 258| 0| accessibleChartElements.append(axElement) 259| 0| 260| 0| } 261| 0| 262| 0| // Post this notification to let VoiceOver account for the redrawn frames 263| 0| accessibilityPostLayoutChangedNotification() 264| 0| 265| 0| context.restoreGState() 266| 0| } 267| | 268| | open override func drawValues(context: CGContext) 269| 0| { 270| 0| guard 271| 0| let dataProvider = dataProvider, 272| 0| let candleData = dataProvider.candleData 273| 0| else { return } 274| 0| 275| 0| // if values are drawn 276| 0| if isDrawingValuesAllowed(dataProvider: dataProvider) 277| 0| { 278| 0| let dataSets = candleData.dataSets 279| 0| 280| 0| let phaseY = animator.phaseY 281| 0| 282| 0| var pt = CGPoint() 283| 0| 284| 0| for i in 0 ..< dataSets.count 285| 0| { 286| 0| guard let 287| 0| dataSet = dataSets[i] as? IBarLineScatterCandleBubbleChartDataSet, 288| 0| shouldDrawValues(forDataSet: dataSet) 289| 0| else { continue } 290| 0| 291| 0| let valueFont = dataSet.valueFont 292| 0| 293| 0| guard let formatter = dataSet.valueFormatter else { continue } 294| 0| 295| 0| let trans = dataProvider.getTransformer(forAxis: dataSet.axisDependency) 296| 0| let valueToPixelMatrix = trans.valueToPixelMatrix 297| 0| 298| 0| let iconsOffset = dataSet.iconsOffset 299| 0| 300| 0| _xBounds.set(chart: dataProvider, dataSet: dataSet, animator: animator) 301| 0| 302| 0| let lineHeight = valueFont.lineHeight 303| 0| let yOffset: CGFloat = lineHeight + 5.0 304| 0| 305| 0| for j in _xBounds 306| 0| { 307| 0| guard let e = dataSet.entryForIndex(j) as? CandleChartDataEntry else { break } 308| 0| 309| 0| pt.x = CGFloat(e.x) 310| 0| pt.y = CGFloat(e.high * phaseY) 311| 0| pt = pt.applying(valueToPixelMatrix) 312| 0| 313| 0| if (!viewPortHandler.isInBoundsRight(pt.x)) 314| 0| { 315| 0| break 316| 0| } 317| 0| 318| 0| if (!viewPortHandler.isInBoundsLeft(pt.x) || !viewPortHandler.isInBoundsY(pt.y)) 319| 0| { 320| 0| continue 321| 0| } 322| 0| 323| 0| if dataSet.isDrawValuesEnabled 324| 0| { 325| 0| ChartUtils.drawText( 326| 0| context: context, 327| 0| text: formatter.stringForValue( 328| 0| e.high, 329| 0| entry: e, 330| 0| dataSetIndex: i, 331| 0| viewPortHandler: viewPortHandler), 332| 0| point: CGPoint( 333| 0| x: pt.x, 334| 0| y: pt.y - yOffset), 335| 0| align: .center, 336| 0| attributes: [NSAttributedString.Key.font: valueFont, NSAttributedString.Key.foregroundColor: dataSet.valueTextColorAt(j)]) 337| 0| } 338| 0| 339| 0| if let icon = e.icon, dataSet.isDrawIconsEnabled 340| 0| { 341| 0| ChartUtils.drawImage(context: context, 342| 0| image: icon, 343| 0| x: pt.x + iconsOffset.x, 344| 0| y: pt.y + iconsOffset.y, 345| 0| size: icon.size) 346| 0| } 347| 0| } 348| 0| } 349| 0| } 350| 0| } 351| | 352| | open override func drawExtras(context: CGContext) 353| 0| { 354| 0| } 355| | 356| | open override func drawHighlighted(context: CGContext, indices: [Highlight]) 357| 0| { 358| 0| guard 359| 0| let dataProvider = dataProvider, 360| 0| let candleData = dataProvider.candleData 361| 0| else { return } 362| 0| 363| 0| context.saveGState() 364| 0| 365| 0| for high in indices 366| 0| { 367| 0| guard 368| 0| let set = candleData.getDataSetByIndex(high.dataSetIndex) as? ICandleChartDataSet, 369| 0| set.isHighlightEnabled 370| 0| else { continue } 371| 0| 372| 0| guard let e = set.entryForXValue(high.x, closestToY: high.y) as? CandleChartDataEntry else { continue } 373| 0| 374| 0| if !isInBoundsX(entry: e, dataSet: set) 375| 0| { 376| 0| continue 377| 0| } 378| 0| 379| 0| let trans = dataProvider.getTransformer(forAxis: set.axisDependency) 380| 0| 381| 0| context.setStrokeColor(set.highlightColor.cgColor) 382| 0| context.setLineWidth(set.highlightLineWidth) 383| 0| 384| 0| if set.highlightLineDashLengths != nil 385| 0| { 386| 0| context.setLineDash(phase: set.highlightLineDashPhase, lengths: set.highlightLineDashLengths!) 387| 0| } 388| 0| else 389| 0| { 390| 0| context.setLineDash(phase: 0.0, lengths: []) 391| 0| } 392| 0| 393| 0| let lowValue = e.low * Double(animator.phaseY) 394| 0| let highValue = e.high * Double(animator.phaseY) 395| 0| let y = (lowValue + highValue) / 2.0 396| 0| 397| 0| let pt = trans.pixelForValues(x: e.x, y: y) 398| 0| 399| 0| high.setDraw(pt: pt) 400| 0| 401| 0| // draw the lines 402| 0| drawHighlightLines(context: context, point: pt, set: set) 403| 0| } 404| 0| 405| 0| context.restoreGState() 406| 0| } 407| | 408| | private func createAccessibleElement(withIndex idx: Int, 409| | container: CandleChartDataProvider, 410| | dataSet: ICandleChartDataSet, 411| 0| modifier: (NSUIAccessibilityElement) -> ()) -> NSUIAccessibilityElement { 412| 0| 413| 0| let element = NSUIAccessibilityElement(accessibilityContainer: container) 414| 0| 415| 0| // The modifier allows changing of traits and frame depending on highlight, rotation, etc 416| 0| modifier(element) 417| 0| 418| 0| return element 419| 0| } 420| |} /Users/travis/build/danielgindi/Charts/Source/Charts/Renderers/ChartDataRendererBase.swift: 1| |// 2| |// DataRenderer.swift 3| |// Charts 4| |// 5| |// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda 6| |// A port of MPAndroidChart for iOS 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| | 12| |import Foundation 13| |import CoreGraphics 14| | 15| |#if canImport(UIKit) 16| | import UIKit 17| |#endif 18| | 19| |#if canImport(Cocoa) 20| |import Cocoa 21| |#endif 22| | 23| |@objc(ChartDataRendererBase) 24| |open class DataRenderer: Renderer 25| |{ 26| | /// An array of accessibility elements that are presented to the ChartViewBase accessibility methods. 27| | /// 28| | /// Note that the order of elements in this array determines the order in which they are presented and navigated by 29| | /// Accessibility clients such as VoiceOver. 30| | /// 31| | /// Renderers should ensure that the order of elements makes sense to a client presenting an audio-only interface to a user. 32| | /// Subclasses should populate this array in drawData() or drawDataSet() to make the chart accessible. 33| | @objc final var accessibleChartElements: [NSUIAccessibilityElement] = [] 34| | 35| | @objc public let animator: Animator 36| | 37| | @objc public init(animator: Animator, viewPortHandler: ViewPortHandler) 38| 64| { 39| 64| self.animator = animator 40| 64| 41| 64| super.init(viewPortHandler: viewPortHandler) 42| 64| } 43| | 44| | @objc open func drawData(context: CGContext) 45| 0| { 46| 0| fatalError("drawData() cannot be called on DataRenderer") 47| 0| } 48| | 49| | @objc open func drawValues(context: CGContext) 50| 0| { 51| 0| fatalError("drawValues() cannot be called on DataRenderer") 52| 0| } 53| | 54| | @objc open func drawExtras(context: CGContext) 55| 0| { 56| 0| fatalError("drawExtras() cannot be called on DataRenderer") 57| 0| } 58| | 59| | /// Draws all highlight indicators for the values that are currently highlighted. 60| | /// 61| | /// - Parameters: 62| | /// - indices: the highlighted values 63| | @objc open func drawHighlighted(context: CGContext, indices: [Highlight]) 64| 0| { 65| 0| fatalError("drawHighlighted() cannot be called on DataRenderer") 66| 0| } 67| | 68| | /// An opportunity for initializing internal buffers used for rendering with a new size. 69| | /// Since this might do memory allocations, it should only be called if necessary. 70| 11| @objc open func initBuffers() { } 71| | 72| | @objc open func isDrawingValuesAllowed(dataProvider: ChartDataProvider?) -> Bool 73| 43| { 74| 43| guard let data = dataProvider?.data else { return false } 75| 43| return data.entryCount < Int(CGFloat(dataProvider?.maxVisibleCount ?? 0) * viewPortHandler.scaleX) 76| 43| } 77| | 78| | /// Creates an ```NSUIAccessibilityElement``` that acts as the first and primary header describing a chart view. 79| | /// 80| | /// - Parameters: 81| | /// - chart: The chartView object being described 82| | /// - data: A non optional data source about the chart 83| | /// - defaultDescription: A simple string describing the type/design of Chart. 84| | /// - Returns: A header ```NSUIAccessibilityElement``` that can be added to accessibleChartElements. 85| | @objc internal func createAccessibleHeader(usingChart chart: ChartViewBase, 86| | andData data: ChartData, 87| | withDefaultDescription defaultDescription: String = "Chart") -> NSUIAccessibilityElement 88| 46| { 89| 46| let chartDescriptionText = chart.chartDescription?.text ?? defaultDescription 90| 49| let dataSetDescriptions = data.dataSets.map { $0.label ?? "" } 91| 46| let dataSetDescriptionText = dataSetDescriptions.joined(separator: ", ") 92| 46| let dataSetCount = data.dataSets.count 93| 46| 94| 46| let 95| 46| element = NSUIAccessibilityElement(accessibilityContainer: chart) 96| 46| element.accessibilityLabel = chartDescriptionText + ". \(dataSetCount) dataset\(dataSetCount == 1 ? "" : "s"). \(dataSetDescriptionText)" 97| 46| element.accessibilityFrame = chart.bounds 98| 46| element.isHeader = true 99| 46| 100| 46| return element 101| 46| } 102| |} /Users/travis/build/danielgindi/Charts/Source/Charts/Renderers/CombinedChartRenderer.swift: 1| |// 2| |// CombinedChartRenderer.swift 3| |// Charts 4| |// 5| |// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda 6| |// A port of MPAndroidChart for iOS 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| | 12| |import Foundation 13| |import CoreGraphics 14| | 15| |open class CombinedChartRenderer: DataRenderer 16| |{ 17| | @objc open weak var chart: CombinedChartView? 18| | 19| | /// if set to true, all values are drawn above their bars, instead of below their top 20| | @objc open var drawValueAboveBarEnabled = true 21| | 22| | /// if set to true, a grey area is drawn behind each bar that indicates the maximum value 23| | @objc open var drawBarShadowEnabled = false 24| | 25| | internal var _renderers = [DataRenderer]() 26| | 27| | internal var _drawOrder: [CombinedChartView.DrawOrder] = [.bar, .bubble, .line, .candle, .scatter] 28| | 29| | @objc public init(chart: CombinedChartView, animator: Animator, viewPortHandler: ViewPortHandler) 30| 3| { 31| 3| super.init(animator: animator, viewPortHandler: viewPortHandler) 32| 3| 33| 3| self.chart = chart 34| 3| 35| 3| createRenderers() 36| 3| } 37| | 38| | /// Creates the renderers needed for this combined-renderer in the required order. Also takes the DrawOrder into consideration. 39| | internal func createRenderers() 40| 6| { 41| 6| _renderers = [DataRenderer]() 42| 6| 43| 6| guard let chart = chart else { return } 44| 6| 45| 6| for order in drawOrder 46| 30| { 47| 30| switch (order) 48| 30| { 49| 30| case .bar: 50| 6| if chart.barData !== nil 51| 6| { 52| 3| _renderers.append(BarChartRenderer(dataProvider: chart, animator: animator, viewPortHandler: viewPortHandler)) 53| 6| } 54| 6| break 55| 30| 56| 30| case .line: 57| 6| if chart.lineData !== nil 58| 6| { 59| 3| _renderers.append(LineChartRenderer(dataProvider: chart, animator: animator, viewPortHandler: viewPortHandler)) 60| 6| } 61| 6| break 62| 30| 63| 30| case .candle: 64| 6| if chart.candleData !== nil 65| 6| { 66| 0| _renderers.append(CandleStickChartRenderer(dataProvider: chart, animator: animator, viewPortHandler: viewPortHandler)) 67| 6| } 68| 6| break 69| 30| 70| 30| case .scatter: 71| 6| if chart.scatterData !== nil 72| 6| { 73| 0| _renderers.append(ScatterChartRenderer(dataProvider: chart, animator: animator, viewPortHandler: viewPortHandler)) 74| 6| } 75| 6| break 76| 30| 77| 30| case .bubble: 78| 6| if chart.bubbleData !== nil 79| 6| { 80| 0| _renderers.append(BubbleChartRenderer(dataProvider: chart, animator: animator, viewPortHandler: viewPortHandler)) 81| 6| } 82| 6| break 83| 30| } 84| 30| } 85| 6| 86| 6| } 87| | 88| | open override func initBuffers() 89| 8| { 90| 10| _renderers.forEach { $0.initBuffers() } 91| 8| } 92| | 93| | open override func drawData(context: CGContext) 94| 3| { 95| 3| // If we redraw the data, remove and repopulate accessible elements to update label values and frames 96| 3| accessibleChartElements.removeAll() 97| 3| 98| 3| if 99| 3| let combinedChart = chart, 100| 3| let data = combinedChart.data { 101| 3| // Make the chart header the first element in the accessible elements array 102| 3| let element = createAccessibleHeader(usingChart: combinedChart, 103| 3| andData: data, 104| 3| withDefaultDescription: "Combined Chart") 105| 3| accessibleChartElements.append(element) 106| 3| } 107| 3| 108| 3| // TODO: Due to the potential complexity of data presented in Combined charts, a more usable way 109| 3| // for VO accessibility would be to use axis based traversal rather than by dataset. 110| 3| // Hence, accessibleChartElements is not populated below. (Individual renderers guard against dataSource being their respective views) 111| 6| _renderers.forEach { $0.drawData(context: context) } 112| 3| } 113| | 114| | open override func drawValues(context: CGContext) 115| 3| { 116| 6| _renderers.forEach { $0.drawValues(context: context) } 117| 3| } 118| | 119| | open override func drawExtras(context: CGContext) 120| 3| { 121| 6| _renderers.forEach { $0.drawExtras(context: context) } 122| 3| } 123| | 124| | open override func drawHighlighted(context: CGContext, indices: [Highlight]) 125| 0| { 126| 0| for renderer in _renderers 127| 0| { 128| 0| var data: ChartData? 129| 0| 130| 0| if renderer is BarChartRenderer 131| 0| { 132| 0| data = (renderer as! BarChartRenderer).dataProvider?.barData 133| 0| } 134| 0| else if renderer is LineChartRenderer 135| 0| { 136| 0| data = (renderer as! LineChartRenderer).dataProvider?.lineData 137| 0| } 138| 0| else if renderer is CandleStickChartRenderer 139| 0| { 140| 0| data = (renderer as! CandleStickChartRenderer).dataProvider?.candleData 141| 0| } 142| 0| else if renderer is ScatterChartRenderer 143| 0| { 144| 0| data = (renderer as! ScatterChartRenderer).dataProvider?.scatterData 145| 0| } 146| 0| else if renderer is BubbleChartRenderer 147| 0| { 148| 0| data = (renderer as! BubbleChartRenderer).dataProvider?.bubbleData 149| 0| } 150| 0| 151| 0| let dataIndex: Int? = { 152| 0| guard let data = data else { return nil } 153| 0| return (chart?.data as? CombinedChartData)? 154| 0| .allData 155| 0| .firstIndex(of: data) 156| 0| }() 157| 0| 158| 0| let dataIndices = indices.filter{ $0.dataIndex == dataIndex || $0.dataIndex == -1 } 159| 0| 160| 0| renderer.drawHighlighted(context: context, indices: dataIndices) 161| 0| } 162| 0| } 163| | 164| | /// - Returns: The sub-renderer object at the specified index. 165| | @objc open func getSubRenderer(index: Int) -> DataRenderer? 166| 0| { 167| 0| if index >= _renderers.count || index < 0 168| 0| { 169| 0| return nil 170| 0| } 171| 0| else 172| 0| { 173| 0| return _renderers[index] 174| 0| } 175| 0| } 176| | 177| | /// All sub-renderers. 178| | @objc open var subRenderers: [DataRenderer] 179| | { 180| 0| get { return _renderers } 181| 0| set { _renderers = newValue } 182| | } 183| | 184| | // MARK: Accessors 185| | 186| | /// `true` if drawing values above bars is enabled, `false` ifnot 187| 0| @objc open var isDrawValueAboveBarEnabled: Bool { return drawValueAboveBarEnabled } 188| | 189| | /// `true` if drawing shadows (maxvalue) for each bar is enabled, `false` ifnot 190| 0| @objc open var isDrawBarShadowEnabled: Bool { return drawBarShadowEnabled } 191| | 192| | /// the order in which the provided data objects should be drawn. 193| | /// The earlier you place them in the provided array, the further they will be in the background. 194| | /// e.g. if you provide [DrawOrder.Bar, DrawOrder.Line], the bars will be drawn behind the lines. 195| | open var drawOrder: [CombinedChartView.DrawOrder] 196| | { 197| | get 198| 6| { 199| 6| return _drawOrder 200| 6| } 201| | set 202| 0| { 203| 0| if newValue.count > 0 204| 0| { 205| 0| _drawOrder = newValue 206| 0| } 207| 0| } 208| | } 209| |} /Users/travis/build/danielgindi/Charts/Source/Charts/Renderers/HorizontalBarChartRenderer.swift: 1| |// 2| |// HorizontalBarChartRenderer.swift 3| |// Charts 4| |// 5| |// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda 6| |// A port of MPAndroidChart for iOS 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| | 12| |import Foundation 13| |import CoreGraphics 14| | 15| |#if canImport(UIKit) 16| | import UIKit 17| |#endif 18| | 19| |#if canImport(Cocoa) 20| |import Cocoa 21| |#endif 22| | 23| |open class HorizontalBarChartRenderer: BarChartRenderer 24| |{ 25| | private class Buffer 26| | { 27| | var rects = [CGRect]() 28| | } 29| | 30| | public override init(dataProvider: BarChartDataProvider, animator: Animator, viewPortHandler: ViewPortHandler) 31| 6| { 32| 6| super.init(dataProvider: dataProvider, animator: animator, viewPortHandler: viewPortHandler) 33| 6| } 34| | 35| | // [CGRect] per dataset 36| | private var _buffers = [Buffer]() 37| | 38| | open override func initBuffers() 39| 11| { 40| 11| if let barData = dataProvider?.barData 41| 11| { 42| 11| // Matche buffers count to dataset count 43| 11| if _buffers.count != barData.dataSetCount 44| 11| { 45| 12| while _buffers.count < barData.dataSetCount 46| 6| { 47| 6| _buffers.append(Buffer()) 48| 6| } 49| 6| while _buffers.count > barData.dataSetCount 50| 6| { 51| 0| _buffers.removeLast() 52| 6| } 53| 11| } 54| 11| 55| 11| for i in stride(from: 0, to: barData.dataSetCount, by: 1) 56| 11| { 57| 11| let set = barData.dataSets[i] as! IBarChartDataSet 58| 11| let size = set.entryCount * (set.isStacked ? set.stackSize : 1) 59| 11| if _buffers[i].rects.count != size 60| 11| { 61| 6| _buffers[i].rects = [CGRect](repeating: CGRect(), count: size) 62| 11| } 63| 11| } 64| 11| } 65| 11| else 66| 11| { 67| 0| _buffers.removeAll() 68| 11| } 69| 11| } 70| | 71| | private func prepareBuffer(dataSet: IBarChartDataSet, index: Int) 72| 6| { 73| 6| guard let 74| 6| dataProvider = dataProvider, 75| 6| let barData = dataProvider.barData 76| 6| else { return } 77| 6| 78| 6| let barWidthHalf = barData.barWidth / 2.0 79| 6| 80| 6| let buffer = _buffers[index] 81| 6| var bufferIndex = 0 82| 6| let containsStacks = dataSet.isStacked 83| 6| 84| 6| let isInverted = dataProvider.isInverted(axis: dataSet.axisDependency) 85| 6| let phaseY = animator.phaseY 86| 6| var barRect = CGRect() 87| 6| var x: Double 88| 6| var y: Double 89| 6| 90| 6| for i in stride(from: 0, to: min(Int(ceil(Double(dataSet.entryCount) * animator.phaseX)), dataSet.entryCount), by: 1) 91| 105| { 92| 105| guard let e = dataSet.entryForIndex(i) as? BarChartDataEntry else { continue } 93| 105| 94| 105| let vals = e.yValues 95| 105| 96| 105| x = e.x 97| 105| y = e.y 98| 105| 99| 105| if !containsStacks || vals == nil 100| 105| { 101| 90| let bottom = CGFloat(x - barWidthHalf) 102| 90| let top = CGFloat(x + barWidthHalf) 103| 90| var right = isInverted 104| 90| ? (y <= 0.0 ? CGFloat(y) : 0) 105| 90| : (y >= 0.0 ? CGFloat(y) : 0) 106| 90| var left = isInverted 107| 90| ? (y >= 0.0 ? CGFloat(y) : 0) 108| 90| : (y <= 0.0 ? CGFloat(y) : 0) 109| 90| 110| 90| // multiply the height of the rect with the phase 111| 90| if right > 0 112| 90| { 113| 60| right *= CGFloat(phaseY) 114| 90| } 115| 90| else 116| 90| { 117| 30| left *= CGFloat(phaseY) 118| 90| } 119| 90| 120| 90| barRect.origin.x = left 121| 90| barRect.size.width = right - left 122| 90| barRect.origin.y = top 123| 90| barRect.size.height = bottom - top 124| 90| 125| 90| buffer.rects[bufferIndex] = barRect 126| 90| bufferIndex += 1 127| 105| } 128| 105| else 129| 105| { 130| 15| var posY = 0.0 131| 15| var negY = -e.negativeSum 132| 15| var yStart = 0.0 133| 15| 134| 15| // fill the stack 135| 15| for k in 0 ..< vals!.count 136| 75| { 137| 75| let value = vals![k] 138| 75| 139| 75| if value == 0.0 && (posY == 0.0 || negY == 0.0) 140| 75| { 141| 0| // Take care of the situation of a 0.0 value, which overlaps a non-zero bar 142| 0| y = value 143| 0| yStart = y 144| 75| } 145| 75| else if value >= 0.0 146| 75| { 147| 45| y = posY 148| 45| yStart = posY + value 149| 45| posY = yStart 150| 75| } 151| 75| else 152| 75| { 153| 30| y = negY 154| 30| yStart = negY + abs(value) 155| 30| negY += abs(value) 156| 75| } 157| 75| 158| 75| let bottom = CGFloat(x - barWidthHalf) 159| 75| let top = CGFloat(x + barWidthHalf) 160| 75| var right = isInverted 161| 75| ? (y <= yStart ? CGFloat(y) : CGFloat(yStart)) 162| 75| : (y >= yStart ? CGFloat(y) : CGFloat(yStart)) 163| 75| var left = isInverted 164| 75| ? (y >= yStart ? CGFloat(y) : CGFloat(yStart)) 165| 75| : (y <= yStart ? CGFloat(y) : CGFloat(yStart)) 166| 75| 167| 75| // multiply the height of the rect with the phase 168| 75| right *= CGFloat(phaseY) 169| 75| left *= CGFloat(phaseY) 170| 75| 171| 75| barRect.origin.x = left 172| 75| barRect.size.width = right - left 173| 75| barRect.origin.y = top 174| 75| barRect.size.height = bottom - top 175| 75| 176| 75| buffer.rects[bufferIndex] = barRect 177| 75| bufferIndex += 1 178| 75| } 179| 105| } 180| 105| } 181| 6| } 182| | 183| | private var _barShadowRectBuffer: CGRect = CGRect() 184| | 185| | open override func drawDataSet(context: CGContext, dataSet: IBarChartDataSet, index: Int) 186| 6| { 187| 6| guard let dataProvider = dataProvider else { return } 188| 6| 189| 6| let trans = dataProvider.getTransformer(forAxis: dataSet.axisDependency) 190| 6| 191| 6| prepareBuffer(dataSet: dataSet, index: index) 192| 6| trans.rectValuesToPixel(&_buffers[index].rects) 193| 6| 194| 6| let borderWidth = dataSet.barBorderWidth 195| 6| let borderColor = dataSet.barBorderColor 196| 6| let drawBorder = borderWidth > 0.0 197| 6| 198| 6| context.saveGState() 199| 6| 200| 6| // draw the bar shadow before the values 201| 6| if dataProvider.isDrawBarShadowEnabled 202| 6| { 203| 0| guard let barData = dataProvider.barData else { return } 204| 0| 205| 0| let barWidth = barData.barWidth 206| 0| let barWidthHalf = barWidth / 2.0 207| 0| var x: Double = 0.0 208| 0| 209| 0| for i in stride(from: 0, to: min(Int(ceil(Double(dataSet.entryCount) * animator.phaseX)), dataSet.entryCount), by: 1) 210| 0| { 211| 0| guard let e = dataSet.entryForIndex(i) as? BarChartDataEntry else { continue } 212| 0| 213| 0| x = e.x 214| 0| 215| 0| _barShadowRectBuffer.origin.y = CGFloat(x - barWidthHalf) 216| 0| _barShadowRectBuffer.size.height = CGFloat(barWidth) 217| 0| 218| 0| trans.rectValueToPixel(&_barShadowRectBuffer) 219| 0| 220| 0| if !viewPortHandler.isInBoundsTop(_barShadowRectBuffer.origin.y + _barShadowRectBuffer.size.height) 221| 0| { 222| 0| break 223| 0| } 224| 0| 225| 0| if !viewPortHandler.isInBoundsBottom(_barShadowRectBuffer.origin.y) 226| 0| { 227| 0| continue 228| 0| } 229| 0| 230| 0| _barShadowRectBuffer.origin.x = viewPortHandler.contentLeft 231| 0| _barShadowRectBuffer.size.width = viewPortHandler.contentWidth 232| 0| 233| 0| context.setFillColor(dataSet.barShadowColor.cgColor) 234| 0| context.fill(_barShadowRectBuffer) 235| 0| } 236| 6| } 237| 6| 238| 6| let buffer = _buffers[index] 239| 6| 240| 6| let isSingleColor = dataSet.colors.count == 1 241| 6| 242| 6| if isSingleColor 243| 6| { 244| 3| context.setFillColor(dataSet.color(atIndex: 0).cgColor) 245| 6| } 246| 6| 247| 6| // In case the chart is stacked, we need to accomodate individual bars within accessibilityOrdereredElements 248| 6| let isStacked = dataSet.isStacked 249| 6| let stackSize = isStacked ? dataSet.stackSize : 1 250| 6| 251| 6| for j in stride(from: 0, to: buffer.rects.count, by: 1) 252| 165| { 253| 165| let barRect = buffer.rects[j] 254| 165| 255| 165| if (!viewPortHandler.isInBoundsTop(barRect.origin.y + barRect.size.height)) 256| 165| { 257| 0| break 258| 165| } 259| 165| 260| 165| if (!viewPortHandler.isInBoundsBottom(barRect.origin.y)) 261| 165| { 262| 0| continue 263| 165| } 264| 165| 265| 165| if !isSingleColor 266| 165| { 267| 75| // Set the color for the currently drawn value. If the index is out of bounds, reuse colors. 268| 75| context.setFillColor(dataSet.color(atIndex: j).cgColor) 269| 165| } 270| 165| 271| 165| context.fill(barRect) 272| 165| 273| 165| if drawBorder 274| 165| { 275| 0| context.setStrokeColor(borderColor.cgColor) 276| 0| context.setLineWidth(borderWidth) 277| 0| context.stroke(barRect) 278| 165| } 279| 165| 280| 165| // Create and append the corresponding accessibility element to accessibilityOrderedElements (see BarChartRenderer) 281| 165| if let chart = dataProvider as? BarChartView 282| 165| { 283| 165| let element = createAccessibleElement(withIndex: j, 284| 165| container: chart, 285| 165| dataSet: dataSet, 286| 165| dataSetIndex: index, 287| 165| stackSize: stackSize) 288| 165| { (element) in 289| 165| element.accessibilityFrame = barRect 290| 165| } 291| 165| 292| 165| accessibilityOrderedElements[j/stackSize].append(element) 293| 165| } 294| 165| } 295| 6| 296| 6| context.restoreGState() 297| 6| } 298| | 299| | open override func prepareBarHighlight( 300| | x: Double, 301| | y1: Double, 302| | y2: Double, 303| | barWidthHalf: Double, 304| | trans: Transformer, 305| | rect: inout CGRect) 306| 0| { 307| 0| let top = x - barWidthHalf 308| 0| let bottom = x + barWidthHalf 309| 0| let left = y1 310| 0| let right = y2 311| 0| 312| 0| rect.origin.x = CGFloat(left) 313| 0| rect.origin.y = CGFloat(top) 314| 0| rect.size.width = CGFloat(right - left) 315| 0| rect.size.height = CGFloat(bottom - top) 316| 0| 317| 0| trans.rectValueToPixelHorizontal(&rect, phaseY: animator.phaseY) 318| 0| } 319| | 320| | open override func drawValues(context: CGContext) 321| 6| { 322| 6| // if values are drawn 323| 6| if isDrawingValuesAllowed(dataProvider: dataProvider) 324| 6| { 325| 6| guard 326| 6| let dataProvider = dataProvider, 327| 6| let barData = dataProvider.barData 328| 6| else { return } 329| 6| 330| 6| let dataSets = barData.dataSets 331| 6| 332| 6| let textAlign = NSTextAlignment.left 333| 6| 334| 6| let valueOffsetPlus: CGFloat = 5.0 335| 6| var posOffset: CGFloat 336| 6| var negOffset: CGFloat 337| 6| let drawValueAboveBar = dataProvider.isDrawValueAboveBarEnabled 338| 6| 339| 6| for dataSetIndex in 0 ..< barData.dataSetCount 340| 6| { 341| 6| guard let 342| 6| dataSet = dataSets[dataSetIndex] as? IBarChartDataSet, 343| 6| shouldDrawValues(forDataSet: dataSet) 344| 6| else { continue } 345| 4| 346| 4| let isInverted = dataProvider.isInverted(axis: dataSet.axisDependency) 347| 4| 348| 4| let valueFont = dataSet.valueFont 349| 4| let yOffset = -valueFont.lineHeight / 2.0 350| 4| 351| 4| guard let formatter = dataSet.valueFormatter else { continue } 352| 4| 353| 4| let trans = dataProvider.getTransformer(forAxis: dataSet.axisDependency) 354| 4| 355| 4| let phaseY = animator.phaseY 356| 4| 357| 4| let iconsOffset = dataSet.iconsOffset 358| 4| 359| 4| let buffer = _buffers[dataSetIndex] 360| 4| 361| 4| // if only single values are drawn (sum) 362| 4| if !dataSet.isStacked 363| 4| { 364| 2| for j in 0 ..< Int(ceil(Double(dataSet.entryCount) * animator.phaseX)) 365| 60| { 366| 60| guard let e = dataSet.entryForIndex(j) as? BarChartDataEntry else { continue } 367| 60| 368| 60| let rect = buffer.rects[j] 369| 60| 370| 60| let y = rect.origin.y + rect.size.height / 2.0 371| 60| 372| 60| if !viewPortHandler.isInBoundsTop(rect.origin.y) 373| 60| { 374| 0| break 375| 60| } 376| 60| 377| 60| if !viewPortHandler.isInBoundsX(rect.origin.x) 378| 60| { 379| 0| continue 380| 60| } 381| 60| 382| 60| if !viewPortHandler.isInBoundsBottom(rect.origin.y) 383| 60| { 384| 0| continue 385| 60| } 386| 60| 387| 60| let val = e.y 388| 60| let valueText = formatter.stringForValue( 389| 60| val, 390| 60| entry: e, 391| 60| dataSetIndex: dataSetIndex, 392| 60| viewPortHandler: viewPortHandler) 393| 60| 394| 60| // calculate the correct offset depending on the draw position of the value 395| 60| let valueTextWidth = valueText.size(withAttributes: [NSAttributedString.Key.font: valueFont]).width 396| 60| posOffset = (drawValueAboveBar ? valueOffsetPlus : -(valueTextWidth + valueOffsetPlus)) 397| 60| negOffset = (drawValueAboveBar ? -(valueTextWidth + valueOffsetPlus) : valueOffsetPlus) - rect.size.width 398| 60| 399| 60| if isInverted 400| 60| { 401| 0| posOffset = -posOffset - valueTextWidth 402| 0| negOffset = -negOffset - valueTextWidth 403| 60| } 404| 60| 405| 60| if dataSet.isDrawValuesEnabled 406| 60| { 407| 60| drawValue( 408| 60| context: context, 409| 60| value: valueText, 410| 60| xPos: (rect.origin.x + rect.size.width) 411| 60| + (val >= 0.0 ? posOffset : negOffset), 412| 60| yPos: y + yOffset, 413| 60| font: valueFont, 414| 60| align: textAlign, 415| 60| color: dataSet.valueTextColorAt(j)) 416| 60| } 417| 60| 418| 60| if let icon = e.icon, dataSet.isDrawIconsEnabled 419| 60| { 420| 0| var px = (rect.origin.x + rect.size.width) 421| 0| + (val >= 0.0 ? posOffset : negOffset) 422| 0| var py = y 423| 0| 424| 0| px += iconsOffset.x 425| 0| py += iconsOffset.y 426| 0| 427| 0| ChartUtils.drawImage( 428| 0| context: context, 429| 0| image: icon, 430| 0| x: px, 431| 0| y: py, 432| 0| size: icon.size) 433| 60| } 434| 60| } 435| 4| } 436| 4| else 437| 4| { 438| 2| // if each value of a potential stack should be drawn 439| 2| 440| 2| var bufferIndex = 0 441| 2| 442| 2| for index in 0 ..< Int(ceil(Double(dataSet.entryCount) * animator.phaseX)) 443| 10| { 444| 10| guard let e = dataSet.entryForIndex(index) as? BarChartDataEntry else { continue } 445| 10| 446| 10| let rect = buffer.rects[bufferIndex] 447| 10| 448| 10| let vals = e.yValues 449| 10| 450| 10| // we still draw stacked bars, but there is one non-stacked in between 451| 10| if vals == nil 452| 10| { 453| 0| if !viewPortHandler.isInBoundsTop(rect.origin.y) 454| 0| { 455| 0| break 456| 0| } 457| 0| 458| 0| if !viewPortHandler.isInBoundsX(rect.origin.x) 459| 0| { 460| 0| continue 461| 0| } 462| 0| 463| 0| if !viewPortHandler.isInBoundsBottom(rect.origin.y) 464| 0| { 465| 0| continue 466| 0| } 467| 0| 468| 0| let val = e.y 469| 0| let valueText = formatter.stringForValue( 470| 0| val, 471| 0| entry: e, 472| 0| dataSetIndex: dataSetIndex, 473| 0| viewPortHandler: viewPortHandler) 474| 0| 475| 0| // calculate the correct offset depending on the draw position of the value 476| 0| let valueTextWidth = valueText.size(withAttributes: [NSAttributedString.Key.font: valueFont]).width 477| 0| posOffset = (drawValueAboveBar ? valueOffsetPlus : -(valueTextWidth + valueOffsetPlus)) 478| 0| negOffset = (drawValueAboveBar ? -(valueTextWidth + valueOffsetPlus) : valueOffsetPlus) 479| 0| 480| 0| if isInverted 481| 0| { 482| 0| posOffset = -posOffset - valueTextWidth 483| 0| negOffset = -negOffset - valueTextWidth 484| 0| } 485| 0| 486| 0| if dataSet.isDrawValuesEnabled 487| 0| { 488| 0| drawValue( 489| 0| context: context, 490| 0| value: valueText, 491| 0| xPos: (rect.origin.x + rect.size.width) 492| 0| + (val >= 0.0 ? posOffset : negOffset), 493| 0| yPos: rect.origin.y + yOffset, 494| 0| font: valueFont, 495| 0| align: textAlign, 496| 0| color: dataSet.valueTextColorAt(index)) 497| 0| } 498| 0| 499| 0| if let icon = e.icon, dataSet.isDrawIconsEnabled 500| 0| { 501| 0| var px = (rect.origin.x + rect.size.width) 502| 0| + (val >= 0.0 ? posOffset : negOffset) 503| 0| var py = rect.origin.y 504| 0| 505| 0| px += iconsOffset.x 506| 0| py += iconsOffset.y 507| 0| 508| 0| ChartUtils.drawImage( 509| 0| context: context, 510| 0| image: icon, 511| 0| x: px, 512| 0| y: py, 513| 0| size: icon.size) 514| 0| } 515| 10| } 516| 10| else 517| 10| { 518| 10| let vals = vals! 519| 10| var transformed = [CGPoint]() 520| 10| 521| 10| var posY = 0.0 522| 10| var negY = -e.negativeSum 523| 10| 524| 10| for k in 0 ..< vals.count 525| 50| { 526| 50| let value = vals[k] 527| 50| var y: Double 528| 50| 529| 50| if value == 0.0 && (posY == 0.0 || negY == 0.0) 530| 50| { 531| 0| // Take care of the situation of a 0.0 value, which overlaps a non-zero bar 532| 0| y = value 533| 50| } 534| 50| else if value >= 0.0 535| 50| { 536| 30| posY += value 537| 30| y = posY 538| 50| } 539| 50| else 540| 50| { 541| 20| y = negY 542| 20| negY -= value 543| 50| } 544| 50| 545| 50| transformed.append(CGPoint(x: CGFloat(y * phaseY), y: 0.0)) 546| 50| } 547| 10| 548| 10| trans.pointValuesToPixel(&transformed) 549| 10| 550| 10| for k in 0 ..< transformed.count 551| 50| { 552| 50| let val = vals[k] 553| 50| let valueText = formatter.stringForValue( 554| 50| val, 555| 50| entry: e, 556| 50| dataSetIndex: dataSetIndex, 557| 50| viewPortHandler: viewPortHandler) 558| 50| 559| 50| // calculate the correct offset depending on the draw position of the value 560| 50| let valueTextWidth = valueText.size(withAttributes: [NSAttributedString.Key.font: valueFont]).width 561| 50| posOffset = (drawValueAboveBar ? valueOffsetPlus : -(valueTextWidth + valueOffsetPlus)) 562| 50| negOffset = (drawValueAboveBar ? -(valueTextWidth + valueOffsetPlus) : valueOffsetPlus) 563| 50| 564| 50| if isInverted 565| 50| { 566| 0| posOffset = -posOffset - valueTextWidth 567| 0| negOffset = -negOffset - valueTextWidth 568| 50| } 569| 50| 570| 50| let drawBelow = (val == 0.0 && negY == 0.0 && posY > 0.0) || val < 0.0 571| 50| 572| 50| let x = transformed[k].x + (drawBelow ? negOffset : posOffset) 573| 50| let y = rect.origin.y + rect.size.height / 2.0 574| 50| 575| 50| if (!viewPortHandler.isInBoundsTop(y)) 576| 50| { 577| 0| break 578| 50| } 579| 50| 580| 50| if (!viewPortHandler.isInBoundsX(x)) 581| 50| { 582| 0| continue 583| 50| } 584| 50| 585| 50| if (!viewPortHandler.isInBoundsBottom(y)) 586| 50| { 587| 0| continue 588| 50| } 589| 50| 590| 50| if dataSet.isDrawValuesEnabled 591| 50| { 592| 50| drawValue(context: context, 593| 50| value: valueText, 594| 50| xPos: x, 595| 50| yPos: y + yOffset, 596| 50| font: valueFont, 597| 50| align: textAlign, 598| 50| color: dataSet.valueTextColorAt(index)) 599| 50| } 600| 50| 601| 50| if let icon = e.icon, dataSet.isDrawIconsEnabled 602| 50| { 603| 0| ChartUtils.drawImage( 604| 0| context: context, 605| 0| image: icon, 606| 0| x: x + iconsOffset.x, 607| 0| y: y + iconsOffset.y, 608| 0| size: icon.size) 609| 50| } 610| 50| } 611| 10| } 612| 10| 613| 10| bufferIndex = vals == nil ? (bufferIndex + 1) : (bufferIndex + vals!.count) 614| 10| } 615| 4| } 616| 6| } 617| 6| } 618| 6| } 619| | 620| | open override func isDrawingValuesAllowed(dataProvider: ChartDataProvider?) -> Bool 621| 6| { 622| 6| guard let data = dataProvider?.data 623| 6| else { return false } 624| 6| return data.entryCount < Int(CGFloat(dataProvider?.maxVisibleCount ?? 0) * self.viewPortHandler.scaleY) 625| 6| } 626| | 627| | /// Sets the drawing position of the highlight object based on the riven bar-rect. 628| | internal override func setHighlightDrawPos(highlight high: Highlight, barRect: CGRect) 629| 0| { 630| 0| high.setDraw(x: barRect.midY, y: barRect.origin.x + barRect.size.width) 631| 0| } 632| |} /Users/travis/build/danielgindi/Charts/Source/Charts/Renderers/LegendRenderer.swift: 1| |// 2| |// LegendRenderer.swift 3| |// Charts 4| |// 5| |// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda 6| |// A port of MPAndroidChart for iOS 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| | 12| |import Foundation 13| |import CoreGraphics 14| | 15| |@objc(ChartLegendRenderer) 16| |open class LegendRenderer: Renderer 17| |{ 18| | /// the legend object this renderer renders 19| | @objc open var legend: Legend? 20| | 21| | @objc public init(viewPortHandler: ViewPortHandler, legend: Legend?) 22| 52| { 23| 52| super.init(viewPortHandler: viewPortHandler) 24| 52| 25| 52| self.legend = legend 26| 52| } 27| | 28| | /// Prepares the legend and calculates all needed forms, labels and colors. 29| | @objc open func computeLegend(data: ChartData) 30| 85| { 31| 85| guard let legend = legend else { return } 32| 85| 33| 85| if !legend.isLegendCustom 34| 85| { 35| 85| var entries: [LegendEntry] = [] 36| 85| 37| 85| // loop for building up the colors and labels used in the legend 38| 85| for i in 0.. 0) 57| 48| { 58| 0| let labelIndex = j % minEntries 59| 0| label = sLabels.indices.contains(labelIndex) ? sLabels[labelIndex] : nil 60| 48| } 61| 48| else 62| 48| { 63| 48| label = nil 64| 48| } 65| 48| 66| 48| entries.append( 67| 48| LegendEntry( 68| 48| label: label, 69| 48| form: dataSet.form, 70| 48| formSize: dataSet.formSize, 71| 48| formLineWidth: dataSet.formLineWidth, 72| 48| formLineDashPhase: dataSet.formLineDashPhase, 73| 48| formLineDashLengths: dataSet.formLineDashLengths, 74| 48| formColor: clrs[j] 75| 48| ) 76| 48| ) 77| 48| } 78| 12| 79| 12| if dataSet.label != nil 80| 12| { 81| 12| // add the legend description label 82| 12| 83| 12| entries.append( 84| 12| LegendEntry( 85| 12| label: dataSet.label, 86| 12| form: .none, 87| 12| formSize: CGFloat.nan, 88| 12| formLineWidth: CGFloat.nan, 89| 12| formLineDashPhase: 0.0, 90| 12| formLineDashLengths: nil, 91| 12| formColor: nil 92| 12| ) 93| 12| ) 94| 12| } 95| 90| } 96| 90| else if dataSet is IPieChartDataSet 97| 90| { 98| 6| let pds = dataSet as! IPieChartDataSet 99| 6| 100| 6| for j in 0.. 0 555| 0| { 556| 0| context.setLineDash(phase: formLineDashPhase, lengths: formLineDashLengths!) 557| 0| } 558| 0| else 559| 0| { 560| 0| context.setLineDash(phase: 0.0, lengths: []) 561| 0| } 562| 0| 563| 0| context.setStrokeColor(formColor.cgColor) 564| 0| 565| 0| _formLineSegmentsBuffer[0].x = x 566| 0| _formLineSegmentsBuffer[0].y = y 567| 0| _formLineSegmentsBuffer[1].x = x + formSize 568| 0| _formLineSegmentsBuffer[1].y = y 569| 0| context.strokeLineSegments(between: _formLineSegmentsBuffer) 570| 109| } 571| 109| } 572| | 573| | /// Draws the provided label at the given position. 574| | @objc open func drawLabel(context: CGContext, x: CGFloat, y: CGFloat, label: String, font: NSUIFont, textColor: NSUIColor) 575| 55| { 576| 55| ChartUtils.drawText(context: context, text: label, point: CGPoint(x: x, y: y), align: .left, attributes: [NSAttributedString.Key.font: font, NSAttributedString.Key.foregroundColor: textColor]) 577| 55| } 578| |} /Users/travis/build/danielgindi/Charts/Source/Charts/Renderers/LineChartRenderer.swift: 1| |// 2| |// LineChartRenderer.swift 3| |// Charts 4| |// 5| |// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda 6| |// A port of MPAndroidChart for iOS 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| | 12| |import Foundation 13| |import CoreGraphics 14| | 15| |open class LineChartRenderer: LineRadarRenderer 16| |{ 17| | // TODO: Currently, this nesting isn't necessary for LineCharts. However, it will make it much easier to add a custom rotor 18| | // that navigates between datasets. 19| | // NOTE: Unlike the other renderers, LineChartRenderer populates accessibleChartElements in drawCircles due to the nature of its drawing options. 20| | /// A nested array of elements ordered logically (i.e not in visual/drawing order) for use with VoiceOver. 21| | private lazy var accessibilityOrderedElements: [[NSUIAccessibilityElement]] = accessibilityCreateEmptyOrderedElements() 22| | 23| | @objc open weak var dataProvider: LineChartDataProvider? 24| | 25| | @objc public init(dataProvider: LineChartDataProvider, animator: Animator, viewPortHandler: ViewPortHandler) 26| 9| { 27| 9| super.init(animator: animator, viewPortHandler: viewPortHandler) 28| 9| 29| 9| self.dataProvider = dataProvider 30| 9| } 31| | 32| | open override func drawData(context: CGContext) 33| 9| { 34| 9| guard let lineData = dataProvider?.lineData else { return } 35| 9| 36| 9| for i in 0 ..< lineData.dataSetCount 37| 9| { 38| 9| guard let set = lineData.getDataSetByIndex(i) else { continue } 39| 9| 40| 9| if set.isVisible 41| 9| { 42| 9| if !(set is ILineChartDataSet) 43| 9| { 44| 0| fatalError("Datasets for LineChartRenderer must conform to ILineChartDataSet") 45| 9| } 46| 9| 47| 9| drawDataSet(context: context, dataSet: set as! ILineChartDataSet) 48| 9| } 49| 9| } 50| 9| } 51| | 52| | @objc open func drawDataSet(context: CGContext, dataSet: ILineChartDataSet) 53| 9| { 54| 9| if dataSet.entryCount < 1 55| 9| { 56| 0| return 57| 9| } 58| 9| 59| 9| context.saveGState() 60| 9| 61| 9| context.setLineWidth(dataSet.lineWidth) 62| 9| if dataSet.lineDashLengths != nil 63| 9| { 64| 0| context.setLineDash(phase: dataSet.lineDashPhase, lengths: dataSet.lineDashLengths!) 65| 9| } 66| 9| else 67| 9| { 68| 9| context.setLineDash(phase: 0.0, lengths: []) 69| 9| } 70| 9| 71| 9| context.setLineCap(dataSet.lineCapType) 72| 9| 73| 9| // if drawing cubic lines is enabled 74| 9| switch dataSet.mode 75| 9| { 76| 9| case .linear: fallthrough 77| 9| case .stepped: 78| 8| drawLinear(context: context, dataSet: dataSet) 79| 9| 80| 9| case .cubicBezier: 81| 1| drawCubicBezier(context: context, dataSet: dataSet) 82| 9| 83| 9| case .horizontalBezier: 84| 0| drawHorizontalBezier(context: context, dataSet: dataSet) 85| 9| } 86| 9| 87| 9| context.restoreGState() 88| 9| } 89| | 90| | @objc open func drawCubicBezier(context: CGContext, dataSet: ILineChartDataSet) 91| 1| { 92| 1| guard let dataProvider = dataProvider else { return } 93| 1| 94| 1| let trans = dataProvider.getTransformer(forAxis: dataSet.axisDependency) 95| 1| 96| 1| let phaseY = animator.phaseY 97| 1| 98| 1| _xBounds.set(chart: dataProvider, dataSet: dataSet, animator: animator) 99| 1| 100| 1| // get the color that is specified for this position from the DataSet 101| 1| let drawingColor = dataSet.colors.first! 102| 1| 103| 1| let intensity = dataSet.cubicIntensity 104| 1| 105| 1| // the path for the cubic-spline 106| 1| let cubicPath = CGMutablePath() 107| 1| 108| 1| let valueToPixelMatrix = trans.valueToPixelMatrix 109| 1| 110| 1| if _xBounds.range >= 1 111| 1| { 112| 1| var prevDx: CGFloat = 0.0 113| 1| var prevDy: CGFloat = 0.0 114| 1| var curDx: CGFloat = 0.0 115| 1| var curDy: CGFloat = 0.0 116| 1| 117| 1| // Take an extra point from the left, and an extra from the right. 118| 1| // That's because we need 4 points for a cubic bezier (cubic=4), otherwise we get lines moving and doing weird stuff on the edges of the chart. 119| 1| // So in the starting `prev` and `cur`, go -2, -1 120| 1| 121| 1| let firstIndex = _xBounds.min + 1 122| 1| 123| 1| var prevPrev: ChartDataEntry! = nil 124| 1| var prev: ChartDataEntry! = dataSet.entryForIndex(max(firstIndex - 2, 0)) 125| 1| var cur: ChartDataEntry! = dataSet.entryForIndex(max(firstIndex - 1, 0)) 126| 1| var next: ChartDataEntry! = cur 127| 1| var nextIndex: Int = -1 128| 1| 129| 1| if cur == nil { return } 130| 1| 131| 1| // let the spline start 132| 1| cubicPath.move(to: CGPoint(x: CGFloat(cur.x), y: CGFloat(cur.y * phaseY)), transform: valueToPixelMatrix) 133| 1| 134| 1| for j in _xBounds.dropFirst() // same as firstIndex 135| 29| { 136| 29| prevPrev = prev 137| 29| prev = cur 138| 29| cur = nextIndex == j ? next : dataSet.entryForIndex(j) 139| 29| 140| 29| nextIndex = j + 1 < dataSet.entryCount ? j + 1 : j 141| 29| next = dataSet.entryForIndex(nextIndex) 142| 29| 143| 29| if next == nil { break } 144| 29| 145| 29| prevDx = CGFloat(cur.x - prevPrev.x) * intensity 146| 29| prevDy = CGFloat(cur.y - prevPrev.y) * intensity 147| 29| curDx = CGFloat(next.x - prev.x) * intensity 148| 29| curDy = CGFloat(next.y - prev.y) * intensity 149| 29| 150| 29| cubicPath.addCurve( 151| 29| to: CGPoint( 152| 29| x: CGFloat(cur.x), 153| 29| y: CGFloat(cur.y) * CGFloat(phaseY)), 154| 29| control1: CGPoint( 155| 29| x: CGFloat(prev.x) + prevDx, 156| 29| y: (CGFloat(prev.y) + prevDy) * CGFloat(phaseY)), 157| 29| control2: CGPoint( 158| 29| x: CGFloat(cur.x) - curDx, 159| 29| y: (CGFloat(cur.y) - curDy) * CGFloat(phaseY)), 160| 29| transform: valueToPixelMatrix) 161| 29| } 162| 1| } 163| 1| 164| 1| context.saveGState() 165| 1| 166| 1| if dataSet.isDrawFilledEnabled 167| 1| { 168| 0| // Copy this path because we make changes to it 169| 0| let fillPath = cubicPath.mutableCopy() 170| 0| 171| 0| drawCubicFill(context: context, dataSet: dataSet, spline: fillPath!, matrix: valueToPixelMatrix, bounds: _xBounds) 172| 1| } 173| 1| 174| 1| context.beginPath() 175| 1| context.addPath(cubicPath) 176| 1| context.setStrokeColor(drawingColor.cgColor) 177| 1| context.strokePath() 178| 1| 179| 1| context.restoreGState() 180| 1| } 181| | 182| | @objc open func drawHorizontalBezier(context: CGContext, dataSet: ILineChartDataSet) 183| 0| { 184| 0| guard let dataProvider = dataProvider else { return } 185| 0| 186| 0| let trans = dataProvider.getTransformer(forAxis: dataSet.axisDependency) 187| 0| 188| 0| let phaseY = animator.phaseY 189| 0| 190| 0| _xBounds.set(chart: dataProvider, dataSet: dataSet, animator: animator) 191| 0| 192| 0| // get the color that is specified for this position from the DataSet 193| 0| let drawingColor = dataSet.colors.first! 194| 0| 195| 0| // the path for the cubic-spline 196| 0| let cubicPath = CGMutablePath() 197| 0| 198| 0| let valueToPixelMatrix = trans.valueToPixelMatrix 199| 0| 200| 0| if _xBounds.range >= 1 201| 0| { 202| 0| var prev: ChartDataEntry! = dataSet.entryForIndex(_xBounds.min) 203| 0| var cur: ChartDataEntry! = prev 204| 0| 205| 0| if cur == nil { return } 206| 0| 207| 0| // let the spline start 208| 0| cubicPath.move(to: CGPoint(x: CGFloat(cur.x), y: CGFloat(cur.y * phaseY)), transform: valueToPixelMatrix) 209| 0| 210| 0| for j in _xBounds.dropFirst() 211| 0| { 212| 0| prev = cur 213| 0| cur = dataSet.entryForIndex(j) 214| 0| 215| 0| let cpx = CGFloat(prev.x + (cur.x - prev.x) / 2.0) 216| 0| 217| 0| cubicPath.addCurve( 218| 0| to: CGPoint( 219| 0| x: CGFloat(cur.x), 220| 0| y: CGFloat(cur.y * phaseY)), 221| 0| control1: CGPoint( 222| 0| x: cpx, 223| 0| y: CGFloat(prev.y * phaseY)), 224| 0| control2: CGPoint( 225| 0| x: cpx, 226| 0| y: CGFloat(cur.y * phaseY)), 227| 0| transform: valueToPixelMatrix) 228| 0| } 229| 0| } 230| 0| 231| 0| context.saveGState() 232| 0| 233| 0| if dataSet.isDrawFilledEnabled 234| 0| { 235| 0| // Copy this path because we make changes to it 236| 0| let fillPath = cubicPath.mutableCopy() 237| 0| 238| 0| drawCubicFill(context: context, dataSet: dataSet, spline: fillPath!, matrix: valueToPixelMatrix, bounds: _xBounds) 239| 0| } 240| 0| 241| 0| context.beginPath() 242| 0| context.addPath(cubicPath) 243| 0| context.setStrokeColor(drawingColor.cgColor) 244| 0| context.strokePath() 245| 0| 246| 0| context.restoreGState() 247| 0| } 248| | 249| | open func drawCubicFill( 250| | context: CGContext, 251| | dataSet: ILineChartDataSet, 252| | spline: CGMutablePath, 253| | matrix: CGAffineTransform, 254| | bounds: XBounds) 255| 0| { 256| 0| guard 257| 0| let dataProvider = dataProvider 258| 0| else { return } 259| 0| 260| 0| if bounds.range <= 0 261| 0| { 262| 0| return 263| 0| } 264| 0| 265| 0| let fillMin = dataSet.fillFormatter?.getFillLinePosition(dataSet: dataSet, dataProvider: dataProvider) ?? 0.0 266| 0| 267| 0| var pt1 = CGPoint(x: CGFloat(dataSet.entryForIndex(bounds.min + bounds.range)?.x ?? 0.0), y: fillMin) 268| 0| var pt2 = CGPoint(x: CGFloat(dataSet.entryForIndex(bounds.min)?.x ?? 0.0), y: fillMin) 269| 0| pt1 = pt1.applying(matrix) 270| 0| pt2 = pt2.applying(matrix) 271| 0| 272| 0| spline.addLine(to: pt1) 273| 0| spline.addLine(to: pt2) 274| 0| spline.closeSubpath() 275| 0| 276| 0| if dataSet.fill != nil 277| 0| { 278| 0| drawFilledPath(context: context, path: spline, fill: dataSet.fill!, fillAlpha: dataSet.fillAlpha) 279| 0| } 280| 0| else 281| 0| { 282| 0| drawFilledPath(context: context, path: spline, fillColor: dataSet.fillColor, fillAlpha: dataSet.fillAlpha) 283| 0| } 284| 0| } 285| | 286| | private var _lineSegments = [CGPoint](repeating: CGPoint(), count: 2) 287| | 288| | @objc open func drawLinear(context: CGContext, dataSet: ILineChartDataSet) 289| 8| { 290| 8| guard let dataProvider = dataProvider else { return } 291| 8| 292| 8| let trans = dataProvider.getTransformer(forAxis: dataSet.axisDependency) 293| 8| 294| 8| let valueToPixelMatrix = trans.valueToPixelMatrix 295| 8| 296| 8| let entryCount = dataSet.entryCount 297| 8| let isDrawSteppedEnabled = dataSet.mode == .stepped 298| 8| let pointsPerEntryPair = isDrawSteppedEnabled ? 4 : 2 299| 8| 300| 8| let phaseY = animator.phaseY 301| 8| 302| 8| _xBounds.set(chart: dataProvider, dataSet: dataSet, animator: animator) 303| 8| 304| 8| // if drawing filled is enabled 305| 8| if dataSet.isDrawFilledEnabled && entryCount > 0 306| 8| { 307| 0| drawLinearFill(context: context, dataSet: dataSet, trans: trans, bounds: _xBounds) 308| 8| } 309| 8| 310| 8| context.saveGState() 311| 8| 312| 8| if _lineSegments.count != pointsPerEntryPair 313| 8| { 314| 0| // Allocate once in correct size 315| 0| _lineSegments = [CGPoint](repeating: CGPoint(), count: pointsPerEntryPair) 316| 8| } 317| 8| 318| 8| for j in _xBounds.dropLast() 319| 232| { 320| 232| var e: ChartDataEntry! = dataSet.entryForIndex(j) 321| 232| 322| 232| if e == nil { continue } 323| 232| 324| 232| _lineSegments[0].x = CGFloat(e.x) 325| 232| _lineSegments[0].y = CGFloat(e.y * phaseY) 326| 232| 327| 232| if j < _xBounds.max 328| 232| { 329| 232| // TODO: remove the check. 330| 232| // With the new XBounds iterator, j is always smaller than _xBounds.max 331| 232| // Keeping this check for a while, if xBounds have no further breaking changes, it should be safe to remove the check 332| 232| e = dataSet.entryForIndex(j + 1) 333| 232| 334| 232| if e == nil { break } 335| 232| 336| 232| if isDrawSteppedEnabled 337| 232| { 338| 0| _lineSegments[1] = CGPoint(x: CGFloat(e.x), y: _lineSegments[0].y) 339| 0| _lineSegments[2] = _lineSegments[1] 340| 0| _lineSegments[3] = CGPoint(x: CGFloat(e.x), y: CGFloat(e.y * phaseY)) 341| 232| } 342| 232| else 343| 232| { 344| 232| _lineSegments[1] = CGPoint(x: CGFloat(e.x), y: CGFloat(e.y * phaseY)) 345| 232| } 346| 232| } 347| 232| else 348| 232| { 349| 0| _lineSegments[1] = _lineSegments[0] 350| 232| } 351| 232| 352| 232| for i in 0..<_lineSegments.count 353| 464| { 354| 464| _lineSegments[i] = _lineSegments[i].applying(valueToPixelMatrix) 355| 464| } 356| 232| 357| 232| if !viewPortHandler.isInBoundsRight(_lineSegments[0].x) 358| 232| { 359| 0| break 360| 232| } 361| 232| 362| 232| // Determine the start and end coordinates of the line, and make sure they differ. 363| 232| guard 364| 232| let firstCoordinate = _lineSegments.first, 365| 232| let lastCoordinate = _lineSegments.last, 366| 232| firstCoordinate != lastCoordinate else { continue } 367| 232| 368| 232| // make sure the lines don't do shitty things outside bounds 369| 232| if !viewPortHandler.isInBoundsLeft(lastCoordinate.x) || 370| 232| !viewPortHandler.isInBoundsTop(max(firstCoordinate.y, lastCoordinate.y)) || 371| 232| !viewPortHandler.isInBoundsBottom(min(firstCoordinate.y, lastCoordinate.y)) 372| 232| { 373| 0| continue 374| 232| } 375| 232| 376| 232| // get the color that is set for this line-segment 377| 232| context.setStrokeColor(dataSet.color(atIndex: j).cgColor) 378| 232| context.strokeLineSegments(between: _lineSegments) 379| 232| } 380| 8| 381| 8| context.restoreGState() 382| 8| } 383| | 384| | open func drawLinearFill(context: CGContext, dataSet: ILineChartDataSet, trans: Transformer, bounds: XBounds) 385| 0| { 386| 0| guard let dataProvider = dataProvider else { return } 387| 0| 388| 0| let filled = generateFilledPath( 389| 0| dataSet: dataSet, 390| 0| fillMin: dataSet.fillFormatter?.getFillLinePosition(dataSet: dataSet, dataProvider: dataProvider) ?? 0.0, 391| 0| bounds: bounds, 392| 0| matrix: trans.valueToPixelMatrix) 393| 0| 394| 0| if dataSet.fill != nil 395| 0| { 396| 0| drawFilledPath(context: context, path: filled, fill: dataSet.fill!, fillAlpha: dataSet.fillAlpha) 397| 0| } 398| 0| else 399| 0| { 400| 0| drawFilledPath(context: context, path: filled, fillColor: dataSet.fillColor, fillAlpha: dataSet.fillAlpha) 401| 0| } 402| 0| } 403| | 404| | /// Generates the path that is used for filled drawing. 405| | private func generateFilledPath(dataSet: ILineChartDataSet, fillMin: CGFloat, bounds: XBounds, matrix: CGAffineTransform) -> CGPath 406| 0| { 407| 0| let phaseY = animator.phaseY 408| 0| let isDrawSteppedEnabled = dataSet.mode == .stepped 409| 0| let matrix = matrix 410| 0| 411| 0| var e: ChartDataEntry! 412| 0| 413| 0| let filled = CGMutablePath() 414| 0| 415| 0| e = dataSet.entryForIndex(bounds.min) 416| 0| if e != nil 417| 0| { 418| 0| filled.move(to: CGPoint(x: CGFloat(e.x), y: fillMin), transform: matrix) 419| 0| filled.addLine(to: CGPoint(x: CGFloat(e.x), y: CGFloat(e.y * phaseY)), transform: matrix) 420| 0| } 421| 0| 422| 0| // create a new path 423| 0| for x in stride(from: (bounds.min + 1), through: bounds.range + bounds.min, by: 1) 424| 0| { 425| 0| guard let e = dataSet.entryForIndex(x) else { continue } 426| 0| 427| 0| if isDrawSteppedEnabled 428| 0| { 429| 0| guard let ePrev = dataSet.entryForIndex(x-1) else { continue } 430| 0| filled.addLine(to: CGPoint(x: CGFloat(e.x), y: CGFloat(ePrev.y * phaseY)), transform: matrix) 431| 0| } 432| 0| 433| 0| filled.addLine(to: CGPoint(x: CGFloat(e.x), y: CGFloat(e.y * phaseY)), transform: matrix) 434| 0| } 435| 0| 436| 0| // close up 437| 0| e = dataSet.entryForIndex(bounds.range + bounds.min) 438| 0| if e != nil 439| 0| { 440| 0| filled.addLine(to: CGPoint(x: CGFloat(e.x), y: fillMin), transform: matrix) 441| 0| } 442| 0| filled.closeSubpath() 443| 0| 444| 0| return filled 445| 0| } 446| | 447| | open override func drawValues(context: CGContext) 448| 9| { 449| 9| guard 450| 9| let dataProvider = dataProvider, 451| 9| let lineData = dataProvider.lineData 452| 9| else { return } 453| 9| 454| 9| if isDrawingValuesAllowed(dataProvider: dataProvider) 455| 9| { 456| 9| let dataSets = lineData.dataSets 457| 9| 458| 9| let phaseY = animator.phaseY 459| 9| 460| 9| var pt = CGPoint() 461| 9| 462| 9| for i in 0 ..< dataSets.count 463| 9| { 464| 9| guard let 465| 9| dataSet = dataSets[i] as? ILineChartDataSet, 466| 9| shouldDrawValues(forDataSet: dataSet) 467| 9| else { continue } 468| 8| 469| 8| let valueFont = dataSet.valueFont 470| 8| 471| 8| guard let formatter = dataSet.valueFormatter else { continue } 472| 8| 473| 8| let trans = dataProvider.getTransformer(forAxis: dataSet.axisDependency) 474| 8| let valueToPixelMatrix = trans.valueToPixelMatrix 475| 8| 476| 8| let iconsOffset = dataSet.iconsOffset 477| 8| 478| 8| // make sure the values do not interfear with the circles 479| 8| var valOffset = Int(dataSet.circleRadius * 1.75) 480| 8| 481| 8| if !dataSet.isDrawCirclesEnabled 482| 8| { 483| 1| valOffset = valOffset / 2 484| 8| } 485| 8| 486| 8| _xBounds.set(chart: dataProvider, dataSet: dataSet, animator: animator) 487| 8| 488| 8| for j in _xBounds 489| 240| { 490| 240| guard let e = dataSet.entryForIndex(j) else { break } 491| 240| 492| 240| pt.x = CGFloat(e.x) 493| 240| pt.y = CGFloat(e.y * phaseY) 494| 240| pt = pt.applying(valueToPixelMatrix) 495| 240| 496| 240| if (!viewPortHandler.isInBoundsRight(pt.x)) 497| 240| { 498| 0| break 499| 240| } 500| 240| 501| 240| if (!viewPortHandler.isInBoundsLeft(pt.x) || !viewPortHandler.isInBoundsY(pt.y)) 502| 240| { 503| 0| continue 504| 240| } 505| 240| 506| 240| if dataSet.isDrawValuesEnabled { 507| 240| ChartUtils.drawText( 508| 240| context: context, 509| 240| text: formatter.stringForValue( 510| 240| e.y, 511| 240| entry: e, 512| 240| dataSetIndex: i, 513| 240| viewPortHandler: viewPortHandler), 514| 240| point: CGPoint( 515| 240| x: pt.x, 516| 240| y: pt.y - CGFloat(valOffset) - valueFont.lineHeight), 517| 240| align: .center, 518| 240| attributes: [NSAttributedString.Key.font: valueFont, NSAttributedString.Key.foregroundColor: dataSet.valueTextColorAt(j)]) 519| 240| } 520| 240| 521| 240| if let icon = e.icon, dataSet.isDrawIconsEnabled 522| 240| { 523| 30| ChartUtils.drawImage(context: context, 524| 30| image: icon, 525| 30| x: pt.x + iconsOffset.x, 526| 30| y: pt.y + iconsOffset.y, 527| 30| size: icon.size) 528| 240| } 529| 240| } 530| 9| } 531| 9| } 532| 9| } 533| | 534| | open override func drawExtras(context: CGContext) 535| 9| { 536| 9| drawCircles(context: context) 537| 9| } 538| | 539| | private func drawCircles(context: CGContext) 540| 9| { 541| 9| guard 542| 9| let dataProvider = dataProvider, 543| 9| let lineData = dataProvider.lineData 544| 9| else { return } 545| 9| 546| 9| let phaseY = animator.phaseY 547| 9| 548| 9| let dataSets = lineData.dataSets 549| 9| 550| 9| var pt = CGPoint() 551| 9| var rect = CGRect() 552| 9| 553| 9| // If we redraw the data, remove and repopulate accessible elements to update label values and frames 554| 9| accessibleChartElements.removeAll() 555| 9| accessibilityOrderedElements = accessibilityCreateEmptyOrderedElements() 556| 9| 557| 9| // Make the chart header the first element in the accessible elements array 558| 9| if let chart = dataProvider as? LineChartView { 559| 6| let element = createAccessibleHeader(usingChart: chart, 560| 6| andData: lineData, 561| 6| withDefaultDescription: "Line Chart") 562| 6| accessibleChartElements.append(element) 563| 9| } 564| 9| 565| 9| context.saveGState() 566| 9| 567| 9| for i in 0 ..< dataSets.count 568| 9| { 569| 9| guard let dataSet = lineData.getDataSetByIndex(i) as? ILineChartDataSet else { continue } 570| 9| 571| 9| if !dataSet.isVisible || dataSet.entryCount == 0 572| 9| { 573| 0| continue 574| 9| } 575| 9| 576| 9| let trans = dataProvider.getTransformer(forAxis: dataSet.axisDependency) 577| 9| let valueToPixelMatrix = trans.valueToPixelMatrix 578| 9| 579| 9| _xBounds.set(chart: dataProvider, dataSet: dataSet, animator: animator) 580| 9| 581| 9| let circleRadius = dataSet.circleRadius 582| 9| let circleDiameter = circleRadius * 2.0 583| 9| let circleHoleRadius = dataSet.circleHoleRadius 584| 9| let circleHoleDiameter = circleHoleRadius * 2.0 585| 9| 586| 9| let drawCircleHole = dataSet.isDrawCircleHoleEnabled && 587| 9| circleHoleRadius < circleRadius && 588| 9| circleHoleRadius > 0.0 589| 9| let drawTransparentCircleHole = drawCircleHole && 590| 9| (dataSet.circleHoleColor == nil || 591| 8| dataSet.circleHoleColor == NSUIColor.clear) 592| 9| 593| 9| for j in _xBounds 594| 270| { 595| 270| guard let e = dataSet.entryForIndex(j) else { break } 596| 270| 597| 270| pt.x = CGFloat(e.x) 598| 270| pt.y = CGFloat(e.y * phaseY) 599| 270| pt = pt.applying(valueToPixelMatrix) 600| 270| 601| 270| if (!viewPortHandler.isInBoundsRight(pt.x)) 602| 270| { 603| 0| break 604| 270| } 605| 270| 606| 270| // make sure the circles don't do shitty things outside bounds 607| 270| if (!viewPortHandler.isInBoundsLeft(pt.x) || !viewPortHandler.isInBoundsY(pt.y)) 608| 270| { 609| 0| continue 610| 270| } 611| 270| 612| 270| 613| 270| // Skip Circles and Accessibility if not enabled, 614| 270| // reduces CPU significantly if not needed 615| 270| if !dataSet.isDrawCirclesEnabled 616| 270| { 617| 30| continue 618| 240| } 619| 240| 620| 240| // Accessibility element geometry 621| 240| let scaleFactor: CGFloat = 3 622| 240| let accessibilityRect = CGRect(x: pt.x - (scaleFactor * circleRadius), 623| 240| y: pt.y - (scaleFactor * circleRadius), 624| 240| width: scaleFactor * circleDiameter, 625| 240| height: scaleFactor * circleDiameter) 626| 240| // Create and append the corresponding accessibility element to accessibilityOrderedElements 627| 240| if let chart = dataProvider as? LineChartView 628| 240| { 629| 150| let element = createAccessibleElement(withIndex: j, 630| 150| container: chart, 631| 150| dataSet: dataSet, 632| 150| dataSetIndex: i) 633| 150| { (element) in 634| 150| element.accessibilityFrame = accessibilityRect 635| 150| } 636| 150| 637| 150| accessibilityOrderedElements[i].append(element) 638| 240| } 639| 240| 640| 240| context.setFillColor(dataSet.getCircleColor(atIndex: j)!.cgColor) 641| 240| 642| 240| rect.origin.x = pt.x - circleRadius 643| 240| rect.origin.y = pt.y - circleRadius 644| 240| rect.size.width = circleDiameter 645| 240| rect.size.height = circleDiameter 646| 240| 647| 240| if drawTransparentCircleHole 648| 240| { 649| 0| // Begin path for circle with hole 650| 0| context.beginPath() 651| 0| context.addEllipse(in: rect) 652| 0| 653| 0| // Cut hole in path 654| 0| rect.origin.x = pt.x - circleHoleRadius 655| 0| rect.origin.y = pt.y - circleHoleRadius 656| 0| rect.size.width = circleHoleDiameter 657| 0| rect.size.height = circleHoleDiameter 658| 0| context.addEllipse(in: rect) 659| 0| 660| 0| // Fill in-between 661| 0| context.fillPath(using: .evenOdd) 662| 240| } 663| 240| else 664| 240| { 665| 240| context.fillEllipse(in: rect) 666| 240| 667| 240| if drawCircleHole 668| 240| { 669| 210| context.setFillColor(dataSet.circleHoleColor!.cgColor) 670| 210| 671| 210| // The hole rect 672| 210| rect.origin.x = pt.x - circleHoleRadius 673| 210| rect.origin.y = pt.y - circleHoleRadius 674| 210| rect.size.width = circleHoleDiameter 675| 210| rect.size.height = circleHoleDiameter 676| 210| 677| 210| context.fillEllipse(in: rect) 678| 240| } 679| 240| } 680| 240| } 681| 9| } 682| 9| 683| 9| context.restoreGState() 684| 9| 685| 9| // Merge nested ordered arrays into the single accessibleChartElements. 686| 9| accessibleChartElements.append(contentsOf: accessibilityOrderedElements.flatMap { $0 } ) 687| 9| accessibilityPostLayoutChangedNotification() 688| 9| } 689| | 690| | open override func drawHighlighted(context: CGContext, indices: [Highlight]) 691| 0| { 692| 0| guard 693| 0| let dataProvider = dataProvider, 694| 0| let lineData = dataProvider.lineData 695| 0| else { return } 696| 0| 697| 0| let chartXMax = dataProvider.chartXMax 698| 0| 699| 0| context.saveGState() 700| 0| 701| 0| for high in indices 702| 0| { 703| 0| guard let set = lineData.getDataSetByIndex(high.dataSetIndex) as? ILineChartDataSet 704| 0| , set.isHighlightEnabled 705| 0| else { continue } 706| 0| 707| 0| guard let e = set.entryForXValue(high.x, closestToY: high.y) else { continue } 708| 0| 709| 0| if !isInBoundsX(entry: e, dataSet: set) 710| 0| { 711| 0| continue 712| 0| } 713| 0| 714| 0| context.setStrokeColor(set.highlightColor.cgColor) 715| 0| context.setLineWidth(set.highlightLineWidth) 716| 0| if set.highlightLineDashLengths != nil 717| 0| { 718| 0| context.setLineDash(phase: set.highlightLineDashPhase, lengths: set.highlightLineDashLengths!) 719| 0| } 720| 0| else 721| 0| { 722| 0| context.setLineDash(phase: 0.0, lengths: []) 723| 0| } 724| 0| 725| 0| let x = e.x // get the x-position 726| 0| let y = e.y * Double(animator.phaseY) 727| 0| 728| 0| if x > chartXMax * animator.phaseX 729| 0| { 730| 0| continue 731| 0| } 732| 0| 733| 0| let trans = dataProvider.getTransformer(forAxis: set.axisDependency) 734| 0| 735| 0| let pt = trans.pixelForValues(x: x, y: y) 736| 0| 737| 0| high.setDraw(pt: pt) 738| 0| 739| 0| // draw the lines 740| 0| drawHighlightLines(context: context, point: pt, set: set) 741| 0| } 742| 0| 743| 0| context.restoreGState() 744| 0| } 745| | 746| | /// Creates a nested array of empty subarrays each of which will be populated with NSUIAccessibilityElements. 747| | /// This is marked internal to support HorizontalBarChartRenderer as well. 748| | private func accessibilityCreateEmptyOrderedElements() -> [[NSUIAccessibilityElement]] 749| 9| { 750| 9| guard let chart = dataProvider as? LineChartView else { return [] } 751| 6| 752| 6| let dataSetCount = chart.lineData?.dataSetCount ?? 0 753| 6| 754| 6| return Array(repeating: [NSUIAccessibilityElement](), 755| 6| count: dataSetCount) 756| 9| } 757| | 758| | /// Creates an NSUIAccessibleElement representing the smallest meaningful bar of the chart 759| | /// i.e. in case of a stacked chart, this returns each stack, not the combined bar. 760| | /// Note that it is marked internal to support subclass modification in the HorizontalBarChart. 761| | private func createAccessibleElement(withIndex idx: Int, 762| | container: LineChartView, 763| | dataSet: ILineChartDataSet, 764| | dataSetIndex: Int, 765| | modifier: (NSUIAccessibilityElement) -> ()) -> NSUIAccessibilityElement 766| 150| { 767| 150| let element = NSUIAccessibilityElement(accessibilityContainer: container) 768| 150| let xAxis = container.xAxis 769| 150| 770| 150| guard let e = dataSet.entryForIndex(idx) else { return element } 771| 150| guard let dataProvider = dataProvider else { return element } 772| 150| 773| 150| // NOTE: The formatter can cause issues when the x-axis labels are consecutive ints. 774| 150| // i.e. due to the Double conversion, if there are more than one data set that are grouped, 775| 150| // there is the possibility of some labels being rounded up. A floor() might fix this, but seems to be a brute force solution. 776| 150| let label = xAxis.valueFormatter?.stringForValue(e.x, axis: xAxis) ?? "\(e.x)" 777| 150| 778| 150| let elementValueText = dataSet.valueFormatter?.stringForValue(e.y, 779| 150| entry: e, 780| 150| dataSetIndex: dataSetIndex, 781| 150| viewPortHandler: viewPortHandler) ?? "\(e.y)" 782| 150| 783| 150| let dataSetCount = dataProvider.lineData?.dataSetCount ?? -1 784| 150| let doesContainMultipleDataSets = dataSetCount > 1 785| 150| 786| 150| element.accessibilityLabel = "\(doesContainMultipleDataSets ? (dataSet.label ?? "") + ", " : "") \(label): \(elementValueText)" 787| 150| 788| 150| modifier(element) 789| 150| 790| 150| return element 791| 150| } 792| |} /Users/travis/build/danielgindi/Charts/Source/Charts/Renderers/LineRadarRenderer.swift: 1| |// 2| |// LineRadarRenderer.swift 3| |// Charts 4| |// 5| |// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda 6| |// A port of MPAndroidChart for iOS 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| | 12| |import Foundation 13| |import CoreGraphics 14| | 15| |@objc(LineRadarChartRenderer) 16| |open class LineRadarRenderer: LineScatterCandleRadarRenderer 17| |{ 18| | public override init(animator: Animator, viewPortHandler: ViewPortHandler) 19| 9| { 20| 9| super.init(animator: animator, viewPortHandler: viewPortHandler) 21| 9| } 22| | 23| | /// Draws the provided path in filled mode with the provided drawable. 24| | @objc open func drawFilledPath(context: CGContext, path: CGPath, fill: Fill, fillAlpha: CGFloat) 25| 0| { 26| 0| 27| 0| context.saveGState() 28| 0| context.beginPath() 29| 0| context.addPath(path) 30| 0| 31| 0| // filled is usually drawn with less alpha 32| 0| context.setAlpha(fillAlpha) 33| 0| 34| 0| fill.fillPath(context: context, rect: viewPortHandler.contentRect) 35| 0| 36| 0| context.restoreGState() 37| 0| } 38| | 39| | /// Draws the provided path in filled mode with the provided color and alpha. 40| | @objc open func drawFilledPath(context: CGContext, path: CGPath, fillColor: NSUIColor, fillAlpha: CGFloat) 41| 0| { 42| 0| context.saveGState() 43| 0| context.beginPath() 44| 0| context.addPath(path) 45| 0| 46| 0| // filled is usually drawn with less alpha 47| 0| context.setAlpha(fillAlpha) 48| 0| 49| 0| context.setFillColor(fillColor.cgColor) 50| 0| context.fillPath() 51| 0| 52| 0| context.restoreGState() 53| 0| } 54| |} /Users/travis/build/danielgindi/Charts/Source/Charts/Renderers/LineScatterCandleRadarRenderer.swift: 1| |// 2| |// LineScatterCandleRadarRenderer.swift 3| |// Charts 4| |// 5| |// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda 6| |// A port of MPAndroidChart for iOS 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| | 12| |import Foundation 13| |import CoreGraphics 14| | 15| |@objc(LineScatterCandleRadarChartRenderer) 16| |open class LineScatterCandleRadarRenderer: BarLineScatterCandleBubbleRenderer 17| |{ 18| | public override init(animator: Animator, viewPortHandler: ViewPortHandler) 19| 9| { 20| 9| super.init(animator: animator, viewPortHandler: viewPortHandler) 21| 9| } 22| | 23| | /// Draws vertical & horizontal highlight-lines if enabled. 24| | /// :param: context 25| | /// :param: points 26| | /// :param: horizontal 27| | /// :param: vertical 28| | @objc open func drawHighlightLines(context: CGContext, point: CGPoint, set: ILineScatterCandleRadarChartDataSet) 29| 0| { 30| 0| 31| 0| // draw vertical highlight lines 32| 0| if set.isVerticalHighlightIndicatorEnabled 33| 0| { 34| 0| context.beginPath() 35| 0| context.move(to: CGPoint(x: point.x, y: viewPortHandler.contentTop)) 36| 0| context.addLine(to: CGPoint(x: point.x, y: viewPortHandler.contentBottom)) 37| 0| context.strokePath() 38| 0| } 39| 0| 40| 0| // draw horizontal highlight lines 41| 0| if set.isHorizontalHighlightIndicatorEnabled 42| 0| { 43| 0| context.beginPath() 44| 0| context.move(to: CGPoint(x: viewPortHandler.contentLeft, y: point.y)) 45| 0| context.addLine(to: CGPoint(x: viewPortHandler.contentRight, y: point.y)) 46| 0| context.strokePath() 47| 0| } 48| 0| } 49| |} /Users/travis/build/danielgindi/Charts/Source/Charts/Renderers/PieChartRenderer.swift: 1| |// 2| |// PieChartRenderer.swift 3| |// Charts 4| |// 5| |// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda 6| |// A port of MPAndroidChart for iOS 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| | 12| |import Foundation 13| |import CoreGraphics 14| | 15| |#if canImport(UIKit) 16| | import UIKit 17| |#endif 18| | 19| |#if canImport(Cocoa) 20| |import Cocoa 21| |#endif 22| | 23| |open class PieChartRenderer: DataRenderer 24| |{ 25| | @objc open weak var chart: PieChartView? 26| | 27| | @objc public init(chart: PieChartView, animator: Animator, viewPortHandler: ViewPortHandler) 28| 6| { 29| 6| super.init(animator: animator, viewPortHandler: viewPortHandler) 30| 6| 31| 6| self.chart = chart 32| 6| } 33| | 34| | open override func drawData(context: CGContext) 35| 6| { 36| 6| guard let chart = chart else { return } 37| 6| 38| 6| let pieData = chart.data 39| 6| 40| 6| if pieData != nil 41| 6| { 42| 6| // If we redraw the data, remove and repopulate accessible elements to update label values and frames 43| 6| accessibleChartElements.removeAll() 44| 6| 45| 6| for set in pieData!.dataSets as! [IPieChartDataSet] 46| 6| where set.isVisible && set.entryCount > 0 47| 6| { 48| 6| drawDataSet(context: context, dataSet: set) 49| 6| } 50| 6| } 51| 6| } 52| | 53| | @objc open func calculateMinimumRadiusForSpacedSlice( 54| | center: CGPoint, 55| | radius: CGFloat, 56| | angle: CGFloat, 57| | arcStartPointX: CGFloat, 58| | arcStartPointY: CGFloat, 59| | startAngle: CGFloat, 60| | sweepAngle: CGFloat) -> CGFloat 61| 0| { 62| 0| let angleMiddle = startAngle + sweepAngle / 2.0 63| 0| 64| 0| // Other point of the arc 65| 0| let arcEndPointX = center.x + radius * cos((startAngle + sweepAngle).DEG2RAD) 66| 0| let arcEndPointY = center.y + radius * sin((startAngle + sweepAngle).DEG2RAD) 67| 0| 68| 0| // Middle point on the arc 69| 0| let arcMidPointX = center.x + radius * cos(angleMiddle.DEG2RAD) 70| 0| let arcMidPointY = center.y + radius * sin(angleMiddle.DEG2RAD) 71| 0| 72| 0| // This is the base of the contained triangle 73| 0| let basePointsDistance = sqrt( 74| 0| pow(arcEndPointX - arcStartPointX, 2) + 75| 0| pow(arcEndPointY - arcStartPointY, 2)) 76| 0| 77| 0| // After reducing space from both sides of the "slice", 78| 0| // the angle of the contained triangle should stay the same. 79| 0| // So let's find out the height of that triangle. 80| 0| let containedTriangleHeight = (basePointsDistance / 2.0 * 81| 0| tan((180.0 - angle).DEG2RAD / 2.0)) 82| 0| 83| 0| // Now we subtract that from the radius 84| 0| var spacedRadius = radius - containedTriangleHeight 85| 0| 86| 0| // And now subtract the height of the arc that's between the triangle and the outer circle 87| 0| spacedRadius -= sqrt( 88| 0| pow(arcMidPointX - (arcEndPointX + arcStartPointX) / 2.0, 2) + 89| 0| pow(arcMidPointY - (arcEndPointY + arcStartPointY) / 2.0, 2)) 90| 0| 91| 0| return spacedRadius 92| 0| } 93| | 94| | /// Calculates the sliceSpace to use based on visible values and their size compared to the set sliceSpace. 95| | @objc open func getSliceSpace(dataSet: IPieChartDataSet) -> CGFloat 96| 48| { 97| 48| guard 98| 48| dataSet.automaticallyDisableSliceSpacing, 99| 48| let data = chart?.data as? PieChartData 100| 48| else { return dataSet.sliceSpace } 101| 0| 102| 0| let spaceSizeRatio = dataSet.sliceSpace / min(viewPortHandler.contentWidth, viewPortHandler.contentHeight) 103| 0| let minValueRatio = dataSet.yMin / data.yValueSum * 2.0 104| 0| 105| 0| let sliceSpace = spaceSizeRatio > CGFloat(minValueRatio) 106| 0| ? 0.0 107| 0| : dataSet.sliceSpace 108| 0| 109| 0| return sliceSpace 110| 48| } 111| | 112| | @objc open func drawDataSet(context: CGContext, dataSet: IPieChartDataSet) 113| 6| { 114| 6| guard let chart = chart else {return } 115| 6| 116| 6| var angle: CGFloat = 0.0 117| 6| let rotationAngle = chart.rotationAngle 118| 6| 119| 6| let phaseX = animator.phaseX 120| 6| let phaseY = animator.phaseY 121| 6| 122| 6| let entryCount = dataSet.entryCount 123| 6| let drawAngles = chart.drawAngles 124| 6| let center = chart.centerCircleBox 125| 6| let radius = chart.radius 126| 6| let drawInnerArc = chart.drawHoleEnabled && !chart.drawSlicesUnderHoleEnabled 127| 6| let userInnerRadius = drawInnerArc ? radius * chart.holeRadiusPercent : 0.0 128| 6| 129| 6| var visibleAngleCount = 0 130| 6| for j in 0 ..< entryCount 131| 42| { 132| 42| guard let e = dataSet.entryForIndex(j) else { continue } 133| 42| if ((abs(e.y) > Double.ulpOfOne)) 134| 42| { 135| 42| visibleAngleCount += 1 136| 42| } 137| 42| } 138| 6| 139| 6| let sliceSpace = visibleAngleCount <= 1 ? 0.0 : getSliceSpace(dataSet: dataSet) 140| 6| 141| 6| context.saveGState() 142| 6| 143| 6| // Make the chart header the first element in the accessible elements array 144| 6| // We can do this in drawDataSet, since we know PieChartView can have only 1 dataSet 145| 6| // Also since there's only 1 dataset, we don't use the typical createAccessibleHeader() here. 146| 6| // NOTE: - Since we want to summarize the total count of slices/portions/elements, use a default string here 147| 6| // This is unlike when we are naming individual slices, wherein it's alright to not use a prefix as descriptor. 148| 6| // i.e. We want to VO to say "3 Elements" even if the developer didn't specify an accessibility prefix 149| 6| // If prefix is unspecified it is safe to assume they did not want to use "Element 1", so that uses a default empty string 150| 6| let prefix: String = chart.data?.accessibilityEntryLabelPrefix ?? "Element" 151| 6| let description = chart.chartDescription?.text ?? dataSet.label ?? chart.centerText ?? "Pie Chart" 152| 6| 153| 6| let 154| 6| element = NSUIAccessibilityElement(accessibilityContainer: chart) 155| 6| element.accessibilityLabel = description + ". \(entryCount) \(prefix + (entryCount == 1 ? "" : "s"))" 156| 6| element.accessibilityFrame = chart.bounds 157| 6| element.isHeader = true 158| 6| accessibleChartElements.append(element) 159| 6| 160| 6| for j in 0 ..< entryCount 161| 42| { 162| 42| let sliceAngle = drawAngles[j] 163| 42| var innerRadius = userInnerRadius 164| 42| 165| 42| guard let e = dataSet.entryForIndex(j) else { continue } 166| 42| 167| 42| defer 168| 42| { 169| 42| // From here on, even when skipping (i.e for highlight), 170| 42| // increase the angle 171| 42| angle += sliceAngle * CGFloat(phaseX) 172| 42| } 173| 42| 174| 42| // draw only if the value is greater than zero 175| 42| if abs(e.y) < Double.ulpOfOne { continue } 176| 42| 177| 42| // Skip if highlighted 178| 42| if dataSet.isHighlightEnabled && chart.needsHighlight(index: j) 179| 42| { 180| 1| continue 181| 41| } 182| 41| 183| 41| let accountForSliceSpacing = sliceSpace > 0.0 && sliceAngle <= 180.0 184| 41| 185| 41| context.setFillColor(dataSet.color(atIndex: j).cgColor) 186| 41| 187| 41| let sliceSpaceAngleOuter = visibleAngleCount == 1 ? 188| 41| 0.0 : 189| 41| sliceSpace / radius.DEG2RAD 190| 41| let startAngleOuter = rotationAngle + (angle + sliceSpaceAngleOuter / 2.0) * CGFloat(phaseY) 191| 41| var sweepAngleOuter = (sliceAngle - sliceSpaceAngleOuter) * CGFloat(phaseY) 192| 41| if sweepAngleOuter < 0.0 193| 41| { 194| 0| sweepAngleOuter = 0.0 195| 41| } 196| 41| 197| 41| let arcStartPointX = center.x + radius * cos(startAngleOuter.DEG2RAD) 198| 41| let arcStartPointY = center.y + radius * sin(startAngleOuter.DEG2RAD) 199| 41| 200| 41| let path = CGMutablePath() 201| 41| 202| 41| path.move(to: CGPoint(x: arcStartPointX, 203| 41| y: arcStartPointY)) 204| 41| 205| 41| path.addRelativeArc(center: center, radius: radius, startAngle: startAngleOuter.DEG2RAD, delta: sweepAngleOuter.DEG2RAD) 206| 41| 207| 41| if drawInnerArc && 208| 41| (innerRadius > 0.0 || accountForSliceSpacing) 209| 41| { 210| 41| if accountForSliceSpacing 211| 41| { 212| 0| var minSpacedRadius = calculateMinimumRadiusForSpacedSlice( 213| 0| center: center, 214| 0| radius: radius, 215| 0| angle: sliceAngle * CGFloat(phaseY), 216| 0| arcStartPointX: arcStartPointX, 217| 0| arcStartPointY: arcStartPointY, 218| 0| startAngle: startAngleOuter, 219| 0| sweepAngle: sweepAngleOuter) 220| 0| if minSpacedRadius < 0.0 221| 0| { 222| 0| minSpacedRadius = -minSpacedRadius 223| 0| } 224| 0| innerRadius = min(max(innerRadius, minSpacedRadius), radius) 225| 41| } 226| 41| 227| 41| let sliceSpaceAngleInner = visibleAngleCount == 1 || innerRadius == 0.0 ? 228| 41| 0.0 : 229| 41| sliceSpace / innerRadius.DEG2RAD 230| 41| let startAngleInner = rotationAngle + (angle + sliceSpaceAngleInner / 2.0) * CGFloat(phaseY) 231| 41| var sweepAngleInner = (sliceAngle - sliceSpaceAngleInner) * CGFloat(phaseY) 232| 41| if sweepAngleInner < 0.0 233| 41| { 234| 0| sweepAngleInner = 0.0 235| 41| } 236| 41| let endAngleInner = startAngleInner + sweepAngleInner 237| 41| 238| 41| path.addLine( 239| 41| to: CGPoint( 240| 41| x: center.x + innerRadius * cos(endAngleInner.DEG2RAD), 241| 41| y: center.y + innerRadius * sin(endAngleInner.DEG2RAD))) 242| 41| 243| 41| path.addRelativeArc(center: center, radius: innerRadius, startAngle: endAngleInner.DEG2RAD, delta: -sweepAngleInner.DEG2RAD) 244| 41| } 245| 41| else 246| 41| { 247| 0| if accountForSliceSpacing 248| 0| { 249| 0| let angleMiddle = startAngleOuter + sweepAngleOuter / 2.0 250| 0| 251| 0| let sliceSpaceOffset = 252| 0| calculateMinimumRadiusForSpacedSlice( 253| 0| center: center, 254| 0| radius: radius, 255| 0| angle: sliceAngle * CGFloat(phaseY), 256| 0| arcStartPointX: arcStartPointX, 257| 0| arcStartPointY: arcStartPointY, 258| 0| startAngle: startAngleOuter, 259| 0| sweepAngle: sweepAngleOuter) 260| 0| 261| 0| let arcEndPointX = center.x + sliceSpaceOffset * cos(angleMiddle.DEG2RAD) 262| 0| let arcEndPointY = center.y + sliceSpaceOffset * sin(angleMiddle.DEG2RAD) 263| 0| 264| 0| path.addLine( 265| 0| to: CGPoint( 266| 0| x: arcEndPointX, 267| 0| y: arcEndPointY)) 268| 0| } 269| 0| else 270| 0| { 271| 0| path.addLine(to: center) 272| 0| } 273| 41| } 274| 41| 275| 41| path.closeSubpath() 276| 41| 277| 41| context.beginPath() 278| 41| context.addPath(path) 279| 41| context.fillPath(using: .evenOdd) 280| 41| 281| 41| let axElement = createAccessibleElement(withIndex: j, 282| 41| container: chart, 283| 41| dataSet: dataSet) 284| 41| { (element) in 285| 41| element.accessibilityFrame = path.boundingBoxOfPath 286| 41| } 287| 41| 288| 41| accessibleChartElements.append(axElement) 289| 41| } 290| 6| 291| 6| // Post this notification to let VoiceOver account for the redrawn frames 292| 6| accessibilityPostLayoutChangedNotification() 293| 6| 294| 6| context.restoreGState() 295| 6| } 296| | 297| | open override func drawValues(context: CGContext) 298| 6| { 299| 6| guard 300| 6| let chart = chart, 301| 6| let data = chart.data 302| 6| else { return } 303| 6| 304| 6| let center = chart.centerCircleBox 305| 6| 306| 6| // get whole the radius 307| 6| let radius = chart.radius 308| 6| let rotationAngle = chart.rotationAngle 309| 6| let drawAngles = chart.drawAngles 310| 6| let absoluteAngles = chart.absoluteAngles 311| 6| 312| 6| let phaseX = animator.phaseX 313| 6| let phaseY = animator.phaseY 314| 6| 315| 6| var labelRadiusOffset = radius / 10.0 * 3.0 316| 6| 317| 6| if chart.drawHoleEnabled 318| 6| { 319| 6| labelRadiusOffset = (radius - (radius * chart.holeRadiusPercent)) / 2.0 320| 6| } 321| 6| 322| 6| let labelRadius = radius - labelRadiusOffset 323| 6| 324| 6| let dataSets = data.dataSets 325| 6| 326| 6| let yValueSum = (data as! PieChartData).yValueSum 327| 6| 328| 6| let drawEntryLabels = chart.isDrawEntryLabelsEnabled 329| 6| let usePercentValuesEnabled = chart.usePercentValuesEnabled 330| 6| 331| 6| var angle: CGFloat = 0.0 332| 6| var xIndex = 0 333| 6| 334| 6| context.saveGState() 335| 6| defer { context.restoreGState() } 336| 6| 337| 6| for i in 0 ..< dataSets.count 338| 6| { 339| 6| guard let dataSet = dataSets[i] as? IPieChartDataSet else { continue } 340| 6| 341| 6| let drawValues = dataSet.isDrawValuesEnabled 342| 6| 343| 6| if !drawValues && !drawEntryLabels && !dataSet.isDrawIconsEnabled 344| 6| { 345| 0| continue 346| 6| } 347| 6| 348| 6| let iconsOffset = dataSet.iconsOffset 349| 6| 350| 6| let xValuePosition = dataSet.xValuePosition 351| 6| let yValuePosition = dataSet.yValuePosition 352| 6| 353| 6| let valueFont = dataSet.valueFont 354| 6| let entryLabelFont = dataSet.entryLabelFont ?? chart.entryLabelFont 355| 6| let lineHeight = valueFont.lineHeight 356| 6| 357| 6| guard let formatter = dataSet.valueFormatter else { continue } 358| 6| 359| 6| for j in 0 ..< dataSet.entryCount 360| 42| { 361| 42| guard let e = dataSet.entryForIndex(j) else { continue } 362| 42| let pe = e as? PieChartDataEntry 363| 42| 364| 42| if xIndex == 0 365| 42| { 366| 6| angle = 0.0 367| 42| } 368| 42| else 369| 42| { 370| 36| angle = absoluteAngles[xIndex - 1] * CGFloat(phaseX) 371| 42| } 372| 42| 373| 42| let sliceAngle = drawAngles[xIndex] 374| 42| let sliceSpace = getSliceSpace(dataSet: dataSet) 375| 42| let sliceSpaceMiddleAngle = sliceSpace / labelRadius.DEG2RAD 376| 42| 377| 42| // offset needed to center the drawn text in the slice 378| 42| let angleOffset = (sliceAngle - sliceSpaceMiddleAngle / 2.0) / 2.0 379| 42| 380| 42| angle = angle + angleOffset 381| 42| 382| 42| let transformedAngle = rotationAngle + angle * CGFloat(phaseY) 383| 42| 384| 42| let value = usePercentValuesEnabled ? e.y / yValueSum * 100.0 : e.y 385| 42| let valueText = formatter.stringForValue( 386| 42| value, 387| 42| entry: e, 388| 42| dataSetIndex: i, 389| 42| viewPortHandler: viewPortHandler) 390| 42| 391| 42| let sliceXBase = cos(transformedAngle.DEG2RAD) 392| 42| let sliceYBase = sin(transformedAngle.DEG2RAD) 393| 42| 394| 42| let drawXOutside = drawEntryLabels && xValuePosition == .outsideSlice 395| 42| let drawYOutside = drawValues && yValuePosition == .outsideSlice 396| 42| let drawXInside = drawEntryLabels && xValuePosition == .insideSlice 397| 42| let drawYInside = drawValues && yValuePosition == .insideSlice 398| 42| 399| 42| let valueTextColor = dataSet.valueTextColorAt(j) 400| 42| let entryLabelColor = dataSet.entryLabelColor ?? chart.entryLabelColor 401| 42| 402| 42| if drawXOutside || drawYOutside 403| 42| { 404| 0| let valueLineLength1 = dataSet.valueLinePart1Length 405| 0| let valueLineLength2 = dataSet.valueLinePart2Length 406| 0| let valueLinePart1OffsetPercentage = dataSet.valueLinePart1OffsetPercentage 407| 0| 408| 0| var pt2: CGPoint 409| 0| var labelPoint: CGPoint 410| 0| var align: NSTextAlignment 411| 0| 412| 0| var line1Radius: CGFloat 413| 0| 414| 0| if chart.drawHoleEnabled 415| 0| { 416| 0| line1Radius = (radius - (radius * chart.holeRadiusPercent)) * valueLinePart1OffsetPercentage + (radius * chart.holeRadiusPercent) 417| 0| } 418| 0| else 419| 0| { 420| 0| line1Radius = radius * valueLinePart1OffsetPercentage 421| 0| } 422| 0| 423| 0| let polyline2Length = dataSet.valueLineVariableLength 424| 0| ? labelRadius * valueLineLength2 * abs(sin(transformedAngle.DEG2RAD)) 425| 0| : labelRadius * valueLineLength2 426| 0| 427| 0| let pt0 = CGPoint( 428| 0| x: line1Radius * sliceXBase + center.x, 429| 0| y: line1Radius * sliceYBase + center.y) 430| 0| 431| 0| let pt1 = CGPoint( 432| 0| x: labelRadius * (1 + valueLineLength1) * sliceXBase + center.x, 433| 0| y: labelRadius * (1 + valueLineLength1) * sliceYBase + center.y) 434| 0| 435| 0| if transformedAngle.truncatingRemainder(dividingBy: 360.0) >= 90.0 && transformedAngle.truncatingRemainder(dividingBy: 360.0) <= 270.0 436| 0| { 437| 0| pt2 = CGPoint(x: pt1.x - polyline2Length, y: pt1.y) 438| 0| align = .right 439| 0| labelPoint = CGPoint(x: pt2.x - 5, y: pt2.y - lineHeight) 440| 0| } 441| 0| else 442| 0| { 443| 0| pt2 = CGPoint(x: pt1.x + polyline2Length, y: pt1.y) 444| 0| align = .left 445| 0| labelPoint = CGPoint(x: pt2.x + 5, y: pt2.y - lineHeight) 446| 0| } 447| 0| 448| 0| DrawLine: do 449| 0| { 450| 0| if dataSet.useValueColorForLine 451| 0| { 452| 0| context.setStrokeColor(dataSet.color(atIndex: j).cgColor) 453| 0| } 454| 0| else if let valueLineColor = dataSet.valueLineColor 455| 0| { 456| 0| context.setStrokeColor(valueLineColor.cgColor) 457| 0| } 458| 0| else 459| 0| { 460| 0| return 461| 0| } 462| 0| context.setLineWidth(dataSet.valueLineWidth) 463| 0| 464| 0| context.move(to: CGPoint(x: pt0.x, y: pt0.y)) 465| 0| context.addLine(to: CGPoint(x: pt1.x, y: pt1.y)) 466| 0| context.addLine(to: CGPoint(x: pt2.x, y: pt2.y)) 467| 0| 468| 0| context.drawPath(using: CGPathDrawingMode.stroke) 469| 0| } 470| 0| 471| 0| if drawXOutside && drawYOutside 472| 0| { 473| 0| ChartUtils.drawText( 474| 0| context: context, 475| 0| text: valueText, 476| 0| point: labelPoint, 477| 0| align: align, 478| 0| attributes: [NSAttributedString.Key.font: valueFont, NSAttributedString.Key.foregroundColor: valueTextColor] 479| 0| ) 480| 0| 481| 0| if j < data.entryCount && pe?.label != nil 482| 0| { 483| 0| ChartUtils.drawText( 484| 0| context: context, 485| 0| text: pe!.label!, 486| 0| point: CGPoint(x: labelPoint.x, y: labelPoint.y + lineHeight), 487| 0| align: align, 488| 0| attributes: [ 489| 0| NSAttributedString.Key.font: entryLabelFont ?? valueFont, 490| 0| NSAttributedString.Key.foregroundColor: entryLabelColor ?? valueTextColor] 491| 0| ) 492| 0| } 493| 0| } 494| 0| else if drawXOutside 495| 0| { 496| 0| if j < data.entryCount && pe?.label != nil 497| 0| { 498| 0| ChartUtils.drawText( 499| 0| context: context, 500| 0| text: pe!.label!, 501| 0| point: CGPoint(x: labelPoint.x, y: labelPoint.y + lineHeight / 2.0), 502| 0| align: align, 503| 0| attributes: [ 504| 0| NSAttributedString.Key.font: entryLabelFont ?? valueFont, 505| 0| NSAttributedString.Key.foregroundColor: entryLabelColor ?? valueTextColor] 506| 0| ) 507| 0| } 508| 0| } 509| 0| else if drawYOutside 510| 0| { 511| 0| ChartUtils.drawText( 512| 0| context: context, 513| 0| text: valueText, 514| 0| point: CGPoint(x: labelPoint.x, y: labelPoint.y + lineHeight / 2.0), 515| 0| align: align, 516| 0| attributes: [NSAttributedString.Key.font: valueFont, NSAttributedString.Key.foregroundColor: valueTextColor] 517| 0| ) 518| 0| } 519| 42| } 520| 42| 521| 42| if drawXInside || drawYInside 522| 42| { 523| 42| // calculate the text position 524| 42| let x = labelRadius * sliceXBase + center.x 525| 42| let y = labelRadius * sliceYBase + center.y - lineHeight 526| 42| 527| 42| if drawXInside && drawYInside 528| 42| { 529| 35| ChartUtils.drawText( 530| 35| context: context, 531| 35| text: valueText, 532| 35| point: CGPoint(x: x, y: y), 533| 35| align: .center, 534| 35| attributes: [NSAttributedString.Key.font: valueFont, NSAttributedString.Key.foregroundColor: valueTextColor] 535| 35| ) 536| 35| 537| 35| if j < data.entryCount && pe?.label != nil 538| 35| { 539| 0| ChartUtils.drawText( 540| 0| context: context, 541| 0| text: pe!.label!, 542| 0| point: CGPoint(x: x, y: y + lineHeight), 543| 0| align: .center, 544| 0| attributes: [ 545| 0| NSAttributedString.Key.font: entryLabelFont ?? valueFont, 546| 0| NSAttributedString.Key.foregroundColor: entryLabelColor ?? valueTextColor] 547| 0| ) 548| 35| } 549| 42| } 550| 42| else if drawXInside 551| 42| { 552| 7| if j < data.entryCount && pe?.label != nil 553| 7| { 554| 0| ChartUtils.drawText( 555| 0| context: context, 556| 0| text: pe!.label!, 557| 0| point: CGPoint(x: x, y: y + lineHeight / 2.0), 558| 0| align: .center, 559| 0| attributes: [ 560| 0| NSAttributedString.Key.font: entryLabelFont ?? valueFont, 561| 0| NSAttributedString.Key.foregroundColor: entryLabelColor ?? valueTextColor] 562| 0| ) 563| 7| } 564| 42| } 565| 42| else if drawYInside 566| 42| { 567| 0| ChartUtils.drawText( 568| 0| context: context, 569| 0| text: valueText, 570| 0| point: CGPoint(x: x, y: y + lineHeight / 2.0), 571| 0| align: .center, 572| 0| attributes: [NSAttributedString.Key.font: valueFont, NSAttributedString.Key.foregroundColor: valueTextColor] 573| 0| ) 574| 42| } 575| 42| } 576| 42| 577| 42| if let icon = e.icon, dataSet.isDrawIconsEnabled 578| 42| { 579| 7| // calculate the icon's position 580| 7| 581| 7| let x = (labelRadius + iconsOffset.y) * sliceXBase + center.x 582| 7| var y = (labelRadius + iconsOffset.y) * sliceYBase + center.y 583| 7| y += iconsOffset.x 584| 7| 585| 7| ChartUtils.drawImage(context: context, 586| 7| image: icon, 587| 7| x: x, 588| 7| y: y, 589| 7| size: icon.size) 590| 42| } 591| 42| 592| 42| xIndex += 1 593| 42| } 594| 6| } 595| 6| } 596| | 597| | open override func drawExtras(context: CGContext) 598| 6| { 599| 6| drawHole(context: context) 600| 6| drawCenterText(context: context) 601| 6| } 602| | 603| | /// draws the hole in the center of the chart and the transparent circle / hole 604| | private func drawHole(context: CGContext) 605| 6| { 606| 6| guard let chart = chart else { return } 607| 6| 608| 6| if chart.drawHoleEnabled 609| 6| { 610| 6| context.saveGState() 611| 6| 612| 6| let radius = chart.radius 613| 6| let holeRadius = radius * chart.holeRadiusPercent 614| 6| let center = chart.centerCircleBox 615| 6| 616| 6| if let holeColor = chart.holeColor 617| 6| { 618| 6| if holeColor != NSUIColor.clear 619| 6| { 620| 6| // draw the hole-circle 621| 6| context.setFillColor(chart.holeColor!.cgColor) 622| 6| context.fillEllipse(in: CGRect(x: center.x - holeRadius, y: center.y - holeRadius, width: holeRadius * 2.0, height: holeRadius * 2.0)) 623| 6| } 624| 6| } 625| 6| 626| 6| // only draw the circle if it can be seen (not covered by the hole) 627| 6| if let transparentCircleColor = chart.transparentCircleColor 628| 6| { 629| 6| if transparentCircleColor != NSUIColor.clear && 630| 6| chart.transparentCircleRadiusPercent > chart.holeRadiusPercent 631| 6| { 632| 6| let alpha = animator.phaseX * animator.phaseY 633| 6| let secondHoleRadius = radius * chart.transparentCircleRadiusPercent 634| 6| 635| 6| // make transparent 636| 6| context.setAlpha(CGFloat(alpha)) 637| 6| context.setFillColor(transparentCircleColor.cgColor) 638| 6| 639| 6| // draw the transparent-circle 640| 6| context.beginPath() 641| 6| context.addEllipse(in: CGRect( 642| 6| x: center.x - secondHoleRadius, 643| 6| y: center.y - secondHoleRadius, 644| 6| width: secondHoleRadius * 2.0, 645| 6| height: secondHoleRadius * 2.0)) 646| 6| context.addEllipse(in: CGRect( 647| 6| x: center.x - holeRadius, 648| 6| y: center.y - holeRadius, 649| 6| width: holeRadius * 2.0, 650| 6| height: holeRadius * 2.0)) 651| 6| context.fillPath(using: .evenOdd) 652| 6| } 653| 6| } 654| 6| 655| 6| context.restoreGState() 656| 6| } 657| 6| } 658| | 659| | /// draws the description text in the center of the pie chart makes most sense when center-hole is enabled 660| | private func drawCenterText(context: CGContext) 661| 6| { 662| 6| guard 663| 6| let chart = chart, 664| 6| let centerAttributedText = chart.centerAttributedText 665| 6| else { return } 666| 6| 667| 6| if chart.drawCenterTextEnabled && centerAttributedText.length > 0 668| 6| { 669| 5| let center = chart.centerCircleBox 670| 5| let offset = chart.centerTextOffset 671| 5| let innerRadius = chart.drawHoleEnabled && !chart.drawSlicesUnderHoleEnabled ? chart.radius * chart.holeRadiusPercent : chart.radius 672| 5| 673| 5| let x = center.x + offset.x 674| 5| let y = center.y + offset.y 675| 5| 676| 5| let holeRect = CGRect( 677| 5| x: x - innerRadius, 678| 5| y: y - innerRadius, 679| 5| width: innerRadius * 2.0, 680| 5| height: innerRadius * 2.0) 681| 5| var boundingRect = holeRect 682| 5| 683| 5| if chart.centerTextRadiusPercent > 0.0 684| 5| { 685| 5| boundingRect = boundingRect.insetBy(dx: (boundingRect.width - boundingRect.width * chart.centerTextRadiusPercent) / 2.0, dy: (boundingRect.height - boundingRect.height * chart.centerTextRadiusPercent) / 2.0) 686| 5| } 687| 5| 688| 5| let textBounds = centerAttributedText.boundingRect(with: boundingRect.size, options: [.usesLineFragmentOrigin, .usesFontLeading, .truncatesLastVisibleLine], context: nil) 689| 5| 690| 5| var drawingRect = boundingRect 691| 5| drawingRect.origin.x += (boundingRect.size.width - textBounds.size.width) / 2.0 692| 5| drawingRect.origin.y += (boundingRect.size.height - textBounds.size.height) / 2.0 693| 5| drawingRect.size = textBounds.size 694| 5| 695| 5| context.saveGState() 696| 5| 697| 5| let clippingPath = CGPath(ellipseIn: holeRect, transform: nil) 698| 5| context.beginPath() 699| 5| context.addPath(clippingPath) 700| 5| context.clip() 701| 5| 702| 5| centerAttributedText.draw(with: drawingRect, options: [.usesLineFragmentOrigin, .usesFontLeading, .truncatesLastVisibleLine], context: nil) 703| 5| 704| 5| context.restoreGState() 705| 6| } 706| 6| } 707| | 708| | open override func drawHighlighted(context: CGContext, indices: [Highlight]) 709| 2| { 710| 2| guard 711| 2| let chart = chart, 712| 2| let data = chart.data 713| 2| else { return } 714| 2| 715| 2| context.saveGState() 716| 2| 717| 2| let phaseX = animator.phaseX 718| 2| let phaseY = animator.phaseY 719| 2| 720| 2| var angle: CGFloat = 0.0 721| 2| let rotationAngle = chart.rotationAngle 722| 2| 723| 2| let drawAngles = chart.drawAngles 724| 2| let absoluteAngles = chart.absoluteAngles 725| 2| let center = chart.centerCircleBox 726| 2| let radius = chart.radius 727| 2| let drawInnerArc = chart.drawHoleEnabled && !chart.drawSlicesUnderHoleEnabled 728| 2| let userInnerRadius = drawInnerArc ? radius * chart.holeRadiusPercent : 0.0 729| 2| 730| 2| // Append highlighted accessibility slices into this array, so we can prioritize them over unselected slices 731| 2| var highlightedAccessibleElements: [NSUIAccessibilityElement] = [] 732| 2| 733| 2| for i in 0 ..< indices.count 734| 2| { 735| 2| // get the index to highlight 736| 2| let index = Int(indices[i].x) 737| 2| if index >= drawAngles.count 738| 2| { 739| 0| continue 740| 2| } 741| 2| 742| 2| guard let set = data.getDataSetByIndex(indices[i].dataSetIndex) as? IPieChartDataSet else { continue } 743| 2| 744| 2| if !set.isHighlightEnabled { continue } 745| 1| 746| 1| let entryCount = set.entryCount 747| 1| var visibleAngleCount = 0 748| 1| for j in 0 ..< entryCount 749| 7| { 750| 7| guard let e = set.entryForIndex(j) else { continue } 751| 7| if ((abs(e.y) > Double.ulpOfOne)) 752| 7| { 753| 7| visibleAngleCount += 1 754| 7| } 755| 7| } 756| 1| 757| 1| if index == 0 758| 1| { 759| 0| angle = 0.0 760| 1| } 761| 1| else 762| 1| { 763| 1| angle = absoluteAngles[index - 1] * CGFloat(phaseX) 764| 1| } 765| 1| 766| 1| let sliceSpace = visibleAngleCount <= 1 ? 0.0 : set.sliceSpace 767| 1| 768| 1| let sliceAngle = drawAngles[index] 769| 1| var innerRadius = userInnerRadius 770| 1| 771| 1| let shift = set.selectionShift 772| 1| let highlightedRadius = radius + shift 773| 1| 774| 1| let accountForSliceSpacing = sliceSpace > 0.0 && sliceAngle <= 180.0 775| 1| 776| 1| context.setFillColor(set.highlightColor?.cgColor ?? set.color(atIndex: index).cgColor) 777| 1| 778| 1| let sliceSpaceAngleOuter = visibleAngleCount == 1 ? 779| 1| 0.0 : 780| 1| sliceSpace / radius.DEG2RAD 781| 1| 782| 1| let sliceSpaceAngleShifted = visibleAngleCount == 1 ? 783| 1| 0.0 : 784| 1| sliceSpace / highlightedRadius.DEG2RAD 785| 1| 786| 1| let startAngleOuter = rotationAngle + (angle + sliceSpaceAngleOuter / 2.0) * CGFloat(phaseY) 787| 1| var sweepAngleOuter = (sliceAngle - sliceSpaceAngleOuter) * CGFloat(phaseY) 788| 1| if sweepAngleOuter < 0.0 789| 1| { 790| 0| sweepAngleOuter = 0.0 791| 1| } 792| 1| 793| 1| let startAngleShifted = rotationAngle + (angle + sliceSpaceAngleShifted / 2.0) * CGFloat(phaseY) 794| 1| var sweepAngleShifted = (sliceAngle - sliceSpaceAngleShifted) * CGFloat(phaseY) 795| 1| if sweepAngleShifted < 0.0 796| 1| { 797| 0| sweepAngleShifted = 0.0 798| 1| } 799| 1| 800| 1| let path = CGMutablePath() 801| 1| 802| 1| path.move(to: CGPoint(x: center.x + highlightedRadius * cos(startAngleShifted.DEG2RAD), 803| 1| y: center.y + highlightedRadius * sin(startAngleShifted.DEG2RAD))) 804| 1| 805| 1| path.addRelativeArc(center: center, radius: highlightedRadius, startAngle: startAngleShifted.DEG2RAD, 806| 1| delta: sweepAngleShifted.DEG2RAD) 807| 1| 808| 1| var sliceSpaceRadius: CGFloat = 0.0 809| 1| if accountForSliceSpacing 810| 1| { 811| 0| sliceSpaceRadius = calculateMinimumRadiusForSpacedSlice( 812| 0| center: center, 813| 0| radius: radius, 814| 0| angle: sliceAngle * CGFloat(phaseY), 815| 0| arcStartPointX: center.x + radius * cos(startAngleOuter.DEG2RAD), 816| 0| arcStartPointY: center.y + radius * sin(startAngleOuter.DEG2RAD), 817| 0| startAngle: startAngleOuter, 818| 0| sweepAngle: sweepAngleOuter) 819| 1| } 820| 1| 821| 1| if drawInnerArc && 822| 1| (innerRadius > 0.0 || accountForSliceSpacing) 823| 1| { 824| 1| if accountForSliceSpacing 825| 1| { 826| 0| var minSpacedRadius = sliceSpaceRadius 827| 0| if minSpacedRadius < 0.0 828| 0| { 829| 0| minSpacedRadius = -minSpacedRadius 830| 0| } 831| 0| innerRadius = min(max(innerRadius, minSpacedRadius), radius) 832| 1| } 833| 1| 834| 1| let sliceSpaceAngleInner = visibleAngleCount == 1 || innerRadius == 0.0 ? 835| 1| 0.0 : 836| 1| sliceSpace / innerRadius.DEG2RAD 837| 1| let startAngleInner = rotationAngle + (angle + sliceSpaceAngleInner / 2.0) * CGFloat(phaseY) 838| 1| var sweepAngleInner = (sliceAngle - sliceSpaceAngleInner) * CGFloat(phaseY) 839| 1| if sweepAngleInner < 0.0 840| 1| { 841| 0| sweepAngleInner = 0.0 842| 1| } 843| 1| let endAngleInner = startAngleInner + sweepAngleInner 844| 1| 845| 1| path.addLine( 846| 1| to: CGPoint( 847| 1| x: center.x + innerRadius * cos(endAngleInner.DEG2RAD), 848| 1| y: center.y + innerRadius * sin(endAngleInner.DEG2RAD))) 849| 1| 850| 1| path.addRelativeArc(center: center, radius: innerRadius, 851| 1| startAngle: endAngleInner.DEG2RAD, 852| 1| delta: -sweepAngleInner.DEG2RAD) 853| 1| } 854| 1| else 855| 1| { 856| 0| if accountForSliceSpacing 857| 0| { 858| 0| let angleMiddle = startAngleOuter + sweepAngleOuter / 2.0 859| 0| 860| 0| let arcEndPointX = center.x + sliceSpaceRadius * cos(angleMiddle.DEG2RAD) 861| 0| let arcEndPointY = center.y + sliceSpaceRadius * sin(angleMiddle.DEG2RAD) 862| 0| 863| 0| path.addLine( 864| 0| to: CGPoint( 865| 0| x: arcEndPointX, 866| 0| y: arcEndPointY)) 867| 0| } 868| 0| else 869| 0| { 870| 0| path.addLine(to: center) 871| 0| } 872| 1| } 873| 1| 874| 1| path.closeSubpath() 875| 1| 876| 1| context.beginPath() 877| 1| context.addPath(path) 878| 1| context.fillPath(using: .evenOdd) 879| 1| 880| 1| let axElement = createAccessibleElement(withIndex: index, 881| 1| container: chart, 882| 1| dataSet: set) 883| 1| { (element) in 884| 1| element.accessibilityFrame = path.boundingBoxOfPath 885| 1| element.isSelected = true 886| 1| } 887| 1| 888| 1| highlightedAccessibleElements.append(axElement) 889| 2| } 890| 2| 891| 2| // Prepend selected slices before the already rendered unselected ones. 892| 2| // NOTE: - This relies on drawDataSet() being called before drawHighlighted in PieChartView. 893| 2| if !accessibleChartElements.isEmpty { 894| 2| accessibleChartElements.insert(contentsOf: highlightedAccessibleElements, at: 1) 895| 2| } 896| 2| 897| 2| context.restoreGState() 898| 2| } 899| | 900| | /// Creates an NSUIAccessibilityElement representing a slice of the PieChart. 901| | /// The element only has it's container and label set based on the chart and dataSet. Use the modifier to alter traits and frame. 902| | private func createAccessibleElement(withIndex idx: Int, 903| | container: PieChartView, 904| | dataSet: IPieChartDataSet, 905| 42| modifier: (NSUIAccessibilityElement) -> ()) -> NSUIAccessibilityElement { 906| 42| 907| 42| let element = NSUIAccessibilityElement(accessibilityContainer: container) 908| 42| 909| 42| guard let e = dataSet.entryForIndex(idx) else { return element } 910| 42| guard let formatter = dataSet.valueFormatter else { return element } 911| 42| guard let data = container.data as? PieChartData else { return element } 912| 42| 913| 42| var elementValueText = formatter.stringForValue( 914| 42| e.y, 915| 42| entry: e, 916| 42| dataSetIndex: idx, 917| 42| viewPortHandler: viewPortHandler) 918| 42| 919| 42| if container.usePercentValuesEnabled { 920| 0| let value = e.y / data.yValueSum * 100.0 921| 0| let valueText = formatter.stringForValue( 922| 0| value, 923| 0| entry: e, 924| 0| dataSetIndex: idx, 925| 0| viewPortHandler: viewPortHandler) 926| 0| 927| 0| elementValueText = valueText 928| 42| } 929| 42| 930| 42| let pieChartDataEntry = (dataSet.entryForIndex(idx) as? PieChartDataEntry) 931| 42| let isCount = data.accessibilityEntryLabelSuffixIsCount 932| 42| let prefix = data.accessibilityEntryLabelPrefix?.appending("\(idx + 1)") ?? pieChartDataEntry?.label ?? "" 933| 42| let suffix = data.accessibilityEntryLabelSuffix ?? "" 934| 42| element.accessibilityLabel = "\(prefix) : \(elementValueText) \(suffix + (isCount ? (e.y == 1.0 ? "" : "s") : "") )" 935| 42| 936| 42| // The modifier allows changing of traits and frame depending on highlight, rotation, etc 937| 42| modifier(element) 938| 42| 939| 42| return element 940| 42| } 941| |} /Users/travis/build/danielgindi/Charts/Source/Charts/Renderers/RadarChartRenderer.swift: 1| |// 2| |// RadarChartRenderer.swift 3| |// Charts 4| |// 5| |// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda 6| |// A port of MPAndroidChart for iOS 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| | 12| |import Foundation 13| |import CoreGraphics 14| | 15| |open class RadarChartRenderer: LineRadarRenderer 16| |{ 17| 0| private lazy var accessibilityXLabels: [String] = { 18| 0| guard let chart = chart else { return [] } 19| 0| guard let formatter = chart.xAxis.valueFormatter else { return [] } 20| 0| 21| 0| let maxEntryCount = chart.data?.maxEntryCountSet?.entryCount ?? 0 22| 0| return stride(from: 0, to: maxEntryCount, by: 1).map { 23| 0| formatter.stringForValue(Double($0), axis: chart.xAxis) 24| 0| } 25| 0| }() 26| | 27| | @objc open weak var chart: RadarChartView? 28| | 29| | @objc public init(chart: RadarChartView, animator: Animator, viewPortHandler: ViewPortHandler) 30| 0| { 31| 0| super.init(animator: animator, viewPortHandler: viewPortHandler) 32| 0| 33| 0| self.chart = chart 34| 0| } 35| | 36| | open override func drawData(context: CGContext) 37| 0| { 38| 0| guard let chart = chart else { return } 39| 0| 40| 0| let radarData = chart.data 41| 0| 42| 0| if radarData != nil 43| 0| { 44| 0| let mostEntries = radarData?.maxEntryCountSet?.entryCount ?? 0 45| 0| 46| 0| // If we redraw the data, remove and repopulate accessible elements to update label values and frames 47| 0| self.accessibleChartElements.removeAll() 48| 0| 49| 0| // Make the chart header the first element in the accessible elements array 50| 0| if let accessibilityHeaderData = radarData as? RadarChartData { 51| 0| let element = createAccessibleHeader(usingChart: chart, 52| 0| andData: accessibilityHeaderData, 53| 0| withDefaultDescription: "Radar Chart") 54| 0| self.accessibleChartElements.append(element) 55| 0| } 56| 0| 57| 0| for set in radarData!.dataSets as! [IRadarChartDataSet] where set.isVisible 58| 0| { 59| 0| drawDataSet(context: context, dataSet: set, mostEntries: mostEntries) 60| 0| } 61| 0| } 62| 0| } 63| | 64| | /// Draws the RadarDataSet 65| | /// 66| | /// - Parameters: 67| | /// - context: 68| | /// - dataSet: 69| | /// - mostEntries: the entry count of the dataset with the most entries 70| | internal func drawDataSet(context: CGContext, dataSet: IRadarChartDataSet, mostEntries: Int) 71| 0| { 72| 0| guard let chart = chart else { return } 73| 0| 74| 0| context.saveGState() 75| 0| 76| 0| let phaseX = animator.phaseX 77| 0| let phaseY = animator.phaseY 78| 0| 79| 0| let sliceangle = chart.sliceAngle 80| 0| 81| 0| // calculate the factor that is needed for transforming the value to pixels 82| 0| let factor = chart.factor 83| 0| 84| 0| let center = chart.centerOffsets 85| 0| let entryCount = dataSet.entryCount 86| 0| let path = CGMutablePath() 87| 0| var hasMovedToPoint = false 88| 0| 89| 0| let prefix: String = chart.data?.accessibilityEntryLabelPrefix ?? "Item" 90| 0| let description = dataSet.label ?? "" 91| 0| 92| 0| // Make a tuple of (xLabels, value, originalIndex) then sort it 93| 0| // This is done, so that the labels are narrated in decreasing order of their corresponding value 94| 0| // Otherwise, there is no non-visual logic to the data presented 95| 0| let accessibilityEntryValues = Array(0 ..< entryCount).map { (dataSet.entryForIndex($0)?.y ?? 0, $0) } 96| 0| let accessibilityAxisLabelValueTuples = zip(accessibilityXLabels, accessibilityEntryValues).map { ($0, $1.0, $1.1) }.sorted { $0.1 > $1.1 } 97| 0| let accessibilityDataSetDescription: String = description + ". \(entryCount) \(prefix + (entryCount == 1 ? "" : "s")). " 98| 0| let accessibilityFrameWidth: CGFloat = 22.0 // To allow a tap target of 44x44 99| 0| 100| 0| var accessibilityEntryElements: [NSUIAccessibilityElement] = [] 101| 0| 102| 0| for j in 0 ..< entryCount 103| 0| { 104| 0| guard let e = dataSet.entryForIndex(j) else { continue } 105| 0| 106| 0| let p = center.moving(distance: CGFloat((e.y - chart.chartYMin) * Double(factor) * phaseY), 107| 0| atAngle: sliceangle * CGFloat(j) * CGFloat(phaseX) + chart.rotationAngle) 108| 0| 109| 0| if p.x.isNaN 110| 0| { 111| 0| continue 112| 0| } 113| 0| 114| 0| if !hasMovedToPoint 115| 0| { 116| 0| path.move(to: p) 117| 0| hasMovedToPoint = true 118| 0| } 119| 0| else 120| 0| { 121| 0| path.addLine(to: p) 122| 0| } 123| 0| 124| 0| let accessibilityLabel = accessibilityAxisLabelValueTuples[j].0 125| 0| let accessibilityValue = accessibilityAxisLabelValueTuples[j].1 126| 0| let accessibilityValueIndex = accessibilityAxisLabelValueTuples[j].2 127| 0| 128| 0| let axp = center.moving(distance: CGFloat((accessibilityValue - chart.chartYMin) * Double(factor) * phaseY), 129| 0| atAngle: sliceangle * CGFloat(accessibilityValueIndex) * CGFloat(phaseX) + chart.rotationAngle) 130| 0| 131| 0| let axDescription = description + " - " + accessibilityLabel + ": \(accessibilityValue) \(chart.data?.accessibilityEntryLabelSuffix ?? "")" 132| 0| let axElement = createAccessibleElement(withDescription: axDescription, 133| 0| container: chart, 134| 0| dataSet: dataSet) 135| 0| { (element) in 136| 0| element.accessibilityFrame = CGRect(x: axp.x - accessibilityFrameWidth, 137| 0| y: axp.y - accessibilityFrameWidth, 138| 0| width: 2 * accessibilityFrameWidth, 139| 0| height: 2 * accessibilityFrameWidth) 140| 0| } 141| 0| 142| 0| accessibilityEntryElements.append(axElement) 143| 0| } 144| 0| 145| 0| // if this is the largest set, close it 146| 0| if dataSet.entryCount < mostEntries 147| 0| { 148| 0| // if this is not the largest set, draw a line to the center before closing 149| 0| path.addLine(to: center) 150| 0| } 151| 0| 152| 0| path.closeSubpath() 153| 0| 154| 0| // draw filled 155| 0| if dataSet.isDrawFilledEnabled 156| 0| { 157| 0| if dataSet.fill != nil 158| 0| { 159| 0| drawFilledPath(context: context, path: path, fill: dataSet.fill!, fillAlpha: dataSet.fillAlpha) 160| 0| } 161| 0| else 162| 0| { 163| 0| drawFilledPath(context: context, path: path, fillColor: dataSet.fillColor, fillAlpha: dataSet.fillAlpha) 164| 0| } 165| 0| } 166| 0| 167| 0| // draw the line (only if filled is disabled or alpha is below 255) 168| 0| if !dataSet.isDrawFilledEnabled || dataSet.fillAlpha < 1.0 169| 0| { 170| 0| context.setStrokeColor(dataSet.color(atIndex: 0).cgColor) 171| 0| context.setLineWidth(dataSet.lineWidth) 172| 0| context.setAlpha(1.0) 173| 0| 174| 0| context.beginPath() 175| 0| context.addPath(path) 176| 0| context.strokePath() 177| 0| 178| 0| let axElement = createAccessibleElement(withDescription: accessibilityDataSetDescription, 179| 0| container: chart, 180| 0| dataSet: dataSet) 181| 0| { (element) in 182| 0| element.isHeader = true 183| 0| element.accessibilityFrame = path.boundingBoxOfPath 184| 0| } 185| 0| 186| 0| accessibleChartElements.append(axElement) 187| 0| accessibleChartElements.append(contentsOf: accessibilityEntryElements) 188| 0| } 189| 0| 190| 0| accessibilityPostLayoutChangedNotification() 191| 0| 192| 0| context.restoreGState() 193| 0| } 194| | 195| | open override func drawValues(context: CGContext) 196| 0| { 197| 0| guard 198| 0| let chart = chart, 199| 0| let data = chart.data 200| 0| else { return } 201| 0| 202| 0| let phaseX = animator.phaseX 203| 0| let phaseY = animator.phaseY 204| 0| 205| 0| let sliceangle = chart.sliceAngle 206| 0| 207| 0| // calculate the factor that is needed for transforming the value to pixels 208| 0| let factor = chart.factor 209| 0| 210| 0| let center = chart.centerOffsets 211| 0| 212| 0| let yoffset = CGFloat(5.0) 213| 0| 214| 0| for i in 0 ..< data.dataSetCount 215| 0| { 216| 0| guard let 217| 0| dataSet = data.getDataSetByIndex(i) as? IRadarChartDataSet, 218| 0| shouldDrawValues(forDataSet: dataSet) 219| 0| else { continue } 220| 0| 221| 0| let entryCount = dataSet.entryCount 222| 0| 223| 0| let iconsOffset = dataSet.iconsOffset 224| 0| 225| 0| for j in 0 ..< entryCount 226| 0| { 227| 0| guard let e = dataSet.entryForIndex(j) else { continue } 228| 0| 229| 0| let p = center.moving(distance: CGFloat(e.y - chart.chartYMin) * factor * CGFloat(phaseY), 230| 0| atAngle: sliceangle * CGFloat(j) * CGFloat(phaseX) + chart.rotationAngle) 231| 0| 232| 0| let valueFont = dataSet.valueFont 233| 0| 234| 0| guard let formatter = dataSet.valueFormatter else { continue } 235| 0| 236| 0| if dataSet.isDrawValuesEnabled 237| 0| { 238| 0| ChartUtils.drawText( 239| 0| context: context, 240| 0| text: formatter.stringForValue( 241| 0| e.y, 242| 0| entry: e, 243| 0| dataSetIndex: i, 244| 0| viewPortHandler: viewPortHandler), 245| 0| point: CGPoint(x: p.x, y: p.y - yoffset - valueFont.lineHeight), 246| 0| align: .center, 247| 0| attributes: [NSAttributedString.Key.font: valueFont, 248| 0| NSAttributedString.Key.foregroundColor: dataSet.valueTextColorAt(j)] 249| 0| ) 250| 0| } 251| 0| 252| 0| if let icon = e.icon, dataSet.isDrawIconsEnabled 253| 0| { 254| 0| var pIcon = center.moving(distance: CGFloat(e.y) * factor * CGFloat(phaseY) + iconsOffset.y, 255| 0| atAngle: sliceangle * CGFloat(j) * CGFloat(phaseX) + chart.rotationAngle) 256| 0| pIcon.y += iconsOffset.x 257| 0| 258| 0| ChartUtils.drawImage(context: context, 259| 0| image: icon, 260| 0| x: pIcon.x, 261| 0| y: pIcon.y, 262| 0| size: icon.size) 263| 0| } 264| 0| } 265| 0| } 266| 0| } 267| | 268| | open override func drawExtras(context: CGContext) 269| 0| { 270| 0| drawWeb(context: context) 271| 0| } 272| | 273| | private var _webLineSegmentsBuffer = [CGPoint](repeating: CGPoint(), count: 2) 274| | 275| | @objc open func drawWeb(context: CGContext) 276| 0| { 277| 0| guard 278| 0| let chart = chart, 279| 0| let data = chart.data 280| 0| else { return } 281| 0| 282| 0| let sliceangle = chart.sliceAngle 283| 0| 284| 0| context.saveGState() 285| 0| 286| 0| // calculate the factor that is needed for transforming the value to 287| 0| // pixels 288| 0| let factor = chart.factor 289| 0| let rotationangle = chart.rotationAngle 290| 0| 291| 0| let center = chart.centerOffsets 292| 0| 293| 0| // draw the web lines that come from the center 294| 0| context.setLineWidth(chart.webLineWidth) 295| 0| context.setStrokeColor(chart.webColor.cgColor) 296| 0| context.setAlpha(chart.webAlpha) 297| 0| 298| 0| let xIncrements = 1 + chart.skipWebLineCount 299| 0| let maxEntryCount = chart.data?.maxEntryCountSet?.entryCount ?? 0 300| 0| 301| 0| for i in stride(from: 0, to: maxEntryCount, by: xIncrements) 302| 0| { 303| 0| let p = center.moving(distance: CGFloat(chart.yRange) * factor, 304| 0| atAngle: sliceangle * CGFloat(i) + rotationangle) 305| 0| 306| 0| _webLineSegmentsBuffer[0].x = center.x 307| 0| _webLineSegmentsBuffer[0].y = center.y 308| 0| _webLineSegmentsBuffer[1].x = p.x 309| 0| _webLineSegmentsBuffer[1].y = p.y 310| 0| 311| 0| context.strokeLineSegments(between: _webLineSegmentsBuffer) 312| 0| } 313| 0| 314| 0| // draw the inner-web 315| 0| context.setLineWidth(chart.innerWebLineWidth) 316| 0| context.setStrokeColor(chart.innerWebColor.cgColor) 317| 0| context.setAlpha(chart.webAlpha) 318| 0| 319| 0| let labelCount = chart.yAxis.entryCount 320| 0| 321| 0| for j in 0 ..< labelCount 322| 0| { 323| 0| for i in 0 ..< data.entryCount 324| 0| { 325| 0| let r = CGFloat(chart.yAxis.entries[j] - chart.chartYMin) * factor 326| 0| 327| 0| let p1 = center.moving(distance: r, atAngle: sliceangle * CGFloat(i) + rotationangle) 328| 0| let p2 = center.moving(distance: r, atAngle: sliceangle * CGFloat(i + 1) + rotationangle) 329| 0| 330| 0| _webLineSegmentsBuffer[0].x = p1.x 331| 0| _webLineSegmentsBuffer[0].y = p1.y 332| 0| _webLineSegmentsBuffer[1].x = p2.x 333| 0| _webLineSegmentsBuffer[1].y = p2.y 334| 0| 335| 0| context.strokeLineSegments(between: _webLineSegmentsBuffer) 336| 0| } 337| 0| } 338| 0| 339| 0| context.restoreGState() 340| 0| } 341| | 342| | private var _highlightPointBuffer = CGPoint() 343| | 344| | open override func drawHighlighted(context: CGContext, indices: [Highlight]) 345| 0| { 346| 0| guard 347| 0| let chart = chart, 348| 0| let radarData = chart.data as? RadarChartData 349| 0| else { return } 350| 0| 351| 0| context.saveGState() 352| 0| 353| 0| let sliceangle = chart.sliceAngle 354| 0| 355| 0| // calculate the factor that is needed for transforming the value pixels 356| 0| let factor = chart.factor 357| 0| 358| 0| let center = chart.centerOffsets 359| 0| 360| 0| for high in indices 361| 0| { 362| 0| guard 363| 0| let set = chart.data?.getDataSetByIndex(high.dataSetIndex) as? IRadarChartDataSet, 364| 0| set.isHighlightEnabled 365| 0| else { continue } 366| 0| 367| 0| guard let e = set.entryForIndex(Int(high.x)) as? RadarChartDataEntry 368| 0| else { continue } 369| 0| 370| 0| if !isInBoundsX(entry: e, dataSet: set) 371| 0| { 372| 0| continue 373| 0| } 374| 0| 375| 0| context.setLineWidth(radarData.highlightLineWidth) 376| 0| if radarData.highlightLineDashLengths != nil 377| 0| { 378| 0| context.setLineDash(phase: radarData.highlightLineDashPhase, lengths: radarData.highlightLineDashLengths!) 379| 0| } 380| 0| else 381| 0| { 382| 0| context.setLineDash(phase: 0.0, lengths: []) 383| 0| } 384| 0| 385| 0| context.setStrokeColor(set.highlightColor.cgColor) 386| 0| 387| 0| let y = e.y - chart.chartYMin 388| 0| 389| 0| _highlightPointBuffer = center.moving(distance: CGFloat(y) * factor * CGFloat(animator.phaseY), 390| 0| atAngle: sliceangle * CGFloat(high.x) * CGFloat(animator.phaseX) + chart.rotationAngle) 391| 0| 392| 0| high.setDraw(pt: _highlightPointBuffer) 393| 0| 394| 0| // draw the lines 395| 0| drawHighlightLines(context: context, point: _highlightPointBuffer, set: set) 396| 0| 397| 0| if set.isDrawHighlightCircleEnabled 398| 0| { 399| 0| if !_highlightPointBuffer.x.isNaN && !_highlightPointBuffer.y.isNaN 400| 0| { 401| 0| var strokeColor = set.highlightCircleStrokeColor 402| 0| if strokeColor == nil 403| 0| { 404| 0| strokeColor = set.color(atIndex: 0) 405| 0| } 406| 0| if set.highlightCircleStrokeAlpha < 1.0 407| 0| { 408| 0| strokeColor = strokeColor?.withAlphaComponent(set.highlightCircleStrokeAlpha) 409| 0| } 410| 0| 411| 0| drawHighlightCircle( 412| 0| context: context, 413| 0| atPoint: _highlightPointBuffer, 414| 0| innerRadius: set.highlightCircleInnerRadius, 415| 0| outerRadius: set.highlightCircleOuterRadius, 416| 0| fillColor: set.highlightCircleFillColor, 417| 0| strokeColor: strokeColor, 418| 0| strokeWidth: set.highlightCircleStrokeWidth) 419| 0| } 420| 0| } 421| 0| } 422| 0| 423| 0| context.restoreGState() 424| 0| } 425| | 426| | internal func drawHighlightCircle( 427| | context: CGContext, 428| | atPoint point: CGPoint, 429| | innerRadius: CGFloat, 430| | outerRadius: CGFloat, 431| | fillColor: NSUIColor?, 432| | strokeColor: NSUIColor?, 433| | strokeWidth: CGFloat) 434| 0| { 435| 0| context.saveGState() 436| 0| 437| 0| if let fillColor = fillColor 438| 0| { 439| 0| context.beginPath() 440| 0| context.addEllipse(in: CGRect(x: point.x - outerRadius, y: point.y - outerRadius, width: outerRadius * 2.0, height: outerRadius * 2.0)) 441| 0| if innerRadius > 0.0 442| 0| { 443| 0| context.addEllipse(in: CGRect(x: point.x - innerRadius, y: point.y - innerRadius, width: innerRadius * 2.0, height: innerRadius * 2.0)) 444| 0| } 445| 0| 446| 0| context.setFillColor(fillColor.cgColor) 447| 0| context.fillPath(using: .evenOdd) 448| 0| } 449| 0| 450| 0| if let strokeColor = strokeColor 451| 0| { 452| 0| context.beginPath() 453| 0| context.addEllipse(in: CGRect(x: point.x - outerRadius, y: point.y - outerRadius, width: outerRadius * 2.0, height: outerRadius * 2.0)) 454| 0| context.setStrokeColor(strokeColor.cgColor) 455| 0| context.setLineWidth(strokeWidth) 456| 0| context.strokePath() 457| 0| } 458| 0| 459| 0| context.restoreGState() 460| 0| } 461| | 462| | private func createAccessibleElement(withDescription description: String, 463| | container: RadarChartView, 464| | dataSet: IRadarChartDataSet, 465| 0| modifier: (NSUIAccessibilityElement) -> ()) -> NSUIAccessibilityElement { 466| 0| 467| 0| let element = NSUIAccessibilityElement(accessibilityContainer: container) 468| 0| element.accessibilityLabel = description 469| 0| 470| 0| // The modifier allows changing of traits and frame depending on highlight, rotation, etc 471| 0| modifier(element) 472| 0| 473| 0| return element 474| 0| } 475| |} /Users/travis/build/danielgindi/Charts/Source/Charts/Renderers/Renderer.swift: 1| |// 2| |// Renderer.swift 3| |// Charts 4| |// 5| |// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda 6| |// A port of MPAndroidChart for iOS 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| | 12| |import Foundation 13| |import CoreGraphics 14| | 15| |@objc(ChartRenderer) 16| |open class Renderer: NSObject 17| |{ 18| | /// the component that handles the drawing area of the chart and it's offsets 19| | @objc public let viewPortHandler: ViewPortHandler 20| | 21| | @objc public init(viewPortHandler: ViewPortHandler) 22| 254| { 23| 254| self.viewPortHandler = viewPortHandler 24| 254| super.init() 25| 254| } 26| |} /Users/travis/build/danielgindi/Charts/Source/Charts/Renderers/Scatter/ChevronDownShapeRenderer.swift: 1| |// 2| |// ChevronDownShapeRenderer.swift 3| |// Charts 4| |// 5| |// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda 6| |// A port of MPAndroidChart for iOS 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| |import Foundation 12| |import CoreGraphics 13| | 14| |open class ChevronDownShapeRenderer : NSObject, IShapeRenderer 15| |{ 16| | open func renderShape( 17| | context: CGContext, 18| | dataSet: IScatterChartDataSet, 19| | viewPortHandler: ViewPortHandler, 20| | point: CGPoint, 21| | color: NSUIColor) 22| 0| { 23| 0| let shapeSize = dataSet.scatterShapeSize 24| 0| let shapeHalf = shapeSize / 2.0 25| 0| 26| 0| context.setLineWidth(1.0) 27| 0| context.setStrokeColor(color.cgColor) 28| 0| 29| 0| context.beginPath() 30| 0| context.move(to: CGPoint(x: point.x, y: point.y + 2 * shapeHalf)) 31| 0| context.addLine(to: CGPoint(x: point.x + 2 * shapeHalf, y: point.y)) 32| 0| context.move(to: CGPoint(x: point.x, y: point.y + 2 * shapeHalf)) 33| 0| context.addLine(to: CGPoint(x: point.x - 2 * shapeHalf, y: point.y)) 34| 0| context.strokePath() 35| 0| } 36| |} /Users/travis/build/danielgindi/Charts/Source/Charts/Renderers/Scatter/ChevronUpShapeRenderer.swift: 1| |// 2| |// ChevronUpShapeRenderer.swift 3| |// Charts 4| |// 5| |// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda 6| |// A port of MPAndroidChart for iOS 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| |import Foundation 12| |import CoreGraphics 13| | 14| |open class ChevronUpShapeRenderer : NSObject, IShapeRenderer 15| |{ 16| | open func renderShape( 17| | context: CGContext, 18| | dataSet: IScatterChartDataSet, 19| | viewPortHandler: ViewPortHandler, 20| | point: CGPoint, 21| | color: NSUIColor) 22| 0| { 23| 0| let shapeSize = dataSet.scatterShapeSize 24| 0| let shapeHalf = shapeSize / 2.0 25| 0| 26| 0| context.setLineWidth(1.0) 27| 0| context.setStrokeColor(color.cgColor) 28| 0| 29| 0| context.beginPath() 30| 0| context.move(to: CGPoint(x: point.x, y: point.y - 2 * shapeHalf)) 31| 0| context.addLine(to: CGPoint(x: point.x + 2 * shapeHalf, y: point.y)) 32| 0| context.move(to: CGPoint(x: point.x, y: point.y - 2 * shapeHalf)) 33| 0| context.addLine(to: CGPoint(x: point.x - 2 * shapeHalf, y: point.y)) 34| 0| context.strokePath() 35| 0| } 36| |} /Users/travis/build/danielgindi/Charts/Source/Charts/Renderers/Scatter/CircleShapeRenderer.swift: 1| |// 2| |// CircleShapeRenderer.swift 3| |// Charts 4| |// 5| |// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda 6| |// A port of MPAndroidChart for iOS 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| |import Foundation 12| |import CoreGraphics 13| | 14| |open class CircleShapeRenderer : NSObject, IShapeRenderer 15| |{ 16| | open func renderShape( 17| | context: CGContext, 18| | dataSet: IScatterChartDataSet, 19| | viewPortHandler: ViewPortHandler, 20| | point: CGPoint, 21| | color: NSUIColor) 22| 0| { 23| 0| let shapeSize = dataSet.scatterShapeSize 24| 0| let shapeHalf = shapeSize / 2.0 25| 0| let shapeHoleSizeHalf = dataSet.scatterShapeHoleRadius 26| 0| let shapeHoleSize = shapeHoleSizeHalf * 2.0 27| 0| let shapeHoleColor = dataSet.scatterShapeHoleColor 28| 0| let shapeStrokeSize = (shapeSize - shapeHoleSize) / 2.0 29| 0| let shapeStrokeSizeHalf = shapeStrokeSize / 2.0 30| 0| 31| 0| if shapeHoleSize > 0.0 32| 0| { 33| 0| context.setStrokeColor(color.cgColor) 34| 0| context.setLineWidth(shapeStrokeSize) 35| 0| var rect = CGRect() 36| 0| rect.origin.x = point.x - shapeHoleSizeHalf - shapeStrokeSizeHalf 37| 0| rect.origin.y = point.y - shapeHoleSizeHalf - shapeStrokeSizeHalf 38| 0| rect.size.width = shapeHoleSize + shapeStrokeSize 39| 0| rect.size.height = shapeHoleSize + shapeStrokeSize 40| 0| context.strokeEllipse(in: rect) 41| 0| 42| 0| if let shapeHoleColor = shapeHoleColor 43| 0| { 44| 0| context.setFillColor(shapeHoleColor.cgColor) 45| 0| rect.origin.x = point.x - shapeHoleSizeHalf 46| 0| rect.origin.y = point.y - shapeHoleSizeHalf 47| 0| rect.size.width = shapeHoleSize 48| 0| rect.size.height = shapeHoleSize 49| 0| context.fillEllipse(in: rect) 50| 0| } 51| 0| } 52| 0| else 53| 0| { 54| 0| context.setFillColor(color.cgColor) 55| 0| var rect = CGRect() 56| 0| rect.origin.x = point.x - shapeHalf 57| 0| rect.origin.y = point.y - shapeHalf 58| 0| rect.size.width = shapeSize 59| 0| rect.size.height = shapeSize 60| 0| context.fillEllipse(in: rect) 61| 0| } 62| 0| } 63| |} /Users/travis/build/danielgindi/Charts/Source/Charts/Renderers/Scatter/CrossShapeRenderer.swift: 1| |// 2| |// CrossShapeRenderer.swift 3| |// Charts 4| |// 5| |// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda 6| |// A port of MPAndroidChart for iOS 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| |import Foundation 12| |import CoreGraphics 13| | 14| |open class CrossShapeRenderer : NSObject, IShapeRenderer 15| |{ 16| | open func renderShape( 17| | context: CGContext, 18| | dataSet: IScatterChartDataSet, 19| | viewPortHandler: ViewPortHandler, 20| | point: CGPoint, 21| | color: NSUIColor) 22| 0| { 23| 0| let shapeSize = dataSet.scatterShapeSize 24| 0| let shapeHalf = shapeSize / 2.0 25| 0| 26| 0| context.setLineWidth(1.0) 27| 0| context.setStrokeColor(color.cgColor) 28| 0| 29| 0| context.beginPath() 30| 0| context.move(to: CGPoint(x: point.x - shapeHalf, y: point.y)) 31| 0| context.addLine(to: CGPoint(x: point.x + shapeHalf, y: point.y)) 32| 0| context.move(to: CGPoint(x: point.x, y: point.y - shapeHalf)) 33| 0| context.addLine(to: CGPoint(x: point.x, y: point.y + shapeHalf)) 34| 0| context.strokePath() 35| 0| } 36| |} /Users/travis/build/danielgindi/Charts/Source/Charts/Renderers/Scatter/SquareShapeRenderer.swift: 1| |// 2| |// SquareShapeRenderer.swift 3| |// Charts 4| |// 5| |// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda 6| |// A port of MPAndroidChart for iOS 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| |import Foundation 12| |import CoreGraphics 13| | 14| |open class SquareShapeRenderer : NSObject, IShapeRenderer 15| |{ 16| | open func renderShape( 17| | context: CGContext, 18| | dataSet: IScatterChartDataSet, 19| | viewPortHandler: ViewPortHandler, 20| | point: CGPoint, 21| | color: NSUIColor) 22| 0| { 23| 0| let shapeSize = dataSet.scatterShapeSize 24| 0| let shapeHalf = shapeSize / 2.0 25| 0| let shapeHoleSizeHalf = dataSet.scatterShapeHoleRadius 26| 0| let shapeHoleSize = shapeHoleSizeHalf * 2.0 27| 0| let shapeHoleColor = dataSet.scatterShapeHoleColor 28| 0| let shapeStrokeSize = (shapeSize - shapeHoleSize) / 2.0 29| 0| let shapeStrokeSizeHalf = shapeStrokeSize / 2.0 30| 0| 31| 0| if shapeHoleSize > 0.0 32| 0| { 33| 0| context.setStrokeColor(color.cgColor) 34| 0| context.setLineWidth(shapeStrokeSize) 35| 0| var rect = CGRect() 36| 0| rect.origin.x = point.x - shapeHoleSizeHalf - shapeStrokeSizeHalf 37| 0| rect.origin.y = point.y - shapeHoleSizeHalf - shapeStrokeSizeHalf 38| 0| rect.size.width = shapeHoleSize + shapeStrokeSize 39| 0| rect.size.height = shapeHoleSize + shapeStrokeSize 40| 0| context.stroke(rect) 41| 0| 42| 0| if let shapeHoleColor = shapeHoleColor 43| 0| { 44| 0| context.setFillColor(shapeHoleColor.cgColor) 45| 0| rect.origin.x = point.x - shapeHoleSizeHalf 46| 0| rect.origin.y = point.y - shapeHoleSizeHalf 47| 0| rect.size.width = shapeHoleSize 48| 0| rect.size.height = shapeHoleSize 49| 0| context.fill(rect) 50| 0| } 51| 0| } 52| 0| else 53| 0| { 54| 0| context.setFillColor(color.cgColor) 55| 0| var rect = CGRect() 56| 0| rect.origin.x = point.x - shapeHalf 57| 0| rect.origin.y = point.y - shapeHalf 58| 0| rect.size.width = shapeSize 59| 0| rect.size.height = shapeSize 60| 0| context.fill(rect) 61| 0| } 62| 0| } 63| |} /Users/travis/build/danielgindi/Charts/Source/Charts/Renderers/Scatter/TriangleShapeRenderer.swift: 1| |// 2| |// TriangleShapeRenderer.swift 3| |// Charts 4| |// 5| |// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda 6| |// A port of MPAndroidChart for iOS 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| |import Foundation 12| |import CoreGraphics 13| | 14| |open class TriangleShapeRenderer : NSObject, IShapeRenderer 15| |{ 16| | open func renderShape( 17| | context: CGContext, 18| | dataSet: IScatterChartDataSet, 19| | viewPortHandler: ViewPortHandler, 20| | point: CGPoint, 21| | color: NSUIColor) 22| 0| { 23| 0| let shapeSize = dataSet.scatterShapeSize 24| 0| let shapeHalf = shapeSize / 2.0 25| 0| let shapeHoleSizeHalf = dataSet.scatterShapeHoleRadius 26| 0| let shapeHoleSize = shapeHoleSizeHalf * 2.0 27| 0| let shapeHoleColor = dataSet.scatterShapeHoleColor 28| 0| let shapeStrokeSize = (shapeSize - shapeHoleSize) / 2.0 29| 0| 30| 0| context.setFillColor(color.cgColor) 31| 0| 32| 0| // create a triangle path 33| 0| context.beginPath() 34| 0| context.move(to: CGPoint(x: point.x, y: point.y - shapeHalf)) 35| 0| context.addLine(to: CGPoint(x: point.x + shapeHalf, y: point.y + shapeHalf)) 36| 0| context.addLine(to: CGPoint(x: point.x - shapeHalf, y: point.y + shapeHalf)) 37| 0| 38| 0| if shapeHoleSize > 0.0 39| 0| { 40| 0| context.addLine(to: CGPoint(x: point.x, y: point.y - shapeHalf)) 41| 0| 42| 0| context.move(to: CGPoint(x: point.x - shapeHalf + shapeStrokeSize, y: point.y + shapeHalf - shapeStrokeSize)) 43| 0| context.addLine(to: CGPoint(x: point.x + shapeHalf - shapeStrokeSize, y: point.y + shapeHalf - shapeStrokeSize)) 44| 0| context.addLine(to: CGPoint(x: point.x, y: point.y - shapeHalf + shapeStrokeSize)) 45| 0| context.addLine(to: CGPoint(x: point.x - shapeHalf + shapeStrokeSize, y: point.y + shapeHalf - shapeStrokeSize)) 46| 0| } 47| 0| 48| 0| context.closePath() 49| 0| 50| 0| context.fillPath() 51| 0| 52| 0| if shapeHoleSize > 0.0 && shapeHoleColor != nil 53| 0| { 54| 0| context.setFillColor(shapeHoleColor!.cgColor) 55| 0| 56| 0| // create a triangle path 57| 0| context.beginPath() 58| 0| context.move(to: CGPoint(x: point.x, y: point.y - shapeHalf + shapeStrokeSize)) 59| 0| context.addLine(to: CGPoint(x: point.x + shapeHalf - shapeStrokeSize, y: point.y + shapeHalf - shapeStrokeSize)) 60| 0| context.addLine(to: CGPoint(x: point.x - shapeHalf + shapeStrokeSize, y: point.y + shapeHalf - shapeStrokeSize)) 61| 0| context.closePath() 62| 0| 63| 0| context.fillPath() 64| 0| } 65| 0| } 66| |} /Users/travis/build/danielgindi/Charts/Source/Charts/Renderers/Scatter/XShapeRenderer.swift: 1| |// 2| |// XShapeRenderer.swift 3| |// Charts 4| |// 5| |// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda 6| |// A port of MPAndroidChart for iOS 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| |import Foundation 12| |import CoreGraphics 13| | 14| |open class XShapeRenderer : NSObject, IShapeRenderer 15| |{ 16| | open func renderShape( 17| | context: CGContext, 18| | dataSet: IScatterChartDataSet, 19| | viewPortHandler: ViewPortHandler, 20| | point: CGPoint, 21| | color: NSUIColor) 22| 0| { 23| 0| let shapeSize = dataSet.scatterShapeSize 24| 0| let shapeHalf = shapeSize / 2.0 25| 0| 26| 0| context.setLineWidth(1.0) 27| 0| context.setStrokeColor(color.cgColor) 28| 0| 29| 0| context.beginPath() 30| 0| context.move(to: CGPoint(x: point.x - shapeHalf, y: point.y - shapeHalf)) 31| 0| context.addLine(to: CGPoint(x: point.x + shapeHalf, y: point.y + shapeHalf)) 32| 0| context.move(to: CGPoint(x: point.x + shapeHalf, y: point.y - shapeHalf)) 33| 0| context.addLine(to: CGPoint(x: point.x - shapeHalf, y: point.y + shapeHalf)) 34| 0| context.strokePath() 35| 0| } 36| |} /Users/travis/build/danielgindi/Charts/Source/Charts/Renderers/ScatterChartRenderer.swift: 1| |// 2| |// ScatterChartRenderer.swift 3| |// Charts 4| |// 5| |// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda 6| |// A port of MPAndroidChart for iOS 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| | 12| |import Foundation 13| |import CoreGraphics 14| | 15| |open class ScatterChartRenderer: LineScatterCandleRadarRenderer 16| |{ 17| | @objc open weak var dataProvider: ScatterChartDataProvider? 18| | 19| | @objc public init(dataProvider: ScatterChartDataProvider, animator: Animator, viewPortHandler: ViewPortHandler) 20| 0| { 21| 0| super.init(animator: animator, viewPortHandler: viewPortHandler) 22| 0| 23| 0| self.dataProvider = dataProvider 24| 0| } 25| | 26| | open override func drawData(context: CGContext) 27| 0| { 28| 0| guard let scatterData = dataProvider?.scatterData else { return } 29| 0| 30| 0| // If we redraw the data, remove and repopulate accessible elements to update label values and frames 31| 0| accessibleChartElements.removeAll() 32| 0| 33| 0| if let chart = dataProvider as? ScatterChartView { 34| 0| // Make the chart header the first element in the accessible elements array 35| 0| let element = createAccessibleHeader(usingChart: chart, 36| 0| andData: scatterData, 37| 0| withDefaultDescription: "Scatter Chart") 38| 0| accessibleChartElements.append(element) 39| 0| } 40| 0| 41| 0| // TODO: Due to the potential complexity of data presented in Scatter charts, a more usable way 42| 0| // for VO accessibility would be to use axis based traversal rather than by dataset. 43| 0| // Hence, accessibleChartElements is not populated below. (Individual renderers guard against dataSource being their respective views) 44| 0| for i in 0 ..< scatterData.dataSetCount 45| 0| { 46| 0| guard let set = scatterData.getDataSetByIndex(i) else { continue } 47| 0| 48| 0| if set.isVisible 49| 0| { 50| 0| if !(set is IScatterChartDataSet) 51| 0| { 52| 0| fatalError("Datasets for ScatterChartRenderer must conform to IScatterChartDataSet") 53| 0| } 54| 0| 55| 0| drawDataSet(context: context, dataSet: set as! IScatterChartDataSet) 56| 0| } 57| 0| } 58| 0| } 59| | 60| | private var _lineSegments = [CGPoint](repeating: CGPoint(), count: 2) 61| | 62| | @objc open func drawDataSet(context: CGContext, dataSet: IScatterChartDataSet) 63| 0| { 64| 0| guard let dataProvider = dataProvider else { return } 65| 0| 66| 0| let trans = dataProvider.getTransformer(forAxis: dataSet.axisDependency) 67| 0| 68| 0| let phaseY = animator.phaseY 69| 0| 70| 0| let entryCount = dataSet.entryCount 71| 0| 72| 0| var point = CGPoint() 73| 0| 74| 0| let valueToPixelMatrix = trans.valueToPixelMatrix 75| 0| 76| 0| if let renderer = dataSet.shapeRenderer 77| 0| { 78| 0| context.saveGState() 79| 0| 80| 0| for j in 0 ..< Int(min(ceil(Double(entryCount) * animator.phaseX), Double(entryCount))) 81| 0| { 82| 0| guard let e = dataSet.entryForIndex(j) else { continue } 83| 0| 84| 0| point.x = CGFloat(e.x) 85| 0| point.y = CGFloat(e.y * phaseY) 86| 0| point = point.applying(valueToPixelMatrix) 87| 0| 88| 0| if !viewPortHandler.isInBoundsRight(point.x) 89| 0| { 90| 0| break 91| 0| } 92| 0| 93| 0| if !viewPortHandler.isInBoundsLeft(point.x) || 94| 0| !viewPortHandler.isInBoundsY(point.y) 95| 0| { 96| 0| continue 97| 0| } 98| 0| 99| 0| renderer.renderShape(context: context, dataSet: dataSet, viewPortHandler: viewPortHandler, point: point, color: dataSet.color(atIndex: j)) 100| 0| } 101| 0| 102| 0| context.restoreGState() 103| 0| } 104| 0| else 105| 0| { 106| 0| print("There's no IShapeRenderer specified for ScatterDataSet", terminator: "\n") 107| 0| } 108| 0| } 109| | 110| | open override func drawValues(context: CGContext) 111| 0| { 112| 0| guard 113| 0| let dataProvider = dataProvider, 114| 0| let scatterData = dataProvider.scatterData 115| 0| else { return } 116| 0| 117| 0| // if values are drawn 118| 0| if isDrawingValuesAllowed(dataProvider: dataProvider) 119| 0| { 120| 0| guard let dataSets = scatterData.dataSets as? [IScatterChartDataSet] else { return } 121| 0| 122| 0| let phaseY = animator.phaseY 123| 0| 124| 0| var pt = CGPoint() 125| 0| 126| 0| for i in 0 ..< scatterData.dataSetCount 127| 0| { 128| 0| let dataSet = dataSets[i] 129| 0| guard let 130| 0| formatter = dataSet.valueFormatter, 131| 0| shouldDrawValues(forDataSet: dataSet) 132| 0| else { continue } 133| 0| 134| 0| let valueFont = dataSet.valueFont 135| 0| 136| 0| let trans = dataProvider.getTransformer(forAxis: dataSet.axisDependency) 137| 0| let valueToPixelMatrix = trans.valueToPixelMatrix 138| 0| 139| 0| let iconsOffset = dataSet.iconsOffset 140| 0| 141| 0| let shapeSize = dataSet.scatterShapeSize 142| 0| let lineHeight = valueFont.lineHeight 143| 0| 144| 0| _xBounds.set(chart: dataProvider, dataSet: dataSet, animator: animator) 145| 0| 146| 0| for j in _xBounds 147| 0| { 148| 0| guard let e = dataSet.entryForIndex(j) else { break } 149| 0| 150| 0| pt.x = CGFloat(e.x) 151| 0| pt.y = CGFloat(e.y * phaseY) 152| 0| pt = pt.applying(valueToPixelMatrix) 153| 0| 154| 0| if (!viewPortHandler.isInBoundsRight(pt.x)) 155| 0| { 156| 0| break 157| 0| } 158| 0| 159| 0| // make sure the lines don't do shitty things outside bounds 160| 0| if (!viewPortHandler.isInBoundsLeft(pt.x) 161| 0| || !viewPortHandler.isInBoundsY(pt.y)) 162| 0| { 163| 0| continue 164| 0| } 165| 0| 166| 0| let text = formatter.stringForValue( 167| 0| e.y, 168| 0| entry: e, 169| 0| dataSetIndex: i, 170| 0| viewPortHandler: viewPortHandler) 171| 0| 172| 0| if dataSet.isDrawValuesEnabled 173| 0| { 174| 0| ChartUtils.drawText( 175| 0| context: context, 176| 0| text: text, 177| 0| point: CGPoint( 178| 0| x: pt.x, 179| 0| y: pt.y - shapeSize - lineHeight), 180| 0| align: .center, 181| 0| attributes: [NSAttributedString.Key.font: valueFont, NSAttributedString.Key.foregroundColor: dataSet.valueTextColorAt(j)] 182| 0| ) 183| 0| } 184| 0| 185| 0| if let icon = e.icon, dataSet.isDrawIconsEnabled 186| 0| { 187| 0| ChartUtils.drawImage(context: context, 188| 0| image: icon, 189| 0| x: pt.x + iconsOffset.x, 190| 0| y: pt.y + iconsOffset.y, 191| 0| size: icon.size) 192| 0| } 193| 0| } 194| 0| } 195| 0| } 196| 0| } 197| | 198| | open override func drawExtras(context: CGContext) 199| 0| { 200| 0| 201| 0| } 202| | 203| | open override func drawHighlighted(context: CGContext, indices: [Highlight]) 204| 0| { 205| 0| guard 206| 0| let dataProvider = dataProvider, 207| 0| let scatterData = dataProvider.scatterData 208| 0| else { return } 209| 0| 210| 0| context.saveGState() 211| 0| 212| 0| for high in indices 213| 0| { 214| 0| guard 215| 0| let set = scatterData.getDataSetByIndex(high.dataSetIndex) as? IScatterChartDataSet, 216| 0| set.isHighlightEnabled 217| 0| else { continue } 218| 0| 219| 0| guard let entry = set.entryForXValue(high.x, closestToY: high.y) else { continue } 220| 0| 221| 0| if !isInBoundsX(entry: entry, dataSet: set) { continue } 222| 0| 223| 0| context.setStrokeColor(set.highlightColor.cgColor) 224| 0| context.setLineWidth(set.highlightLineWidth) 225| 0| if set.highlightLineDashLengths != nil 226| 0| { 227| 0| context.setLineDash(phase: set.highlightLineDashPhase, lengths: set.highlightLineDashLengths!) 228| 0| } 229| 0| else 230| 0| { 231| 0| context.setLineDash(phase: 0.0, lengths: []) 232| 0| } 233| 0| 234| 0| let x = entry.x // get the x-position 235| 0| let y = entry.y * Double(animator.phaseY) 236| 0| 237| 0| let trans = dataProvider.getTransformer(forAxis: set.axisDependency) 238| 0| 239| 0| let pt = trans.pixelForValues(x: x, y: y) 240| 0| 241| 0| high.setDraw(pt: pt) 242| 0| 243| 0| // draw the lines 244| 0| drawHighlightLines(context: context, point: pt, set: set) 245| 0| } 246| 0| 247| 0| context.restoreGState() 248| 0| } 249| |} /Users/travis/build/danielgindi/Charts/Source/Charts/Renderers/XAxisRenderer.swift: 1| |// 2| |// XAxisRenderer.swift 3| |// Charts 4| |// 5| |// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda 6| |// A port of MPAndroidChart for iOS 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| | 12| |import Foundation 13| |import CoreGraphics 14| | 15| |#if canImport(UIKit) 16| | import UIKit 17| |#endif 18| | 19| |#if canImport(Cocoa) 20| |import Cocoa 21| |#endif 22| | 23| |@objc(ChartXAxisRenderer) 24| |open class XAxisRenderer: AxisRendererBase 25| |{ 26| | @objc public init(viewPortHandler: ViewPortHandler, xAxis: XAxis?, transformer: Transformer?) 27| 46| { 28| 46| super.init(viewPortHandler: viewPortHandler, transformer: transformer, axis: xAxis) 29| 46| } 30| | 31| | open override func computeAxis(min: Double, max: Double, inverted: Bool) 32| 108| { 33| 108| var min = min, max = max 34| 108| 35| 108| if let transformer = self.transformer 36| 108| { 37| 108| // calculate the starting and entry point of the y-labels (depending on 38| 108| // zoom / contentrect bounds) 39| 108| if viewPortHandler.contentWidth > 10 && !viewPortHandler.isFullyZoomedOutX 40| 108| { 41| 0| let p1 = transformer.valueForTouchPoint(CGPoint(x: viewPortHandler.contentLeft, y: viewPortHandler.contentTop)) 42| 0| let p2 = transformer.valueForTouchPoint(CGPoint(x: viewPortHandler.contentRight, y: viewPortHandler.contentTop)) 43| 0| 44| 0| if inverted 45| 0| { 46| 0| min = Double(p2.x) 47| 0| max = Double(p1.x) 48| 0| } 49| 0| else 50| 0| { 51| 0| min = Double(p1.x) 52| 0| max = Double(p2.x) 53| 0| } 54| 108| } 55| 108| } 56| 108| 57| 108| computeAxisValues(min: min, max: max) 58| 108| } 59| | 60| | open override func computeAxisValues(min: Double, max: Double) 61| 125| { 62| 125| super.computeAxisValues(min: min, max: max) 63| 125| 64| 125| computeSize() 65| 125| } 66| | 67| | @objc open func computeSize() 68| 108| { 69| 108| guard let 70| 108| xAxis = self.axis as? XAxis 71| 108| else { return } 72| 108| 73| 108| let longest = xAxis.getLongestLabel() 74| 108| 75| 108| let labelSize = longest.size(withAttributes: [NSAttributedString.Key.font: xAxis.labelFont]) 76| 108| 77| 108| let labelWidth = labelSize.width 78| 108| let labelHeight = labelSize.height 79| 108| 80| 108| let labelRotatedSize = labelSize.rotatedBy(degrees: xAxis.labelRotationAngle) 81| 108| 82| 108| xAxis.labelWidth = labelWidth 83| 108| xAxis.labelHeight = labelHeight 84| 108| xAxis.labelRotatedWidth = labelRotatedSize.width 85| 108| xAxis.labelRotatedHeight = labelRotatedSize.height 86| 108| } 87| | 88| | open override func renderAxisLabels(context: CGContext) 89| 40| { 90| 40| guard let xAxis = self.axis as? XAxis else { return } 91| 40| 92| 40| if !xAxis.isEnabled || !xAxis.isDrawLabelsEnabled 93| 40| { 94| 0| return 95| 40| } 96| 40| 97| 40| let yOffset = xAxis.yOffset 98| 40| 99| 40| if xAxis.labelPosition == .top 100| 40| { 101| 40| drawLabels(context: context, pos: viewPortHandler.contentTop - yOffset, anchor: CGPoint(x: 0.5, y: 1.0)) 102| 40| } 103| 40| else if xAxis.labelPosition == .topInside 104| 40| { 105| 0| drawLabels(context: context, pos: viewPortHandler.contentTop + yOffset + xAxis.labelRotatedHeight, anchor: CGPoint(x: 0.5, y: 1.0)) 106| 40| } 107| 40| else if xAxis.labelPosition == .bottom 108| 40| { 109| 0| drawLabels(context: context, pos: viewPortHandler.contentBottom + yOffset, anchor: CGPoint(x: 0.5, y: 0.0)) 110| 40| } 111| 40| else if xAxis.labelPosition == .bottomInside 112| 40| { 113| 0| drawLabels(context: context, pos: viewPortHandler.contentBottom - yOffset - xAxis.labelRotatedHeight, anchor: CGPoint(x: 0.5, y: 0.0)) 114| 40| } 115| 40| else 116| 40| { // BOTH SIDED 117| 40| drawLabels(context: context, pos: viewPortHandler.contentTop - yOffset, anchor: CGPoint(x: 0.5, y: 1.0)) 118| 40| drawLabels(context: context, pos: viewPortHandler.contentBottom + yOffset, anchor: CGPoint(x: 0.5, y: 0.0)) 119| 40| } 120| 40| } 121| | 122| | private var _axisLineSegmentsBuffer = [CGPoint](repeating: CGPoint(), count: 2) 123| | 124| | open override func renderAxisLine(context: CGContext) 125| 40| { 126| 40| guard let xAxis = self.axis as? XAxis else { return } 127| 40| 128| 40| if !xAxis.isEnabled || !xAxis.isDrawAxisLineEnabled 129| 40| { 130| 0| return 131| 40| } 132| 40| 133| 40| context.saveGState() 134| 40| 135| 40| context.setStrokeColor(xAxis.axisLineColor.cgColor) 136| 40| context.setLineWidth(xAxis.axisLineWidth) 137| 40| if xAxis.axisLineDashLengths != nil 138| 40| { 139| 0| context.setLineDash(phase: xAxis.axisLineDashPhase, lengths: xAxis.axisLineDashLengths) 140| 40| } 141| 40| else 142| 40| { 143| 40| context.setLineDash(phase: 0.0, lengths: []) 144| 40| } 145| 40| 146| 40| if xAxis.labelPosition == .top 147| 40| || xAxis.labelPosition == .topInside 148| 40| || xAxis.labelPosition == .bothSided 149| 40| { 150| 40| _axisLineSegmentsBuffer[0].x = viewPortHandler.contentLeft 151| 40| _axisLineSegmentsBuffer[0].y = viewPortHandler.contentTop 152| 40| _axisLineSegmentsBuffer[1].x = viewPortHandler.contentRight 153| 40| _axisLineSegmentsBuffer[1].y = viewPortHandler.contentTop 154| 40| context.strokeLineSegments(between: _axisLineSegmentsBuffer) 155| 40| } 156| 40| 157| 40| if xAxis.labelPosition == .bottom 158| 40| || xAxis.labelPosition == .bottomInside 159| 40| || xAxis.labelPosition == .bothSided 160| 40| { 161| 0| _axisLineSegmentsBuffer[0].x = viewPortHandler.contentLeft 162| 0| _axisLineSegmentsBuffer[0].y = viewPortHandler.contentBottom 163| 0| _axisLineSegmentsBuffer[1].x = viewPortHandler.contentRight 164| 0| _axisLineSegmentsBuffer[1].y = viewPortHandler.contentBottom 165| 0| context.strokeLineSegments(between: _axisLineSegmentsBuffer) 166| 40| } 167| 40| 168| 40| context.restoreGState() 169| 40| } 170| | 171| | /// draws the x-labels on the specified y-position 172| | @objc open func drawLabels(context: CGContext, pos: CGFloat, anchor: CGPoint) 173| 40| { 174| 40| guard 175| 40| let xAxis = self.axis as? XAxis, 176| 40| let transformer = self.transformer 177| 40| else { return } 178| 40| 179| 40| let paraStyle = NSParagraphStyle.default.mutableCopy() as! NSMutableParagraphStyle 180| 40| paraStyle.alignment = .center 181| 40| 182| 40| let labelAttrs: [NSAttributedString.Key : Any] = [ 183| 40| .font: xAxis.labelFont, 184| 40| .foregroundColor: xAxis.labelTextColor, 185| 40| .paragraphStyle: paraStyle 186| 40| ] 187| 40| let labelRotationAngleRadians = xAxis.labelRotationAngle.DEG2RAD 188| 40| 189| 40| let centeringEnabled = xAxis.isCenterAxisLabelsEnabled 190| 40| 191| 40| let valueToPixelMatrix = transformer.valueToPixelMatrix 192| 40| 193| 40| var position = CGPoint(x: 0.0, y: 0.0) 194| 40| 195| 40| var labelMaxSize = CGSize() 196| 40| 197| 40| if xAxis.isWordWrapEnabled 198| 40| { 199| 0| labelMaxSize.width = xAxis.wordWrapWidthPercent * valueToPixelMatrix.a 200| 40| } 201| 40| 202| 40| let entries = xAxis.entries 203| 40| 204| 40| for i in stride(from: 0, to: entries.count, by: 1) 205| 240| { 206| 240| if centeringEnabled 207| 240| { 208| 0| position.x = CGFloat(xAxis.centeredEntries[i]) 209| 240| } 210| 240| else 211| 240| { 212| 240| position.x = CGFloat(entries[i]) 213| 240| } 214| 240| 215| 240| position.y = 0.0 216| 240| position = position.applying(valueToPixelMatrix) 217| 240| 218| 240| if viewPortHandler.isInBoundsX(position.x) 219| 240| { 220| 240| let label = xAxis.valueFormatter?.stringForValue(xAxis.entries[i], axis: xAxis) ?? "" 221| 240| 222| 240| let labelns = label as NSString 223| 240| 224| 240| if xAxis.isAvoidFirstLastClippingEnabled 225| 240| { 226| 0| // avoid clipping of the last 227| 0| if i == xAxis.entryCount - 1 && xAxis.entryCount > 1 228| 0| { 229| 0| let width = labelns.boundingRect(with: labelMaxSize, options: .usesLineFragmentOrigin, attributes: labelAttrs, context: nil).size.width 230| 0| 231| 0| if width > viewPortHandler.offsetRight * 2.0 232| 0| && position.x + width > viewPortHandler.chartWidth 233| 0| { 234| 0| position.x -= width / 2.0 235| 0| } 236| 0| } 237| 0| else if i == 0 238| 0| { // avoid clipping of the first 239| 0| let width = labelns.boundingRect(with: labelMaxSize, options: .usesLineFragmentOrigin, attributes: labelAttrs, context: nil).size.width 240| 0| position.x += width / 2.0 241| 0| } 242| 240| } 243| 240| 244| 240| drawLabel(context: context, 245| 240| formattedLabel: label, 246| 240| x: position.x, 247| 240| y: pos, 248| 240| attributes: labelAttrs, 249| 240| constrainedToSize: labelMaxSize, 250| 240| anchor: anchor, 251| 240| angleRadians: labelRotationAngleRadians) 252| 240| } 253| 240| } 254| 40| } 255| | 256| | @objc open func drawLabel( 257| | context: CGContext, 258| | formattedLabel: String, 259| | x: CGFloat, 260| | y: CGFloat, 261| | attributes: [NSAttributedString.Key : Any], 262| | constrainedToSize: CGSize, 263| | anchor: CGPoint, 264| | angleRadians: CGFloat) 265| 240| { 266| 240| ChartUtils.drawMultilineText( 267| 240| context: context, 268| 240| text: formattedLabel, 269| 240| point: CGPoint(x: x, y: y), 270| 240| attributes: attributes, 271| 240| constrainedToSize: constrainedToSize, 272| 240| anchor: anchor, 273| 240| angleRadians: angleRadians) 274| 240| } 275| | 276| | open override func renderGridLines(context: CGContext) 277| 46| { 278| 46| guard 279| 46| let xAxis = self.axis as? XAxis, 280| 46| let transformer = self.transformer 281| 46| else { return } 282| 46| 283| 46| if !xAxis.isDrawGridLinesEnabled || !xAxis.isEnabled 284| 46| { 285| 1| return 286| 45| } 287| 45| 288| 45| context.saveGState() 289| 45| defer { context.restoreGState() } 290| 45| context.clip(to: self.gridClippingRect) 291| 45| 292| 45| context.setShouldAntialias(xAxis.gridAntialiasEnabled) 293| 45| context.setStrokeColor(xAxis.gridColor.cgColor) 294| 45| context.setLineWidth(xAxis.gridLineWidth) 295| 45| context.setLineCap(xAxis.gridLineCap) 296| 45| 297| 45| if xAxis.gridLineDashLengths != nil 298| 45| { 299| 0| context.setLineDash(phase: xAxis.gridLineDashPhase, lengths: xAxis.gridLineDashLengths) 300| 45| } 301| 45| else 302| 45| { 303| 45| context.setLineDash(phase: 0.0, lengths: []) 304| 45| } 305| 45| 306| 45| let valueToPixelMatrix = transformer.valueToPixelMatrix 307| 45| 308| 45| var position = CGPoint(x: 0.0, y: 0.0) 309| 45| 310| 45| let entries = xAxis.entries 311| 45| 312| 45| for i in stride(from: 0, to: entries.count, by: 1) 313| 270| { 314| 270| position.x = CGFloat(entries[i]) 315| 270| position.y = position.x 316| 270| position = position.applying(valueToPixelMatrix) 317| 270| 318| 270| drawGridLine(context: context, x: position.x, y: position.y) 319| 270| } 320| 45| } 321| | 322| | @objc open var gridClippingRect: CGRect 323| 39| { 324| 39| var contentRect = viewPortHandler.contentRect 325| 39| let dx = self.axis?.gridLineWidth ?? 0.0 326| 39| contentRect.origin.x -= dx / 2.0 327| 39| contentRect.size.width += dx 328| 39| return contentRect 329| 39| } 330| | 331| | @objc open func drawGridLine(context: CGContext, x: CGFloat, y: CGFloat) 332| 234| { 333| 234| if x >= viewPortHandler.offsetLeft 334| 234| && x <= viewPortHandler.chartWidth 335| 234| { 336| 234| context.beginPath() 337| 234| context.move(to: CGPoint(x: x, y: viewPortHandler.contentTop)) 338| 234| context.addLine(to: CGPoint(x: x, y: viewPortHandler.contentBottom)) 339| 234| context.strokePath() 340| 234| } 341| 234| } 342| | 343| | open override func renderLimitLines(context: CGContext) 344| 40| { 345| 40| guard 346| 40| let xAxis = self.axis as? XAxis, 347| 40| let transformer = self.transformer, 348| 40| !xAxis.limitLines.isEmpty 349| 40| else { return } 350| 0| 351| 0| let trans = transformer.valueToPixelMatrix 352| 0| 353| 0| var position = CGPoint(x: 0.0, y: 0.0) 354| 0| 355| 0| for l in xAxis.limitLines where l.isEnabled 356| 0| { 357| 0| context.saveGState() 358| 0| defer { context.restoreGState() } 359| 0| 360| 0| var clippingRect = viewPortHandler.contentRect 361| 0| clippingRect.origin.x -= l.lineWidth / 2.0 362| 0| clippingRect.size.width += l.lineWidth 363| 0| context.clip(to: clippingRect) 364| 0| 365| 0| position.x = CGFloat(l.limit) 366| 0| position.y = 0.0 367| 0| position = position.applying(trans) 368| 0| 369| 0| renderLimitLineLine(context: context, limitLine: l, position: position) 370| 0| renderLimitLineLabel(context: context, limitLine: l, position: position, yOffset: 2.0 + l.yOffset) 371| 0| } 372| 0| } 373| | 374| | @objc open func renderLimitLineLine(context: CGContext, limitLine: ChartLimitLine, position: CGPoint) 375| 0| { 376| 0| 377| 0| context.beginPath() 378| 0| context.move(to: CGPoint(x: position.x, y: viewPortHandler.contentTop)) 379| 0| context.addLine(to: CGPoint(x: position.x, y: viewPortHandler.contentBottom)) 380| 0| 381| 0| context.setStrokeColor(limitLine.lineColor.cgColor) 382| 0| context.setLineWidth(limitLine.lineWidth) 383| 0| if limitLine.lineDashLengths != nil 384| 0| { 385| 0| context.setLineDash(phase: limitLine.lineDashPhase, lengths: limitLine.lineDashLengths!) 386| 0| } 387| 0| else 388| 0| { 389| 0| context.setLineDash(phase: 0.0, lengths: []) 390| 0| } 391| 0| 392| 0| context.strokePath() 393| 0| } 394| | 395| | @objc open func renderLimitLineLabel(context: CGContext, limitLine: ChartLimitLine, position: CGPoint, yOffset: CGFloat) 396| 0| { 397| 0| 398| 0| let label = limitLine.label 399| 0| guard limitLine.drawLabelEnabled, !label.isEmpty else { return } 400| 0| 401| 0| let labelLineHeight = limitLine.valueFont.lineHeight 402| 0| 403| 0| let xOffset: CGFloat = limitLine.lineWidth + limitLine.xOffset 404| 0| let attributes: [NSAttributedString.Key : Any] = [ 405| 0| .font : limitLine.valueFont, 406| 0| .foregroundColor : limitLine.valueTextColor 407| 0| ] 408| 0| 409| 0| let (point, align): (CGPoint, NSTextAlignment) 410| 0| switch limitLine.labelPosition { 411| 0| case .topRight: 412| 0| point = CGPoint( 413| 0| x: position.x + xOffset, 414| 0| y: viewPortHandler.contentTop + yOffset 415| 0| ) 416| 0| align = .left 417| 0| 418| 0| case .bottomRight: 419| 0| point = CGPoint( 420| 0| x: position.x + xOffset, 421| 0| y: viewPortHandler.contentBottom - labelLineHeight - yOffset 422| 0| ) 423| 0| align = .left 424| 0| 425| 0| case .topLeft: 426| 0| point = CGPoint( 427| 0| x: position.x - xOffset, 428| 0| y: viewPortHandler.contentTop + yOffset 429| 0| ) 430| 0| align = .right 431| 0| 432| 0| case .bottomLeft: 433| 0| point = CGPoint( 434| 0| x: position.x - xOffset, 435| 0| y: viewPortHandler.contentBottom - labelLineHeight - yOffset 436| 0| ) 437| 0| align = .right 438| 0| } 439| 0| 440| 0| ChartUtils.drawText( 441| 0| context: context, 442| 0| text: label, 443| 0| point: point, 444| 0| align: align, 445| 0| attributes: attributes 446| 0| ) 447| 0| } 448| |} /Users/travis/build/danielgindi/Charts/Source/Charts/Renderers/XAxisRendererHorizontalBarChart.swift: 1| |// 2| |// XAxisRendererHorizontalBarChart.swift 3| |// Charts 4| |// 5| |// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda 6| |// A port of MPAndroidChart for iOS 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| | 12| |import Foundation 13| |import CoreGraphics 14| | 15| |open class XAxisRendererHorizontalBarChart: XAxisRenderer 16| |{ 17| | internal weak var chart: BarChartView? 18| | 19| | @objc public init(viewPortHandler: ViewPortHandler, xAxis: XAxis?, transformer: Transformer?, chart: BarChartView) 20| 6| { 21| 6| super.init(viewPortHandler: viewPortHandler, xAxis: xAxis, transformer: transformer) 22| 6| 23| 6| self.chart = chart 24| 6| } 25| | 26| | open override func computeAxis(min: Double, max: Double, inverted: Bool) 27| 17| { 28| 17| var min = min, max = max 29| 17| 30| 17| if let transformer = self.transformer 31| 17| { 32| 17| // calculate the starting and entry point of the y-labels (depending on 33| 17| // zoom / contentrect bounds) 34| 17| if viewPortHandler.contentWidth > 10 && !viewPortHandler.isFullyZoomedOutY 35| 17| { 36| 0| let p1 = transformer.valueForTouchPoint(CGPoint(x: viewPortHandler.contentLeft, y: viewPortHandler.contentBottom)) 37| 0| let p2 = transformer.valueForTouchPoint(CGPoint(x: viewPortHandler.contentLeft, y: viewPortHandler.contentTop)) 38| 0| 39| 0| if inverted 40| 0| { 41| 0| min = Double(p2.y) 42| 0| max = Double(p1.y) 43| 0| } 44| 0| else 45| 0| { 46| 0| min = Double(p1.y) 47| 0| max = Double(p2.y) 48| 0| } 49| 17| } 50| 17| } 51| 17| 52| 17| computeAxisValues(min: min, max: max) 53| 17| } 54| | 55| | open override func computeSize() 56| 17| { 57| 17| guard let 58| 17| xAxis = self.axis as? XAxis 59| 17| else { return } 60| 17| 61| 17| let longest = xAxis.getLongestLabel() as NSString 62| 17| 63| 17| let labelSize = longest.size(withAttributes: [NSAttributedString.Key.font: xAxis.labelFont]) 64| 17| 65| 17| let labelWidth = floor(labelSize.width + xAxis.xOffset * 3.5) 66| 17| let labelHeight = labelSize.height 67| 17| let labelRotatedSize = CGSize(width: labelSize.width, height: labelHeight).rotatedBy(degrees: xAxis.labelRotationAngle) 68| 17| 69| 17| xAxis.labelWidth = labelWidth 70| 17| xAxis.labelHeight = labelHeight 71| 17| xAxis.labelRotatedWidth = round(labelRotatedSize.width + xAxis.xOffset * 3.5) 72| 17| xAxis.labelRotatedHeight = round(labelRotatedSize.height) 73| 17| } 74| | 75| | open override func renderAxisLabels(context: CGContext) 76| 6| { 77| 6| guard 78| 6| let xAxis = self.axis as? XAxis 79| 6| else { return } 80| 6| 81| 6| if !xAxis.isEnabled || !xAxis.isDrawLabelsEnabled || chart?.data === nil 82| 6| { 83| 0| return 84| 6| } 85| 6| 86| 6| let xoffset = xAxis.xOffset 87| 6| 88| 6| if xAxis.labelPosition == .top 89| 6| { 90| 6| drawLabels(context: context, pos: viewPortHandler.contentRight + xoffset, anchor: CGPoint(x: 0.0, y: 0.5)) 91| 6| } 92| 6| else if xAxis.labelPosition == .topInside 93| 6| { 94| 0| drawLabels(context: context, pos: viewPortHandler.contentRight - xoffset, anchor: CGPoint(x: 1.0, y: 0.5)) 95| 6| } 96| 6| else if xAxis.labelPosition == .bottom 97| 6| { 98| 0| drawLabels(context: context, pos: viewPortHandler.contentLeft - xoffset, anchor: CGPoint(x: 1.0, y: 0.5)) 99| 6| } 100| 6| else if xAxis.labelPosition == .bottomInside 101| 6| { 102| 0| drawLabels(context: context, pos: viewPortHandler.contentLeft + xoffset, anchor: CGPoint(x: 0.0, y: 0.5)) 103| 6| } 104| 6| else 105| 6| { // BOTH SIDED 106| 6| drawLabels(context: context, pos: viewPortHandler.contentRight + xoffset, anchor: CGPoint(x: 0.0, y: 0.5)) 107| 6| drawLabels(context: context, pos: viewPortHandler.contentLeft - xoffset, anchor: CGPoint(x: 1.0, y: 0.5)) 108| 6| } 109| 6| } 110| | 111| | /// draws the x-labels on the specified y-position 112| | open override func drawLabels(context: CGContext, pos: CGFloat, anchor: CGPoint) 113| 6| { 114| 6| guard 115| 6| let xAxis = self.axis as? XAxis, 116| 6| let transformer = self.transformer 117| 6| else { return } 118| 6| 119| 6| let labelFont = xAxis.labelFont 120| 6| let labelTextColor = xAxis.labelTextColor 121| 6| let labelRotationAngleRadians = xAxis.labelRotationAngle.DEG2RAD 122| 6| 123| 6| let centeringEnabled = xAxis.isCenterAxisLabelsEnabled 124| 6| 125| 6| // pre allocate to save performance (dont allocate in loop) 126| 6| var position = CGPoint(x: 0.0, y: 0.0) 127| 6| 128| 6| for i in stride(from: 0, to: xAxis.entryCount, by: 1) 129| 36| { 130| 36| // only fill x values 131| 36| 132| 36| position.x = 0.0 133| 36| 134| 36| if centeringEnabled 135| 36| { 136| 0| position.y = CGFloat(xAxis.centeredEntries[i]) 137| 36| } 138| 36| else 139| 36| { 140| 36| position.y = CGFloat(xAxis.entries[i]) 141| 36| } 142| 36| 143| 36| transformer.pointValueToPixel(&position) 144| 36| 145| 36| if viewPortHandler.isInBoundsY(position.y) 146| 36| { 147| 36| if let label = xAxis.valueFormatter?.stringForValue(xAxis.entries[i], axis: xAxis) 148| 36| { 149| 36| drawLabel( 150| 36| context: context, 151| 36| formattedLabel: label, 152| 36| x: pos, 153| 36| y: position.y, 154| 36| attributes: [NSAttributedString.Key.font: labelFont, NSAttributedString.Key.foregroundColor: labelTextColor], 155| 36| anchor: anchor, 156| 36| angleRadians: labelRotationAngleRadians) 157| 36| } 158| 36| } 159| 36| } 160| 6| } 161| | 162| | @objc open func drawLabel( 163| | context: CGContext, 164| | formattedLabel: String, 165| | x: CGFloat, 166| | y: CGFloat, 167| | attributes: [NSAttributedString.Key : Any], 168| | anchor: CGPoint, 169| | angleRadians: CGFloat) 170| 36| { 171| 36| ChartUtils.drawText( 172| 36| context: context, 173| 36| text: formattedLabel, 174| 36| point: CGPoint(x: x, y: y), 175| 36| attributes: attributes, 176| 36| anchor: anchor, 177| 36| angleRadians: angleRadians) 178| 36| } 179| | 180| | open override var gridClippingRect: CGRect 181| 6| { 182| 6| var contentRect = viewPortHandler.contentRect 183| 6| let dy = self.axis?.gridLineWidth ?? 0.0 184| 6| contentRect.origin.y -= dy / 2.0 185| 6| contentRect.size.height += dy 186| 6| return contentRect 187| 6| } 188| | 189| | private var _gridLineSegmentsBuffer = [CGPoint](repeating: CGPoint(), count: 2) 190| | 191| | open override func drawGridLine(context: CGContext, x: CGFloat, y: CGFloat) 192| 36| { 193| 36| if viewPortHandler.isInBoundsY(y) 194| 36| { 195| 36| context.beginPath() 196| 36| context.move(to: CGPoint(x: viewPortHandler.contentLeft, y: y)) 197| 36| context.addLine(to: CGPoint(x: viewPortHandler.contentRight, y: y)) 198| 36| context.strokePath() 199| 36| } 200| 36| } 201| | 202| | open override func renderAxisLine(context: CGContext) 203| 6| { 204| 6| guard let xAxis = self.axis as? XAxis else { return } 205| 6| 206| 6| if !xAxis.isEnabled || !xAxis.isDrawAxisLineEnabled 207| 6| { 208| 0| return 209| 6| } 210| 6| 211| 6| context.saveGState() 212| 6| 213| 6| context.setStrokeColor(xAxis.axisLineColor.cgColor) 214| 6| context.setLineWidth(xAxis.axisLineWidth) 215| 6| if xAxis.axisLineDashLengths != nil 216| 6| { 217| 0| context.setLineDash(phase: xAxis.axisLineDashPhase, lengths: xAxis.axisLineDashLengths) 218| 6| } 219| 6| else 220| 6| { 221| 6| context.setLineDash(phase: 0.0, lengths: []) 222| 6| } 223| 6| 224| 6| if xAxis.labelPosition == .top || 225| 6| xAxis.labelPosition == .topInside || 226| 6| xAxis.labelPosition == .bothSided 227| 6| { 228| 6| context.beginPath() 229| 6| context.move(to: CGPoint(x: viewPortHandler.contentRight, y: viewPortHandler.contentTop)) 230| 6| context.addLine(to: CGPoint(x: viewPortHandler.contentRight, y: viewPortHandler.contentBottom)) 231| 6| context.strokePath() 232| 6| } 233| 6| 234| 6| if xAxis.labelPosition == .bottom || 235| 6| xAxis.labelPosition == .bottomInside || 236| 6| xAxis.labelPosition == .bothSided 237| 6| { 238| 0| context.beginPath() 239| 0| context.move(to: CGPoint(x: viewPortHandler.contentLeft, y: viewPortHandler.contentTop)) 240| 0| context.addLine(to: CGPoint(x: viewPortHandler.contentLeft, y: viewPortHandler.contentBottom)) 241| 0| context.strokePath() 242| 6| } 243| 6| 244| 6| context.restoreGState() 245| 6| } 246| | 247| | open override func renderLimitLines(context: CGContext) 248| 6| { 249| 6| guard 250| 6| let xAxis = self.axis as? XAxis, 251| 6| let transformer = self.transformer 252| 6| else { return } 253| 6| 254| 6| let limitLines = xAxis.limitLines 255| 6| 256| 6| if limitLines.count == 0 257| 6| { 258| 6| return 259| 6| } 260| 0| 261| 0| let trans = transformer.valueToPixelMatrix 262| 0| 263| 0| var position = CGPoint(x: 0.0, y: 0.0) 264| 0| 265| 0| for i in 0 ..< limitLines.count 266| 0| { 267| 0| let l = limitLines[i] 268| 0| 269| 0| if !l.isEnabled 270| 0| { 271| 0| continue 272| 0| } 273| 0| 274| 0| context.saveGState() 275| 0| defer { context.restoreGState() } 276| 0| 277| 0| var clippingRect = viewPortHandler.contentRect 278| 0| clippingRect.origin.y -= l.lineWidth / 2.0 279| 0| clippingRect.size.height += l.lineWidth 280| 0| context.clip(to: clippingRect) 281| 0| 282| 0| position.x = 0.0 283| 0| position.y = CGFloat(l.limit) 284| 0| position = position.applying(trans) 285| 0| 286| 0| context.beginPath() 287| 0| context.move(to: CGPoint(x: viewPortHandler.contentLeft, y: position.y)) 288| 0| context.addLine(to: CGPoint(x: viewPortHandler.contentRight, y: position.y)) 289| 0| 290| 0| context.setStrokeColor(l.lineColor.cgColor) 291| 0| context.setLineWidth(l.lineWidth) 292| 0| if l.lineDashLengths != nil 293| 0| { 294| 0| context.setLineDash(phase: l.lineDashPhase, lengths: l.lineDashLengths!) 295| 0| } 296| 0| else 297| 0| { 298| 0| context.setLineDash(phase: 0.0, lengths: []) 299| 0| } 300| 0| 301| 0| context.strokePath() 302| 0| 303| 0| let label = l.label 304| 0| 305| 0| // if drawing the limit-value label is enabled 306| 0| if l.drawLabelEnabled && label.count > 0 307| 0| { 308| 0| let labelLineHeight = l.valueFont.lineHeight 309| 0| 310| 0| let xOffset: CGFloat = 4.0 + l.xOffset 311| 0| let yOffset: CGFloat = l.lineWidth + labelLineHeight + l.yOffset 312| 0| 313| 0| if l.labelPosition == .topRight 314| 0| { 315| 0| ChartUtils.drawText(context: context, 316| 0| text: label, 317| 0| point: CGPoint( 318| 0| x: viewPortHandler.contentRight - xOffset, 319| 0| y: position.y - yOffset), 320| 0| align: .right, 321| 0| attributes: [NSAttributedString.Key.font: l.valueFont, NSAttributedString.Key.foregroundColor: l.valueTextColor]) 322| 0| } 323| 0| else if l.labelPosition == .bottomRight 324| 0| { 325| 0| ChartUtils.drawText(context: context, 326| 0| text: label, 327| 0| point: CGPoint( 328| 0| x: viewPortHandler.contentRight - xOffset, 329| 0| y: position.y + yOffset - labelLineHeight), 330| 0| align: .right, 331| 0| attributes: [NSAttributedString.Key.font: l.valueFont, NSAttributedString.Key.foregroundColor: l.valueTextColor]) 332| 0| } 333| 0| else if l.labelPosition == .topLeft 334| 0| { 335| 0| ChartUtils.drawText(context: context, 336| 0| text: label, 337| 0| point: CGPoint( 338| 0| x: viewPortHandler.contentLeft + xOffset, 339| 0| y: position.y - yOffset), 340| 0| align: .left, 341| 0| attributes: [NSAttributedString.Key.font: l.valueFont, NSAttributedString.Key.foregroundColor: l.valueTextColor]) 342| 0| } 343| 0| else 344| 0| { 345| 0| ChartUtils.drawText(context: context, 346| 0| text: label, 347| 0| point: CGPoint( 348| 0| x: viewPortHandler.contentLeft + xOffset, 349| 0| y: position.y + yOffset - labelLineHeight), 350| 0| align: .left, 351| 0| attributes: [NSAttributedString.Key.font: l.valueFont, NSAttributedString.Key.foregroundColor: l.valueTextColor]) 352| 0| } 353| 0| } 354| 0| } 355| 0| } 356| |} /Users/travis/build/danielgindi/Charts/Source/Charts/Renderers/XAxisRendererRadarChart.swift: 1| |// 2| |// XAxisRendererRadarChart.swift 3| |// Charts 4| |// 5| |// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda 6| |// A port of MPAndroidChart for iOS 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| | 12| |import Foundation 13| |import CoreGraphics 14| | 15| |open class XAxisRendererRadarChart: XAxisRenderer 16| |{ 17| | @objc open weak var chart: RadarChartView? 18| | 19| | @objc public init(viewPortHandler: ViewPortHandler, xAxis: XAxis?, chart: RadarChartView) 20| 0| { 21| 0| super.init(viewPortHandler: viewPortHandler, xAxis: xAxis, transformer: nil) 22| 0| 23| 0| self.chart = chart 24| 0| } 25| | 26| | open override func renderAxisLabels(context: CGContext) 27| 0| { 28| 0| guard let 29| 0| xAxis = axis as? XAxis, 30| 0| let chart = chart 31| 0| else { return } 32| 0| 33| 0| if !xAxis.isEnabled || !xAxis.isDrawLabelsEnabled 34| 0| { 35| 0| return 36| 0| } 37| 0| 38| 0| let labelFont = xAxis.labelFont 39| 0| let labelTextColor = xAxis.labelTextColor 40| 0| let labelRotationAngleRadians = xAxis.labelRotationAngle.RAD2DEG 41| 0| let drawLabelAnchor = CGPoint(x: 0.5, y: 0.25) 42| 0| 43| 0| let sliceangle = chart.sliceAngle 44| 0| 45| 0| // calculate the factor that is needed for transforming the value to pixels 46| 0| let factor = chart.factor 47| 0| 48| 0| let center = chart.centerOffsets 49| 0| 50| 0| for i in stride(from: 0, to: chart.data?.maxEntryCountSet?.entryCount ?? 0, by: 1) 51| 0| { 52| 0| 53| 0| let label = xAxis.valueFormatter?.stringForValue(Double(i), axis: xAxis) ?? "" 54| 0| 55| 0| let angle = (sliceangle * CGFloat(i) + chart.rotationAngle).truncatingRemainder(dividingBy: 360.0) 56| 0| 57| 0| let p = center.moving(distance: CGFloat(chart.yRange) * factor + xAxis.labelRotatedWidth / 2.0, atAngle: angle) 58| 0| 59| 0| drawLabel(context: context, 60| 0| formattedLabel: label, 61| 0| x: p.x, 62| 0| y: p.y - xAxis.labelRotatedHeight / 2.0, 63| 0| attributes: [NSAttributedString.Key.font: labelFont, NSAttributedString.Key.foregroundColor: labelTextColor], 64| 0| anchor: drawLabelAnchor, 65| 0| angleRadians: labelRotationAngleRadians) 66| 0| } 67| 0| } 68| | 69| | @objc open func drawLabel( 70| | context: CGContext, 71| | formattedLabel: String, 72| | x: CGFloat, 73| | y: CGFloat, 74| | attributes: [NSAttributedString.Key : Any], 75| | anchor: CGPoint, 76| | angleRadians: CGFloat) 77| 0| { 78| 0| ChartUtils.drawText( 79| 0| context: context, 80| 0| text: formattedLabel, 81| 0| point: CGPoint(x: x, y: y), 82| 0| attributes: attributes, 83| 0| anchor: anchor, 84| 0| angleRadians: angleRadians) 85| 0| } 86| | 87| | open override func renderLimitLines(context: CGContext) 88| 0| { 89| 0| /// XAxis LimitLines on RadarChart not yet supported. 90| 0| } 91| |} /Users/travis/build/danielgindi/Charts/Source/Charts/Renderers/YAxisRenderer.swift: 1| |// 2| |// YAxisRenderer.swift 3| |// Charts 4| |// 5| |// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda 6| |// A port of MPAndroidChart for iOS 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| | 12| |import Foundation 13| |import CoreGraphics 14| | 15| |#if canImport(UIKit) 16| | import UIKit 17| |#endif 18| | 19| |#if canImport(Cocoa) 20| |import Cocoa 21| |#endif 22| | 23| |@objc(ChartYAxisRenderer) 24| |open class YAxisRenderer: AxisRendererBase 25| |{ 26| | @objc public init(viewPortHandler: ViewPortHandler, yAxis: YAxis?, transformer: Transformer?) 27| 92| { 28| 92| super.init(viewPortHandler: viewPortHandler, transformer: transformer, axis: yAxis) 29| 92| } 30| | 31| | /// draws the y-axis labels to the screen 32| | open override func renderAxisLabels(context: CGContext) 33| 80| { 34| 80| guard let yAxis = self.axis as? YAxis else { return } 35| 80| 36| 80| if !yAxis.isEnabled || !yAxis.isDrawLabelsEnabled 37| 80| { 38| 2| return 39| 78| } 40| 78| 41| 78| let xoffset = yAxis.xOffset 42| 78| let yoffset = yAxis.labelFont.lineHeight / 2.5 + yAxis.yOffset 43| 78| 44| 78| let dependency = yAxis.axisDependency 45| 78| let labelPosition = yAxis.labelPosition 46| 78| 47| 78| var xPos = CGFloat(0.0) 48| 78| 49| 78| var textAlign: NSTextAlignment 50| 78| 51| 78| if dependency == .left 52| 78| { 53| 39| if labelPosition == .outsideChart 54| 39| { 55| 39| textAlign = .right 56| 39| xPos = viewPortHandler.offsetLeft - xoffset 57| 39| } 58| 39| else 59| 39| { 60| 0| textAlign = .left 61| 0| xPos = viewPortHandler.offsetLeft + xoffset 62| 39| } 63| 39| 64| 78| } 65| 78| else 66| 78| { 67| 39| if labelPosition == .outsideChart 68| 39| { 69| 39| textAlign = .left 70| 39| xPos = viewPortHandler.contentRight + xoffset 71| 39| } 72| 39| else 73| 39| { 74| 0| textAlign = .right 75| 0| xPos = viewPortHandler.contentRight - xoffset 76| 39| } 77| 78| } 78| 78| 79| 78| drawYLabels( 80| 78| context: context, 81| 78| fixedPosition: xPos, 82| 78| positions: transformedPositions(), 83| 78| offset: yoffset - yAxis.labelFont.lineHeight, 84| 78| textAlign: textAlign) 85| 78| } 86| | 87| | open override func renderAxisLine(context: CGContext) 88| 80| { 89| 80| guard let yAxis = self.axis as? YAxis else { return } 90| 80| 91| 80| if !yAxis.isEnabled || !yAxis.drawAxisLineEnabled 92| 80| { 93| 2| return 94| 78| } 95| 78| 96| 78| context.saveGState() 97| 78| 98| 78| context.setStrokeColor(yAxis.axisLineColor.cgColor) 99| 78| context.setLineWidth(yAxis.axisLineWidth) 100| 78| if yAxis.axisLineDashLengths != nil 101| 78| { 102| 0| context.setLineDash(phase: yAxis.axisLineDashPhase, lengths: yAxis.axisLineDashLengths) 103| 78| } 104| 78| else 105| 78| { 106| 78| context.setLineDash(phase: 0.0, lengths: []) 107| 78| } 108| 78| 109| 78| if yAxis.axisDependency == .left 110| 78| { 111| 39| context.beginPath() 112| 39| context.move(to: CGPoint(x: viewPortHandler.contentLeft, y: viewPortHandler.contentTop)) 113| 39| context.addLine(to: CGPoint(x: viewPortHandler.contentLeft, y: viewPortHandler.contentBottom)) 114| 39| context.strokePath() 115| 78| } 116| 78| else 117| 78| { 118| 39| context.beginPath() 119| 39| context.move(to: CGPoint(x: viewPortHandler.contentRight, y: viewPortHandler.contentTop)) 120| 39| context.addLine(to: CGPoint(x: viewPortHandler.contentRight, y: viewPortHandler.contentBottom)) 121| 39| context.strokePath() 122| 78| } 123| 78| 124| 78| context.restoreGState() 125| 78| } 126| | 127| | /// draws the y-labels on the specified x-position 128| | open func drawYLabels( 129| | context: CGContext, 130| | fixedPosition: CGFloat, 131| | positions: [CGPoint], 132| | offset: CGFloat, 133| | textAlign: NSTextAlignment) 134| 78| { 135| 78| guard 136| 78| let yAxis = self.axis as? YAxis 137| 78| else { return } 138| 78| 139| 78| let labelFont = yAxis.labelFont 140| 78| let labelTextColor = yAxis.labelTextColor 141| 78| 142| 78| let from = yAxis.isDrawBottomYLabelEntryEnabled ? 0 : 1 143| 78| let to = yAxis.isDrawTopYLabelEntryEnabled ? yAxis.entryCount : (yAxis.entryCount - 1) 144| 78| 145| 78| let xOffset = yAxis.labelXOffset 146| 78| 147| 78| for i in stride(from: from, to: to, by: 1) 148| 468| { 149| 468| let text = yAxis.getFormattedLabel(i) 150| 468| 151| 468| ChartUtils.drawText( 152| 468| context: context, 153| 468| text: text, 154| 468| point: CGPoint(x: fixedPosition + xOffset, y: positions[i].y + offset), 155| 468| align: textAlign, 156| 468| attributes: [.font: labelFont, .foregroundColor: labelTextColor] 157| 468| ) 158| 468| } 159| 78| } 160| | 161| | open override func renderGridLines(context: CGContext) 162| 92| { 163| 92| guard let 164| 92| yAxis = self.axis as? YAxis 165| 92| else { return } 166| 92| 167| 92| if !yAxis.isEnabled 168| 92| { 169| 2| return 170| 90| } 171| 90| 172| 90| if yAxis.drawGridLinesEnabled 173| 90| { 174| 88| let positions = transformedPositions() 175| 88| 176| 88| context.saveGState() 177| 88| defer { context.restoreGState() } 178| 88| context.clip(to: self.gridClippingRect) 179| 88| 180| 88| context.setShouldAntialias(yAxis.gridAntialiasEnabled) 181| 88| context.setStrokeColor(yAxis.gridColor.cgColor) 182| 88| context.setLineWidth(yAxis.gridLineWidth) 183| 88| context.setLineCap(yAxis.gridLineCap) 184| 88| 185| 88| if yAxis.gridLineDashLengths != nil 186| 88| { 187| 0| context.setLineDash(phase: yAxis.gridLineDashPhase, lengths: yAxis.gridLineDashLengths) 188| 0| 189| 88| } 190| 88| else 191| 88| { 192| 88| context.setLineDash(phase: 0.0, lengths: []) 193| 88| } 194| 88| 195| 88| // draw the grid 196| 522| positions.forEach { drawGridLine(context: context, position: $0) } 197| 90| } 198| 90| 199| 90| if yAxis.drawZeroLineEnabled 200| 90| { 201| 0| // draw zero line 202| 0| drawZeroLine(context: context) 203| 90| } 204| 90| } 205| | 206| | @objc open var gridClippingRect: CGRect 207| 76| { 208| 76| var contentRect = viewPortHandler.contentRect 209| 76| let dy = self.axis?.gridLineWidth ?? 0.0 210| 76| contentRect.origin.y -= dy / 2.0 211| 76| contentRect.size.height += dy 212| 76| return contentRect 213| 76| } 214| | 215| | @objc open func drawGridLine( 216| | context: CGContext, 217| | position: CGPoint) 218| 456| { 219| 456| context.beginPath() 220| 456| context.move(to: CGPoint(x: viewPortHandler.contentLeft, y: position.y)) 221| 456| context.addLine(to: CGPoint(x: viewPortHandler.contentRight, y: position.y)) 222| 456| context.strokePath() 223| 456| } 224| | 225| | @objc open func transformedPositions() -> [CGPoint] 226| 154| { 227| 154| guard 228| 154| let yAxis = self.axis as? YAxis, 229| 154| let transformer = self.transformer 230| 154| else { return [CGPoint]() } 231| 154| 232| 154| var positions = [CGPoint]() 233| 154| positions.reserveCapacity(yAxis.entryCount) 234| 154| 235| 154| let entries = yAxis.entries 236| 154| 237| 154| for i in stride(from: 0, to: yAxis.entryCount, by: 1) 238| 924| { 239| 924| positions.append(CGPoint(x: 0.0, y: entries[i])) 240| 924| } 241| 154| 242| 154| transformer.pointValuesToPixel(&positions) 243| 154| 244| 154| return positions 245| 154| } 246| | 247| | /// Draws the zero line at the specified position. 248| | @objc open func drawZeroLine(context: CGContext) 249| 0| { 250| 0| guard 251| 0| let yAxis = self.axis as? YAxis, 252| 0| let transformer = self.transformer, 253| 0| let zeroLineColor = yAxis.zeroLineColor 254| 0| else { return } 255| 0| 256| 0| context.saveGState() 257| 0| defer { context.restoreGState() } 258| 0| 259| 0| var clippingRect = viewPortHandler.contentRect 260| 0| clippingRect.origin.y -= yAxis.zeroLineWidth / 2.0 261| 0| clippingRect.size.height += yAxis.zeroLineWidth 262| 0| context.clip(to: clippingRect) 263| 0| 264| 0| context.setStrokeColor(zeroLineColor.cgColor) 265| 0| context.setLineWidth(yAxis.zeroLineWidth) 266| 0| 267| 0| let pos = transformer.pixelForValues(x: 0.0, y: 0.0) 268| 0| 269| 0| if yAxis.zeroLineDashLengths != nil 270| 0| { 271| 0| context.setLineDash(phase: yAxis.zeroLineDashPhase, lengths: yAxis.zeroLineDashLengths!) 272| 0| } 273| 0| else 274| 0| { 275| 0| context.setLineDash(phase: 0.0, lengths: []) 276| 0| } 277| 0| 278| 0| context.move(to: CGPoint(x: viewPortHandler.contentLeft, y: pos.y)) 279| 0| context.addLine(to: CGPoint(x: viewPortHandler.contentRight, y: pos.y)) 280| 0| context.drawPath(using: CGPathDrawingMode.stroke) 281| 0| } 282| | 283| | open override func renderLimitLines(context: CGContext) 284| 78| { 285| 78| guard 286| 78| let yAxis = self.axis as? YAxis, 287| 78| let transformer = self.transformer 288| 78| else { return } 289| 78| 290| 78| let limitLines = yAxis.limitLines 291| 78| 292| 78| if limitLines.count == 0 293| 78| { 294| 78| return 295| 78| } 296| 0| 297| 0| context.saveGState() 298| 0| 299| 0| let trans = transformer.valueToPixelMatrix 300| 0| 301| 0| var position = CGPoint(x: 0.0, y: 0.0) 302| 0| 303| 0| for i in 0 ..< limitLines.count 304| 0| { 305| 0| let l = limitLines[i] 306| 0| 307| 0| if !l.isEnabled 308| 0| { 309| 0| continue 310| 0| } 311| 0| 312| 0| context.saveGState() 313| 0| defer { context.restoreGState() } 314| 0| 315| 0| var clippingRect = viewPortHandler.contentRect 316| 0| clippingRect.origin.y -= l.lineWidth / 2.0 317| 0| clippingRect.size.height += l.lineWidth 318| 0| context.clip(to: clippingRect) 319| 0| 320| 0| position.x = 0.0 321| 0| position.y = CGFloat(l.limit) 322| 0| position = position.applying(trans) 323| 0| 324| 0| context.beginPath() 325| 0| context.move(to: CGPoint(x: viewPortHandler.contentLeft, y: position.y)) 326| 0| context.addLine(to: CGPoint(x: viewPortHandler.contentRight, y: position.y)) 327| 0| 328| 0| context.setStrokeColor(l.lineColor.cgColor) 329| 0| context.setLineWidth(l.lineWidth) 330| 0| if l.lineDashLengths != nil 331| 0| { 332| 0| context.setLineDash(phase: l.lineDashPhase, lengths: l.lineDashLengths!) 333| 0| } 334| 0| else 335| 0| { 336| 0| context.setLineDash(phase: 0.0, lengths: []) 337| 0| } 338| 0| 339| 0| context.strokePath() 340| 0| 341| 0| let label = l.label 342| 0| 343| 0| // if drawing the limit-value label is enabled 344| 0| if l.drawLabelEnabled && label.count > 0 345| 0| { 346| 0| let labelLineHeight = l.valueFont.lineHeight 347| 0| 348| 0| let xOffset: CGFloat = 4.0 + l.xOffset 349| 0| let yOffset: CGFloat = l.lineWidth + labelLineHeight + l.yOffset 350| 0| 351| 0| if l.labelPosition == .topRight 352| 0| { 353| 0| ChartUtils.drawText(context: context, 354| 0| text: label, 355| 0| point: CGPoint( 356| 0| x: viewPortHandler.contentRight - xOffset, 357| 0| y: position.y - yOffset), 358| 0| align: .right, 359| 0| attributes: [NSAttributedString.Key.font: l.valueFont, NSAttributedString.Key.foregroundColor: l.valueTextColor]) 360| 0| } 361| 0| else if l.labelPosition == .bottomRight 362| 0| { 363| 0| ChartUtils.drawText(context: context, 364| 0| text: label, 365| 0| point: CGPoint( 366| 0| x: viewPortHandler.contentRight - xOffset, 367| 0| y: position.y + yOffset - labelLineHeight), 368| 0| align: .right, 369| 0| attributes: [NSAttributedString.Key.font: l.valueFont, NSAttributedString.Key.foregroundColor: l.valueTextColor]) 370| 0| } 371| 0| else if l.labelPosition == .topLeft 372| 0| { 373| 0| ChartUtils.drawText(context: context, 374| 0| text: label, 375| 0| point: CGPoint( 376| 0| x: viewPortHandler.contentLeft + xOffset, 377| 0| y: position.y - yOffset), 378| 0| align: .left, 379| 0| attributes: [NSAttributedString.Key.font: l.valueFont, NSAttributedString.Key.foregroundColor: l.valueTextColor]) 380| 0| } 381| 0| else 382| 0| { 383| 0| ChartUtils.drawText(context: context, 384| 0| text: label, 385| 0| point: CGPoint( 386| 0| x: viewPortHandler.contentLeft + xOffset, 387| 0| y: position.y + yOffset - labelLineHeight), 388| 0| align: .left, 389| 0| attributes: [NSAttributedString.Key.font: l.valueFont, NSAttributedString.Key.foregroundColor: l.valueTextColor]) 390| 0| } 391| 0| } 392| 0| } 393| 0| 394| 0| context.restoreGState() 395| 0| } 396| |} /Users/travis/build/danielgindi/Charts/Source/Charts/Renderers/YAxisRendererHorizontalBarChart.swift: 1| |// 2| |// YAxisRendererHorizontalBarChart.swift 3| |// Charts 4| |// 5| |// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda 6| |// A port of MPAndroidChart for iOS 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| | 12| |import Foundation 13| |import CoreGraphics 14| | 15| |open class YAxisRendererHorizontalBarChart: YAxisRenderer 16| |{ 17| | public override init(viewPortHandler: ViewPortHandler, yAxis: YAxis?, transformer: Transformer?) 18| 12| { 19| 12| super.init(viewPortHandler: viewPortHandler, yAxis: yAxis, transformer: transformer) 20| 12| } 21| | 22| | /// Computes the axis values. 23| | open override func computeAxis(min: Double, max: Double, inverted: Bool) 24| 34| { 25| 34| guard let transformer = self.transformer else { return } 26| 34| 27| 34| var min = min, max = max 28| 34| 29| 34| // calculate the starting and entry point of the y-labels (depending on zoom / contentrect bounds) 30| 34| if viewPortHandler.contentHeight > 10.0 && !viewPortHandler.isFullyZoomedOutX 31| 34| { 32| 0| let p1 = transformer.valueForTouchPoint(CGPoint(x: viewPortHandler.contentLeft, y: viewPortHandler.contentTop)) 33| 0| let p2 = transformer.valueForTouchPoint(CGPoint(x: viewPortHandler.contentRight, y: viewPortHandler.contentTop)) 34| 0| 35| 0| if !inverted 36| 0| { 37| 0| min = Double(p1.x) 38| 0| max = Double(p2.x) 39| 0| } 40| 0| else 41| 0| { 42| 0| min = Double(p2.x) 43| 0| max = Double(p1.x) 44| 0| } 45| 34| } 46| 34| 47| 34| computeAxisValues(min: min, max: max) 48| 34| } 49| | 50| | /// draws the y-axis labels to the screen 51| | open override func renderAxisLabels(context: CGContext) 52| 12| { 53| 12| guard let yAxis = axis as? YAxis else { return } 54| 12| 55| 12| if !yAxis.isEnabled || !yAxis.isDrawLabelsEnabled 56| 12| { 57| 0| return 58| 12| } 59| 12| 60| 12| let lineHeight = yAxis.labelFont.lineHeight 61| 12| let baseYOffset: CGFloat = 2.5 62| 12| 63| 12| let dependency = yAxis.axisDependency 64| 12| let labelPosition = yAxis.labelPosition 65| 12| 66| 12| var yPos: CGFloat = 0.0 67| 12| 68| 12| if dependency == .left 69| 12| { 70| 6| if labelPosition == .outsideChart 71| 6| { 72| 6| yPos = viewPortHandler.contentTop - baseYOffset 73| 6| } 74| 6| else 75| 6| { 76| 0| yPos = viewPortHandler.contentTop - baseYOffset 77| 6| } 78| 12| } 79| 12| else 80| 12| { 81| 6| if labelPosition == .outsideChart 82| 6| { 83| 6| yPos = viewPortHandler.contentBottom + lineHeight + baseYOffset 84| 6| } 85| 6| else 86| 6| { 87| 0| yPos = viewPortHandler.contentBottom + lineHeight + baseYOffset 88| 6| } 89| 12| } 90| 12| 91| 12| // For compatibility with Android code, we keep above calculation the same, 92| 12| // And here we pull the line back up 93| 12| yPos -= lineHeight 94| 12| 95| 12| drawYLabels( 96| 12| context: context, 97| 12| fixedPosition: yPos, 98| 12| positions: transformedPositions(), 99| 12| offset: yAxis.yOffset) 100| 12| } 101| | 102| | open override func renderAxisLine(context: CGContext) 103| 12| { 104| 12| guard let yAxis = axis as? YAxis else { return } 105| 12| 106| 12| if !yAxis.isEnabled || !yAxis.drawAxisLineEnabled 107| 12| { 108| 0| return 109| 12| } 110| 12| 111| 12| context.saveGState() 112| 12| 113| 12| context.setStrokeColor(yAxis.axisLineColor.cgColor) 114| 12| context.setLineWidth(yAxis.axisLineWidth) 115| 12| if yAxis.axisLineDashLengths != nil 116| 12| { 117| 0| context.setLineDash(phase: yAxis.axisLineDashPhase, lengths: yAxis.axisLineDashLengths) 118| 12| } 119| 12| else 120| 12| { 121| 12| context.setLineDash(phase: 0.0, lengths: []) 122| 12| } 123| 12| 124| 12| if yAxis.axisDependency == .left 125| 12| { 126| 6| context.beginPath() 127| 6| context.move(to: CGPoint(x: viewPortHandler.contentLeft, y: viewPortHandler.contentTop)) 128| 6| context.addLine(to: CGPoint(x: viewPortHandler.contentRight, y: viewPortHandler.contentTop)) 129| 6| context.strokePath() 130| 12| } 131| 12| else 132| 12| { 133| 6| context.beginPath() 134| 6| context.move(to: CGPoint(x: viewPortHandler.contentLeft, y: viewPortHandler.contentBottom)) 135| 6| context.addLine(to: CGPoint(x: viewPortHandler.contentRight, y: viewPortHandler.contentBottom)) 136| 12| context.strokePath() } 137| 12| 138| 12| context.restoreGState() 139| 12| } 140| | 141| | /// draws the y-labels on the specified x-position 142| | @objc open func drawYLabels( 143| | context: CGContext, 144| | fixedPosition: CGFloat, 145| | positions: [CGPoint], 146| | offset: CGFloat) 147| 12| { 148| 12| guard let 149| 12| yAxis = axis as? YAxis 150| 12| else { return } 151| 12| 152| 12| let labelFont = yAxis.labelFont 153| 12| let labelTextColor = yAxis.labelTextColor 154| 12| 155| 12| let from = yAxis.isDrawBottomYLabelEntryEnabled ? 0 : 1 156| 12| let to = yAxis.isDrawTopYLabelEntryEnabled ? yAxis.entryCount : (yAxis.entryCount - 1) 157| 12| 158| 12| let xOffset = yAxis.labelXOffset 159| 12| 160| 12| for i in stride(from: from, to: to, by: 1) 161| 66| { 162| 66| let text = yAxis.getFormattedLabel(i) 163| 66| 164| 66| ChartUtils.drawText( 165| 66| context: context, 166| 66| text: text, 167| 66| point: CGPoint( 168| 66| x: positions[i].x, y: 169| 66| fixedPosition - offset + xOffset 170| 66| ), 171| 66| align: .center, 172| 66| attributes: [NSAttributedString.Key.font: labelFont, NSAttributedString.Key.foregroundColor: labelTextColor]) 173| 66| } 174| 12| } 175| | 176| | open override var gridClippingRect: CGRect 177| 12| { 178| 12| var contentRect = viewPortHandler.contentRect 179| 12| let dx = self.axis?.gridLineWidth ?? 0.0 180| 12| contentRect.origin.x -= dx / 2.0 181| 12| contentRect.size.width += dx 182| 12| return contentRect 183| 12| } 184| | 185| | open override func drawGridLine( 186| | context: CGContext, 187| | position: CGPoint) 188| 66| { 189| 66| context.beginPath() 190| 66| context.move(to: CGPoint(x: position.x, y: viewPortHandler.contentTop)) 191| 66| context.addLine(to: CGPoint(x: position.x, y: viewPortHandler.contentBottom)) 192| 66| context.strokePath() 193| 66| } 194| | 195| | open override func transformedPositions() -> [CGPoint] 196| 24| { 197| 24| guard 198| 24| let yAxis = self.axis as? YAxis, 199| 24| let transformer = self.transformer 200| 24| else { return [CGPoint]() } 201| 24| 202| 24| var positions = [CGPoint]() 203| 24| positions.reserveCapacity(yAxis.entryCount) 204| 24| 205| 24| let entries = yAxis.entries 206| 24| 207| 24| for i in stride(from: 0, to: yAxis.entryCount, by: 1) 208| 132| { 209| 132| positions.append(CGPoint(x: entries[i], y: 0.0)) 210| 132| } 211| 24| 212| 24| transformer.pointValuesToPixel(&positions) 213| 24| 214| 24| return positions 215| 24| } 216| | 217| | /// Draws the zero line at the specified position. 218| | open override func drawZeroLine(context: CGContext) 219| 0| { 220| 0| guard 221| 0| let yAxis = self.axis as? YAxis, 222| 0| let transformer = self.transformer, 223| 0| let zeroLineColor = yAxis.zeroLineColor 224| 0| else { return } 225| 0| 226| 0| context.saveGState() 227| 0| defer { context.restoreGState() } 228| 0| 229| 0| var clippingRect = viewPortHandler.contentRect 230| 0| clippingRect.origin.x -= yAxis.zeroLineWidth / 2.0 231| 0| clippingRect.size.width += yAxis.zeroLineWidth 232| 0| context.clip(to: clippingRect) 233| 0| 234| 0| context.setStrokeColor(zeroLineColor.cgColor) 235| 0| context.setLineWidth(yAxis.zeroLineWidth) 236| 0| 237| 0| let pos = transformer.pixelForValues(x: 0.0, y: 0.0) 238| 0| 239| 0| if yAxis.zeroLineDashLengths != nil 240| 0| { 241| 0| context.setLineDash(phase: yAxis.zeroLineDashPhase, lengths: yAxis.zeroLineDashLengths!) 242| 0| } 243| 0| else 244| 0| { 245| 0| context.setLineDash(phase: 0.0, lengths: []) 246| 0| } 247| 0| 248| 0| context.move(to: CGPoint(x: pos.x - 1.0, y: viewPortHandler.contentTop)) 249| 0| context.addLine(to: CGPoint(x: pos.x - 1.0, y: viewPortHandler.contentBottom)) 250| 0| context.drawPath(using: CGPathDrawingMode.stroke) 251| 0| } 252| | 253| | private var _limitLineSegmentsBuffer = [CGPoint](repeating: CGPoint(), count: 2) 254| | 255| | open override func renderLimitLines(context: CGContext) 256| 12| { 257| 12| guard 258| 12| let yAxis = axis as? YAxis, 259| 12| let transformer = self.transformer 260| 12| else { return } 261| 12| 262| 12| let limitLines = yAxis.limitLines 263| 12| 264| 12| if limitLines.count <= 0 265| 12| { 266| 12| return 267| 12| } 268| 0| 269| 0| context.saveGState() 270| 0| 271| 0| let trans = transformer.valueToPixelMatrix 272| 0| 273| 0| var position = CGPoint(x: 0.0, y: 0.0) 274| 0| 275| 0| for i in 0 ..< limitLines.count 276| 0| { 277| 0| let l = limitLines[i] 278| 0| 279| 0| if !l.isEnabled 280| 0| { 281| 0| continue 282| 0| } 283| 0| 284| 0| context.saveGState() 285| 0| defer { context.restoreGState() } 286| 0| 287| 0| var clippingRect = viewPortHandler.contentRect 288| 0| clippingRect.origin.x -= l.lineWidth / 2.0 289| 0| clippingRect.size.width += l.lineWidth 290| 0| context.clip(to: clippingRect) 291| 0| 292| 0| position.x = CGFloat(l.limit) 293| 0| position.y = 0.0 294| 0| position = position.applying(trans) 295| 0| 296| 0| context.beginPath() 297| 0| context.move(to: CGPoint(x: position.x, y: viewPortHandler.contentTop)) 298| 0| context.addLine(to: CGPoint(x: position.x, y: viewPortHandler.contentBottom)) 299| 0| 300| 0| context.setStrokeColor(l.lineColor.cgColor) 301| 0| context.setLineWidth(l.lineWidth) 302| 0| if l.lineDashLengths != nil 303| 0| { 304| 0| context.setLineDash(phase: l.lineDashPhase, lengths: l.lineDashLengths!) 305| 0| } 306| 0| else 307| 0| { 308| 0| context.setLineDash(phase: 0.0, lengths: []) 309| 0| } 310| 0| 311| 0| context.strokePath() 312| 0| 313| 0| let label = l.label 314| 0| 315| 0| // if drawing the limit-value label is enabled 316| 0| if l.drawLabelEnabled && label.count > 0 317| 0| { 318| 0| let labelLineHeight = l.valueFont.lineHeight 319| 0| 320| 0| let xOffset: CGFloat = l.lineWidth + l.xOffset 321| 0| let yOffset: CGFloat = 2.0 + l.yOffset 322| 0| 323| 0| if l.labelPosition == .topRight 324| 0| { 325| 0| ChartUtils.drawText(context: context, 326| 0| text: label, 327| 0| point: CGPoint( 328| 0| x: position.x + xOffset, 329| 0| y: viewPortHandler.contentTop + yOffset), 330| 0| align: .left, 331| 0| attributes: [NSAttributedString.Key.font: l.valueFont, NSAttributedString.Key.foregroundColor: l.valueTextColor]) 332| 0| } 333| 0| else if l.labelPosition == .bottomRight 334| 0| { 335| 0| ChartUtils.drawText(context: context, 336| 0| text: label, 337| 0| point: CGPoint( 338| 0| x: position.x + xOffset, 339| 0| y: viewPortHandler.contentBottom - labelLineHeight - yOffset), 340| 0| align: .left, 341| 0| attributes: [NSAttributedString.Key.font: l.valueFont, NSAttributedString.Key.foregroundColor: l.valueTextColor]) 342| 0| } 343| 0| else if l.labelPosition == .topLeft 344| 0| { 345| 0| ChartUtils.drawText(context: context, 346| 0| text: label, 347| 0| point: CGPoint( 348| 0| x: position.x - xOffset, 349| 0| y: viewPortHandler.contentTop + yOffset), 350| 0| align: .right, 351| 0| attributes: [NSAttributedString.Key.font: l.valueFont, NSAttributedString.Key.foregroundColor: l.valueTextColor]) 352| 0| } 353| 0| else 354| 0| { 355| 0| ChartUtils.drawText(context: context, 356| 0| text: label, 357| 0| point: CGPoint( 358| 0| x: position.x - xOffset, 359| 0| y: viewPortHandler.contentBottom - labelLineHeight - yOffset), 360| 0| align: .right, 361| 0| attributes: [NSAttributedString.Key.font: l.valueFont, NSAttributedString.Key.foregroundColor: l.valueTextColor]) 362| 0| } 363| 0| } 364| 0| } 365| 0| 366| 0| context.restoreGState() 367| 0| } 368| |} /Users/travis/build/danielgindi/Charts/Source/Charts/Renderers/YAxisRendererRadarChart.swift: 1| |// 2| |// YAxisRendererRadarChart.swift 3| |// Charts 4| |// 5| |// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda 6| |// A port of MPAndroidChart for iOS 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| | 12| |import Foundation 13| |import CoreGraphics 14| | 15| |#if canImport(UIKit) 16| | import UIKit 17| |#endif 18| | 19| |#if canImport(Cocoa) 20| |import Cocoa 21| |#endif 22| | 23| |open class YAxisRendererRadarChart: YAxisRenderer 24| |{ 25| | private weak var chart: RadarChartView? 26| | 27| | @objc public init(viewPortHandler: ViewPortHandler, yAxis: YAxis?, chart: RadarChartView) 28| 0| { 29| 0| super.init(viewPortHandler: viewPortHandler, yAxis: yAxis, transformer: nil) 30| 0| 31| 0| self.chart = chart 32| 0| } 33| | 34| | open override func computeAxisValues(min yMin: Double, max yMax: Double) 35| 0| { 36| 0| guard let 37| 0| axis = axis as? YAxis 38| 0| else { return } 39| 0| 40| 0| let labelCount = axis.labelCount 41| 0| let range = abs(yMax - yMin) 42| 0| 43| 0| if labelCount == 0 || range <= 0 || range.isInfinite 44| 0| { 45| 0| axis.entries = [Double]() 46| 0| axis.centeredEntries = [Double]() 47| 0| return 48| 0| } 49| 0| 50| 0| // Find out how much spacing (in yValue space) between axis values 51| 0| let rawInterval = range / Double(labelCount) 52| 0| var interval = rawInterval.roundedToNextSignficant() 53| 0| 54| 0| // If granularity is enabled, then do not allow the interval to go below specified granularity. 55| 0| // This is used to avoid repeated values when rounding values for display. 56| 0| if axis.isGranularityEnabled 57| 0| { 58| 0| interval = interval < axis.granularity ? axis.granularity : interval 59| 0| } 60| 0| 61| 0| // Normalize interval 62| 0| let intervalMagnitude = pow(10.0, floor(log10(interval))).roundedToNextSignficant() 63| 0| let intervalSigDigit = Int(interval / intervalMagnitude) 64| 0| 65| 0| if intervalSigDigit > 5 66| 0| { 67| 0| // Use one order of magnitude higher, to avoid intervals like 0.9 or 90 68| 0| // if it's 0.0 after floor(), we use the old value 69| 0| interval = floor(10.0 * intervalMagnitude) == 0.0 ? interval : floor(10.0 * intervalMagnitude) 70| 0| } 71| 0| 72| 0| let centeringEnabled = axis.isCenterAxisLabelsEnabled 73| 0| var n = centeringEnabled ? 1 : 0 74| 0| 75| 0| // force label count 76| 0| if axis.isForceLabelsEnabled 77| 0| { 78| 0| let step = Double(range) / Double(labelCount - 1) 79| 0| 80| 0| // Ensure stops contains at least n elements. 81| 0| axis.entries.removeAll(keepingCapacity: true) 82| 0| axis.entries.reserveCapacity(labelCount) 83| 0| 84| 0| var v = yMin 85| 0| 86| 0| for _ in 0 ..< labelCount 87| 0| { 88| 0| axis.entries.append(v) 89| 0| v += step 90| 0| } 91| 0| 92| 0| n = labelCount 93| 0| } 94| 0| else 95| 0| { 96| 0| // no forced count 97| 0| 98| 0| var first = interval == 0.0 ? 0.0 : ceil(yMin / interval) * interval 99| 0| 100| 0| if centeringEnabled 101| 0| { 102| 0| first -= interval 103| 0| } 104| 0| 105| 0| let last = interval == 0.0 ? 0.0 : (floor(yMax / interval) * interval).nextUp 106| 0| 107| 0| if interval != 0.0 108| 0| { 109| 0| for _ in stride(from: first, through: last, by: interval) 110| 0| { 111| 0| n += 1 112| 0| } 113| 0| } 114| 0| 115| 0| n += 1 116| 0| 117| 0| // Ensure stops contains at least n elements. 118| 0| axis.entries.removeAll(keepingCapacity: true) 119| 0| axis.entries.reserveCapacity(labelCount) 120| 0| 121| 0| var f = first 122| 0| var i = 0 123| 0| while i < n 124| 0| { 125| 0| if f == 0.0 126| 0| { 127| 0| // Fix for IEEE negative zero case (Where value == -0.0, and 0.0 == -0.0) 128| 0| f = 0.0 129| 0| } 130| 0| 131| 0| axis.entries.append(Double(f)) 132| 0| 133| 0| f += interval 134| 0| i += 1 135| 0| } 136| 0| } 137| 0| 138| 0| // set decimals 139| 0| if interval < 1 140| 0| { 141| 0| axis.decimals = Int(ceil(-log10(interval))) 142| 0| } 143| 0| else 144| 0| { 145| 0| axis.decimals = 0 146| 0| } 147| 0| 148| 0| if centeringEnabled 149| 0| { 150| 0| axis.centeredEntries.reserveCapacity(n) 151| 0| axis.centeredEntries.removeAll() 152| 0| 153| 0| let offset = (axis.entries[1] - axis.entries[0]) / 2.0 154| 0| 155| 0| for i in 0 ..< n 156| 0| { 157| 0| axis.centeredEntries.append(axis.entries[i] + offset) 158| 0| } 159| 0| } 160| 0| 161| 0| axis._axisMinimum = axis.entries[0] 162| 0| axis._axisMaximum = axis.entries[n-1] 163| 0| axis.axisRange = abs(axis._axisMaximum - axis._axisMinimum) 164| 0| } 165| | 166| | open override func renderAxisLabels(context: CGContext) 167| 0| { 168| 0| guard let 169| 0| yAxis = axis as? YAxis, 170| 0| let chart = chart 171| 0| else { return } 172| 0| 173| 0| if !yAxis.isEnabled || !yAxis.isDrawLabelsEnabled 174| 0| { 175| 0| return 176| 0| } 177| 0| 178| 0| let labelFont = yAxis.labelFont 179| 0| let labelTextColor = yAxis.labelTextColor 180| 0| 181| 0| let center = chart.centerOffsets 182| 0| let factor = chart.factor 183| 0| 184| 0| let labelLineHeight = yAxis.labelFont.lineHeight 185| 0| 186| 0| let from = yAxis.isDrawBottomYLabelEntryEnabled ? 0 : 1 187| 0| let to = yAxis.isDrawTopYLabelEntryEnabled ? yAxis.entryCount : (yAxis.entryCount - 1) 188| 0| 189| 0| let alignment: NSTextAlignment = yAxis.labelAlignment 190| 0| let xOffset = yAxis.labelXOffset 191| 0| 192| 0| for j in stride(from: from, to: to, by: 1) 193| 0| { 194| 0| let r = CGFloat(yAxis.entries[j] - yAxis._axisMinimum) * factor 195| 0| 196| 0| let p = center.moving(distance: r, atAngle: chart.rotationAngle) 197| 0| 198| 0| let label = yAxis.getFormattedLabel(j) 199| 0| 200| 0| ChartUtils.drawText( 201| 0| context: context, 202| 0| text: label, 203| 0| point: CGPoint(x: p.x + xOffset, y: p.y - labelLineHeight), 204| 0| align: alignment, 205| 0| attributes: [ 206| 0| NSAttributedString.Key.font: labelFont, 207| 0| NSAttributedString.Key.foregroundColor: labelTextColor 208| 0| ]) 209| 0| } 210| 0| } 211| | 212| | open override func renderLimitLines(context: CGContext) 213| 0| { 214| 0| guard 215| 0| let yAxis = axis as? YAxis, 216| 0| let chart = chart, 217| 0| let data = chart.data 218| 0| else { return } 219| 0| 220| 0| let limitLines = yAxis.limitLines 221| 0| 222| 0| if limitLines.count == 0 223| 0| { 224| 0| return 225| 0| } 226| 0| 227| 0| context.saveGState() 228| 0| 229| 0| let sliceangle = chart.sliceAngle 230| 0| 231| 0| // calculate the factor that is needed for transforming the value to pixels 232| 0| let factor = chart.factor 233| 0| 234| 0| let center = chart.centerOffsets 235| 0| 236| 0| for i in 0 ..< limitLines.count 237| 0| { 238| 0| let l = limitLines[i] 239| 0| 240| 0| if !l.isEnabled 241| 0| { 242| 0| continue 243| 0| } 244| 0| 245| 0| context.setStrokeColor(l.lineColor.cgColor) 246| 0| context.setLineWidth(l.lineWidth) 247| 0| if l.lineDashLengths != nil 248| 0| { 249| 0| context.setLineDash(phase: l.lineDashPhase, lengths: l.lineDashLengths!) 250| 0| } 251| 0| else 252| 0| { 253| 0| context.setLineDash(phase: 0.0, lengths: []) 254| 0| } 255| 0| 256| 0| let r = CGFloat(l.limit - chart.chartYMin) * factor 257| 0| 258| 0| context.beginPath() 259| 0| 260| 0| for j in 0 ..< (data.maxEntryCountSet?.entryCount ?? 0) 261| 0| { 262| 0| let p = center.moving(distance: r, atAngle: sliceangle * CGFloat(j) + chart.rotationAngle) 263| 0| 264| 0| if j == 0 265| 0| { 266| 0| context.move(to: CGPoint(x: p.x, y: p.y)) 267| 0| } 268| 0| else 269| 0| { 270| 0| context.addLine(to: CGPoint(x: p.x, y: p.y)) 271| 0| } 272| 0| } 273| 0| 274| 0| context.closePath() 275| 0| 276| 0| context.strokePath() 277| 0| } 278| 0| 279| 0| context.restoreGState() 280| 0| } 281| |} /Users/travis/build/danielgindi/Charts/Source/Charts/Utils/ChartColorTemplates.swift: 1| |// 2| |// ChartColorTemplates.swift 3| |// Charts 4| |// 5| |// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda 6| |// A port of MPAndroidChart for iOS 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| | 12| |import Foundation 13| |import CoreGraphics 14| | 15| |open class ChartColorTemplates: NSObject 16| |{ 17| | @objc open class func liberty () -> [NSUIColor] 18| 6| { 19| 6| return [ 20| 6| NSUIColor(red: 207/255.0, green: 248/255.0, blue: 246/255.0, alpha: 1.0), 21| 6| NSUIColor(red: 148/255.0, green: 212/255.0, blue: 212/255.0, alpha: 1.0), 22| 6| NSUIColor(red: 136/255.0, green: 180/255.0, blue: 187/255.0, alpha: 1.0), 23| 6| NSUIColor(red: 118/255.0, green: 174/255.0, blue: 175/255.0, alpha: 1.0), 24| 6| NSUIColor(red: 42/255.0, green: 109/255.0, blue: 130/255.0, alpha: 1.0) 25| 6| ] 26| 6| } 27| | 28| | @objc open class func joyful () -> [NSUIColor] 29| 6| { 30| 6| return [ 31| 6| NSUIColor(red: 217/255.0, green: 80/255.0, blue: 138/255.0, alpha: 1.0), 32| 6| NSUIColor(red: 254/255.0, green: 149/255.0, blue: 7/255.0, alpha: 1.0), 33| 6| NSUIColor(red: 254/255.0, green: 247/255.0, blue: 120/255.0, alpha: 1.0), 34| 6| NSUIColor(red: 106/255.0, green: 167/255.0, blue: 134/255.0, alpha: 1.0), 35| 6| NSUIColor(red: 53/255.0, green: 194/255.0, blue: 209/255.0, alpha: 1.0) 36| 6| ] 37| 6| } 38| | 39| | @objc open class func pastel () -> [NSUIColor] 40| 6| { 41| 6| return [ 42| 6| NSUIColor(red: 64/255.0, green: 89/255.0, blue: 128/255.0, alpha: 1.0), 43| 6| NSUIColor(red: 149/255.0, green: 165/255.0, blue: 124/255.0, alpha: 1.0), 44| 6| NSUIColor(red: 217/255.0, green: 184/255.0, blue: 162/255.0, alpha: 1.0), 45| 6| NSUIColor(red: 191/255.0, green: 134/255.0, blue: 134/255.0, alpha: 1.0), 46| 6| NSUIColor(red: 179/255.0, green: 48/255.0, blue: 80/255.0, alpha: 1.0) 47| 6| ] 48| 6| } 49| | 50| | @objc open class func colorful () -> [NSUIColor] 51| 6| { 52| 6| return [ 53| 6| NSUIColor(red: 193/255.0, green: 37/255.0, blue: 82/255.0, alpha: 1.0), 54| 6| NSUIColor(red: 255/255.0, green: 102/255.0, blue: 0/255.0, alpha: 1.0), 55| 6| NSUIColor(red: 245/255.0, green: 199/255.0, blue: 0/255.0, alpha: 1.0), 56| 6| NSUIColor(red: 106/255.0, green: 150/255.0, blue: 31/255.0, alpha: 1.0), 57| 6| NSUIColor(red: 179/255.0, green: 100/255.0, blue: 53/255.0, alpha: 1.0) 58| 6| ] 59| 6| } 60| | 61| | @objc open class func vordiplom () -> [NSUIColor] 62| 6| { 63| 6| return [ 64| 6| NSUIColor(red: 192/255.0, green: 255/255.0, blue: 140/255.0, alpha: 1.0), 65| 6| NSUIColor(red: 255/255.0, green: 247/255.0, blue: 140/255.0, alpha: 1.0), 66| 6| NSUIColor(red: 255/255.0, green: 208/255.0, blue: 140/255.0, alpha: 1.0), 67| 6| NSUIColor(red: 140/255.0, green: 234/255.0, blue: 255/255.0, alpha: 1.0), 68| 6| NSUIColor(red: 255/255.0, green: 140/255.0, blue: 157/255.0, alpha: 1.0) 69| 6| ] 70| 6| } 71| | 72| | @objc open class func material () -> [NSUIColor] 73| 0| { 74| 0| return [ 75| 0| NSUIColor(red: 46/255.0, green: 204/255.0, blue: 113/255.0, alpha: 1.0), 76| 0| NSUIColor(red: 241/255.0, green: 196/255.0, blue: 15/255.0, alpha: 1.0), 77| 0| NSUIColor(red: 231/255.0, green: 76/255.0, blue: 60/255.0, alpha: 1.0), 78| 0| NSUIColor(red: 52/255.0, green: 152/255.0, blue: 219/255.0, alpha: 1.0) 79| 0| ] 80| 0| } 81| | 82| | @objc open class func colorFromString(_ colorString: String) -> NSUIColor 83| 0| { 84| 0| let leftParenCharset: CharacterSet = CharacterSet(charactersIn: "( ") 85| 0| let commaCharset: CharacterSet = CharacterSet(charactersIn: ", ") 86| 0| 87| 0| let colorString = colorString.lowercased() 88| 0| 89| 0| if colorString.hasPrefix("#") 90| 0| { 91| 0| var argb: [UInt] = [255, 0, 0, 0] 92| 0| let colorString = colorString.unicodeScalars 93| 0| var length = colorString.count 94| 0| var index = colorString.startIndex 95| 0| let endIndex = colorString.endIndex 96| 0| 97| 0| index = colorString.index(after: index) 98| 0| length = length - 1 99| 0| 100| 0| if length == 3 || length == 6 || length == 8 101| 0| { 102| 0| var i = length == 8 ? 0 : 1 103| 0| while index < endIndex 104| 0| { 105| 0| var c = colorString[index] 106| 0| index = colorString.index(after: index) 107| 0| 108| 0| var val = (c.value >= 0x61 && c.value <= 0x66) ? (c.value - 0x61 + 10) : c.value - 0x30 109| 0| argb[i] = UInt(val) * 16 110| 0| if length == 3 111| 0| { 112| 0| argb[i] = argb[i] + UInt(val) 113| 0| } 114| 0| else 115| 0| { 116| 0| c = colorString[index] 117| 0| index = colorString.index(after: index) 118| 0| 119| 0| val = (c.value >= 0x61 && c.value <= 0x66) ? (c.value - 0x61 + 10) : c.value - 0x30 120| 0| argb[i] = argb[i] + UInt(val) 121| 0| } 122| 0| 123| 0| i += 1 124| 0| } 125| 0| } 126| 0| 127| 0| 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) 128| 0| } 129| 0| else if colorString.hasPrefix("rgba") 130| 0| { 131| 0| var a: Float = 1.0 132| 0| var r: Int32 = 0 133| 0| var g: Int32 = 0 134| 0| var b: Int32 = 0 135| 0| let scanner: Scanner = Scanner(string: colorString) 136| 0| scanner.scanString("rgba", into: nil) 137| 0| scanner.scanCharacters(from: leftParenCharset, into: nil) 138| 0| scanner.scanInt32(&r) 139| 0| scanner.scanCharacters(from: commaCharset, into: nil) 140| 0| scanner.scanInt32(&g) 141| 0| scanner.scanCharacters(from: commaCharset, into: nil) 142| 0| scanner.scanInt32(&b) 143| 0| scanner.scanCharacters(from: commaCharset, into: nil) 144| 0| scanner.scanFloat(&a) 145| 0| return NSUIColor( 146| 0| red: CGFloat(r) / 255.0, 147| 0| green: CGFloat(g) / 255.0, 148| 0| blue: CGFloat(b) / 255.0, 149| 0| alpha: CGFloat(a) 150| 0| ) 151| 0| } 152| 0| else if colorString.hasPrefix("argb") 153| 0| { 154| 0| var a: Float = 1.0 155| 0| var r: Int32 = 0 156| 0| var g: Int32 = 0 157| 0| var b: Int32 = 0 158| 0| let scanner: Scanner = Scanner(string: colorString) 159| 0| scanner.scanString("argb", into: nil) 160| 0| scanner.scanCharacters(from: leftParenCharset, into: nil) 161| 0| scanner.scanFloat(&a) 162| 0| scanner.scanCharacters(from: commaCharset, into: nil) 163| 0| scanner.scanInt32(&r) 164| 0| scanner.scanCharacters(from: commaCharset, into: nil) 165| 0| scanner.scanInt32(&g) 166| 0| scanner.scanCharacters(from: commaCharset, into: nil) 167| 0| scanner.scanInt32(&b) 168| 0| return NSUIColor( 169| 0| red: CGFloat(r) / 255.0, 170| 0| green: CGFloat(g) / 255.0, 171| 0| blue: CGFloat(b) / 255.0, 172| 0| alpha: CGFloat(a) 173| 0| ) 174| 0| } 175| 0| else if colorString.hasPrefix("rgb") 176| 0| { 177| 0| var r: Int32 = 0 178| 0| var g: Int32 = 0 179| 0| var b: Int32 = 0 180| 0| let scanner: Scanner = Scanner(string: colorString) 181| 0| scanner.scanString("rgb", into: nil) 182| 0| scanner.scanCharacters(from: leftParenCharset, into: nil) 183| 0| scanner.scanInt32(&r) 184| 0| scanner.scanCharacters(from: commaCharset, into: nil) 185| 0| scanner.scanInt32(&g) 186| 0| scanner.scanCharacters(from: commaCharset, into: nil) 187| 0| scanner.scanInt32(&b) 188| 0| return NSUIColor( 189| 0| red: CGFloat(r) / 255.0, 190| 0| green: CGFloat(g) / 255.0, 191| 0| blue: CGFloat(b) / 255.0, 192| 0| alpha: 1.0 193| 0| ) 194| 0| } 195| 0| 196| 0| return NSUIColor.clear 197| 0| } 198| |} /Users/travis/build/danielgindi/Charts/Source/Charts/Utils/ChartUtils.swift: 1| |// 2| |// Utils.swift 3| |// Charts 4| |// 5| |// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda 6| |// A port of MPAndroidChart for iOS 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| | 12| |import Foundation 13| |import CoreGraphics 14| | 15| |#if canImport(UIKit) 16| | import UIKit 17| |#endif 18| | 19| |#if canImport(Cocoa) 20| |import Cocoa 21| |#endif 22| | 23| |extension Comparable 24| |{ 25| | func clamped(to range: ClosedRange) -> Self 26| 0| { 27| 0| if self > range.upperBound 28| 0| { 29| 0| return range.upperBound 30| 0| } 31| 0| else if self < range.lowerBound 32| 0| { 33| 0| return range.lowerBound 34| 0| } 35| 0| else 36| 0| { 37| 0| return self 38| 0| } 39| 0| } 40| |} 41| | 42| |extension FloatingPoint 43| |{ 44| | var DEG2RAD: Self 45| 718| { 46| 718| return self * .pi / 180 47| 718| } 48| | 49| | var RAD2DEG: Self 50| 0| { 51| 0| return self * 180 / .pi 52| 0| } 53| | 54| | /// - Note: Value must be in degrees 55| | /// - Returns: An angle between 0.0 < 360.0 (not less than zero, less than 360) 56| | var normalizedAngle: Self 57| 0| { 58| 0| let angle = truncatingRemainder(dividingBy: 360) 59| 0| return (sign == .minus) ? angle + 360 : angle 60| 0| } 61| |} 62| | 63| |extension CGSize 64| |{ 65| | func rotatedBy(degrees: CGFloat) -> CGSize 66| 125| { 67| 125| let radians = degrees.DEG2RAD 68| 125| return rotatedBy(radians: radians) 69| 125| } 70| | 71| | func rotatedBy(radians: CGFloat) -> CGSize 72| 125| { 73| 125| return CGSize( 74| 125| width: abs(width * cos(radians)) + abs(height * sin(radians)), 75| 125| height: abs(width * sin(radians)) + abs(height * cos(radians)) 76| 125| ) 77| 125| } 78| |} 79| | 80| |extension Double 81| |{ 82| | /// Rounds the number to the nearest multiple of it's order of magnitude, rounding away from zero if halfway. 83| | func roundedToNextSignficant() -> Double 84| 800| { 85| 800| guard 86| 800| !isInfinite, 87| 800| !isNaN, 88| 800| self != 0 89| 800| else { return self } 90| 800| 91| 800| let d = ceil(log10(self < 0 ? -self : self)) 92| 800| let pw = 1 - Int(d) 93| 800| let magnitude = pow(10.0, Double(pw)) 94| 800| let shifted = (self * magnitude).rounded() 95| 800| return shifted / magnitude 96| 800| } 97| | 98| | var decimalPlaces: Int 99| 58| { 100| 58| guard 101| 58| !isNaN, 102| 58| !isInfinite, 103| 58| self != 0.0 104| 58| else { return 0 } 105| 54| 106| 54| let i = self.roundedToNextSignficant() 107| 54| 108| 54| guard 109| 54| !i.isInfinite, 110| 54| !i.isNaN 111| 54| else { return 0 } 112| 53| 113| 53| return Int(ceil(-log10(i))) + 2 114| 54| } 115| |} 116| | 117| |extension CGPoint 118| |{ 119| | /// Calculates the position around a center point, depending on the distance from the center, and the angle of the position around the center. 120| | func moving(distance: CGFloat, atAngle angle: CGFloat) -> CGPoint 121| 0| { 122| 0| return CGPoint(x: x + distance * cos(angle.DEG2RAD), 123| 0| y: y + distance * sin(angle.DEG2RAD)) 124| 0| } 125| |} 126| | 127| |open class ChartUtils 128| |{ 129| | private static var _defaultValueFormatter: IValueFormatter = ChartUtils.generateDefaultValueFormatter() 130| | 131| | open class func drawImage( 132| | context: CGContext, 133| | image: NSUIImage, 134| | x: CGFloat, 135| | y: CGFloat, 136| | size: CGSize) 137| 67| { 138| 67| var drawOffset = CGPoint() 139| 67| drawOffset.x = x - (size.width / 2) 140| 67| drawOffset.y = y - (size.height / 2) 141| 67| 142| 67| NSUIGraphicsPushContext(context) 143| 67| 144| 67| if image.size.width != size.width && image.size.height != size.height 145| 67| { 146| 0| let key = "resized_\(size.width)_\(size.height)" 147| 0| 148| 0| // Try to take scaled image from cache of this image 149| 0| var scaledImage = objc_getAssociatedObject(image, key) as? NSUIImage 150| 0| if scaledImage == nil 151| 0| { 152| 0| // Scale the image 153| 0| NSUIGraphicsBeginImageContextWithOptions(size, false, 0.0) 154| 0| 155| 0| image.draw(in: CGRect(origin: CGPoint(x: 0, y: 0), size: size)) 156| 0| 157| 0| scaledImage = NSUIGraphicsGetImageFromCurrentImageContext() 158| 0| NSUIGraphicsEndImageContext() 159| 0| 160| 0| // Put the scaled image in a cache owned by the original image 161| 0| objc_setAssociatedObject(image, key, scaledImage, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) 162| 0| } 163| 0| 164| 0| scaledImage?.draw(in: CGRect(origin: drawOffset, size: size)) 165| 67| } 166| 67| else 167| 67| { 168| 67| image.draw(in: CGRect(origin: drawOffset, size: size)) 169| 67| } 170| 67| 171| 67| NSUIGraphicsPopContext() 172| 67| } 173| | 174| | open class func drawText(context: CGContext, text: String, point: CGPoint, align: NSTextAlignment, attributes: [NSAttributedString.Key : Any]?) 175| 1.86k| { 176| 1.86k| var point = point 177| 1.86k| 178| 1.86k| if align == .center 179| 1.86k| { 180| 1.23k| point.x -= text.size(withAttributes: attributes).width / 2.0 181| 1.86k| } 182| 1.86k| else if align == .right 183| 1.86k| { 184| 236| point.x -= text.size(withAttributes: attributes).width 185| 1.86k| } 186| 1.86k| 187| 1.86k| NSUIGraphicsPushContext(context) 188| 1.86k| 189| 1.86k| (text as NSString).draw(at: point, withAttributes: attributes) 190| 1.86k| 191| 1.86k| NSUIGraphicsPopContext() 192| 1.86k| } 193| | 194| | open class func drawText(context: CGContext, text: String, point: CGPoint, attributes: [NSAttributedString.Key : Any]?, anchor: CGPoint, angleRadians: CGFloat) 195| 36| { 196| 36| var drawOffset = CGPoint() 197| 36| 198| 36| NSUIGraphicsPushContext(context) 199| 36| 200| 36| if angleRadians != 0.0 201| 36| { 202| 0| let size = text.size(withAttributes: attributes) 203| 0| 204| 0| // Move the text drawing rect in a way that it always rotates around its center 205| 0| drawOffset.x = -size.width * 0.5 206| 0| drawOffset.y = -size.height * 0.5 207| 0| 208| 0| var translate = point 209| 0| 210| 0| // Move the "outer" rect relative to the anchor, assuming its centered 211| 0| if anchor.x != 0.5 || anchor.y != 0.5 212| 0| { 213| 0| let rotatedSize = size.rotatedBy(radians: angleRadians) 214| 0| 215| 0| translate.x -= rotatedSize.width * (anchor.x - 0.5) 216| 0| translate.y -= rotatedSize.height * (anchor.y - 0.5) 217| 0| } 218| 0| 219| 0| context.saveGState() 220| 0| context.translateBy(x: translate.x, y: translate.y) 221| 0| context.rotate(by: angleRadians) 222| 0| 223| 0| (text as NSString).draw(at: drawOffset, withAttributes: attributes) 224| 0| 225| 0| context.restoreGState() 226| 36| } 227| 36| else 228| 36| { 229| 36| if anchor.x != 0.0 || anchor.y != 0.0 230| 36| { 231| 36| let size = text.size(withAttributes: attributes) 232| 36| 233| 36| drawOffset.x = -size.width * anchor.x 234| 36| drawOffset.y = -size.height * anchor.y 235| 36| } 236| 36| 237| 36| drawOffset.x += point.x 238| 36| drawOffset.y += point.y 239| 36| 240| 36| (text as NSString).draw(at: drawOffset, withAttributes: attributes) 241| 36| } 242| 36| 243| 36| NSUIGraphicsPopContext() 244| 36| } 245| | 246| | internal class func drawMultilineText(context: CGContext, text: String, knownTextSize: CGSize, point: CGPoint, attributes: [NSAttributedString.Key : Any]?, constrainedToSize: CGSize, anchor: CGPoint, angleRadians: CGFloat) 247| 240| { 248| 240| var rect = CGRect(origin: CGPoint(), size: knownTextSize) 249| 240| 250| 240| NSUIGraphicsPushContext(context) 251| 240| 252| 240| if angleRadians != 0.0 253| 240| { 254| 0| // Move the text drawing rect in a way that it always rotates around its center 255| 0| rect.origin.x = -knownTextSize.width * 0.5 256| 0| rect.origin.y = -knownTextSize.height * 0.5 257| 0| 258| 0| var translate = point 259| 0| 260| 0| // Move the "outer" rect relative to the anchor, assuming its centered 261| 0| if anchor.x != 0.5 || anchor.y != 0.5 262| 0| { 263| 0| let rotatedSize = knownTextSize.rotatedBy(radians: angleRadians) 264| 0| 265| 0| translate.x -= rotatedSize.width * (anchor.x - 0.5) 266| 0| translate.y -= rotatedSize.height * (anchor.y - 0.5) 267| 0| } 268| 0| 269| 0| context.saveGState() 270| 0| context.translateBy(x: translate.x, y: translate.y) 271| 0| context.rotate(by: angleRadians) 272| 0| 273| 0| (text as NSString).draw(with: rect, options: .usesLineFragmentOrigin, attributes: attributes, context: nil) 274| 0| 275| 0| context.restoreGState() 276| 240| } 277| 240| else 278| 240| { 279| 240| if anchor.x != 0.0 || anchor.y != 0.0 280| 240| { 281| 240| rect.origin.x = -knownTextSize.width * anchor.x 282| 240| rect.origin.y = -knownTextSize.height * anchor.y 283| 240| } 284| 240| 285| 240| rect.origin.x += point.x 286| 240| rect.origin.y += point.y 287| 240| 288| 240| (text as NSString).draw(with: rect, options: .usesLineFragmentOrigin, attributes: attributes, context: nil) 289| 240| } 290| 240| 291| 240| NSUIGraphicsPopContext() 292| 240| } 293| | 294| | internal class func drawMultilineText(context: CGContext, text: String, point: CGPoint, attributes: [NSAttributedString.Key : Any]?, constrainedToSize: CGSize, anchor: CGPoint, angleRadians: CGFloat) 295| 240| { 296| 240| let rect = text.boundingRect(with: constrainedToSize, options: .usesLineFragmentOrigin, attributes: attributes, context: nil) 297| 240| drawMultilineText(context: context, text: text, knownTextSize: rect.size, point: point, attributes: attributes, constrainedToSize: constrainedToSize, anchor: anchor, angleRadians: angleRadians) 298| 240| } 299| | 300| | private class func generateDefaultValueFormatter() -> IValueFormatter 301| 0| { 302| 0| let formatter = DefaultValueFormatter(decimals: 1) 303| 0| return formatter 304| 0| } 305| | 306| | /// - Returns: The default value formatter used for all chart components that needs a default 307| | open class func defaultValueFormatter() -> IValueFormatter 308| 0| { 309| 0| return _defaultValueFormatter 310| 0| } 311| |} /Users/travis/build/danielgindi/Charts/Source/Charts/Utils/Fill.swift: 1| |// 2| |// Fill.swift 3| |// Charts 4| |// 5| |// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda 6| |// A port of MPAndroidChart for iOS 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| | 12| |import Foundation 13| |import CoreGraphics 14| | 15| |@objc(ChartFillType) 16| |public enum FillType: Int 17| |{ 18| | case empty 19| | case color 20| | case linearGradient 21| | case radialGradient 22| | case image 23| | case tiledImage 24| | case layer 25| |} 26| | 27| |@objc(ChartFill) 28| |open class Fill: NSObject 29| |{ 30| | private var _type: FillType = FillType.empty 31| | private var _color: CGColor? 32| | private var _gradient: CGGradient? 33| | private var _gradientAngle: CGFloat = 0.0 34| | private var _gradientStartOffsetPercent: CGPoint = CGPoint() 35| | private var _gradientStartRadiusPercent: CGFloat = 0.0 36| | private var _gradientEndOffsetPercent: CGPoint = CGPoint() 37| | private var _gradientEndRadiusPercent: CGFloat = 0.0 38| | private var _image: CGImage? 39| | private var _layer: CGLayer? 40| | 41| | // MARK: Properties 42| | 43| | @objc open var type: FillType 44| 0| { 45| 0| return _type 46| 0| } 47| | 48| | @objc open var color: CGColor? 49| 0| { 50| 0| return _color 51| 0| } 52| | 53| | @objc open var gradient: CGGradient? 54| 0| { 55| 0| return _gradient 56| 0| } 57| | 58| | @objc open var gradientAngle: CGFloat 59| 0| { 60| 0| return _gradientAngle 61| 0| } 62| | 63| | @objc open var gradientStartOffsetPercent: CGPoint 64| 0| { 65| 0| return _gradientStartOffsetPercent 66| 0| } 67| | 68| | @objc open var gradientStartRadiusPercent: CGFloat 69| 0| { 70| 0| return _gradientStartRadiusPercent 71| 0| } 72| | 73| | @objc open var gradientEndOffsetPercent: CGPoint 74| 0| { 75| 0| return _gradientEndOffsetPercent 76| 0| } 77| | 78| | @objc open var gradientEndRadiusPercent: CGFloat 79| 0| { 80| 0| return _gradientEndRadiusPercent 81| 0| } 82| | 83| | @objc open var image: CGImage? 84| 0| { 85| 0| return _image 86| 0| } 87| | 88| | @objc open var layer: CGLayer? 89| 0| { 90| 0| return _layer 91| 0| } 92| | 93| | // MARK: Constructors 94| | 95| | public override init() 96| 0| { 97| 0| } 98| | 99| | @objc public init(CGColor: CGColor) 100| 0| { 101| 0| _type = .color 102| 0| _color = CGColor 103| 0| } 104| | 105| | @objc public convenience init(color: NSUIColor) 106| 0| { 107| 0| self.init(CGColor: color.cgColor) 108| 0| } 109| | 110| | @objc public init(linearGradient: CGGradient, angle: CGFloat) 111| 0| { 112| 0| _type = .linearGradient 113| 0| _gradient = linearGradient 114| 0| _gradientAngle = angle 115| 0| } 116| | 117| | @objc public init( 118| | radialGradient: CGGradient, 119| | startOffsetPercent: CGPoint, 120| | startRadiusPercent: CGFloat, 121| | endOffsetPercent: CGPoint, 122| | endRadiusPercent: CGFloat 123| | ) 124| 0| { 125| 0| _type = .radialGradient 126| 0| _gradient = radialGradient 127| 0| _gradientStartOffsetPercent = startOffsetPercent 128| 0| _gradientStartRadiusPercent = startRadiusPercent 129| 0| _gradientEndOffsetPercent = endOffsetPercent 130| 0| _gradientEndRadiusPercent = endRadiusPercent 131| 0| } 132| | 133| | @objc public convenience init(radialGradient: CGGradient) 134| 0| { 135| 0| self.init( 136| 0| radialGradient: radialGradient, 137| 0| startOffsetPercent: CGPoint(x: 0.0, y: 0.0), 138| 0| startRadiusPercent: 0.0, 139| 0| endOffsetPercent: CGPoint(x: 0.0, y: 0.0), 140| 0| endRadiusPercent: 1.0 141| 0| ) 142| 0| } 143| | 144| | @objc public init(CGImage: CGImage, tiled: Bool) 145| 0| { 146| 0| _type = tiled ? .tiledImage : .image 147| 0| _image = CGImage 148| 0| } 149| | 150| | @objc public convenience init(image: NSUIImage, tiled: Bool) 151| 0| { 152| 0| self.init(CGImage: image.cgImage!, tiled: tiled) 153| 0| } 154| | 155| | @objc public convenience init(CGImage: CGImage) 156| 0| { 157| 0| self.init(CGImage: CGImage, tiled: false) 158| 0| } 159| | 160| | @objc public convenience init(image: NSUIImage) 161| 0| { 162| 0| self.init(image: image, tiled: false) 163| 0| } 164| | 165| | @objc public init(CGLayer: CGLayer) 166| 0| { 167| 0| _type = .layer 168| 0| _layer = CGLayer 169| 0| } 170| | 171| | // MARK: Constructors 172| | 173| | @objc open class func fillWithCGColor(_ CGColor: CGColor) -> Fill 174| 0| { 175| 0| return Fill(CGColor: CGColor) 176| 0| } 177| | 178| | @objc open class func fillWithColor(_ color: NSUIColor) -> Fill 179| 0| { 180| 0| return Fill(color: color) 181| 0| } 182| | 183| | @objc open class func fillWithLinearGradient( 184| | _ linearGradient: CGGradient, 185| | angle: CGFloat) -> Fill 186| 0| { 187| 0| return Fill(linearGradient: linearGradient, angle: angle) 188| 0| } 189| | 190| | @objc open class func fillWithRadialGradient( 191| | _ radialGradient: CGGradient, 192| | startOffsetPercent: CGPoint, 193| | startRadiusPercent: CGFloat, 194| | endOffsetPercent: CGPoint, 195| | endRadiusPercent: CGFloat 196| | ) -> Fill 197| 0| { 198| 0| return Fill( 199| 0| radialGradient: radialGradient, 200| 0| startOffsetPercent: startOffsetPercent, 201| 0| startRadiusPercent: startRadiusPercent, 202| 0| endOffsetPercent: endOffsetPercent, 203| 0| endRadiusPercent: endRadiusPercent 204| 0| ) 205| 0| } 206| | 207| | @objc open class func fillWithRadialGradient(_ radialGradient: CGGradient) -> Fill 208| 0| { 209| 0| return Fill(radialGradient: radialGradient) 210| 0| } 211| | 212| | @objc open class func fillWithCGImage(_ CGImage: CGImage, tiled: Bool) -> Fill 213| 0| { 214| 0| return Fill(CGImage: CGImage, tiled: tiled) 215| 0| } 216| | 217| | @objc open class func fillWithImage(_ image: NSUIImage, tiled: Bool) -> Fill 218| 0| { 219| 0| return Fill(image: image, tiled: tiled) 220| 0| } 221| | 222| | @objc open class func fillWithCGImage(_ CGImage: CGImage) -> Fill 223| 0| { 224| 0| return Fill(CGImage: CGImage) 225| 0| } 226| | 227| | @objc open class func fillWithImage(_ image: NSUIImage) -> Fill 228| 0| { 229| 0| return Fill(image: image) 230| 0| } 231| | 232| | @objc open class func fillWithCGLayer(_ CGLayer: CGLayer) -> Fill 233| 0| { 234| 0| return Fill(CGLayer: CGLayer) 235| 0| } 236| | 237| | // MARK: Drawing code 238| | 239| | /// Draws the provided path in filled mode with the provided area 240| | @objc open func fillPath( 241| | context: CGContext, 242| | rect: CGRect) 243| 0| { 244| 0| let fillType = _type 245| 0| if fillType == .empty 246| 0| { 247| 0| return 248| 0| } 249| 0| 250| 0| context.saveGState() 251| 0| 252| 0| switch fillType 253| 0| { 254| 0| case .color: 255| 0| 256| 0| context.setFillColor(_color!) 257| 0| context.fillPath() 258| 0| 259| 0| case .image: 260| 0| 261| 0| context.clip() 262| 0| context.draw(_image!, in: rect) 263| 0| 264| 0| case .tiledImage: 265| 0| 266| 0| context.clip() 267| 0| context.draw(_image!, in: rect, byTiling: true) 268| 0| 269| 0| case .layer: 270| 0| 271| 0| context.clip() 272| 0| context.draw(_layer!, in: rect) 273| 0| 274| 0| case .linearGradient: 275| 0| 276| 0| let radians = (360.0 - _gradientAngle).DEG2RAD 277| 0| let centerPoint = CGPoint(x: rect.midX, y: rect.midY) 278| 0| let xAngleDelta = cos(radians) * rect.width / 2.0 279| 0| let yAngleDelta = sin(radians) * rect.height / 2.0 280| 0| let startPoint = CGPoint( 281| 0| x: centerPoint.x - xAngleDelta, 282| 0| y: centerPoint.y - yAngleDelta 283| 0| ) 284| 0| let endPoint = CGPoint( 285| 0| x: centerPoint.x + xAngleDelta, 286| 0| y: centerPoint.y + yAngleDelta 287| 0| ) 288| 0| 289| 0| context.clip() 290| 0| context.drawLinearGradient(_gradient!, 291| 0| start: startPoint, 292| 0| end: endPoint, 293| 0| options: [.drawsAfterEndLocation, .drawsBeforeStartLocation] 294| 0| ) 295| 0| 296| 0| case .radialGradient: 297| 0| 298| 0| let centerPoint = CGPoint(x: rect.midX, y: rect.midY) 299| 0| let radius = max(rect.width, rect.height) / 2.0 300| 0| 301| 0| context.clip() 302| 0| context.drawRadialGradient(_gradient!, 303| 0| startCenter: CGPoint( 304| 0| x: centerPoint.x + rect.width * _gradientStartOffsetPercent.x, 305| 0| y: centerPoint.y + rect.height * _gradientStartOffsetPercent.y 306| 0| ), 307| 0| startRadius: radius * _gradientStartRadiusPercent, 308| 0| endCenter: CGPoint( 309| 0| x: centerPoint.x + rect.width * _gradientEndOffsetPercent.x, 310| 0| y: centerPoint.y + rect.height * _gradientEndOffsetPercent.y 311| 0| ), 312| 0| endRadius: radius * _gradientEndRadiusPercent, 313| 0| options: [.drawsAfterEndLocation, .drawsBeforeStartLocation] 314| 0| ) 315| 0| 316| 0| case .empty: 317| 0| break 318| 0| } 319| 0| 320| 0| context.restoreGState() 321| 0| } 322| | 323| |} /Users/travis/build/danielgindi/Charts/Source/Charts/Utils/Platform+Accessibility.swift: 1| |// 2| |// Platform+Accessibility.swift 3| |// Charts 4| |// 5| |// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda 6| |// A port of MPAndroidChart for iOS 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| | 12| |import Foundation 13| | 14| |#if os(iOS) || os(tvOS) 15| |#if canImport(UIKit) 16| | import UIKit 17| |#endif 18| | 19| |internal func accessibilityPostLayoutChangedNotification(withElement element: Any? = nil) 20| 55|{ 21| 55| UIAccessibility.post(notification: UIAccessibility.Notification.layoutChanged, argument: element) 22| 55|} 23| | 24| |internal func accessibilityPostScreenChangedNotification(withElement element: Any? = nil) 25| 0|{ 26| 0| UIAccessibility.post(notification: UIAccessibility.Notification.screenChanged, argument: element) 27| 0|} 28| | 29| |/// A simple abstraction over UIAccessibilityElement and NSAccessibilityElement. 30| |open class NSUIAccessibilityElement: UIAccessibilityElement 31| |{ 32| | private weak var containerView: UIView? 33| | 34| | final var isHeader: Bool = false 35| | { 36| | didSet 37| 52| { 38| 52| accessibilityTraits = isHeader ? UIAccessibilityTraits.header : UIAccessibilityTraits.none 39| 52| } 40| | } 41| | 42| | final var isSelected: Bool = false 43| | { 44| | didSet 45| 1| { 46| 1| accessibilityTraits = isSelected ? UIAccessibilityTraits.selected : UIAccessibilityTraits.none 47| 1| } 48| | } 49| | 50| | override public init(accessibilityContainer container: Any) 51| 1.32k| { 52| 1.32k| // We can force unwrap since all chart views are subclasses of UIView 53| 1.32k| containerView = (container as! UIView) 54| 1.32k| super.init(accessibilityContainer: container) 55| 1.32k| } 56| | 57| | override open var accessibilityFrame: CGRect 58| | { 59| | get 60| 0| { 61| 0| return super.accessibilityFrame 62| 0| } 63| | 64| | set 65| 1.32k| { 66| 1.32k| guard let containerView = containerView else { return } 67| 1.32k| super.accessibilityFrame = containerView.convert(newValue, to: UIScreen.main.coordinateSpace) 68| 1.32k| } 69| | } 70| |} 71| | 72| |extension NSUIView 73| |{ 74| | /// An array of accessibilityElements that is used to implement UIAccessibilityContainer internally. 75| | /// Subclasses **MUST** override this with an array of such elements. 76| | @objc open func accessibilityChildren() -> [Any]? 77| 0| { 78| 0| return nil 79| 0| } 80| | 81| | public final override var isAccessibilityElement: Bool 82| | { 83| 0| get { return false } // Return false here, so we can make individual elements accessible 84| 0| set { } 85| | } 86| | 87| | open override func accessibilityElementCount() -> Int 88| 0| { 89| 0| return accessibilityChildren()?.count ?? 0 90| 0| } 91| | 92| | open override func accessibilityElement(at index: Int) -> Any? 93| 0| { 94| 0| return accessibilityChildren()?[index] 95| 0| } 96| | 97| | open override func index(ofAccessibilityElement element: Any) -> Int 98| 0| { 99| 0| guard let axElement = element as? NSUIAccessibilityElement else { return NSNotFound } 100| 0| return (accessibilityChildren() as? [NSUIAccessibilityElement])? 101| 0| .firstIndex(of: axElement) ?? NSNotFound 102| 0| } 103| |} 104| | 105| |#endif 106| | 107| |#if os(OSX) 108| | 109| |#if canImport(AppKit) 110| |import AppKit 111| |#endif 112| | 113| |internal func accessibilityPostLayoutChangedNotification(withElement element: Any? = nil) 114| |{ 115| | guard let validElement = element else { return } 116| | NSAccessibility.post(element: validElement, notification: .layoutChanged) 117| |} 118| | 119| |internal func accessibilityPostScreenChangedNotification(withElement element: Any? = nil) 120| |{ 121| | // Placeholder 122| |} 123| | 124| |/// A simple abstraction over UIAccessibilityElement and NSAccessibilityElement. 125| |open class NSUIAccessibilityElement: NSAccessibilityElement 126| |{ 127| | private weak var containerView: NSView? 128| | 129| | final var isHeader: Bool = false 130| | { 131| | didSet 132| | { 133| | setAccessibilityRole(isHeader ? .staticText : .none) 134| | } 135| | } 136| | 137| | final var isSelected: Bool = false 138| | { 139| | didSet 140| | { 141| | setAccessibilitySelected(isSelected) 142| | } 143| | } 144| | 145| | open var accessibilityLabel: String 146| | { 147| | get 148| | { 149| | return accessibilityLabel() ?? "" 150| | } 151| | 152| | set 153| | { 154| | setAccessibilityLabel(newValue) 155| | } 156| | } 157| | 158| | open var accessibilityFrame: NSRect 159| | { 160| | get 161| | { 162| | return accessibilityFrame() 163| | } 164| | 165| | set 166| | { 167| | guard let containerView = containerView else { return } 168| | 169| | let bounds = NSAccessibility.screenRect(fromView: containerView, rect: newValue) 170| | 171| | // This works, but won't auto update if the window is resized or moved. 172| | // setAccessibilityFrame(bounds) 173| | 174| | // using FrameInParentSpace allows for automatic updating of frame when windows are moved and resized. 175| | // However, there seems to be a bug right now where using it causes an offset in the frame. 176| | // This is a slightly hacky workaround that calculates the offset and removes it from frame calculation. 177| | setAccessibilityFrameInParentSpace(bounds) 178| | let axFrame = accessibilityFrame() 179| | let widthOffset = abs(axFrame.origin.x - bounds.origin.x) 180| | let heightOffset = abs(axFrame.origin.y - bounds.origin.y) 181| | let rect = NSRect(x: bounds.origin.x - widthOffset, 182| | y: bounds.origin.y - heightOffset, 183| | width: bounds.width, 184| | height: bounds.height) 185| | setAccessibilityFrameInParentSpace(rect) 186| | } 187| | } 188| | 189| | public init(accessibilityContainer container: Any) 190| | { 191| | // We can force unwrap since all chart views are subclasses of NSView 192| | containerView = (container as! NSView) 193| | 194| | super.init() 195| | 196| | setAccessibilityParent(containerView) 197| | setAccessibilityRole(.row) 198| | } 199| |} 200| | 201| |/// - Note: setAccessibilityRole(.list) is called at init. See Platform.swift. 202| |extension NSUIView: NSAccessibilityGroup 203| |{ 204| | open override func accessibilityLabel() -> String? 205| | { 206| | return "Chart View" 207| | } 208| | 209| | open override func accessibilityRows() -> [Any]? 210| | { 211| | return accessibilityChildren() 212| | } 213| |} 214| | 215| |#endif /Users/travis/build/danielgindi/Charts/Source/Charts/Utils/Platform+Color.swift: 1| |// 2| |// Platform+Color.swift 3| |// Charts 4| |// 5| |// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda 6| |// A port of MPAndroidChart for iOS 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| | 12| |#if canImport(UIKit) 13| |import UIKit 14| | 15| |public typealias NSUIColor = UIColor 16| |private func fetchLabelColor() -> UIColor 17| 1|{ 18| 1| if #available(iOS 13, tvOS 13, *) 19| 1| { 20| 1| return .label 21| 1| } 22| 0| else 23| 0| { 24| 0| return .black 25| 0| } 26| 0|} 27| |private let labelColor: UIColor = fetchLabelColor() 28| | 29| |extension UIColor 30| |{ 31| 370| static var labelOrBlack: UIColor { labelColor } 32| |} 33| |#endif 34| | 35| |#if canImport(AppKit) && !targetEnvironment(macCatalyst) 36| | 37| |import AppKit 38| | 39| |public typealias NSUIColor = NSColor 40| |private func fetchLabelColor() -> NSColor 41| |{ 42| | if #available(macOS 10.14, *) 43| | { 44| | return .labelColor 45| | } 46| | else 47| | { 48| | return .black 49| | } 50| |} 51| |private let labelColor: NSColor = fetchLabelColor() 52| | 53| |extension NSColor 54| |{ 55| | static var labelOrBlack: NSColor { labelColor } 56| |} 57| |#endif /Users/travis/build/danielgindi/Charts/Source/Charts/Utils/Platform+Gestures.swift: 1| |// 2| |// Platform+Gestures.swift 3| |// Charts 4| |// 5| |// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda 6| |// A port of MPAndroidChart for iOS 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| | 12| |// MARK: - UIKit 13| |#if canImport(UIKit) 14| |import UIKit 15| | 16| |public typealias NSUIGestureRecognizer = UIGestureRecognizer 17| |public typealias NSUIGestureRecognizerState = UIGestureRecognizer.State 18| |public typealias NSUIGestureRecognizerDelegate = UIGestureRecognizerDelegate 19| |public typealias NSUITapGestureRecognizer = UITapGestureRecognizer 20| |public typealias NSUIPanGestureRecognizer = UIPanGestureRecognizer 21| | 22| |extension NSUITapGestureRecognizer 23| |{ 24| | @objc final func nsuiNumberOfTouches() -> Int 25| 0| { 26| 0| return numberOfTouches 27| 0| } 28| | 29| | @objc final var nsuiNumberOfTapsRequired: Int 30| | { 31| | get 32| 0| { 33| 0| return self.numberOfTapsRequired 34| 0| } 35| | set 36| 46| { 37| 46| self.numberOfTapsRequired = newValue 38| 46| } 39| | } 40| |} 41| | 42| |extension NSUIPanGestureRecognizer 43| |{ 44| | @objc final func nsuiNumberOfTouches() -> Int 45| 0| { 46| 0| return numberOfTouches 47| 0| } 48| | 49| | @objc final func nsuiLocationOfTouch(_ touch: Int, inView: UIView?) -> CGPoint 50| 0| { 51| 0| return super.location(ofTouch: touch, in: inView) 52| 0| } 53| |} 54| | 55| |#if !os(tvOS) 56| |public typealias NSUIPinchGestureRecognizer = UIPinchGestureRecognizer 57| |public typealias NSUIRotationGestureRecognizer = UIRotationGestureRecognizer 58| | 59| |extension NSUIRotationGestureRecognizer 60| |{ 61| | @objc final var nsuiRotation: CGFloat 62| | { 63| | get { return rotation } 64| | set { rotation = newValue } 65| | } 66| |} 67| | 68| |extension NSUIPinchGestureRecognizer 69| |{ 70| | @objc final var nsuiScale: CGFloat 71| | { 72| | get 73| | { 74| | return scale 75| | } 76| | set 77| | { 78| | scale = newValue 79| | } 80| | } 81| | 82| | @objc final func nsuiLocationOfTouch(_ touch: Int, inView: UIView?) -> CGPoint 83| | { 84| | return super.location(ofTouch: touch, in: inView) 85| | } 86| |} 87| |#endif 88| |#endif 89| | 90| |// MARK: - AppKit 91| |#if canImport(AppKit) && !targetEnvironment(macCatalyst) 92| |import AppKit 93| | 94| |public typealias NSUIGestureRecognizer = NSGestureRecognizer 95| |public typealias NSUIGestureRecognizerState = NSGestureRecognizer.State 96| |public typealias NSUIGestureRecognizerDelegate = NSGestureRecognizerDelegate 97| |public typealias NSUITapGestureRecognizer = NSClickGestureRecognizer 98| |public typealias NSUIPanGestureRecognizer = NSPanGestureRecognizer 99| |public typealias NSUIPinchGestureRecognizer = NSMagnificationGestureRecognizer 100| |public typealias NSUIRotationGestureRecognizer = NSRotationGestureRecognizer 101| | 102| |/** The 'tap' gesture is mapped to clicks. */ 103| |extension NSUITapGestureRecognizer 104| |{ 105| | final func nsuiNumberOfTouches() -> Int 106| | { 107| | return 1 108| | } 109| | 110| | final var nsuiNumberOfTapsRequired: Int 111| | { 112| | get 113| | { 114| | return self.numberOfClicksRequired 115| | } 116| | set 117| | { 118| | self.numberOfClicksRequired = newValue 119| | } 120| | } 121| |} 122| | 123| |extension NSUIPanGestureRecognizer 124| |{ 125| | final func nsuiNumberOfTouches() -> Int 126| | { 127| | return 1 128| | } 129| | 130| | /// FIXME: Currently there are no more than 1 touch in OSX gestures, and not way to create custom touch gestures. 131| | final func nsuiLocationOfTouch(_ touch: Int, inView: NSView?) -> NSPoint 132| | { 133| | return super.location(in: inView) 134| | } 135| |} 136| | 137| |extension NSUIRotationGestureRecognizer 138| |{ 139| | /// FIXME: Currently there are no velocities in OSX gestures, and not way to create custom touch gestures. 140| | final var velocity: CGFloat 141| | { 142| | return 0.1 143| | } 144| | 145| | final var nsuiRotation: CGFloat 146| | { 147| | get { return -rotation } 148| | set { rotation = -newValue } 149| | } 150| |} 151| | 152| |extension NSUIPinchGestureRecognizer 153| |{ 154| | final var nsuiScale: CGFloat 155| | { 156| | get 157| | { 158| | return magnification + 1.0 159| | } 160| | set 161| | { 162| | magnification = newValue - 1.0 163| | } 164| | } 165| | 166| | /// FIXME: Currently there are no more than 1 touch in OSX gestures, and not way to create custom touch gestures. 167| | final func nsuiLocationOfTouch(_ touch: Int, inView view: NSView?) -> NSPoint 168| | { 169| | return super.location(in: view) 170| | } 171| |} 172| |#endif /Users/travis/build/danielgindi/Charts/Source/Charts/Utils/Platform+Graphics.swift: 1| |// 2| |// Platform+Graphics.swift 3| |// Charts 4| |// 5| |// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda 6| |// A port of MPAndroidChart for iOS 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| | 12| |enum Orientation 13| |{ 14| | case portrait, landscape 15| |} 16| | 17| |extension CGSize 18| |{ 19| 0| var orientation: Orientation { return width > height ? .landscape : .portrait } 20| |} 21| | 22| |extension CGRect 23| |{ 24| 0| var orientation: Orientation { size.orientation } 25| |} 26| | 27| |// MARK: - UIKit 28| |#if canImport(UIKit) 29| |import UIKit 30| | 31| |func NSUIGraphicsGetCurrentContext() -> CGContext? 32| 104|{ 33| 104| return UIGraphicsGetCurrentContext() 34| 104|} 35| | 36| |func NSUIGraphicsGetImageFromCurrentImageContext() -> NSUIImage! 37| 0|{ 38| 0| return UIGraphicsGetImageFromCurrentImageContext() 39| 0|} 40| | 41| |func NSUIGraphicsPushContext(_ context: CGContext) 42| 2.20k|{ 43| 2.20k| UIGraphicsPushContext(context) 44| 2.20k|} 45| | 46| |func NSUIGraphicsPopContext() 47| 2.20k|{ 48| 2.20k| UIGraphicsPopContext() 49| 2.20k|} 50| | 51| |func NSUIGraphicsEndImageContext() 52| 0|{ 53| 0| UIGraphicsEndImageContext() 54| 0|} 55| | 56| |func NSUIImagePNGRepresentation(_ image: NSUIImage) -> Data? 57| 0|{ 58| 0| return image.pngData() 59| 0|} 60| | 61| |func NSUIImageJPEGRepresentation(_ image: NSUIImage, _ quality: CGFloat = 0.8) -> Data? 62| 0|{ 63| 0| return image.jpegData(compressionQuality: quality) 64| 0|} 65| | 66| |func NSUIGraphicsBeginImageContextWithOptions(_ size: CGSize, _ opaque: Bool, _ scale: CGFloat) 67| 0|{ 68| 0| UIGraphicsBeginImageContextWithOptions(size, opaque, scale) 69| 0|} 70| |#endif 71| | 72| |// MARK: - AppKit 73| |#if canImport(AppKit) && !targetEnvironment(macCatalyst) 74| |import AppKit 75| | 76| |func NSUIGraphicsGetCurrentContext() -> CGContext? 77| |{ 78| | return NSGraphicsContext.current?.cgContext 79| |} 80| | 81| |func NSUIGraphicsPushContext(_ context: CGContext) 82| |{ 83| | let cx = NSGraphicsContext(cgContext: context, flipped: true) 84| | NSGraphicsContext.saveGraphicsState() 85| | NSGraphicsContext.current = cx 86| |} 87| | 88| |func NSUIGraphicsPopContext() 89| |{ 90| | NSGraphicsContext.restoreGraphicsState() 91| |} 92| | 93| |func NSUIImagePNGRepresentation(_ image: NSUIImage) -> Data? 94| |{ 95| | image.lockFocus() 96| | let rep = NSBitmapImageRep(focusedViewRect: NSMakeRect(0, 0, image.size.width, image.size.height)) 97| | image.unlockFocus() 98| | return rep?.representation(using: .png, properties: [:]) 99| |} 100| | 101| |func NSUIImageJPEGRepresentation(_ image: NSUIImage, _ quality: CGFloat = 0.9) -> Data? 102| |{ 103| | image.lockFocus() 104| | let rep = NSBitmapImageRep(focusedViewRect: NSMakeRect(0, 0, image.size.width, image.size.height)) 105| | image.unlockFocus() 106| | return rep?.representation(using: .jpeg, properties: [NSBitmapImageRep.PropertyKey.compressionFactor: quality]) 107| |} 108| | 109| |private var imageContextStack: [CGFloat] = [] 110| | 111| |func NSUIGraphicsBeginImageContextWithOptions(_ size: CGSize, _ opaque: Bool, _ scale: CGFloat) 112| |{ 113| | var scale = scale 114| | if scale == 0.0 115| | { 116| | scale = NSScreen.main?.backingScaleFactor ?? 1.0 117| | } 118| | 119| | let width = Int(size.width * scale) 120| | let height = Int(size.height * scale) 121| | 122| | if width > 0 && height > 0 123| | { 124| | imageContextStack.append(scale) 125| | 126| | let colorSpace = CGColorSpaceCreateDeviceRGB() 127| | 128| | guard let ctx = CGContext(data: nil, width: width, height: height, bitsPerComponent: 8, bytesPerRow: 4*width, space: colorSpace, bitmapInfo: (opaque ? CGImageAlphaInfo.noneSkipFirst.rawValue : CGImageAlphaInfo.premultipliedFirst.rawValue)) 129| | else { return } 130| | 131| | ctx.concatenate(CGAffineTransform(a: 1, b: 0, c: 0, d: -1, tx: 0, ty: CGFloat(height))) 132| | ctx.scaleBy(x: scale, y: scale) 133| | NSUIGraphicsPushContext(ctx) 134| | } 135| |} 136| | 137| |func NSUIGraphicsGetImageFromCurrentImageContext() -> NSUIImage? 138| |{ 139| | if !imageContextStack.isEmpty 140| | { 141| | guard let ctx = NSUIGraphicsGetCurrentContext() 142| | else { return nil } 143| | 144| | let scale = imageContextStack.last! 145| | if let theCGImage = ctx.makeImage() 146| | { 147| | let size = CGSize(width: CGFloat(ctx.width) / scale, height: CGFloat(ctx.height) / scale) 148| | let image = NSImage(cgImage: theCGImage, size: size) 149| | return image 150| | } 151| | } 152| | return nil 153| |} 154| | 155| |func NSUIGraphicsEndImageContext() 156| |{ 157| | if imageContextStack.last != nil 158| | { 159| | imageContextStack.removeLast() 160| | NSUIGraphicsPopContext() 161| | } 162| |} 163| |#endif /Users/travis/build/danielgindi/Charts/Source/Charts/Utils/Platform+Touch Handling.swift: 1| |// 2| |// Platform+Touch Handling.swift 3| |// Charts 4| |// 5| |// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda 6| |// A port of MPAndroidChart for iOS 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| | 12| |#if canImport(UIKit) 13| |import UIKit 14| | 15| |public typealias NSUIEvent = UIEvent 16| |public typealias NSUITouch = UITouch 17| | 18| |@objc 19| |extension NSUIView { 20| | public final override func touchesBegan(_ touches: Set, with event: NSUIEvent?) 21| 0| { 22| 0| self.nsuiTouchesBegan(touches, withEvent: event) 23| 0| } 24| | 25| | public final override func touchesMoved(_ touches: Set, with event: NSUIEvent?) 26| 0| { 27| 0| self.nsuiTouchesMoved(touches, withEvent: event) 28| 0| } 29| | 30| | public final override func touchesEnded(_ touches: Set, with event: NSUIEvent?) 31| 0| { 32| 0| self.nsuiTouchesEnded(touches, withEvent: event) 33| 0| } 34| | 35| | public final override func touchesCancelled(_ touches: Set, with event: NSUIEvent?) 36| 0| { 37| 0| self.nsuiTouchesCancelled(touches, withEvent: event) 38| 0| } 39| | 40| | open func nsuiTouchesBegan(_ touches: Set, withEvent event: NSUIEvent?) 41| 0| { 42| 0| super.touchesBegan(touches, with: event!) 43| 0| } 44| | 45| | open func nsuiTouchesMoved(_ touches: Set, withEvent event: NSUIEvent?) 46| 0| { 47| 0| super.touchesMoved(touches, with: event!) 48| 0| } 49| | 50| | open func nsuiTouchesEnded(_ touches: Set, withEvent event: NSUIEvent?) 51| 0| { 52| 0| super.touchesEnded(touches, with: event!) 53| 0| } 54| | 55| | open func nsuiTouchesCancelled(_ touches: Set?, withEvent event: NSUIEvent?) 56| 0| { 57| 0| super.touchesCancelled(touches!, with: event!) 58| 0| } 59| |} 60| | 61| |extension UIView 62| |{ 63| | @objc final var nsuiGestureRecognizers: [NSUIGestureRecognizer]? 64| 0| { 65| 0| return self.gestureRecognizers 66| 0| } 67| |} 68| |#endif 69| | 70| | 71| |#if canImport(AppKit) && !targetEnvironment(macCatalyst) 72| |import AppKit 73| | 74| |public typealias NSUIEvent = NSEvent 75| |public typealias NSUITouch = NSTouch 76| | 77| |@objc 78| |extension NSUIView 79| |{ 80| | public final override func touchesBegan(with event: NSEvent) 81| | { 82| | self.nsuiTouchesBegan(event.touches(matching: .any, in: self), withEvent: event) 83| | } 84| | 85| | public final override func touchesEnded(with event: NSEvent) 86| | { 87| | self.nsuiTouchesEnded(event.touches(matching: .any, in: self), withEvent: event) 88| | } 89| | 90| | public final override func touchesMoved(with event: NSEvent) 91| | { 92| | self.nsuiTouchesMoved(event.touches(matching: .any, in: self), withEvent: event) 93| | } 94| | 95| | open override func touchesCancelled(with event: NSEvent) 96| | { 97| | self.nsuiTouchesCancelled(event.touches(matching: .any, in: self), withEvent: event) 98| | } 99| | 100| | open func nsuiTouchesBegan(_ touches: Set, withEvent event: NSUIEvent?) 101| | { 102| | super.touchesBegan(with: event!) 103| | } 104| | 105| | open func nsuiTouchesMoved(_ touches: Set, withEvent event: NSUIEvent?) 106| | { 107| | super.touchesMoved(with: event!) 108| | } 109| | 110| | open func nsuiTouchesEnded(_ touches: Set, withEvent event: NSUIEvent?) 111| | { 112| | super.touchesEnded(with: event!) 113| | } 114| | 115| | open func nsuiTouchesCancelled(_ touches: Set?, withEvent event: NSUIEvent?) 116| | { 117| | super.touchesCancelled(with: event!) 118| | } 119| |} 120| | 121| |extension NSTouch 122| |{ 123| | /** Touch locations on OS X are relative to the trackpad, whereas on iOS they are actually *on* the view. */ 124| | func locationInView(view: NSView) -> NSPoint 125| | { 126| | let n = self.normalizedPosition 127| | let b = view.bounds 128| | return NSPoint( 129| | x: b.origin.x + b.size.width * n.x, 130| | y: b.origin.y + b.size.height * n.y 131| | ) 132| | } 133| |} 134| |#endif /Users/travis/build/danielgindi/Charts/Source/Charts/Utils/Platform.swift: 1| |import Foundation 2| | 3| |/** This file provides a thin abstraction layer atop of UIKit (iOS, tvOS) and Cocoa (OS X). The two APIs are very much 4| | alike, and for the chart library's usage of the APIs it is often sufficient to typealias one to the other. The NSUI* 5| | types are aliased to either their UI* implementation (on iOS) or their NS* implementation (on OS X). */ 6| |#if os(iOS) || os(tvOS) 7| |#if canImport(UIKit) 8| | import UIKit 9| |#endif 10| | 11| |public typealias NSUIFont = UIFont 12| |public typealias NSUIImage = UIImage 13| |public typealias NSUIScrollView = UIScrollView 14| |public typealias NSUIScreen = UIScreen 15| |public typealias NSUIDisplayLink = CADisplayLink 16| | 17| |open class NSUIView: UIView 18| |{ 19| | @objc var nsuiLayer: CALayer? 20| 0| { 21| 0| return self.layer 22| 0| } 23| |} 24| | 25| |extension UIScrollView 26| |{ 27| | @objc var nsuiIsScrollEnabled: Bool 28| | { 29| 0| get { return isScrollEnabled } 30| 0| set { isScrollEnabled = newValue } 31| | } 32| |} 33| | 34| |extension UIScreen 35| |{ 36| | @objc final var nsuiScale: CGFloat 37| 0| { 38| 0| return self.scale 39| 0| } 40| |} 41| | 42| |#endif 43| | 44| |#if os(OSX) 45| |import Cocoa 46| |import Quartz 47| | 48| |public typealias NSUIFont = NSFont 49| |public typealias NSUIImage = NSImage 50| |public typealias NSUIScrollView = NSScrollView 51| |public typealias NSUIScreen = NSScreen 52| | 53| |/** On OS X there is no CADisplayLink. Use a 60 fps timer to render the animations. */ 54| |public class NSUIDisplayLink 55| |{ 56| | private var timer: Timer? 57| | private var displayLink: CVDisplayLink? 58| | private var _timestamp: CFTimeInterval = 0.0 59| | 60| | private weak var _target: AnyObject? 61| | private var _selector: Selector 62| | 63| | public var timestamp: CFTimeInterval 64| | { 65| | return _timestamp 66| | } 67| | 68| | init(target: Any, selector: Selector) 69| | { 70| | _target = target as AnyObject 71| | _selector = selector 72| | 73| | if CVDisplayLinkCreateWithActiveCGDisplays(&displayLink) == kCVReturnSuccess 74| | { 75| | 76| | CVDisplayLinkSetOutputCallback(displayLink!, { (displayLink, inNow, inOutputTime, flagsIn, flagsOut, userData) -> CVReturn in 77| | 78| | let _self = unsafeBitCast(userData, to: NSUIDisplayLink.self) 79| | 80| | _self._timestamp = CFAbsoluteTimeGetCurrent() 81| | _self._target?.performSelector(onMainThread: _self._selector, with: _self, waitUntilDone: false) 82| | 83| | return kCVReturnSuccess 84| | }, Unmanaged.passUnretained(self).toOpaque()) 85| | } 86| | else 87| | { 88| | timer = Timer(timeInterval: 1.0 / 60.0, target: target, selector: selector, userInfo: nil, repeats: true) 89| | } 90| | } 91| | 92| | deinit 93| | { 94| | stop() 95| | } 96| | 97| | open func add(to runloop: RunLoop, forMode mode: RunLoop.Mode) 98| | { 99| | if displayLink != nil 100| | { 101| | CVDisplayLinkStart(displayLink!) 102| | } 103| | else if timer != nil 104| | { 105| | runloop.add(timer!, forMode: mode) 106| | } 107| | } 108| | 109| | open func remove(from: RunLoop, forMode: RunLoop.Mode) 110| | { 111| | stop() 112| | } 113| | 114| | private func stop() 115| | { 116| | if displayLink != nil 117| | { 118| | CVDisplayLinkStop(displayLink!) 119| | } 120| | if timer != nil 121| | { 122| | timer?.invalidate() 123| | } 124| | } 125| |} 126| | 127| |extension NSView 128| |{ 129| | final var nsuiGestureRecognizers: [NSGestureRecognizer]? 130| | { 131| | return self.gestureRecognizers 132| | } 133| |} 134| | 135| |extension NSScrollView 136| |{ 137| | var nsuiIsScrollEnabled: Bool 138| | { 139| | get { return scrollEnabled } 140| | set { scrollEnabled = newValue } 141| | } 142| |} 143| | 144| |open class NSUIView: NSView 145| |{ 146| | /// A private constant to set the accessibility role during initialization. 147| | /// It ensures parity with the iOS element ordering as well as numbered counts of chart components. 148| | /// (See Platform+Accessibility for details) 149| | private let role: NSAccessibility.Role = .list 150| | 151| | public override init(frame frameRect: NSRect) 152| | { 153| | super.init(frame: frameRect) 154| | setAccessibilityRole(role) 155| | } 156| | 157| | required public init?(coder decoder: NSCoder) 158| | { 159| | super.init(coder: decoder) 160| | setAccessibilityRole(role) 161| | } 162| | 163| | public final override var isFlipped: Bool 164| | { 165| | return true 166| | } 167| | 168| | func setNeedsDisplay() 169| | { 170| | self.setNeedsDisplay(self.bounds) 171| | } 172| | 173| | 174| | open var backgroundColor: NSUIColor? 175| | { 176| | get 177| | { 178| | return self.layer?.backgroundColor == nil 179| | ? nil 180| | : NSColor(cgColor: self.layer!.backgroundColor!) 181| | } 182| | set 183| | { 184| | self.wantsLayer = true 185| | self.layer?.backgroundColor = newValue == nil ? nil : newValue!.cgColor 186| | } 187| | } 188| | 189| | final var nsuiLayer: CALayer? 190| | { 191| | return self.layer 192| | } 193| |} 194| | 195| |extension NSFont 196| |{ 197| | var lineHeight: CGFloat 198| | { 199| | // Not sure if this is right, but it looks okay 200| | return self.boundingRectForFont.size.height 201| | } 202| |} 203| | 204| |extension NSScreen 205| |{ 206| | final var nsuiScale: CGFloat 207| | { 208| | return self.backingScaleFactor 209| | } 210| |} 211| | 212| |extension NSImage 213| |{ 214| | var cgImage: CGImage? 215| | { 216| | return self.cgImage(forProposedRect: nil, context: nil, hints: nil) 217| | } 218| |} 219| | 220| |extension NSScrollView 221| |{ 222| | /// NOTE: Unable to disable scrolling in macOS 223| | var scrollEnabled: Bool 224| | { 225| | get 226| | { 227| | return true 228| | } 229| | set 230| | { 231| | } 232| | } 233| |} 234| | 235| |#endif 236| | 237| |extension NSUIScreen 238| |{ 239| 0| class var nsuiMain: NSUIScreen? { .main } 240| |} /Users/travis/build/danielgindi/Charts/Source/Charts/Utils/Transformer.swift: 1| |// 2| |// Transformer.swift 3| |// Charts 4| |// 5| |// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda 6| |// A port of MPAndroidChart for iOS 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| | 12| |import Foundation 13| |import CoreGraphics 14| | 15| |/// Transformer class that contains all matrices and is responsible for transforming values into pixels on the screen and backwards. 16| |@objc(ChartTransformer) 17| |open class Transformer: NSObject 18| |{ 19| | /// matrix to map the values to the screen pixels 20| | internal var _matrixValueToPx = CGAffineTransform.identity 21| | 22| | /// matrix for handling the different offsets of the chart 23| | internal var _matrixOffset = CGAffineTransform.identity 24| | 25| | internal var _viewPortHandler: ViewPortHandler 26| | 27| | @objc public init(viewPortHandler: ViewPortHandler) 28| 104| { 29| 104| _viewPortHandler = viewPortHandler 30| 104| } 31| | 32| | /// Prepares the matrix that transforms values to pixels. Calculates the scale factors from the charts size and offsets. 33| | @objc open func prepareMatrixValuePx(chartXMin: Double, deltaX: CGFloat, deltaY: CGFloat, chartYMin: Double) 34| 250| { 35| 250| var scaleX = (_viewPortHandler.contentWidth / deltaX) 36| 250| var scaleY = (_viewPortHandler.contentHeight / deltaY) 37| 250| 38| 250| if CGFloat.infinity == scaleX 39| 250| { 40| 0| scaleX = 0.0 41| 250| } 42| 250| if CGFloat.infinity == scaleY 43| 250| { 44| 0| scaleY = 0.0 45| 250| } 46| 250| 47| 250| // setup all matrices 48| 250| _matrixValueToPx = CGAffineTransform.identity 49| 250| _matrixValueToPx = _matrixValueToPx.scaledBy(x: scaleX, y: -scaleY) 50| 250| _matrixValueToPx = _matrixValueToPx.translatedBy(x: CGFloat(-chartXMin), y: CGFloat(-chartYMin)) 51| 250| } 52| | 53| | /// Prepares the matrix that contains all offsets. 54| | @objc open func prepareMatrixOffset(inverted: Bool) 55| 216| { 56| 216| if !inverted 57| 216| { 58| 204| _matrixOffset = CGAffineTransform(translationX: _viewPortHandler.offsetLeft, y: _viewPortHandler.chartHeight - _viewPortHandler.offsetBottom) 59| 216| } 60| 216| else 61| 216| { 62| 12| _matrixOffset = CGAffineTransform(scaleX: 1.0, y: -1.0) 63| 12| _matrixOffset = _matrixOffset.translatedBy(x: _viewPortHandler.offsetLeft, y: -_viewPortHandler.offsetTop) 64| 216| } 65| 216| } 66| | 67| | /// Transform an array of points with all matrices. 68| | // VERY IMPORTANT: Keep matrix order "value-touch-offset" when transforming. 69| | open func pointValuesToPixel(_ points: inout [CGPoint]) 70| 198| { 71| 198| let trans = valueToPixelMatrix 72| 1.15k| points = points.map { $0.applying(trans) } 73| 198| } 74| | 75| | open func pointValueToPixel(_ point: inout CGPoint) 76| 36| { 77| 36| point = point.applying(valueToPixelMatrix) 78| 36| } 79| | 80| | @objc open func pixelForValues(x: Double, y: Double) -> CGPoint 81| 0| { 82| 0| return CGPoint(x: x, y: y).applying(valueToPixelMatrix) 83| 0| } 84| | 85| | /// Transform a rectangle with all matrices. 86| | open func rectValueToPixel(_ r: inout CGRect) 87| 0| { 88| 0| r = r.applying(valueToPixelMatrix) 89| 0| } 90| | 91| | /// Transform a rectangle with all matrices with potential animation phases. 92| | open func rectValueToPixel(_ r: inout CGRect, phaseY: Double) 93| 0| { 94| 0| // multiply the height of the rect with the phase 95| 0| var bottom = r.origin.y + r.size.height 96| 0| bottom *= CGFloat(phaseY) 97| 0| let top = r.origin.y * CGFloat(phaseY) 98| 0| r.size.height = bottom - top 99| 0| r.origin.y = top 100| 0| 101| 0| r = r.applying(valueToPixelMatrix) 102| 0| } 103| | 104| | /// Transform a rectangle with all matrices. 105| | open func rectValueToPixelHorizontal(_ r: inout CGRect) 106| 0| { 107| 0| r = r.applying(valueToPixelMatrix) 108| 0| } 109| | 110| | /// Transform a rectangle with all matrices with potential animation phases. 111| | open func rectValueToPixelHorizontal(_ r: inout CGRect, phaseY: Double) 112| 0| { 113| 0| // multiply the height of the rect with the phase 114| 0| let left = r.origin.x * CGFloat(phaseY) 115| 0| let right = (r.origin.x + r.size.width) * CGFloat(phaseY) 116| 0| r.size.width = right - left 117| 0| r.origin.x = left 118| 0| 119| 0| r = r.applying(valueToPixelMatrix) 120| 0| } 121| | 122| | /// transforms multiple rects with all matrices 123| | open func rectValuesToPixel(_ rects: inout [CGRect]) 124| 40| { 125| 40| let trans = valueToPixelMatrix 126| 1.17k| rects = rects.map { $0.applying(trans) } 127| 40| } 128| | 129| | /// Transforms the given array of touch points (pixels) into values on the chart. 130| | open func pixelsToValues(_ pixels: inout [CGPoint]) 131| 0| { 132| 0| let trans = pixelToValueMatrix 133| 0| pixels = pixels.map { $0.applying(trans) } 134| 0| } 135| | 136| | /// Transforms the given touch point (pixels) into a value on the chart. 137| | open func pixelToValues(_ pixel: inout CGPoint) 138| 52| { 139| 52| pixel = pixel.applying(pixelToValueMatrix) 140| 52| } 141| | 142| | /// - Returns: The x and y values in the chart at the given touch point 143| | /// (encapsulated in a CGPoint). This method transforms pixel coordinates to 144| | /// coordinates / values in the chart. 145| | @objc open func valueForTouchPoint(_ point: CGPoint) -> CGPoint 146| 0| { 147| 0| return point.applying(pixelToValueMatrix) 148| 0| } 149| | 150| | /// - Returns: The x and y values in the chart at the given touch point 151| | /// (x/y). This method transforms pixel coordinates to 152| | /// coordinates / values in the chart. 153| | @objc open func valueForTouchPoint(x: CGFloat, y: CGFloat) -> CGPoint 154| 0| { 155| 0| return CGPoint(x: x, y: y).applying(pixelToValueMatrix) 156| 0| } 157| | 158| | @objc open var valueToPixelMatrix: CGAffineTransform 159| 437| { 160| 437| return 161| 437| _matrixValueToPx.concatenating(_viewPortHandler.touchMatrix 162| 437| ).concatenating(_matrixOffset 163| 437| ) 164| 437| } 165| | 166| | @objc open var pixelToValueMatrix: CGAffineTransform 167| 52| { 168| 52| return valueToPixelMatrix.inverted() 169| 52| } 170| |} /Users/travis/build/danielgindi/Charts/Source/Charts/Utils/TransformerHorizontalBarChart.swift: 1| |// 2| |// TransformerHorizontalBarChart.swift 3| |// Charts 4| |// 5| |// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda 6| |// A port of MPAndroidChart for iOS 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| | 12| |import Foundation 13| |import CoreGraphics 14| | 15| |@objc(ChartTransformerHorizontalBarChart) 16| |open class TransformerHorizontalBarChart: Transformer 17| |{ 18| | /// Prepares the matrix that contains all offsets. 19| | open override func prepareMatrixOffset(inverted: Bool) 20| 34| { 21| 34| if !inverted 22| 34| { 23| 34| _matrixOffset = CGAffineTransform(translationX: _viewPortHandler.offsetLeft, y: _viewPortHandler.chartHeight - _viewPortHandler.offsetBottom) 24| 34| } 25| 34| else 26| 34| { 27| 0| _matrixOffset = CGAffineTransform(scaleX: -1.0, y: 1.0) 28| 0| _matrixOffset = _matrixOffset.translatedBy(x: -(_viewPortHandler.chartWidth - _viewPortHandler.offsetRight), 29| 0| y: _viewPortHandler.chartHeight - _viewPortHandler.offsetBottom) 30| 34| } 31| 34| } 32| |} /Users/travis/build/danielgindi/Charts/Source/Charts/Utils/ViewPortHandler.swift: 1| |// 2| |// ViewPortHandler.swift 3| |// Charts 4| |// 5| |// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda 6| |// A port of MPAndroidChart for iOS 7| |// Licensed under Apache License 2.0 8| |// 9| |// https://github.com/danielgindi/Charts 10| |// 11| | 12| |import Foundation 13| |import CoreGraphics 14| | 15| |/// Class that contains information about the charts current viewport settings, including offsets, scale & translation levels, ... 16| |@objc(ChartViewPortHandler) 17| |open class ViewPortHandler: NSObject 18| |{ 19| | /// matrix used for touch events 20| | private var _touchMatrix = CGAffineTransform.identity 21| | 22| | /// this rectangle defines the area in which graph values can be drawn 23| | private var _contentRect = CGRect() 24| | 25| | private var _chartWidth = CGFloat(0.0) 26| | private var _chartHeight = CGFloat(0.0) 27| | 28| | /// minimum scale value on the y-axis 29| | private var _minScaleY = CGFloat(1.0) 30| | 31| | /// maximum scale value on the y-axis 32| | private var _maxScaleY = CGFloat.greatestFiniteMagnitude 33| | 34| | /// minimum scale value on the x-axis 35| | private var _minScaleX = CGFloat(1.0) 36| | 37| | /// maximum scale value on the x-axis 38| | private var _maxScaleX = CGFloat.greatestFiniteMagnitude 39| | 40| | /// contains the current scale factor of the x-axis 41| | private var _scaleX = CGFloat(1.0) 42| | 43| | /// contains the current scale factor of the y-axis 44| | private var _scaleY = CGFloat(1.0) 45| | 46| | /// current translation (drag distance) on the x-axis 47| | private var _transX = CGFloat(0.0) 48| | 49| | /// current translation (drag distance) on the y-axis 50| | private var _transY = CGFloat(0.0) 51| | 52| | /// offset that allows the chart to be dragged over its bounds on the x-axis 53| | private var _transOffsetX = CGFloat(0.0) 54| | 55| | /// offset that allows the chart to be dragged over its bounds on the x-axis 56| | private var _transOffsetY = CGFloat(0.0) 57| | 58| | /// Constructor - don't forget calling setChartDimens(...) 59| | @objc public init(width: CGFloat, height: CGFloat) 60| 52| { 61| 52| super.init() 62| 52| 63| 52| setChartDimens(width: width, height: height) 64| 52| } 65| | 66| | @objc open func setChartDimens(width: CGFloat, height: CGFloat) 67| 52| { 68| 52| let offsetLeft = self.offsetLeft 69| 52| let offsetTop = self.offsetTop 70| 52| let offsetRight = self.offsetRight 71| 52| let offsetBottom = self.offsetBottom 72| 52| 73| 52| _chartHeight = height 74| 52| _chartWidth = width 75| 52| 76| 52| restrainViewPort(offsetLeft: offsetLeft, offsetTop: offsetTop, offsetRight: offsetRight, offsetBottom: offsetBottom) 77| 52| } 78| | 79| | @objc open var hasChartDimens: Bool 80| 0| { 81| 0| if _chartHeight > 0.0 && _chartWidth > 0.0 82| 0| { 83| 0| return true 84| 0| } 85| 0| else 86| 0| { 87| 0| return false 88| 0| } 89| 0| } 90| | 91| | @objc open func restrainViewPort(offsetLeft: CGFloat, offsetTop: CGFloat, offsetRight: CGFloat, offsetBottom: CGFloat) 92| 189| { 93| 189| _contentRect.origin.x = offsetLeft 94| 189| _contentRect.origin.y = offsetTop 95| 189| _contentRect.size.width = _chartWidth - offsetLeft - offsetRight 96| 189| _contentRect.size.height = _chartHeight - offsetBottom - offsetTop 97| 189| } 98| | 99| | @objc open var offsetLeft: CGFloat 100| 575| { 101| 575| return _contentRect.origin.x 102| 575| } 103| | 104| | @objc open var offsetRight: CGFloat 105| 52| { 106| 52| return _chartWidth - _contentRect.size.width - _contentRect.origin.x 107| 52| } 108| | 109| | @objc open var offsetTop: CGFloat 110| 64| { 111| 64| return _contentRect.origin.y 112| 64| } 113| | 114| | @objc open var offsetBottom: CGFloat 115| 290| { 116| 290| return _chartHeight - _contentRect.size.height - _contentRect.origin.y 117| 290| } 118| | 119| | @objc open var contentTop: CGFloat 120| 522| { 121| 522| return _contentRect.origin.y 122| 522| } 123| | 124| | @objc open var contentLeft: CGFloat 125| 700| { 126| 700| return _contentRect.origin.x 127| 700| } 128| | 129| | @objc open var contentRight: CGFloat 130| 705| { 131| 705| return _contentRect.origin.x + _contentRect.size.width 132| 705| } 133| | 134| | @objc open var contentBottom: CGFloat 135| 454| { 136| 454| return _contentRect.origin.y + _contentRect.size.height 137| 454| } 138| | 139| | @objc open var contentWidth: CGFloat 140| 674| { 141| 674| return _contentRect.size.width 142| 674| } 143| | 144| | @objc open var contentHeight: CGFloat 145| 284| { 146| 284| return _contentRect.size.height 147| 284| } 148| | 149| | @objc open var contentRect: CGRect 150| 192| { 151| 192| return _contentRect 152| 192| } 153| | 154| | @objc open var contentCenter: CGPoint 155| 12| { 156| 12| return CGPoint(x: _contentRect.origin.x + _contentRect.size.width / 2.0, y: _contentRect.origin.y + _contentRect.size.height / 2.0) 157| 12| } 158| | 159| | @objc open var chartHeight: CGFloat 160| 427| { 161| 427| return _chartHeight 162| 427| } 163| | 164| | @objc open var chartWidth: CGFloat 165| 246| { 166| 246| return _chartWidth 167| 246| } 168| | 169| | // MARK: - Scaling/Panning etc. 170| | 171| | /// Zooms by the specified zoom factors. 172| | @objc open func zoom(scaleX: CGFloat, scaleY: CGFloat) -> CGAffineTransform 173| 0| { 174| 0| return _touchMatrix.scaledBy(x: scaleX, y: scaleY) 175| 0| } 176| | 177| | /// Zooms around the specified center 178| | @objc open func zoom(scaleX: CGFloat, scaleY: CGFloat, x: CGFloat, y: CGFloat) -> CGAffineTransform 179| 0| { 180| 0| var matrix = _touchMatrix.translatedBy(x: x, y: y) 181| 0| matrix = matrix.scaledBy(x: scaleX, y: scaleY) 182| 0| matrix = matrix.translatedBy(x: -x, y: -y) 183| 0| return matrix 184| 0| } 185| | 186| | /// Zooms in by 1.4, x and y are the coordinates (in pixels) of the zoom center. 187| | @objc open func zoomIn(x: CGFloat, y: CGFloat) -> CGAffineTransform 188| 0| { 189| 0| return zoom(scaleX: 1.4, scaleY: 1.4, x: x, y: y) 190| 0| } 191| | 192| | /// Zooms out by 0.7, x and y are the coordinates (in pixels) of the zoom center. 193| | @objc open func zoomOut(x: CGFloat, y: CGFloat) -> CGAffineTransform 194| 0| { 195| 0| return zoom(scaleX: 0.7, scaleY: 0.7, x: x, y: y) 196| 0| } 197| | 198| | /// Zooms out to original size. 199| | @objc open func resetZoom() -> CGAffineTransform 200| 0| { 201| 0| return zoom(scaleX: 1.0, scaleY: 1.0, x: 0.0, y: 0.0) 202| 0| } 203| | 204| | /// Sets the scale factor to the specified values. 205| | @objc open func setZoom(scaleX: CGFloat, scaleY: CGFloat) -> CGAffineTransform 206| 0| { 207| 0| var matrix = _touchMatrix 208| 0| matrix.a = scaleX 209| 0| matrix.d = scaleY 210| 0| return matrix 211| 0| } 212| | 213| | /// Sets the scale factor to the specified values. x and y is pivot. 214| | @objc open func setZoom(scaleX: CGFloat, scaleY: CGFloat, x: CGFloat, y: CGFloat) -> CGAffineTransform 215| 0| { 216| 0| var matrix = _touchMatrix 217| 0| matrix.a = 1.0 218| 0| matrix.d = 1.0 219| 0| matrix = matrix.translatedBy(x: x, y: y) 220| 0| matrix = matrix.scaledBy(x: scaleX, y: scaleY) 221| 0| matrix = matrix.translatedBy(x: -x, y: -y) 222| 0| return matrix 223| 0| } 224| | 225| | /// Resets all zooming and dragging and makes the chart fit exactly it's bounds. 226| | @objc open func fitScreen() -> CGAffineTransform 227| 0| { 228| 0| _minScaleX = 1.0 229| 0| _minScaleY = 1.0 230| 0| 231| 0| return CGAffineTransform.identity 232| 0| } 233| | 234| | /// Translates to the specified point. 235| | @objc open func translate(pt: CGPoint) -> CGAffineTransform 236| 0| { 237| 0| let translateX = pt.x - offsetLeft 238| 0| let translateY = pt.y - offsetTop 239| 0| 240| 0| let matrix = _touchMatrix.concatenating(CGAffineTransform(translationX: -translateX, y: -translateY)) 241| 0| 242| 0| return matrix 243| 0| } 244| | 245| | /// Centers the viewport around the specified position (x-index and y-value) in the chart. 246| | /// Centering the viewport outside the bounds of the chart is not possible. 247| | /// Makes most sense in combination with the setScaleMinima(...) method. 248| | @objc open func centerViewPort(pt: CGPoint, chart: ChartViewBase) 249| 0| { 250| 0| let translateX = pt.x - offsetLeft 251| 0| let translateY = pt.y - offsetTop 252| 0| 253| 0| let matrix = _touchMatrix.concatenating(CGAffineTransform(translationX: -translateX, y: -translateY)) 254| 0| refresh(newMatrix: matrix, chart: chart, invalidate: true) 255| 0| } 256| | 257| | /// call this method to refresh the graph with a given matrix 258| | @objc @discardableResult open func refresh(newMatrix: CGAffineTransform, chart: ChartViewBase, invalidate: Bool) -> CGAffineTransform 259| 0| { 260| 0| _touchMatrix = newMatrix 261| 0| 262| 0| // make sure scale and translation are within their bounds 263| 0| limitTransAndScale(matrix: &_touchMatrix, content: _contentRect) 264| 0| 265| 0| chart.setNeedsDisplay() 266| 0| 267| 0| return _touchMatrix 268| 0| } 269| | 270| | /// limits the maximum scale and X translation of the given matrix 271| | private func limitTransAndScale(matrix: inout CGAffineTransform, content: CGRect?) 272| 0| { 273| 0| // min scale-x is 1 274| 0| _scaleX = min(max(_minScaleX, matrix.a), _maxScaleX) 275| 0| 276| 0| // min scale-y is 1 277| 0| _scaleY = min(max(_minScaleY, matrix.d), _maxScaleY) 278| 0| 279| 0| 280| 0| var width: CGFloat = 0.0 281| 0| var height: CGFloat = 0.0 282| 0| 283| 0| if content != nil 284| 0| { 285| 0| width = content!.width 286| 0| height = content!.height 287| 0| } 288| 0| 289| 0| let maxTransX = -width * (_scaleX - 1.0) 290| 0| _transX = min(max(matrix.tx, maxTransX - _transOffsetX), _transOffsetX) 291| 0| 292| 0| let maxTransY = height * (_scaleY - 1.0) 293| 0| _transY = max(min(matrix.ty, maxTransY + _transOffsetY), -_transOffsetY) 294| 0| 295| 0| matrix.tx = _transX 296| 0| matrix.a = _scaleX 297| 0| matrix.ty = _transY 298| 0| matrix.d = _scaleY 299| 0| } 300| | 301| | /// Sets the minimum scale factor for the x-axis 302| | @objc open func setMinimumScaleX(_ xScale: CGFloat) 303| 0| { 304| 0| var newValue = xScale 305| 0| 306| 0| if newValue < 1.0 307| 0| { 308| 0| newValue = 1.0 309| 0| } 310| 0| 311| 0| _minScaleX = newValue 312| 0| 313| 0| limitTransAndScale(matrix: &_touchMatrix, content: _contentRect) 314| 0| } 315| | 316| | /// Sets the maximum scale factor for the x-axis 317| | @objc open func setMaximumScaleX(_ xScale: CGFloat) 318| 0| { 319| 0| var newValue = xScale 320| 0| 321| 0| if newValue == 0.0 322| 0| { 323| 0| newValue = CGFloat.greatestFiniteMagnitude 324| 0| } 325| 0| 326| 0| _maxScaleX = newValue 327| 0| 328| 0| limitTransAndScale(matrix: &_touchMatrix, content: _contentRect) 329| 0| } 330| | 331| | /// Sets the minimum and maximum scale factors for the x-axis 332| | @objc open func setMinMaxScaleX(minScaleX: CGFloat, maxScaleX: CGFloat) 333| 0| { 334| 0| var newMin = minScaleX 335| 0| var newMax = maxScaleX 336| 0| 337| 0| if newMin < 1.0 338| 0| { 339| 0| newMin = 1.0 340| 0| } 341| 0| if newMax == 0.0 342| 0| { 343| 0| newMax = CGFloat.greatestFiniteMagnitude 344| 0| } 345| 0| 346| 0| _minScaleX = newMin 347| 0| _maxScaleX = maxScaleX 348| 0| 349| 0| limitTransAndScale(matrix: &_touchMatrix, content: _contentRect) 350| 0| } 351| | 352| | /// Sets the minimum scale factor for the y-axis 353| | @objc open func setMinimumScaleY(_ yScale: CGFloat) 354| 0| { 355| 0| var newValue = yScale 356| 0| 357| 0| if newValue < 1.0 358| 0| { 359| 0| newValue = 1.0 360| 0| } 361| 0| 362| 0| _minScaleY = newValue 363| 0| 364| 0| limitTransAndScale(matrix: &_touchMatrix, content: _contentRect) 365| 0| } 366| | 367| | /// Sets the maximum scale factor for the y-axis 368| | @objc open func setMaximumScaleY(_ yScale: CGFloat) 369| 0| { 370| 0| var newValue = yScale 371| 0| 372| 0| if newValue == 0.0 373| 0| { 374| 0| newValue = CGFloat.greatestFiniteMagnitude 375| 0| } 376| 0| 377| 0| _maxScaleY = newValue 378| 0| 379| 0| limitTransAndScale(matrix: &_touchMatrix, content: _contentRect) 380| 0| } 381| | 382| | @objc open func setMinMaxScaleY(minScaleY: CGFloat, maxScaleY: CGFloat) 383| 0| { 384| 0| var minScaleY = minScaleY, maxScaleY = maxScaleY 385| 0| 386| 0| if minScaleY < 1.0 387| 0| { 388| 0| minScaleY = 1.0 389| 0| } 390| 0| 391| 0| if maxScaleY == 0.0 392| 0| { 393| 0| maxScaleY = CGFloat.greatestFiniteMagnitude 394| 0| } 395| 0| 396| 0| _minScaleY = minScaleY 397| 0| _maxScaleY = maxScaleY 398| 0| 399| 0| limitTransAndScale(matrix: &_touchMatrix, content: _contentRect) 400| 0| } 401| | 402| | @objc open var touchMatrix: CGAffineTransform 403| 437| { 404| 437| return _touchMatrix 405| 437| } 406| | 407| | // MARK: - Boundaries Check 408| | 409| | @objc open func isInBoundsX(_ x: CGFloat) -> Bool 410| 350| { 411| 350| return isInBoundsLeft(x) && isInBoundsRight(x) 412| 350| } 413| | 414| | @objc open func isInBoundsY(_ y: CGFloat) -> Bool 415| 1.53k| { 416| 1.53k| return isInBoundsTop(y) && isInBoundsBottom(y) 417| 1.53k| } 418| | 419| | /** 420| | A method to check whether coordinate lies within the viewport. 421| | 422| | - Parameters: 423| | - point: a coordinate. 424| | */ 425| | @objc open func isInBounds(point: CGPoint) -> Bool 426| 0| { 427| 0| return isInBounds(x: point.x, y: point.y) 428| 0| } 429| | 430| | @objc open func isInBounds(x: CGFloat, y: CGFloat) -> Bool 431| 0| { 432| 0| return isInBoundsX(x) && isInBoundsY(y) 433| 0| } 434| | 435| | @objc open func isInBoundsLeft(_ x: CGFloat) -> Bool 436| 2.98k| { 437| 2.98k| return _contentRect.origin.x <= x + 1.0 438| 2.98k| } 439| | 440| | @objc open func isInBoundsRight(_ x: CGFloat) -> Bool 441| 3.04k| { 442| 3.04k| let x = floor(x * 100.0) / 100.0 443| 3.04k| return (_contentRect.origin.x + _contentRect.size.width) >= x - 1.0 444| 3.04k| } 445| | 446| | @objc open func isInBoundsTop(_ y: CGFloat) -> Bool 447| 2.03k| { 448| 2.03k| return _contentRect.origin.y <= y 449| 2.03k| } 450| | 451| | @objc open func isInBoundsBottom(_ y: CGFloat) -> Bool 452| 1.97k| { 453| 1.97k| let normalizedY = floor(y * 100.0) / 100.0 454| 1.97k| return (_contentRect.origin.y + _contentRect.size.height) >= normalizedY 455| 1.97k| } 456| | 457| | /** 458| | A method to check whether a line between two coordinates intersects with the view port by using a linear function. 459| | 460| | Linear function (calculus): `y = ax + b` 461| | 462| | Note: this method will not check for collision with the right edge of the view port, as we assume lines run from left 463| | to right (e.g. `startPoint < endPoint`). 464| | 465| | - Parameters: 466| | - startPoint: the start coordinate of the line. 467| | - endPoint: the end coordinate of the line. 468| | */ 469| | @objc open func isIntersectingLine(from startPoint: CGPoint, to endPoint: CGPoint) -> Bool 470| 0| { 471| 0| // If start- and/or endpoint fall within the viewport, bail out early. 472| 0| if isInBounds(point: startPoint) || isInBounds(point: endPoint) { return true } 473| 0| // check if x in bound when it's a vertical line 474| 0| if startPoint.x == endPoint.x { return isInBoundsX(startPoint.x) } 475| 0| 476| 0| // Calculate the slope (`a`) of the line (e.g. `a = (y2 - y1) / (x2 - x1)`). 477| 0| let a = (endPoint.y - startPoint.y) / (endPoint.x - startPoint.x) 478| 0| // Calculate the y-correction (`b`) of the line (e.g. `b = y1 - (a * x1)`). 479| 0| let b = startPoint.y - (a * startPoint.x) 480| 0| 481| 0| // Check for colission with the left edge of the view port (e.g. `y = (a * minX) + b`). 482| 0| // if a is 0, it's a horizontal line; checking b here is still valid, as b is `point.y` all the time 483| 0| if isInBoundsY((a * contentRect.minX) + b) { return true } 484| 0| 485| 0| // Skip unnecessary check for collision with the right edge of the view port 486| 0| // (e.g. `y = (a * maxX) + b`), as such a line will either begin inside the view port, 487| 0| // or intersect the left, top or bottom edges of the view port. Leaving this logic here for clarity's sake: 488| 0| // if isInBoundsY((a * contentRect.maxX) + b) { return true } 489| 0| 490| 0| // While slope `a` can theoretically never be `0`, we should protect against division by zero. 491| 0| guard a != 0 else { return false } 492| 0| 493| 0| // Check for collision with the bottom edge of the view port (e.g. `x = (maxY - b) / a`). 494| 0| if isInBoundsX((contentRect.maxY - b) / a) { return true } 495| 0| 496| 0| // Check for collision with the top edge of the view port (e.g. `x = (minY - b) / a`). 497| 0| if isInBoundsX((contentRect.minY - b) / a) { return true } 498| 0| 499| 0| // This line does not intersect the view port. 500| 0| return false 501| 0| } 502| | 503| | /// The current x-scale factor 504| | @objc open var scaleX: CGFloat 505| 43| { 506| 43| return _scaleX 507| 43| } 508| | 509| | /// The current y-scale factor 510| | @objc open var scaleY: CGFloat 511| 6| { 512| 6| return _scaleY 513| 6| } 514| | 515| | /// The minimum x-scale factor 516| | @objc open var minScaleX: CGFloat 517| 0| { 518| 0| return _minScaleX 519| 0| } 520| | 521| | /// The minimum y-scale factor 522| | @objc open var minScaleY: CGFloat 523| 0| { 524| 0| return _minScaleY 525| 0| } 526| | 527| | /// The minimum x-scale factor 528| | @objc open var maxScaleX: CGFloat 529| 0| { 530| 0| return _maxScaleX 531| 0| } 532| | 533| | /// The minimum y-scale factor 534| | @objc open var maxScaleY: CGFloat 535| 0| { 536| 0| return _maxScaleY 537| 0| } 538| | 539| | /// The translation (drag / pan) distance on the x-axis 540| | @objc open var transX: CGFloat 541| 0| { 542| 0| return _transX 543| 0| } 544| | 545| | /// The translation (drag / pan) distance on the y-axis 546| | @objc open var transY: CGFloat 547| 0| { 548| 0| return _transY 549| 0| } 550| | 551| | /// if the chart is fully zoomed out, return true 552| | @objc open var isFullyZoomedOut: Bool 553| 0| { 554| 0| return isFullyZoomedOutX && isFullyZoomedOutY 555| 0| } 556| | 557| | /// `true` if the chart is fully zoomed out on it's y-axis (vertical). 558| | @objc open var isFullyZoomedOutY: Bool 559| 231| { 560| 231| return !(_scaleY > _minScaleY || _minScaleY > 1.0) 561| 231| } 562| | 563| | /// `true` if the chart is fully zoomed out on it's x-axis (horizontal). 564| | @objc open var isFullyZoomedOutX: Bool 565| 142| { 566| 142| return !(_scaleX > _minScaleX || _minScaleX > 1.0) 567| 142| } 568| | 569| | /// Set an offset in pixels that allows the user to drag the chart over it's bounds on the x-axis. 570| | @objc open func setDragOffsetX(_ offset: CGFloat) 571| 0| { 572| 0| _transOffsetX = offset 573| 0| } 574| | 575| | /// Set an offset in pixels that allows the user to drag the chart over it's bounds on the y-axis. 576| | @objc open func setDragOffsetY(_ offset: CGFloat) 577| 0| { 578| 0| _transOffsetY = offset 579| 0| } 580| | 581| | /// `true` if both drag offsets (x and y) are zero or smaller. 582| | @objc open var hasNoDragOffset: Bool 583| 0| { 584| 0| return _transOffsetX <= 0.0 && _transOffsetY <= 0.0 585| 0| } 586| | 587| | /// `true` if the chart is not yet fully zoomed out on the x-axis 588| | @objc open var canZoomOutMoreX: Bool 589| 0| { 590| 0| return _scaleX > _minScaleX 591| 0| } 592| | 593| | /// `true` if the chart is not yet fully zoomed in on the x-axis 594| | @objc open var canZoomInMoreX: Bool 595| 0| { 596| 0| return _scaleX < _maxScaleX 597| 0| } 598| | 599| | /// `true` if the chart is not yet fully zoomed out on the y-axis 600| | @objc open var canZoomOutMoreY: Bool 601| 0| { 602| 0| return _scaleY > _minScaleY 603| 0| } 604| | 605| | /// `true` if the chart is not yet fully zoomed in on the y-axis 606| | @objc open var canZoomInMoreY: Bool 607| 0| { 608| 0| return _scaleY < _maxScaleY 609| 0| } 610| |} <<<<<< EOF # path=./ChartsTests.xctest.coverage.txt /Users/travis/build/danielgindi/Charts/ChartDataTests.swift: 1| |// 2| |// ChartDataTests.swift 3| |// ChartsTests 4| |// 5| |// Created by Peter Kaminski on 1/23/20. 6| |// 7| | 8| |import XCTest 9| |@testable import Charts 10| | 11| |class ChartDataTests: XCTestCase { 12| | 13| | var data: ScatterChartData! 14| | 15| | private enum SetLabels { 16| | static let one = "label1" 17| | static let two = "label2" 18| | static let three = "label3" 19| | static let badLabel = "Bad label" 20| | } 21| | 22| 3| override func setUp() { 23| 3| super.setUp() 24| 3| 25| 3| let setCount = 5 26| 3| let range: UInt32 = 32 27| 15| let values1 = (0.. ChartDataEntry in 28| 15| let val = Double(arc4random_uniform(range) + 3) 29| 15| return ChartDataEntry(x: Double(i), y: val) 30| 15| } 31| 15| let values2 = (0.. ChartDataEntry in 32| 15| let val = Double(arc4random_uniform(range) + 3) 33| 15| return ChartDataEntry(x: Double(i), y: val) 34| 15| } 35| 15| let values3 = (0.. ChartDataEntry in 36| 15| let val = Double(arc4random_uniform(range) + 3) 37| 15| return ChartDataEntry(x: Double(i), y: val) 38| 15| } 39| 3| 40| 3| let set1 = ScatterChartDataSet(entries: values1, label: SetLabels.one) 41| 3| let set2 = ScatterChartDataSet(entries: values2, label: SetLabels.two) 42| 3| let set3 = ScatterChartDataSet(entries: values3, label: SetLabels.three) 43| 3| 44| 3| data = ScatterChartData(dataSets: [set1, set2, set3]) 45| 3| } 46| | 47| 1| func testGetDataSetByLabelCaseSensitive() { 48| 1| XCTAssertTrue(data.getDataSetByLabel(SetLabels.one, ignorecase: false)?.label == SetLabels.one) 49| 1| XCTAssertTrue(data.getDataSetByLabel(SetLabels.two, ignorecase: false)?.label == SetLabels.two) 50| 1| XCTAssertTrue(data.getDataSetByLabel(SetLabels.three, ignorecase: false)?.label == SetLabels.three) 51| 1| XCTAssertTrue(data.getDataSetByLabel(SetLabels.one.uppercased(), ignorecase: false) == nil) 52| 1| } 53| | 54| 1| func testGetDataSetByLabelIgnoreCase() { 55| 1| XCTAssertTrue(data.getDataSetByLabel(SetLabels.one, ignorecase: true)?.label == SetLabels.one) 56| 1| XCTAssertTrue(data.getDataSetByLabel(SetLabels.two, ignorecase: true)?.label == SetLabels.two) 57| 1| XCTAssertTrue(data.getDataSetByLabel(SetLabels.three, ignorecase: true)?.label == SetLabels.three) 58| 1| 59| 1| XCTAssertTrue(data.getDataSetByLabel(SetLabels.one.uppercased(), ignorecase: true)?.label == SetLabels.one) 60| 1| XCTAssertTrue(data.getDataSetByLabel(SetLabels.two.uppercased(), ignorecase: true)?.label == SetLabels.two) 61| 1| XCTAssertTrue(data.getDataSetByLabel(SetLabels.three.uppercased(), ignorecase: true)?.label == SetLabels.three) 62| 1| } 63| | 64| 1| func testGetDataSetByLabelNilWithBadLabel() { 65| 1| XCTAssertTrue(data.getDataSetByLabel(SetLabels.badLabel, ignorecase: true) == nil) 66| 1| XCTAssertTrue(data.getDataSetByLabel(SetLabels.badLabel, ignorecase: false) == nil) 67| 1| } 68| |} 69| | /Users/travis/build/danielgindi/Charts/Tests/Charts/BarChartTests.swift: 1| |import XCTest 2| |import FBSnapshotTestCase 3| |@testable import Charts 4| | 5| |class BarChartTests: FBSnapshotTestCase 6| |{ 7| | override func setUp() 8| 31| { 9| 31| super.setUp() 10| 31| 11| 31| // Set to `true` to re-capture all snapshots 12| 31| self.recordMode = false 13| 31| } 14| | 15| | override func tearDown() 16| 31| { 17| 31| // Put teardown code here. This method is called after the invocation of each test method in the class. 18| 31| super.tearDown() 19| 31| } 20| | 21| | //MARK: Prepare 22| | func setupCustomValuesDataEntries(values: [Double]) -> [ChartDataEntry] 23| 28| { 24| 28| var entries: [ChartDataEntry] = Array() 25| 28| for (i, value) in values.enumerated() 26| 840| { 27| 840| entries.append(BarChartDataEntry(x: Double(i), y: value, icon: UIImage(named: "icon", in: Bundle(for: self.classForCoder), compatibleWith: nil))) 28| 840| } 29| 28| return entries 30| 28| } 31| | 32| | func setupDefaultValuesDataEntries() -> [ChartDataEntry] 33| 11| { 34| 11| let values: [Double] = [8, 104, -81, 93, 52, -44, 97, 101, -75, 28, 35| 11| -76, 25, 20, -13, 52, 44, -57, 23, 45, -91, 36| 11| 99, 14, -84, 48, 40, -71, 106, 41, -45, 61] 37| 11| return setupCustomValuesDataEntries(values: values) 38| 11| } 39| | 40| | func setupPositiveValuesDataEntries() -> [ChartDataEntry] 41| 8| { 42| 8| let values: [Double] = [8, 104, 81, 93, 52, 44, 97, 101, 75, 28, 43| 8| 76, 25, 20, 13, 52, 44, 57, 23, 45, 91, 44| 8| 99, 14, 84, 48, 40, 71, 106, 41, 45, 61] 45| 8| return setupCustomValuesDataEntries(values: values) 46| 8| } 47| | 48| | func setupNegativeValuesDataEntries() -> [ChartDataEntry] 49| 8| { 50| 8| let values: [Double] = [-8, -104, -81, -93, -52, -44, -97, -101, -75, -28, 51| 8| -76, -25, -20, -13, -52, -44, -57, -23, -45, -91, 52| 8| -99, -14, -84, -48, -40, -71, -106, -41, -45, -61] 53| 8| return setupCustomValuesDataEntries(values: values) 54| 8| } 55| | 56| | func setupZeroValuesDataEntries() -> [ChartDataEntry] 57| 1| { 58| 1| let values = [Double](repeating: 0.0, count: 30) 59| 1| return setupCustomValuesDataEntries(values: values) 60| 1| } 61| | 62| | func setupStackedValuesDataEntries() -> [ChartDataEntry] 63| 3| { 64| 3| var entries: [ChartDataEntry] = Array() 65| 3| entries.append(BarChartDataEntry(x: 0, yValues: [28, 50, 60, 30, 42], icon: UIImage(named: "icon"))) 66| 3| entries.append(BarChartDataEntry(x: 1, yValues: [-20, -36, -52, -40, -15], icon: UIImage(named: "icon"))) 67| 3| entries.append(BarChartDataEntry(x: 2, yValues: [10, 30, 40, 90, 72], icon: UIImage(named: "icon"))) 68| 3| entries.append(BarChartDataEntry(x: 3, yValues: [-40, -50, -30, -60, -20], icon: UIImage(named: "icon"))) 69| 3| entries.append(BarChartDataEntry(x: 4, yValues: [10, 40, 60, 45, 62], icon: UIImage(named: "icon"))) 70| 3| return entries 71| 3| } 72| | 73| | func setupDefaultStackedDataSet(chartDataEntries: [ChartDataEntry]) -> BarChartDataSet 74| 3| { 75| 3| let dataSet = BarChartDataSet(entries: chartDataEntries, label: "Stacked bar chart unit test data") 76| 3| dataSet.drawIconsEnabled = false 77| 3| dataSet.iconsOffset = CGPoint(x: 0, y: -10.0) 78| 3| dataSet.colors = Array(arrayLiteral:NSUIColor(red: 46/255.0, green: 204/255.0, blue: 113/255.0, alpha: 1.0), 79| 3| NSUIColor(red: 241/255.0, green: 196/255.0, blue: 15/255.0, alpha: 1.0), 80| 3| NSUIColor(red: 231/255.0, green: 76/255.0, blue: 60/255.0, alpha: 1.0), 81| 3| NSUIColor(red: 52/255.0, green: 152/255.0, blue: 219/255.0, alpha: 1.0) 82| 3| ) 83| 3| return dataSet 84| 3| } 85| | 86| | func setupDefaultDataSet(chartDataEntries: [ChartDataEntry]) -> BarChartDataSet 87| 27| { 88| 27| let dataSet = BarChartDataSet(entries: chartDataEntries, label: "Bar chart unit test data") 89| 27| dataSet.drawIconsEnabled = false 90| 27| dataSet.iconsOffset = CGPoint(x: 0, y: -10.0) 91| 27| return dataSet 92| 27| } 93| | 94| | func setupDefaultChart(dataSets: [BarChartDataSet]) -> BarChartView 95| 31| { 96| 31| let data = BarChartData(dataSets: dataSets) 97| 31| data.barWidth = 0.85 98| 31| 99| 31| let chart = BarChartView(frame: CGRect(x: 0, y: 0, width: 480, height: 350)) 100| 31| chart.backgroundColor = NSUIColor.clear 101| 31| chart.data = data 102| 31| return chart 103| 31| } 104| | 105| | //MARK: Start Test 106| | func testDefaultValues() 107| 1| { 108| 1| let dataEntries = setupDefaultValuesDataEntries() 109| 1| let dataSet = setupDefaultDataSet(chartDataEntries: dataEntries) 110| 1| let chart = setupDefaultChart(dataSets: [dataSet]) 111| 1| ChartsSnapshotVerifyView(chart, identifier: Snapshot.identifier(UIScreen.main.bounds.size), overallTolerance: Snapshot.tolerance) 112| 1| 113| 1| } 114| | 115| | func testDefaultBarDataSetLabels() 116| 1| { 117| 1| let dataEntries = setupDefaultValuesDataEntries() 118| 1| let dataSet = BarChartDataSet(entries: dataEntries) 119| 1| dataSet.drawIconsEnabled = false 120| 1| let chart = setupDefaultChart(dataSets: [dataSet]) 121| 1| ChartsSnapshotVerifyView(chart, identifier: Snapshot.identifier(UIScreen.main.bounds.size), overallTolerance: Snapshot.tolerance) 122| 1| } 123| | 124| | func testZeroValues() 125| 1| { 126| 1| let dataEntries = setupZeroValuesDataEntries() 127| 1| let dataSet = setupDefaultDataSet(chartDataEntries: dataEntries) 128| 1| let chart = setupDefaultChart(dataSets: [dataSet]) 129| 1| ChartsSnapshotVerifyView(chart, identifier: Snapshot.identifier(UIScreen.main.bounds.size), overallTolerance: Snapshot.tolerance) 130| 1| } 131| | 132| | func testPositiveValues() 133| 1| { 134| 1| let dataEntries = setupPositiveValuesDataEntries() 135| 1| let dataSet = setupDefaultDataSet(chartDataEntries: dataEntries) 136| 1| let chart = setupDefaultChart(dataSets: [dataSet]) 137| 1| ChartsSnapshotVerifyView(chart, identifier: Snapshot.identifier(UIScreen.main.bounds.size), overallTolerance: Snapshot.tolerance) 138| 1| } 139| | 140| | func testPositiveValuesWithCustomAxisMaximum() 141| 1| { 142| 1| let dataEntries = setupPositiveValuesDataEntries() 143| 1| let dataSet = setupDefaultDataSet(chartDataEntries: dataEntries) 144| 1| let chart = setupDefaultChart(dataSets: [dataSet]) 145| 1| chart.leftAxis.axisMaximum = 50 146| 1| chart.clipValuesToContentEnabled = true 147| 1| chart.notifyDataSetChanged() 148| 1| ChartsSnapshotVerifyView(chart, identifier: Snapshot.identifier(UIScreen.main.bounds.size), overallTolerance: Snapshot.tolerance) 149| 1| } 150| | 151| | func testPositiveValuesWithCustomAxisMaximum2() 152| 1| { 153| 1| let dataEntries = setupPositiveValuesDataEntries() 154| 1| let dataSet = setupDefaultDataSet(chartDataEntries: dataEntries) 155| 1| let chart = setupDefaultChart(dataSets: [dataSet]) 156| 1| chart.leftAxis.axisMaximum = -10 157| 1| chart.notifyDataSetChanged() 158| 1| ChartsSnapshotVerifyView(chart, identifier: Snapshot.identifier(UIScreen.main.bounds.size), overallTolerance: Snapshot.tolerance) 159| 1| } 160| | 161| | func testPositiveValuesWithCustomAxisMinimum() 162| 1| { 163| 1| let dataEntries = setupPositiveValuesDataEntries() 164| 1| let dataSet = setupDefaultDataSet(chartDataEntries: dataEntries) 165| 1| let chart = setupDefaultChart(dataSets: [dataSet]) 166| 1| chart.leftAxis.axisMinimum = 50 167| 1| chart.notifyDataSetChanged() 168| 1| ChartsSnapshotVerifyView(chart, identifier: Snapshot.identifier(UIScreen.main.bounds.size), overallTolerance: Snapshot.tolerance) 169| 1| } 170| | 171| | func testPositiveValuesWithCustomAxisMinimum2() 172| 1| { 173| 1| let dataEntries = setupPositiveValuesDataEntries() 174| 1| let dataSet = setupDefaultDataSet(chartDataEntries: dataEntries) 175| 1| let chart = setupDefaultChart(dataSets: [dataSet]) 176| 1| chart.leftAxis.axisMinimum = 110 177| 1| chart.notifyDataSetChanged() 178| 1| ChartsSnapshotVerifyView(chart, identifier: Snapshot.identifier(UIScreen.main.bounds.size), overallTolerance: Snapshot.tolerance) 179| 1| } 180| | 181| | func testPositiveValuesWithCustomAxisMaximumAndCustomAxisMaximum() 182| 1| { 183| 1| let dataEntries = setupPositiveValuesDataEntries() 184| 1| let dataSet = setupDefaultDataSet(chartDataEntries: dataEntries) 185| 1| let chart = setupDefaultChart(dataSets: [dataSet]) 186| 1| //If min is greater than max, then min and max will be exchanged. 187| 1| chart.leftAxis.axisMaximum = 200 188| 1| chart.leftAxis.axisMinimum = -10 189| 1| chart.notifyDataSetChanged() 190| 1| ChartsSnapshotVerifyView(chart, identifier: Snapshot.identifier(UIScreen.main.bounds.size), overallTolerance: Snapshot.tolerance) 191| 1| } 192| | 193| | func testNegativeValues() 194| 1| { 195| 1| let dataEntries = setupNegativeValuesDataEntries() 196| 1| let dataSet = setupDefaultDataSet(chartDataEntries: dataEntries) 197| 1| let chart = setupDefaultChart(dataSets: [dataSet]) 198| 1| ChartsSnapshotVerifyView(chart, identifier: Snapshot.identifier(UIScreen.main.bounds.size), overallTolerance: Snapshot.tolerance) 199| 1| } 200| | 201| | func testNegativeValuesWithCustomAxisMaximum() 202| 1| { 203| 1| let dataEntries = setupNegativeValuesDataEntries() 204| 1| let dataSet = setupDefaultDataSet(chartDataEntries: dataEntries) 205| 1| let chart = setupDefaultChart(dataSets: [dataSet]) 206| 1| chart.leftAxis.axisMaximum = 10 207| 1| chart.notifyDataSetChanged() 208| 1| ChartsSnapshotVerifyView(chart, identifier: Snapshot.identifier(UIScreen.main.bounds.size), overallTolerance: Snapshot.tolerance) 209| 1| } 210| | 211| | func testNegativeValuesWithCustomAxisMaximum2() 212| 1| { 213| 1| let dataEntries = setupNegativeValuesDataEntries() 214| 1| let dataSet = setupDefaultDataSet(chartDataEntries: dataEntries) 215| 1| let chart = setupDefaultChart(dataSets: [dataSet]) 216| 1| chart.leftAxis.axisMaximum = -150 217| 1| chart.notifyDataSetChanged() 218| 1| ChartsSnapshotVerifyView(chart, identifier: Snapshot.identifier(UIScreen.main.bounds.size), overallTolerance: Snapshot.tolerance) 219| 1| } 220| | 221| | 222| | func testNegativeValuesWithCustomAxisMinimum() 223| 1| { 224| 1| let dataEntries = setupNegativeValuesDataEntries() 225| 1| let dataSet = setupDefaultDataSet(chartDataEntries: dataEntries) 226| 1| let chart = setupDefaultChart(dataSets: [dataSet]) 227| 1| chart.leftAxis.axisMinimum = -200 228| 1| chart.notifyDataSetChanged() 229| 1| ChartsSnapshotVerifyView(chart, identifier: Snapshot.identifier(UIScreen.main.bounds.size), overallTolerance: Snapshot.tolerance) 230| 1| } 231| | 232| | func testNegativeValuesWithCustomAxisMinimum2() 233| 1| { 234| 1| let dataEntries = setupNegativeValuesDataEntries() 235| 1| let dataSet = setupDefaultDataSet(chartDataEntries: dataEntries) 236| 1| let chart = setupDefaultChart(dataSets: [dataSet]) 237| 1| chart.leftAxis.axisMinimum = 10 238| 1| chart.notifyDataSetChanged() 239| 1| ChartsSnapshotVerifyView(chart, identifier: Snapshot.identifier(UIScreen.main.bounds.size), overallTolerance: Snapshot.tolerance) 240| 1| } 241| | 242| | func testNegativeValuesWithCustomAxisMaximumAndCustomAxisMaximum() 243| 1| { 244| 1| let dataEntries = setupNegativeValuesDataEntries() 245| 1| let dataSet = setupDefaultDataSet(chartDataEntries: dataEntries) 246| 1| let chart = setupDefaultChart(dataSets: [dataSet]) 247| 1| //If min is greater than max, then min and max will be exchanged. 248| 1| chart.leftAxis.axisMaximum = 10 249| 1| chart.leftAxis.axisMinimum = -200 250| 1| chart.notifyDataSetChanged() 251| 1| ChartsSnapshotVerifyView(chart, identifier: Snapshot.identifier(UIScreen.main.bounds.size), overallTolerance: Snapshot.tolerance) 252| 1| } 253| | 254| | func testHidesValues() 255| 1| { 256| 1| let dataEntries = setupDefaultValuesDataEntries() 257| 1| let dataSet = setupDefaultDataSet(chartDataEntries: dataEntries) 258| 1| let chart = setupDefaultChart(dataSets: [dataSet]) 259| 1| dataSet.drawValuesEnabled = false 260| 1| chart.notifyDataSetChanged() 261| 1| ChartsSnapshotVerifyView(chart, identifier: Snapshot.identifier(UIScreen.main.bounds.size), overallTolerance: Snapshot.tolerance) 262| 1| } 263| | 264| | func testNotDrawValueAboveBars() 265| 1| { 266| 1| let dataEntries = setupDefaultValuesDataEntries() 267| 1| let dataSet = setupDefaultDataSet(chartDataEntries: dataEntries) 268| 1| let chart = setupDefaultChart(dataSets: [dataSet]) 269| 1| chart.drawValueAboveBarEnabled = false 270| 1| chart.notifyDataSetChanged() 271| 1| ChartsSnapshotVerifyView(chart, identifier: Snapshot.identifier(UIScreen.main.bounds.size), overallTolerance: Snapshot.tolerance) 272| 1| } 273| | 274| | func testStackedDrawValues() 275| 1| { 276| 1| let dataEntries = setupStackedValuesDataEntries() 277| 1| let dataSet = setupDefaultStackedDataSet(chartDataEntries: dataEntries) 278| 1| let chart = setupDefaultChart(dataSets: [dataSet]) 279| 1| chart.notifyDataSetChanged() 280| 1| ChartsSnapshotVerifyView(chart, identifier: Snapshot.identifier(UIScreen.main.bounds.size), overallTolerance: Snapshot.tolerance) 281| 1| } 282| | 283| | func testStackedNotDrawValues() 284| 1| { 285| 1| let dataEntries = setupStackedValuesDataEntries() 286| 1| let dataSet = setupDefaultStackedDataSet(chartDataEntries: dataEntries) 287| 1| dataSet.drawValuesEnabled = false 288| 1| let chart = setupDefaultChart(dataSets: [dataSet]) 289| 1| chart.notifyDataSetChanged() 290| 1| ChartsSnapshotVerifyView(chart, identifier: Snapshot.identifier(UIScreen.main.bounds.size), overallTolerance: Snapshot.tolerance) 291| 1| } 292| | 293| | func testStackedNotDrawValuesAboveBars() 294| 1| { 295| 1| let dataEntries = setupStackedValuesDataEntries() 296| 1| let dataSet = setupDefaultStackedDataSet(chartDataEntries: dataEntries) 297| 1| let chart = setupDefaultChart(dataSets: [dataSet]) 298| 1| chart.drawValueAboveBarEnabled = false 299| 1| chart.notifyDataSetChanged() 300| 1| ChartsSnapshotVerifyView(chart, identifier: Snapshot.identifier(UIScreen.main.bounds.size), overallTolerance: Snapshot.tolerance) 301| 1| } 302| | 303| | func testHideLeftAxis() 304| 1| { 305| 1| let dataEntries = setupDefaultValuesDataEntries() 306| 1| let dataSet = setupDefaultDataSet(chartDataEntries: dataEntries) 307| 1| let chart = setupDefaultChart(dataSets: [dataSet]) 308| 1| chart.leftAxis.enabled = false 309| 1| chart.notifyDataSetChanged() 310| 1| ChartsSnapshotVerifyView(chart, identifier: Snapshot.identifier(UIScreen.main.bounds.size), overallTolerance: Snapshot.tolerance) 311| 1| } 312| | 313| | func testHideRightAxis() 314| 1| { 315| 1| let dataEntries = setupDefaultValuesDataEntries() 316| 1| let dataSet = setupDefaultDataSet(chartDataEntries: dataEntries) 317| 1| let chart = setupDefaultChart(dataSets: [dataSet]) 318| 1| chart.rightAxis.enabled = false 319| 1| chart.notifyDataSetChanged() 320| 1| ChartsSnapshotVerifyView(chart, identifier: Snapshot.identifier(UIScreen.main.bounds.size), overallTolerance: Snapshot.tolerance) 321| 1| } 322| | 323| | func testInvertedLeftAxis() 324| 1| { 325| 1| let dataEntries = setupDefaultValuesDataEntries() 326| 1| let dataSet = setupDefaultDataSet(chartDataEntries: dataEntries) 327| 1| let chart = setupDefaultChart(dataSets: [dataSet]) 328| 1| chart.leftAxis.inverted = true 329| 1| chart.notifyDataSetChanged() 330| 1| ChartsSnapshotVerifyView(chart, identifier: Snapshot.identifier(UIScreen.main.bounds.size), overallTolerance: Snapshot.tolerance) 331| 1| } 332| | 333| | func testInvertedLeftAxisWithNegativeValues() 334| 1| { 335| 1| let dataEntries = setupNegativeValuesDataEntries() 336| 1| let dataSet = setupDefaultDataSet(chartDataEntries: dataEntries) 337| 1| let chart = setupDefaultChart(dataSets: [dataSet]) 338| 1| chart.leftAxis.inverted = true 339| 1| chart.notifyDataSetChanged() 340| 1| ChartsSnapshotVerifyView(chart, identifier: Snapshot.identifier(UIScreen.main.bounds.size), overallTolerance: Snapshot.tolerance) 341| 1| } 342| | 343| | func testInvertedLeftAxisWithPositiveValues() 344| 1| { 345| 1| let dataEntries = setupPositiveValuesDataEntries() 346| 1| let dataSet = setupDefaultDataSet(chartDataEntries: dataEntries) 347| 1| let chart = setupDefaultChart(dataSets: [dataSet]) 348| 1| chart.leftAxis.inverted = true 349| 1| chart.notifyDataSetChanged() 350| 1| ChartsSnapshotVerifyView(chart, identifier: Snapshot.identifier(UIScreen.main.bounds.size), overallTolerance: Snapshot.tolerance) 351| 1| } 352| | 353| | func testInvertedRightAxis() 354| 1| { 355| 1| let dataEntries = setupDefaultValuesDataEntries() 356| 1| let dataSet = setupDefaultDataSet(chartDataEntries: dataEntries) 357| 1| dataSet.axisDependency = .right 358| 1| let chart = setupDefaultChart(dataSets: [dataSet]) 359| 1| chart.rightAxis.inverted = true 360| 1| chart.notifyDataSetChanged() 361| 1| ChartsSnapshotVerifyView(chart, identifier: Snapshot.identifier(UIScreen.main.bounds.size), overallTolerance: Snapshot.tolerance) 362| 1| } 363| | 364| | func testInvertedRightAxisWithNegativeValues() 365| 1| { 366| 1| let dataEntries = setupNegativeValuesDataEntries() 367| 1| let dataSet = setupDefaultDataSet(chartDataEntries: dataEntries) 368| 1| dataSet.axisDependency = .right 369| 1| let chart = setupDefaultChart(dataSets: [dataSet]) 370| 1| chart.rightAxis.inverted = true 371| 1| chart.notifyDataSetChanged() 372| 1| ChartsSnapshotVerifyView(chart, identifier: Snapshot.identifier(UIScreen.main.bounds.size), overallTolerance: Snapshot.tolerance) 373| 1| } 374| | 375| | func testInvertedRightAxisWithPositiveValues() 376| 1| { 377| 1| let dataEntries = setupPositiveValuesDataEntries() 378| 1| let dataSet = setupDefaultDataSet(chartDataEntries: dataEntries) 379| 1| dataSet.axisDependency = .right 380| 1| let chart = setupDefaultChart(dataSets: [dataSet]) 381| 1| chart.rightAxis.inverted = true 382| 1| chart.notifyDataSetChanged() 383| 1| ChartsSnapshotVerifyView(chart, identifier: Snapshot.identifier(UIScreen.main.bounds.size), overallTolerance: Snapshot.tolerance) 384| 1| } 385| | 386| | func testHideHorizontalGridlines() 387| 1| { 388| 1| let dataEntries = setupDefaultValuesDataEntries() 389| 1| let dataSet = setupDefaultDataSet(chartDataEntries: dataEntries) 390| 1| let chart = setupDefaultChart(dataSets: [dataSet]) 391| 1| chart.leftAxis.drawGridLinesEnabled = false 392| 1| chart.rightAxis.drawGridLinesEnabled = false 393| 1| chart.notifyDataSetChanged() 394| 1| ChartsSnapshotVerifyView(chart, identifier: Snapshot.identifier(UIScreen.main.bounds.size), overallTolerance: Snapshot.tolerance) 395| 1| } 396| | 397| | func testHideVerticalGridlines() 398| 1| { 399| 1| let dataEntries = setupDefaultValuesDataEntries() 400| 1| let dataSet = setupDefaultDataSet(chartDataEntries: dataEntries) 401| 1| let chart = setupDefaultChart(dataSets: [dataSet]) 402| 1| chart.xAxis.drawGridLinesEnabled = false 403| 1| chart.notifyDataSetChanged() 404| 1| ChartsSnapshotVerifyView(chart, identifier: Snapshot.identifier(UIScreen.main.bounds.size), overallTolerance: Snapshot.tolerance) 405| 1| } 406| | 407| | func testDrawIcons() 408| 1| { 409| 1| let dataEntries = setupDefaultValuesDataEntries() 410| 1| let dataSet = setupDefaultDataSet(chartDataEntries: dataEntries) 411| 1| let chart = setupDefaultChart(dataSets: [dataSet]) 412| 1| dataSet.drawIconsEnabled = true 413| 1| chart.notifyDataSetChanged() 414| 1| ChartsSnapshotVerifyView(chart, identifier: Snapshot.identifier(UIScreen.main.bounds.size), overallTolerance: Snapshot.tolerance) 415| 1| } 416| |} /Users/travis/build/danielgindi/Charts/Tests/Charts/ChartUtilsTests.swift: 1| |import XCTest 2| |@testable import Charts 3| | 4| |class ChartUtilsTests: XCTestCase { 5| | 6| 6| override func setUp() { 7| 6| super.setUp() 8| 6| // Put setup code here. This method is called before the invocation of each test method in the class. 9| 6| } 10| | 11| 6| override func tearDown() { 12| 6| // Put teardown code here. This method is called after the invocation of each test method in the class. 13| 6| super.tearDown() 14| 6| } 15| | 16| 1| func testDecimalWithNaN() { 17| 1| 18| 1| let number = Double.nan 19| 1| 20| 1| let actual = number.decimalPlaces 21| 1| let expected = 0 22| 1| 23| 1| XCTAssertEqual(expected, actual) 24| 1| } 25| | 26| 1| func testDecimalWithInfinite() { 27| 1| 28| 1| let number = Double.infinity 29| 1| 30| 1| let actual = number.decimalPlaces 31| 1| let expected = 0 32| 1| 33| 1| XCTAssertEqual(expected, actual) 34| 1| } 35| | 36| 1| func testDecimalWithZero() { 37| 1| 38| 1| let number = 0.0 39| 1| 40| 1| let actual = number.decimalPlaces 41| 1| let expected = 0 42| 1| 43| 1| XCTAssertEqual(expected, actual) 44| 1| } 45| | 46| 1| func testDecimalWithMaxValue() { 47| 1| 48| 1| let number = Double.greatestFiniteMagnitude 49| 1| 50| 1| let actual = number.decimalPlaces 51| 1| let expected = 0 52| 1| 53| 1| XCTAssertEqual(expected, actual) 54| 1| } 55| | 56| 1| func testDecimalWithMinValue() { 57| 1| 58| 1| let number = Double.leastNormalMagnitude 59| 1| 60| 1| let actual = number.decimalPlaces 61| 1| let expected = 310 // Don't think this is supposed to be this value maybe 0? 62| 1| 63| 1| XCTAssertEqual(expected, actual) 64| 1| } 65| | 66| 1| func testDecimalWithNormalValue() { 67| 1| 68| 1| let number = 13.123123 69| 1| 70| 1| let actual = number.decimalPlaces 71| 1| let expected = 1 // Don't think this is supposed to be this value maybe 6? 72| 1| 73| 1| XCTAssertEqual(expected, actual) 74| 1| } 75| |} /Users/travis/build/danielgindi/Charts/Tests/Charts/CombinedChartTests.swift: 1| |// 2| |// CombinedChartTests.swift 3| |// ChartsTests 4| |// 5| |// Created by Xuan Liu on 14/10/2017. 6| |// 7| | 8| |import XCTest 9| |import FBSnapshotTestCase 10| |@testable import Charts 11| | 12| |class CombinedChartTests: FBSnapshotTestCase 13| |{ 14| | var chart: CombinedChartView! 15| | var lineDataSet: LineChartDataSet! 16| | var barDataSet: BarChartDataSet! 17| | 18| | override func setUp() 19| 3| { 20| 3| super.setUp() 21| 3| 22| 3| // Set to `true` to re-capture all snapshots 23| 3| self.recordMode = false 24| 3| 25| 3| // Sample data 26| 3| let combinedData = CombinedChartData() 27| 3| combinedData.barData = generateBarData() 28| 3| combinedData.lineData = generateLineData() 29| 3| chart = CombinedChartView(frame: CGRect(x: 0, y: 0, width: 480, height: 350)) 30| 3| chart.backgroundColor = NSUIColor.clear 31| 3| chart.leftAxis.axisMinimum = 0.0 32| 3| chart.rightAxis.axisMinimum = 0.0 33| 3| chart.data = combinedData 34| 3| } 35| | 36| | func generateBarData() -> BarChartData 37| 3| { 38| 3| let values: [Double] = [8, 104, 81, 93, 52, 44, 97, 101, 75, 28, 39| 3| 76, 25, 20, 13, 52, 44, 57, 23, 45, 91, 40| 3| 99, 14, 84, 48, 40, 71, 106, 41, 45, 61] 41| 3| 42| 3| var entries: [ChartDataEntry] = Array() 43| 3| 44| 3| for (i, value) in values.enumerated() 45| 90| { 46| 90| entries.append(BarChartDataEntry(x: Double(i), y: value, icon: UIImage(named: "icon", in: Bundle(for: self.classForCoder), compatibleWith: nil))) 47| 90| } 48| 3| 49| 3| barDataSet = BarChartDataSet(entries: entries, label: "Bar chart unit test data") 50| 3| barDataSet.drawIconsEnabled = false 51| 3| 52| 3| let data = BarChartData(dataSet: barDataSet) 53| 3| data.barWidth = 0.85 54| 3| return data 55| 3| } 56| | 57| | func generateLineData() -> LineChartData 58| 3| { 59| 3| let values: [Double] = [0, 254, 81, 93, 52, 44, 97, 101, 75, 28, 60| 3| 76, 25, 20, 13, 52, 44, 57, 23, 45, 91, 61| 3| 99, 14, 84, 48, 40, 71, 106, 41, 45, 61] 62| 3| 63| 3| var entries: [ChartDataEntry] = Array() 64| 3| 65| 3| for (i, value) in values.enumerated() 66| 90| { 67| 90| entries.append(ChartDataEntry(x: Double(i), y: value, icon: UIImage(named: "icon", in: Bundle(for: self.classForCoder), compatibleWith: nil))) 68| 90| } 69| 3| 70| 3| lineDataSet = LineChartDataSet(entries: entries, label: "Line chart unit test data") 71| 3| lineDataSet.drawIconsEnabled = false 72| 3| return LineChartData(dataSet: lineDataSet) 73| 3| } 74| | 75| | override func tearDown() 76| 3| { 77| 3| // Put teardown code here. This method is called after the invocation of each test method in the class. 78| 3| super.tearDown() 79| 3| } 80| | 81| | func testDefaultAxisDependency() 82| 1| { 83| 1| ChartsSnapshotVerifyView(chart, identifier: Snapshot.identifier(UIScreen.main.bounds.size), overallTolerance: Snapshot.tolerance) 84| 1| } 85| | 86| | func testLeftRightAxisDependency() 87| 1| { 88| 1| lineDataSet.axisDependency = .left 89| 1| barDataSet.axisDependency = .right 90| 1| chart.data?.notifyDataChanged() 91| 1| chart.notifyDataSetChanged() 92| 1| ChartsSnapshotVerifyView(chart, identifier: Snapshot.identifier(UIScreen.main.bounds.size), overallTolerance: Snapshot.tolerance) 93| 1| } 94| | 95| | func testAllRightAxisDependency() 96| 1| { 97| 1| lineDataSet.axisDependency = .right 98| 1| barDataSet.axisDependency = .right 99| 1| chart.data?.notifyDataChanged() 100| 1| chart.notifyDataSetChanged() 101| 1| ChartsSnapshotVerifyView(chart, identifier: Snapshot.identifier(UIScreen.main.bounds.size), overallTolerance: Snapshot.tolerance) 102| 1| } 103| |} 104| | /Users/travis/build/danielgindi/Charts/Tests/Charts/EquatableTests.swift: 1| |// 2| |// EquatableTests.swift 3| |// Charts 4| |// 5| |// Created by Jacob Christie on 2017-11-13. 6| |// 7| | 8| |import XCTest 9| |@testable import Charts 10| | 11| |class EquatableTests: XCTestCase { 12| 1| func testChartDataEntryEquality() { 13| 1| let image = UIImage() 14| 1| let data = NSObject() 15| 1| let entry1 = ChartDataEntry(x: 5, y: 3, icon: image, data: data) 16| 1| let entry2 = ChartDataEntry(x: 5, y: 3, icon: image, data: data) 17| 1| 18| 1| XCTAssertTrue(entry1 == entry2) 19| 1| } 20| | 21| 1| func testChartDataEntryInequality() { 22| 1| let image = UIImage() 23| 1| let data1 = NSObject() 24| 1| let data2 = NSObject() 25| 1| let entry1 = ChartDataEntry(x: 5, y: 3, icon: image, data: data1) 26| 1| let entry2 = ChartDataEntry(x: 5, y: 9, icon: image, data: data2) 27| 1| 28| 1| XCTAssertFalse(entry1 == entry2) 29| 1| } 30| | 31| 1| func testHighlightEquality() { 32| 1| let high1 = Highlight(x: 5, y: 3, xPx: 1, yPx: -1, dataSetIndex: 8, stackIndex: 8, axis: .right) 33| 1| let high2 = Highlight(x: 5, y: 3, xPx: 1, yPx: -1, dataSetIndex: 8, stackIndex: 8, axis: .right) 34| 1| 35| 1| XCTAssertTrue(high1 == high2) 36| 1| } 37| | 38| 1| func testHighlightInequality() { 39| 1| let high1 = Highlight(x: 5, y: 3, xPx: 1, yPx: -1, dataSetIndex: 8, stackIndex: 8, axis: .left) 40| 1| let high2 = Highlight(x: 5, y: 3, xPx: 1, yPx: -1, dataSetIndex: 8, stackIndex: 9, axis: .left) 41| 1| 42| 1| XCTAssertFalse(high1 == high2) 43| 1| } 44| |} 45| | /Users/travis/build/danielgindi/Charts/Tests/Charts/HorizontalBarChartTests.swift: 1| |// 2| |// HorizontalBarChartTests.swift 3| |// ChartsTests 4| |// 5| |// Created by Xuan Liu on 2019/3/20. 6| |// 7| | 8| |import XCTest 9| |import FBSnapshotTestCase 10| |@testable import Charts 11| | 12| |class HorizontalBarChartTests: FBSnapshotTestCase 13| |{ 14| | 15| | override func setUp() 16| 6| { 17| 6| super.setUp() 18| 6| // Set to `true` to re-capture all snapshots 19| 6| self.recordMode = false 20| 6| } 21| | 22| | override func tearDown() 23| 6| { 24| 6| // Put teardown code here. This method is called after the invocation of each test method in the class. 25| 6| super.tearDown() 26| 6| } 27| | 28| | //MARK: Prepare 29| | func setupCustomValuesDataEntries(values: [Double]) -> [ChartDataEntry] 30| 3| { 31| 3| var entries: [ChartDataEntry] = Array() 32| 3| for (i, value) in values.enumerated() 33| 90| { 34| 90| entries.append(BarChartDataEntry(x: Double(i), y: value, icon: UIImage(named: "icon", in: Bundle(for: self.classForCoder), compatibleWith: nil))) 35| 90| } 36| 3| return entries 37| 3| } 38| | 39| | func setupStackedvaluesDataEntries() -> [ChartDataEntry] 40| 3| { 41| 3| var entries: [ChartDataEntry] = Array() 42| 3| entries.append(BarChartDataEntry(x: 0, yValues: [28, 50, 60, 30, 42], icon: UIImage(named: "icon"))) 43| 3| entries.append(BarChartDataEntry(x: 1, yValues: [-20, -36, -52, -40, -15], icon: UIImage(named: "icon"))) 44| 3| entries.append(BarChartDataEntry(x: 2, yValues: [10, 30, 40, 90, 72], icon: UIImage(named: "icon"))) 45| 3| entries.append(BarChartDataEntry(x: 3, yValues: [-40, -50, -30, -60, -20], icon: UIImage(named: "icon"))) 46| 3| entries.append(BarChartDataEntry(x: 4, yValues: [10, 40, 60, 45, 62], icon: UIImage(named: "icon"))) 47| 3| return entries 48| 3| } 49| | 50| | func setupDefaultValuesDataEntries() -> [ChartDataEntry] 51| 3| { 52| 3| let values: [Double] = [8, 104, -81, 93, 52, -44, 97, 101, -75, 28, 53| 3| -76, 25, 20, -13, 52, 44, -57, 23, 45, -91, 54| 3| 99, 14, -84, 48, 40, -71, 106, 41, -45, 61] 55| 3| return setupCustomValuesDataEntries(values: values) 56| 3| } 57| | 58| | func setupDefaultDataSet(chartDataEntries: [ChartDataEntry]) -> BarChartDataSet 59| 3| { 60| 3| let dataSet = BarChartDataSet(entries: chartDataEntries, label: "Bar chart unit test data") 61| 3| dataSet.drawIconsEnabled = false 62| 3| dataSet.iconsOffset = CGPoint(x: 0, y: -10.0) 63| 3| return dataSet 64| 3| } 65| | 66| | func setupDefaultStackedDataSet(chartDataEntries: [ChartDataEntry]) -> BarChartDataSet 67| 3| { 68| 3| let dataSet = BarChartDataSet(entries: chartDataEntries, label: "Stacked bar chart unit test data") 69| 3| dataSet.drawIconsEnabled = false 70| 3| dataSet.iconsOffset = CGPoint(x: 0, y: -10.0) 71| 3| dataSet.colors = Array(arrayLiteral:NSUIColor(red: 46/255.0, green: 204/255.0, blue: 113/255.0, alpha: 1.0), 72| 3| NSUIColor(red: 241/255.0, green: 196/255.0, blue: 15/255.0, alpha: 1.0), 73| 3| NSUIColor(red: 231/255.0, green: 76/255.0, blue: 60/255.0, alpha: 1.0), 74| 3| NSUIColor(red: 52/255.0, green: 152/255.0, blue: 219/255.0, alpha: 1.0) 75| 3| ) 76| 3| return dataSet 77| 3| } 78| | 79| | func setupDefaultChart(dataSets: [BarChartDataSet]) -> BarChartView 80| 6| { 81| 6| let data = BarChartData(dataSets: dataSets) 82| 6| data.barWidth = 0.85 83| 6| 84| 6| let chart = HorizontalBarChartView(frame: CGRect(x: 0, y: 0, width: 480, height: 350)) 85| 6| chart.backgroundColor = NSUIColor.clear 86| 6| chart.data = data 87| 6| return chart 88| 6| } 89| | 90| | //MARK: Start Test 91| | func testDefaultValues() 92| 1| { 93| 1| let dataEntries = setupDefaultValuesDataEntries() 94| 1| let dataSet = setupDefaultDataSet(chartDataEntries: dataEntries) 95| 1| let chart = setupDefaultChart(dataSets: [dataSet]) 96| 1| ChartsSnapshotVerifyView(chart, identifier: Snapshot.identifier(UIScreen.main.bounds.size), overallTolerance: Snapshot.tolerance) 97| 1| } 98| | 99| | func testHidesValues() 100| 1| { 101| 1| let dataEntries = setupDefaultValuesDataEntries() 102| 1| let dataSet = setupDefaultDataSet(chartDataEntries: dataEntries) 103| 1| let chart = setupDefaultChart(dataSets: [dataSet]) 104| 1| dataSet.drawValuesEnabled = false 105| 1| chart.notifyDataSetChanged() 106| 1| ChartsSnapshotVerifyView(chart, identifier: Snapshot.identifier(UIScreen.main.bounds.size), overallTolerance: Snapshot.tolerance) 107| 1| } 108| | 109| | func testNotDrawValueAboveBars() 110| 1| { 111| 1| let dataEntries = setupDefaultValuesDataEntries() 112| 1| let dataSet = setupDefaultDataSet(chartDataEntries: dataEntries) 113| 1| let chart = setupDefaultChart(dataSets: [dataSet]) 114| 1| chart.drawValueAboveBarEnabled = false 115| 1| chart.notifyDataSetChanged() 116| 1| ChartsSnapshotVerifyView(chart, identifier: Snapshot.identifier(UIScreen.main.bounds.size), overallTolerance: Snapshot.tolerance) 117| 1| } 118| | 119| | func testStackedDrawValues() 120| 1| { 121| 1| let dataEntries = setupStackedvaluesDataEntries() 122| 1| let dataSet = setupDefaultStackedDataSet(chartDataEntries: dataEntries) 123| 1| let chart = setupDefaultChart(dataSets: [dataSet]) 124| 1| chart.notifyDataSetChanged() 125| 1| ChartsSnapshotVerifyView(chart, identifier: Snapshot.identifier(UIScreen.main.bounds.size), overallTolerance: Snapshot.tolerance) 126| 1| } 127| | 128| | func testStackedNotDrawValues() 129| 1| { 130| 1| let dataEntries = setupStackedvaluesDataEntries() 131| 1| let dataSet = setupDefaultStackedDataSet(chartDataEntries: dataEntries) 132| 1| dataSet.drawValuesEnabled = false 133| 1| let chart = setupDefaultChart(dataSets: [dataSet]) 134| 1| chart.notifyDataSetChanged() 135| 1| ChartsSnapshotVerifyView(chart, identifier: Snapshot.identifier(UIScreen.main.bounds.size), overallTolerance: Snapshot.tolerance) 136| 1| } 137| | 138| | func testStackedNotDrawValuesAboveBars() 139| 1| { 140| 1| let dataEntries = setupStackedvaluesDataEntries() 141| 1| let dataSet = setupDefaultStackedDataSet(chartDataEntries: dataEntries) 142| 1| let chart = setupDefaultChart(dataSets: [dataSet]) 143| 1| chart.drawValueAboveBarEnabled = false 144| 1| chart.notifyDataSetChanged() 145| 1| ChartsSnapshotVerifyView(chart, identifier: Snapshot.identifier(UIScreen.main.bounds.size), overallTolerance: Snapshot.tolerance) 146| 1| } 147| |} /Users/travis/build/danielgindi/Charts/Tests/Charts/LineChartTests.swift: 1| |import XCTest 2| |import FBSnapshotTestCase 3| |@testable import Charts 4| | 5| |class LineChartTests: FBSnapshotTestCase 6| |{ 7| | 8| | var chart: LineChartView! 9| | var dataSet: LineChartDataSet! 10| | 11| | override func setUp() 12| 6| { 13| 6| super.setUp() 14| 6| 15| 6| // Set to `true` to re-capture all snapshots 16| 6| self.recordMode = false 17| 6| 18| 6| // Sample data 19| 6| let values: [Double] = [8, 104, 81, 93, 52, 44, 97, 101, 75, 28, 20| 6| 76, 25, 20, 13, 52, 44, 57, 23, 45, 91, 21| 6| 99, 14, 84, 48, 40, 71, 106, 41, 45, 61] 22| 6| 23| 6| var entries: [ChartDataEntry] = Array() 24| 6| 25| 6| for (i, value) in values.enumerated() 26| 180| { 27| 180| entries.append(ChartDataEntry(x: Double(i), y: value, icon: UIImage(named: "icon", in: Bundle(for: self.classForCoder), compatibleWith: nil))) 28| 180| } 29| 6| 30| 6| dataSet = LineChartDataSet(entries: entries, label: "First unit test data") 31| 6| dataSet.drawIconsEnabled = false 32| 6| dataSet.iconsOffset = CGPoint(x: 0, y: 20.0) 33| 6| 34| 6| chart = LineChartView(frame: CGRect(x: 0, y: 0, width: 480, height: 350)) 35| 6| chart.backgroundColor = NSUIColor.clear 36| 6| chart.leftAxis.axisMinimum = 0.0 37| 6| chart.rightAxis.axisMinimum = 0.0 38| 6| chart.data = LineChartData(dataSet: dataSet) 39| 6| } 40| | 41| | override func tearDown() 42| 6| { 43| 6| // Put teardown code here. This method is called after the invocation of each test method in the class. 44| 6| super.tearDown() 45| 6| } 46| | 47| | func testDefaultValues() 48| 1| { 49| 1| ChartsSnapshotVerifyView(chart, identifier: Snapshot.identifier(UIScreen.main.bounds.size), overallTolerance: Snapshot.tolerance) 50| 1| } 51| | 52| | func testHidesValues() 53| 1| { 54| 1| dataSet.drawValuesEnabled = false 55| 1| ChartsSnapshotVerifyView(chart, identifier: Snapshot.identifier(UIScreen.main.bounds.size), overallTolerance: Snapshot.tolerance) 56| 1| } 57| | 58| | func testDoesntDrawCircles() 59| 1| { 60| 1| dataSet.drawCirclesEnabled = false 61| 1| ChartsSnapshotVerifyView(chart, identifier: Snapshot.identifier(UIScreen.main.bounds.size), overallTolerance: Snapshot.tolerance) 62| 1| } 63| | 64| | func testIsCubic() 65| 1| { 66| 1| dataSet.mode = LineChartDataSet.Mode.cubicBezier 67| 1| ChartsSnapshotVerifyView(chart, identifier: Snapshot.identifier(UIScreen.main.bounds.size), overallTolerance: Snapshot.tolerance) 68| 1| } 69| | 70| | func testDoesntDrawCircleHole() 71| 1| { 72| 1| dataSet.drawCircleHoleEnabled = false 73| 1| ChartsSnapshotVerifyView(chart, identifier: Snapshot.identifier(UIScreen.main.bounds.size), overallTolerance: Snapshot.tolerance) 74| 1| } 75| | 76| | func testDrawIcons() 77| 1| { 78| 1| dataSet.drawIconsEnabled = true 79| 1| ChartsSnapshotVerifyView(chart, identifier: Snapshot.identifier(UIScreen.main.bounds.size), overallTolerance: Snapshot.tolerance) 80| 1| } 81| |} /Users/travis/build/danielgindi/Charts/Tests/Charts/PieChartTests.swift: 1| |import XCTest 2| |import FBSnapshotTestCase 3| |@testable import Charts 4| | 5| |class PieChartTests: FBSnapshotTestCase 6| |{ 7| | 8| | var chart: PieChartView! 9| | var dataSet: PieChartDataSet! 10| | 11| | override func setUp() 12| 6| { 13| 6| super.setUp() 14| 6| 15| 6| // Set to `true` to re-capture all snapshots 16| 6| self.recordMode = false 17| 6| 18| 6| // Sample data 19| 6| let values: [Double] = [11, 33, 81, 52, 97, 101, 75] 20| 6| 21| 6| var entries: [PieChartDataEntry] = Array() 22| 6| 23| 6| for value in values 24| 42| { 25| 42| entries.append(PieChartDataEntry(value: value, icon: UIImage(named: "icon", in: Bundle(for: self.classForCoder), compatibleWith: nil))) 26| 42| } 27| 6| 28| 6| dataSet = PieChartDataSet(entries: entries, label: "First unit test data") 29| 6| dataSet.drawIconsEnabled = false 30| 6| dataSet.iconsOffset = CGPoint(x: 0, y: 20.0) 31| 6| 32| 6| dataSet.colors = ChartColorTemplates.vordiplom() 33| 6| + ChartColorTemplates.joyful() 34| 6| + ChartColorTemplates.colorful() 35| 6| + ChartColorTemplates.liberty() 36| 6| + ChartColorTemplates.pastel() 37| 6| + [UIColor(red: 51/255, green: 181/255, blue: 229/255, alpha: 1)] 38| 6| 39| 6| chart = PieChartView(frame: CGRect(x: 0, y: 0, width: 480, height: 350)) 40| 6| chart.backgroundColor = NSUIColor.clear 41| 6| chart.centerText = "PieChart Unit Test" 42| 6| chart.data = PieChartData(dataSet: dataSet) 43| 6| } 44| | 45| | override func tearDown() 46| 6| { 47| 6| // Put teardown code here. This method is called after the invocation of each test method in the class. 48| 6| super.tearDown() 49| 6| } 50| | 51| | func testDefaultValues() 52| 1| { 53| 1| ChartsSnapshotVerifyView(chart, identifier: Snapshot.identifier(UIScreen.main.bounds.size), overallTolerance: Snapshot.tolerance) 54| 1| } 55| | 56| | func testHidesValues() 57| 1| { 58| 1| dataSet.drawValuesEnabled = false 59| 1| ChartsSnapshotVerifyView(chart, identifier: Snapshot.identifier(UIScreen.main.bounds.size), overallTolerance: Snapshot.tolerance) 60| 1| } 61| | 62| | func testDrawIcons() 63| 1| { 64| 1| dataSet.drawIconsEnabled = true 65| 1| ChartsSnapshotVerifyView(chart, identifier: Snapshot.identifier(UIScreen.main.bounds.size), overallTolerance: Snapshot.tolerance) 66| 1| } 67| | 68| | func testHideCenterLabel() 69| 1| { 70| 1| chart.drawCenterTextEnabled = false 71| 1| ChartsSnapshotVerifyView(chart, identifier: Snapshot.identifier(UIScreen.main.bounds.size), overallTolerance: Snapshot.tolerance) 72| 1| } 73| | 74| | func testHighlightDisabled() 75| 1| { 76| 1| chart.data?.dataSets[0].highlightEnabled = false 77| 1| chart.highlightValue(x: 1.0, dataSetIndex: 0, callDelegate: false) 78| 1| ChartsSnapshotVerifyView(chart, identifier: Snapshot.identifier(UIScreen.main.bounds.size), overallTolerance: Snapshot.tolerance) 79| 1| } 80| | 81| | func testHighlightEnabled() 82| 1| { 83| 1| // by default, it's enabled 84| 1| chart.highlightValue(x: 1.0, dataSetIndex: 0, callDelegate: false) 85| 1| ChartsSnapshotVerifyView(chart, identifier: Snapshot.identifier(UIScreen.main.bounds.size), overallTolerance: Snapshot.tolerance) 86| 1| } 87| |} /Users/travis/build/danielgindi/Charts/Tests/Charts/Snapshot.swift: 1| |import CoreGraphics 2| |import FBSnapshotTestCase 3| | 4| |public struct Snapshot 5| |{ 6| | public static let tolerance: CGFloat = 0.001 7| | 8| 52| public static func identifier(_ size: CGSize) -> String { 9| 52| #if os(tvOS) 10| 52| let identifier = "tvOS" 11| 52| #elseif os(iOS) 12| 52| let identifier = "iOS" 13| 52| #elseif os(OSX) 14| 52| let identifier = "macOS" 15| 52| #else 16| 52| let identifier = "" 17| 52| #endif 18| 52| 19| 52| return "\(identifier)_\(size.width)_\(size.height)" 20| 52| } 21| |} 22| | 23| |public extension FBSnapshotTestCase 24| |{ 25| | func ChartsSnapshotVerifyView(_ view: UIView, identifier: String = "", suffixes: NSOrderedSet = NSOrderedSet(object: "_64"), perPixelTolerance: CGFloat = 0, overallTolerance: CGFloat = 0, file: StaticString = #file, line: UInt = #line) 26| 52| { 27| 52| FBSnapshotVerifyView(view, identifier: identifier, suffixes: suffixes, perPixelTolerance: perPixelTolerance, overallTolerance: overallTolerance, file: file, line: line) 28| 52| } 29| |} <<<<<< EOF # path=fixes ./ChartDataTests.swift:7,10,12,14,20,21,24,30,34,38,39,43,45,46,52,53,58,62,63,67,68,69 ./Source/Charts/Filters/DataApproximator.swift:11,14,17,20,23,25,26,28,32,39,42,43,57,59,62,63,66,68,70,72,74,77,78,79,81,84,88,89,90,92,95,98,100,102,108,109,111,113,114,115 ./Source/Charts/Filters/DataApproximator+N.swift:10,13,18,21,23,24,25,29,32,36,39,42,43,46,48,52,53,54,55,56,60,61,64,65,66,67,72,75,77,79,84,88,91,94,97,100,101,106,107,111,112,114,118,119,121,122,127,128,131,135,138,142,146,147,148,150,151,152,153 ./Source/Charts/Renderers/RadarChartRenderer.swift:11,14,16,20,24,26,28,30,32,34,35,37,39,41,43,45,48,55,56,58,60,61,62,63,71,73,75,78,80,83,88,91,99,101,103,105,108,110,112,113,115,118,120,122,123,127,130,140,141,143,144,147,150,151,153,156,158,160,162,164,165,166,169,173,177,184,185,188,189,191,193,194,196,201,204,206,209,211,213,215,220,222,224,226,228,231,233,235,237,250,251,253,257,263,264,265,266,267,269,271,272,274,276,281,283,285,290,292,297,300,302,305,310,312,313,318,320,322,324,326,329,334,336,337,338,340,341,343,345,350,352,354,357,359,361,366,369,371,373,374,377,379,381,383,384,386,388,391,393,396,398,400,403,405,407,409,410,419,420,421,422,424,425,434,436,438,442,444,445,448,449,451,457,458,460,461,466,469,472,474,475 ./Source/Charts/Renderers/LegendRenderer.swift:11,14,17,20,22,24,26,27,30,32,34,36,39,41,44,48,52,54,57,60,62,64,65,77,78,80,82,94,95,97,99,101,113,114,116,118,130,131,134,136,148,160,162,163,165,167,170,172,174,176,177,189,190,191,192,194,195,198,199,201,203,205,207,208,213,215,220,225,228,232,234,236,238,240,242,244,245,247,249,250,252,254,256,258,260,261,263,265,266,268,270,272,274,277,278,282,286,288,290,292,294,295,296,297,299,301,305,308,310,313,316,319,320,322,324,328,331,334,335,339,344,345,347,349,351,353,354,361,363,365,366,367,369,371,373,374,376,378,379,387,389,391,392,394,396,398,399,400,402,406,408,410,416,422,424,426,427,429,433,435,437,439,441,443,445,446,453,455,457,458,459,461,463,465,467,469,470,472,474,475,477,479,481,484,485,489,491,494,495,496,497,498,500,508,513,516,518,519,521,524,526,530,534,537,540,542,545,547,551,553,555,557,559,561,562,564,570,571,572,575,577,578 ./Source/Charts/Renderers/YAxisRendererHorizontalBarChart.swift:11,14,16,18,20,21,24,26,28,31,34,36,39,41,44,45,46,48,49,52,54,56,58,59,62,65,67,69,71,73,75,77,78,80,82,84,86,88,89,90,94,100,101,103,105,107,109,110,112,116,118,120,122,123,125,130,132,137,139,140,147,151,154,157,159,161,163,173,174,175,177,183,184,188,193,194,196,201,204,206,208,210,211,213,215,216,219,225,228,233,236,238,240,242,244,246,247,251,252,254,256,261,263,265,267,268,270,272,274,276,278,280,282,283,286,291,295,299,303,305,307,309,310,312,314,317,319,322,324,332,334,342,344,352,354,362,363,364,365,367,368 ./Source/Charts/Renderers/BubbleChartRenderer.swift:11,14,16,19,21,23,25,27,28,30,35,39,46,47,49,51,52,56,57,63,69,70,73,75,77,79,81,83,85,90,92,95,97,102,104,106,110,113,119,121,123,130,133,136,144,145,147,148,149,150,152,159,162,164,166,168,173,175,177,180,182,184,186,188,192,194,199,205,209,211,220,221,223,229,230,231,232,233,235,236,237,238,240,245,248,250,252,259,261,266,268,270,275,279,282,288,290,292,297,299,306,310,312,313,314,317,319,321,324,325,333,336,339,344,349,352,354,356,358,359 ./Source/Charts/Renderers/LineChartRenderer.swift:11,14,16,22,24,26,28,30,31,33,35,37,39,41,43,45,46,48,49,50,51,53,55,57,58,60,63,65,67,69,70,72,75,79,82,85,86,88,89,91,93,95,97,99,102,104,107,109,111,116,120,122,128,130,133,135,139,142,144,149,161,162,163,165,167,170,172,173,178,180,181,183,185,187,189,191,194,197,199,201,204,206,209,211,214,216,228,229,230,232,234,237,239,240,245,247,248,255,259,261,263,264,266,271,275,277,279,281,283,284,285,287,289,291,293,295,299,301,303,306,308,309,311,313,316,317,319,321,323,326,328,333,335,337,341,343,345,346,348,350,351,353,355,356,358,360,361,367,372,374,375,379,380,382,383,385,387,393,395,397,399,401,402,403,406,410,412,414,417,420,421,424,426,428,431,432,434,435,439,441,443,445,446,448,453,455,457,459,461,463,468,470,472,475,477,480,482,484,485,487,489,491,495,497,499,500,502,504,505,519,520,522,528,529,530,531,532,533,535,537,538,540,545,547,549,552,556,563,564,566,568,570,572,574,575,578,580,585,592,594,596,600,602,604,605,608,610,611,612,616,618,619,628,635,636,638,639,641,646,648,652,659,662,664,666,668,670,676,678,679,680,681,682,684,688,689,691,696,698,700,702,706,708,710,712,713,717,719,721,723,724,727,729,731,732,734,736,738,741,742,744,745,749,751,753,756,757,766,769,772,777,782,785,787,789,791,792 ./Source/Charts/Renderers/AxisRendererBase.swift:11,14,17,20,23,25,27,30,31,34,36,37,40,42,43,46,48,49,52,54,55,62,64,66,69,72,74,77,79,82,83,84,85,87,88,91,93,96,99,101,105,106,110,114,116,117,122,126,127,129,132,134,138,140,142,145,146,148,150,152,154,156,158,159,161,163,165,167,168,170,172,173,177,181,183,186,187,189,192,193,194,197,199,201,203,204,206,209,211,213,215,216,217,218 ./Source/Charts/Renderers/ChartDataRendererBase.swift:11,14,18,22,25,34,36,38,40,42,43,45,47,48,50,52,53,55,57,58,64,66,67,71,73,76,77,88,93,99,101,102 ./Source/Charts/Renderers/YAxisRenderer.swift:11,14,18,22,25,27,29,30,33,35,37,39,40,43,46,48,50,52,54,57,59,62,63,64,66,68,71,73,76,77,78,85,86,88,90,92,94,95,97,101,103,105,107,108,110,115,117,122,123,125,126,134,138,141,144,146,148,150,158,159,160,162,166,168,170,171,173,175,179,184,186,188,189,191,193,194,197,198,200,203,204,205,207,213,214,218,223,224,226,231,234,236,238,240,241,243,245,246,249,255,258,263,266,268,270,272,274,276,277,281,282,284,289,291,293,295,296,298,300,302,304,306,308,310,311,314,319,323,327,331,333,335,337,338,340,342,345,347,350,352,360,362,370,372,380,382,390,391,392,393,395,396 ./Source/Charts/Renderers/ScatterChartRenderer.swift:11,14,16,18,20,22,24,25,27,29,32,39,40,45,47,49,51,53,54,56,57,58,59,61,63,65,67,69,71,73,75,77,79,81,83,87,89,91,92,95,97,98,100,101,103,105,107,108,109,111,116,119,121,123,125,127,133,135,138,140,143,145,147,149,153,155,157,158,162,164,165,171,173,183,184,186,192,193,194,195,196,197,199,200,201,202,204,209,211,213,218,220,222,226,228,230,232,233,236,238,240,242,245,246,248,249 ./Source/Charts/Renderers/CombinedChartRenderer.swift:11,14,16,18,21,24,26,28,30,32,34,36,37,40,42,44,46,48,51,53,55,58,60,62,65,67,69,72,74,76,79,81,83,84,85,86,87,89,91,92,94,97,106,107,112,113,115,117,118,120,122,123,125,127,129,131,133,135,137,139,141,143,145,147,149,150,157,159,161,162,163,166,168,170,172,174,175,176,179,182,183,185,188,191,196,198,200,202,204,206,207,208,209 ./Source/Charts/Renderers/CandleStickChartRenderer.swift:11,14,16,18,20,22,24,25,27,29,32,39,40,42,44,45,46,53,55,59,61,65,67,69,71,73,76,78,83,91,93,95,100,102,107,109,114,116,121,122,124,126,129,131,133,135,137,139,141,142,143,145,147,148,151,153,158,160,162,164,166,168,170,173,175,178,179,181,183,185,187,190,192,195,196,198,200,203,204,206,211,216,221,225,228,230,233,235,238,240,242,243,248,249,256,257,259,260,261,264,266,267,269,274,277,279,281,283,285,290,292,294,297,299,301,304,306,308,312,314,316,317,319,321,322,324,337,338,340,346,347,348,349,350,351,353,354,355,357,362,364,366,371,373,375,377,378,380,383,385,387,389,391,392,396,398,400,403,404,406,407,412,414,417,419,420 ./Source/Charts/Renderers/BarChartRenderer.swift:11,14,18,22,24,46,48,50,51,53,55,57,59,60,63,65,67,70,72,74,76,78,79,80,82,86,88,89,90,92,94,95,96,98,103,105,109,115,116,118,120,122,125,127,136,173,176,179,181,183,185,186,188,191,193,195,197,198,200,205,206,210,214,216,218,220,221,228,230,234,237,239,241,245,247,251,253,257,258,267,271,276,279,280,281,282,283,285,290,294,301,302,305,307,309,311,313,314,316,317,318,322,323,325,327,329,331,334,338,340,343,345,349,351,353,355,358,360,362,364,365,367,369,370,373,376,377,378,380,383,385,387,389,391,392,394,396,397,400,401,402,404,406,408,409,413,415,417,419,421,422,424,426,427,429,432,433,435,437,441,442,445,453,454,456,457,458,460,461,469,474,479,481,482,484,487,492,494,499,501,506,508,514,516,519,520,522,524,526,528,530,533,535,537,539,541,543,545,546,549,551,552,554,556,571,572,574,579,582,589,590,591,593,595,597,599,601,603,605,607,610,612,614,615,618,620,621,623,637,638,640,644,647,654,655,657,659,662,665,667,670,672,675,677,680,682,685,686,688,689,691,693,697,699,701,702,704,706,707,709,722,723,725,732,733,734,735,737,738,739,740,741,742,745,747,748,750,751,752,753,755,760,762,764,766,771,773,775,777,778,780,783,785,788,790,792,795,797,799,802,803,805,808,809,811,813,815,816,817,819,820,823,825,826,830,832,835,838,839,849,852,855,860,866,868,870,877,878,881,887,892,893,894,897,899,901,903,904 ./Source/Charts/Renderers/XAxisRenderer.swift:11,14,18,22,25,27,29,30,32,34,36,40,43,45,48,50,53,54,55,56,58,59,61,63,65,66,68,72,74,76,79,81,86,87,89,91,93,95,96,98,100,102,104,106,108,110,112,114,116,119,120,121,123,125,127,129,131,132,134,138,140,142,144,145,149,155,156,160,166,167,169,170,173,178,181,188,190,192,194,196,198,200,201,203,205,207,209,211,213,214,217,219,221,223,225,228,230,233,235,236,238,241,242,243,252,253,254,255,265,274,275,277,282,284,286,287,291,296,298,300,302,304,305,307,309,311,313,317,319,320,321,323,329,330,332,335,340,341,342,344,350,352,354,356,359,364,368,371,372,373,375,376,380,384,386,388,390,391,393,394,396,397,400,402,408,417,424,431,438,439,447,448 ./Source/Charts/Renderers/LineRadarRenderer.swift:11,14,17,19,21,22,25,26,30,33,35,37,38,41,45,48,51,53,54 ./Source/Charts/Renderers/BarLineScatterCandleBubbleRenderer.swift:11,14,17,19,21,23,24,27,30,31,37,39,40,43,45,46,49,52,55,58,60,61,62,63,67,69,70,75,77,80,83,87,88,89,90,94,96,97,100,101,102,106,109,110,113,114,115,118,119,120,122,124,126,127 ./Source/Charts/Renderers/Scatter/XShapeRenderer.swift:13,15,22,25,28,35,36 ./Source/Charts/Renderers/Scatter/SquareShapeRenderer.swift:13,15,22,30,32,41,43,50,51,53,61,62,63 ./Source/Charts/Renderers/Scatter/ChevronDownShapeRenderer.swift:13,15,22,25,28,35,36 ./Source/Charts/Renderers/Scatter/IShapeRenderer.swift:11,14,17,32 ./Source/Charts/Renderers/Scatter/CircleShapeRenderer.swift:13,15,22,30,32,41,43,50,51,53,61,62,63 ./Source/Charts/Renderers/Scatter/CrossShapeRenderer.swift:13,15,22,25,28,35,36 ./Source/Charts/Renderers/Scatter/TriangleShapeRenderer.swift:13,15,22,29,31,37,39,41,46,47,49,51,53,55,62,64,65,66 ./Source/Charts/Renderers/Scatter/ChevronUpShapeRenderer.swift:13,15,22,25,28,35,36 ./Source/Charts/Renderers/XAxisRendererHorizontalBarChart.swift:11,14,16,18,20,22,24,25,27,29,31,35,38,40,43,45,48,49,50,51,53,54,56,60,62,64,68,73,74,76,80,82,84,85,87,89,91,93,95,97,99,101,103,105,108,109,110,113,118,122,124,127,129,131,133,135,137,139,141,142,144,146,148,157,158,159,160,161,170,178,179,181,187,188,190,192,194,199,200,201,203,205,207,209,210,212,216,218,220,222,223,227,232,233,237,242,243,245,246,248,253,255,257,259,260,262,264,266,268,270,272,273,276,281,285,289,293,295,297,299,300,302,304,307,309,312,314,322,324,332,334,342,344,352,353,354,355,356 ./Source/Charts/Renderers/HorizontalBarChartRenderer.swift:11,14,18,22,24,26,28,29,31,33,34,37,39,41,44,46,48,50,52,53,54,56,60,62,63,64,66,68,69,70,72,77,79,83,89,91,93,95,98,100,109,112,114,116,118,119,124,127,129,133,136,138,140,144,146,150,152,156,157,166,170,175,178,179,180,181,182,184,186,188,190,193,197,199,202,204,208,210,212,214,217,219,221,223,224,226,228,229,232,235,236,237,239,241,243,245,246,250,252,254,256,258,259,261,263,264,266,269,270,272,274,278,279,282,290,291,293,294,295,297,298,306,311,316,318,319,321,324,329,331,333,338,340,345,347,350,352,354,356,358,360,363,365,367,369,371,373,375,376,378,380,381,383,385,386,393,398,400,403,404,406,416,417,419,423,426,433,434,435,437,439,441,443,445,447,449,452,454,456,457,459,461,462,464,466,467,474,479,481,484,485,487,497,498,500,504,507,514,515,517,520,523,525,528,530,533,535,538,540,543,544,546,547,549,551,558,563,565,568,569,571,574,576,578,579,581,583,584,586,588,589,591,599,600,602,609,610,611,612,614,615,616,617,618,619,621,625,626,629,631,632 ./Source/Charts/Renderers/XAxisRendererRadarChart.swift:11,14,16,18,20,22,24,25,27,32,34,36,37,42,44,47,49,51,52,54,56,58,66,67,68,77,85,86,88,90,91 ./Source/Charts/Renderers/YAxisRendererRadarChart.swift:11,14,18,22,24,26,28,30,32,33,35,39,42,44,48,49,53,57,59,60,64,66,70,71,74,77,79,83,85,87,90,91,93,95,97,99,101,103,104,106,108,110,112,113,114,116,120,124,126,129,130,132,135,136,137,140,142,144,146,147,149,152,154,156,158,159,160,164,165,167,172,174,176,177,180,183,185,188,191,193,195,197,199,209,210,211,213,219,221,223,225,226,228,230,233,235,237,239,241,243,244,248,250,252,254,255,257,259,261,263,265,267,269,271,272,273,275,277,278,280,281 ./Source/Charts/Renderers/PieChartRenderer.swift:11,14,18,22,24,26,28,30,32,33,35,37,39,41,44,47,49,50,51,52,61,63,67,71,76,82,85,90,92,93,96,101,104,108,110,111,113,115,118,121,128,131,134,136,137,138,140,142,152,159,161,164,166,168,172,173,176,179,181,182,184,186,193,195,196,199,201,204,206,209,211,221,223,225,226,233,235,237,242,244,246,248,250,260,263,268,270,272,273,274,276,280,286,287,289,290,293,295,296,298,303,305,311,314,316,318,320,321,323,325,327,330,333,336,338,340,342,344,346,347,349,352,356,358,360,363,365,367,369,371,372,376,379,381,383,390,393,398,401,403,407,411,413,415,417,419,421,422,426,430,434,436,440,442,446,447,449,451,453,455,457,459,461,463,467,469,470,472,480,482,492,493,495,497,507,508,510,518,519,520,522,526,528,536,538,548,549,551,553,563,564,566,574,575,576,578,580,584,590,591,593,594,595,596,598,601,602,605,607,609,611,615,617,619,623,624,625,628,631,634,638,652,653,654,656,657,658,661,666,668,672,675,682,684,686,687,689,694,696,701,703,705,706,707,709,714,716,719,722,729,732,734,738,740,741,743,745,749,752,754,755,756,758,760,762,764,765,767,770,773,775,777,781,785,789,791,792,796,798,799,801,804,807,810,819,820,823,825,828,830,832,833,840,842,844,849,853,855,857,859,862,867,869,871,872,873,875,879,886,887,889,890,895,896,898,899,906,908,912,918,926,928,929,935,938,940,941 ./Source/Charts/Renderers/Renderer.swift:11,14,17,20,22,25,26 ./Source/Charts/Renderers/LineScatterCandleRadarRenderer.swift:11,14,17,19,21,22,29,30,33,38,39,42,47,48,49 ./Source/Charts/Highlight/BarHighlighter.swift:11,14,17,19,24,26,29,34,36,38,39,40,42,44,45,47,49,50,63,68,71,73,74,79,84,92,93,99,106,107,108 ./Source/Charts/Highlight/RadarHighlighter.swift:11,14,17,19,21,23,25,28,30,33,36,37,38,40,41,47,49,54,59,61,66,68,71,74,75,77,78 ./Source/Charts/Highlight/Highlight.swift:11,14,17,20,23,26,29,32,35,40,43,46,49,51,53,54,71,73,82,83,98,104,105,120,122,129,130,137,142,143,149,152,153,161,163,166,169,170,173,176,177,179,181,183,184,185,186,191,193,195,196,202,203 ./Source/Charts/Highlight/PieHighlighter.swift:11,14,17,19,24,26,27 ./Source/Charts/Highlight/HorizontalBarHighlighter.swift:11,14,17,19,21,24,27,32,33,35,36,42,44,47,50,51,56,57,58,60,62,63 ./Source/Charts/Highlight/PieRadarHighlighter.swift:11,14,17,19,21,23,26,29,30,32,34,36,37,39,42,44,46,48,49,50,51,58,60,61 ./Source/Charts/Highlight/Range.swift:11,13,16,19,21,24,26,27,32,34,36,38,40,41,42,44,46,47,49,51,52 ./Source/Charts/Highlight/ChartHighlighter.swift:11,14,16,19,21,23,24,26,29,30,35,37,40,41,48,50,53,56,58,60,62,63,71,73,75,77,82,83,87,88,90,91,98,100,103,106,107,111,113,114,115,117,125,128,130,132,134,136,139,140,141,142,144,145,153,155,158,160,161,162,164,165,167,169,170,172,174,175,177,179,180 ./Source/Charts/Highlight/IHighlighter.swift:11,14,17,23 ./Source/Charts/Highlight/CombinedHighlighter.swift:11,14,17,20,22,24,27,28,30,32,37,39,41,45,48,50,52,56,58,60,63,64,65,66,67,69,70 ./Source/Charts/Charts/CandleStickChartView.swift:11,14,17,19,21,23,26,27,29,31,33,34 ./Source/Charts/Charts/RadarChartView.swift:11,14,15,19,22,25,28,31,34,37,40,43,46,48,50,51,53,55,56,58,60,63,65,68,70,71,73,75,77,80,81,83,85,88,92,94,95,97,99,100,102,104,106,109,111,113,114,116,118,120,121,123,125,126,128,130,132,133,135,137,138,140,142,144,146,148,149,152,156,157,160,162,163,165,168,170,175,176,179,181,182,186,188,190,192,194,195,196,198,200,201,203,205,206,208,211,212,215,218,221 ./Source/Charts/Charts/BarLineChartViewBase.swift:11,14,18,22,25,29,32,37,40,43,46,49,53,56,61,64,68,72,76,80,84,87,91,98,101,103,105,106,108,110,111,113,115,116,118,120,123,125,130,132,136,139,146,147,149,153,156,157,160,163,166,168,170,171,172,174,176,178,181,184,185,187,189,190,192,194,195,197,199,200,202,204,205,209,212,216,217,219,221,222,224,226,227,229,231,232,237,239,242,246,247,250,252,253,255,257,259,261,262,264,266,267,269,271,272,276,278,281,283,285,287,289,290,292,294,296,297,300,303,306,308,310,312,314,316,317,319,321,322,324,325,327,330,331,333,336,337,339,341,343,346,348,353,355,357,358,359,361,363,364,366,369,373,374,376,379,381,383,385,388,391,393,395,398,401,404,405,406,408,410,413,416,419,420,421,422,423,425,427,432,437,440,442,443,445,447,448,450,452,455,457,459,461,463,466,467,468,473,479,480,483,484,487,489,491,492,494,498,499,501,505,506,508,510,511,512,514,516,520,521,528,530,534,536,538,540,541,543,545,547,549,552,554,557,558,559,560,562,564,566,567,569,571,574,576,578,580,582,583,586,589,590,591,592,595,597,599,602,604,606,608,610,613,615,617,619,621,622,623,624,627,629,631,635,636,638,642,644,648,651,653,655,657,659,660,663,667,669,671,673,675,676,677,679,680,681,683,685,687,689,691,693,694,699,701,703,706,708,710,712,713,715,718,720,724,725,727,729,732,733,734,736,738,740,742,743,745,747,750,752,754,756,758,759,761,763,765,767,769,771,774,775,776,778,780,782,784,787,790,791,793,795,796,798,801,802,803,804,806,808,810,812,814,816,818,819,820,822,825,827,829,831,832,835,836,838,842,843,845,847,850,851,852,854,856,859,861,866,868,872,873,875,877,879,883,884,885,887,889,895,897,898,900,903,905,907,908,910,911,913,914,917,919,921,922,924,926,929,931,933,935,939,941,943,947,950,952,953,958,960,961,963,965,967,968,971,972,974,976,978,979,980,982,983,985,988,990,993,997,998,1001,1003,1006,1010,1011,1014,1017,1021,1022,1036,1039,1043,1044,1060,1071,1072,1084,1092,1093,1112,1116,1133,1135,1136,1155,1157,1158,1176,1178,1179,1182,1185,1188,1189,1192,1195,1196,1198,1200,1201,1208,1211,1212,1219,1222,1223,1231,1237,1238,1245,1248,1249,1256,1259,1260,1268,1272,1273,1277,1284,1286,1287,1295,1297,1304,1306,1307,1316,1318,1325,1327,1328,1344,1348,1350,1361,1363,1364,1380,1382,1383,1398,1400,1401,1413,1416,1423,1425,1426,1441,1445,1448,1459,1461,1462,1477,1479,1480,1494,1496,1497,1501,1503,1505,1509,1511,1515,1516,1517,1520,1523,1524,1526,1529,1531,1533,1535,1537,1538,1539,1542,1544,1546,1548,1549,1552,1554,1556,1558,1561,1562,1563,1566,1568,1569,1572,1574,1576,1578,1580,1581,1582,1585,1587,1589,1591,1593,1594,1595,1598,1600,1606,1607,1608,1610,1612,1614,1616,1618,1623,1624,1625,1626,1628,1630,1632,1634,1636,1641,1642,1643,1644,1647,1650,1652,1654,1656,1658,1661,1662,1663,1664,1668,1670,1671,1674,1680,1682,1683,1687,1689,1690,1694,1696,1697,1703,1705,1706,1710,1712,1713,1716,1718,1720,1722,1723,1726,1729,1731,1733,1734,1737,1739,1741,1743,1744,1747,1749,1751,1753,1754,1757,1761,1763,1765,1767,1769,1770,1771,1774,1776,1778,1780,1782,1787,1788,1789,1790,1794,1798,1800,1801,1805,1807,1808,1811,1813,1815,1816,1818,1820,1821,1824,1826,1827,1831,1834,1835,1839,1842,1844,1846,1848,1850,1851,1852,1857,1859,1861,1863,1865,1866,1870,1872,1874,1876,1878,1879,1880,1887,1889,1891,1893,1895,1896,1897,1900,1902,1904,1906,1908,1909,1910,1912,1917,1919,1921,1923,1925,1926,1927,1930,1932,1934,1936,1938,1939,1940,1942,1944,1945,1948,1952,1954,1956,1957,1960,1964,1966,1968,1969 ./Source/Charts/Charts/LineChartView.swift:11,14,17,19,21,23,24,26,28 ./Source/Charts/Charts/CombinedChartView.swift:11,14,17,20,24,30,31,33,35,37,40,42,44,45,47,49,51,53,55,57,60,61,62,64,66,68,70,73,75,76,77,78,81,83,86,87,90,92,101,102,104,106,108,110,111,112,114,116,118,120,121,122,124,126,128,130,131,132,134,136,138,140,141,142,144,146,148,150,151,152,154,156,158,160,161,162,164,167,170,171,174,177,178,181,184,189,191,193,195,197,198,199,202,205,207,210,215,217,219,224,227,229,230,232,235,237,238,241,244,245,246 ./Source/Charts/Charts/HorizontalBarChartView.swift:11,14,17,19,21,24,29,31,32,34,40,43,46,49,52,54,56,59,62,65,66,67,70,73,76,78,79,82,85,87,90,91,92,93,95,100,105,108,110,111,113,115,116,118,120,123,125,127,129,131,134,135,136,141,147,150,151,153,156,157,159,161,162,164,169,172,174,179,181,183,185,186,188,190,192,194,195,197,199,202,203,205,206,209,213,215,217,218,221,225,227,229,230,232,234,237,238,240,243,244,246,250,251,253,256,257,259,262,263,265,269,270 ./Source/Charts/Charts/ChartViewBase.swift:12,15,19,23,26,33,36,39,42,45,48,49,51,53,58,60,61,64,67,70,73,77,80,83,87,90,93,96,99,102,105,107,110,112,115,118,121,124,128,132,135,137,140,143,146,149,151,156,157,159,161,164,165,167,170,171,173,176,177,179,183,186,188,190,193,195,198,199,201,204,206,208,210,213,215,218,219,222,224,226,228,229,230,233,234,235,238,243,245,246,249,252,253,256,258,260,262,264,266,267,268,272,274,275,278,280,281,284,286,287,290,293,295,297,299,303,304,305,307,310,313,314,315,317,320,322,324,327,332,344,346,347,349,352,353,354,357,365,368,370,373,380,381,383,386,387,389,392,394,395,400,403,404,407,409,410,415,417,418,424,427,429,431,433,435,436,439,440,450,452,453,464,466,467,477,479,480,491,493,496,497,499,501,503,505,506,507,514,516,517,520,523,525,528,530,534,537,539,541,542,543,545,547,550,552,554,555,556,559,560,565,567,570,571,573,574,577,579,582,589,591,593,598,601,603,604,606,609,611,612,615,618,619,620,623,625,626,628,631,633,634,644,646,647,657,659,660,669,671,672,681,683,684,692,694,695,703,705,706,714,716,717,724,726,727,735,737,738,746,748,749,756,758,759,761,764,766,767,770,772,773,775,777,778,780,782,783,785,787,788,792,795,796,799,801,802,805,807,808,811,813,814,817,819,820,824,826,827,830,832,835,837,839,843,845,848,849,850,852,854,856,858,859,861,864,865,877,879,882,885,886,888,890,892,894,896,897,899,900,902,904,906,908,912,914,918,921,924,925,926,927,928,930,932,934,935,936,938,940,941,943,945,947,949,951,952,953,957,959,960,966,968,970,972,975,977,979,981,982,984,985,986,990,993,995,996,998,1000,1002,1003,1005,1007,1008,1010,1012,1014,1016,1017,1018,1020,1022,1024,1025,1026,1028,1030,1032,1033,1034,1036,1038,1040,1041,1042 ./Source/Charts/Charts/BubbleChartView.swift:11,14,16,18,20,22,23,25,27 ./Source/Charts/Charts/PieRadarChartViewBase.swift:11,15,19,20,23,26,29,32,35,38,43,45,47,48,50,52,53,55,57,58,60,62,64,66,72,73,75,77,78,80,82,84,85,86,88,90,92,94,95,97,99,100,102,107,109,111,113,115,117,120,122,125,127,129,132,135,137,143,146,149,152,154,156,159,160,161,162,164,167,170,172,174,177,180,183,184,185,187,189,192,197,201,202,204,206,208,210,212,215,216,217,222,223,228,230,232,234,236,238,239,240,245,247,248,252,254,259,261,263,265,266,269,272,274,275,277,278,282,285,286,289,291,293,296,298,300,302,304,305,307,309,311,313,314,317,319,320,324,326,327,333,335,337,339,343,344,345,349,351,352,355,362,363,366,368,369,372,374,375,379,381,382,384,386,387,389,391,392,394,403,405,407,409,414,415,416,425,427,428,430,432,435,437,439,440,444,446,448,449,451,453,454,456,458,459,461,463,465,466,467,469,473,475,478,479,481,485,487,489,491,493,494,496,498,499,501,503,505,506,513,515,517,520,521,522,524,526,528,530,532,534,538,539,540,541,543,545,547,548,549,552,555,557,559,561,562,563,565,567,568,569,571,573,576,577,579,581,582,583,585,587,589,590,592,595,596,598,600,601,602,604,606,608,610,613,616,618,620,622,623,625,627,628,629,631,633,635,637,638,640,642,643,644,646,648,650,651,653,655,657,658,660,662,663,665,667,669,670,672,678,681,684,686,690,692,694,695,697,698,700,701,703,707,711,717,725,728,730,732,734,735,739,740,743,745,748,749,752,754,755,757,759,762,763,764,766,768,770,772,774,776,778,780,781,782,785,789,790,793,797,798,801,803,805,807,809,812,813,814,817,819,821,823,824,826,828,831,833,835,838,840,842,844,846,850,851,852,853,855 ./Source/Charts/Charts/BarChartView.swift:11,14,17,20,23,25,27,29,31,34,35,37,40,42,46,48,50,51,59,60,63,65,68,69,72,74,83,84,87,92,95,97,102,104,106,108,109,119,122,125,126,129,130,138,140,141,143,146,149,152,153,154,157,160,163,164,165,169,173,176,178,180,183,186 ./Source/Charts/Charts/ScatterChartView.swift:11,14,17,19,21,23,26,27,29,31 ./Source/Charts/Charts/PieChartView.swift:11,14,18,22,25,28,31,34,37,40,42,45,48,51,54,57,60,65,67,70,73,75,78,80,82,83,85,87,88,90,92,95,97,98,100,102,104,106,107,110,112,113,115,117,119,120,122,124,126,128,130,131,134,136,137,140,142,143,146,150,151,153,155,158,160,161,163,165,167,173,174,175,177,179,180,182,184,189,191,193,195,196,199,202,204,205,207,208,211,213,215,218,220,222,224,226,227,229,231,233,235,236,239,241,242,244,247,249,251,253,254,256,258,260,263,267,269,270,273,276,278,280,283,285,287,289,291,293,295,297,299,301,303,304,306,307,308,309,312,314,315,318,320,321,324,326,327,330,332,333,335,340,341,344,349,350,355,357,358,362,364,365,370,372,374,376,379,380,381,386,388,390,392,395,396,397,400,402,403,406,408,410,412,415,416,417,420,422,424,425,426,429,431,433,435,438,440,442,446,453,455,456,457,460,462,464,466,469,470,471,474,476,478,480,483,484,485,488,490,492,494,497,498,499,502,504,506,507,508,510,512,513,515,517,518,520,522,523,526,528,529,532,534,535,540,542,544,546,549,550,551,556,558,560,562,565,566,567,572,574,576,578,581,582,583,586,589,592,593,594,597,600,603,604,605,608,610,612,614,617,618,619,622,624,626,627,628,631,633,635,637,640,641,642,645,647,649,650,651,654,656,658,660,663,664,665,670,672,674,676,678,680,682,683,685,687,688,689,690 ./Source/Charts/Animation/ChartAnimationEasing.swift:11,14,17,49,50,52,54,56,119,120,121,123,125,129,130,134,135,139,141,142,144,145,149,150,155,156,160,162,165,166,170,171,176,177,181,183,186,187,191,192,197,198,202,204,206,209,210,211,215,216,220,221,225,226,229,230,233,234,237,239,241,243,244,247,249,250,253,254,258,259,264,265,269,271,274,275,278,280,281,284,286,287,292,293,296,298,299,302,304,305,309,310,313,315,316,319,321,322,326,329,332,333,338,339,345,346,351,354,358,359,362,363,367,369,371,374,376,379,381,384,385,386,389,391,393,394 ./Source/Charts/Animation/Animator.swift:11,15,18,21,24,25,28,32,35,38,42,45,49,52,55,57,59,60,62,64,65,67,69,72,75,78,81,84,85,88,89,91,93,98,100,101,103,104,106,111,113,114,116,117,118,120,122,124,127,129,131,132,133,143,145,155,158,161,163,166,167,168,178,180,181,190,192,193,202,204,205,213,219,221,224,227,230,231,232,240,242,243,251,257,259,262,265,268,269,270,278,280,281 ./Source/Charts/Formatters/IAxisValueFormatter.swift:11,13,17,18,29,30 ./Source/Charts/Formatters/DefaultFillFormatter.swift:11,14,18,22,24,26,28,30,31,33,35,36,40,43,45,47,49,52,54,55,57,58 ./Source/Charts/Formatters/DefaultValueFormatter.swift:11,13,16,22,24,26,29,32,35,36,37,40,43,45,47,51,52,53,54,56,58,61,62,64,66,68,69,71,73,78,79,81,83,85,86,88,90,91,96,101,102,103 ./Source/Charts/Formatters/DefaultAxisValueFormatter.swift:11,13,16,20,22,24,27,30,33,34,35,39,42,44,46,50,51,52,53,55,57,60,61,63,65,67,68,70,72,77,78,80,82,84,85,87,89,90,93,98,99,100 ./Source/Charts/Formatters/IndexAxisValueFormatter.swift:11,13,17,20,22,24,26,28,31,32,33,35,37,38,39,41,43,45,46,48,50,51,54,58,59 ./Source/Charts/Formatters/IFillFormatter.swift:11,14,18,21 ./Source/Charts/Formatters/IValueFormatter.swift:11,13,18,21,22,36 ./Source/Charts/Utils/Fill.swift:11,14,17,25,26,29,40,42,44,46,47,49,51,52,54,56,57,59,61,62,64,66,67,69,71,72,74,76,77,79,81,82,84,86,87,89,91,92,94,96,97,98,100,103,104,106,108,109,111,115,116,124,131,132,134,142,143,145,148,149,151,153,154,156,158,159,161,163,164,166,169,170,172,174,176,177,179,181,182,186,188,189,197,205,206,208,210,211,213,215,216,218,220,221,223,225,226,228,230,231,233,235,236,238,243,246,248,249,251,253,255,258,260,263,265,268,270,273,275,288,295,297,300,315,318,319,321,322,323 ./Source/Charts/Utils/Transformer.swift:11,14,18,21,24,26,28,30,31,34,37,39,41,43,45,46,51,52,55,57,59,61,64,65,66,70,73,74,76,78,79,81,83,84,87,89,90,93,100,102,103,106,108,109,112,118,120,121,124,127,128,131,134,135,138,140,141,146,148,149,154,156,157,159,164,165,167,169,170 ./Source/Charts/Utils/Platform+Touch Handling.swift:11,14,17,21,23,24,26,28,29,31,33,34,36,38,39,41,43,44,46,48,49,51,53,54,56,58,59,60,62,64,66,67,69,70,73,76,79,81,83,84,86,88,89,91,93,94,96,98,99,101,103,104,106,108,109,111,113,114,116,118,119,120,122,125,132,133 ./Source/Charts/Utils/ViewPortHandler.swift:11,14,18,21,24,27,30,33,36,39,42,45,48,51,54,57,60,62,64,65,67,72,75,77,78,80,82,84,86,88,89,90,92,97,98,100,102,103,105,107,108,110,112,113,115,117,118,120,122,123,125,127,128,130,132,133,135,137,138,140,142,143,145,147,148,150,152,153,155,157,158,160,162,163,165,167,168,170,173,175,176,179,184,185,188,190,191,194,196,197,200,202,203,206,211,212,215,223,224,227,230,232,233,236,239,241,243,244,249,252,255,256,259,261,264,266,268,269,272,275,278,279,282,284,287,288,291,294,299,300,303,305,307,309,310,312,314,315,318,320,322,324,325,327,329,330,333,336,338,340,342,344,345,348,350,351,354,356,358,360,361,363,365,366,369,371,373,375,376,378,380,381,383,385,387,389,390,392,394,395,398,400,401,403,405,406,408,410,412,413,415,417,418,421,426,428,429,431,433,434,436,438,439,441,444,445,447,449,450,452,455,456,459,461,464,470,475,480,484,489,492,495,498,501,502,505,507,508,511,513,514,517,519,520,523,525,526,529,531,532,535,537,538,541,543,544,547,549,550,553,555,556,559,561,562,565,567,568,571,573,574,577,579,580,583,585,586,589,591,592,595,597,598,601,603,604,607,609,610 ./Source/Charts/Utils/Platform+Gestures.swift:11,15,21,23,25,27,28,30,32,34,36,38,39,40,41,43,45,47,48,50,52,53,54,58,60,62,65,66,67,69,71,73,75,77,79,80,81,83,85,86,89,93,101,104,106,108,109,111,113,115,117,119,120,121,122,124,126,128,129,132,134,135,136,138,141,143,144,146,149,150,151,153,155,157,159,161,163,164,165,168,170,171 ./Source/Charts/Utils/Platform+Graphics.swift:11,13,15,16,18,20,21,23,25,26,30,32,34,35,37,39,40,42,44,45,47,49,50,52,54,55,57,59,60,62,64,65,67,69,71,75,77,79,80,82,86,87,89,91,92,94,99,100,102,107,108,110,112,115,117,118,121,123,125,127,130,134,135,136,138,140,143,146,150,151,153,154,156,158,161,162 ./Source/Charts/Utils/Platform+Accessibility.swift:11,13,18,20,22,23,25,27,28,31,33,35,37,39,40,41,43,45,47,48,49,51,55,56,58,60,62,63,65,68,69,70,71,73,77,79,80,82,85,86,88,90,91,93,95,96,98,102,103,104,106,108,112,114,117,118,120,122,123,126,128,130,132,134,135,136,138,140,142,143,144,146,148,150,151,153,155,156,157,159,161,163,164,166,168,170,173,186,187,188,190,193,195,198,199,200,203,205,207,208,210,212,213,214 ./Source/Charts/Utils/Platform.swift:2,10,16,18,20,22,23,24,26,28,31,32,33,35,37,39,40,41,43,47,52,55,59,62,64,66,67,69,72,74,75,77,79,82,85,87,89,90,91,93,95,96,98,100,102,104,106,107,108,110,112,113,115,117,119,121,123,124,125,126,128,130,132,133,134,136,138,141,142,143,145,150,152,155,156,158,161,162,164,166,167,169,171,172,173,175,177,181,183,186,187,188,190,192,193,194,196,198,201,202,203,205,207,209,210,211,213,215,217,218,219,221,224,226,228,230,231,232,233,234,236,238,240 ./Source/Charts/Utils/ChartColorTemplates.swift:11,14,16,18,26,27,29,37,38,40,48,49,51,59,60,62,70,71,73,80,81,83,86,88,90,96,99,101,104,107,111,113,115,118,121,122,124,125,126,128,130,151,153,174,176,194,195,197,198 ./Source/Charts/Utils/TransformerHorizontalBarChart.swift:11,14,17,20,22,24,26,30,31,32 ./Source/Charts/Utils/Platform+Color.swift:11,14,17,19,21,23,25,26,28,30,32,34,36,38,41,43,45,47,49,50,52,54,56 ./Source/Charts/Utils/ChartUtils.swift:11,14,18,22,24,26,28,30,32,34,36,38,39,40,41,43,45,47,48,50,52,53,57,60,61,62,64,66,69,70,72,77,78,79,81,84,90,96,97,99,105,107,112,114,115,116,118,121,124,125,126,128,130,137,141,143,145,147,151,154,156,159,162,163,165,167,169,170,172,173,175,177,179,181,183,185,186,188,190,192,193,195,197,199,201,203,207,209,212,214,217,218,222,224,226,228,230,232,235,236,239,241,242,244,245,247,249,251,253,257,259,262,264,267,268,272,274,276,278,280,283,284,287,289,290,292,293,295,298,299,301,304,305,308,310,311 ./Source/Charts/Components/Description.swift:11,14,18,22,25,27,36,38,39,42,45,48,51,54 ./Source/Charts/Components/IMarker.swift:11,14,17,22,29,36,39 ./Source/Charts/Components/MarkerImage.swift:11,14,17,20,22,24,27,29,31,32,34,36,38,40,42,44,46,48,49,52,54,56,58,60,61,63,65,67,69,70,72,73,75,77,78,80,82,84,86,88,90,92,94,95,101,105,106 ./Source/Charts/Components/Legend.swift:11,14,17,20,23,26,29,32,35,38,39,42,46,47,50,54,55,58,61,62,65,68,69,72,76,81,84,87,90,93,96,99,102,105,108,111,116,123,128,132,134,136,139,140,142,144,146,147,149,152,154,156,159,161,162,165,167,169,171,173,175,176,177,182,183,188,195,198,205,207,217,220,222,224,229,231,233,238,240,242,243,245,247,249,251,252,254,256,258,260,262,267,268,271,273,276,278,280,281,282,284,285,288,290,292,294,297,299,300,302,304,305,307,309,315,317,321,323,325,328,330,333,334,337,341,343,346,348,351,352,353,355,357,361,364,366,367,371,375,376,378,381,382,383,385,386,390,391,394,395,397,403,406,407,410,412,413,417,419,420 ./Source/Charts/Components/LegendEntry.swift:11,14,17,19,21,22,39,47,48,52,59,64,69,76,85,88 ./Source/Charts/Components/YAxis.swift:11,14,18,22,23,29,32,35,36,40,43,44,47,50,53,56,59,62,65,70,73,76,79,82,85,88,93,99,101,103,105,106,108,110,112,114,115,117,119,120,122,129,130,132,134,135,138,140,142,144,146,147,148,150,152,156,160,162,171,172,173,176,179,182,183,186,189,190,193,196,197,200,201,203,205,206 ./Source/Charts/Components/AxisBase.swift:11,14,18,20,22,23,26,29,34,40,43,46,48,52,55,56,58,60,61,64,69,74,77,80,83,86,91,94,100,102,108,110,112,114,116,119,120,121,124,126,128,129,130,133,135,137,139,141,143,145,146,147,149,150,153,155,157,158,160,161,166,168,170,172,176,178,179,181,183,185,186,187,189,191,193,198,203,206,209,212,215,220,225,228,232,233,237,238,245,247,249,251,254,256,257,258,260,263,264,267,270,272,273,276,279,280,283,285,286,289,291,292,294,297,299,300,302,305,307,308,310,315,317,319,321,325,326,327,332,334,336,338,342,343,344,351,355,358,361,364,365,368,371,372 ./Source/Charts/Components/XAxis.swift:11,14,17,20,26,27,30,33,36,39,42,45,48,54,57,63,65,67,69,70,72,74,75 ./Source/Charts/Components/ChartLimitLine.swift:11,14,15,19,22,27,28,31,36,39,43,45,47,48,50,53,54,56,60,61,64,66,68,70,72,73,74 ./Source/Charts/Components/MarkerView.swift:11,14,18,21,23,25,27,29,31,34,36,38,40,42,43,45,47,49,51,52,54,55,57,59,60,62,64,72,73,76,78,84,87,92,94,95,98,99,100 ./Source/Charts/Components/ComponentBase.swift:11,14,15,19,22,26,30,32,34,35,37 ./Source/Charts/Jobs/AnimatedZoomViewJob.swift:11,14,16,25,42,52,61,62,64,70,73,76,79,84,86,89,90,92,95,96 ./Source/Charts/Jobs/ViewPortJob.swift:11,14,18,25,32,34,40,41,43,45,46 ./Source/Charts/Jobs/MoveViewJob.swift:11,14,17,19,25,30,33,34 ./Source/Charts/Jobs/ZoomViewJob.swift:11,14,17,21,31,38,42,43,45,51,54,57,62,64,67,70,71 ./Source/Charts/Jobs/AnimatedViewPortJob.swift:11,15,17,21,26,28,39,45,50,51,53,55,56,58,60,61,63,67,69,72,73,75,77,80,82,84,87,88,90,91,92,94,98,100,102,103,105,107,109,111,113,115,116,117,119,121,122,124,126,127 ./Source/Charts/Jobs/AnimatedMoveViewJob.swift:11,14,16,18,24,29,32,33 ./Source/Charts/Data/Implementations/Standard/ChartData.swift:11,13,15,24,26,28,30,32,33,35,37,39,41,42,44,46,47,49,51,52,56,58,59,61,65,66,69,74,76,81,84,86,89,91,93,95,97,98,100,102,103,104,105,106,109,111,114,116,118,120,122,123,125,127,128,129,130,131,132,135,137,139,140,142,144,145,147,149,150,152,154,155,157,159,161,162,164,166,167,169,171,173,174,176,178,179,180,181,184,186,188,189,191,193,194,196,198,199,201,203,204,206,208,210,211,213,215,216,218,220,222,223,225,227,228,229,230,233,235,236,239,241,242,245,247,248,250,252,254,256,258,260,261,263,265,267,269,271,272,273,274,277,279,280,283,285,286,288,290,292,294,296,298,299,301,303,305,307,309,310,311,312,315,317,320,322,323,326,328,330,332,335,336,337,348,351,354,356,359,360,361,368,370,372,374,376,377,378,386,388,390,392,394,396,397,398,400,402,404,405,407,408,410,412,414,415,421,424,425,431,433,435,436,438,440,442,443,446,448,450,452,454,456,458,459,460,463,466,468,469,472,474,476,477,479,480,486,488,490,491,493,495,496,498,499,502,504,505,508,511,512,515,517,518,521,523,524,527,530,531,534,536,537,540,542,543,546,548,549,552,554,555,559,562,563,566,570,573,574,579,581,582,585,587,588,591,593,594,596,601,606,610 ./Source/Charts/Data/Implementations/Standard/BarChartDataEntry.swift:11,13,15,18,21,24,27,29,31,32,35,37,38,41,44,45,48,51,52,55,59,60,63,68,69,72,75,76,79,82,83,86,90,91,93,95,97,98,101,103,106,107,109,110,113,115,116,119,121,122,124,127,129,131,133,135,136,143,145,147,149,151,153,154,156,159,161,163,166,168,171,172,173,174,176,179,182,185,190,191,192,195,197,198,200,202,209,210,217,220,222,224,226,227,229,230 ./Source/Charts/Data/Implementations/Standard/BarChartDataSet.swift:11,14,15,17,19,21,24,25,27,30,31,33,36,37,39,43,46,50,52,54,56,58,60,62,63,64,65,68,70,72,74,76,77,78,79,80,82,85,87,89,91,93,94,96,98,99,101,103,105,106,108,110,111,112,114,115,116,119,121,122,125,127,128,131,133,134,137,139,142,145,148,151,153,155,160,166,167 ./Source/Charts/Data/Implementations/Standard/RadarChartDataEntry.swift:11,14,16,18,20,21,25,27,28,33,36,37,39,41,44,45,47,49,51,53,54 ./Source/Charts/Data/Implementations/Standard/BarLineScatterCandleBubbleChartDataSet.swift:11,14,15,17,19,21,26,28,30,37,38 ./Source/Charts/Data/Implementations/Standard/PieChartDataEntry.swift:11,14,16,18,20,21,22,26,28,29,34,37,38,44,46,47,53,57,58,65,70,71,76,79,80,85,88,89,95,99,100,102,104,106,109,110,112,114,118,119 ./Source/Charts/Data/Implementations/Standard/CandleChartDataEntry.swift:11,13,15,18,21,24,27,29,31,32,34,36,41,42,44,47,48,50,53,54,56,60,61,64,66,67,70,72,73,76,78,80,82,84,85,86,88,90,97,98 ./Source/Charts/Data/Implementations/Standard/CombinedChartData.swift:11,13,15,21,23,25,26,28,30,31,33,35,37,39,42,43,44,46,48,50,52,55,56,57,59,61,63,65,68,69,70,72,74,76,78,81,82,83,85,87,89,91,94,95,96,98,100,105,110,112,114,116,119,121,123,124,126,128,129,131,133,134,136,138,139,141,143,145,147,149,151,152,154,156,158,160,162,163,164,165,166,167,170,172,174,176,178,180,182,184,186,188,190,192,193,195,196,198,200,201,203,205,206,208,210,211,213,216,217,219,222,223,225,228,229,231,233,235,237,239,241,243,245,247,249,251,252,254,255,262,264,266,267,269,271,273,274,278,279,286,288,290,291,293,295,297,298,300,301 ./Source/Charts/Data/Implementations/Standard/LineChartData.swift:11,13,16,18,20,21,23,25,26 ./Source/Charts/Data/Implementations/Standard/RadarChartData.swift:11,14,15,17,22,25,28,30,31,33,35,36,38,40,41,43,45,46 ./Source/Charts/Data/Implementations/Standard/CandleChartDataSet.swift:11,14,15,17,18,20,22,23,25,27,28,30,32,35,37,39,40,42,44,45,47,48,50,53,55,57,59,61,62,64,66,68,70,71,72,74,79,83,85,87,89,91,92,93,99,104,107,110,113,116,119,122,126,129,133,136 ./Source/Charts/Data/Implementations/Standard/LineRadarChartDataSet.swift:11,14,15,17,19,21,24,27,30,33,34,35,39,43,45,50,52,54,56,58,59,60,65,68,70,71,73,75,83,84,85 ./Source/Charts/Data/Implementations/Standard/BarLineScatterCandleBubbleChartData.swift:11,13,15,17,19,20,22,24,25 ./Source/Charts/Data/Implementations/Standard/BubbleChartDataEntry.swift:11,14,16,19,21,23,24,30,32,34,35,42,45,46,53,56,57,65,69,70,72,74,78,79 ./Source/Charts/Data/Implementations/Standard/ChartDataEntryBase.swift:11,13,15,18,21,24,26,28,29,35,37,39,40,44,46,48,50,51,55,57,59,61,62,67,69,71,74,75,77,79,81,82,83,88,90,92,93,95,96 ./Source/Charts/Data/Implementations/Standard/ChartDataEntry.swift:11,13,15,18,20,22,23,30,33,34,41,43,46,47,54,56,59,60,68,70,74,75,77,79,81,82,84,86,88,92,94,95,96,101,103,105,106,109,110 ./Source/Charts/Data/Implementations/Standard/PieChartDataSet.swift:11,14,16,19,22,23,25,28,29,31,34,35,37,40,41,43,45,46,48,50,55,57,59,61,64,66,68,70,72,73,74,77,80,83,86,89,92,95,98,101,104,107,110,113,115,117,134,135 ./Source/Charts/Data/Implementations/Standard/BubbleChartData.swift:11,14,16,18,20,21,23,25,26,29,31,32 ./Source/Charts/Data/Implementations/Standard/ChartDataSet.swift:11,13,17,21,22,26,28,30,32,33,35,37,38,40,42,44,46,47,49,51,52,54,61,64,74,75,78,81,84,87,89,94,96,98,99,101,104,106,109,113,114,116,118,120,122,124,125,126,128,130,132,134,136,137,138,144,147,148,151,154,157,160,164,170,173,175,176,188,191,193,195,196,206,208,209,213,215,218,220,223,226,228,230,231,233,236,239,241,243,245,246,248,249,251,253,255,257,259,261,262,263,264,266,267,278,282,284,286,290,292,296,298,302,304,306,308,311,313,316,317,318,320,321,323,325,327,330,332,333,335,338,340,341,342,345,347,349,350,353,355,358,360,363,366,367,368,370,371,372,374,375,381,383,384,394,397,398,407,409,411,414,416,418,420,422,423,425,426,429,431,432,440,444,445,451,454,455,461,464,465,469,471,472,474,476,478,480,486,488,489,490,495,498,499,502,503,506,507,514,518,519,520,521,526,527,528,534,535,540,541,546,547,551,552,557,558,562,563,567,568,573,574 ./Source/Charts/Data/Implementations/Standard/ScatterChartDataSet.swift:11,14,16,17,20,28,29,32,36,40,44,46,47,52,54,56,64,65,66,68,70,77,78 ./Source/Charts/Data/Implementations/Standard/ScatterChartData.swift:11,14,16,18,20,21,23,25,26,29,33,34 ./Source/Charts/Data/Implementations/Standard/PieChartData.swift:11,13,15,17,19,20,22,24,25,28,30,33,35,37,38,39,41,43,45,47,49,51,53,55,56,57,58,60,62,64,66,67,69,71,73,74,76,78,80,81,83,85,87,88,90,91,93,95,96,98,100,101,107,109,111,112,114,115,118,122,123,124 ./Source/Charts/Data/Implementations/Standard/CandleChartData.swift:11,13,15,17,19,20,22,24,25 ./Source/Charts/Data/Implementations/Standard/LineChartDataSet.swift:11,14,15,17,20,25,26,28,31,32,34,37,38,40,43,44,46,48,53,55,60,62,64,66,68,69,70,73,76,78,82,86,88,90,91,95,98,99,101,104,105,108,110,111,114,117,120,123,126,129,134,137,140,143,145,147,149,151,152,153,155,157,172,173 ./Source/Charts/Data/Implementations/Standard/BubbleChartDataSet.swift:11,14,15,17,19,21,25,27,30,32,34,36,38,39,40,42,45,47,49,57,58 ./Source/Charts/Data/Implementations/Standard/RadarChartDataSet.swift:11,14,15,17,19,21,22,24,27,28,30,33,34,36,38,42,45,47,51,53,55,57,59 ./Source/Charts/Data/Implementations/Standard/BarChartData.swift:11,14,16,18,20,21,23,25,26,31,41,44,47,48,51,55,57,59,61,64,68,70,72,74,75,76,79,80,85,88,90,91,92,93,95,96,103,105,106,107 ./Source/Charts/Data/Implementations/Standard/LineScatterCandleRadarChartDataSet.swift:11,13,14,16,18,20,23,26,29,32,36,39,40,42,44,49,50,51 ./Source/Charts/Data/Implementations/ChartBaseDataSet.swift:11,14,15,17,19,21,25,26,28,30,34,36,37,39,42,44,45,47,49,50,52,54,55,57,59,60,62,64,65,67,69,70,72,74,75,77,79,80,82,84,85,90,92,93,97,99,100,102,104,105,110,112,113,115,117,118,120,122,123,125,127,128,130,132,133,135,137,139,141,142,144,146,148,150,151,153,155,157,159,160,162,163,165,167,169,171,172,174,175,177,179,180,182,184,185,187,191,194,197,200,204,207,209,211,212,215,217,218,224,226,227,234,237,238,245,247,248,255,257,258,265,267,268,271,274,277,280,282,284,286,287,289,291,293,295,296,297,299,301,302,307,309,311,313,316,317,318,321,324,326,328,329,332,335,340,345,350,357,362,365,367,368,373,376,378,379,386,389,392,394,395,397,399,401,402,404,407,408,409,411,413,415,432,434,435 ./Source/Charts/Data/Interfaces/IPieChartDataSet.swift:11,14,17,19,24,27,30,33,36,39,42,45,48,51,54,57,60,63,64 ./Source/Charts/Data/Interfaces/IScatterChartDataSet.swift:11,14,17,19,21,24,29,33,36 ./Source/Charts/Data/Interfaces/ILineChartDataSet.swift:11,14,15,18,20,22,27,32,35,38,40,44,48,51,54,57,60,63,66,69,74,77,80 ./Source/Charts/Data/Interfaces/IRadarChartDataSet.swift:11,14,17,19,21,24,26,28,32,34,36,38,40 ./Source/Charts/Data/Interfaces/IBarChartDataSet.swift:11,14,17,19,21,24,27,30,33,36,39,42 ./Source/Charts/Data/Interfaces/ILineRadarChartDataSet.swift:11,14,17,19,21,24,28,32,37,42,45 ./Source/Charts/Data/Interfaces/IChartDataSet.swift:11,14,17,19,22,25,29,32,35,38,41,44,49,61,71,75,86,91,102,115,124,133,142,149,156,161,166,168,171,174,177,181,185,187,189,191,194,197,200,203,208,211,214,219,224,229,234,241,246,249,254,257,264,267,270 ./Source/Charts/Data/Interfaces/ICandleChartDataSet.swift:11,14,17,19,21,25,31,36,39,42,45,48,51,54,57,60,63,66 ./Source/Charts/Data/Interfaces/ILineScatterCandleRadarChartDataSet.swift:11,13,16,18,20,23,26,29,32,36 ./Source/Charts/Data/Interfaces/IBubbleChartDataSet.swift:11,14,17,19,22,24,27 ./Source/Charts/Data/Interfaces/IBarLineScatterCandleBubbleChartDataSet.swift:11,14,17,19,21,26 ./Source/Charts/Interfaces/BarChartDataProvider.swift:11,14,17,19,23 ./Source/Charts/Interfaces/ChartDataProvider.swift:11,14,17,20,23,26,29,31,33,35,37,39 ./Source/Charts/Interfaces/CandleChartDataProvider.swift:11,14,17,19 ./Source/Charts/Interfaces/CombinedChartDataProvider.swift:11,14,17,19 ./Source/Charts/Interfaces/LineChartDataProvider.swift:11,14,17,19,21 ./Source/Charts/Interfaces/BarLineScatterCandleBubbleChartDataProvider.swift:11,14,17,20,23 ./Source/Charts/Interfaces/ScatterChartDataProvider.swift:11,14,17,19 ./Source/Charts/Interfaces/BubbleChartDataProvider.swift:11,14,17,19 ./Source/Supporting Files/Charts.h:11,13,19,22,25,27,28 ./Tests/Charts/EquatableTests.swift:7,10,17,19,20,27,29,30,34,36,37,41,43,44,45 ./Tests/Charts/Snapshot.swift:3,5,7,18,20,21,22,24,26,28,29 ./Tests/Charts/PieChartTests.swift:4,6,7,10,12,14,17,20,22,24,26,27,31,38,43,44,46,49,50,52,54,55,57,60,61,63,66,67,69,72,73,75,79,80,82,86,87 ./Tests/Charts/LineChartTests.swift:4,6,7,10,12,14,17,22,24,26,28,29,33,39,40,42,45,46,48,50,51,53,56,57,59,62,63,65,68,69,71,74,75,77,80,81 ./Tests/Charts/HorizontalBarChartTests.swift:7,11,13,14,16,20,21,23,26,27,30,33,35,37,38,40,48,49,51,56,57,59,64,65,67,77,78,80,83,88,89,92,97,98,100,107,108,110,117,118,120,126,127,129,136,137,139,146,147 ./Tests/Charts/BarChartTests.swift:4,6,8,10,13,14,16,19,20,23,26,28,30,31,33,38,39,41,46,47,49,54,55,57,60,61,63,71,72,74,84,85,87,92,93,95,98,103,104,107,112,113,114,116,122,123,125,130,131,133,138,139,141,149,150,152,159,160,162,169,170,172,179,180,182,191,192,194,199,200,202,209,210,212,219,220,221,223,230,231,233,240,241,243,252,253,255,262,263,265,272,273,275,281,282,284,291,292,294,301,302,304,311,312,314,321,322,324,331,332,334,341,342,344,351,352,354,362,363,365,373,374,376,384,385,387,395,396,398,405,406,408,415,416 ./Tests/Charts/ChartUtilsTests.swift:3,5,9,10,14,15,17,19,22,24,25,27,29,32,34,35,37,39,42,44,45,47,49,52,54,55,57,59,62,64,65,67,69,72,74,75 ./Tests/Charts/CombinedChartTests.swift:7,11,13,17,19,21,24,34,35,37,41,43,45,47,48,51,55,56,58,62,64,66,68,69,73,74,76,79,80,82,84,85,87,93,94,96,102,103,104 ./ChartsDemo-macOS/PlaygroundChart.playground/Pages/Menu.xcplaygroundpage/Contents.swift:11,13,14,16,18,20,22,24,26,28,30,32,34,36,37,40 ./ChartsDemo-macOS/PlaygroundChart.playground/Pages/HorizontalBarChart.xcplaygroundpage/Contents.swift:13,17,22,23,67,75,78,82,87,93,98 ./ChartsDemo-macOS/PlaygroundChart.playground/Pages/BarChart.xcplaygroundpage/Contents.swift:10,14,18,25,26,29,41,43,49,55 ./ChartsDemo-macOS/PlaygroundChart.playground/Pages/StackedBarChart.xcplaygroundpage/Contents.swift:13,17,22,23,78,81,82,87,94,101,112 ./ChartsDemo-macOS/PlaygroundChart.playground/Pages/ScatterChart.xcplaygroundpage/Contents.swift:13,17,22,52,56,58,65,71,78,83,92,94,98,103,104 ./ChartsDemo-macOS/PlaygroundChart.playground/Pages/CombinedChart.xcplaygroundpage/Contents.swift:13,17,22,23,25,31,34,38,40,57,60,64,66,72,79,90,102,105,106,137,140,144,149,150 ./ChartsDemo-macOS/PlaygroundChart.playground/Pages/RadarChart.xcplaygroundpage/Contents.swift:13,17,22,63,70,73,83,98,100,104,105,110,111 ./ChartsDemo-macOS/PlaygroundChart.playground/Pages/PieChart.xcplaygroundpage/Contents.swift:13,17,22,23,30,35,48,50 ./ChartsDemo-macOS/PlaygroundChart.playground/Pages/BubbleChart.xcplaygroundpage/Contents.swift:13,17,22,24,54,58,70,78,82 ./ChartsDemo-macOS/PlaygroundChart.playground/Pages/CandleChart.xcplaygroundpage/Contents.swift:13,17,22,23,25,27,28,29,31,32,61,63,71,73,77,95,96 ./ChartsDemo-macOS/PlaygroundChart.playground/Pages/LineChart.xcplaygroundpage/Contents.swift:13,17,22,23,24,75,77,82,83,88,89,94,95,99,111,112,124,136,146,152,153 ./ChartsDemo-macOS/ChartsDemo-macOS/AppDelegate.swift:2,5,6,7 ./ChartsDemo-macOS/ChartsDemo-macOS/Demos/RadarDemoViewController.swift:10,14,16,18,20,22,26,29,34,40,41,42,44,46,47 ./ChartsDemo-macOS/ChartsDemo-macOS/Demos/PieDemoViewController.swift:10,14,16,18,20,22,25,27,30,32,34,42,44,46,48,49,51,53,54 ./ChartsDemo-macOS/ChartsDemo-macOS/Demos/BarDemoViewController.swift:10,14,16,18,20,22,27,30,35,39,43,49,51,53,55,56,58,63,65,67,68,69,70,71,73,75,76 ./ChartsDemo-macOS/ChartsDemo-macOS/Demos/LineDemoViewController.swift:10,14,16,18,20,22,26,29,34,39,41,43,44,46,48,49 ./Carthage/Checkouts/ios-snapshot-test-case/FBSnapshotTestCaseDemo/FBSnapshotTestCaseDemo/FBAppDelegate.h:9,11,13,15 ./Carthage/Checkouts/ios-snapshot-test-case/FBSnapshotTestCaseDemo/FBSnapshotTestCaseDemo/main.m:9,11,13,15,18,19 ./Carthage/Checkouts/ios-snapshot-test-case/FBSnapshotTestCaseDemo/FBSnapshotTestCaseDemo/FBAppDelegate.m:9,11,13,15,23,24,26,29,30,32,35,36,38,40,41,43,45,46,48,50,51 ./Carthage/Checkouts/ios-snapshot-test-case/FBSnapshotTestCaseDemo/FBSnapshotTestCaseDemoTests/FBSnapshotTestCaseDemoTests.m:9,11,13,15,17,19,25,26,28,33,34,36,43,48,51,52,53,55,60,63,64,66,68,71,81,84,85,87,89,93,94 ./Carthage/Checkouts/ios-snapshot-test-case/FBSnapshotTestCaseDemo/FBSnapshotTestCaseDemoTests/FBSnapshotTestCaseSwiftTests.swift:9,11,16,17,23,24 ./Carthage/Checkouts/ios-snapshot-test-case/iOSSnapshotTestCaseCarthageDemo/iOSSnapshotTestCaseCarthageDemoSwiftTests/iOSSnapshotTestCaseCarthageDemoSwiftTests.swift:8,11,13,17,18,24,25 ./Carthage/Checkouts/ios-snapshot-test-case/iOSSnapshotTestCaseCarthageDemo/iOSSnapshotTestCaseCarthageDemo/AppDelegate.swift:8,10,13,15,18,20,21,22,25,29,31,32,36,37,41,42,45,46,49,50,53,54,55,56 ./Carthage/Checkouts/ios-snapshot-test-case/SnapshotTest.xctemplate/___FILEBASENAME___.m:8,11,15,17,19,21,23,25,26,28,31,32,34,36,39,40 ./Carthage/Checkouts/ios-snapshot-test-case/FBSnapshotTestCase/FBSnapshotTestCasePlatform.m:9,12,14,20,21,23,28,29,30,32,36,37,42,43,47,48,54,58,59,61 ./Carthage/Checkouts/ios-snapshot-test-case/FBSnapshotTestCase/FBSnapshotTestCase.h:9,12,14,16,18,21,33,36,47,57,68,71,72,83,93,96,102,103,109,110,112,116,118,122,126,129,133,138,141,143,145,147,150,152,155,159,166,170,173,190,209,226,245,262,281,292,295,297,301,304,306,310,312 ./Carthage/Checkouts/ios-snapshot-test-case/FBSnapshotTestCase/FBSnapshotTestController.m:9,15,18,24,31,34,35,37,39,43,45,47,48,50,52,54,55,57,62,69,70,75,82,83,89,96,97,98,105,110,111,112,116,133,134,136,137,142,148,149,155,159,160,165,175,177,178,184,186,190,193,196,201,204,208,217,219,220,223,224,228,231,232,236,238,241,242,246,248,249,251,255,270,274,275,279,280,283,284,287,294,295,299,303,307,308,315,324,325,327,329,330,335,337,343,345,346,351,365,367,371,379,380,381,383,384,386,392,397,399,400 ./Carthage/Checkouts/ios-snapshot-test-case/FBSnapshotTestCase/SwiftSupport.swift:9,13,14,17,18,24,35,43,46,47,49,52,53,55,56,57,61,62,63 ./Carthage/Checkouts/ios-snapshot-test-case/FBSnapshotTestCase/FBSnapshotTestCase.m:9,12,15,16,18,20,23,24,26,29,30,32,34,35,37,40,41,43,45,46,48,51,52,54,56,57,59,62,63,65,67,68,70,72,73,75,82,90,91,99,102,103,107,108,112,113,116,117,120,126,127,134,143,146,147,148,153,154,155,156,163,171,172,180,188,189,196,204,205,213,221,222,226,232,234,235,237,241,244,246,247,249,253,256,258,259,261,269,278,279 ./Carthage/Checkouts/ios-snapshot-test-case/FBSnapshotTestCase/FBSnapshotTestCasePlatform.h:9,11,15,17,20,34,39,43,47,51,54,60,62,64 ./Carthage/Checkouts/ios-snapshot-test-case/FBSnapshotTestCase/Categories/UIImage+Diff.h:30,32,34,36,38,40 ./Carthage/Checkouts/ios-snapshot-test-case/FBSnapshotTestCase/Categories/UIImage+Snapshot.m:9,11,13,15,19,27,31,32,34,37,38,40,46,47,51,52,54,58,60,64,67,68,70,71 ./Carthage/Checkouts/ios-snapshot-test-case/FBSnapshotTestCase/Categories/UIImage+Compare.m:30,32,44,46,48,50,53,59,64,65,80,87,88,91,94,98,110,111,114,116,117,121,126,127,136,141,143,144,147,152,153,159,167,171,172,173,176,178,179 ./Carthage/Checkouts/ios-snapshot-test-case/FBSnapshotTestCase/Categories/UIImage+Diff.m:30,32,34,36,39,54,55 ./Carthage/Checkouts/ios-snapshot-test-case/FBSnapshotTestCase/Categories/UIImage+Compare.h:30,32,34,36,39,46,48 ./Carthage/Checkouts/ios-snapshot-test-case/FBSnapshotTestCase/Categories/UIImage+Snapshot.h:9,11,13,15,18,21,24,26 ./Carthage/Checkouts/ios-snapshot-test-case/FBSnapshotTestCase/FBSnapshotTestController.h:9,12,14,16,24,29,34,39,44,49,56,61,64,66,68,70,74,79,84,89,94,100,113,126,141,158,169,182,197,213 ./Carthage/Checkouts/ios-snapshot-test-case/FBSnapshotTestCaseTests/FBSnapshotControllerTests.m:9,13,15,17,19,21,23,28,34,35,37,42,49,50,52,57,65,66,68,73,80,81,83,88,96,97,99,104,111,121,124,125,126,128,133,135,139,149,153,154,156,161,169,170,172,177,184,185,187,189,194,195 ./Carthage/Build/tvOS/FBSnapshotTestCase.framework/Headers/FBSnapshotTestCase-Swift.h:4,17,21,27,49,64,122,127,131,185,187,195,202,203,204 ./Carthage/Build/tvOS/FBSnapshotTestCase.framework/Headers/FBSnapshotTestCase.h:9,12,14,16,18,21,33,36,47,57,68,71,72,83,93,96,102,103,109,110,112,116,118,122,126,129,133,138,141,143,145,147,150,152,155,159,166,170,173,190,209,226,245,262,281,292,295,297,301,304,306,310,312 ./Carthage/Build/tvOS/FBSnapshotTestCase.framework/Headers/FBSnapshotTestCasePlatform.h:9,11,15,17,20,34,39,43,47,51,54,60,62,64 ./Carthage/Build/tvOS/FBSnapshotTestCase.framework/Headers/FBSnapshotTestController.h:9,12,14,16,24,29,34,39,44,49,56,61,64,66,68,70,74,79,84,89,94,100,113,126,141,158,169,182,197,213 ./ChartsDemo-iOS/Supporting Files/main.m:11,14,18,19 ./ChartsDemo-iOS/Supporting Files/ChartsDemo-Bridging-Header.h:4 ./ChartsDemo-iOS/Swift/Formatters/IntAxisValueFormatter.swift:8,11,15,16 ./ChartsDemo-iOS/Swift/Formatters/DayAxisValueFormatter.swift:8,11,18,21,22,27,30,37,43,44,46,47,48,58,59,61,64,67,68,69,73,78,79,82,83,85,86,90,95,96,98,99,107,108,109 ./ChartsDemo-iOS/Swift/Formatters/DateValueFormatter.swift:8,11,14,18,19,22,23 ./ChartsDemo-iOS/Swift/Formatters/LargeValueFormatter.swift:6,9,11,13,15,20,23,26,27,32,36,37,39,42,43,45,46,49,50,57,58 ./ChartsDemo-iOS/Swift/Components/XYMarkerView.swift:8,14,18,25,26,33,34,35 ./ChartsDemo-iOS/Swift/Components/RadarMarkerView.swift:11,17,20,24,25,29,30 ./ChartsDemo-iOS/Swift/DemoListViewController.swift:8,12,17,18,20,92,95,99,100,101,102,106,107,110,111,118,120,121,124,127,130,131 ./ChartsDemo-iOS/Swift/DemoBaseViewController.swift:8,13,50,88,89,90,91,99,102,104,108,109,113,114,117,118,120,126,128,132,134,138,141,144,147,150,155,160,164,169,170,174,175,176,182,183,188,190,192,194,202,210,218,221,230,231,234,235,243,245,249,258,263,273,274,277,278,281,285,287,290,292,297,298,301,302,304,305,306,308,309,310,311,316,317,319,320,325,326,328,329,330,334,335,337,338,342,348,350,352,353,357,360,362,363,364,365,366 ./ChartsDemo-iOS/Swift/AppDelegate.swift:8,12,15,17,21,22,25,28,30,31,35,36,40,41,44,45,48,49,52,53,54,55,56 ./ChartsDemo-iOS/Swift/Demos/MultipleLinesChartViewController.swift:8,13,15,21,24,40,42,44,48,51,58,62,63,68,69,71,72,76,80,90,92,93,97,101,102,108,110,114,116,120,122,126,128,131,132,133,137,139,140 ./ChartsDemo-iOS/Swift/Demos/MultipleBarChartViewController.swift:8,13,15,21,24,27,38,40,42,45,50,61,67,70,76,78,82,83,88,89,91,92,98,103,106,111,114,117,120,123,127,130,133,136,138,140,141,144,145,150,153,155,156 ./ChartsDemo-iOS/Swift/Demos/HalfPieChartViewController.swift:8,13,15,17,20,23,35,37,39,45,49,59,63,65,67,68,73,74,76,77,83,84,89,91,98,101,103,105,106,112,116,120,124,127,130,133,139,142,143,144 ./ChartsDemo-iOS/Swift/Demos/LineChartTimeViewController.swift:8,13,18,21,38,40,42,47,49,51,61,71,72,74,76,79,81,82,87,88,90,91,95,98,102,103,114,118,120,121,127,129,133,135,139,141,145,147,151,153,156,157,158,162,163 ./ChartsDemo-iOS/Swift/Demos/ColoredLineChartViewController.swift:8,13,16,19,21,26,30,32,33,34,37,40,42,47,49,55,57,59,60,65,66,68,76,78,79 ./ChartsDemo-iOS/Swift/Demos/LineChart2ViewController.swift:8,13,15,21,24,41,43,48,57,62,69,75,79,81,82,87,88,90,91,97,101,105,106,117,128,139,143,145,146,152,154,158,160,164,166,170,172,176,178,181,182,183,187,189,195,201,202 ./ChartsDemo-iOS/Swift/Demos/LineChart1ViewController.swift:8,13,15,21,24,42,44,49,56,59,65,71,80,82,85,93,95,99,101,102,107,108,110,111,116,117,120,132,136,140,142,144,145,151,153,157,159,163,165,169,171,175,177,180,181,182,186,188,189 ./ChartsDemo-iOS/Swift/Demos/NegativeStackedBarChartViewController.swift:8,13,15,17,27,30,44,45,47,49,52,61,72,81,83,84,89,90,92,93,107,117,120,123,124,127,128,129,133,134 ./ChartsDemo-iOS/Swift/Demos/ScatterChartViewController.swift:8,13,15,21,24,36,38,40,45,53,57,59,60,63,67,68,73,74,76,77,82,86,90,91,92,97,104,109,112,114,115,118,119,123,125,126 ./ChartsDemo-iOS/Swift/Demos/StackedBarChartViewController.swift:8,13,15,21,27,30,33,47,48,50,52,57,61,63,66,76,80,82,83,88,89,91,92,99,101,102,107,112,115,116,119,120,124,126,127 ./ChartsDemo-iOS/Swift/Demos/BubbleChartViewController.swift:8,13,15,21,24,37,39,41,46,52,57,59,62,66,67,72,73,75,76,82,87,92,93,98,104,108,114,116,117,120,121,126,128,129 ./ChartsDemo-iOS/Swift/Demos/LineChartFilledViewController.swift:8,13,15,21,24,27,29,33,35,37,41,43,45,50,52,56,57,62,63,65,66,71,75,76,90,91,105,106,109,111,112,116,118,119 ./ChartsDemo-iOS/Swift/Demos/PositiveNegativeBarChartViewController.swift:8,13,15,17,23,26,39,41,43,45,48,50,52,62,71,73,74,79,80,82,83,91,96,97,101,104,109,111,112,115,116,117,121,122 ./ChartsDemo-iOS/Swift/Demos/AnotherBarChartViewController.swift:8,13,15,21,24,27,37,39,44,47,49,53,54,55,60,61,63,64,70,71,82,86,87,89,90,93,94,99,101,102 ./ChartsDemo-iOS/Swift/Demos/PieChartViewController.swift:8,13,15,21,24,27,40,42,44,53,57,61,63,64,69,70,72,73,80,81,85,86,93,95,102,105,108,109,115,119,123,127,130,133,136,142,145,146,147,152,154,155 ./ChartsDemo-iOS/Swift/Demos/CubicLineChartViewController.swift:8,13,17,18,19,21,27,30,33,48,50,53,58,60,67,70,74,76,77,82,83,85,86,92,93,105,109,111,112,118,120,124,126,130,132,136,138,142,144,147,148,149,154,156,157 ./ChartsDemo-iOS/Swift/Demos/RadarChartViewController.swift:8,13,15,17,22,25,41,43,50,54,61,68,79,81,83,84,87,93,97,98,99,102,108,109,110,115,116,118,119,124,128,137,146,151,153,154,162,166,169,173,174,176,180,182,185,188,191,194,197,198,199,200,204,205 ./ChartsDemo-iOS/Swift/Demos/HorizontalBarChartViewController.swift:8,13,15,21,24,38,40,42,45,47,53,59,65,76,78,82,84,85,90,91,93,94,98,103,104,107,111,113,114,117,118,123,125,126 ./ChartsDemo-iOS/Swift/Demos/PiePolylineChartViewController.swift:8,11,13,19,22,25,37,39,41,44,48,50,51,56,57,59,60,66,67,70,71,78,84,86,95,98,99,105,109,113,117,120,123,126,132,135,136,137,142,144,145 ./ChartsDemo-iOS/Swift/Demos/CombinedChartViewController.swift:8,16,18,21,26,27,30,39,41,43,46,47,53,61,64,67,73,75,76,81,82,84,85,93,95,97,98,105,106,107,109,114,115,117,123,126,127,128,132,133,145,147,149,150,154,157,158,164,173,178,181,184,186,187,191,192,198,200,201,205,206,213,215,216,222,223,229,231,232,233,237,238 ./ChartsDemo-iOS/Swift/Demos/BarChartViewController.swift:8,16,18,24,27,30,40,42,44,47,49,56,62,70,78,89,98,102,103,108,109,111,112,115,123,124,125,136,141,142,144,145,148,149,154,156,157 ./ChartsDemo-iOS/Swift/Demos/SinusBarChartViewController.swift:8,13,15,19,22,34,36,38,42,46,53,59,70,73,75,76,81,82,84,85,89,90,93,98,100,101,104,105,109,110 ./ChartsDemo-iOS/Swift/Demos/CandleStickChartViewController.swift:8,13,15,21,24,39,41,43,48,54,59,61,64,68,69,74,75,77,78,88,90,91,103,106,107,113,118,122,123,124,129 ./ChartsDemo-iOS/Objective-C/DemoBaseViewController.m:11,13,15,17,19,21,23,26,28,30,31,33,36,38,40,41,43,45,53,54,56,59,60,62,65,66,68,69,70,71,73,75,77,79,81,82,84,85,87,89,91,92,94,95,97,100,101,103,105,106,108,110,111,113,115,116,118,120,121,123,126,128,129,131,134,136,137,139,142,143,145,147,149,151,152,153,155,156,157,159,161,163,167,168,174,176,178,180,182,184,186,188,192,193,195,197,199,201,202,204,205,207,209,211,212,214,215,217,219,221,222,224,225,227,232,234,236,237,239,241,243,245,248,249,251,252,253,255,257,259,260,262,269,271,275,290,295,304,305,307,309,310,312,314,316,320,322,325,327,328 ./ChartsDemo-iOS/Objective-C/AppDelegate.h:11,13,15,17,18,20 ./ChartsDemo-iOS/Objective-C/DemoListViewController.m:11,36,38,42,44,46,48,50,148,154,160,166,170,173,174,176,179,180,182,184,186,187,189,191,192,194,196,197,199,201,204,206,207,211,213,214,216,218,221,223,225,226 ./ChartsDemo-iOS/Objective-C/Formatters/DayAxisValueFormatter.h:6,9,11,13 ./ChartsDemo-iOS/Objective-C/Formatters/DateValueFormatter.m:11,12,14,16,18,20,22,24,27,30,32,33,35,37,38 ./ChartsDemo-iOS/Objective-C/Formatters/IntAxisValueFormatter.m:6,8,10,11,12,15,17,18 ./ChartsDemo-iOS/Objective-C/Formatters/DayAxisValueFormatter.m:6,8,10,13,14,16,19,21,28,30,31,34,38,41,43,45,47,49,51,53,75,76,78,79,80,82,84,86,88,90,92,94,96,97,99,100,102,104,105,107,108,110,113,115,117,120,123,124,126,127,128,130,133,135,139,140,142,143,145,147,149,151,153,155,157,159,161,162,164,165 ./ChartsDemo-iOS/Objective-C/Formatters/IntAxisValueFormatter.h:6,9,11 ./ChartsDemo-iOS/Objective-C/Formatters/DateValueFormatter.h:11,14,16 ./ChartsDemo-iOS/Objective-C/Formatters/LargeValueFormatter.swift:6,9,11,13,18,21,23,24,25,26,28,30,31,33,37,39,42,43,45,47,49,50,52,53,56,58,59,65,67,68 ./ChartsDemo-iOS/Objective-C/Components/XYMarkerView.swift:6,12,14,17,20,25,26,28,30,31,32 ./ChartsDemo-iOS/Objective-C/Components/BalloonMarker.swift:11,17,19,26,31,33,38,42,43,45,48,50,52,54,56,57,61,65,67,69,72,74,75,77,79,82,84,85,87,88,90,92,95,103,105,107,109,137,139,167,168,173,174,176,178,180,182,184,185,187,189,190,192,194,199,201,208,209 ./ChartsDemo-iOS/Objective-C/Components/RadarMarkerView.swift:11,17,19,21,23,26,27,29,32,33 ./ChartsDemo-iOS/Objective-C/AppDelegate.m:11,14,16,18,20,22,24,27,30,32,33,37,38,42,43,46,47,50,51,54,55 ./ChartsDemo-iOS/Objective-C/DemoBaseViewController.h:11,14,16,19,20,23,25,27,29,33 ./ChartsDemo-iOS/Objective-C/DemoListViewController.h:11,13,15,16,18 ./ChartsDemo-iOS/Objective-C/Demos/MultipleLinesChartViewController.h:11,15,17 ./ChartsDemo-iOS/Objective-C/Demos/LineChartTimeViewController.m:11,15,17,21,23,25,27,29,31,48,50,52,58,60,62,72,83,85,87,90,91,93,96,97,99,101,104,105,107,108,110,113,115,118,120,123,124,127,132,134,145,148,152,154,155,156,158,160,162,164,165,168,169,171,173,175,176,179,180,182,184,186,187,190,191,193,195,203,204,205,207,208,210,212,214,215,218,219,221,222,224,226,228,230,231,233,235,237,238,240,242,243 ./ChartsDemo-iOS/Objective-C/Demos/SinusBarChartViewController.m:11,14,16,20,22,24,26,28,30,42,44,46,52,58,66,74,84,87,89,90,92,95,96,98,100,103,104,106,107,109,111,113,115,116,119,124,126,129,133,135,137,138,139,141,143,144,146,148,150,152,153,155,157,159,160,162,164,165 ./ChartsDemo-iOS/Objective-C/Demos/CubicLineChartViewController.m:11,14,16,17,19,21,23,25,26,28,30,36,38,40,42,44,46,63,65,68,70,76,78,86,89,93,95,96,98,101,102,104,106,109,110,112,113,115,117,119,123,124,127,132,134,148,152,154,155,156,158,160,162,164,165,168,169,171,173,175,176,179,180,182,184,186,187,190,191,193,195,197,198,200,201,203,205,207,208,211,212,214,215,217,219,222,224,225,227,229,231,232,234,236,237 ./ChartsDemo-iOS/Objective-C/Demos/NegativeStackedBarChartViewController.m:11,14,16,18,20,22,24,26,28,42,49,51,53,57,60,62,71,82,84,93,95,96,98,100,103,104,106,107,109,122,125,130,132,139,141,143,154,156,158,161,162,163,165,168,169,171,173,174,176,178,180,181,183,185,186,188,191,193,194 ./ChartsDemo-iOS/Objective-C/Demos/ScatterChartViewController.m:11,14,16,22,24,26,28,30,32,44,46,48,54,62,66,68,72,76,77,79,82,83,85,87,90,91,93,94,96,100,102,105,108,111,112,124,128,133,136,138,139,141,143,144,146,148,151,153,154,156,158,160,161,163,165,166 ./ChartsDemo-iOS/Objective-C/Demos/AnotherBarChartViewController.h:11,15,17 ./ChartsDemo-iOS/Objective-C/Demos/StackedBarChartViewController.m:11,14,16,22,24,26,28,30,32,46,48,50,57,62,66,68,71,81,85,86,88,91,92,94,96,99,100,102,103,105,107,109,114,116,117,120,125,127,129,131,134,137,142,147,150,151,152,154,156,157,159,161,164,166,167,169,171,173,174,176,178,179 ./ChartsDemo-iOS/Objective-C/Demos/ColoredLineChartViewController.h:11,15,17 ./ChartsDemo-iOS/Objective-C/Demos/HalfPieChartViewController.h:11,15,17 ./ChartsDemo-iOS/Objective-C/Demos/BarChartViewController.m:11,15,17,23,25,27,29,31,33,47,49,51,54,56,64,70,78,87,97,107,111,112,114,117,118,120,122,125,126,128,129,131,133,135,137,144,145,146,149,154,156,160,163,166,168,170,171,172,174,176,177,179,181,184,186,187,189,191,193,194,196,198,199 ./ChartsDemo-iOS/Objective-C/Demos/RadarChartViewController.m:11,14,16,22,24,26,28,30,32,34,50,52,59,63,70,77,87,89,91,92,94,96,102,107,108,110,112,119,120,122,125,126,128,130,133,134,136,137,139,143,146,149,152,153,162,171,176,178,179,181,183,185,190,191,193,197,198,200,203,204,206,208,210,211,214,215,217,219,221,222,225,226,228,231,232,234,237,238,240,243,244,246,249,250,252,253,255,257,259,260,262,264,265,267,270,272,273 ./ChartsDemo-iOS/Objective-C/Demos/CombinedChartViewController.m:11,14,16,18,20,21,23,25,27,29,31,33,42,49,51,53,57,65,72,76,80,86,88,89,91,94,95,97,99,102,103,105,106,108,115,117,119,120,122,124,126,128,130,131,132,135,136,138,140,142,144,145,146,149,150,152,157,158,160,161,163,165,167,169,171,172,184,186,188,190,191,193,196,198,200,203,204,210,220,225,228,231,233,234,236,238,240,242,244,245,251,253,255,256,258,260,262,264,266,267,274,276,278,279,281,283,285,287,291,292,298,300,302,303,305,307,309,310,312,314,315,317,320,322,323 ./ChartsDemo-iOS/Objective-C/Demos/PieChartViewController.m:11,14,16,22,24,26,28,30,32,47,49,51,60,64,68,70,71,73,76,77,79,81,84,85,87,88,90,92,94,96,98,99,101,103,106,108,116,118,120,129,132,133,135,137,139,142,143,145,147,150,151,153,155,158,159,161,163,166,167,169,172,173,175,178,179,181,184,185,187,190,191,193,194,196,198,201,203,204,206,208,210,211,213,215,216 ./ChartsDemo-iOS/Objective-C/Demos/MultipleBarChartViewController.h:11,15,17 ./ChartsDemo-iOS/Objective-C/Demos/LineChart1ViewController.h:11,15,17 ./ChartsDemo-iOS/Objective-C/Demos/PositiveNegativeBarChartViewController.h:11,15,17 ./ChartsDemo-iOS/Objective-C/Demos/CandleStickChartViewController.m:11,14,16,22,24,26,28,30,32,47,49,51,55,59,64,67,69,73,74,76,79,80,82,84,87,88,90,91,93,95,97,106,107,111,113,121,123,125,126,128,130,132,134,135,139,141,143,144,147,148,150,151,153,155,158,160,161,163,165,167,168,170,172,173 ./ChartsDemo-iOS/Objective-C/Demos/BubbleChartViewController.m:11,14,16,22,24,26,28,30,32,45,47,49,55,62,68,70,74,78,79,81,84,85,87,89,92,93,95,96,98,102,104,108,112,116,117,122,127,131,136,142,144,145,147,149,150,152,154,157,159,160,162,164,166,167,169,171,172 ./ChartsDemo-iOS/Objective-C/Demos/LineChart2ViewController.m:11,14,16,22,24,26,28,30,32,49,51,53,58,60,69,75,83,90,94,96,97,99,102,103,105,107,110,111,113,114,116,120,122,126,127,129,133,134,136,140,141,143,145,154,156,167,178,189,194,198,200,201,202,204,206,208,210,211,214,215,217,219,221,222,225,226,228,230,232,233,236,237,239,241,249,250,251,253,254,256,258,260,261,264,265,267,268,270,272,275,277,278,280,282,284,288,289,290,292,294,295 ./ChartsDemo-iOS/Objective-C/Demos/HorizontalBarChartViewController.m:11,14,16,22,24,26,28,30,32,46,48,50,53,55,62,68,75,85,87,91,93,94,96,99,100,102,104,107,108,110,111,113,116,118,120,124,125,128,133,135,137,139,142,146,148,149,150,152,154,155,157,159,162,164,165,167,169,171,172,174,176,177 ./ChartsDemo-iOS/Objective-C/Demos/PiePolylineChartViewController.h:8,10,12 ./ChartsDemo-iOS/Objective-C/Demos/LineChartFilledViewController.m:11,14,16,22,24,26,28,30,32,34,38,40,42,46,49,52,59,61,65,66,68,71,72,74,76,79,80,82,83,85,88,90,93,94,96,99,100,103,105,112,114,129,144,148,151,153,154,155,157,159,162,164,165,167,169,171,172,174,176,177 ./ChartsDemo-iOS/Objective-C/Demos/NegativeStackedBarChartViewController.h:11,15,17 ./ChartsDemo-iOS/Objective-C/Demos/CubicLineChartViewController.h:11,15,17 ./ChartsDemo-iOS/Objective-C/Demos/SinusBarChartViewController.h:11,15,17 ./ChartsDemo-iOS/Objective-C/Demos/LineChartTimeViewController.h:11,15,17 ./ChartsDemo-iOS/Objective-C/Demos/MultipleLinesChartViewController.m:11,14,16,22,24,26,28,30,32,48,50,52,58,64,70,74,75,77,80,81,83,85,88,89,91,92,94,96,98,100,102,104,107,108,113,118,119,123,127,128,130,132,134,136,137,140,141,143,145,147,148,151,152,154,156,158,159,162,163,165,167,175,176,177,179,180,182,183,185,187,190,192,193,195,197,199,200,202,204,205 ./ChartsDemo-iOS/Objective-C/Demos/ColoredLineChartViewController.m:11,14,16,18,20,22,24,26,28,30,33,40,42,43,44,46,48,51,53,59,61,67,69,71,72,74,77,78,80,82,84,87,88,90,98,100,101,103,105,107,108,110,112,113 ./ChartsDemo-iOS/Objective-C/Demos/StackedBarChartViewController.h:11,15,17 ./ChartsDemo-iOS/Objective-C/Demos/AnotherBarChartViewController.m:11,14,16,22,24,26,28,30,32,44,46,48,53,57,60,62,66,67,69,72,73,75,77,80,81,83,84,86,88,90,94,95,98,103,105,109,112,114,117,118,120,121,123,125,126,128,130,133,135,136,138,140,142,143,145,147,148 ./ChartsDemo-iOS/Objective-C/Demos/ScatterChartViewController.h:11,15,17 ./ChartsDemo-iOS/Objective-C/Demos/CandleStickChartViewController.h:11,15,17 ./ChartsDemo-iOS/Objective-C/Demos/LineChart1ViewController.m:11,14,16,22,24,26,28,30,32,50,52,54,59,66,68,71,77,83,93,95,98,107,109,113,115,116,118,121,122,124,126,129,130,132,133,135,137,139,142,143,146,151,153,155,157,169,175,179,181,184,186,188,189,190,192,194,196,198,199,202,203,205,207,209,210,213,214,216,218,220,221,224,225,227,229,237,238,239,241,242,244,246,248,249,252,253,255,256,258,260,263,265,266,268,270,272,273,275,277,278 ./ChartsDemo-iOS/Objective-C/Demos/PositiveNegativeBarChartViewController.m:11,14,16,18,19,21,23,25,27,29,31,44,46,48,53,56,58,61,63,74,84,87,89,90,92,95,96,98,100,103,104,106,107,109,128,131,134,136,140,143,145,147,149,150,151,155,158,162,164,166,167,169,171,172,174,176,178,179,181,183,184,186,189,191,192,193 ./ChartsDemo-iOS/Objective-C/Demos/PieChartViewController.h:11,15,17 ./ChartsDemo-iOS/Objective-C/Demos/MultipleBarChartViewController.m:11,15,17,23,25,27,29,31,33,46,48,50,54,63,73,79,82,89,91,95,96,98,101,102,104,106,109,110,112,113,115,120,125,127,131,133,137,141,145,149,150,153,162,164,168,171,173,176,179,182,185,191,195,198,201,204,206,208,209,210,212,214,215,217,219,222,225,227,228,230,232,234,235,237,239,240 ./ChartsDemo-iOS/Objective-C/Demos/CombinedChartViewController.h:11,15,17 ./ChartsDemo-iOS/Objective-C/Demos/RadarChartViewController.h:11,15,17 ./ChartsDemo-iOS/Objective-C/Demos/BarChartViewController.h:11,15,17 ./ChartsDemo-iOS/Objective-C/Demos/HalfPieChartViewController.m:11,14,16,18,20,22,24,26,28,42,44,46,52,56,65,69,71,73,74,76,79,80,82,84,87,88,90,91,93,95,97,100,102,103,107,109,111,118,121,123,125,126,128,130,132,135,136,138,140,143,144,146,148,151,152,154,156,159,160,162,165,166,168,171,172,174,177,178,180,183,184,186,187,189,191,193,195,196,198,200,201 ./ChartsDemo-iOS/Objective-C/Demos/LineChartFilledViewController.h:11,15,17 ./ChartsDemo-iOS/Objective-C/Demos/PiePolylineChartViewController.m:8,11,13,20,22,24,26,28,42,44,47,49,53,55,56,58,61,62,64,66,69,70,72,73,75,77,79,81,83,84,87,89,97,99,105,107,116,119,120,122,124,126,129,130,132,134,137,138,140,142,145,146,148,150,153,154,156,159,160,162,165,166,168,171,172,174,177,178,180,181,183,185,188,190,191,193,195,197,198,200,202,203,205 ./ChartsDemo-iOS/Objective-C/Demos/HorizontalBarChartViewController.h:11,15,17 ./ChartsDemo-iOS/Objective-C/Demos/LineChart2ViewController.h:11,15,17 ./ChartsDemo-iOS/Objective-C/Demos/BubbleChartViewController.h:11,15,17 ./Package.swift:4 ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/ext/json/ext/fbuffer/fbuffer.h:1,4,6,10,14,24,33,40,45,52,54,59,72,74,81,82,84,87,88,90,92,93,95,97,101,102,104,108,109,110,112,117,118,119,122,125,127,129,131,133,137,138,141,143,146,147,148,150,154,160,161,163,167,168,170,173,177,178,180,185 ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/ext/json/ext/parser/parser.h:3,5,9,15,17,19,23,29,47,54,57,77,81,90 ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/ext/json/ext/parser/parser.c:1,5,11,14,18,20,27,29,46,48,64,65,67,88,90,91,95,101,102,104,105,106,111,113,114,116,117,119,123,126,127,129,130,132,134,135,137,139,143,161,167,173,185,196,212,238,247,257,259,260,273,286,297,313,329,345,371,387,403,419,428,455,458,459,461,469,474,475,476,480,481,482,483,484,489,491,492,494,495,497,499,500,502,504,505,507,509,513,531,543,546,550,559,560,566,570,574,578,582,586,591,592,596,601,602,606,608,612,614,618,620,633,644,660,676,692,834,864,867,868,870,875,876,877,878,883,885,886,888,889,891,893,894,896,898,899,902,904,908,913,953,958,961,962,964,974,975,976,977,982,984,985,987,988,990,994,997,998,1000,1001,1003,1005,1006,1008,1010,1011,1014,1016,1020,1025,1049,1065,1089,1107,1122,1126,1136,1139,1140,1142,1157,1158,1162,1163,1164,1165,1166,1171,1173,1174,1176,1177,1179,1182,1185,1187,1188,1190,1192,1193,1195,1197,1201,1227,1236,1246,1248,1249,1262,1283,1297,1313,1329,1345,1371,1387,1396,1413,1416,1417,1419,1425,1426,1427,1429,1433,1477,1486,1487,1490,1495,1500,1501,1504,1505,1506,1511,1513,1514,1516,1517,1520,1526,1528,1529,1531,1534,1536,1538,1540,1541,1544,1546,1550,1565,1571,1579,1580,1651,1659,1662,1663,1665,1674,1675,1676,1681,1686,1687,1688,1700,1702,1708,1712,1715,1716,1745,1748,1751,1772,1775,1781,1787,1793,1798,1804,1810,1816,1822,1829,1831,1841,1848,1849,1850,1855,1857,1858,1860,1861,1869,1874,1875,1877,1879,1880,1884,1886,1890,1908,1920,1923,1934,1945,1961,1977,1993,2002,2013,2016,2017,2019,2025,2026,2027,2029,2037,2038,2040,2044,2045,2047,2050,2051,2062,2064,2069,2070,2078,2081,2082,2084,2098,2101,2104,2107,2128,2129 ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/ext/json/ext/generator/generator.c:3,8,20,26,48,66,74,86,95,103,104,106,109,110,113,115,120,121,126,129,130,134,138,145,149,160,162,186,207,208,209,223,224,226,227,233,241,272,284,291,295,296,298,301,302,307,309,310,317,318,330,340,342,343,354,355,363,365,366,374,376,377,384,386,388,395,397,398,407,408,417,419,420,430,437,438,446,450,451,459,464,465,472,474,475,482,484,485,492,494,495,504,511,512,514,525,526,528,540,541,552,554,558,559,567,580,588,596,604,612,622,623,633,634,643,644,650,651,653,661,662,663,671,686,687,694,700,701,702,709,711,718,720,721,728,731,736,748,752,756,757,758,766,771,774,775,777,786,790,792,798,805,806,807,809,810,812,825,833,834,836,843,844,845,847,848,851,855,857,859,864,870,872,873,875,877,878,880,882,883,885,887,888,890,892,893,895,898,899,902,907,910,921,922,924,925,927,956,957,958,960,964,969,975,979,984,988,989,991,996,997,1006,1011,1012,1034,1042,1043,1051,1053,1058,1069,1070,1079,1087,1088,1089,1096,1099,1100,1107,1117,1122,1124,1125,1133,1136,1137,1145,1155,1160,1162,1163,1170,1173,1174,1181,1191,1196,1198,1199,1207,1210,1211,1219,1228,1233,1235,1236,1243,1246,1247,1254,1263,1268,1270,1271,1272,1280,1283,1284,1292,1295,1296,1304,1308,1309,1317,1320,1321,1329,1332,1333,1340,1343,1344,1352,1357,1358,1365,1368,1369,1377,1384,1386,1387,1392,1395,1399,1404,1436,1468,1499 ./vendor/bundle/ruby/2.6.0/gems/json-2.3.0/ext/json/ext/generator/generator.h:3,6,8,14,18,22,24,26,28,32,38,43,45,48,55,57,78,81,85,90,97,157,161,170 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/Type.h:33,36,39,43,45,47,52,55,57,59,61 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/rbffi_endian.h:3,7,9,22,35,47,53,57,59 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/MappedType.h:29,32,33,35,39,40,46,48,50,52,53,55,57,59 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/Thread.c:29,37,50,59,61,64,71,72,75,81,90,91,94,100,101,104,107,110,111,114,116,118,120,121,124,126,128,131,137 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/Buffer.c:30,43,47,54,60,62,65,68,72,74,75,78,82,83,85,86,98,102,104,108,114,115,118,121,122,126,127,130,131,133,134,142,145,150,155,156,160,163,165,166,169,171,172,175,179,182,189,191,192,201,204,206,208,209,219,221,222,230,233,235,237,239,240,241,247,260,262,270,273,278,281,282,286,290,291,293,294,295,299,301,306,307,309,310,313,315,316,319,321,328,334,356,364,365 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/Types.h:30,33,37,61,64,67,70,73,77,80,83,85,87,89 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/LastError.h:29,32,36,37,39,41,43,45,47 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/ArrayType.h:29,32,36,40,41,49,52,53,55,57,59 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/DynamicLibrary.c:29,47,49,55,61,64,65,69,71,83,86,89,90,101,103,104,115,118,120,123,131,139,143,144,147,151,154,156,157,164,168,169,172,177,180,181,185,191,192,193,196,199,201,204,210,212,213,214,223,226,227,230,233,240,242,243,246,249,250,258,261,266,267,270,284,317,322,337,338,339 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/Variadic.c:29,34,44,48,57,62,69,70,75,77,78,81,84,89,91,92,95,99,100,103,112,115,121,129,134,135,137,139,145,149,153,154,160,162,163,166,179,182,191,194,197,199,213,218,221,222,223,227,229,230,234,235,238,253,254,257,259,269,273,274,276,278,281,282,284,285,286,289,292,294,297,298 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/StructByValue.h:29,32,35,39,45,47,49,51,53,55 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/AbstractMemory.h:29,32,40,43,47,48,54,56,61,80,87,88,91,93,95,97,100,104,105,106,109,112,113,114,117,120,121,122,125,161,162,163,167,168,169,171,173,175 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/ffi.c:30,34,36,53,55,57,59,62,70,72,75,93 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/ClosurePool.h:28,31,34,42,44,48,50,53,55,57 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/Pointer.c:29,43,45,48,51,54,57,60,61,68,70,71,74,77,81,83,84,98,102,104,115,116,124,126,130,136,138,139,141,143,144,157,160,166,167,171,172,176,177,182,183,189,192,194,195,198,202,205,207,213,215,216,226,229,231,233,234,245,247,248,256,259,261,267,268,270,271,280,282,284,286,287,296,298,300,303,304,306,307,315,317,319,321,322,328,340,342,350,353,358,361,362,366,370,371,373,374,375,376,384,386,388,393,395,398,400,401,403,404,407,409,411,413,414,423,425,428,430,431,439,441,443,445,446,447,450,454,456,457,460,462,463,466,469,484,501,507,508 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/MemoryPointer.c:30,44,45,50,52,54,57,59,60,63,68,70,71,82,85,88,91,92,94,95,98,101,103,105,110,117,120,121,123,124,127,129,131,136,138,139,141,142,145,149,151,152,161,166,168,169,172,174,176,192,196,197 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/Call.h:32,35,37,41,47,51,73,75,79,82,84,86,89,98,101,103,105,107 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/Platform.c:29,45,49,51,54,69,70,73,82 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/LongDouble.c:5,9,13,16,20,21,25,26,29,30,33,36,37,40,41,45,46,49,50,51,54,57,58,61,63 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/MethodHandle.h:29,32,36,39,40,43,44,49,51,53,55 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi-x86_64-darwin18/include/ffitarget.h:5,7,15,18,27,29,32,36,38,41,46,51,56,58,79,91,100,126,128,131,136,145,147 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi-x86_64-darwin18/include/ffi.h:4,12,15,24,26,29,34,36,38,40,43,46,50,55,57,59,61,65,68,72,74,99,102,104,110,128,136,144,154,167,175,185,199,205,216,222,234,236,244,248,256,270,271,277,281,285,293,300,302,304,323,329,332,344,351,363,365,369,372,374,377,379,387,389,391,395,398,400,403,405,411,418,425,433,435,437,443,446,449,451,453,460,468,474,478,481,483,485,507,510,512,514 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi-x86_64-darwin18/fficonfig.h:3,6,11,14,17,20,23,26,29,32,35,38,42,45,48,51,55,58,61,64,67,70,73,76,79,82,85,88,91,94,97,100,103,106,109,112,115,118,121,124,127,130,133,136,139,142,145,148,151,154,157,160,168,171,174,178,181,193,196,197,215 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/Function.c:29,38,51,57,60,74,84,93,95,96,101,107,109,111,117,119,121,122,124,128,130,147,148,159,160,163,166,168,174,176,177,180,184,185,188,191,192,195,196,198,199,216,217,222,224,233,243,244,249,251,253,254,262,265,266,269,271,272,275,278,285,286,287,291,292,303,304,306,307,310,312,314,316,318,324,330,331,332,336,338,344,348,349,351,353,354,363,365,367,369,370,380,383,385,389,390,394,395,398,399,405,408,409,412,414,415,424,426,428,430,432,433,436,438,440,442,443,451,453,455,458,459,462,464,465,468,470,476,478,484,488,491,497,500,505,509,513,515,522,524,529,530,531,537,540,543,545,552,553,554,556,557,561,563,565,567,572,573,577,578,580,582,583,586,588,593,594,598,600,602,604,607,608,612,613,615,617,618,621,623,628,630,633,635,637,647,649,650,652,655,658,659,662,664,674,680,684,685,735,741,745,746,751,752,754,755,757,763,764,802,804,808,812,814,817,819,823,825,829,832,835,836,839,841,845,846,848,849,852,854,857,859,860,863,866,871,872,874,875,878,884,887,907,917 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/Struct.h:30,33,38,42,48,52,54,58,61,64,72,78,83,86,91,96,100,106,108,110,112 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/rbffi.h:29,32,34,38,40,42,50,52,54 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/Thread.h:29,32,41,45,46,52,63,74,78,80,82,84 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/MappedType.c:29,31,34,37,38,43,45,48,50,52,58,60,61,70,72,75,76,79,80,83,84,89,90,94,96,97,100,103,104,112,115,117,118,125,127,129,131,132,139,141,143,145,146,149,154,156,160,167,168 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/Type.c:29,33,41,42,47,49,51,56,59,62,65,67,68,77,80,82,91,92,94,95,103,105,107,109,110,118,120,122,124,125,133,136,138,141,143,144,147,150,152,156,158,159,162,165,166,174,177,181,183,184,187,189,192,203,206,207,208,211,214,215,216,219,228,230,232,233,236,237,240,249,260,304,311,317,321,324,332,337,347,378,379 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/Types.c:31,42,44,45,48,62,73,78,81,88,94,95,100,105,107,108,116,119,120,124,126,127,131,132,133,136,138,139 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/compat.h:29,32,34,38,42,46,50,54,58,66,73,77 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/StructLayout.c:30,32,54,56,60,65,67,68,71,74,78,80,81,84,87,88,99,103,105,107,111,112,114,118,119,126,133,140,141,143,144,152,156,157,165,169,170,178,182,183,191,194,196,197,205,209,210,219,221,226,227,229,230,240,242,247,248,250,252,253,262,264,266,268,269,281,284,286,293,294,296,298,299,302,305,306,315,319,322,325,328,329,339,342,343,346,349,352,354,361,364,365,372,373,376,379,380,382,386,390,391,395,398,399,402,406,407,409,410,411,414,417,426,428,429,440,444,458,465,466,469,471,474,477,478,482,483,486,487,488,493,494,497,498,500,501,510,516,518,523,524,528,529,534,537,538,540,541,544,546,548,550,551,559,561,563,565,566,574,576,578,580,581,589,591,593,595,596,599,607,608,611,616,617,618,621,623,631,638,645,652,659,666,673,683,686,689,697,698,699 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/DynamicLibrary.h:28,31,35,40,44,48,52,57,61,65,69,73,78,82,86,90,92,94,96,98 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/ArrayType.c:29,33,38,40,43,46,48,55,57,58,61,63,64,67,71,72,73,83,86,88,92,97,100,101,103,104,112,114,116,118,119,127,129,131,133,134,137,139,141,156,161,162 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/win32/stdbool.h:3,7 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/win32/stdint.h:8,15,21,25,29,33,37,41,50,59,62,65,68,71,76,83,87,94,98,105,110,116,120,124,132,135,143,146,149,153,157,161,165,173,177,180,185,187,190,196 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/LastError.c:30,44,46,51,57,64,68,70,72,75,77,79,81,82,83,86,89,90,93,95,96,99,102,105,108,110,111,114,116,119,120,122,123,125,126,134,136,137,146,148,150,151,160,161,167,169,170,180,183,185,186,189,196,201,203,204,207,214,217,222,228,229 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/Struct.c:30,53,57,65,66,73,75,78,81,84,86,87,90,93,96,98,99,109,113,115,117,123,124,127,128,130,136,137,139,140,148,151,156,157,160,173,174,178,179,181,182,185,189,190,194,195,197,198,201,205,206,210,211,213,214,217,220,223,224,227,228,230,231,234,237,240,241,243,244,247,252,253,254,257,260,261,262,265,269,275,276,277,279,280,281,284,287,294,298,299,301,302,310,313,315,319,322,327,328,329,339,342,344,348,350,352,360,361,364,365,367,368,377,381,386,387,388,392,396,397,401,403,404,412,414,416,418,419,428,431,436,437,440,442,443,451,453,455,457,458,466,468,470,472,473,479,481,485,490,492,493,494,497,500,504,506,507,510,513,514,524,526,530,535,539,540,542,544,545,553,555,557,559,560,563,566,567,569,570,578,580,582,591,592,597,600,603,604,605,614,616,618,623,626,630,634,635,638,642,644,648,651,652,654,655,662,664,666,668,671,672,674,675,683,687,690,691,694,695,697,698,707,710,712,716,717,720,722,723,731,733,735,738,739,740,743,745,747,767,773,780,781,786,793,796,799,803,813,816,824,825 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/Platform.h:29,32,36,38,39,41,43,45 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/Call.c:31,65,70,80,82,88,91,93,98,102,108,109,110,112,116,117,122,123,126,128,135,136,140,145,148,149,153,158,161,162,166,170,174,181,182,186,193,194,198,205,206,210,217,218,222,229,230,234,241,242,246,253,254,258,265,266,270,277,278,282,289,290,294,295,299,302,303,307,315,316,324,327,331,334,335,336,337,340,349,351,352,355,357,359,360,363,367,368,371,377,379,382,393,397,401,403,406,410,414,415,418,419,422,423,426,428,429,432,434,436,438,441,443,445,447,449,451,455,457,458,461,462,465,467,468,469,472,476,477,483,484,487,489,490,491,494,498,499 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/Function.h:29,32,36,42,44,46,50,55,74,76,81,83,85,87 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/MethodHandle.c:28,52,56,64,65,67,74,82,83,84,87,91,92,96,98,99,102,108,109,114,116,117,120,123,124,125,128,130,131,134,140,142,145,147,156,157,159,160,161,164,166,167,174,177,185,187,188,190,191,192,195,197,200,225,228,231,234,236,237,239,243,270,273,276,277,279,283,285,288,293,294,295,297,298,301,305,306,310,311,313,314,317,319,324,326,327,330,332,333,335,336,339,343,345,349,355,356,358 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/LongDouble.h:29,32,34,38,42,45,47,49,51 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/AbstractMemory.c:31,41,44,51,60,65,68,73,75,77,133,179,180,185,187,188,191,193,194,201,211,214,216,217,220,222,223,226,228,229,232,234,235,242,250,264,267,282,283,284,286,289,291,292,295,297,298,300,301,309,313,314,322,324,326,328,329,340,344,347,350,353,355,360,361,362,372,376,379,382,385,388,393,394,395,407,413,418,422,423,435,440,445,448,451,453,457,458,465,467,468,469,471,472,482,485,489,490,492,493,494,507,510,514,517,520,522,523,535,538,541,544,546,547,563,568,570,576,581,582,585,587,589,590,600,602,603,615,618,622,623,625,626,634,636,638,640,641,651,654,656,658,660,661,664,666,667,670,672,674,676,678,679,682,687,688,691,692,695,703,704,705,708,710,715,716,718,719,722,724,725,727,728,747,750,786,790,791,810,816,834,839,1082,1090,1093,1100,1104,1105 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/MemoryPointer.h:30,33,40,44,49,51,53 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/include/ffi_common.h:5,9,12,16,18,49,58,62,67,76,81,86,87,92,101,105,108,113,140,142,148,150,152 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/include/ffi_cfi.h:3,6,9,11,31,33,53 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.call/err_bad_typedef.c:6,8,10,12,15,17,19,21,24,26 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.call/float3.c:6,8,11,13,15,17,18,20,22,23,25,30,34,41,45,49,51,53,55,62,66,68,70,72,74 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.call/strlen4.c:6,8,10,12,14,15,17,31,35,41,47,53,55 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.call/many2.c:6,8,10,12,14,21,23,24,28,30,31,34,41,44,47,49,52,54,57 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.call/return_fl3.c:6,9,11,13,15,29,37,42 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.call/struct5.c:6,10,14,16,19,21,22,24,30,32,36,44,49,52,57,59,62,63,66 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.call/struct1.c:6,9,11,16,18,22,24,25,27,33,35,39,48,51,55,59,61,64,67 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.call/struct10.c:6,9,12,18,25,26,37,42,46,49,52,57 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.call/align_stdcall.c:6,8,10,15,17,18,20,32,36,38,40,46 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.call/align_mixed.c:6,8,10,15,17,18,20,32,36,38,40,46 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.call/ffitest.h:7,11,15,17,19,34,39,44,53,55,57,63,65,74,88,93,115,124,135 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.call/strlen3.c:6,8,10,12,14,15,17,28,32,37,42,47,49 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.call/va_struct3.c:6,9,12,14,18,20,27,30,35,48,49,52,56,59,62,66,69,74,78,83,90,96,98,101,107,110,112,118,123,125 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.call/float4.c:6,9,12,14,18,20,22,24,25,27,34,37,41,43,47,49,53,55,59,61,62 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.call/struct6.c:6,10,14,16,19,21,22,24,30,32,36,44,47,50,53,56,58,61,64 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.call/return_uc.c:6,9,11,13,14,16,21,23,26,30,33,36,38 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.call/strlen.c:6,9,11,13,14,16,22,25,29,33,37,41,43,44 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.call/pyobjc-tc.c:6,9,14,19,24,26,30,31,32,34,42,46,54,62,70,80,85,86,87,89,90,97,104,107,109,111,112,114 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.call/return_sl.c:6,10,12,13,15,21,26,29,32,36,38 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.call/struct8.c:6,10,16,18,23,25,26,28,34,36,40,50,53,56,61,66,68,73,78,81 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.call/struct2.c:6,9,11,15,17,20,22,23,25,32,36,44,47,50,53,56,58,61,64,67 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.call/return_ll1.c:6,11,13,14,16,23,30,34,38,43 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.call/return_ldl.c:7,9,11,13,15,20,23,27,29,32,34 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.call/float1.c:6,10,12,14,18,20,22,24,25,27,34,37,41,43,47,49,51,53,57,59,60 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.call/return_ll.c:6,10,12,13,15,21,24,28,30,33,34,36,39,41 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.call/return_dbl.c:6,9,11,14,16,21,24,28,30,34,36 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.call/return_dbl2.c:6,9,11,13,15,29,37,42 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.call/many.c:6,9,13,15,22,24,25,27,34,36,40,41,45,47,54,59 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.call/many_mixed.c:6,9,13,33,35,36,38,46,48,53,58,59,60,64,66,78 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.call/va_struct2.c:6,9,12,14,18,20,27,30,35,46,47,50,54,57,60,64,67,72,76,81,88,94,96,99,105,108,110,116,121,123 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.call/strlen2.c:6,8,10,12,14,15,17,28,32,37,42,47,49 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.call/offsets.c:6,10,12,18,21,25,31,36,44,46 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.call/struct7.c:6,10,15,17,21,23,24,26,32,34,38,47,50,53,57,61,63,67,71,74 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.call/negint.c:6,8,10,12,13,15,16,18,23,27,34,38,42,44,46,48,50,52 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.call/return_sc.c:6,9,11,13,15,21,24,28,31,34,36 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.call/float_va.c:6,9,11,13,15,20,24,27,29,32,36,38,40,42,43,45,47,53,62,68,77,84,92,105,107 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.call/pr1172638.c:5,8,13,20,25,27,32,34,35,37,44,49,53,61,71,80,83,109,120,122,124,127 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.call/return_fl1.c:6,9,11,13,15,20,25,31,36 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.call/float.c:6,8,10,12,14,16,18,19,21,26,31,40,44,49,51,53,55,57,59 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.call/struct3.c:6,9,11,14,16,18,20,21,23,30,34,41,44,48,51,53,55,57,60 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.call/return_ul.c:6,10,12,13,15,21,26,29,32,36,38 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.call/struct9.c:6,9,11,15,17,20,22,23,25,31,33,37,45,48,51,54,57,59,62,65,68 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.call/return_fl.c:6,9,11,13,15,20,23,27,29,33,35 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.call/va_1.c:6,9,12,14,18,20,27,30,45,50,53,56,59,62,66,77,78,81,85,88,91,95,98,109,114,118,123,130,146,148,151,157,160,162,173,189,194,196 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.call/float2.c:7,10,12,14,16,17,19,26,29,33,35,42,45,52,59,61 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.call/va_struct1.c:6,9,12,14,18,20,27,30,35,44,45,48,52,55,58,62,65,70,74,79,86,92,94,97,103,106,108,114,119,121 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.call/return_dbl1.c:6,9,11,13,15,30,38,43 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.call/return_fl2.c:6,9,12,14,17,19,25,34,42,45,49 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.call/promotion.c:6,11,13,15,16,18,28,37,41,44,51,56,59 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.call/struct4.c:6,9,11,16,18,20,22,23,25,31,33,37,46,49,52,56,58,60,61,64 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.call/uninitialized.c:3,5,10,12,16,18,19,21,27,37,42,45,49,53,55,58,61 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.call/many_double.c:6,9,13,27,34,36,37,39,46,48,52,53,57,59,70 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.complex/return_complex_float.c:6,8 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.complex/return_complex1_float.c:6,8 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.complex/cls_align_complex_double.c:6,8 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.complex/cls_complex_va_longdouble.c:6,8 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.complex/return_complex2_longdouble.c:6,8 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.complex/complex_float.c:6,8 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.complex/return_complex1_double.c:6,8 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.complex/cls_complex_struct_longdouble.c:6,8 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.complex/cls_align_complex_longdouble.c:6,8 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.complex/cls_complex_struct_double.c:6,8 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.complex/return_complex2_float.c:6,8 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.complex/cls_complex_va_double.c:6,8 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.complex/cls_complex_float.c:6,8 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.complex/complex_int.c:6,8,12,14,19,20,41,42,48,50,54,60,67,71,76,84,86 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.complex/cls_align_complex_float.c:6,8 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.complex/many_complex_longdouble.c:6,8 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.complex/cls_complex_struct_float.c:6,8 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.complex/many_complex_double.c:6,8 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.complex/complex_double.c:6,8 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.complex/complex_longdouble.c:6,8 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.complex/cls_complex_longdouble.c:6,8 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.complex/many_complex_float.c:6,8 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.complex/cls_complex_va_float.c:6,8,14 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.complex/return_complex_double.c:6,8 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.complex/cls_complex_double.c:6,8 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.complex/return_complex_longdouble.c:6,8 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.complex/return_complex2_double.c:6,8 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.complex/return_complex1_longdouble.c:6,8 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/nested_struct9.c:8,11,16,21,26,28,30,34,38,40,41,45,49,53,55,56,58,68,72,74,79,84,89,93,97,101,102,107,110,115,121,123,129,131 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_struct_va1.c:6,10,12,16,18,25,29,34,39,40,43,48,50,53,56,60,62,67,71,76,83,89,92,96,99,105,107,112,114 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_4byte.c:7,9,11,16,19,21,24,26,28,29,33,34,36,39,41,42,44,52,56,61,65,69,72,76,81,83,88,90 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_align_uint32.c:6,9,15,18,20,24,26,28,29,33,34,36,39,41,42,44,52,56,61,66,70,73,77,82,84,89,91 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_20byte.c:7,10,16,19,21,25,29,30,34,36,39,41,42,44,52,56,61,66,70,73,77,82,84,89,91 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_3float.c:7,9,11,17,20,22,26,29,31,32,36,38,41,43,44,46,54,58,63,68,72,75,79,84,87,93,95 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/nested_struct3.c:8,11,16,21,23,25,29,33,35,36,40,43,46,48,49,51,60,63,65,70,75,79,83,84,88,91,95,101,102,104,111 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_7_1_byte.c:7,10,20,23,25,33,38,40,41,45,46,48,51,53,54,56,64,68,73,82,86,89,93,99,107,109,115,117 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/err_bad_abi.c:6,8,10,15,17,22,24,27,30,32,34,36 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_6_1_byte.c:7,10,19,22,24,31,36,38,39,43,44,46,49,51,52,54,62,66,71,79,83,86,90,96,103,105,111,113 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_ulong_va.c:6,8,10,12,15,17,19,20,22,24,30,34,38,45 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_ushort.c:6,9,12,14,17,19,21,27,30,34,36,41,43 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_4_1byte.c:8,11,18,21,23,28,32,34,35,39,40,42,45,47,48,50,58,62,67,73,77,80,84,89,91,96,98 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/nested_struct7.c:8,11,16,21,23,25,29,33,35,36,40,43,46,48,49,51,60,63,65,70,75,79,83,84,88,91,95,101,103,109,111 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_schar.c:6,7,8,11,14,18,20,22,28,31,35,37,42,44 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_6byte.c:7,8,11,18,21,23,28,32,34,35,39,40,42,45,47,48,50,58,62,67,73,77,80,84,89,91,96,97,99 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_sint.c:6,9,12,16,18,20,26,29,33,35,40,42 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_2byte.c:8,11,16,19,21,24,26,28,29,33,34,36,39,41,42,44,52,56,61,65,69,72,76,81,83,88,90 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/closure_fn2.c:8,11,14,24,35,36,40,42,48,66,70,73,81 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/closure_fn6.c:7,10,14,27,40,41,42,49,51,57,75,79,82,90 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_multi_sshortchar.c:6,9,12,14,16,18,20,21,22,25,28,33,35,36,37,40,42,51,56,62,68,72,77,79,84,86 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_align_float.c:6,9,15,18,20,24,26,28,29,33,34,36,39,41,42,44,52,56,61,66,70,73,77,82,84,89,91 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/nested_struct.c:7,10,16,22,27,31,33,40,48,50,51,55,59,63,64,66,67,69,79,85,90,95,100,105,110,114,115,120,123,128,137,139,152 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_24byte.c:7,10,17,22,24,29,36,38,39,43,45,50,52,53,55,63,69,74,80,86,89,95,100,102,111,113 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_uchar.c:6,9,12,16,18,20,26,29,33,35,40,42 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_19byte.c:7,10,18,21,23,29,30,36,37,41,43,46,48,49,51,59,63,68,75,79,82,86,92,94,100,102 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/nested_struct10.c:8,11,16,22,27,29,31,36,40,42,43,47,51,55,57,58,60,70,74,76,81,86,91,95,100,104,105,110,113,118,124,126,132,134 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_7byte.c:7,10,17,20,22,27,31,33,34,38,39,41,44,46,47,49,57,61,66,72,76,79,83,88,90,95,97 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_sshort.c:6,9,12,16,18,20,26,29,33,35,40,42 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_double.c:6,9,12,14,17,19,21,27,30,34,36,41,43 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/ffitest.h:7,11,15,17,19,34,39,44,53,55,57,63,65,74,88,93,115,124,135 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/nested_struct4.c:8,11,16,21,23,25,29,33,35,36,40,43,46,48,49,51,60,63,65,70,75,79,83,84,88,91,95,101,103,109,111 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_5byte.c:7,10,16,19,21,25,29,31,32,36,37,39,42,44,45,47,55,59,64,69,73,76,80,85,89,91,96,98 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_64byte.c:8,11,22,27,29,38,41,43,44,48,50,55,57,58,60,68,74,79,89,95,98,104,110,112,122,124 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_align_sint32.c:6,9,15,18,20,24,26,28,29,33,34,36,39,41,42,44,52,56,61,66,70,73,77,82,84,89,91 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/huge_struct.c:7,11,13,66,119,130,151,153,154,157,208,215,216,219,222,226,230,243,245,250,263,265,290,293,295,311,313,339,341 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/problem1.c:6,9,15,17,22,23,26,28,29,32,35,38,40,41,42,44,52,56,61,66,70,73,81,83,88,90 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/stret_large2.c:8,11,14,32,38,40,56,60,62,63,66,68,73,75,76,78,86,92,97,114,120,123,129,136,138,146,148 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/closure_fn1.c:8,11,12,15,25,36,37,42,48,66,70,73,81 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_18byte.c:7,10,17,20,22,27,28,33,34,38,40,43,45,46,48,56,60,65,71,75,78,82,87,89,94,96 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_align_pointer.c:6,9,15,18,20,24,30,32,33,37,38,40,43,45,46,48,56,60,65,70,74,77,81,86,88,93,95 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_uint.c:6,9,12,14,17,19,21,27,30,34,36,41,43 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/closure_fn5.c:8,11,15,28,47,48,49,58,60,66,69,73,76,80,83,90,92 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_20byte1.c:7,8,9,12,18,21,23,27,31,32,36,38,41,43,44,46,54,58,63,68,72,75,79,84,86,91,93 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_9byte2.c:9,12,17,20,22,25,28,30,31,34,36,39,41,42,44,52,56,61,65,69,72,76,81,82,84,89,91 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/closure_loc_fn0.c:8,9,10,11,14,18,29,41,42,43,48,50,56,74,78,82,85,87,95 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_longdouble.c:6,11,13,23,25,28,30,31,35,44,47,48,50,57,66,76,79,89,94,96,103,105 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_double_va.c:6,10,12,16,19,21,22,24,30,34,38,42,46,51,54,59,61 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_16byte.c:7,10,16,19,21,25,28,30,31,34,36,39,41,42,44,52,56,61,66,70,73,77,82,86,88,93,95 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_3_1byte.c:8,11,17,20,22,26,30,32,33,37,38,40,43,45,46,48,56,60,65,70,74,77,81,86,88,93,95 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/nested_struct1.c:7,10,16,22,27,32,34,41,50,52,53,57,62,67,68,70,71,73,83,90,95,100,105,110,115,119,120,126,129,135,144,146,161 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/nested_struct11.c:9,12,17,22,27,29,35,37,44,46,47,49,51,56,58,62,65,70,75,80,84,88,92,101,112,121 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_align_longdouble_split.c:6,9,11,21,25,27,35,41,43,44,47,49,57,62,64,65,69,71,74,76,77,79,87,91,96,105,109,112,116,122,124,130,132 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_align_sint16.c:6,9,15,18,20,24,26,28,29,33,34,36,39,41,42,44,52,56,61,66,70,73,77,82,84,89,91 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_3byte1.c:8,11,16,19,21,24,26,28,29,33,34,36,39,41,42,44,52,56,61,65,69,72,76,81,83,88,90 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/nested_struct5.c:8,11,16,21,23,25,29,33,35,36,40,43,46,48,49,51,60,63,65,70,75,79,83,84,88,91,95,101,102,104,110,112 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_multi_sshort.c:6,9,11,13,15,17,19,20,21,24,26,29,31,32,33,35,37,45,48,52,56,60,65,67,72,74 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/stret_medium2.c:8,12,24,30,32,42,45,47,48,51,53,58,60,61,63,71,77,82,93,99,102,108,114,116,123,125 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/closure_fn0.c:8,9,10,11,14,18,29,41,42,43,48,50,56,74,78,81,89 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_float.c:6,9,12,14,17,18,20,22,28,31,35,42 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_longdouble_va.c:6,10,12,16,19,21,22,24,30,34,38,42,46,51,54,59,61 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/stret_medium.c:8,11,23,29,31,41,44,46,47,50,52,57,59,60,62,70,76,81,92,98,101,107,113,115,122,124 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_align_uint64.c:6,7,11,17,20,22,26,28,30,31,35,36,38,41,43,44,46,54,58,63,68,72,75,79,84,86,91,93 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_12byte.c:6,9,15,18,20,24,27,29,30,33,35,38,40,41,43,51,55,60,65,69,72,76,81,83,87,92,94 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_5_1_byte.c:7,10,18,21,23,29,34,36,37,41,42,44,47,49,50,52,60,64,69,76,80,83,87,93,99,101,107,109 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_dbls_struct.c:6,8,10,15,18,20,21,25,27,28,30,32,36,39,41,46,50,52,56,58,61,64,66 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_align_longdouble_split2.c:7,10,12,22,26,28,36,42,44,45,49,51,54,56,57,59,67,71,76,85,89,92,96,102,104,110,112,113,114,115 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/testclosure.c:6,9,16,18,23,24,28,30,32,34,35,36,38,45,47,52,58,61,64,66,70 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/closure_fn4.c:8,10,12,16,29,48,49,50,59,61,67,70,73,77,80,87,89 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/nested_struct2.c:8,11,16,21,23,25,29,32,34,35,39,42,45,47,48,50,59,62,64,69,74,78,82,83,87,90,94,100,102,108,110 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/nested_struct8.c:8,11,16,21,26,28,30,34,38,40,41,45,49,53,55,56,58,68,72,74,79,84,89,93,97,101,102,107,110,115,121,123,129,131 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/stret_large.c:8,11,14,31,37,39,54,58,60,61,64,66,71,73,74,76,84,90,95,111,117,120,126,133,135,143,145 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_multi_uchar.c:6,9,12,14,16,18,20,21,22,25,27,32,34,35,36,39,42,46,48,56,61,67,73,77,82,84,89,91 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_uchar_va.c:6,9,11,14,16,18,19,21,23,29,33,37,44 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_9byte1.c:9,12,17,20,22,25,28,30,31,34,36,39,41,42,44,52,56,61,65,69,72,76,81,83,88,90 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_multi_ushort.c:6,9,11,13,15,17,19,20,21,24,26,29,31,32,33,35,37,45,48,52,56,60,65,67,72,74 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_align_uint16.c:6,9,15,18,20,24,26,28,29,33,34,36,39,41,42,44,52,56,61,66,70,73,77,82,84,89,91 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_many_mixed_float_double.c:6,11,13,16,21,26,28,30,32,34,42,43,55 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_align_longdouble.c:6,8,10,16,19,21,25,27,29,30,34,35,37,40,42,43,45,53,57,62,67,71,74,78,83,85,90,92 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/nested_struct6.c:8,11,16,21,26,28,30,34,38,40,41,45,49,53,55,56,58,68,72,74,79,84,89,93,97,101,102,107,110,115,121,123,129,131 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_3byte2.c:8,11,16,19,21,24,26,28,29,33,34,36,39,41,42,44,52,56,61,65,69,72,76,81,83,88,90 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_uint_va.c:6,8,10,12,15,17,19,20,22,24,30,34,38,45 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_many_mixed_args.c:6,11,13,16,21,23,26,28,31,33,35,39,41,49,51,56,57,61,63,70 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_multi_ushortchar.c:6,9,12,14,16,18,20,21,22,25,28,33,35,36,37,40,42,51,56,62,68,72,77,79,84,86 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_align_sint64.c:6,10,16,19,21,25,27,29,30,34,35,37,40,42,43,45,53,57,62,67,71,74,78,83,85,90,92 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/closure_fn3.c:8,11,14,24,35,36,37,41,43,49,67,71,74,82 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_ushort_va.c:6,9,11,14,16,18,19,21,23,29,33,37,44 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_pointer_stack.c:6,9,11,17,19,20,22,32,35,37,42,44,45,47,57,60,62,67,69,71,72,76,79,88,91,93,94,96,103,108,112,116,119,123,126,131,133,135,140,142 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_multi_schar.c:6,9,11,13,15,17,19,20,21,24,26,29,31,32,33,35,37,45,48,52,56,60,65,67,72,74 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_1_1byte.c:8,9,10,13,17,20,22,24,26,28,29,33,34,36,39,41,42,44,52,56,61,64,68,71,75,80,82,87,89 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/closure_simple.c:6,9,12,17,22,23,24,26,28,34,40,44,47,50,53,55 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_align_double.c:6,7,8,11,17,20,22,26,28,30,31,35,36,38,41,43,44,46,54,58,63,68,72,75,79,84,86,91,93 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_pointer.c:6,9,11,13,18,20,21,25,28,30,31,33,40,45,49,53,56,60,65,67,72,74 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_ulonglong.c:6,10,13,15,18,20,22,28,31,40,45,47 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.closures/cls_8byte.c:7,10,15,18,20,23,25,27,28,32,33,35,38,40,41,43,51,55,60,64,68,71,75,81,86,88 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.go/closure1.c:2,4,6,10,11,13,15,19,22,24,26,28 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.go/aa-direct.c:2,4,6,8,13,16,17,19,22,24,26,28,30,31 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.bhaible/test-call.c:4,9,14,18,20,27,36,39,41,55,56,58,60,64,66,70,75,78,85,104,105,108,112,115,117,118,121,124,132,135,138,139,143,149,153,157,158,162,168,172,176,177,181,187,191,195,196,200,206,210,214,215,219,225,229,233,234,238,240,243,245,251,255,258,259,263,269,273,276,277,281,287,291,294,295,299,305,309,312,313,317,323,327,330,331,335,341,345,348,349,353,356,358,360,365,369,372,373,377,383,387,390,391,395,401,405,408,409,413,419,423,426,427,431,437,441,444,445,450,453,455,461,465,472,473,478,481,487,495,499,504,505,509,517,521,524,525,529,535,539,542,543,547,553,557,560,561,565,571,575,578,579,583,589,593,598,599,603,611,615,618,619,623,629,633,636,637,641,647,651,654,655,659,665,669,672,673,677,683,687,690,691,695,701,705,708,709,713,719,723,726,727,731,737,741,744,745,749,755,759,762,763,767,773,777,780,781,785,791,795,798,799,803,809,813,816,817,821,827,831,834,835,839,845,849,852,853,857,863,867,870,871,875,881,885,888,889,893,899,903,906,907,911,917,921,924,925,930,933,935,940,949,951,952,955,958,963,972,974,975,978,981,986,995,997,998,1001,1004,1009,1018,1020,1021,1024,1027,1032,1041,1043,1044,1047,1050,1055,1064,1066,1067,1070,1073,1078,1087,1089,1090,1093,1096,1101,1110,1112,1113,1116,1119,1124,1133,1135,1136,1139,1141,1144,1154,1160,1170,1173,1174,1183,1193,1196,1197,1206,1216,1219,1220,1229,1239,1242,1243,1252,1262,1265,1266,1275,1285,1288,1289,1299,1309,1313,1314,1323,1333,1336,1337,1342,1344,1345,1348,1357,1362,1367,1373,1377,1380,1381,1390,1394,1397,1398,1407,1411,1414,1415,1424,1428,1431,1432,1441,1445,1448,1449,1458,1462,1465,1466,1475,1479,1482,1483,1492,1496,1499,1500,1509,1513,1516,1517,1526,1530,1533,1534,1543,1547,1550,1551,1560,1564,1567,1568,1577,1581,1584,1585,1594,1598,1601,1602,1611,1615,1618,1619,1628,1632,1635,1636,1645,1649,1652,1653,1662,1666,1669,1670,1679,1683,1686,1687,1696,1700,1703,1704,1713,1717,1720,1721,1726,1727,1730,1733,1743,1745 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.bhaible/alignof.h:3,8,13,16,19,21,35,49 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.bhaible/test-callback.c:18,20,27,36,39,41,55,56,58,60,64,66,70,75,78,83,96,97,99,102,106,107,110,118,125,127,137,149,165,189,192,201,211,223,239,263,294,297,306,316,328,344,367,370,381,384,396,408,421,433,444,456,469,480,490,501,513,526,542,559,580,602,612,623,635,648,664,681,702,723,726,734,742,750,758,766,774,782,790,797,800,812,824,836,848,860,873,885,901,904,914,925,937,950,964,979,995,1024,1053,1065,1078,1092,1107,1123,1140,1152,1165,1179,1194,1210,1226,1227,1253,1254,1256,1266,1269,1275,1280,1283,1286,1293,1298,1303,1310,1316,1321,1328,1334,1339,1346,1352,1357,1364,1370,1375,1382,1388,1393,1394,1397,1404,1410,1415,1422,1428,1433,1440,1446,1451,1458,1464,1469,1476,1482,1487,1494,1500,1505,1506,1507,1510,1517,1523,1528,1535,1541,1546,1553,1559,1564,1571,1577,1582,1589,1595,1600,1601,1604,1611,1617,1622,1623,1630,1637,1643,1648,1655,1661,1666,1673,1679,1684,1691,1697,1702,1709,1715,1720,1727,1733,1738,1745,1751,1756,1763,1769,1774,1781,1787,1792,1799,1805,1810,1817,1823,1828,1835,1841,1846,1853,1859,1864,1871,1877,1882,1889,1895,1900,1907,1913,1918,1925,1931,1936,1943,1949,1954,1961,1967,1972,1979,1985,1990,1997,2003,2008,2015,2021,2026,2033,2039,2044,2045,2048,2054,2065,2069,2071,2073,2079,2090,2094,2096,2098,2104,2115,2119,2121,2123,2129,2140,2144,2146,2148,2154,2165,2169,2171,2173,2179,2190,2194,2196,2198,2204,2215,2219,2221,2223,2229,2240,2244,2246,2248,2254,2265,2269,2271,2272,2283,2290,2302,2307,2314,2326,2331,2338,2350,2355,2362,2374,2379,2386,2398,2403,2410,2422,2427,2435,2447,2452,2460,2472,2479,2480,2481,2483,2492,2497,2502,2509,2515,2520,2527,2533,2538,2545,2551,2556,2563,2569,2574,2581,2587,2592,2599,2605,2610,2617,2623,2628,2635,2641,2646,2653,2659,2664,2671,2677,2682,2689,2695,2700,2707,2713,2718,2725,2731,2736,2743,2749,2754,2761,2767,2772,2779,2785,2790,2797,2803,2808,2815,2821,2826,2833,2839,2844,2851,2857,2862,2869,2875,2880,2881,2882,2884,2885 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/testsuite/libffi.bhaible/testcases.c:18,21,23,25,30,66,78,83,90,107,118,122,125,128,129,132,137,139,144,146,151,153,158,160,165,168,174,175,178,183,185,190,192,197,200,205,208,213,217,222,223,226,231,233,238,240,245,248,253,257,262,263,266,271,272,275,280,282,287,289,294,296,301,303,308,310,315,316,318,323,325,330,331,333,338,340,345,347,352,354,359,362,367,370,375,378,383,386,391,392,394,399,401,406,408,413,415,420,423,428,431,436,440,445,449,454,455,458,462,464,468,470,474,476,480,482,486,488,492,494,498,500,504,506,510,511,514,520,522,528,530,536,538,544,546,552,554,560,562,568,570,579,580,585,587,592,594,599,601,606,608,613,615,620,622,627,629,634,642,647,652,657,658,660,665,667,672,674,679,681,686,688,693,695,700,701,703,708,710,715,717,722,724,729,731,736,738,743 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/msvc_build/aarch64/aarch64_include/fficonfig.h:3,6,11,14,17,20,23,26,29,32,35,38,42,45,48,51,55,58,61,64,67,70,73,76,79,82,85,88,91,94,97,100,103,109,112,115,118,121,124,127,131,134,137,140,143,146,149,152,155,158,161,164,172,175,178,182,185,197,200,201,219 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/msvc_build/aarch64/aarch64_include/ffi.h:4,12,15,24,26,29,34,36,38,40,43,46,50,55,57,59,61,65,68,72,74,99,102,104,110,128,136,144,154,167,175,185,199,205,216,222,234,236,244,248,256,270,271,277,281,285,291,298,300,302,321,327,330,342,349,361,363,367,370,372,375,377,385,387,389,393,396,398,401,403,409,416,422,429,431,433,439,442,445,447,449,456,464,470,474,477,479,481,505,506,508,510 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/m68k/ffitarget.h:5,13,16,25,27,30,34,38,46,48,52,54 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/m68k/ffi.c:3,6,9,23,32,35,38,44,46,56,58,62,65,67,69,73,77,81,85,96,99,101,103,105,109,110,113,114,116,117,128,132,135,139,143,146,147,149,175,177,181,185,195,199,204,208,212,216,217,219,220,223,225,228,231,238,240,245,249,250,251,254,259,262,264,266,272,274,276,281,283,285,289,291,293,295,297,301,302,305,306,307,310,313,316,318,320,322,323,330,333,337,347,356,360,362 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/moxie/ffitarget.h:4,12,15,24,26,29,31,35,43,45,48,51 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/moxie/ffi.c:3,5,13,16,26,29,31,34,36,42,45,47,50,51,55,57,59,61,64,66,69,73,77,81,85,88,89,91,93,95,97,101,102,104,105,108,113,115,117,118,124,129,131,134,137,140,142,145,147,155,156,157,160,166,170,173,176,181,187,192,193,196,198,219,225,227,229,232,234,241,242,245,247,249,254,255,256,263,267,270,272,279,283,285 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/avr32/ffitarget.h:5,13,16,25,27,30,34,38,46,48,50,54 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/avr32/ffi.c:4,6,14,17,27,30,35,37,42,44,47,52,56,58,59,66,68,76,78,81,84,85,88,93,96,98,100,103,105,107,110,113,115,117,120,122,125,126,127,128,130,133,134,137,139,154,155,157,158,162,167,168,170,172,174,175,178,183,186,189,212,223,230,231,233,234,236,238,241,244,247,250,256,258,266,267,268,271,278,282,284,286,289,292,293,295,297,300,302,305,307,309,312,314,316,319,322,324,326,329,331,334,335,336,337,339,342,343,346,351,352,354,355,359,361,363,364,366,369,374,376,379,381,386,388,390,392,393,397,400,416,420,422,423 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/m88k/ffitarget.h:23,27,30,34,42,44,48 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/m88k/ffi.c:23,45,48,51,60,63,67,70,73,81,85,91,93,95,98,102,111,116,118,120,123,126,127,132,133,136,139,140,142,146,150,154,158,166,173,176,177,181,183,187,190,193,194,196,197,201,204,208,216,222,226,227,229,230,233,235,238,241,249,251,255,259,260,261,265,269,275,277,279,281,284,288,297,302,304,306,309,312,313,318,319,322,325,326,331,335,337,341,344,347,348,349,353,356,359,361,363,365,366,371,374,376,381,392,394,398,400 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/ia64/ffitarget.h:5,13,16,25,27,30,34,38,46,48,55 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/ia64/ia64_flags.h:3,5,7,15,18,28,32,35 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/ia64/ffi.c:5,7,15,18,28,31,35,37,42,47,50,51,53,55,60,61,63,66,72,73,78,81,84,87,90,93,95,104,105,106,109,112,114,126,127,128,131,134,136,138,143,145,150,152,157,160,161,162,166,169,171,173,180,186,194,196,198,200,204,209,210,212,215,216,218,219,220,222,225,227,235,239,246,248,251,253,257,259,262,263,265,268,270,272,273,276,279,280,285,288,289,291,294,298,300,304,307,311,313,336,340,344,348,350,356,365,367,371,375,377,381,385,391,392,393,396,398,401,402,403,405,406,413,421,423,430,434,438,440,445,448,451,454,461,463,464,465,469,474,479,484,487,490,510,513,519,524,527,533,538,543,549,554,556,560,564,566,571,573,577,583,584,588,591,593,595,598,599,600,602,604 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/xtensa/ffitarget.h:4,12,15,25,28,32,36,44,46,48,52 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/xtensa/ffi.c:3,5,13,16,26,29,42,44,46,47,49,50,54,56,81,83,87,88,93,95,96,98,102,115,118,121,124,126,127,131,133,161,163,166,169,172,177,181,182,185,186,187,188,189,191,196,199,205,207,210,212,214,215,218,220,223,224,227,234,238,242,247,248,249,252,257,261,263,266,269,270,274,276,279,283,285,289,290,293,294,296,298 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/closures.c:6,8,16,19,29,33,37,41,45,48,53,55,58,63,67,71,74,80,86,91,92,98,99,102,105,111,113,133,142,144,146,148,153,155,158,160,164,169,173,175,179,182,185,188,197,204,216,219,220,226,230,232,236,239,240,242,244,245,248,252,255,258,262,263,266,271,273,277,280,284,285,290,292,293,299,301,306,308,309,312,314,316,320,325,330,332,334,340,342,343,345,348,349,351,353,355,363,366,369,372,376,379,395,400,404,406,409,414,422,430,434,435,439,440,443,445,447,449,453,455,458,467,470,475,479,480,484,486,488,491,493,497,514,520,523,525,528,530,533,537,540,544,546,552,555,557,558,562,569,575,583,585,588,591,594,596,597,602,604,607,609,610,618,621,623,626,628,633,634,637,639,643,646,651,653,656,657,659,663,678,681,687,690,695,698,699,701,702,707,709,711,714,717,720,721,723,725,726,736,738,742,745,747,752,753,755,756,764,766,768,774,775,777,780,783,787,789,792,794,798,799,801,805,807,809,812,816,818,819,821,823,825,826,832,834,839,841,844,845,847,849,853,857,858,860,864,866,867,869,870,875,884,886,890,891,893,894,899,907,908,910,912,918,920,923,925,927,929,931,932,934,935,938,948,949,956,959,963,965,966,968,971,973,976,979,981,982,985,987,988,991,993,994,997 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/powerpc/ffi_sysv.c:8,10,18,21,30,32,36,37,42,43,48,50,53,55,58,59,61,65,72,80,82,86,88,89,93,101,104,107,110,121,123,125,140,148,154,157,164,168,169,176,178,180,182,186,191,199,202,206,213,224,236,243,249,252,256,264,280,283,284,285,292,296,299,302,305,308,310,311,314,316,320,323,327,331,336,341,342,344,345,348,350,369,371,374,377,379,386,389,394,401,405,408,415,429,441,448,452,458,460,462,465,470,472,481,483,487,493,495,500,505,509,512,518,525,529,532,533,535,538,541,542,544,548,554,556,565,567,572,574,578,591,596,598,605,606,607,616,617,619,622,630,631,638,640,643,655,658,662,664,665,672,681,686,694,697,699,702,709,713,714,718,722,725,727,734,744,746,749,751,754,758,760,765,767,771,775,777,783,787,792,796,798,802,804,809,813,815,818,821,826,830,832,835,838,843,847,849,852,854,859,863,865,868,870,882,884,888,892,894,900,902,905,906,908,909,911,922 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/powerpc/ffitarget.h:5,7,15,18,27,29,32,36,38,55,59,62,68,74,84,107,117,136,139,141,152,155,160,166,169,172,179,193,203 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/powerpc/ffi_linux64.c:8,10,18,21,30,32,36,37,45,46,51,53,56,58,61,62,64,65,70,72,77,80,86,89,96,98,102,118,121,122,125,126,127,128,132,138,154,160,167,171,178,182,185,196,205,210,214,216,219,227,231,232,234,236,238,242,249,251,254,264,267,274,280,285,289,293,295,298,300,319,320,321,328,336,337,346,349,352,354,355,358,363,369,374,375,380,385,391,399,400,401,404,406,435,437,440,443,445,453,456,463,468,473,478,494,513,521,525,537,539,541,545,559,561,564,570,578,584,593,602,608,616,623,627,633,635,637,643,649,652,657,661,662,665,673,678,680,689,691,695,697,707,712,715,724,732,734,737,742,744,746,757,758,760,780,790,791,792,796,797,798,801,804,812,814,815,822,825,828,840,843,849,853,855,856,857,866,872,879,881,886,889,890,899,902,904,906,914,922,930,937,940,946,949,959,967,972,979,985,987,994,996,1000,1002,1004,1007,1012,1014,1016,1018,1020,1023,1028,1030,1037,1039,1048,1051,1055,1064,1066,1068,1071,1073,1075,1080,1082,1085,1094,1096,1099,1104,1110,1116,1118,1124,1127,1130,1131,1133,1134,1136,1139,1148,1152 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/powerpc/ffi_powerpc.h:8,10,18,21,30,38,42,44,53,55,59,67,72,85,90 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/powerpc/ffi.c:8,10,18,21,30,34,39,47,49,53,59,60,65,71,72,79,83,86,92,95,103,110,113,132,133,134,137,139,140,144,146,147,154,160,161,166,175 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/powerpc/asm.h:3,5,13,16,25,27,28,36,42,76,83,92,114,117,123 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/powerpc/ffi_darwin.c:3,7,9,17,20,29,32,34,37,48,50,56,63,65,68,70,72,95,97,103,105,108,115,118,123,126,136,141,145,148,151,153,171,187,189,255,266,271,282,288,293,302,303,304,310,311,313,319,321,323,325,328,341,342,343,344,347,349,351,357,359,361,388,391,393,394,398,400,402,406,411,416,421,423,424,428,432,435,442,444,467,470,473,474,480,483,485,488,494,501,503,506,508,513,514,516,517,520,523,526,533,535,541,544,549,552,556,559,563,566,568,569,571,575,578,580,583,586,589,609,610,612,620,621,624,627,629,632,635,638,645,646,648,655,656,660,668,672,674,678,679,681,685,686,689,691,712,713,720,727,735,738,741,751,753,757,758,763,767,777,781,782,790,793,805,819,836,864,870,871,872,875,888,899,902,905,907,908,911,914,917,920,922,925,928,931,933,936,938,950,951,952,956,958,961,964,967,969,972,974,982,983,984,987,990,995,998,1000,1002,1036,1038,1045,1049,1051,1053,1055,1067,1085,1088,1090,1092,1095,1097,1105,1109,1111,1112,1117,1119,1121,1123,1128,1133,1135,1136,1139,1149,1150,1153,1159,1160,1162,1166,1170,1174,1181,1187,1191,1193,1195,1199,1208,1210,1212,1215,1219,1222,1225,1230,1231,1235,1238,1240,1250,1260,1271,1277,1281,1285,1286,1288,1294,1316,1330,1335,1340,1342,1344,1347,1352,1355,1357,1359,1366,1368,1372,1375,1377,1379,1382,1384,1390,1393,1398,1404,1406,1408,1415,1417,1418,1420,1423,1424,1428,1431,1432,1436,1439,1440 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/m32r/ffitarget.h:5,13,16,24,26,29,33,35,39,41,48,52 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/m32r/ffi.c:4,6,14,17,26,29,31,34,36,43,46,48,51,52,55,59,61,65,67,71,73,75,79,83,87,91,100,103,104,106,108,110,112,114,117,119,122,123,125,128,129,132,133,134,136,137,141,144,148,152,155,159,165,170,171,173,174,177,179,181,184,189,191,194,196,201,204,206,209,211,213,215,217,220,223,224,225,227,231,232 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/or1k/ffitarget.h:3,5,13,16,26,29,33,35,39,47,49,53,56,58 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/or1k/ffi.c:3,5,13,16,26,29,32,34,40,44,46,50,52,53,56,59,61,64,68,72,76,80,84,91,94,97,101,102,107,109,110,117,118,120,124,126,128,136,137,141,144,145,150,152,159,160,161,162,165,168,171,175,178,186,188,190,193,194,197,198,201,204,206,208,213,218,225,229,232,240,243,246,249,250,252,255,260,261,262,263,270,274,277,281,287,292,295,298,300,301,302,304,306,313,315,317,318,319,322,324,328 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/tile/ffitarget.h:4,12,15,25,28,32,34,36,39,47,50,64 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/tile/ffi.c:3,5,13,16,26,35,36,39,47,51,52,55,61,66,69,70,71,75,77,81,85,89,93,103,107,112,115,117,119,128,132,136,140,141,142,143,146,154,156,161,164,165,167,171,179,181,184,187,190,191,194,196,198,199,200,204,207,208,209,212,213,220,227,230,232,236,242,245,250,252,254,259,262,265,268,272,275,277,278,279,288,299,302,306,310,312,316,317,320,324,332,336,340,341,345,346,349,351,354,355 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/s390/ffitarget.h:5,13,16,25,27,30,34,40,42,46,54,57,59,68,70 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/s390/internal.h:7,10 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/s390/ffi.c:4,6,14,17,30,35,37,42,45,52,55,57,62,64,71,74,77,79,88,91,93,99,103,106,109,115,121,124,125,128,129,131,139,142,147,150,152,154,159,166,171,175,188,204,208,209,211,215,217,223,226,231,236,237,240,243,250,257,262,274,277,284,285,286,289,291,293,294,296,304,311,320,322,325,330,331,333,340,342,347,349,355,360,363,370,375,379,384,387,412,429,434,441,443,451,459,470,474,475,476,478,479,482,484,485,489,491,492,494,502,510,512,516,520,523,526,532,535,538,544,547,552,557,558,561,567,568,571,579,586,603,612,620,628,632,633,638,639,640,643,646,655,660,664,676,683,690,694,695,696,698,706,713,723,725,728,732,736,738,739,741,743,747,750,754,756 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/prep_cif.c:4,12,15,25,29,31,33,36,38,40,43,46,48,51,53,57,60,65,68,70,71,80,87,92,93,98,101,104,107,108,114,118,122,125,130,138,143,150,167,169,170,175,183,185,189,193,197,203,205,207,208,210,216,218,220,223,225,226,233,235,236,238,244,246,247,249,252,257,261,263 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/cris/ffitarget.h:5,13,16,25,27,30,34,38,46,48,55 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/cris/ffi.c:6,8,16,19,28,31,33,36,38,40,44,46,48,52,54,56,59,61,62,67,68,71,77,79,81,84,86,88,90,93,96,98,101,103,111,113,117,119,123,128,132,137,140,142,148,151,152,154,155,161,165,170,175,177,181,183,185,189,191,195,197,200,202,207,208,211,212,214,216,217,220,222,231,235,236,238,239,244,247,249,252,254,256,259,261,269,270,271,274,278,283,288,295,298,305,311,314,317,320,322,325,327,329,333,334,339,342,343,344,347,353,358,360,362,363,365,372,384,386 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/debug.c:3,11,14,24,29,31,33,37,38,40,42,46,47,49,51,53,63,64 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/mips/ffitarget.h:5,13,16,25,27,30,34,47,57,71,82,84,87,94,98,113,123,146,193,203,226,230,232,236,242,244 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/mips/ffi.c:5,7,15,18,28,31,34,40,48,54,62,66,67,70,75,80,92,94,100,104,105,107,109,112,117,119,122,123,126,129,135,138,140,149,150,152,156,160,164,168,172,183,188,193,194,196,200,203,206,210,212,218,219,221,225,226,227,229,235,239,242,244,247,249,253,260,264,267,269,270,273,277,284,287,290,292,297,299,306,308,312,315,319,321,322,324,327,330,335,337,339,341,346,349,350,352,356,358,363,366,367,368,369,370,371,373,375,377,382,388,393,394,396,399,406,411,415,416,418,421,427,431,433,435,437,440,443,445,448,451,453,455,458,460,469,470,472,484,486,488,495,497,504,508,509,511,512,515,517,519,523,525,530,532,533,537,544,547,550,558,563,566,568,573,578,579,581,583,584,586,588,589,593,595,596,601,606,609,611,614,617,623,625,633,639,644,650,654,660,665,668,672,673,674,677,679,680,684,686,687,688,697,704,708,725,773,775,779,786,787,811,816,819,822,824,828,829,833,835,842,849,851,853,858,863,868,873,877,879,882,883,886,888,890,897,898,900,902,903,904,906,911,914,920,926,929,931,936,942,943,944,966,973,978,980,982,989,990,994,996,1000,1003,1006,1013,1015,1017,1020,1022,1027,1030,1032,1037,1042,1047,1052,1057,1062,1065,1071,1073,1078,1079,1082,1083,1086,1088,1089,1091,1099,1103,1105,1122,1126,1128,1129 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/sh/ffitarget.h:5,13,16,25,27,30,34,36,40,48,52,54 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/sh/ffi.c:4,6,14,17,27,30,32,37,43,47,52,54,55,58,60,63,66,68,76,79,80,81,84,87,89,92,98,101,102,103,104,106,107,110,112,123,126,128,132,135,140,142,144,147,150,153,157,161,165,169,173,176,178,180,183,186,189,192,195,198,205,208,220,221,222,229,231,233,236,239,242,246,250,254,258,262,265,267,269,272,275,278,281,284,287,289,293,296,299,302,305,308,311,315,316,317,319,320,323,331,333,336,339,342,350,359,369,370,373,383,385,388,392,400,404,405,407,408,411,413,416,419,422,428,430,433,435,443,444,449,450,455,462,465,468,474,484,488,493,495,496,504,512,517,526,529,533,536,539,543,546,548,551,554,557,562,567,571,574,576,578,581,586,589,594,595,598,607,610,622,623,624,629,631,633,636,639,642,647,652,656,659,661,663,666,669,672,675,678,681,683,687,690,693,696,699,702,706,710,711,712,714,717 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/sh64/ffitarget.h:5,13,16,25,27,30,34,36,40,47,50,52,56,58 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/sh64/ffi.c:4,6,14,17,27,30,32,35,38,39,42,52,54,55,58,60,66,68,70,73,74,77,79,82,86,88,92,96,100,104,108,111,113,115,117,122,129,133,135,139,142,144,146,149,150,151,153,154,157,164,168,170,173,180,183,188,193,196,200,215,216,217,220,224,232,236,237,239,240,250,255,258,261,264,270,272,275,277,285,286,291,292,295,302,304,307,329,333,337,339,340,348,352,359,362,366,369,372,376,379,382,385,387,389,401,404,405,407,409,411,413,416,418,427,428,435,443,445,449,452,454,456,458,461,462,463,465,468,469 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/frv/ffitarget.h:5,13,16,25,27,30,34,36,40,48,50,53,61 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/frv/ffi.c:5,7,15,18,28,31,33,36,38,44,47,51,53,55,57,60,62,64,68,73,76,80,84,88,92,95,96,98,100,102,104,108,109,111,112,115,120,122,124,125,131,136,138,141,144,147,149,152,153,155,163,164,165,168,174,179,183,189,192,194,216,218,223,224,227,233,235,239,245,246,247,254,262,264,281,285,290,292 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/pa/ffitarget.h:5,13,16,25,27,30,34,36,40,43,49,55,64,66,68,71,77 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/pa/ffi.c:6,9,17,20,30,33,36,38,42,51,53,55,57,63,82,83,85,100,106,112,116,121,124,127,130,133,138,141,143,150,153,156,158,160,162,166,170,174,178,186,193,199,205,207,214,218,220,228,230,234,237,240,242,246,250,253,254,258,259,261,263,266,269,271,272,274,276,277,279,283,285,287,289,295,302,305,306,307,314,316,317,320,323,329,336,345,350,354,355,359,363,367,368,370,371,375,377,379,382,385,393,395,398,399,401,407,411,412,413,420,430,432,438,442,444,446,448,458,464,474,479,483,489,492,496,503,509,512,514,518,522,525,526,529,530,533,536,539,562,566,570,574,582,587,590,593,598,599,602,605,607,611,616,618,619,623,625,632,637,640,643,653,674,686,712,716,718 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/metag/ffitarget.h:4,12,15,24,26,29,33,37,45,47,51,53 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/metag/ffi.c:3,12,15,24,27,29,31,36,38,43,45,50,51,53,56,58,62,65,69,86,91,92,93,97,98,101,104,108,112,116,118,119,122,126,129,130,132,159,161,162,164,174,176,180,182,187,194,202,203,206,207,209,212,214,217,219,234,235,236,237,239,246,248,253,258,262,264,265,266,273,276,279,288,290,292,293,297,302,305,310,311,313,317,323,328,330 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/x86/ffitarget.h:5,7,15,18,27,29,32,36,38,41,46,51,56,58,79,91,100,126,128,131,136,145,147 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/x86/internal.h:17,20,24 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/x86/ffi64.c:6,8,16,19,29,32,37,39,42,54,56,61,63,70,73,76,82,86,99,101,103,107,110,113,117,124,128,136,146,149,150,156,162,164,175,177,179,182,184,187,189,193,195,198,201,218,224,228,231,235,239,240,243,245,247,252,256,257,259,260,262,269,273,274,277,282,288,292,293,298,302,303,305,307,310,321,325,328,338,339,340,342,343,347,351,355,359,363,382,383,386,388,389,391,396,399,405,412,414,418,462,468,470,472,478,489,490,494,519,523,524,529,533,535,538,541,543,546,547,550,553,555,556,560,566,569,574,579,580,585,587,589,594,597,599,601,606,608,612,617,619,623,625,627,638,651,663,664,665,666,668,671,672,677,680,683,686,689,690,696,700,703,706,709,710,711,714,723,730,741,748,753,756,760,762,763,771,777,782,784,791,792,795,798,803,805,809,814,820,823,826,828,831,832,835,838,841,846,847,848,849,852,855,856,859,865,869,876,882,884,885 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/x86/ffi.c:8,10,18,21,31,38,49,53,60,64,67,69,80,81,83,131,134,144,147,151,173,177,179,181,183,186,188,190,191,194,196,205,211,214,215,216,218,226,228,234,245,255,257,261,268,273,276,278,292,293,294,301,306,309,313,317,323,324,327,332,334,336,340,343,345,348,349,351,354,363,373,375,380,382,386,387,388,390,392,393,396,398,399,403,405,406,408,412,414,421,424,432,440,442,445,450,457,458,461,464,469,471,475,478,480,483,484,486,489,493,502,504,509,511,515,516,517,519,520,522,527,528,535,539,541,558,559,563,567,571,573,574,578,582,584,586,602,603,607,609,610,612,614,617,624,628,635,639,640,642,651,652,656,660,664,666,667,670,677,681,684,686,700,701,702,709,713,716,720,724,731,732,735,739,741,745,747,751,754,757,759 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/x86/ffiw64.c:4,6,14,17,27,33,39,41,48,51,54,56,58,64,65,68,81,94,96,98,106,108,109,113,118,120,123,127,132,133,138,142,145,148,149,151,153,169,170,171,173,174,177,179,180,184,186,187,188,191,198,208,210,216,217,220,224,226,227,231,233,239,240,244,246,247,249,255,265,269,273,279,283,284,286,290,292,297,302,304,305,309,310 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/x86/asmnames.h:3,11,17,23,29 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/x86/internal64.h:17,19 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/types.c:3,5,13,16,26,30,33,35,46,47,62,63,68,77,79,82,88,101 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/microblaze/ffitarget.h:3,5,13,16,26,29,33,37,45,47,50,52 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/microblaze/ffi.c:3,5,13,16,26,29,33,35,39,43,48,51,52,54,57,64,65,68,69,72,78,81,83,121,124,134,135,136,137,139,142,147,149,150,152,156,163,164,166,174,175,176,180,184,195,200,202,207,208,213,214,217,219,243,245,261,263,264,274,275,276,281,286,290,292,295,301,307,315,319,321 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/arm/ffitarget.h:5,7,15,18,27,29,32,36,40,53,58,63,65,69,71,78,88 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/arm/ffi.c:7,9,17,20,30,38,43,45,49,57,61,64,75,76,79,81,83,96,106,114,120,125,128,129,131,132,135,143,146,148,151,152,154,158,159,160,164,170,175,179,182,183,185,189,192,196,199,206,212,217,223,224,229,230,231,235,238,245,248,252,263,268,275,279,281,289,290,298,301,303,306,307,312,316,319,321,322,327,331,333,334,336,338,345,350,354,360,363,371,373,376,379,382,385,388,391,392,394,398,402,404,407,409,412,413,416,417,420,422,423,427,429,430,434,437,439,442,444,447,448,450,453,457,458,460,461,465,471,474,476,479,480,482,486,488,491,493,495,497,501,505,510,513,515,518,520,521,522,527,528,530,531,533,538,544,550,551,557,563,564,569,571,577,579,581,585,588,594,601,617,621,623,624,628,630,632,636,639,643,645,646,648,652,655,658,661,664,668,670,671,673,674,677,680,683,686,689,692,695,696,698,699,703,706,709,713,717,732,733,738,743,745,749,750,751,755,768,771,774,777,780,783,784,788,789,792,795,798,802,804,807,810,813,814,818,821,826,829,834,835,838,845,847,851,852,853 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/arc/ffitarget.h:5,13,16,24,26,29,33,35,39,41,48,52 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/arc/ffi.c:3,5,13,16,25,28,31,33,41,44,47,52,54,56,59,60,62,65,68,71,75,78,80,82,86,90,94,98,102,105,106,108,110,112,114,116,118,121,122,125,126,128,129,133,136,140,144,150,155,156,158,159,163,166,168,171,175,177,180,182,187,191,192,193,197,203,205,208,211,212,214,217,220,223,227,231,232,234,236,237,239,244,246,248,255,258,259,264,266 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/riscv/ffitarget.h:3,5,13,16,25,27,30,34,38,40,43,53,56,58,60,67,69 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/riscv/ffi.c:6,8,16,19,29,32,35,43,47,49,57,59,65,73,78,84,93,95,96,105,110,120,125,126,128,130,147,162,163,168,169,170,184,185,190,191,205,206,207,211,220,221,222,226,228,237,243,244,250,251,252,257,266,267,268,272,274,285,291,292,299,300,301,307,309,311,312,317,318,320,324,325,329,333,342,354,355,358,363,367,371,373,377,378,381,383,384,388,390,391,393,395,398,401,404,415,419,421,423,424,426,430,433,437,439,440,449,460,464,470,474,476,480,481 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/dlmalloc.c:6,8,12,14,20,34,36,43,48,54,57,66,79,90,100,106,116,125,129,131,137,150,157,162,167,170,182,185,192,194,201,203,207,211,218,222,225,230,235,238,243,254,265,276,283,287,290,303,311,317,327,331,335,343,350,354,359,364,370,376,391,414,438,440,445,466,474,482,486,489,587,594,598,600,612,623,625,629,632,645,648,652,654,656,675,676,682,692,701,708,714,718,720,723,727,731,733,738,743,747,754,767,774,785,798,803,817,824,827,836,843,848,854,860,862,875,878,881,889,895,900,906,910,914,917,928,929,933,939,940,947,950,959,966,970,973,981,986,998,1002,1007,1009,1011,1017,1030,1038,1049,1055,1059,1065,1069,1076,1082,1088,1095,1102,1108,1114,1115,1123,1129,1135,1140,1142,1146,1154,1156,1158,1162,1164,1208,1255,1257,1261,1271,1274,1277,1282,1284,1290,1291,1295,1302,1306,1328,1330,1332,1340,1341,1343,1358,1360,1361,1365,1367,1372,1373,1379,1380,1395,1397,1398,1404,1410,1416,1419,1422,1423,1425,1427,1430,1437,1441,1449,1453,1455,1465,1471,1483,1484,1485,1488,1489,1498,1504,1512,1520,1521,1523,1526,1530,1538,1543,1545,1565,1567,1595,1600,1604,1615,1620,1628,1633,1635,1647,1656,1658,1665,1672,1674,1676,1682,1687,1691,1697,1701,1705,1709,1710,1712,1720,1724,1727,1732,1735,1739,1743,1746,1750,1754,1758,1761,1765,1772,1774,1778,1781,1797,1802,1825,1833,1840,1848,1856,1863,1870,1875,1879,1882,1884,1892,1906,1914,1921,1926,1939,1947,1949,1954,1957,1959,1968,1974,1978,1982,1985,1988,1990,1994,2003,2010,2020,2026,2039,2043,2048,2051,2054,2058,2063,2073,2094,2096,2098,2104,2113,2115,2121,2123,2125,2129,2133,2136,2141,2145,2149,2154,2158,2167,2168,2169,2178,2179,2180,2186,2194,2195,2197,2203,2205,2208,2212,2216,2220,2222,2230,2232,2235,2238,2241,2243,2247,2251,2253,2255,2257,2264,2272,2286,2288,2293,2297,2312,2330,2332,2336,2341,2346,2347,2349,2352,2357,2361,2363,2370,2371,2375,2387,2390,2393,2396,2399,2400,2402,2412,2428,2438,2445,2452,2453,2464,2466,2468,2470,2475,2480,2484,2486,2490,2494,2499,2504,2508,2510,2512,2517,2525,2527,2536,2540,2543,2544,2554,2556,2567,2572,2574,2590,2592,2593,2606,2614,2615,2616,2619,2624,2625,2638,2639,2652,2653,2663,2664,2682,2685,2686,2687,2699,2700,2701,2714,2726,2738,2743,2746,2747,2751,2752,2762,2763,2784,2785,2786,2787,2800,2801,2811,2818,2819,2820,2822,2823,2840,2845,2848,2850,2851,2853,2854,2864,2870,2871,2877,2878,2882,2884,2886,2906,2908,2910,2911,2919,2920,2922,2924,2926,2938,2946,2948,2949,2950,2954,2956,2957,2958,2960,2967,2985,2986,3005,3006,3022,3023,3035,3036,3038,3089,3090,3093,3107,3177,3178,3180,3184,3188,3189,3191,3206,3208,3218,3233,3241,3242,3244,3245,3269,3276,3277,3279,3280,3282,3289,3296,3297,3305,3306,3307,3309,3324,3326,3336,3340,3347,3352,3359,3363,3364,3367,3368,3369,3386,3389,3398,3408,3410,3418,3419,3421,3422,3424,3430,3432,3438,3439,3456,3462,3475,3476,3477,3486,3487,3488,3501,3502,3503,3504,3508,3511,3512,3514,3515,3525,3526,3527,3528,3543,3544,3545,3546,3547,3549,3552,3565,3566,3567,3580,3595,3598,3599,3600,3610,3611,3612,3615,3616,3618,3638,3641,3648,3651,3652,3653,3656,3658,3659,3664,3671,3682,3683,3684,3689,3697,3698,3700,3701,3702,3708,3709,3710,3714,3718,3719,3721,3722,3724,3732,3744,3752,3754,3755,3756,3764,3765,3766,3772,3774,3775,3789,3791,3792,3794,3796,3797,3805,3808,3814,3815,3816,3828,3830,3831,3832,3835,3836,3838,3843,3850,3852,3866,3867,3878,3879,3884,3885,3887,3891,3894,3901,3903,3904,3906,3907,3909,3919,3920,3924,3925,3934,3954,3958,3963,3965,3966,3976,3977,3978,3985,3988,3990,3991,3993,3994,3996,4005,4010,4022,4029,4036,4037,4042,4048,4049,4051,4064,4068,4070,4073,4074,4083,4084,4096,4100,4101,4102,4108,4111,4113,4116,4118,4121,4122,4123,4125,4127,4148,4151,4161,4173,4174,4196,4200,4201,4205,4206,4207,4215,4216,4217,4226,4232,4236,4237,4248,4249,4251,4255,4256,4258,4259,4266,4274,4291,4299,4304,4305,4308,4309,4310,4320,4324,4330,4339,4340,4341,4347,4348,4353,4354,4358,4359,4368,4373,4374,4382,4392,4395,4396,4397,4400,4401,4406,4407,4411,4412,4418,4419,4425,4426,4432,4434,4435,4438,4439,4442,4443,4447,4449,4452,4453,4459,4461,4462,4465,4466,4468,4470,4472,4491,4492,4497,4507,4508,4510,4511,4516,4522,4524,4525,4539,4540,4543,4545,4546,4551,4552,4558,4568,4580,4581,4603,4607,4608,4612,4613,4614,4622,4623,4624,4633,4639,4643,4644,4655,4656,4658,4662,4663,4665,4666,4678,4692,4700,4705,4706,4709,4710,4711,4721,4725,4731,4740,4741,4742,4748,4749,4754,4755,4756,4757,4765,4771,4776,4777,4785,4797,4799,4800,4801,4807,4809,4810,4818,4820,4821,4828,4830,4831,4839,4840,4843,4845,4846,4851,4854,4855,4856,4862,4865,4866,4867,4873,4876,4877,4878,4884,4886,4888,4891,4892,4894,4896,4899,4918,4925,4927,4930,4935,4937,4940,4942,4948,4950,4957,4959,4962,4964,4966,4967,4968,4971,4973,4975,4978,4981,4982,4983,4985,4986,5001,5004,5008,5024,5027,5040,5064,5080,5083,5092,5113,5124,5128,5132,5134,5143,5152,5161,5165 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/alpha/ffitarget.h:5,13,16,25,27,30,34,38,46,49,51,56 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/alpha/internal.h:7,19 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/alpha/ffi.c:4,6,14,17,27,32,43,49,53,57,58,61,63,64,67,71,74,77,80,97,103,111,114,115,116,120,160,173,177,179,187,189,190,193,195,204,209,215,221,224,225,226,230,235,240,245,249,252,254,259,261,277,283,290,295,302,305,306,307,310,311,314,316,317,321,323,324,331,333,336,343,347,349,352,355,357,358,363,366,370,372,373,379,383,387,391,394,395,397,400,405,407,420,426,431,434,437,443,450,454,459,472,477,480,486,493,497,499,502,505,508,511,512,514,515,518,521 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/aarch64/ffitarget.h:2,10,13,21,24,28,43,45,52,54,57,59,66,71,75,77,86,91 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/aarch64/internal.h:9,12,20,24,30,37,42,47,52,56,58,61,64 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/aarch64/ffi.c:2,10,13,21,33,44,46,50,52,55,57,61,63,67,69,73,76,86,87,89,93,96,99,102,105,109,111,112,114,115,118,121,124,127,130,133,136,137,139,140,145,148,151,155,159,170,176,180,181,186,191,193,197,198,199,203,221,224,227,230,233,236,237,241,242,245,248,250,254,259,263,270,271,276,278,288,291,293,294,297,299,321,322,323,329,332,379,381,387,389,392,396,417,420,424,445,450,452,454,458,463,466,469,470,473,477,479,509,517,520,523,530,532,535,536,539,542,543,550,552,553,559,563,565,569,575,582,587,593,596,601,607,610,615,618,622,636,641,652,653,655,661,663,666,670,672,677,680,682,685,690,694,696,698,706,708,711,718,720,727,728,730,732,735,736,739,743,745,746,748,751,752,755,757,758,763,765,767,769,772,779,782,784,789,803,805,807,809,820,824,826,827,831,835,837,840,845,849,851,853,855,862,865,869,876,880,882,884,888,890,894,907,915,919,921,924,933,935,940,941,943,946,950,952,956,958,960,962,968,970,973,976,978,982,983,985,988,989,992,996,998,999,1003,1005,1007,1008 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/sparc/ffitarget.h:5,13,16,25,27,30,34,36,42,46,59,62,67,69,73,79,81 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/sparc/internal.h:12,21,25 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/sparc/ffi64.c:4,6,14,17,27,32,43,45,49,53,56,59,61,64,70,72,74,77,80,98,100,101,104,106,107,110,113,117,123,126,130,132,133,134,136,139,143,149,152,156,158,159,161,164,169,172,185,189,192,194,199,201,205,207,212,213,216,225,226,228,253,256,257,260,264,266,271,274,286,289,290,295,298,301,305,306,309,312,313,316,319,320,323,326,329,333,335,337,342,344,347,348,349,355,358,361,365,367,394,400,404,410,413,414,415,417,418,422,424,426,429,431,432,435,437,438,442,444,445,449,451,455,458,465,468,471,480,484,486,488,489,493,496,500,502,503,509,513,518,520,524,528,531,534,539,542,549,552,555,559,560,562,577,595,598,600,601,604,607 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/sparc/ffi.c:4,6,14,17,27,32,34,45,49,54,57,97,126,130,132,135,139,141,148,154,157,159,160,165,168,171,175,177,178,181,184,188,190,192,197,199,202,203,204,208,214,217,222,224,230,237,245,258,265,268,270,273,275,278,279,280,282,283,287,289,291,297,299,300,303,305,306,310,312,313,317,321,325,328,335,339,342,347,351,353,355,356,360,363,367,369,370,376,380,385,390,394,395,398,401,406,408,415,420,425,428,443,454,457,460,461,464,467 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/java_raw_api.c:3,5,8,10,18,21,31,37,41,43,46,49,51,53,68,69,70,72,73,74,77,80,82,84,86,91,96,105,109,113,118,119,120,122,124,127,141,147,148,152,154,155,158,161,163,165,173,181,189,197,205,213,217,226,230,239,240,241,242,244,247,250,256,266,270,273,275,276,279,282,288,295,299,302,304,305,312,315,320,321,323,327,330,334,335,342,344,351,354,355,357,358,362,368,370,371 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/vax/ffitarget.h:23,27,30,34,42,44,48 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/vax/ffi.c:23,30,33,36,41,45,49,52,58,60,66,68,72,74,77,79,83,87,91,95,99,102,104,106,108,112,113,116,117,119,120,123,126,130,134,137,138,150,157,158,160,161,164,166,169,172,179,181,185,189,190,191,195,199,202,206,208,210,212,215,219,222,223,224,227,230,233,235,237,239,240,245,248,250,258,264,270,274,276 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/bfin/ffitarget.h:3,5,13,16,26,29,33,41,43 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/bfin/ffi.c:4,6,14,17,29,32,35,44,49,54,56,61,62,66,68,104,109,111,112,121,127,135,136,137,138,145,164,170,184,189,192,193,194,195,196 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/raw_api.c:3,5,13,16,26,28,31,33,36,39,41,43,50,51,53,54,55,58,61,63,65,67,72,77,84,90,94,98,102,103,104,106,108,111,114,116,120,122,124,127,128,129,133,135,136,139,142,144,146,150,154,158,162,167,172,178,182,186,190,191,192,193,195,196,203,205,209,210,212,216,219,222,223,230,232,239,242,243,245,246,249,251,255,261,263,264,266 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/nios2/ffitarget.h:2,4,12,15,23,24,27,31,35,43,47,51 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/libffi/src/nios2/ffi.c:2,4,12,15,23,24,27,29,32,37,41,44,48,49,51,57,59,61,70,72,73,74,80,82,85,90,93,94,96,101,105,109,112,116,120,124,128,132,135,136,142,143,144,145,149,151,152,155,161,164,171,173,179,195,196,197,201,205,212,218,221,224,227,230,234,238,242,243,247,248,249,258,261,264,279,291,297,301,303,304 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/FunctionInfo.c:29,35,42,45,49,55,60,62,65,68,76,78,79,82,88,89,90,93,100,102,103,117,126,132,133,135,145,149,153,154,158,159,162,163,168,169,174,175,178,179,182,183,191,203,204,206,208,209,217,219,221,223,224,232,234,236,238,239,242,244,246,264,269,270,271 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/Pointer.h:29,32,38,42,44,49,57,59,61,63 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/ClosurePool.c:28,53,60,66,68,69,76,82,91,93,97,102,104,110,112,113,116,118,125,127,128,131,136,137,138,139,142,150,155,157,158,164,168,169,175,178,179,180,183,184,190,195,198,204,205,206,209,210,213,223,224,225,226,229,231,232,233,236,244,245,248,255,256,259,265,266,269,276,277,280,282,283 ./vendor/bundle/ruby/2.6.0/gems/ffi-1.12.2/ext/ffi_c/StructByValue.c:29,44,48,52,54,59,61,64,66,68,72,77,79,80,83,87,91,92,97,100,102,103,106,109,110,113,116,117,118,121,123,126,127,130,132,134,136,137,140,144,149,150 ./vendor/bundle/ruby/2.6.0/gems/xcpretty-0.3.0/spec/fixtures/NSStringTests.m:8,11,13,15,17,20,22,24,26,30,34,38,42,44,48,53,55,59,61,62,63 ./vendor/bundle/ruby/2.6.0/gems/rake-13.0.1/doc/example/a.c:2,4,6 ./vendor/bundle/ruby/2.6.0/gems/rake-13.0.1/doc/example/main.c:2,5,7,11 ./vendor/bundle/ruby/2.6.0/gems/rake-13.0.1/doc/example/b.c:2,4,6 <<<<<< EOF