├── .gitignore
├── Resources
├── bar-chart-screenshot.png
├── bar-chart-screenshot-2.png
└── Package.swift
├── Examples
├── BarChartExample-iOS
│ ├── BarChartExample-iOS
│ │ ├── Assets.xcassets
│ │ │ ├── Contents.json
│ │ │ └── AppIcon.appiconset
│ │ │ │ └── Contents.json
│ │ ├── Preview Content
│ │ │ └── Preview Assets.xcassets
│ │ │ │ └── Contents.json
│ │ ├── Base.lproj
│ │ │ └── LaunchScreen.storyboard
│ │ ├── Info.plist
│ │ ├── AppDelegate.swift
│ │ ├── SceneDelegate.swift
│ │ └── ContentView.swift
│ └── BarChartExample-iOS.xcodeproj
│ │ └── project.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
├── BarChartExample-tvOS
│ ├── BarChartExample-tvOS
│ │ ├── Assets.xcassets
│ │ │ ├── Contents.json
│ │ │ └── App Icon & Top Shelf Image.brandassets
│ │ │ │ ├── App Icon.imagestack
│ │ │ │ ├── Back.imagestacklayer
│ │ │ │ │ ├── Contents.json
│ │ │ │ │ └── Content.imageset
│ │ │ │ │ │ └── Contents.json
│ │ │ │ ├── Front.imagestacklayer
│ │ │ │ │ ├── Contents.json
│ │ │ │ │ └── Content.imageset
│ │ │ │ │ │ └── Contents.json
│ │ │ │ ├── Middle.imagestacklayer
│ │ │ │ │ ├── Contents.json
│ │ │ │ │ └── Content.imageset
│ │ │ │ │ │ └── Contents.json
│ │ │ │ └── Contents.json
│ │ │ │ ├── App Icon - App Store.imagestack
│ │ │ │ ├── Back.imagestacklayer
│ │ │ │ │ ├── Contents.json
│ │ │ │ │ └── Content.imageset
│ │ │ │ │ │ └── Contents.json
│ │ │ │ ├── Front.imagestacklayer
│ │ │ │ │ ├── Contents.json
│ │ │ │ │ └── Content.imageset
│ │ │ │ │ │ └── Contents.json
│ │ │ │ ├── Middle.imagestacklayer
│ │ │ │ │ ├── Contents.json
│ │ │ │ │ └── Content.imageset
│ │ │ │ │ │ └── Contents.json
│ │ │ │ └── Contents.json
│ │ │ │ ├── Top Shelf Image.imageset
│ │ │ │ └── Contents.json
│ │ │ │ ├── Top Shelf Image Wide.imageset
│ │ │ │ └── Contents.json
│ │ │ │ └── Contents.json
│ │ ├── Preview Content
│ │ │ └── Preview Assets.xcassets
│ │ │ │ └── Contents.json
│ │ ├── Info.plist
│ │ ├── Base.lproj
│ │ │ └── LaunchScreen.storyboard
│ │ ├── AppDelegate.swift
│ │ └── ContentView.swift
│ └── BarChartExample-tvOS.xcodeproj
│ │ ├── project.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ │ └── IDEWorkspaceChecks.plist
│ │ └── project.pbxproj
├── BarChartExample-macOS
│ ├── BarChartExample-macOS
│ │ ├── Assets.xcassets
│ │ │ ├── Contents.json
│ │ │ └── AppIcon.appiconset
│ │ │ │ └── Contents.json
│ │ ├── Preview Content
│ │ │ └── Preview Assets.xcassets
│ │ │ │ └── Contents.json
│ │ ├── BarChartExample_macOS.entitlements
│ │ ├── Info.plist
│ │ ├── AppDelegate.swift
│ │ └── ContentView.swift
│ └── BarChartExample-macOS.xcodeproj
│ │ ├── project.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ │ └── IDEWorkspaceChecks.plist
│ │ └── project.pbxproj
├── BarChartExample-watchOS
│ ├── BarChartExample-watchOS WatchKit App
│ │ ├── Assets.xcassets
│ │ │ ├── Contents.json
│ │ │ └── AppIcon.appiconset
│ │ │ │ └── Contents.json
│ │ ├── Base.lproj
│ │ │ └── Interface.storyboard
│ │ └── Info.plist
│ ├── BarChartExample-watchOS WatchKit Extension
│ │ ├── Assets.xcassets
│ │ │ ├── Contents.json
│ │ │ └── Complication.complicationset
│ │ │ │ ├── Circular.imageset
│ │ │ │ └── Contents.json
│ │ │ │ ├── Modular.imageset
│ │ │ │ └── Contents.json
│ │ │ │ ├── Extra Large.imageset
│ │ │ │ └── Contents.json
│ │ │ │ ├── Graphic Bezel.imageset
│ │ │ │ └── Contents.json
│ │ │ │ ├── Graphic Corner.imageset
│ │ │ │ └── Contents.json
│ │ │ │ ├── Utilitarian.imageset
│ │ │ │ └── Contents.json
│ │ │ │ ├── Graphic Circular.imageset
│ │ │ │ └── Contents.json
│ │ │ │ ├── Graphic Large Rectangular.imageset
│ │ │ │ └── Contents.json
│ │ │ │ └── Contents.json
│ │ ├── Preview Content
│ │ │ └── Preview Assets.xcassets
│ │ │ │ └── Contents.json
│ │ ├── Info.plist
│ │ ├── HostingController.swift
│ │ ├── ContentView.swift
│ │ └── ExtensionDelegate.swift
│ └── BarChartExample-watchOS.xcodeproj
│ │ └── project.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
├── SelectableBarChartExample-iOS
│ ├── SelectableBarChartExample-iOS
│ │ ├── Assets.xcassets
│ │ │ ├── Contents.json
│ │ │ └── AppIcon.appiconset
│ │ │ │ └── Contents.json
│ │ ├── Preview Content
│ │ │ └── Preview Assets.xcassets
│ │ │ │ └── Contents.json
│ │ ├── Base.lproj
│ │ │ └── LaunchScreen.storyboard
│ │ ├── Info.plist
│ │ ├── MiniSelectionIndicator.swift
│ │ ├── SelectionLine.swift
│ │ ├── AppDelegate.swift
│ │ ├── SelectionIndicator.swift
│ │ ├── SceneDelegate.swift
│ │ └── ContentView.swift
│ └── SelectableBarChartExample-iOS.xcodeproj
│ │ └── project.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
└── Package.swift
├── LICENSE
├── Package.swift
├── README.md
├── Sources
└── BarChart
│ ├── GradientColor.swift
│ ├── Extension+Decimals.swift
│ ├── ChartData.swift
│ ├── BarChartCell.swift
│ ├── Extension+StringSize.swift
│ ├── ChartConfiguration.swift
│ ├── Extension+ViewModifiers.swift
│ ├── AxisBase.swift
│ ├── XAxisLayout.swift
│ ├── BarShape.swift
│ ├── XAxis.swift
│ ├── YAxis.swift
│ ├── BarChartView.swift
│ ├── BarChartCollectionView.swift
│ ├── YAxisScaler.swift
│ └── CoordinateSystemView.swift
└── Tests
└── BarChartTests
├── XAxisTests.swift
└── TestData.swift
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | /.build
3 | /Packages
4 | /*.xcodeproj
5 | xcuserdata/
6 | .swiftpm
--------------------------------------------------------------------------------
/Resources/bar-chart-screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/romanbaitaliuk/BarChart/HEAD/Resources/bar-chart-screenshot.png
--------------------------------------------------------------------------------
/Resources/bar-chart-screenshot-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/romanbaitaliuk/BarChart/HEAD/Resources/bar-chart-screenshot-2.png
--------------------------------------------------------------------------------
/Examples/BarChartExample-iOS/BarChartExample-iOS/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Examples/BarChartExample-tvOS/BarChartExample-tvOS/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Examples/BarChartExample-macOS/BarChartExample-macOS/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Examples/BarChartExample-watchOS/BarChartExample-watchOS WatchKit App/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Examples/SelectableBarChartExample-iOS/SelectableBarChartExample-iOS/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Examples/BarChartExample-iOS/BarChartExample-iOS/Preview Content/Preview Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Examples/BarChartExample-macOS/BarChartExample-macOS/Preview Content/Preview Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Examples/BarChartExample-tvOS/BarChartExample-tvOS/Preview Content/Preview Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Examples/BarChartExample-watchOS/BarChartExample-watchOS WatchKit Extension/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Examples/SelectableBarChartExample-iOS/SelectableBarChartExample-iOS/Preview Content/Preview Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Examples/BarChartExample-watchOS/BarChartExample-watchOS WatchKit Extension/Preview Content/Preview Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Examples/BarChartExample-tvOS/BarChartExample-tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Back.imagestacklayer/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Examples/BarChartExample-tvOS/BarChartExample-tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Front.imagestacklayer/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Examples/BarChartExample-tvOS/BarChartExample-tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Middle.imagestacklayer/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Examples/BarChartExample-tvOS/BarChartExample-tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Back.imagestacklayer/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Examples/BarChartExample-tvOS/BarChartExample-tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Front.imagestacklayer/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Examples/BarChartExample-tvOS/BarChartExample-tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Middle.imagestacklayer/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Examples/BarChartExample-iOS/BarChartExample-iOS.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Examples/BarChartExample-tvOS/BarChartExample-tvOS.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Examples/BarChartExample-macOS/BarChartExample-macOS.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Examples/BarChartExample-watchOS/BarChartExample-watchOS.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Examples/SelectableBarChartExample-iOS/SelectableBarChartExample-iOS.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Examples/Package.swift:
--------------------------------------------------------------------------------
1 | // swift-tools-version:5.2
2 | // The swift-tools-version declares the minimum version of Swift required to build this package.
3 |
4 | import PackageDescription
5 |
6 | let package = Package(
7 | name: "Examples",
8 | products: [],
9 | targets: []
10 | )
11 |
--------------------------------------------------------------------------------
/Resources/Package.swift:
--------------------------------------------------------------------------------
1 | // swift-tools-version:5.2
2 | // The swift-tools-version declares the minimum version of Swift required to build this package.
3 |
4 | import PackageDescription
5 |
6 | let package = Package(
7 | name: "Resources",
8 | products: [],
9 | targets: []
10 | )
11 |
--------------------------------------------------------------------------------
/Examples/BarChartExample-tvOS/BarChartExample-tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Back.imagestacklayer/Content.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "tv"
5 | }
6 | ],
7 | "info" : {
8 | "author" : "xcode",
9 | "version" : 1
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Examples/BarChartExample-tvOS/BarChartExample-tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Front.imagestacklayer/Content.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "tv"
5 | }
6 | ],
7 | "info" : {
8 | "author" : "xcode",
9 | "version" : 1
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Examples/BarChartExample-tvOS/BarChartExample-tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "tv"
5 | }
6 | ],
7 | "info" : {
8 | "author" : "xcode",
9 | "version" : 1
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Examples/BarChartExample-iOS/BarChartExample-iOS.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Examples/BarChartExample-tvOS/BarChartExample-tvOS.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Examples/BarChartExample-macOS/BarChartExample-macOS.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Examples/BarChartExample-watchOS/BarChartExample-watchOS.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Examples/SelectableBarChartExample-iOS/SelectableBarChartExample-iOS.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Examples/BarChartExample-tvOS/BarChartExample-tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Back.imagestacklayer/Content.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "tv",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "tv",
9 | "scale" : "2x"
10 | }
11 | ],
12 | "info" : {
13 | "author" : "xcode",
14 | "version" : 1
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Examples/BarChartExample-tvOS/BarChartExample-tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Front.imagestacklayer/Content.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "tv",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "tv",
9 | "scale" : "2x"
10 | }
11 | ],
12 | "info" : {
13 | "author" : "xcode",
14 | "version" : 1
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Examples/BarChartExample-tvOS/BarChartExample-tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "tv",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "tv",
9 | "scale" : "2x"
10 | }
11 | ],
12 | "info" : {
13 | "author" : "xcode",
14 | "version" : 1
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Examples/BarChartExample-macOS/BarChartExample-macOS/BarChartExample_macOS.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | com.apple.security.app-sandbox
6 |
7 | com.apple.security.files.user-selected.read-only
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/Examples/BarChartExample-tvOS/BarChartExample-tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | },
6 | "layers" : [
7 | {
8 | "filename" : "Front.imagestacklayer"
9 | },
10 | {
11 | "filename" : "Middle.imagestacklayer"
12 | },
13 | {
14 | "filename" : "Back.imagestacklayer"
15 | }
16 | ]
17 | }
18 |
--------------------------------------------------------------------------------
/Examples/BarChartExample-tvOS/BarChartExample-tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | },
6 | "layers" : [
7 | {
8 | "filename" : "Front.imagestacklayer"
9 | },
10 | {
11 | "filename" : "Middle.imagestacklayer"
12 | },
13 | {
14 | "filename" : "Back.imagestacklayer"
15 | }
16 | ]
17 | }
18 |
--------------------------------------------------------------------------------
/Examples/BarChartExample-tvOS/BarChartExample-tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "tv",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "tv",
9 | "scale" : "2x"
10 | },
11 | {
12 | "idiom" : "tv-marketing",
13 | "scale" : "1x"
14 | },
15 | {
16 | "idiom" : "tv-marketing",
17 | "scale" : "2x"
18 | }
19 | ],
20 | "info" : {
21 | "author" : "xcode",
22 | "version" : 1
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/Examples/BarChartExample-tvOS/BarChartExample-tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image Wide.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "tv",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "tv",
9 | "scale" : "2x"
10 | },
11 | {
12 | "idiom" : "tv-marketing",
13 | "scale" : "1x"
14 | },
15 | {
16 | "idiom" : "tv-marketing",
17 | "scale" : "2x"
18 | }
19 | ],
20 | "info" : {
21 | "author" : "xcode",
22 | "version" : 1
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/Examples/BarChartExample-watchOS/BarChartExample-watchOS WatchKit Extension/Assets.xcassets/Complication.complicationset/Circular.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "watch",
5 | "scale" : "2x",
6 | "screen-width" : "<=145"
7 | },
8 | {
9 | "idiom" : "watch",
10 | "scale" : "2x",
11 | "screen-width" : ">161"
12 | },
13 | {
14 | "idiom" : "watch",
15 | "scale" : "2x",
16 | "screen-width" : ">145"
17 | },
18 | {
19 | "idiom" : "watch",
20 | "scale" : "2x",
21 | "screen-width" : ">183"
22 | }
23 | ],
24 | "info" : {
25 | "author" : "xcode",
26 | "version" : 1
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/Examples/BarChartExample-watchOS/BarChartExample-watchOS WatchKit Extension/Assets.xcassets/Complication.complicationset/Modular.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "watch",
5 | "scale" : "2x",
6 | "screen-width" : "<=145"
7 | },
8 | {
9 | "idiom" : "watch",
10 | "scale" : "2x",
11 | "screen-width" : ">161"
12 | },
13 | {
14 | "idiom" : "watch",
15 | "scale" : "2x",
16 | "screen-width" : ">145"
17 | },
18 | {
19 | "idiom" : "watch",
20 | "scale" : "2x",
21 | "screen-width" : ">183"
22 | }
23 | ],
24 | "info" : {
25 | "author" : "xcode",
26 | "version" : 1
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/Examples/BarChartExample-watchOS/BarChartExample-watchOS WatchKit Extension/Assets.xcassets/Complication.complicationset/Extra Large.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "watch",
5 | "scale" : "2x",
6 | "screen-width" : "<=145"
7 | },
8 | {
9 | "idiom" : "watch",
10 | "scale" : "2x",
11 | "screen-width" : ">161"
12 | },
13 | {
14 | "idiom" : "watch",
15 | "scale" : "2x",
16 | "screen-width" : ">145"
17 | },
18 | {
19 | "idiom" : "watch",
20 | "scale" : "2x",
21 | "screen-width" : ">183"
22 | }
23 | ],
24 | "info" : {
25 | "author" : "xcode",
26 | "version" : 1
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/Examples/BarChartExample-watchOS/BarChartExample-watchOS WatchKit Extension/Assets.xcassets/Complication.complicationset/Graphic Bezel.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "watch",
5 | "scale" : "2x",
6 | "screen-width" : "<=145"
7 | },
8 | {
9 | "idiom" : "watch",
10 | "scale" : "2x",
11 | "screen-width" : ">161"
12 | },
13 | {
14 | "idiom" : "watch",
15 | "scale" : "2x",
16 | "screen-width" : ">145"
17 | },
18 | {
19 | "idiom" : "watch",
20 | "scale" : "2x",
21 | "screen-width" : ">183"
22 | }
23 | ],
24 | "info" : {
25 | "author" : "xcode",
26 | "version" : 1
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/Examples/BarChartExample-watchOS/BarChartExample-watchOS WatchKit Extension/Assets.xcassets/Complication.complicationset/Graphic Corner.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "watch",
5 | "scale" : "2x",
6 | "screen-width" : "<=145"
7 | },
8 | {
9 | "idiom" : "watch",
10 | "scale" : "2x",
11 | "screen-width" : ">161"
12 | },
13 | {
14 | "idiom" : "watch",
15 | "scale" : "2x",
16 | "screen-width" : ">145"
17 | },
18 | {
19 | "idiom" : "watch",
20 | "scale" : "2x",
21 | "screen-width" : ">183"
22 | }
23 | ],
24 | "info" : {
25 | "author" : "xcode",
26 | "version" : 1
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/Examples/BarChartExample-watchOS/BarChartExample-watchOS WatchKit Extension/Assets.xcassets/Complication.complicationset/Utilitarian.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "watch",
5 | "scale" : "2x",
6 | "screen-width" : "<=145"
7 | },
8 | {
9 | "idiom" : "watch",
10 | "scale" : "2x",
11 | "screen-width" : ">161"
12 | },
13 | {
14 | "idiom" : "watch",
15 | "scale" : "2x",
16 | "screen-width" : ">145"
17 | },
18 | {
19 | "idiom" : "watch",
20 | "scale" : "2x",
21 | "screen-width" : ">183"
22 | }
23 | ],
24 | "info" : {
25 | "author" : "xcode",
26 | "version" : 1
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/Examples/BarChartExample-watchOS/BarChartExample-watchOS WatchKit Extension/Assets.xcassets/Complication.complicationset/Graphic Circular.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "watch",
5 | "scale" : "2x",
6 | "screen-width" : "<=145"
7 | },
8 | {
9 | "idiom" : "watch",
10 | "scale" : "2x",
11 | "screen-width" : ">161"
12 | },
13 | {
14 | "idiom" : "watch",
15 | "scale" : "2x",
16 | "screen-width" : ">145"
17 | },
18 | {
19 | "idiom" : "watch",
20 | "scale" : "2x",
21 | "screen-width" : ">183"
22 | }
23 | ],
24 | "info" : {
25 | "author" : "xcode",
26 | "version" : 1
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/Examples/BarChartExample-watchOS/BarChartExample-watchOS WatchKit Extension/Assets.xcassets/Complication.complicationset/Graphic Large Rectangular.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "watch",
5 | "scale" : "2x",
6 | "screen-width" : "<=145"
7 | },
8 | {
9 | "idiom" : "watch",
10 | "scale" : "2x",
11 | "screen-width" : ">161"
12 | },
13 | {
14 | "idiom" : "watch",
15 | "scale" : "2x",
16 | "screen-width" : ">145"
17 | },
18 | {
19 | "idiom" : "watch",
20 | "scale" : "2x",
21 | "screen-width" : ">183"
22 | }
23 | ],
24 | "info" : {
25 | "author" : "xcode",
26 | "version" : 1
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/Examples/BarChartExample-tvOS/BarChartExample-tvOS/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "assets" : [
3 | {
4 | "filename" : "App Icon - App Store.imagestack",
5 | "idiom" : "tv",
6 | "role" : "primary-app-icon",
7 | "size" : "1280x768"
8 | },
9 | {
10 | "filename" : "App Icon.imagestack",
11 | "idiom" : "tv",
12 | "role" : "primary-app-icon",
13 | "size" : "400x240"
14 | },
15 | {
16 | "filename" : "Top Shelf Image Wide.imageset",
17 | "idiom" : "tv",
18 | "role" : "top-shelf-image-wide",
19 | "size" : "2320x720"
20 | },
21 | {
22 | "filename" : "Top Shelf Image.imageset",
23 | "idiom" : "tv",
24 | "role" : "top-shelf-image",
25 | "size" : "1920x720"
26 | }
27 | ],
28 | "info" : {
29 | "author" : "xcode",
30 | "version" : 1
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/Examples/BarChartExample-watchOS/BarChartExample-watchOS WatchKit App/Base.lproj/Interface.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/Examples/BarChartExample-tvOS/BarChartExample-tvOS/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | UILaunchStoryboardName
24 | LaunchScreen
25 | UIRequiredDeviceCapabilities
26 |
27 | arm64
28 |
29 | UIUserInterfaceStyle
30 | Automatic
31 |
32 |
33 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 | -----------
3 |
4 | Copyright (c) 2020 Roman Baitaliuk
5 | Permission is hereby granted, free of charge, to any person
6 | obtaining a copy of this software and associated documentation
7 | files (the "Software"), to deal in the Software without
8 | restriction, including without limitation the rights to use,
9 | copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the
11 | Software is furnished to do so, subject to the following
12 | conditions:
13 |
14 | The above copyright notice and this permission notice shall be
15 | included in all copies or substantial portions of the Software.
16 |
17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
19 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
21 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
22 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
24 | OTHER DEALINGS IN THE SOFTWARE.
25 |
--------------------------------------------------------------------------------
/Examples/BarChartExample-watchOS/BarChartExample-watchOS WatchKit App/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleDisplayName
8 | BarChartExample-watchOS WatchKit App
9 | CFBundleExecutable
10 | $(EXECUTABLE_NAME)
11 | CFBundleIdentifier
12 | $(PRODUCT_BUNDLE_IDENTIFIER)
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | $(PRODUCT_NAME)
17 | CFBundlePackageType
18 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
19 | CFBundleShortVersionString
20 | 1.0
21 | CFBundleVersion
22 | 1
23 | UISupportedInterfaceOrientations
24 |
25 | UIInterfaceOrientationPortrait
26 | UIInterfaceOrientationPortraitUpsideDown
27 |
28 | WKWatchKitApp
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/Package.swift:
--------------------------------------------------------------------------------
1 | // swift-tools-version:5.2
2 | // The swift-tools-version declares the minimum version of Swift required to build this package.
3 |
4 | import PackageDescription
5 |
6 | let package = Package(
7 | name: "BarChart",
8 | platforms: [
9 | .iOS(.v13), .macOS(.v10_15), .watchOS(.v6), .tvOS(.v13)
10 | ],
11 | products: [
12 | // Products define the executables and libraries produced by a package, and make them visible to other packages.
13 | .library(
14 | name: "BarChart",
15 | targets: ["BarChart"]),
16 | ],
17 | dependencies: [
18 | // Dependencies declare other packages that this package depends on.
19 | // .package(url: /* package url */, from: "1.0.0"),
20 | ],
21 | targets: [
22 | // Targets are the basic building blocks of a package. A target can define a module or a test suite.
23 | // Targets can depend on other targets in this package, and on products in packages which this package depends on.
24 | .target(
25 | name: "BarChart",
26 | dependencies: []),
27 | .testTarget(
28 | name: "BarChartTests",
29 | dependencies: ["BarChart"]),
30 | ]
31 | )
32 |
--------------------------------------------------------------------------------
/Examples/BarChartExample-macOS/BarChartExample-macOS/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "mac",
5 | "scale" : "1x",
6 | "size" : "16x16"
7 | },
8 | {
9 | "idiom" : "mac",
10 | "scale" : "2x",
11 | "size" : "16x16"
12 | },
13 | {
14 | "idiom" : "mac",
15 | "scale" : "1x",
16 | "size" : "32x32"
17 | },
18 | {
19 | "idiom" : "mac",
20 | "scale" : "2x",
21 | "size" : "32x32"
22 | },
23 | {
24 | "idiom" : "mac",
25 | "scale" : "1x",
26 | "size" : "128x128"
27 | },
28 | {
29 | "idiom" : "mac",
30 | "scale" : "2x",
31 | "size" : "128x128"
32 | },
33 | {
34 | "idiom" : "mac",
35 | "scale" : "1x",
36 | "size" : "256x256"
37 | },
38 | {
39 | "idiom" : "mac",
40 | "scale" : "2x",
41 | "size" : "256x256"
42 | },
43 | {
44 | "idiom" : "mac",
45 | "scale" : "1x",
46 | "size" : "512x512"
47 | },
48 | {
49 | "idiom" : "mac",
50 | "scale" : "2x",
51 | "size" : "512x512"
52 | }
53 | ],
54 | "info" : {
55 | "author" : "xcode",
56 | "version" : 1
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/Examples/BarChartExample-watchOS/BarChartExample-watchOS WatchKit Extension/Assets.xcassets/Complication.complicationset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "assets" : [
3 | {
4 | "filename" : "Circular.imageset",
5 | "idiom" : "watch",
6 | "role" : "circular"
7 | },
8 | {
9 | "filename" : "Extra Large.imageset",
10 | "idiom" : "watch",
11 | "role" : "extra-large"
12 | },
13 | {
14 | "filename" : "Graphic Bezel.imageset",
15 | "idiom" : "watch",
16 | "role" : "graphic-bezel"
17 | },
18 | {
19 | "filename" : "Graphic Circular.imageset",
20 | "idiom" : "watch",
21 | "role" : "graphic-circular"
22 | },
23 | {
24 | "filename" : "Graphic Corner.imageset",
25 | "idiom" : "watch",
26 | "role" : "graphic-corner"
27 | },
28 | {
29 | "filename" : "Graphic Large Rectangular.imageset",
30 | "idiom" : "watch",
31 | "role" : "graphic-large-rectangular"
32 | },
33 | {
34 | "filename" : "Modular.imageset",
35 | "idiom" : "watch",
36 | "role" : "modular"
37 | },
38 | {
39 | "filename" : "Utilitarian.imageset",
40 | "idiom" : "watch",
41 | "role" : "utilitarian"
42 | }
43 | ],
44 | "info" : {
45 | "author" : "xcode",
46 | "version" : 1
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/Examples/BarChartExample-macOS/BarChartExample-macOS/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIconFile
10 |
11 | CFBundleIdentifier
12 | $(PRODUCT_BUNDLE_IDENTIFIER)
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | $(PRODUCT_NAME)
17 | CFBundlePackageType
18 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
19 | CFBundleShortVersionString
20 | 1.0
21 | CFBundleVersion
22 | 1
23 | LSMinimumSystemVersion
24 | $(MACOSX_DEPLOYMENT_TARGET)
25 | NSHumanReadableCopyright
26 | Copyright © 2020 Roman Baitaliuk. All rights reserved.
27 | NSMainStoryboardFile
28 | Main
29 | NSPrincipalClass
30 | NSApplication
31 | NSSupportsAutomaticTermination
32 |
33 | NSSupportsSuddenTermination
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## SwiftUI BarChart
2 | Lightweight and easy to use SwiftUI chart library for all Apple platforms
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 | ## Features
13 |
14 | - Scaling on both axes
15 | - Fully customizable axes (labels font, color, dashed lines)
16 | - Custom gradient bars
17 | - Reactive chart configuration
18 | - Bar selection API
19 | - **[WIP]** horizontal scrolling
20 |
21 | ## Requirements
22 |
23 | - iOS 13+ / macOS 10.15+ / watchOS 6+ / tvOS 13+
24 | - Xcode 11.0+
25 | - Swift 5+
26 |
27 | ## Installation
28 |
29 | ### Swift Package Manager
30 |
31 | Add this swift package to your project
32 | ```
33 | https://github.com/dawigr/BarChart.git
34 | ```
35 |
36 | ## Usage
37 |
38 | [See Wiki](https://github.com/dawigr/BarChart/wiki) for usage details
39 |
40 | ## Help
41 |
42 | If you like the library, you could:
43 | - Contribute code, issues and pull requests
44 | - Let other people know about it
45 | - [](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=7D5E9VK2WYZUY) any amount to accelaerate new feature development
46 |
47 | ## License
48 |
49 | BarChart is released under the MIT license. [See LICENSE](https://github.com/dawigr/BarChart/blob/master/LICENSE) for details
50 |
--------------------------------------------------------------------------------
/Examples/BarChartExample-watchOS/BarChartExample-watchOS WatchKit Extension/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleDisplayName
8 | BarChartExample-watchOS WatchKit Extension
9 | CFBundleExecutable
10 | $(EXECUTABLE_NAME)
11 | CFBundleIdentifier
12 | $(PRODUCT_BUNDLE_IDENTIFIER)
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | $(PRODUCT_NAME)
17 | CFBundlePackageType
18 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
19 | CFBundleShortVersionString
20 | 1.0
21 | CFBundleVersion
22 | 1
23 | NSExtension
24 |
25 | NSExtensionAttributes
26 |
27 | WKAppBundleIdentifier
28 | com.ByteKit.BarChartExample-watchOS.watchkitapp
29 |
30 | NSExtensionPointIdentifier
31 | com.apple.watchkit
32 |
33 | WKExtensionDelegateClassName
34 | $(PRODUCT_MODULE_NAME).ExtensionDelegate
35 | WKWatchOnly
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/Examples/BarChartExample-watchOS/BarChartExample-watchOS WatchKit Extension/HostingController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // HostingController.swift
3 | // BarChartExample-watchOS WatchKit Extension
4 | //
5 | // Copyright (c) 2020 Roman Baitaliuk
6 | // Permission is hereby granted, free of charge, to any person
7 | // obtaining a copy of this software and associated documentation
8 | // files (the "Software"), to deal in the Software without
9 | // restriction, including without limitation the rights to use,
10 | // copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | // copies of the Software, and to permit persons to whom the
12 | // Software is furnished to do so, subject to the following
13 | // conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be
16 | // included in all copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
20 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
22 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25 | // OTHER DEALINGS IN THE SOFTWARE.
26 |
27 | import WatchKit
28 | import Foundation
29 | import SwiftUI
30 |
31 | class HostingController: WKHostingController {
32 | override var body: ContentView {
33 | return ContentView()
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/Sources/BarChart/GradientColor.swift:
--------------------------------------------------------------------------------
1 | //
2 | // GradientColor.swift
3 | // BarChart
4 | //
5 | // Copyright (c) 2020 Roman Baitaliuk
6 | // Permission is hereby granted, free of charge, to any person
7 | // obtaining a copy of this software and associated documentation
8 | // files (the "Software"), to deal in the Software without
9 | // restriction, including without limitation the rights to use,
10 | // copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | // copies of the Software, and to permit persons to whom the
12 | // Software is furnished to do so, subject to the following
13 | // conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be
16 | // included in all copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
20 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
22 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25 | // OTHER DEALINGS IN THE SOFTWARE.
26 |
27 | import SwiftUI
28 |
29 | public struct GradientColor {
30 | public let start: Color
31 | public let end: Color
32 |
33 | public init(start: Color, end: Color) {
34 | self.start = start
35 | self.end = end
36 | }
37 |
38 | public func gradient() -> Gradient {
39 | return Gradient(colors: [start, end])
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/Examples/BarChartExample-tvOS/BarChartExample-tvOS/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/Sources/BarChart/Extension+Decimals.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Extension+Decimals.swift
3 | // BarChart
4 | //
5 | // Copyright (c) 2020 Roman Baitaliuk
6 | // Permission is hereby granted, free of charge, to any person
7 | // obtaining a copy of this software and associated documentation
8 | // files (the "Software"), to deal in the Software without
9 | // restriction, including without limitation the rights to use,
10 | // copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | // copies of the Software, and to permit persons to whom the
12 | // Software is furnished to do so, subject to the following
13 | // conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be
16 | // included in all copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
20 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
22 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25 | // OTHER DEALINGS IN THE SOFTWARE.
26 |
27 | import Foundation
28 |
29 | extension Double {
30 | func decimalsCount() -> Int {
31 | if self == Double(Int(self)) {
32 | return 0
33 | }
34 |
35 | let integerString = String(Int(self))
36 | let doubleString = String(Double(self))
37 | let decimalCount = doubleString.count - integerString.count - 1
38 |
39 | return decimalCount
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/Examples/BarChartExample-iOS/BarChartExample-iOS/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/Examples/SelectableBarChartExample-iOS/SelectableBarChartExample-iOS/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/Examples/BarChartExample-watchOS/BarChartExample-watchOS WatchKit App/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "watch",
5 | "role" : "notificationCenter",
6 | "scale" : "2x",
7 | "size" : "24x24",
8 | "subtype" : "38mm"
9 | },
10 | {
11 | "idiom" : "watch",
12 | "role" : "notificationCenter",
13 | "scale" : "2x",
14 | "size" : "27.5x27.5",
15 | "subtype" : "42mm"
16 | },
17 | {
18 | "idiom" : "watch",
19 | "role" : "companionSettings",
20 | "scale" : "2x",
21 | "size" : "29x29"
22 | },
23 | {
24 | "idiom" : "watch",
25 | "role" : "companionSettings",
26 | "scale" : "3x",
27 | "size" : "29x29"
28 | },
29 | {
30 | "idiom" : "watch",
31 | "role" : "appLauncher",
32 | "scale" : "2x",
33 | "size" : "40x40",
34 | "subtype" : "38mm"
35 | },
36 | {
37 | "idiom" : "watch",
38 | "role" : "appLauncher",
39 | "scale" : "2x",
40 | "size" : "44x44",
41 | "subtype" : "40mm"
42 | },
43 | {
44 | "idiom" : "watch",
45 | "role" : "appLauncher",
46 | "scale" : "2x",
47 | "size" : "50x50",
48 | "subtype" : "44mm"
49 | },
50 | {
51 | "idiom" : "watch",
52 | "role" : "quickLook",
53 | "scale" : "2x",
54 | "size" : "86x86",
55 | "subtype" : "38mm"
56 | },
57 | {
58 | "idiom" : "watch",
59 | "role" : "quickLook",
60 | "scale" : "2x",
61 | "size" : "98x98",
62 | "subtype" : "42mm"
63 | },
64 | {
65 | "idiom" : "watch",
66 | "role" : "quickLook",
67 | "scale" : "2x",
68 | "size" : "108x108",
69 | "subtype" : "44mm"
70 | },
71 | {
72 | "idiom" : "watch-marketing",
73 | "scale" : "1x",
74 | "size" : "1024x1024"
75 | }
76 | ],
77 | "info" : {
78 | "author" : "xcode",
79 | "version" : 1
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/Sources/BarChart/ChartData.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ChartData.swift
3 | // BarChart
4 | //
5 | // Copyright (c) 2020 Roman Baitaliuk
6 | // Permission is hereby granted, free of charge, to any person
7 | // obtaining a copy of this software and associated documentation
8 | // files (the "Software"), to deal in the Software without
9 | // restriction, including without limitation the rights to use,
10 | // copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | // copies of the Software, and to permit persons to whom the
12 | // Software is furnished to do so, subject to the following
13 | // conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be
16 | // included in all copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
20 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
22 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25 | // OTHER DEALINGS IN THE SOFTWARE.
26 |
27 | import SwiftUI
28 |
29 | public struct ChartDataEntry: Identifiable, Equatable {
30 | public var id = UUID()
31 | public var x: String
32 | public var y: Double
33 |
34 | public init(x: String, y: Double) {
35 | self.x = x
36 | self.y = y
37 | }
38 | }
39 |
40 | public struct ChartData {
41 | public var entries: [ChartDataEntry] = []
42 | public var gradientColor: GradientColor?
43 | public var color: Color = .red {
44 | didSet {
45 | self.gradientColor = nil
46 | }
47 | }
48 |
49 | var yValues: [Double] {
50 | return self.entries.map { $0.y }
51 | }
52 |
53 | var xValues: [String] {
54 | return self.entries.map { $0.x }
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/Examples/BarChartExample-iOS/BarChartExample-iOS/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "scale" : "2x",
6 | "size" : "20x20"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "scale" : "3x",
11 | "size" : "20x20"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "scale" : "2x",
16 | "size" : "29x29"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "scale" : "3x",
21 | "size" : "29x29"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "scale" : "2x",
26 | "size" : "40x40"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "scale" : "3x",
31 | "size" : "40x40"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "scale" : "2x",
36 | "size" : "60x60"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "scale" : "3x",
41 | "size" : "60x60"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "scale" : "1x",
46 | "size" : "20x20"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "scale" : "2x",
51 | "size" : "20x20"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "scale" : "1x",
56 | "size" : "29x29"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "scale" : "2x",
61 | "size" : "29x29"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "scale" : "1x",
66 | "size" : "40x40"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "scale" : "2x",
71 | "size" : "40x40"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "scale" : "1x",
76 | "size" : "76x76"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "scale" : "2x",
81 | "size" : "76x76"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "scale" : "2x",
86 | "size" : "83.5x83.5"
87 | },
88 | {
89 | "idiom" : "ios-marketing",
90 | "scale" : "1x",
91 | "size" : "1024x1024"
92 | }
93 | ],
94 | "info" : {
95 | "author" : "xcode",
96 | "version" : 1
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/Examples/SelectableBarChartExample-iOS/SelectableBarChartExample-iOS/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "scale" : "2x",
6 | "size" : "20x20"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "scale" : "3x",
11 | "size" : "20x20"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "scale" : "2x",
16 | "size" : "29x29"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "scale" : "3x",
21 | "size" : "29x29"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "scale" : "2x",
26 | "size" : "40x40"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "scale" : "3x",
31 | "size" : "40x40"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "scale" : "2x",
36 | "size" : "60x60"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "scale" : "3x",
41 | "size" : "60x60"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "scale" : "1x",
46 | "size" : "20x20"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "scale" : "2x",
51 | "size" : "20x20"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "scale" : "1x",
56 | "size" : "29x29"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "scale" : "2x",
61 | "size" : "29x29"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "scale" : "1x",
66 | "size" : "40x40"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "scale" : "2x",
71 | "size" : "40x40"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "scale" : "1x",
76 | "size" : "76x76"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "scale" : "2x",
81 | "size" : "76x76"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "scale" : "2x",
86 | "size" : "83.5x83.5"
87 | },
88 | {
89 | "idiom" : "ios-marketing",
90 | "scale" : "1x",
91 | "size" : "1024x1024"
92 | }
93 | ],
94 | "info" : {
95 | "author" : "xcode",
96 | "version" : 1
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/Examples/BarChartExample-iOS/BarChartExample-iOS/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | UIApplicationSceneManifest
24 |
25 | UIApplicationSupportsMultipleScenes
26 |
27 | UISceneConfigurations
28 |
29 | UIWindowSceneSessionRoleApplication
30 |
31 |
32 | UISceneConfigurationName
33 | Default Configuration
34 | UISceneDelegateClassName
35 | $(PRODUCT_MODULE_NAME).SceneDelegate
36 |
37 |
38 |
39 |
40 | UILaunchStoryboardName
41 | LaunchScreen
42 | UIRequiredDeviceCapabilities
43 |
44 | armv7
45 |
46 | UISupportedInterfaceOrientations
47 |
48 | UIInterfaceOrientationPortrait
49 | UIInterfaceOrientationLandscapeLeft
50 | UIInterfaceOrientationLandscapeRight
51 |
52 | UISupportedInterfaceOrientations~ipad
53 |
54 | UIInterfaceOrientationPortrait
55 | UIInterfaceOrientationPortraitUpsideDown
56 | UIInterfaceOrientationLandscapeLeft
57 | UIInterfaceOrientationLandscapeRight
58 |
59 |
60 |
61 |
--------------------------------------------------------------------------------
/Sources/BarChart/BarChartCell.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BarChartCell.swift
3 | // BarChart
4 | //
5 | // Copyright (c) 2020 Roman Baitaliuk
6 | // Permission is hereby granted, free of charge, to any person
7 | // obtaining a copy of this software and associated documentation
8 | // files (the "Software"), to deal in the Software without
9 | // restriction, including without limitation the rights to use,
10 | // copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | // copies of the Software, and to permit persons to whom the
12 | // Software is furnished to do so, subject to the following
13 | // conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be
16 | // included in all copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
20 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
22 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25 | // OTHER DEALINGS IN THE SOFTWARE.
26 |
27 | import SwiftUI
28 |
29 | struct BarChartCell: View {
30 | let width, height, cornerRadius: CGFloat
31 | let gradient: Gradient?
32 | let color: Color
33 |
34 | var body: some View {
35 | Group {
36 | if self.gradient != nil {
37 | BarShape(cornerRadius: self.cornerRadius,
38 | corners: RoundedCorner.allCases)
39 | .fill(LinearGradient(gradient: self.gradient!,
40 | startPoint: .bottom,
41 | endPoint: .top))
42 | } else {
43 | BarShape(cornerRadius: self.cornerRadius,
44 | corners: RoundedCorner.allCases)
45 | .fill(self.color)
46 | }
47 | }
48 | .frame(width: self.width, height: self.height)
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/Examples/SelectableBarChartExample-iOS/SelectableBarChartExample-iOS/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | UIApplicationSceneManifest
24 |
25 | UIApplicationSupportsMultipleScenes
26 |
27 | UISceneConfigurations
28 |
29 | UIWindowSceneSessionRoleApplication
30 |
31 |
32 | UISceneConfigurationName
33 | Default Configuration
34 | UISceneDelegateClassName
35 | $(PRODUCT_MODULE_NAME).SceneDelegate
36 |
37 |
38 |
39 |
40 | UILaunchStoryboardName
41 | LaunchScreen
42 | UIRequiredDeviceCapabilities
43 |
44 | armv7
45 |
46 | UISupportedInterfaceOrientations
47 |
48 | UIInterfaceOrientationPortrait
49 | UIInterfaceOrientationLandscapeLeft
50 | UIInterfaceOrientationLandscapeRight
51 |
52 | UISupportedInterfaceOrientations~ipad
53 |
54 | UIInterfaceOrientationPortrait
55 | UIInterfaceOrientationPortraitUpsideDown
56 | UIInterfaceOrientationLandscapeLeft
57 | UIInterfaceOrientationLandscapeRight
58 |
59 |
60 |
61 |
--------------------------------------------------------------------------------
/Sources/BarChart/Extension+StringSize.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Extension+StringSize.swift
3 | // BarChart
4 | //
5 | // Copyright (c) 2020 Roman Baitaliuk
6 | // Permission is hereby granted, free of charge, to any person
7 | // obtaining a copy of this software and associated documentation
8 | // files (the "Software"), to deal in the Software without
9 | // restriction, including without limitation the rights to use,
10 | // copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | // copies of the Software, and to permit persons to whom the
12 | // Software is furnished to do so, subject to the following
13 | // conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be
16 | // included in all copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
20 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
22 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25 | // OTHER DEALINGS IN THE SOFTWARE.
26 |
27 | import SwiftUI
28 |
29 | extension String {
30 | func width(ctFont: CTFont) -> CGFloat {
31 | return self.size(ctFont: ctFont).width
32 | }
33 |
34 | func height(ctFont: CTFont) -> CGFloat {
35 | return self.size(ctFont: ctFont).height
36 | }
37 |
38 | func size(ctFont: CTFont) -> CGSize {
39 | let attributes = [NSAttributedString.Key.init(kCTFontAttributeName as String): ctFont]
40 | let attString = NSAttributedString(string: self == "" ? " " : self, attributes: attributes)
41 | let framesetter = CTFramesetterCreateWithAttributedString(attString)
42 | let range = CFRange(location: 0, length: self.count)
43 | let size = CGSize(width: 10000, height: 10000)
44 | let frame = CTFramesetterSuggestFrameSizeWithConstraints(framesetter, range, nil, size, nil)
45 | return frame
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/Sources/BarChart/ChartConfiguration.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ChartConfiguration.swift
3 | // BarChart
4 | //
5 | // Copyright (c) 2020 Roman Baitaliuk
6 | // Permission is hereby granted, free of charge, to any person
7 | // obtaining a copy of this software and associated documentation
8 | // files (the "Software"), to deal in the Software without
9 | // restriction, including without limitation the rights to use,
10 | // copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | // copies of the Software, and to permit persons to whom the
12 | // Software is furnished to do so, subject to the following
13 | // conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be
16 | // included in all copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
20 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
22 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25 | // OTHER DEALINGS IN THE SOFTWARE.
26 |
27 | import SwiftUI
28 | import Combine
29 |
30 | public class ChartConfiguration: ObservableObject {
31 | @Published public var data = ChartData()
32 | public var xAxis = XAxisReference()
33 | public var yAxis = YAxisReference()
34 |
35 | private var xAxisCancellable: AnyCancellable?
36 | private var yAxisCancellable: AnyCancellable?
37 |
38 | static let defaultLabelsCTFont = CTFontCreateWithName(("SFProText-Regular" as CFString), 12, nil)
39 | @Published public var labelsCTFont: CTFont = ChartConfiguration.defaultLabelsCTFont
40 |
41 | public init() {
42 | self.xAxisCancellable = self.xAxis.objectWillChange.sink(receiveValue: { _ in
43 | self.objectWillChange.send()
44 | })
45 |
46 | self.yAxisCancellable = self.yAxis.objectWillChange.sink(receiveValue: { _ in
47 | self.objectWillChange.send()
48 | })
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/Examples/SelectableBarChartExample-iOS/SelectableBarChartExample-iOS/MiniSelectionIndicator.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MiniSelectionIndicator.swift
3 | // SelectableBarChartExample-iOS
4 | //
5 | // Copyright (c) 2020 Roman Baitaliuk
6 | // Permission is hereby granted, free of charge, to any person
7 | // obtaining a copy of this software and associated documentation
8 | // files (the "Software"), to deal in the Software without
9 | // restriction, including without limitation the rights to use,
10 | // copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | // copies of the Software, and to permit persons to whom the
12 | // Software is furnished to do so, subject to the following
13 | // conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be
16 | // included in all copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
20 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
22 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25 | // OTHER DEALINGS IN THE SOFTWARE.
26 |
27 | import SwiftUI
28 | import BarChart
29 |
30 | struct MiniSelectionIndicator: View {
31 | let entry: ChartDataEntry?
32 | let location: CGPoint?
33 |
34 | let height: CGFloat = 30
35 | let width: CGFloat = 40
36 | let spaceFromBar: CGFloat = 5
37 | let color: Color = Color(red: 230/255, green: 230/255, blue: 230/255)
38 |
39 | var body: some View {
40 | Group {
41 | if location != nil && self.entry != nil {
42 | ZStack {
43 | RoundedRectangle(cornerRadius: 3.0)
44 | .foregroundColor(self.color)
45 | Text("\(Int(self.entry!.y))").font(.system(size: 12)).fontWeight(.bold)
46 | }
47 | .zIndex(1)
48 | .frame(width: self.width, height: self.height)
49 | .offset(x: self.location!.x - self.width / 2, y: self.location!.y - (self.height + self.spaceFromBar))
50 | }
51 | }
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/Examples/BarChartExample-macOS/BarChartExample-macOS/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // BarChartExample-macOS
4 | //
5 | // Copyright (c) 2020 Roman Baitaliuk
6 | // Permission is hereby granted, free of charge, to any person
7 | // obtaining a copy of this software and associated documentation
8 | // files (the "Software"), to deal in the Software without
9 | // restriction, including without limitation the rights to use,
10 | // copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | // copies of the Software, and to permit persons to whom the
12 | // Software is furnished to do so, subject to the following
13 | // conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be
16 | // included in all copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
20 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
22 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25 | // OTHER DEALINGS IN THE SOFTWARE.
26 |
27 | import Cocoa
28 | import SwiftUI
29 |
30 | @NSApplicationMain
31 | class AppDelegate: NSObject, NSApplicationDelegate {
32 |
33 | var window: NSWindow!
34 |
35 |
36 | func applicationDidFinishLaunching(_ aNotification: Notification) {
37 | // Create the SwiftUI view that provides the window contents.
38 | let contentView = ContentView()
39 |
40 | // Create the window and set the content view.
41 | window = NSWindow(
42 | contentRect: NSRect(x: 0, y: 0, width: 600, height: 500),
43 | styleMask: [.titled, .closable, .miniaturizable, .fullSizeContentView],
44 | backing: .buffered, defer: false)
45 | window.center()
46 | window.setFrameAutosaveName("Main Window")
47 | window.contentView = NSHostingView(rootView: contentView)
48 | window.makeKeyAndOrderFront(nil)
49 | }
50 |
51 | func applicationWillTerminate(_ aNotification: Notification) {
52 | // Insert code here to tear down your application
53 | }
54 |
55 |
56 | }
57 |
58 |
--------------------------------------------------------------------------------
/Sources/BarChart/Extension+ViewModifiers.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Extension+ViewModifiers.swift
3 | // BarChart
4 | //
5 | // Copyright (c) 2020 Roman Baitaliuk
6 | // Permission is hereby granted, free of charge, to any person
7 | // obtaining a copy of this software and associated documentation
8 | // files (the "Software"), to deal in the Software without
9 | // restriction, including without limitation the rights to use,
10 | // copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | // copies of the Software, and to permit persons to whom the
12 | // Software is furnished to do so, subject to the following
13 | // conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be
16 | // included in all copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
20 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
22 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25 | // OTHER DEALINGS IN THE SOFTWARE.
26 |
27 | import SwiftUI
28 |
29 | public typealias BarChartView = SelectableBarChartView
30 |
31 | #if !os(tvOS)
32 | public extension SelectableBarChartView {
33 | func onBarSelection(_ callback: @escaping (ChartDataEntry, CGPoint) -> ()) -> Self {
34 | SelectableBarChartView(config: self.config, selectionCallback: callback)
35 | }
36 |
37 | func selectionView(@ViewBuilder view: () -> SelectionView) -> Self {
38 | SelectableBarChartView(config: self.config, selectionCallback: self.selectionCallback, selectionView: view())
39 | }
40 | }
41 | #endif
42 |
43 | extension View {
44 | func onSelect(callback: @escaping () -> ()) -> some View {
45 | return self.modifier(Selectable(callback: callback))
46 | }
47 | }
48 |
49 | struct Selectable: ViewModifier {
50 | let callback: () -> ()
51 |
52 | func body(content: Content) -> some View {
53 | Group {
54 | #if !os(tvOS)
55 | content
56 | .onTapGesture {
57 | self.callback()
58 | }
59 | #else
60 | content
61 | #endif
62 | }
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/Examples/SelectableBarChartExample-iOS/SelectableBarChartExample-iOS/SelectionLine.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SelectionLine.swift
3 | // SelectableBarChartExample-iOS
4 | //
5 | // Copyright (c) 2020 Roman Baitaliuk
6 | // Permission is hereby granted, free of charge, to any person
7 | // obtaining a copy of this software and associated documentation
8 | // files (the "Software"), to deal in the Software without
9 | // restriction, including without limitation the rights to use,
10 | // copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | // copies of the Software, and to permit persons to whom the
12 | // Software is furnished to do so, subject to the following
13 | // conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be
16 | // included in all copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
20 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
22 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25 | // OTHER DEALINGS IN THE SOFTWARE.
26 |
27 | import SwiftUI
28 |
29 | struct SelectionLine: View {
30 | let location: CGPoint?
31 | let height: CGFloat
32 | let color = Color(red: 100/255, green: 100/255, blue: 100/255)
33 |
34 | var body: some View {
35 | Group {
36 | if location != nil {
37 | self.centreLine()
38 | .stroke(lineWidth: 2)
39 | .offset(x: self.location!.x)
40 | .foregroundColor(self.color)
41 | /* '.id(UUID())' will prevent view from slide animation.
42 | Because this view is a child view and passed to 'BarChartView' parent, parent might already has animation.
43 | So, If you want to disable it, just call '.animation(nil)' instead of '.id(UUID())' */
44 | .id(UUID())
45 | }
46 | }
47 | }
48 |
49 | func centreLine() -> Path {
50 | var path = Path()
51 | let p1 = CGPoint(x: 0, y: 0)
52 | let p2 = CGPoint(x: 0, y: self.height)
53 | path.move(to: p1)
54 | path.addLine(to: p2)
55 | return path
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/Tests/BarChartTests/XAxisTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // XAxisTests.swift
3 | // BarChartTests
4 | //
5 | // Copyright (c) 2020 Roman Baitaliuk
6 | // Permission is hereby granted, free of charge, to any person
7 | // obtaining a copy of this software and associated documentation
8 | // files (the "Software"), to deal in the Software without
9 | // restriction, including without limitation the rights to use,
10 | // copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | // copies of the Software, and to permit persons to whom the
12 | // Software is furnished to do so, subject to the following
13 | // conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be
16 | // included in all copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
20 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
22 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25 | // OTHER DEALINGS IN THE SOFTWARE.
26 |
27 | import XCTest
28 | @testable import BarChart
29 |
30 | class XAxisTests: XCTestCase {
31 |
32 | func testTicksInterval1() {
33 | let xAxis = XAxis(frameWidth: 300, data: TestData.generate(with: TestData.Values.Positive.Small.values4))
34 | let expectedLabels = ["0", "1", "2", "3", "4", "5", "6"]
35 | XCTAssert(xAxis.formattedLabels() == expectedLabels)
36 | }
37 |
38 | func testTicksInterval2() {
39 | let ref = XAxisReference()
40 | ref.ticksInterval = 2
41 | let xAxis = XAxis(frameWidth: 300,
42 | data: TestData.generate(with: TestData.Values.Positive.Small.values4),
43 | ref: ref)
44 | let expectedLabels = ["0", "2", "4", "6"]
45 | XCTAssert(xAxis.formattedLabels() == expectedLabels)
46 | }
47 |
48 | func testTicksInterval3() {
49 | let ref = XAxisReference()
50 | ref.ticksInterval = 0
51 | let xAxis = XAxis(frameWidth: 300,
52 | data: TestData.generate(with: TestData.Values.Positive.Small.values4),
53 | ref: ref)
54 | let expectedLabels = ["0", "1", "2", "3", "4", "5", "6"]
55 | XCTAssert(xAxis.formattedLabels() == expectedLabels)
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/Sources/BarChart/AxisBase.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AxisBase.swift
3 | // BarChart
4 | //
5 | // Copyright (c) 2020 Roman Baitaliuk
6 | // Permission is hereby granted, free of charge, to any person
7 | // obtaining a copy of this software and associated documentation
8 | // files (the "Software"), to deal in the Software without
9 | // restriction, including without limitation the rights to use,
10 | // copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | // copies of the Software, and to permit persons to whom the
12 | // Software is furnished to do so, subject to the following
13 | // conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be
16 | // included in all copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
20 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
22 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25 | // OTHER DEALINGS IN THE SOFTWARE.
26 |
27 | import SwiftUI
28 |
29 | public class AxisBase: ObservableObject {
30 | @Published public var labelsColor: Color = .black
31 | @Published public var ticksColor: Color = .black
32 | @Published public var ticksStyle = StrokeStyle(lineWidth: 1.5, lineCap: .round, dash: [5, 10])
33 | }
34 |
35 | public class XAxisReference: AxisBase {
36 | /// Horizontal interval between the bars
37 | @Published public var ticksInterval: Int? {
38 | didSet {
39 | self.validateTicksInterval()
40 | }
41 | }
42 |
43 | private func validateTicksInterval() {
44 | if let newValue = self.ticksInterval, newValue < 1 {
45 | self.ticksInterval = nil
46 | }
47 | }
48 | }
49 |
50 | public class YAxisReference: AxisBase {
51 | /// Minimum spacing between the ticks in pixels
52 | @Published public var minTicksSpacing: CGFloat = 40.0 {
53 | didSet {
54 | self.validateMinTicksSpacing()
55 | }
56 | }
57 |
58 | @Published public var formatter: ((Double, Int) -> String) = {
59 | return { return String(format: "%.\($1)f", $0) }
60 | }()
61 |
62 | private func validateMinTicksSpacing() {
63 | if minTicksSpacing <= 0 {
64 | self.minTicksSpacing = 40.0
65 | }
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/Sources/BarChart/XAxisLayout.swift:
--------------------------------------------------------------------------------
1 | //
2 | // XAxisLayout.swift
3 | // BarChart
4 | //
5 | // Copyright (c) 2020 Roman Baitaliuk
6 | // Permission is hereby granted, free of charge, to any person
7 | // obtaining a copy of this software and associated documentation
8 | // files (the "Software"), to deal in the Software without
9 | // restriction, including without limitation the rights to use,
10 | // copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | // copies of the Software, and to permit persons to whom the
12 | // Software is furnished to do so, subject to the following
13 | // conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be
16 | // included in all copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
20 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
22 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25 | // OTHER DEALINGS IN THE SOFTWARE.
26 |
27 | import SwiftUI
28 |
29 | struct XAxisLayout {
30 | private let frameWidth: CGFloat
31 | private let dataCount: Int
32 |
33 | private(set) var spacing: CGFloat?
34 | private(set) var barWidth: CGFloat?
35 |
36 | init(frameWidth: CGFloat, dataCount: Int) {
37 | self.frameWidth = frameWidth
38 | self.dataCount = dataCount
39 | self.calculate()
40 | }
41 |
42 | func barCentre(at index: Int) -> CGFloat? {
43 | guard let barWidth = self.barWidth,
44 | let spacing = self.spacing else { return nil }
45 | if self.dataCount == 1 {
46 | return spacing + barWidth / 2
47 | } else {
48 | let centre = barWidth / 2
49 | return barWidth * CGFloat(index + 1) + spacing * CGFloat(index) - centre
50 | }
51 | }
52 |
53 | private mutating func calculate() {
54 | guard self.dataCount != 0 else { return }
55 |
56 | let barWidth = self.frameWidth / (CGFloat(self.dataCount) * 1.5)
57 | self.barWidth = barWidth
58 |
59 | if self.dataCount == 1 {
60 | self.spacing = (self.frameWidth - barWidth) / 2
61 | } else {
62 | self.spacing = self.frameWidth / CGFloat((self.dataCount - 1) * 3)
63 | }
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/Examples/BarChartExample-iOS/BarChartExample-iOS/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // BarChartExample-iOS
4 | //
5 | // Copyright (c) 2020 Roman Baitaliuk
6 | // Permission is hereby granted, free of charge, to any person
7 | // obtaining a copy of this software and associated documentation
8 | // files (the "Software"), to deal in the Software without
9 | // restriction, including without limitation the rights to use,
10 | // copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | // copies of the Software, and to permit persons to whom the
12 | // Software is furnished to do so, subject to the following
13 | // conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be
16 | // included in all copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
20 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
22 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25 | // OTHER DEALINGS IN THE SOFTWARE.
26 |
27 | import UIKit
28 |
29 | @UIApplicationMain
30 | class AppDelegate: UIResponder, UIApplicationDelegate {
31 |
32 |
33 |
34 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
35 | // Override point for customization after application launch.
36 | return true
37 | }
38 |
39 | // MARK: UISceneSession Lifecycle
40 |
41 | func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
42 | // Called when a new scene session is being created.
43 | // Use this method to select a configuration to create the new scene with.
44 | return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
45 | }
46 |
47 | func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) {
48 | // Called when the user discards a scene session.
49 | // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
50 | // Use this method to release any resources that were specific to the discarded scenes, as they will not return.
51 | }
52 |
53 |
54 | }
55 |
56 |
--------------------------------------------------------------------------------
/Examples/SelectableBarChartExample-iOS/SelectableBarChartExample-iOS/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // SelectableBarChartExample-iOS
4 | //
5 | // Copyright (c) 2020 Roman Baitaliuk
6 | // Permission is hereby granted, free of charge, to any person
7 | // obtaining a copy of this software and associated documentation
8 | // files (the "Software"), to deal in the Software without
9 | // restriction, including without limitation the rights to use,
10 | // copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | // copies of the Software, and to permit persons to whom the
12 | // Software is furnished to do so, subject to the following
13 | // conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be
16 | // included in all copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
20 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
22 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25 | // OTHER DEALINGS IN THE SOFTWARE.
26 |
27 | import UIKit
28 |
29 | @UIApplicationMain
30 | class AppDelegate: UIResponder, UIApplicationDelegate {
31 |
32 |
33 |
34 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
35 | // Override point for customization after application launch.
36 | return true
37 | }
38 |
39 | // MARK: UISceneSession Lifecycle
40 |
41 | func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
42 | // Called when a new scene session is being created.
43 | // Use this method to select a configuration to create the new scene with.
44 | return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
45 | }
46 |
47 | func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) {
48 | // Called when the user discards a scene session.
49 | // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
50 | // Use this method to release any resources that were specific to the discarded scenes, as they will not return.
51 | }
52 |
53 |
54 | }
55 |
56 |
--------------------------------------------------------------------------------
/Examples/BarChartExample-watchOS/BarChartExample-watchOS WatchKit Extension/ContentView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ContentView.swift
3 | // BarChartExample-watchOS WatchKit Extension
4 | //
5 | // Copyright (c) 2020 Roman Baitaliuk
6 | // Permission is hereby granted, free of charge, to any person
7 | // obtaining a copy of this software and associated documentation
8 | // files (the "Software"), to deal in the Software without
9 | // restriction, including without limitation the rights to use,
10 | // copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | // copies of the Software, and to permit persons to whom the
12 | // Software is furnished to do so, subject to the following
13 | // conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be
16 | // included in all copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
20 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
22 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25 | // OTHER DEALINGS IN THE SOFTWARE.
26 |
27 | import SwiftUI
28 | import BarChart
29 |
30 | struct ContentView: View {
31 |
32 | // MARK: - Chart Properties
33 | let config = ChartConfiguration()
34 |
35 | var body: some View {
36 | GeometryReader { geometry in
37 | BarChartView(config: self.config)
38 | .onAppear() {
39 | let font = CTFontCreateWithName(("SFProText-Regular" as CFString), 8, nil)
40 | self.config.data.entries = self.randomEntries()
41 | self.config.labelsCTFont = font
42 | self.config.xAxis.labelsColor = .white
43 | self.config.xAxis.ticksColor = .white
44 | self.config.yAxis.labelsColor = .white
45 | self.config.yAxis.ticksColor = .white
46 | self.config.yAxis.minTicksSpacing = 20.0
47 | }
48 | .animation(Animation.easeInOut.delay(1.0))
49 | .frame(height: geometry.size.height)
50 | }
51 | }
52 |
53 | // MARK: - Random Helpers
54 |
55 | func randomEntries() -> [ChartDataEntry] {
56 | var entries = [ChartDataEntry]()
57 | for data in 0..<8 {
58 | let randomDouble = Double.random(in: 0...10)
59 | let newEntry = ChartDataEntry(x: "\(data)", y: randomDouble)
60 | entries.append(newEntry)
61 | }
62 | return entries
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/Examples/SelectableBarChartExample-iOS/SelectableBarChartExample-iOS/SelectionIndicator.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SelectionIndicator.swift
3 | // SelectableBarChartExample-iOS
4 | //
5 | // Copyright (c) 2020 Roman Baitaliuk
6 | // Permission is hereby granted, free of charge, to any person
7 | // obtaining a copy of this software and associated documentation
8 | // files (the "Software"), to deal in the Software without
9 | // restriction, including without limitation the rights to use,
10 | // copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | // copies of the Software, and to permit persons to whom the
12 | // Software is furnished to do so, subject to the following
13 | // conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be
16 | // included in all copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
20 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
22 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25 | // OTHER DEALINGS IN THE SOFTWARE.
26 |
27 | import SwiftUI
28 | import BarChart
29 |
30 | struct SelectionIndicator: View {
31 | let entry: ChartDataEntry
32 | let location: CGFloat
33 | let infoRectangleColor: Color
34 | let infoRectangleWidth: CGFloat = 70
35 |
36 | var body: some View {
37 | GeometryReader { proxy in
38 | ZStack {
39 | RoundedRectangle(cornerRadius: 3.0)
40 | .foregroundColor(self.infoRectangleColor)
41 | VStack(alignment: .leading) {
42 | HStack(alignment: .bottom, spacing: 2) {
43 | Text("\(Int(self.entry.y))").font(.headline).fontWeight(.bold)
44 | Text("b").font(.footnote)
45 | .foregroundColor(.gray).fontWeight(.bold)
46 | }
47 | Text(self.entry.x)
48 | .font(.footnote).foregroundColor(.gray).fontWeight(.bold)
49 | }
50 | }
51 | .frame(width: self.infoRectangleWidth)
52 | .offset(x: self.positionX(proxy, location: self.location))
53 | // '.id(UUID())' will prevent view from slide animation.
54 | .id(UUID())
55 | }
56 | }
57 |
58 | func positionX(_ proxy: GeometryProxy, location: CGFloat) -> CGFloat {
59 | let selectorCentre = self.infoRectangleWidth / 2
60 | let startX = location - selectorCentre
61 | if startX < 0 {
62 | return 0
63 | } else if startX + self.infoRectangleWidth > proxy.size.width {
64 | return proxy.size.width - self.infoRectangleWidth
65 | } else {
66 | return startX
67 | }
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/Sources/BarChart/BarShape.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BarShape.swift
3 | // BarChart
4 | //
5 | // Copyright (c) 2020 Roman Baitaliuk
6 | // Permission is hereby granted, free of charge, to any person
7 | // obtaining a copy of this software and associated documentation
8 | // files (the "Software"), to deal in the Software without
9 | // restriction, including without limitation the rights to use,
10 | // copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | // copies of the Software, and to permit persons to whom the
12 | // Software is furnished to do so, subject to the following
13 | // conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be
16 | // included in all copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
20 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
22 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25 | // OTHER DEALINGS IN THE SOFTWARE.
26 |
27 | import SwiftUI
28 |
29 | enum RoundedCorner: CaseIterable {
30 | case topLeft, topRight, bottomRight, bottomLeft
31 | }
32 |
33 | struct BarShape: Shape {
34 | let cornerRadius: CGFloat
35 | let corners: [RoundedCorner]
36 |
37 | func radius(for corner: RoundedCorner) -> CGFloat {
38 | if self.corners.contains(corner) {
39 | return self.cornerRadius
40 | }
41 | return 0
42 | }
43 |
44 | func path(in rect: CGRect) -> Path {
45 | var path = Path()
46 |
47 | let control1 = CGPoint(x: rect.minX, y: rect.maxY)
48 | let control2 = CGPoint(x: rect.maxX, y: rect.maxY)
49 | let control3 = CGPoint(x: rect.maxX, y: rect.minY)
50 | let control4 = CGPoint(x: rect.minX, y: rect.minY)
51 |
52 | let p1 = CGPoint(x: rect.minX, y: rect.minY + self.radius(for: .bottomLeft))
53 | let p2 = CGPoint(x: rect.minX, y: rect.maxY - self.radius(for: .topLeft))
54 | let p3 = CGPoint(x: rect.minX + self.radius(for: .topLeft), y: rect.maxY)
55 | let p4 = CGPoint(x: rect.maxX - self.radius(for: .topRight), y: rect.maxY)
56 | let p5 = CGPoint(x: rect.maxX, y: rect.maxY - self.radius(for: .topRight))
57 | let p6 = CGPoint(x: rect.maxX, y: rect.minY + self.radius(for: .bottomRight))
58 | let p7 = CGPoint(x: rect.maxX - self.radius(for: .bottomRight), y: rect.minY)
59 | let p8 = CGPoint(x: rect.minX + self.radius(for: .bottomLeft), y: rect.minY)
60 |
61 | path.move(to: p1)
62 | path.addLine(to: p2)
63 | path.addQuadCurve(to: p3, control: control1)
64 | path.addLine(to: p4)
65 | path.addQuadCurve(to: p5, control: control2)
66 | path.addLine(to: p6)
67 | path.addQuadCurve(to: p7, control: control3)
68 | path.addLine(to: p8)
69 | path.addQuadCurve(to: p1, control: control4)
70 |
71 | return path
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/Examples/BarChartExample-tvOS/BarChartExample-tvOS/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // BarChartExample-tvOS
4 | //
5 | // Copyright (c) 2020 Roman Baitaliuk
6 | // Permission is hereby granted, free of charge, to any person
7 | // obtaining a copy of this software and associated documentation
8 | // files (the "Software"), to deal in the Software without
9 | // restriction, including without limitation the rights to use,
10 | // copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | // copies of the Software, and to permit persons to whom the
12 | // Software is furnished to do so, subject to the following
13 | // conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be
16 | // included in all copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
20 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
22 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25 | // OTHER DEALINGS IN THE SOFTWARE.
26 |
27 | import UIKit
28 | import SwiftUI
29 |
30 | @UIApplicationMain
31 | class AppDelegate: UIResponder, UIApplicationDelegate {
32 |
33 | var window: UIWindow?
34 |
35 |
36 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
37 |
38 | // Create the SwiftUI view that provides the window contents.
39 | let contentView = ContentView()
40 |
41 | // Use a UIHostingController as window root view controller.
42 | let window = UIWindow(frame: UIScreen.main.bounds)
43 | window.rootViewController = UIHostingController(rootView: contentView)
44 | self.window = window
45 | window.makeKeyAndVisible()
46 | return true
47 | }
48 |
49 | func applicationWillResignActive(_ application: UIApplication) {
50 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
51 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
52 | }
53 |
54 | func applicationDidEnterBackground(_ application: UIApplication) {
55 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
56 | }
57 |
58 | func applicationWillEnterForeground(_ application: UIApplication) {
59 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
60 | }
61 |
62 | func applicationDidBecomeActive(_ application: UIApplication) {
63 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
64 | }
65 |
66 |
67 | }
68 |
69 |
--------------------------------------------------------------------------------
/Sources/BarChart/XAxis.swift:
--------------------------------------------------------------------------------
1 | //
2 | // XAxis.swift
3 | // BarChart
4 | //
5 | // Copyright (c) 2020 Roman Baitaliuk
6 | // Permission is hereby granted, free of charge, to any person
7 | // obtaining a copy of this software and associated documentation
8 | // files (the "Software"), to deal in the Software without
9 | // restriction, including without limitation the rights to use,
10 | // copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | // copies of the Software, and to permit persons to whom the
12 | // Software is furnished to do so, subject to the following
13 | // conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be
16 | // included in all copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
20 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
22 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25 | // OTHER DEALINGS IN THE SOFTWARE.
26 |
27 | import SwiftUI
28 |
29 | struct XAxis: Identifiable {
30 | let id = UUID()
31 | let data: [ChartDataEntry]
32 | let frameWidth: CGFloat
33 | let ref: XAxisReference
34 | let labelsCTFont: CTFont
35 |
36 | var layout: XAxisLayout {
37 | XAxisLayout(frameWidth: self.frameWidth, dataCount: self.data.count)
38 | }
39 |
40 | init(frameWidth: CGFloat = 0,
41 | data: [ChartDataEntry] = [],
42 | ref: XAxisReference = XAxisReference(),
43 | labelsCTFont: CTFont = ChartConfiguration.defaultLabelsCTFont) {
44 | self.labelsCTFont = labelsCTFont
45 | self.frameWidth = frameWidth
46 | self.data = data
47 | self.ref = ref
48 | }
49 |
50 | func chartEntry(at index: Int) -> ChartDataEntry {
51 | return self.labels()[index]
52 | }
53 |
54 | func formattedLabels() -> [String] {
55 | return self.labels().map { $0.x }
56 | }
57 |
58 | private func labels() -> [ChartDataEntry] {
59 | guard !self.data.isEmpty else { return [] }
60 | let totalLabelsWidth = self.data.compactMap { $0.x.width(ctFont: self.labelsCTFont) }.reduce(0, +)
61 | let averageLabelWidth = totalLabelsWidth / CGFloat(data.count)
62 |
63 | guard averageLabelWidth != 0 else { return [] }
64 | let maxLabelsCount = Int((frameWidth / averageLabelWidth))
65 |
66 | if let interval = self.ref.ticksInterval {
67 | return self.calculateLabels(with: interval, to: maxLabelsCount)
68 | }
69 |
70 | if maxLabelsCount > 0, maxLabelsCount < self.data.count {
71 | return self.calculateLabels(with: 2, to: maxLabelsCount)
72 | } else {
73 | return self.data
74 | }
75 | }
76 |
77 | private func calculateLabels(with interval: Int,
78 | to maxLabelsCount: Int) -> [ChartDataEntry] {
79 | let reversedData = Array(self.data.reversed())
80 | var finalLabels = [ChartDataEntry]()
81 | for index in stride(from: 0, through: self.data.count - 1, by: interval) {
82 | finalLabels.append(reversedData[index])
83 | }
84 | if finalLabels.count > maxLabelsCount {
85 | let adj = self.ref.ticksInterval ?? 1
86 | return self.calculateLabels(with: interval + adj, to: maxLabelsCount)
87 | }
88 | return Array(finalLabels.reversed())
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/Sources/BarChart/YAxis.swift:
--------------------------------------------------------------------------------
1 | //
2 | // YAxisLayout.swift
3 | // BarChart
4 | //
5 | // Copyright (c) 2020 Roman Baitaliuk
6 | // Permission is hereby granted, free of charge, to any person
7 | // obtaining a copy of this software and associated documentation
8 | // files (the "Software"), to deal in the Software without
9 | // restriction, including without limitation the rights to use,
10 | // copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | // copies of the Software, and to permit persons to whom the
12 | // Software is furnished to do so, subject to the following
13 | // conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be
16 | // included in all copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
20 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
22 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25 | // OTHER DEALINGS IN THE SOFTWARE.
26 |
27 | import SwiftUI
28 |
29 | struct YAxis: Identifiable {
30 | let id = UUID()
31 | let data: [Double]
32 | let frameHeight: CGFloat
33 | let ref: YAxisReference
34 | let labelsCTFont: CTFont
35 |
36 | var scaler: YAxisScaler? {
37 | guard let minValue = self.data.min(),
38 | let maxValue = self.data.max() else {
39 | return nil
40 | }
41 | let adjustedMin = minValue > 0 ? 0 : minValue
42 | let adjustedMax = maxValue < 0 ? 0 : maxValue
43 | return YAxisScaler(min: adjustedMin, max: adjustedMax, maxTicks: maxTicks)
44 | }
45 |
46 | var maxLabelWidth: CGFloat {
47 | return self.formattedLabels().map { $0.width(ctFont: self.labelsCTFont) }.max() ?? 0
48 | }
49 |
50 | init(frameHeight: CGFloat = 0,
51 | data: [Double] = [],
52 | ref: YAxisReference = YAxisReference(),
53 | labelsCTFont: CTFont = ChartConfiguration.defaultLabelsCTFont) {
54 | self.labelsCTFont = labelsCTFont
55 | self.frameHeight = frameHeight
56 | self.data = data
57 | self.ref = ref
58 | }
59 |
60 | private var maxTicks: Int {
61 | return Int(self.frameHeight / self.ref.minTicksSpacing)
62 | }
63 |
64 | func formattedLabels() -> [String] {
65 | guard let tickSpacing = self.scaler?.tickSpacing else { return [] }
66 | return self.scaler?.scaledValues().map { self.ref.formatter($0, tickSpacing.decimalsCount()) } ?? []
67 | }
68 |
69 | func labelValue(at index: Int) -> Double? {
70 | return self.scaler?.scaledValues()[index]
71 | }
72 |
73 | func pixelsRatio() -> CGFloat? {
74 | guard let verticalDistance = self.verticalDistance(),
75 | verticalDistance != 0 else { return nil }
76 | return self.frameHeight / CGFloat(verticalDistance)
77 | }
78 |
79 | func centre() -> CGFloat? {
80 | guard let chartMin = self.scaler?.scaledMin,
81 | let pixelsRatio = self.pixelsRatio() else { return nil }
82 | return CGFloat(chartMin) * pixelsRatio
83 | }
84 |
85 | func normalizedValues() -> [Double] {
86 | guard let verticalDistance = self.verticalDistance(),
87 | verticalDistance != 0 else { return [] }
88 | return self.data.map { $0 / verticalDistance }
89 | }
90 |
91 | private func verticalDistance() -> Double? {
92 | guard let chartMax = self.scaler?.scaledMax,
93 | let chartMin = self.scaler?.scaledMin else { return nil }
94 | return abs(chartMax) + abs(chartMin)
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/Sources/BarChart/BarChartView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BarChartView.swift
3 | // BarChart
4 | //
5 | // Copyright (c) 2020 Roman Baitaliuk
6 | // Permission is hereby granted, free of charge, to any person
7 | // obtaining a copy of this software and associated documentation
8 | // files (the "Software"), to deal in the Software without
9 | // restriction, including without limitation the rights to use,
10 | // copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | // copies of the Software, and to permit persons to whom the
12 | // Software is furnished to do so, subject to the following
13 | // conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be
16 | // included in all copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
20 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
22 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25 | // OTHER DEALINGS IN THE SOFTWARE.
26 |
27 | import SwiftUI
28 |
29 | public struct SelectableBarChartView : View {
30 | @ObservedObject var config: ChartConfiguration
31 | @State var xAxis = XAxis()
32 | @State var yAxis = YAxis()
33 | @State var selectionCallback: ((ChartDataEntry, CGPoint) -> Void)?
34 | var selectionView: SelectionView?
35 |
36 | public init(config: ChartConfiguration) {
37 | self.config = config
38 | }
39 |
40 | init(config: ChartConfiguration,
41 | selectionCallback: ((ChartDataEntry, CGPoint) -> Void)? = nil,
42 | selectionView: SelectionView? = nil) {
43 | self.init(config: config)
44 | self._selectionCallback = State(wrappedValue: selectionCallback)
45 | self.selectionView = selectionView
46 | }
47 |
48 | public var body: some View {
49 | ZStack {
50 | GeometryReader { proxy in
51 | CoordinateSystemView(yAxis: self.yAxis,
52 | xAxis: self.xAxis,
53 | frameSize: proxy.size).id(UUID())
54 | .onReceive(self.config.objectWillChange) { _ in
55 | self.yAxis = YAxis(frameHeight: self.yAxisHeight(proxy.size.height),
56 | data: self.config.data.yValues,
57 | ref: self.config.yAxis,
58 | labelsCTFont: self.config.labelsCTFont)
59 | self.xAxis = XAxis(frameWidth: proxy.size.width - self.yAxis.maxLabelWidth,
60 | data: self.config.data.entries,
61 | ref: self.config.xAxis,
62 | labelsCTFont: self.config.labelsCTFont)
63 | }
64 | self.selectionView
65 | BarChartCollectionView(yAxis: self.yAxis,
66 | xAxis: self.xAxis,
67 | gradient: self.config.data.gradientColor?.gradient(),
68 | color: self.config.data.color,
69 | selectionCallback: self.$selectionCallback)
70 | }
71 | }
72 | }
73 |
74 | private func yAxisHeight(_ frameHeight: CGFloat) -> CGFloat {
75 | let labelsHeight = String().height(ctFont: self.config.labelsCTFont)
76 | let topPadding = labelsHeight / 2
77 | let bottomPadding = labelsHeight * 1.5
78 | return frameHeight - (topPadding + bottomPadding)
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/Sources/BarChart/BarChartCollectionView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BarChartCollection.swift
3 | // BarChart
4 | //
5 | // Copyright (c) 2020 Roman Baitaliuk
6 | // Permission is hereby granted, free of charge, to any person
7 | // obtaining a copy of this software and associated documentation
8 | // files (the "Software"), to deal in the Software without
9 | // restriction, including without limitation the rights to use,
10 | // copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | // copies of the Software, and to permit persons to whom the
12 | // Software is furnished to do so, subject to the following
13 | // conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be
16 | // included in all copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
20 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
22 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25 | // OTHER DEALINGS IN THE SOFTWARE.
26 |
27 | import SwiftUI
28 |
29 | struct BarChartCollectionView: View {
30 | let yAxis: YAxis
31 | let xAxis: XAxis
32 | let gradient: Gradient?
33 | let color: Color
34 | @Binding var selectionCallback: ((ChartDataEntry, CGPoint) -> Void)?
35 |
36 | var body: some View {
37 | HStack(alignment: .bottom, spacing: self.xAxis.layout.spacing ?? 0) {
38 | if self.xAxis.layout.barWidth != nil {
39 | ForEach(0.. CGPoint {
57 | let x = self.xAxis.layout.barCentre(at: index)!
58 | let value = CGFloat(self.yAxis.normalizedValues()[index])
59 | let y = self.calculateTopOffset(for: value)
60 | return CGPoint(x: x, y: y)
61 | }
62 |
63 | func offsetY(at index: Int) -> CGFloat {
64 | guard let maxNormalizedValue = self.yAxis.normalizedValues().max() else { return 0 }
65 | let chartNormalisedMax = maxNormalizedValue > 0 ? maxNormalizedValue : 0
66 | let absoluteMax = abs(CGFloat(chartNormalisedMax))
67 | var offset = self.calculateTopOffset(for: absoluteMax)
68 | let barHeight = self.barHeight(at: index)
69 | // Adding offset for bars with negative normalised value
70 | if barHeight < 0 {
71 | offset -= barHeight
72 | }
73 | return offset
74 | }
75 |
76 | func calculateTopOffset(for value: CGFloat) -> CGFloat {
77 | guard let centre = self.yAxis.centre() else { return 0 }
78 | let maxBarHeight = value * self.yAxis.frameHeight
79 | let topPadding = String().height(ctFont: self.xAxis.labelsCTFont) / 2
80 | return self.yAxis.frameHeight - abs(centre) - maxBarHeight + topPadding
81 | }
82 |
83 | func barHeight(at index: Int) -> CGFloat {
84 | return CGFloat(self.yAxis.normalizedValues()[index]) * self.yAxis.frameHeight
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/Examples/BarChartExample-iOS/BarChartExample-iOS/SceneDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SceneDelegate.swift
3 | // BarChartExample-iOS
4 | //
5 | // Copyright (c) 2020 Roman Baitaliuk
6 | // Permission is hereby granted, free of charge, to any person
7 | // obtaining a copy of this software and associated documentation
8 | // files (the "Software"), to deal in the Software without
9 | // restriction, including without limitation the rights to use,
10 | // copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | // copies of the Software, and to permit persons to whom the
12 | // Software is furnished to do so, subject to the following
13 | // conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be
16 | // included in all copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
20 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
22 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25 | // OTHER DEALINGS IN THE SOFTWARE.
26 |
27 | import UIKit
28 | import SwiftUI
29 |
30 | class SceneDelegate: UIResponder, UIWindowSceneDelegate {
31 |
32 | var window: UIWindow?
33 |
34 |
35 | func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
36 | // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
37 | // If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
38 | // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
39 |
40 | // Create the SwiftUI view that provides the window contents.
41 | let contentView = ContentView()
42 |
43 | // Use a UIHostingController as window root view controller.
44 | if let windowScene = scene as? UIWindowScene {
45 | let window = UIWindow(windowScene: windowScene)
46 | window.rootViewController = UIHostingController(rootView: contentView)
47 | self.window = window
48 | window.makeKeyAndVisible()
49 | }
50 | }
51 |
52 | func sceneDidDisconnect(_ scene: UIScene) {
53 | // Called as the scene is being released by the system.
54 | // This occurs shortly after the scene enters the background, or when its session is discarded.
55 | // Release any resources associated with this scene that can be re-created the next time the scene connects.
56 | // The scene may re-connect later, as its session was not neccessarily discarded (see `application:didDiscardSceneSessions` instead).
57 | }
58 |
59 | func sceneDidBecomeActive(_ scene: UIScene) {
60 | // Called when the scene has moved from an inactive state to an active state.
61 | // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
62 | }
63 |
64 | func sceneWillResignActive(_ scene: UIScene) {
65 | // Called when the scene will move from an active state to an inactive state.
66 | // This may occur due to temporary interruptions (ex. an incoming phone call).
67 | }
68 |
69 | func sceneWillEnterForeground(_ scene: UIScene) {
70 | // Called as the scene transitions from the background to the foreground.
71 | // Use this method to undo the changes made on entering the background.
72 | }
73 |
74 | func sceneDidEnterBackground(_ scene: UIScene) {
75 | // Called as the scene transitions from the foreground to the background.
76 | // Use this method to save data, release shared resources, and store enough scene-specific state information
77 | // to restore the scene back to its current state.
78 | }
79 |
80 |
81 | }
82 |
83 |
--------------------------------------------------------------------------------
/Examples/SelectableBarChartExample-iOS/SelectableBarChartExample-iOS/SceneDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SceneDelegate.swift
3 | // SelectableBarChartExample-iOS
4 | //
5 | // Copyright (c) 2020 Roman Baitaliuk
6 | // Permission is hereby granted, free of charge, to any person
7 | // obtaining a copy of this software and associated documentation
8 | // files (the "Software"), to deal in the Software without
9 | // restriction, including without limitation the rights to use,
10 | // copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | // copies of the Software, and to permit persons to whom the
12 | // Software is furnished to do so, subject to the following
13 | // conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be
16 | // included in all copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
20 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
22 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25 | // OTHER DEALINGS IN THE SOFTWARE.
26 |
27 | import UIKit
28 | import SwiftUI
29 |
30 | class SceneDelegate: UIResponder, UIWindowSceneDelegate {
31 |
32 | var window: UIWindow?
33 |
34 |
35 | func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
36 | // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
37 | // If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
38 | // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
39 |
40 | // Create the SwiftUI view that provides the window contents.
41 | let contentView = ContentView()
42 |
43 | // Use a UIHostingController as window root view controller.
44 | if let windowScene = scene as? UIWindowScene {
45 | let window = UIWindow(windowScene: windowScene)
46 | window.rootViewController = UIHostingController(rootView: contentView)
47 | self.window = window
48 | window.makeKeyAndVisible()
49 | }
50 | }
51 |
52 | func sceneDidDisconnect(_ scene: UIScene) {
53 | // Called as the scene is being released by the system.
54 | // This occurs shortly after the scene enters the background, or when its session is discarded.
55 | // Release any resources associated with this scene that can be re-created the next time the scene connects.
56 | // The scene may re-connect later, as its session was not neccessarily discarded (see `application:didDiscardSceneSessions` instead).
57 | }
58 |
59 | func sceneDidBecomeActive(_ scene: UIScene) {
60 | // Called when the scene has moved from an inactive state to an active state.
61 | // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
62 | }
63 |
64 | func sceneWillResignActive(_ scene: UIScene) {
65 | // Called when the scene will move from an active state to an inactive state.
66 | // This may occur due to temporary interruptions (ex. an incoming phone call).
67 | }
68 |
69 | func sceneWillEnterForeground(_ scene: UIScene) {
70 | // Called as the scene transitions from the background to the foreground.
71 | // Use this method to undo the changes made on entering the background.
72 | }
73 |
74 | func sceneDidEnterBackground(_ scene: UIScene) {
75 | // Called as the scene transitions from the foreground to the background.
76 | // Use this method to save data, release shared resources, and store enough scene-specific state information
77 | // to restore the scene back to its current state.
78 | }
79 |
80 |
81 | }
82 |
83 |
--------------------------------------------------------------------------------
/Examples/BarChartExample-watchOS/BarChartExample-watchOS WatchKit Extension/ExtensionDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ExtensionDelegate.swift
3 | // BarChartExample-watchOS WatchKit Extension
4 | //
5 | // Copyright (c) 2020 Roman Baitaliuk
6 | // Permission is hereby granted, free of charge, to any person
7 | // obtaining a copy of this software and associated documentation
8 | // files (the "Software"), to deal in the Software without
9 | // restriction, including without limitation the rights to use,
10 | // copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | // copies of the Software, and to permit persons to whom the
12 | // Software is furnished to do so, subject to the following
13 | // conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be
16 | // included in all copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
20 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
22 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25 | // OTHER DEALINGS IN THE SOFTWARE.
26 |
27 | import WatchKit
28 |
29 | class ExtensionDelegate: NSObject, WKExtensionDelegate {
30 |
31 | func applicationDidFinishLaunching() {
32 | // Perform any final initialization of your application.
33 | }
34 |
35 | func applicationDidBecomeActive() {
36 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
37 | }
38 |
39 | func applicationWillResignActive() {
40 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
41 | // Use this method to pause ongoing tasks, disable timers, etc.
42 | }
43 |
44 | func handle(_ backgroundTasks: Set) {
45 | // Sent when the system needs to launch the application in the background to process tasks. Tasks arrive in a set, so loop through and process each one.
46 | for task in backgroundTasks {
47 | // Use a switch statement to check the task type
48 | switch task {
49 | case let backgroundTask as WKApplicationRefreshBackgroundTask:
50 | // Be sure to complete the background task once you’re done.
51 | backgroundTask.setTaskCompletedWithSnapshot(false)
52 | case let snapshotTask as WKSnapshotRefreshBackgroundTask:
53 | // Snapshot tasks have a unique completion call, make sure to set your expiration date
54 | snapshotTask.setTaskCompleted(restoredDefaultState: true, estimatedSnapshotExpiration: Date.distantFuture, userInfo: nil)
55 | case let connectivityTask as WKWatchConnectivityRefreshBackgroundTask:
56 | // Be sure to complete the connectivity task once you’re done.
57 | connectivityTask.setTaskCompletedWithSnapshot(false)
58 | case let urlSessionTask as WKURLSessionRefreshBackgroundTask:
59 | // Be sure to complete the URL session task once you’re done.
60 | urlSessionTask.setTaskCompletedWithSnapshot(false)
61 | case let relevantShortcutTask as WKRelevantShortcutRefreshBackgroundTask:
62 | // Be sure to complete the relevant-shortcut task once you're done.
63 | relevantShortcutTask.setTaskCompletedWithSnapshot(false)
64 | case let intentDidRunTask as WKIntentDidRunRefreshBackgroundTask:
65 | // Be sure to complete the intent-did-run task once you're done.
66 | intentDidRunTask.setTaskCompletedWithSnapshot(false)
67 | default:
68 | // make sure to complete unhandled task types
69 | task.setTaskCompletedWithSnapshot(false)
70 | }
71 | }
72 | }
73 |
74 | }
75 |
--------------------------------------------------------------------------------
/Sources/BarChart/YAxisScaler.swift:
--------------------------------------------------------------------------------
1 | //
2 | // YAxisScaler.swift
3 | // BarChart
4 | //
5 | // Copyright (c) 2020 Roman Baitaliuk
6 | // Permission is hereby granted, free of charge, to any person
7 | // obtaining a copy of this software and associated documentation
8 | // files (the "Software"), to deal in the Software without
9 | // restriction, including without limitation the rights to use,
10 | // copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | // copies of the Software, and to permit persons to whom the
12 | // Software is furnished to do so, subject to the following
13 | // conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be
16 | // included in all copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
20 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
22 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25 | // OTHER DEALINGS IN THE SOFTWARE.
26 |
27 | import Foundation
28 |
29 | struct YAxisScaler {
30 | private var minPoint: Double
31 | private var maxPoint: Double
32 | private var maxTicks: Int
33 | private(set) var tickSpacing: Double?
34 | private(set) var scaledMin: Double?
35 | private(set) var scaledMax: Double?
36 |
37 | init(min: Double, max: Double, maxTicks: Int) {
38 | self.maxTicks = maxTicks
39 | self.minPoint = min
40 | self.maxPoint = max
41 | self.calculate()
42 | }
43 |
44 | func scaledValues() -> [Double] {
45 | guard let tickSpacing = self.tickSpacing,
46 | let min = self.scaledMin,
47 | let max = self.scaledMax else { return [] }
48 | var labels = [Double]()
49 |
50 | // Adjusted max to include actual max to the list
51 | let adjustedMax = max + tickSpacing / 2
52 | for label in stride(from: min, to: adjustedMax, by: tickSpacing) {
53 | labels.append(self.removeTrailingZeros(label, to: tickSpacing.decimalsCount()))
54 | }
55 | return labels
56 | }
57 |
58 | private mutating func calculate() {
59 | guard self.maxTicks > 1,
60 | self.maxPoint > self.minPoint else { return }
61 | let range = self.scale(self.maxPoint - self.minPoint, round: false)
62 | let tickSpacing = self.scale(range / Double((self.maxTicks - 1)), round: true)
63 | let scaledMin = floor(self.minPoint / tickSpacing) * tickSpacing
64 | self.scaledMin = self.removeTrailingZeros(scaledMin, to: tickSpacing.decimalsCount())
65 | let scaledMax = ceil(self.maxPoint / tickSpacing) * tickSpacing
66 | self.scaledMax = self.removeTrailingZeros(scaledMax, to: tickSpacing.decimalsCount())
67 | self.tickSpacing = tickSpacing
68 | }
69 |
70 | private func removeTrailingZeros(_ value: Double, to decimalsCount: Int) -> Double {
71 | return Double(String(format: "%.\(decimalsCount)f", value))!
72 | }
73 |
74 | private func scale(_ range: Double, round: Bool) -> Double {
75 | let exponent = floor(log10(range))
76 | let fraction = range / pow(10, exponent)
77 | let niceFraction: Double
78 |
79 | if round {
80 | if fraction <= 1.5 {
81 | niceFraction = 1
82 | } else if fraction <= 3 {
83 | niceFraction = 2
84 | } else if fraction <= 7 {
85 | niceFraction = 5
86 | } else {
87 | niceFraction = 10
88 | }
89 | } else {
90 | if fraction <= 1 {
91 | niceFraction = 1
92 | } else if fraction <= 2 {
93 | niceFraction = 2
94 | } else if fraction <= 5 {
95 | niceFraction = 5
96 | } else {
97 | niceFraction = 10
98 | }
99 | }
100 |
101 | return niceFraction * pow(10, exponent)
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/Examples/BarChartExample-tvOS/BarChartExample-tvOS/ContentView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ContentView.swift
3 | // BarChartExample-tvOS
4 | //
5 | // Copyright (c) 2020 Roman Baitaliuk
6 | // Permission is hereby granted, free of charge, to any person
7 | // obtaining a copy of this software and associated documentation
8 | // files (the "Software"), to deal in the Software without
9 | // restriction, including without limitation the rights to use,
10 | // copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | // copies of the Software, and to permit persons to whom the
12 | // Software is furnished to do so, subject to the following
13 | // conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be
16 | // included in all copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
20 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
22 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25 | // OTHER DEALINGS IN THE SOFTWARE.
26 |
27 | import SwiftUI
28 | import BarChart
29 |
30 | struct ContentView: View {
31 |
32 | // MARK: - Chart Properties
33 |
34 | let chartHeight: CGFloat = 400
35 | let config = ChartConfiguration()
36 | @State var entries: [ChartDataEntry] = []
37 |
38 | // MARK: - Controls Properties
39 |
40 | @State var maxEntriesCount: String = ""
41 | @State var xAxisTicksIntervalValue: String = ""
42 | @State var isXAxisTicksHidden: Bool = false
43 |
44 | // MARK: - Views
45 |
46 | var body: some View {
47 | NavigationView {
48 | ScrollView {
49 | VStack(spacing: 10) {
50 | self.chartView()
51 | self.controlsView()
52 | }
53 | .padding(5)
54 | }
55 | }
56 | }
57 |
58 | func chartView() -> some View {
59 | ZStack {
60 | // Drop shadow rectangle
61 | RoundedRectangle(cornerRadius: 5)
62 | .foregroundColor(.white)
63 | .padding(5)
64 | .shadow(color: .black, radius: 5)
65 | Text("No data").opacity(self.entries.isEmpty ? 1.0 : 0.0)
66 | BarChartView(config: self.config)
67 | .onAppear() {
68 | let labelsFont = CTFontCreateWithName(("SFProText-Regular" as CFString), 10, nil)
69 | self.config.data.color = .red
70 | self.config.xAxis.labelsColor = .gray
71 | self.config.xAxis.ticksColor = .gray
72 | self.config.labelsCTFont = labelsFont
73 | self.config.xAxis.ticksStyle = StrokeStyle(lineWidth: 1.5, lineCap: .round, dash: [2, 4])
74 | self.config.yAxis.labelsColor = .gray
75 | self.config.yAxis.ticksColor = .gray
76 | self.config.yAxis.ticksStyle = StrokeStyle(lineWidth: 1.5, lineCap: .round, dash: [2, 4])
77 | self.config.yAxis.minTicksSpacing = 30.0
78 | self.config.yAxis.formatter = { (value, decimals) in
79 | let format = value == 0 ? "" : "b"
80 | return String(format: "%.\(decimals)f\(format)", value)
81 | }
82 | }
83 | .animation(.easeInOut)
84 | .onReceive([self.isXAxisTicksHidden].publisher.first()) { (value) in
85 | self.config.xAxis.ticksColor = value ? .clear : .gray
86 | }
87 | .onReceive([self.xAxisTicksIntervalValue].publisher.first()) { (value) in
88 | self.config.xAxis.ticksInterval = Int(value)
89 | }
90 | .padding(15)
91 | }.frame(height: self.chartHeight)
92 | }
93 |
94 | func controlsView() -> some View {
95 | Group {
96 | TextField("Max entries count", text: self.$maxEntriesCount).padding(15)
97 | HStack {
98 | Button(action: {
99 | let newEntries = self.randomEntries()
100 | self.entries = newEntries
101 | self.config.data.entries = newEntries
102 | }) {
103 | Text("Generate entries")
104 | }
105 | Button(action: {
106 | self.config.data.color = Color.random
107 | }) {
108 | Text("Generate color")
109 | }
110 | Button(action: {
111 | self.config.data.gradientColor = GradientColor(start: Color.random, end: Color.random)
112 | }) {
113 | Text("Generate gradient")
114 | }
115 | }
116 | TextField("x- axis ticks interval", text: self.$xAxisTicksIntervalValue).padding(15)
117 | Toggle(isOn: self.$isXAxisTicksHidden, label: {
118 | Text("X axis ticks is hidden")
119 | }).padding(15)
120 | }
121 | }
122 |
123 | // MARK: - Random Helpers
124 |
125 | func randomEntries() -> [ChartDataEntry] {
126 | var entries = [ChartDataEntry]()
127 | guard let maxEntriesCount = Int(self.maxEntriesCount), maxEntriesCount > 0 else { return [] }
128 | for data in 0.. some View {
79 | VStack(alignment: .leading, spacing: 0) {
80 | self.selectionIndicatorView()
81 | self.chartView()
82 | }
83 | .frame(height: chartHeight)
84 | .padding(15)
85 | }
86 |
87 | func miniSelectableChartView() -> some View {
88 | SelectableBarChartView(config: self.config)
89 | .onBarSelection { entry, location in
90 | self.selectedBarTopCentreLocation = location
91 | self.selectedEntry = entry
92 | }
93 | .selectionView {
94 | MiniSelectionIndicator(entry: self.selectedEntry,
95 | location: self.selectedBarTopCentreLocation)
96 | }
97 | .frame(height: self.chartHeight - self.selectionIndicatorHeight)
98 | .padding(15)
99 | }
100 |
101 | func chartView() -> some View {
102 | GeometryReader { proxy in
103 | SelectableBarChartView(config: self.config)
104 | .onBarSelection { entry, location in
105 | self.selectedBarTopCentreLocation = location
106 | self.selectedEntry = entry
107 | }
108 | .selectionView {
109 | SelectionLine(location: self.selectedBarTopCentreLocation,
110 | height: proxy.size.height - 17)
111 | }
112 | }
113 | }
114 |
115 | func selectionIndicatorView() -> some View {
116 | Group {
117 | if self.selectedEntry != nil && self.selectedBarTopCentreLocation != nil {
118 | SelectionIndicator(entry: self.selectedEntry!,
119 | location: self.selectedBarTopCentreLocation!.x,
120 | infoRectangleColor: Color(red: 241/255, green: 242/255, blue: 245/255))
121 | } else {
122 | Rectangle().foregroundColor(.clear)
123 | }
124 | }
125 | .frame(height: self.selectionIndicatorHeight)
126 | }
127 |
128 | func randomEntries() -> [ChartDataEntry] {
129 | var entries = [ChartDataEntry]()
130 | for data in 0..<15 {
131 | let randomDouble = Double.random(in: -20...50)
132 | let newEntry = ChartDataEntry(x: "\(2000+data)", y: randomDouble)
133 | entries.append(newEntry)
134 | }
135 | return entries
136 | }
137 |
138 | func resetSelection() {
139 | self.selectedBarTopCentreLocation = nil
140 | self.selectedEntry = nil
141 | }
142 | }
143 |
144 | struct ContentView_Previews: PreviewProvider {
145 | static var previews: some View {
146 | ContentView()
147 | }
148 | }
149 |
--------------------------------------------------------------------------------
/Examples/BarChartExample-macOS/BarChartExample-macOS/ContentView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ContentView.swift
3 | // BarChartExample-macOS
4 | //
5 | // Copyright (c) 2020 Roman Baitaliuk
6 | // Permission is hereby granted, free of charge, to any person
7 | // obtaining a copy of this software and associated documentation
8 | // files (the "Software"), to deal in the Software without
9 | // restriction, including without limitation the rights to use,
10 | // copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | // copies of the Software, and to permit persons to whom the
12 | // Software is furnished to do so, subject to the following
13 | // conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be
16 | // included in all copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
20 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
22 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25 | // OTHER DEALINGS IN THE SOFTWARE.
26 |
27 | import SwiftUI
28 | import BarChart
29 |
30 | struct ContentView: View {
31 |
32 | // MARK: - Chart Properties
33 |
34 | let chartHeight: CGFloat = 300
35 | let config = ChartConfiguration()
36 | @State var entries: [ChartDataEntry] = []
37 |
38 | // MARK: - Controls Properties
39 |
40 | @State var maxEntriesCount: Int = 0
41 | @State var xAxisTicksIntervalValue: Double = 1
42 | @State var isXAxisTicksHidden: Bool = false
43 |
44 | // MARK: - Views
45 |
46 | var body: some View {
47 | NavigationView {
48 | ScrollView {
49 | VStack(spacing: 10) {
50 | self.chartView()
51 | self.controlsView()
52 | }
53 | .padding(5)
54 | }
55 | }
56 | }
57 |
58 | func chartView() -> some View {
59 | ZStack {
60 | // Drop shadow rectangle
61 | RoundedRectangle(cornerRadius: 5)
62 | .foregroundColor(.white)
63 | .padding(5)
64 | .shadow(color: .black, radius: 5)
65 | Text("No data").opacity(self.entries.isEmpty ? 1.0 : 0.0)
66 | BarChartView(config: self.config)
67 | .onAppear() {
68 | let labelsFont = CTFontCreateWithName(("SFProText-Regular" as CFString), 10, nil)
69 | self.config.data.color = .red
70 | self.config.xAxis.labelsColor = .gray
71 | self.config.xAxis.ticksColor = .gray
72 | self.config.labelsCTFont = labelsFont
73 | self.config.xAxis.ticksStyle = StrokeStyle(lineWidth: 1.5, lineCap: .round, dash: [2, 4])
74 | self.config.yAxis.labelsColor = .gray
75 | self.config.yAxis.ticksColor = .gray
76 | self.config.yAxis.ticksStyle = StrokeStyle(lineWidth: 1.5, lineCap: .round, dash: [2, 4])
77 | self.config.yAxis.minTicksSpacing = 30.0
78 | self.config.yAxis.formatter = { (value, decimals) in
79 | let format = value == 0 ? "" : "b"
80 | return String(format: "%.\(decimals)f\(format)", value)
81 | }
82 | }
83 | .animation(.easeInOut)
84 | .onReceive([self.isXAxisTicksHidden].publisher.first()) { (value) in
85 | self.config.xAxis.ticksColor = value ? .clear : .gray
86 | }
87 | .onReceive([self.xAxisTicksIntervalValue].publisher.first()) { (value) in
88 | self.config.xAxis.ticksInterval = Int(value)
89 | }
90 | .padding(15)
91 | }.frame(height: self.chartHeight)
92 | }
93 |
94 | func controlsView() -> some View {
95 | Group {
96 | Stepper(value: self.$maxEntriesCount, in: 0...30) {
97 | Text("Max entries count: \(self.maxEntriesCount)")
98 | }.padding(15)
99 | HStack {
100 | Button(action: {
101 | let newEntries = self.randomEntries()
102 | self.entries = newEntries
103 | self.config.data.entries = newEntries
104 | }) {
105 | Text("Generate entries")
106 | }
107 | Button(action: {
108 | self.config.data.color = Color.random
109 | }) {
110 | Text("Generate color")
111 | }
112 | Button(action: {
113 | self.config.data.gradientColor = GradientColor(start: Color.random, end: Color.random)
114 | }) {
115 | Text("Generate gradient")
116 | }
117 | }
118 | HStack {
119 | Stepper(value: self.$xAxisTicksIntervalValue, in: 1...4) {
120 | Text("X axis ticks interval: \(Int(self.xAxisTicksIntervalValue))")
121 | }.padding(15)
122 | Toggle(isOn: self.$isXAxisTicksHidden, label: {
123 | Text("X axis ticks is hidden")
124 | }).padding(15)
125 | }
126 | }
127 | }
128 |
129 | // MARK: - Random Helpers
130 |
131 | func randomEntries() -> [ChartDataEntry] {
132 | var entries = [ChartDataEntry]()
133 | guard self.maxEntriesCount > 0 else { return [] }
134 | for data in 0.. Path {
61 | var vLine = Path()
62 | vLine.move(to: self.points.0)
63 | vLine.addLine(to: self.points.1)
64 | return vLine
65 | }
66 | }
67 |
68 | struct LabelView: View {
69 | let text: String
70 | let ctFont: CTFont
71 | let color: Color
72 |
73 | var body: some View {
74 | Text(self.text)
75 | .font(Font(self.ctFont))
76 | .foregroundColor(self.color)
77 | }
78 | }
79 |
80 | struct XAxisView: View {
81 | let xAxis: XAxis
82 | let frameSize: CGSize
83 |
84 | var body: some View {
85 | ForEach((0.. CGFloat {
100 | let tickX = self.tickX(at: index)
101 | let x = tickX - self.frameSize.width / 2
102 | return x
103 | }
104 |
105 | func tickX(at index: Int) -> CGFloat {
106 | let chartEntry = self.xAxis.chartEntry(at: index)
107 | guard let indexAtFullRange = self.xAxis.data.firstIndex(where: { $0 == chartEntry }),
108 | let centre = self.xAxis.layout.barCentre(at: indexAtFullRange) else { return 0 }
109 | return centre
110 | }
111 |
112 | func tickPoints(index: Int) -> (CGPoint, CGPoint) {
113 | let x = self.tickX(at: index)
114 | let labelsHeight = String().height(ctFont: self.xAxis.labelsCTFont)
115 | let startY = labelsHeight / 2
116 | let endY = self.frameSize.height - labelsHeight * 1.5
117 | return (CGPoint(x: x, y: startY), CGPoint(x: x, y: endY))
118 | }
119 | }
120 |
121 | struct YAxisView: View {
122 | let yAxis: YAxis
123 | let frameSize: CGSize
124 |
125 | var body: some View {
126 | ForEach((0.. StrokeStyle {
141 | var style = self.yAxis.ref.ticksStyle
142 | if self.yAxis.labelValue(at: index) == 0 {
143 | style.dash = []
144 | return style
145 | }
146 | return style
147 | }
148 |
149 | func labelOffsetY(at index: Int) -> CGFloat {
150 | let tickY = self.tickY(at: index)
151 | let height = self.frameSize.height
152 | let y = (height - tickY) - (height / 2)
153 | return y
154 | }
155 |
156 | func tickY(at index: Int) -> CGFloat {
157 | guard let chartMin = self.yAxis.scaler?.scaledMin,
158 | let pixelsRatio = self.yAxis.pixelsRatio(),
159 | let label = self.yAxis.labelValue(at: index) else { return 0 }
160 | let shift = String().height(ctFont: self.yAxis.labelsCTFont) * 1.5
161 | return (CGFloat(label) - CGFloat(chartMin)) * pixelsRatio + shift
162 | }
163 |
164 | func tickPoints(index: Int) -> (CGPoint, CGPoint) {
165 | let y = self.tickY(at: index)
166 | return self.tickPoints(y: y)
167 | }
168 |
169 | func tickPoints(y: CGFloat) -> (CGPoint, CGPoint) {
170 | let endPointX = self.frameSize.width - self.yAxis.maxLabelWidth
171 | return (CGPoint(x: 0, y: y), CGPoint(x: endPointX, y: y))
172 | }
173 | }
174 |
--------------------------------------------------------------------------------
/Examples/BarChartExample-iOS/BarChartExample-iOS/ContentView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ContentView.swift
3 | // BarChartExample-iOS
4 | //
5 | // Copyright (c) 2020 Roman Baitaliuk
6 | // Permission is hereby granted, free of charge, to any person
7 | // obtaining a copy of this software and associated documentation
8 | // files (the "Software"), to deal in the Software without
9 | // restriction, including without limitation the rights to use,
10 | // copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | // copies of the Software, and to permit persons to whom the
12 | // Software is furnished to do so, subject to the following
13 | // conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be
16 | // included in all copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
20 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
22 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25 | // OTHER DEALINGS IN THE SOFTWARE.
26 |
27 | import SwiftUI
28 | import BarChart
29 |
30 | struct ContentView: View {
31 |
32 | let orientationChanged = NotificationCenter.default.publisher(for: UIDevice.orientationDidChangeNotification)
33 | .makeConnectable()
34 | .autoconnect()
35 |
36 | // MARK: - Chart Properties
37 |
38 | let chartHeight: CGFloat = 400
39 | let config = ChartConfiguration()
40 | @State var entries = [ChartDataEntry]()
41 | @State var selectedBarTopCentreLocation: CGPoint?
42 | @State var selectedEntry: ChartDataEntry?
43 |
44 | // MARK: - Controls Properties
45 |
46 | @State var maxEntriesCount: Int = 0
47 | @State var xAxisTicksIntervalValue: Double = 1
48 | @State var isXAxisTicksHidden: Bool = false
49 |
50 | // MARK: - Views
51 |
52 | var body: some View {
53 | NavigationView {
54 | ScrollView {
55 | VStack(spacing: 10) {
56 | self.chartView()
57 | self.controlsView()
58 | .navigationBarTitle(Text("BarChart"))
59 | }
60 | .padding(5)
61 | }
62 | }.navigationViewStyle(StackNavigationViewStyle())
63 | }
64 |
65 | func selectionIndicatorView() -> some View {
66 | Group {
67 | if self.selectedEntry != nil && self.selectedBarTopCentreLocation != nil {
68 | SelectionIndicator(entry: self.selectedEntry!,
69 | location: self.selectedBarTopCentreLocation!.x,
70 | infoRectangleColor: Color(red: 241/255, green: 242/255, blue: 245/255))
71 | } else {
72 | Rectangle().foregroundColor(.clear)
73 | }
74 | }
75 | .frame(height: 60)
76 | }
77 |
78 | func chartView() -> some View {
79 | ZStack {
80 | // Drop shadow rectangle
81 | RoundedRectangle(cornerRadius: 5)
82 | .foregroundColor(.white)
83 | .padding(5)
84 | .shadow(color: .black, radius: 5)
85 | Text("No data").opacity(self.entries.isEmpty ? 1.0 : 0.0)
86 | VStack(alignment: .leading, spacing: 0) {
87 | self.selectionIndicatorView()
88 | SelectableBarChartView(config: self.config)
89 | .onBarSelection { entry, location in
90 | self.selectedBarTopCentreLocation = location
91 | self.selectedEntry = entry
92 | }
93 | .selectionView {
94 | SelectionLine(location: self.selectedBarTopCentreLocation,
95 | height: 295)
96 | }
97 | .onAppear() {
98 | let labelsFont = CTFontCreateWithName(("SFProText-Regular" as CFString), 10, nil)
99 | self.config.data.entries = self.randomEntries()
100 | self.config.data.color = .red
101 | self.config.xAxis.labelsColor = .gray
102 | self.config.xAxis.ticksColor = .gray
103 | self.config.labelsCTFont = labelsFont
104 | self.config.xAxis.ticksStyle = StrokeStyle(lineWidth: 1.5, lineCap: .round, dash: [2, 4])
105 | self.config.yAxis.labelsColor = .gray
106 | self.config.yAxis.ticksColor = .gray
107 | self.config.yAxis.ticksStyle = StrokeStyle(lineWidth: 1.5, lineCap: .round, dash: [2, 4])
108 | self.config.yAxis.minTicksSpacing = 30.0
109 | self.config.yAxis.formatter = { (value, decimals) in
110 | let format = value == 0 ? "" : "b"
111 | return String(format: " %.\(decimals)f\(format)", value)
112 | }
113 | }
114 | .animation(.easeInOut)
115 | .onReceive([self.isXAxisTicksHidden].publisher.first()) { (value) in
116 | self.config.xAxis.ticksColor = value ? .clear : .gray
117 | }
118 | .onReceive([self.xAxisTicksIntervalValue].publisher.first()) { (value) in
119 | self.config.xAxis.ticksInterval = Int(value)
120 | }
121 | .onReceive(self.orientationChanged) { _ in
122 | self.config.objectWillChange.send()
123 | }
124 | }.padding(15)
125 | }.frame(height: self.chartHeight)
126 | }
127 |
128 | func controlsView() -> some View {
129 | Group {
130 | VStack(spacing: 0) {
131 | Stepper(value: self.$maxEntriesCount, in: 0...30) {
132 | Text("Max entries count: \(self.maxEntriesCount)")
133 | }.padding(15)
134 | Button(action: {
135 | let newEntries = self.randomEntries()
136 | self.entries = newEntries
137 | self.config.data.entries = newEntries
138 | }) {
139 | Text("Generate entries")
140 | }.randomButtonStyle()
141 | }
142 | HStack {
143 | Button(action: {
144 | self.config.data.color = Color.random
145 | }) {
146 | Text("Generate color")
147 | }.randomButtonStyle()
148 | Button(action: {
149 | self.config.data.gradientColor = GradientColor(start: Color.random, end: Color.random)
150 | }) {
151 | Text("Generate gradient")
152 | }.randomButtonStyle()
153 | }
154 | Stepper(value: self.$xAxisTicksIntervalValue, in: 1...4) {
155 | Text("X axis ticks interval: \(Int(self.xAxisTicksIntervalValue))")
156 | }.padding(15)
157 | Toggle(isOn: self.$isXAxisTicksHidden, label: {
158 | Text("X axis ticks is hidden")
159 | }).padding(15)
160 | }
161 | }
162 |
163 | // MARK: - Random Helpers
164 |
165 | func randomEntries() -> [ChartDataEntry] {
166 | var entries = [ChartDataEntry]()
167 | guard self.maxEntriesCount > 0 else { return [] }
168 | for data in 0.. some View {
189 | content
190 | .padding(10)
191 | .background(Color.gray.opacity(0.2))
192 | .cornerRadius(8)
193 | }
194 | }
195 |
196 | extension View {
197 | func randomButtonStyle() -> some View {
198 | self.modifier(RandomButtonStyle())
199 | }
200 | }
201 |
--------------------------------------------------------------------------------
/Tests/BarChartTests/TestData.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TestData.swift
3 | // BarChartTests
4 | //
5 | // Copyright (c) 2020 Roman Baitaliuk
6 | // Permission is hereby granted, free of charge, to any person
7 | // obtaining a copy of this software and associated documentation
8 | // files (the "Software"), to deal in the Software without
9 | // restriction, including without limitation the rights to use,
10 | // copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | // copies of the Software, and to permit persons to whom the
12 | // Software is furnished to do so, subject to the following
13 | // conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be
16 | // included in all copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
20 | // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
22 | // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25 | // OTHER DEALINGS IN THE SOFTWARE.
26 |
27 | import Foundation
28 | @testable import BarChart
29 |
30 | struct TestData {
31 |
32 | static func generate(with values: [Double]) -> [ChartDataEntry] {
33 | var entries = [ChartDataEntry]()
34 | for (index, value) in values.enumerated() {
35 | let newEntry = ChartDataEntry(x: "\(index)", y: value)
36 | entries.append(newEntry)
37 | }
38 | return entries
39 | }
40 |
41 | struct Values {
42 | struct Positive {
43 | struct Small {
44 | static let values1: [Double] = [0.23875672295222253]
45 | static let values2: [Double] = [0.2684136185901309, 0.16131669522994863]
46 | static let values3: [Double] = [0.2639830126014629, 0.15974664769619834, 0.22752326268788364, 0.13911307358474653, 0.28026824376151305]
47 | static let values4: [Double] = [0.19727250308928962, 0.2308106471922598, 0.13256217023006187, 0.1367648372664736, 0.15714402753315498, 0.22588350803628962, 0.2644809090012066]
48 | static let values5: [Double] = [0.5466323238920077, 0.5156455479675484, 0.13291550274624686, 0.7771603858442256, 0.9025048107614076, 0.40737263782697297, 0.6655120656097606, 0.647796170763738, 0.3207767946207413, 0.2868540478265839, 0.2620104724701646, 0.8367088377208742, 0.21919262237132098, 0.1722920524489231, 0.15922626432748044, 0.4891199176880685, 0.23470257555145846, 0.8706489523436453, 0.8311258151046474, 0.5778233129883721, 0.8526875093676144]
49 | }
50 |
51 | struct Mid {
52 | static let values1: [Double] = [98.40067879858509]
53 | static let values2: [Double] = [55.052756589112676, 69.48356595339442]
54 | static let values3: [Double] = [40.57943586235161, 54.6206979706237, 43.43520250456608, 31.636360365610194, 42.312501067159566, 59.874004415953074]
55 | static let values4: [Double] = [46.23376707364597, 78.1047124748174, 96.76482212585093, 10.875552416027393, 4.145508110947263, 19.89589074913821, 57.87656976286651, 51.427645821760045]
56 | static let values5: [Double] = [49.172347022669214, 62.638089607406826, 39.332530499289774, 98.51617133533895, 89.76300260279845, 53.48150921316537, 50.61944810303782, 86.73384074151308, 6.481826092252144, 39.76813483486283, 42.43219019704493, 95.85471451668741, 6.639584266033531, 82.20578895864162, 57.20033695917166, 19.549376342682226, 9.526520334855517, 15.954728800028686]
57 | }
58 |
59 | struct Large {
60 | static let values1: [Double] = [933.608090793989]
61 | static let values2: [Double] = [260.29939965518247, 461.8232573168553]
62 | static let values3: [Double] = [212.20237931356752, 134.26672344492164, 170.78818158912125, 726.9360462508057, 433.4176900479346, 853.6549857725398]
63 | static let values4: [Double] = [172.6209415482361, 619.3983725348953, 613.0122947735748, 411.4339313375111, 959.4363998296446, 613.204165830946, 499.49495683521883, 591.6883034445457, 288.30229436515344, 722.2358023940463]
64 | static let values5: [Double] = [485.1778745682676, 372.1598793295034, 937.5620722111946, 667.034524273335, 645.3795123800068, 151.02751655585465, 801.0126816467382, 709.3331910204965, 950.5785950961556, 614.2357925588653, 848.0686234611463, 172.26868259108699, 990.3253385258535, 177.4444336874585, 677.0505570069992, 860.3715740108657, 584.0133371945478, 830.5029774825001, 103.07842008613726, 411.27737210941496, 803.2825484502141]
65 | }
66 | }
67 |
68 | struct Negative {
69 | struct Small {
70 | static let values1: [Double] = [-0.2362110700260261]
71 | static let values2: [Double] = [-0.11719829568796988, -0.1995677967246154]
72 | static let values3: [Double] = [-0.2882649374950868, -0.1328421271991442, -0.26172464939834195, -0.25592332283759134, -0.2887961694356732, -0.25240426028516927]
73 | static let values4: [Double] = [-0.2523331512221314, -0.18935587960194128, -0.1507128289270137, -0.2473339367312253, -0.11248666006869831, -0.1135295222658772, -0.14617562966908498]
74 | static let values5: [Double] = [-0.14539804216132646, -0.29087341537264905, -0.2791428956717379, -0.12177629522748437, -0.21288959751910208, -0.26150650039906886, -0.16288768820222366, -0.26280536120587306, -0.11326897716694947, -0.17391125484591427, -0.10603393446904713, -0.17493115249989497, -0.1022184734124871, -0.1483562776481696, -0.16983033913139306, -0.18051178923391525, -0.28008667534171316, -0.11474472761680429, -0.12902809125618483, -0.16910750985712852, -0.200144420741012]
75 | }
76 |
77 | struct Mid {
78 | static let values1: [Double] = [-14.317389855452234]
79 | static let values2: [Double] = [-40.44939166476918, -5.267268367336996]
80 | static let values3: [Double] = [-25.948740362913725, -25.864675726579208, -20.201968323409645, -4.5575961274022205, -43.374370609825185, -48.50547096385824, -73.3148551940273]
81 | static let values4: [Double] = [-23.32930085055102, -44.81745644382531, -58.26116506455848, -21.868106648509922, -77.66153242628351, -61.74060343537626, -95.28112276855798, -20.72286052859303, -36.07821463080642, -9.036730358526029, -21.34876740902675]
82 | static let values5: [Double] = [-29.377128218151938, -43.583959440724, -60.57144998506984, -27.912392970038724, -67.66153493841162, -70.30545485895426, -46.609860516676626, -80.6715155854962, -21.121938873732148, -3.267065074012308, -52.523454355897, -15.809916074446946, -88.4664530162171, -53.46209175820739, -98.24645012760485, -40.621009321511025, -75.7607035928469, -38.65992086484787, -25.06331734152529, -78.77873313645318, -2.9205965090560397]
83 | }
84 |
85 | struct Large {
86 | static let values1: [Double] = [-239.74265265469944]
87 | static let values2: [Double] = [-193.61155473573785, -368.1931642646799]
88 | static let values3: [Double] = [-263.8260844385155, -379.47607946315, -182.0835402863488, -929.4225571744635, -135.37498938480132, -209.39533249920567]
89 | static let values4: [Double] = [-482.9912080921938, -543.0718270711238, -841.6834886284742, -734.3505573873854, -473.230466741987, -125.96731083377028, -950.3737016579273, -570.0150207483283, -402.2457519917757, -852.9327226621378, -866.820088496364, -749.8733270188756, -725.0817569634371, -964.5704647521372, -350.6768794744197, -693.8371332429392, -887.906685288875]
90 | static let values5: [Double] = [-682.298899071088, -289.8263516807647, -818.3603392841937, -156.83179737381136, -473.12448740337095, -204.6093884182285, -146.3741735870775, -771.3164241007768, -309.95411564741835, -532.0014464500366, -127.9993431009284, -223.90190879367856, -121.77408461442997, -479.21421264087246, -553.9472924202291, -980.8133668245063, -328.23929968378593, -367.45499321001125, -960.5696614584499, -697.1179671816379, -333.80047277900246]
91 | }
92 | }
93 |
94 | struct PositiveAndNegative {
95 | struct Small {
96 | static let values1: [Double] = [-0.1335971968625974, 0.15042626326352287]
97 | static let values2: [Double] = [-0.19179890231919727, -0.19824635093222207, -0.05614434058402015, 0.16531352492670082, -0.10222339146220016, -0.17616552491728152]
98 | static let values3: [Double] = [0.057043207052957345, -0.17266114786523465, -0.09896188581597838, 0.1634180468399561, 0.1535860219929393, -0.06401882651635035, -0.08171773896238582, -0.12653024551489617, -0.12004760971991035, 0.10813657584652997, 0.14047068164695253, 0.17068410990347432]
99 | static let values4: [Double] = [0.12667162089982958, 0.17602664191040757, -0.10828495319777849, 0.07979324073295657, 0.13153427513942845, -0.10111136704122692, 0.11681627329019051, -0.05903421856412311, 0.19521921218263705, -0.02370810151114977, 0.06461703898036253, 0.13998786150718262, -0.11201883397754818, -0.09976159758237757, -0.06217398412416958, -0.12906739295486927, -0.12133652920981391, -0.1271372430804091, 0.0274669493943423, 0.1583307792565014, -0.06211459861341548]
100 | }
101 |
102 | struct Mid {
103 | static let values1: [Double] = [23.339024477255577, -12.441113408473313]
104 | static let values2: [Double] = [-57.836785834777515, -16.987389371760187, -63.09884786907845, -3.3619202228148026, -83.07094357032865, 63.49941469148311, 36.21429109196649]
105 | static let values3: [Double] = [56.823797332560076, -9.357855660626186, 86.79928262657432, 56.28186010394933, 10.37623574317368, -42.93800045609437, 22.666713287829793, 28.987019069115746, -51.07790280394842, -41.19925956467978, 34.99749052093938]
106 | static let values4: [Double] = [-80.9558114658461, -67.43064256340811, -31.010891918466513, -16.32131696464714, -61.831198991633585, -82.08059846836338, -30.70622918552634, -92.0481265531018, -80.01410560184858, -82.78945014138348, -64.95836971316137, -37.965892989649944, 54.22067420486641, -26.048142477280933, -39.952902182187145, 83.91447831477453, 5.514409071277669, -10.492105497958562, 61.820823940755304, 62.98528862708713, -20.57484781633869]
107 | }
108 |
109 | struct Large {
110 | static let values1: [Double] = [-411.5522077713565, 452.5998797184061]
111 | static let values2: [Double] = [679.0210908916486, -64.84909457164622, 735.5191229658603, -977.9345158798944, 784.6456208118452, -547.5630323624714, -759.5371547032937, -895.6974715191906]
112 | static let values3: [Double] = [-554.6985982768471, 635.2717161738949, 988.9598813698935, -992.9083819967719, 160.33476011719517, -220.36808281929598, -514.4973029310049, -895.4112690956259, 815.015255945395, -5.453655979820837]
113 | static let values4: [Double] = [-352.5312506773248, 696.7781263271556, -826.1156693622315, -826.6704401550977, -986.5498962658393, -916.2192263655826, -219.01079748666393, -275.6620455326597, 75.32925703258411, -837.5219362769275, -72.8034295891922, 501.8440974667251, 215.25711662569665, 679.3870482501363, -614.2731047486398, -864.5668565796616, 931.4398647576736, 128.20720034681813, -735.4685658273128, 419.3802969561673, -925.4498519189034]
114 | }
115 | }
116 |
117 | }
118 | }
119 |
--------------------------------------------------------------------------------
/Examples/BarChartExample-tvOS/BarChartExample-tvOS.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 52;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | D317956D24C1B27F00DC2168 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D317956C24C1B27F00DC2168 /* AppDelegate.swift */; };
11 | D317956F24C1B27F00DC2168 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D317956E24C1B27F00DC2168 /* ContentView.swift */; };
12 | D317957124C1B27F00DC2168 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D317957024C1B27F00DC2168 /* Assets.xcassets */; };
13 | D317957424C1B27F00DC2168 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D317957324C1B27F00DC2168 /* Preview Assets.xcassets */; };
14 | D317957724C1B27F00DC2168 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = D317957524C1B27F00DC2168 /* LaunchScreen.storyboard */; };
15 | D399CAF0265C7F1A00A92054 /* BarChart in Frameworks */ = {isa = PBXBuildFile; productRef = D399CAEF265C7F1A00A92054 /* BarChart */; };
16 | /* End PBXBuildFile section */
17 |
18 | /* Begin PBXFileReference section */
19 | D317956924C1B27F00DC2168 /* BarChartExample-tvOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "BarChartExample-tvOS.app"; sourceTree = BUILT_PRODUCTS_DIR; };
20 | D317956C24C1B27F00DC2168 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
21 | D317956E24C1B27F00DC2168 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; };
22 | D317957024C1B27F00DC2168 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
23 | D317957324C1B27F00DC2168 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; };
24 | D317957624C1B27F00DC2168 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
25 | D317957824C1B27F00DC2168 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
26 | D399CAED265C7F1000A92054 /* BarChart */ = {isa = PBXFileReference; lastKnownFileType = folder; name = BarChart; path = ../..; sourceTree = ""; };
27 | /* End PBXFileReference section */
28 |
29 | /* Begin PBXFrameworksBuildPhase section */
30 | D317956624C1B27F00DC2168 /* Frameworks */ = {
31 | isa = PBXFrameworksBuildPhase;
32 | buildActionMask = 2147483647;
33 | files = (
34 | D399CAF0265C7F1A00A92054 /* BarChart in Frameworks */,
35 | );
36 | runOnlyForDeploymentPostprocessing = 0;
37 | };
38 | /* End PBXFrameworksBuildPhase section */
39 |
40 | /* Begin PBXGroup section */
41 | D317956024C1B27F00DC2168 = {
42 | isa = PBXGroup;
43 | children = (
44 | D399CAED265C7F1000A92054 /* BarChart */,
45 | D317956B24C1B27F00DC2168 /* BarChartExample-tvOS */,
46 | D317956A24C1B27F00DC2168 /* Products */,
47 | D399CAEE265C7F1A00A92054 /* Frameworks */,
48 | );
49 | sourceTree = "";
50 | };
51 | D317956A24C1B27F00DC2168 /* Products */ = {
52 | isa = PBXGroup;
53 | children = (
54 | D317956924C1B27F00DC2168 /* BarChartExample-tvOS.app */,
55 | );
56 | name = Products;
57 | sourceTree = "";
58 | };
59 | D317956B24C1B27F00DC2168 /* BarChartExample-tvOS */ = {
60 | isa = PBXGroup;
61 | children = (
62 | D317956C24C1B27F00DC2168 /* AppDelegate.swift */,
63 | D317956E24C1B27F00DC2168 /* ContentView.swift */,
64 | D317957024C1B27F00DC2168 /* Assets.xcassets */,
65 | D317957524C1B27F00DC2168 /* LaunchScreen.storyboard */,
66 | D317957824C1B27F00DC2168 /* Info.plist */,
67 | D317957224C1B27F00DC2168 /* Preview Content */,
68 | );
69 | path = "BarChartExample-tvOS";
70 | sourceTree = "";
71 | };
72 | D317957224C1B27F00DC2168 /* Preview Content */ = {
73 | isa = PBXGroup;
74 | children = (
75 | D317957324C1B27F00DC2168 /* Preview Assets.xcassets */,
76 | );
77 | path = "Preview Content";
78 | sourceTree = "";
79 | };
80 | D399CAEE265C7F1A00A92054 /* Frameworks */ = {
81 | isa = PBXGroup;
82 | children = (
83 | );
84 | name = Frameworks;
85 | sourceTree = "";
86 | };
87 | /* End PBXGroup section */
88 |
89 | /* Begin PBXNativeTarget section */
90 | D317956824C1B27F00DC2168 /* BarChartExample-tvOS */ = {
91 | isa = PBXNativeTarget;
92 | buildConfigurationList = D317957B24C1B27F00DC2168 /* Build configuration list for PBXNativeTarget "BarChartExample-tvOS" */;
93 | buildPhases = (
94 | D317956524C1B27F00DC2168 /* Sources */,
95 | D317956624C1B27F00DC2168 /* Frameworks */,
96 | D317956724C1B27F00DC2168 /* Resources */,
97 | );
98 | buildRules = (
99 | );
100 | dependencies = (
101 | );
102 | name = "BarChartExample-tvOS";
103 | packageProductDependencies = (
104 | D399CAEF265C7F1A00A92054 /* BarChart */,
105 | );
106 | productName = "BarChartExample-tvOS";
107 | productReference = D317956924C1B27F00DC2168 /* BarChartExample-tvOS.app */;
108 | productType = "com.apple.product-type.application";
109 | };
110 | /* End PBXNativeTarget section */
111 |
112 | /* Begin PBXProject section */
113 | D317956124C1B27F00DC2168 /* Project object */ = {
114 | isa = PBXProject;
115 | attributes = {
116 | LastSwiftUpdateCheck = 1160;
117 | LastUpgradeCheck = 1240;
118 | ORGANIZATIONNAME = "Roman Baitaliuk";
119 | TargetAttributes = {
120 | D317956824C1B27F00DC2168 = {
121 | CreatedOnToolsVersion = 11.6;
122 | };
123 | };
124 | };
125 | buildConfigurationList = D317956424C1B27F00DC2168 /* Build configuration list for PBXProject "BarChartExample-tvOS" */;
126 | compatibilityVersion = "Xcode 9.3";
127 | developmentRegion = en;
128 | hasScannedForEncodings = 0;
129 | knownRegions = (
130 | en,
131 | Base,
132 | );
133 | mainGroup = D317956024C1B27F00DC2168;
134 | packageReferences = (
135 | );
136 | productRefGroup = D317956A24C1B27F00DC2168 /* Products */;
137 | projectDirPath = "";
138 | projectRoot = "";
139 | targets = (
140 | D317956824C1B27F00DC2168 /* BarChartExample-tvOS */,
141 | );
142 | };
143 | /* End PBXProject section */
144 |
145 | /* Begin PBXResourcesBuildPhase section */
146 | D317956724C1B27F00DC2168 /* Resources */ = {
147 | isa = PBXResourcesBuildPhase;
148 | buildActionMask = 2147483647;
149 | files = (
150 | D317957724C1B27F00DC2168 /* LaunchScreen.storyboard in Resources */,
151 | D317957424C1B27F00DC2168 /* Preview Assets.xcassets in Resources */,
152 | D317957124C1B27F00DC2168 /* Assets.xcassets in Resources */,
153 | );
154 | runOnlyForDeploymentPostprocessing = 0;
155 | };
156 | /* End PBXResourcesBuildPhase section */
157 |
158 | /* Begin PBXSourcesBuildPhase section */
159 | D317956524C1B27F00DC2168 /* Sources */ = {
160 | isa = PBXSourcesBuildPhase;
161 | buildActionMask = 2147483647;
162 | files = (
163 | D317956F24C1B27F00DC2168 /* ContentView.swift in Sources */,
164 | D317956D24C1B27F00DC2168 /* AppDelegate.swift in Sources */,
165 | );
166 | runOnlyForDeploymentPostprocessing = 0;
167 | };
168 | /* End PBXSourcesBuildPhase section */
169 |
170 | /* Begin PBXVariantGroup section */
171 | D317957524C1B27F00DC2168 /* LaunchScreen.storyboard */ = {
172 | isa = PBXVariantGroup;
173 | children = (
174 | D317957624C1B27F00DC2168 /* Base */,
175 | );
176 | name = LaunchScreen.storyboard;
177 | sourceTree = "";
178 | };
179 | /* End PBXVariantGroup section */
180 |
181 | /* Begin XCBuildConfiguration section */
182 | D317957924C1B27F00DC2168 /* Debug */ = {
183 | isa = XCBuildConfiguration;
184 | buildSettings = {
185 | ALWAYS_SEARCH_USER_PATHS = NO;
186 | CLANG_ANALYZER_NONNULL = YES;
187 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
188 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
189 | CLANG_CXX_LIBRARY = "libc++";
190 | CLANG_ENABLE_MODULES = YES;
191 | CLANG_ENABLE_OBJC_ARC = YES;
192 | CLANG_ENABLE_OBJC_WEAK = YES;
193 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
194 | CLANG_WARN_BOOL_CONVERSION = YES;
195 | CLANG_WARN_COMMA = YES;
196 | CLANG_WARN_CONSTANT_CONVERSION = YES;
197 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
198 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
199 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
200 | CLANG_WARN_EMPTY_BODY = YES;
201 | CLANG_WARN_ENUM_CONVERSION = YES;
202 | CLANG_WARN_INFINITE_RECURSION = YES;
203 | CLANG_WARN_INT_CONVERSION = YES;
204 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
205 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
206 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
207 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
208 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
209 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
210 | CLANG_WARN_STRICT_PROTOTYPES = YES;
211 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
212 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
213 | CLANG_WARN_UNREACHABLE_CODE = YES;
214 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
215 | COPY_PHASE_STRIP = NO;
216 | DEBUG_INFORMATION_FORMAT = dwarf;
217 | ENABLE_STRICT_OBJC_MSGSEND = YES;
218 | ENABLE_TESTABILITY = YES;
219 | GCC_C_LANGUAGE_STANDARD = gnu11;
220 | GCC_DYNAMIC_NO_PIC = NO;
221 | GCC_NO_COMMON_BLOCKS = YES;
222 | GCC_OPTIMIZATION_LEVEL = 0;
223 | GCC_PREPROCESSOR_DEFINITIONS = (
224 | "DEBUG=1",
225 | "$(inherited)",
226 | );
227 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
228 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
229 | GCC_WARN_UNDECLARED_SELECTOR = YES;
230 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
231 | GCC_WARN_UNUSED_FUNCTION = YES;
232 | GCC_WARN_UNUSED_VARIABLE = YES;
233 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
234 | MTL_FAST_MATH = YES;
235 | ONLY_ACTIVE_ARCH = YES;
236 | SDKROOT = appletvos;
237 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
238 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
239 | TVOS_DEPLOYMENT_TARGET = 13.4;
240 | };
241 | name = Debug;
242 | };
243 | D317957A24C1B27F00DC2168 /* Release */ = {
244 | isa = XCBuildConfiguration;
245 | buildSettings = {
246 | ALWAYS_SEARCH_USER_PATHS = NO;
247 | CLANG_ANALYZER_NONNULL = YES;
248 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
249 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
250 | CLANG_CXX_LIBRARY = "libc++";
251 | CLANG_ENABLE_MODULES = YES;
252 | CLANG_ENABLE_OBJC_ARC = YES;
253 | CLANG_ENABLE_OBJC_WEAK = YES;
254 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
255 | CLANG_WARN_BOOL_CONVERSION = YES;
256 | CLANG_WARN_COMMA = YES;
257 | CLANG_WARN_CONSTANT_CONVERSION = YES;
258 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
259 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
260 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
261 | CLANG_WARN_EMPTY_BODY = YES;
262 | CLANG_WARN_ENUM_CONVERSION = YES;
263 | CLANG_WARN_INFINITE_RECURSION = YES;
264 | CLANG_WARN_INT_CONVERSION = YES;
265 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
266 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
267 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
268 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
269 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
270 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
271 | CLANG_WARN_STRICT_PROTOTYPES = YES;
272 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
273 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
274 | CLANG_WARN_UNREACHABLE_CODE = YES;
275 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
276 | COPY_PHASE_STRIP = NO;
277 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
278 | ENABLE_NS_ASSERTIONS = NO;
279 | ENABLE_STRICT_OBJC_MSGSEND = YES;
280 | GCC_C_LANGUAGE_STANDARD = gnu11;
281 | GCC_NO_COMMON_BLOCKS = YES;
282 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
283 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
284 | GCC_WARN_UNDECLARED_SELECTOR = YES;
285 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
286 | GCC_WARN_UNUSED_FUNCTION = YES;
287 | GCC_WARN_UNUSED_VARIABLE = YES;
288 | MTL_ENABLE_DEBUG_INFO = NO;
289 | MTL_FAST_MATH = YES;
290 | SDKROOT = appletvos;
291 | SWIFT_COMPILATION_MODE = wholemodule;
292 | SWIFT_OPTIMIZATION_LEVEL = "-O";
293 | TVOS_DEPLOYMENT_TARGET = 13.4;
294 | VALIDATE_PRODUCT = YES;
295 | };
296 | name = Release;
297 | };
298 | D317957C24C1B27F00DC2168 /* Debug */ = {
299 | isa = XCBuildConfiguration;
300 | buildSettings = {
301 | ASSETCATALOG_COMPILER_APPICON_NAME = "App Icon & Top Shelf Image";
302 | CODE_SIGN_STYLE = Manual;
303 | DEVELOPMENT_ASSET_PATHS = "\"BarChartExample-tvOS/Preview Content\"";
304 | DEVELOPMENT_TEAM = "";
305 | ENABLE_PREVIEWS = YES;
306 | INFOPLIST_FILE = "BarChartExample-tvOS/Info.plist";
307 | LD_RUNPATH_SEARCH_PATHS = (
308 | "$(inherited)",
309 | "@executable_path/Frameworks",
310 | );
311 | PRODUCT_BUNDLE_IDENTIFIER = "com.ByteKit.BarChartExample-tvOS";
312 | PRODUCT_NAME = "$(TARGET_NAME)";
313 | PROVISIONING_PROFILE_SPECIFIER = "";
314 | SWIFT_VERSION = 5.0;
315 | TARGETED_DEVICE_FAMILY = 3;
316 | };
317 | name = Debug;
318 | };
319 | D317957D24C1B27F00DC2168 /* Release */ = {
320 | isa = XCBuildConfiguration;
321 | buildSettings = {
322 | ASSETCATALOG_COMPILER_APPICON_NAME = "App Icon & Top Shelf Image";
323 | CODE_SIGN_STYLE = Manual;
324 | DEVELOPMENT_ASSET_PATHS = "\"BarChartExample-tvOS/Preview Content\"";
325 | DEVELOPMENT_TEAM = "";
326 | ENABLE_PREVIEWS = YES;
327 | INFOPLIST_FILE = "BarChartExample-tvOS/Info.plist";
328 | LD_RUNPATH_SEARCH_PATHS = (
329 | "$(inherited)",
330 | "@executable_path/Frameworks",
331 | );
332 | PRODUCT_BUNDLE_IDENTIFIER = "com.ByteKit.BarChartExample-tvOS";
333 | PRODUCT_NAME = "$(TARGET_NAME)";
334 | PROVISIONING_PROFILE_SPECIFIER = "";
335 | SWIFT_VERSION = 5.0;
336 | TARGETED_DEVICE_FAMILY = 3;
337 | };
338 | name = Release;
339 | };
340 | /* End XCBuildConfiguration section */
341 |
342 | /* Begin XCConfigurationList section */
343 | D317956424C1B27F00DC2168 /* Build configuration list for PBXProject "BarChartExample-tvOS" */ = {
344 | isa = XCConfigurationList;
345 | buildConfigurations = (
346 | D317957924C1B27F00DC2168 /* Debug */,
347 | D317957A24C1B27F00DC2168 /* Release */,
348 | );
349 | defaultConfigurationIsVisible = 0;
350 | defaultConfigurationName = Release;
351 | };
352 | D317957B24C1B27F00DC2168 /* Build configuration list for PBXNativeTarget "BarChartExample-tvOS" */ = {
353 | isa = XCConfigurationList;
354 | buildConfigurations = (
355 | D317957C24C1B27F00DC2168 /* Debug */,
356 | D317957D24C1B27F00DC2168 /* Release */,
357 | );
358 | defaultConfigurationIsVisible = 0;
359 | defaultConfigurationName = Release;
360 | };
361 | /* End XCConfigurationList section */
362 |
363 | /* Begin XCSwiftPackageProductDependency section */
364 | D399CAEF265C7F1A00A92054 /* BarChart */ = {
365 | isa = XCSwiftPackageProductDependency;
366 | productName = BarChart;
367 | };
368 | /* End XCSwiftPackageProductDependency section */
369 | };
370 | rootObject = D317956124C1B27F00DC2168 /* Project object */;
371 | }
372 |
--------------------------------------------------------------------------------
/Examples/BarChartExample-macOS/BarChartExample-macOS.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 52;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | D317954B24C1ADDF00DC2168 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D317954A24C1ADDF00DC2168 /* AppDelegate.swift */; };
11 | D317954D24C1ADDF00DC2168 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D317954C24C1ADDF00DC2168 /* ContentView.swift */; };
12 | D317954F24C1ADE000DC2168 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D317954E24C1ADE000DC2168 /* Assets.xcassets */; };
13 | D317955224C1ADE000DC2168 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D317955124C1ADE000DC2168 /* Preview Assets.xcassets */; };
14 | D317955524C1ADE000DC2168 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = D317955324C1ADE000DC2168 /* Main.storyboard */; };
15 | D399CAEA265C7E6900A92054 /* BarChart in Frameworks */ = {isa = PBXBuildFile; productRef = D399CAE9265C7E6900A92054 /* BarChart */; };
16 | /* End PBXBuildFile section */
17 |
18 | /* Begin PBXFileReference section */
19 | D317954724C1ADDF00DC2168 /* BarChartExample-macOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "BarChartExample-macOS.app"; sourceTree = BUILT_PRODUCTS_DIR; };
20 | D317954A24C1ADDF00DC2168 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
21 | D317954C24C1ADDF00DC2168 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; };
22 | D317954E24C1ADE000DC2168 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
23 | D317955124C1ADE000DC2168 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; };
24 | D317955424C1ADE000DC2168 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
25 | D317955624C1ADE000DC2168 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
26 | D317955724C1ADE000DC2168 /* BarChartExample_macOS.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = BarChartExample_macOS.entitlements; sourceTree = ""; };
27 | D399CAE7265C7E5D00A92054 /* BarChart */ = {isa = PBXFileReference; lastKnownFileType = folder; name = BarChart; path = ../..; sourceTree = ""; };
28 | /* End PBXFileReference section */
29 |
30 | /* Begin PBXFrameworksBuildPhase section */
31 | D317954424C1ADDF00DC2168 /* Frameworks */ = {
32 | isa = PBXFrameworksBuildPhase;
33 | buildActionMask = 2147483647;
34 | files = (
35 | D399CAEA265C7E6900A92054 /* BarChart in Frameworks */,
36 | );
37 | runOnlyForDeploymentPostprocessing = 0;
38 | };
39 | /* End PBXFrameworksBuildPhase section */
40 |
41 | /* Begin PBXGroup section */
42 | D317953E24C1ADDF00DC2168 = {
43 | isa = PBXGroup;
44 | children = (
45 | D399CAE7265C7E5D00A92054 /* BarChart */,
46 | D317954924C1ADDF00DC2168 /* BarChartExample-macOS */,
47 | D317954824C1ADDF00DC2168 /* Products */,
48 | D399CAE8265C7E6900A92054 /* Frameworks */,
49 | );
50 | sourceTree = "";
51 | };
52 | D317954824C1ADDF00DC2168 /* Products */ = {
53 | isa = PBXGroup;
54 | children = (
55 | D317954724C1ADDF00DC2168 /* BarChartExample-macOS.app */,
56 | );
57 | name = Products;
58 | sourceTree = "";
59 | };
60 | D317954924C1ADDF00DC2168 /* BarChartExample-macOS */ = {
61 | isa = PBXGroup;
62 | children = (
63 | D317954A24C1ADDF00DC2168 /* AppDelegate.swift */,
64 | D317954C24C1ADDF00DC2168 /* ContentView.swift */,
65 | D317954E24C1ADE000DC2168 /* Assets.xcassets */,
66 | D317955324C1ADE000DC2168 /* Main.storyboard */,
67 | D317955624C1ADE000DC2168 /* Info.plist */,
68 | D317955724C1ADE000DC2168 /* BarChartExample_macOS.entitlements */,
69 | D317955024C1ADE000DC2168 /* Preview Content */,
70 | );
71 | path = "BarChartExample-macOS";
72 | sourceTree = "";
73 | };
74 | D317955024C1ADE000DC2168 /* Preview Content */ = {
75 | isa = PBXGroup;
76 | children = (
77 | D317955124C1ADE000DC2168 /* Preview Assets.xcassets */,
78 | );
79 | path = "Preview Content";
80 | sourceTree = "";
81 | };
82 | D399CAE8265C7E6900A92054 /* Frameworks */ = {
83 | isa = PBXGroup;
84 | children = (
85 | );
86 | name = Frameworks;
87 | sourceTree = "";
88 | };
89 | /* End PBXGroup section */
90 |
91 | /* Begin PBXNativeTarget section */
92 | D317954624C1ADDF00DC2168 /* BarChartExample-macOS */ = {
93 | isa = PBXNativeTarget;
94 | buildConfigurationList = D317955A24C1ADE000DC2168 /* Build configuration list for PBXNativeTarget "BarChartExample-macOS" */;
95 | buildPhases = (
96 | D317954324C1ADDF00DC2168 /* Sources */,
97 | D317954424C1ADDF00DC2168 /* Frameworks */,
98 | D317954524C1ADDF00DC2168 /* Resources */,
99 | );
100 | buildRules = (
101 | );
102 | dependencies = (
103 | );
104 | name = "BarChartExample-macOS";
105 | packageProductDependencies = (
106 | D399CAE9265C7E6900A92054 /* BarChart */,
107 | );
108 | productName = "BarChartExample-macOS";
109 | productReference = D317954724C1ADDF00DC2168 /* BarChartExample-macOS.app */;
110 | productType = "com.apple.product-type.application";
111 | };
112 | /* End PBXNativeTarget section */
113 |
114 | /* Begin PBXProject section */
115 | D317953F24C1ADDF00DC2168 /* Project object */ = {
116 | isa = PBXProject;
117 | attributes = {
118 | LastSwiftUpdateCheck = 1160;
119 | LastUpgradeCheck = 1240;
120 | ORGANIZATIONNAME = "Roman Baitaliuk";
121 | TargetAttributes = {
122 | D317954624C1ADDF00DC2168 = {
123 | CreatedOnToolsVersion = 11.6;
124 | };
125 | };
126 | };
127 | buildConfigurationList = D317954224C1ADDF00DC2168 /* Build configuration list for PBXProject "BarChartExample-macOS" */;
128 | compatibilityVersion = "Xcode 9.3";
129 | developmentRegion = en;
130 | hasScannedForEncodings = 0;
131 | knownRegions = (
132 | en,
133 | Base,
134 | );
135 | mainGroup = D317953E24C1ADDF00DC2168;
136 | packageReferences = (
137 | );
138 | productRefGroup = D317954824C1ADDF00DC2168 /* Products */;
139 | projectDirPath = "";
140 | projectRoot = "";
141 | targets = (
142 | D317954624C1ADDF00DC2168 /* BarChartExample-macOS */,
143 | );
144 | };
145 | /* End PBXProject section */
146 |
147 | /* Begin PBXResourcesBuildPhase section */
148 | D317954524C1ADDF00DC2168 /* Resources */ = {
149 | isa = PBXResourcesBuildPhase;
150 | buildActionMask = 2147483647;
151 | files = (
152 | D317955524C1ADE000DC2168 /* Main.storyboard in Resources */,
153 | D317955224C1ADE000DC2168 /* Preview Assets.xcassets in Resources */,
154 | D317954F24C1ADE000DC2168 /* Assets.xcassets in Resources */,
155 | );
156 | runOnlyForDeploymentPostprocessing = 0;
157 | };
158 | /* End PBXResourcesBuildPhase section */
159 |
160 | /* Begin PBXSourcesBuildPhase section */
161 | D317954324C1ADDF00DC2168 /* Sources */ = {
162 | isa = PBXSourcesBuildPhase;
163 | buildActionMask = 2147483647;
164 | files = (
165 | D317954D24C1ADDF00DC2168 /* ContentView.swift in Sources */,
166 | D317954B24C1ADDF00DC2168 /* AppDelegate.swift in Sources */,
167 | );
168 | runOnlyForDeploymentPostprocessing = 0;
169 | };
170 | /* End PBXSourcesBuildPhase section */
171 |
172 | /* Begin PBXVariantGroup section */
173 | D317955324C1ADE000DC2168 /* Main.storyboard */ = {
174 | isa = PBXVariantGroup;
175 | children = (
176 | D317955424C1ADE000DC2168 /* Base */,
177 | );
178 | name = Main.storyboard;
179 | sourceTree = "";
180 | };
181 | /* End PBXVariantGroup section */
182 |
183 | /* Begin XCBuildConfiguration section */
184 | D317955824C1ADE000DC2168 /* Debug */ = {
185 | isa = XCBuildConfiguration;
186 | buildSettings = {
187 | ALWAYS_SEARCH_USER_PATHS = NO;
188 | CLANG_ANALYZER_NONNULL = YES;
189 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
190 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
191 | CLANG_CXX_LIBRARY = "libc++";
192 | CLANG_ENABLE_MODULES = YES;
193 | CLANG_ENABLE_OBJC_ARC = YES;
194 | CLANG_ENABLE_OBJC_WEAK = YES;
195 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
196 | CLANG_WARN_BOOL_CONVERSION = YES;
197 | CLANG_WARN_COMMA = YES;
198 | CLANG_WARN_CONSTANT_CONVERSION = YES;
199 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
200 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
201 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
202 | CLANG_WARN_EMPTY_BODY = YES;
203 | CLANG_WARN_ENUM_CONVERSION = YES;
204 | CLANG_WARN_INFINITE_RECURSION = YES;
205 | CLANG_WARN_INT_CONVERSION = YES;
206 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
207 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
208 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
209 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
210 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
211 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
212 | CLANG_WARN_STRICT_PROTOTYPES = YES;
213 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
214 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
215 | CLANG_WARN_UNREACHABLE_CODE = YES;
216 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
217 | COPY_PHASE_STRIP = NO;
218 | DEBUG_INFORMATION_FORMAT = dwarf;
219 | ENABLE_STRICT_OBJC_MSGSEND = YES;
220 | ENABLE_TESTABILITY = YES;
221 | GCC_C_LANGUAGE_STANDARD = gnu11;
222 | GCC_DYNAMIC_NO_PIC = NO;
223 | GCC_NO_COMMON_BLOCKS = YES;
224 | GCC_OPTIMIZATION_LEVEL = 0;
225 | GCC_PREPROCESSOR_DEFINITIONS = (
226 | "DEBUG=1",
227 | "$(inherited)",
228 | );
229 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
230 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
231 | GCC_WARN_UNDECLARED_SELECTOR = YES;
232 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
233 | GCC_WARN_UNUSED_FUNCTION = YES;
234 | GCC_WARN_UNUSED_VARIABLE = YES;
235 | MACOSX_DEPLOYMENT_TARGET = 10.15;
236 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
237 | MTL_FAST_MATH = YES;
238 | ONLY_ACTIVE_ARCH = YES;
239 | SDKROOT = macosx;
240 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
241 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
242 | };
243 | name = Debug;
244 | };
245 | D317955924C1ADE000DC2168 /* Release */ = {
246 | isa = XCBuildConfiguration;
247 | buildSettings = {
248 | ALWAYS_SEARCH_USER_PATHS = NO;
249 | CLANG_ANALYZER_NONNULL = YES;
250 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
251 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
252 | CLANG_CXX_LIBRARY = "libc++";
253 | CLANG_ENABLE_MODULES = YES;
254 | CLANG_ENABLE_OBJC_ARC = YES;
255 | CLANG_ENABLE_OBJC_WEAK = YES;
256 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
257 | CLANG_WARN_BOOL_CONVERSION = YES;
258 | CLANG_WARN_COMMA = YES;
259 | CLANG_WARN_CONSTANT_CONVERSION = YES;
260 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
261 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
262 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
263 | CLANG_WARN_EMPTY_BODY = YES;
264 | CLANG_WARN_ENUM_CONVERSION = YES;
265 | CLANG_WARN_INFINITE_RECURSION = YES;
266 | CLANG_WARN_INT_CONVERSION = YES;
267 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
268 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
269 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
270 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
271 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
272 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
273 | CLANG_WARN_STRICT_PROTOTYPES = YES;
274 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
275 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
276 | CLANG_WARN_UNREACHABLE_CODE = YES;
277 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
278 | COPY_PHASE_STRIP = NO;
279 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
280 | ENABLE_NS_ASSERTIONS = NO;
281 | ENABLE_STRICT_OBJC_MSGSEND = YES;
282 | GCC_C_LANGUAGE_STANDARD = gnu11;
283 | GCC_NO_COMMON_BLOCKS = YES;
284 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
285 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
286 | GCC_WARN_UNDECLARED_SELECTOR = YES;
287 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
288 | GCC_WARN_UNUSED_FUNCTION = YES;
289 | GCC_WARN_UNUSED_VARIABLE = YES;
290 | MACOSX_DEPLOYMENT_TARGET = 10.15;
291 | MTL_ENABLE_DEBUG_INFO = NO;
292 | MTL_FAST_MATH = YES;
293 | SDKROOT = macosx;
294 | SWIFT_COMPILATION_MODE = wholemodule;
295 | SWIFT_OPTIMIZATION_LEVEL = "-O";
296 | };
297 | name = Release;
298 | };
299 | D317955B24C1ADE000DC2168 /* Debug */ = {
300 | isa = XCBuildConfiguration;
301 | buildSettings = {
302 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
303 | CODE_SIGN_ENTITLEMENTS = "BarChartExample-macOS/BarChartExample_macOS.entitlements";
304 | CODE_SIGN_IDENTITY = "-";
305 | CODE_SIGN_STYLE = Manual;
306 | COMBINE_HIDPI_IMAGES = YES;
307 | DEVELOPMENT_ASSET_PATHS = "\"BarChartExample-macOS/Preview Content\"";
308 | DEVELOPMENT_TEAM = "";
309 | ENABLE_HARDENED_RUNTIME = YES;
310 | ENABLE_PREVIEWS = YES;
311 | INFOPLIST_FILE = "BarChartExample-macOS/Info.plist";
312 | LD_RUNPATH_SEARCH_PATHS = (
313 | "$(inherited)",
314 | "@executable_path/../Frameworks",
315 | );
316 | MACOSX_DEPLOYMENT_TARGET = 10.15;
317 | PRODUCT_BUNDLE_IDENTIFIER = "com.ByteKit.BarChartExample-macOS";
318 | PRODUCT_NAME = "$(TARGET_NAME)";
319 | PROVISIONING_PROFILE_SPECIFIER = "";
320 | SWIFT_VERSION = 5.0;
321 | };
322 | name = Debug;
323 | };
324 | D317955C24C1ADE000DC2168 /* Release */ = {
325 | isa = XCBuildConfiguration;
326 | buildSettings = {
327 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
328 | CODE_SIGN_ENTITLEMENTS = "BarChartExample-macOS/BarChartExample_macOS.entitlements";
329 | CODE_SIGN_IDENTITY = "-";
330 | CODE_SIGN_STYLE = Manual;
331 | COMBINE_HIDPI_IMAGES = YES;
332 | DEVELOPMENT_ASSET_PATHS = "\"BarChartExample-macOS/Preview Content\"";
333 | DEVELOPMENT_TEAM = "";
334 | ENABLE_HARDENED_RUNTIME = YES;
335 | ENABLE_PREVIEWS = YES;
336 | INFOPLIST_FILE = "BarChartExample-macOS/Info.plist";
337 | LD_RUNPATH_SEARCH_PATHS = (
338 | "$(inherited)",
339 | "@executable_path/../Frameworks",
340 | );
341 | MACOSX_DEPLOYMENT_TARGET = 10.15;
342 | PRODUCT_BUNDLE_IDENTIFIER = "com.ByteKit.BarChartExample-macOS";
343 | PRODUCT_NAME = "$(TARGET_NAME)";
344 | PROVISIONING_PROFILE_SPECIFIER = "";
345 | SWIFT_VERSION = 5.0;
346 | };
347 | name = Release;
348 | };
349 | /* End XCBuildConfiguration section */
350 |
351 | /* Begin XCConfigurationList section */
352 | D317954224C1ADDF00DC2168 /* Build configuration list for PBXProject "BarChartExample-macOS" */ = {
353 | isa = XCConfigurationList;
354 | buildConfigurations = (
355 | D317955824C1ADE000DC2168 /* Debug */,
356 | D317955924C1ADE000DC2168 /* Release */,
357 | );
358 | defaultConfigurationIsVisible = 0;
359 | defaultConfigurationName = Release;
360 | };
361 | D317955A24C1ADE000DC2168 /* Build configuration list for PBXNativeTarget "BarChartExample-macOS" */ = {
362 | isa = XCConfigurationList;
363 | buildConfigurations = (
364 | D317955B24C1ADE000DC2168 /* Debug */,
365 | D317955C24C1ADE000DC2168 /* Release */,
366 | );
367 | defaultConfigurationIsVisible = 0;
368 | defaultConfigurationName = Release;
369 | };
370 | /* End XCConfigurationList section */
371 |
372 | /* Begin XCSwiftPackageProductDependency section */
373 | D399CAE9265C7E6900A92054 /* BarChart */ = {
374 | isa = XCSwiftPackageProductDependency;
375 | productName = BarChart;
376 | };
377 | /* End XCSwiftPackageProductDependency section */
378 | };
379 | rootObject = D317953F24C1ADDF00DC2168 /* Project object */;
380 | }
381 |
--------------------------------------------------------------------------------