mirror of
https://github.com/morgan9e/macos-stats
synced 2026-04-14 00:04:15 +09:00
finished RAM, Disk, Battery and Network modules
This commit is contained in:
2
Cartfile
2
Cartfile
@@ -1,2 +1,2 @@
|
||||
github "sindresorhus/LaunchAtLogin"
|
||||
github "danielgindi/Charts" ~> 3.3.0
|
||||
github "danielgindi/Charts" ~> 3.4.0
|
||||
@@ -1,2 +1,2 @@
|
||||
github "danielgindi/Charts" "v3.4.0"
|
||||
github "danielgindi/Charts" "v2.1.4a"
|
||||
github "sindresorhus/LaunchAtLogin" "v2.5.0"
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
> ℹ Please fill out this template when filing an issue.
|
||||
> All lines beginning with an ℹ symbol instruct you with what info we expect. You can delete those lines once you've filled in the info.
|
||||
>
|
||||
> Per our [*CONTRIBUTING guidelines](https://github.com/jjatie/Charts/blob/master/CONTRIBUTING.md), we use GitHub for
|
||||
> bugs and feature requests, not general support. Other issues should be opened on Stack Overflow with the tag [`ios-charts`.](https://stackoverflow.com/questions/tagged/ios-charts)
|
||||
>
|
||||
> Please remove this line and everything above it before submitting.
|
||||
|
||||
* [ ] I've read, understood, and done my best to follow the [*CONTRIBUTING guidelines](https://github.com/jjatie/Charts/blob/master/CONTRIBUTING.md).
|
||||
|
||||
## What did you do?
|
||||
|
||||
ℹ Please replace this with what you did.
|
||||
|
||||
## What did you expect to happen?
|
||||
|
||||
ℹ Please replace this with what you expected to happen.
|
||||
|
||||
## What happened instead?
|
||||
|
||||
ℹ Please replace this with of what happened instead.
|
||||
|
||||
## Charts Environment
|
||||
|
||||
**Charts version/Branch/Commit Number:**
|
||||
**Xcode version:**
|
||||
**Swift version:**
|
||||
**Platform(s) running Charts:**
|
||||
**macOS version running Xcode:**
|
||||
|
||||
## Demo Project
|
||||
|
||||
ℹ Please link to or upload a project we can download that reproduces the issue.
|
||||
@@ -1,13 +0,0 @@
|
||||
### Issue Link :link:
|
||||
<!-- What issue does this fix? If an issue doesn't exist, remove this section. -->
|
||||
|
||||
### Goals :soccer:
|
||||
<!-- List the high-level objectives of this pull request. -->
|
||||
<!-- Include any relevant context. -->
|
||||
|
||||
### Implementation Details :construction:
|
||||
<!-- Explain the reasoning behind any architectural changes. -->
|
||||
<!-- Highlight any new functionality. -->
|
||||
|
||||
### Testing Details :mag:
|
||||
<!-- Describe what tests you've added for your changes. -->
|
||||
56
Carthage/Checkouts/Charts/.gitignore
vendored
56
Carthage/Checkouts/Charts/.gitignore
vendored
@@ -1,15 +1,6 @@
|
||||
# OS X
|
||||
.DS_Store
|
||||
|
||||
# Xcode
|
||||
#
|
||||
# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
|
||||
|
||||
## Build generated
|
||||
build/
|
||||
DerivedData/
|
||||
|
||||
## Various settings
|
||||
*.pbxuser
|
||||
!default.pbxuser
|
||||
*.mode1v3
|
||||
@@ -18,58 +9,19 @@ DerivedData/
|
||||
!default.mode2v3
|
||||
*.perspectivev3
|
||||
!default.perspectivev3
|
||||
xcuserdata/
|
||||
|
||||
## Other
|
||||
xcuserdata
|
||||
*.xccheckout
|
||||
*.moved-aside
|
||||
*.xcuserstate
|
||||
|
||||
## Obj-C/Swift specific
|
||||
DerivedData
|
||||
*.hmap
|
||||
*.ipa
|
||||
*.dSYM.zip
|
||||
*.dSYM
|
||||
|
||||
## Playgrounds
|
||||
timeline.xctimeline
|
||||
playground.xcworkspace
|
||||
|
||||
# Swift Package Manager
|
||||
#
|
||||
# Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
|
||||
# Packages/
|
||||
.build/
|
||||
project.xcworkspace
|
||||
*.xcuserstate
|
||||
*.xcworkspace
|
||||
|
||||
# CocoaPods
|
||||
#
|
||||
# We recommend against adding the Pods directory to your .gitignore. However
|
||||
# you should judge for yourself, the pros and cons are mentioned at:
|
||||
# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
|
||||
# http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control
|
||||
#
|
||||
# Pods/
|
||||
|
||||
# Carthage
|
||||
#
|
||||
# Add this line if you want to avoid checking in source code from Carthage dependencies.
|
||||
# Carthage/Checkouts
|
||||
|
||||
Carthage/Build
|
||||
|
||||
# fastlane
|
||||
#
|
||||
# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
|
||||
# screenshots whenever they are needed.
|
||||
# For more information about the recommended setup visit:
|
||||
# https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md
|
||||
|
||||
fastlane/report.xml
|
||||
fastlane/Preview.html
|
||||
fastlane/screenshots
|
||||
fastlane/test_output
|
||||
Carthage
|
||||
Charts.framework.zip
|
||||
ChartsRealm.framework.zip
|
||||
.swiftpm/
|
||||
|
||||
25
Carthage/Checkouts/Charts/.travis.yml
vendored
25
Carthage/Checkouts/Charts/.travis.yml
vendored
@@ -1,25 +0,0 @@
|
||||
language: objective-c
|
||||
osx_image: xcode11
|
||||
matrix:
|
||||
include:
|
||||
- osx_image: xcode11
|
||||
env: PLATFORM="iOS"
|
||||
- osx_image: xcode11
|
||||
env: PLATFORM="tvOS"
|
||||
- osx_image: xcode11
|
||||
env: PLATFORM="macOS"
|
||||
env:
|
||||
global:
|
||||
- LANG=en_US.UTF-8
|
||||
- secure: HRl5Cg3/LmTJYCSDGtV8Fiqf6OgWXR6C5YkNviOElU9YmcCTvnmE7MCm+gK8hJNIQ2mWCBTlxTC7jJxeYlx0D+JQ6IhRc75B4zXgbtth6HCzlvhWDcBbNU/K+JPDjy2EAoVgvf8Xseq6GqM4WcVg2Pwr9PS3aaH/SKDE6yVoPXRM2wXRAxIdxayqm/RQgG88jAKgg+Ub5DKW/c9NLLbUf/WdY9SgQDJtqeZCMv7G3/IzW34KZgVPsqSrPByzZXbf7KgYkYLQlscH4mcUctk1qxhdCae//zcgUZo/utpXWbPXQqtvDpuqrg9IRvoGxa/D1I7dLSJsVnk4aP7RW18vn4HJ82C2AiEp+lU2TQE9y5lXcGssZVIa5aZNTWL90HVer3Kg6AnHffvdCSZ/UHsMZJFURUXL9fRIlWVGuEDeQOqlV6lUmEtp/BiEdV4D5PuCyT6snsmEwkc51goyqh6uS6XhJyqYEQdxdoybznwp91tVmASsRybppIGHTkcWN5csF4zQt40tEwd8LoqM+bBUo0wxKiKsNsecL4JA+YDYs2saZY9U3s8jAaIon+qDu071fPRaPEvBhYHYDhy4cTvBXibyGUYGHkrgLu0w19wDfHcJKt2In58yOmaCCLNoTGp/ZLNVRyZ8VDlj/NdJ2dWpMsL2Aj7OxU065kCL2FlvuRU=
|
||||
cache:
|
||||
- bundler
|
||||
before_install:
|
||||
- brew update
|
||||
- brew upgrade carthage || true
|
||||
- carthage version
|
||||
- carthage bootstrap --platform $PLATFORM
|
||||
script:
|
||||
- bundle exec rake ci[$PLATFORM]
|
||||
after_success:
|
||||
- bash <(curl -s https://codecov.io/bash)
|
||||
BIN
Carthage/Checkouts/Charts/Assets/feature_graphic.png
vendored
BIN
Carthage/Checkouts/Charts/Assets/feature_graphic.png
vendored
Binary file not shown.
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 29 KiB |
BIN
Carthage/Checkouts/Charts/Assets/feature_graphic.psd
vendored
BIN
Carthage/Checkouts/Charts/Assets/feature_graphic.psd
vendored
Binary file not shown.
3701
Carthage/Checkouts/Charts/CHANGELOG.md
vendored
3701
Carthage/Checkouts/Charts/CHANGELOG.md
vendored
File diff suppressed because it is too large
Load Diff
2
Carthage/Checkouts/Charts/CONTRIBUTING.md
vendored
2
Carthage/Checkouts/Charts/CONTRIBUTING.md
vendored
@@ -31,7 +31,7 @@ If you are reporting a bug which can be observed visually, please add to your is
|
||||
````
|
||||
First line must be up to 50 chars (Fixes #1234)
|
||||
|
||||
The first line should be a short statement as to what have changed, and should also include an issue number, prefixed with a hash.
|
||||
The first line should be a short statement as to what have changed, and should also include an issue number, prefixed with a dash.
|
||||
The body of the message comes after an empty new line, and describes the changes
|
||||
more thoroughly, especially if there was a special case handled there,
|
||||
or maybe some trickery that only code wizards can understand.
|
||||
|
||||
1
Carthage/Checkouts/Charts/Cartfile.private
vendored
1
Carthage/Checkouts/Charts/Cartfile.private
vendored
@@ -1 +0,0 @@
|
||||
github "uber/ios-snapshot-test-case"
|
||||
1
Carthage/Checkouts/Charts/Cartfile.resolved
vendored
1
Carthage/Checkouts/Charts/Cartfile.resolved
vendored
@@ -1 +0,0 @@
|
||||
github "uber/ios-snapshot-test-case" "6.1.0"
|
||||
19
Carthage/Checkouts/Charts/Charts.podspec
vendored
19
Carthage/Checkouts/Charts/Charts.podspec
vendored
@@ -1,19 +1,12 @@
|
||||
Pod::Spec.new do |s|
|
||||
s.name = "Charts"
|
||||
s.version = "3.4.0"
|
||||
s.summary = "Charts is a powerful & easy to use chart library for iOS, tvOS and OSX (and Android)"
|
||||
s.homepage = "https://github.com/danielgindi/Charts"
|
||||
s.version = "2.1.4a"
|
||||
s.summary = "ios-charts is a powerful & easy to use chart library for iOS"
|
||||
s.homepage = "https://github.com/danielgindi/ios-charts"
|
||||
s.license = { :type => "Apache License, Version 2.0", :file => "LICENSE" }
|
||||
s.authors = "Daniel Cohen Gindi", "Philipp Jahoda"
|
||||
s.ios.deployment_target = "8.0"
|
||||
s.tvos.deployment_target = "9.0"
|
||||
s.osx.deployment_target = "10.11"
|
||||
s.source = { :git => "https://github.com/danielgindi/Charts.git", :tag => "v#{s.version}" }
|
||||
s.default_subspec = "Core"
|
||||
s.swift_version = '5.0'
|
||||
s.cocoapods_version = '>= 1.5.0'
|
||||
|
||||
s.subspec "Core" do |ss|
|
||||
ss.source_files = "Source/Charts/**/*.swift"
|
||||
end
|
||||
s.source = { :git => "https://github.com/danielgindi/ios-charts.git", :tag => "v#{s.version}" }
|
||||
s.source_files = "Classes", "Charts/Classes/**/*.swift"
|
||||
s.frameworks = "Foundation", "UIKit", "CoreGraphics"
|
||||
end
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
13
Carthage/Checkouts/Charts/Charts.xcworkspace/contents.xcworkspacedata
generated
vendored
13
Carthage/Checkouts/Charts/Charts.xcworkspace/contents.xcworkspacedata
generated
vendored
@@ -1,13 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "container:Charts.xcodeproj">
|
||||
</FileRef>
|
||||
<FileRef
|
||||
location = "group:ChartsDemo-iOS/ChartsDemo-iOS.xcodeproj">
|
||||
</FileRef>
|
||||
<FileRef
|
||||
location = "group:ChartsDemo-macOS/ChartsDemo-macOS.xcodeproj">
|
||||
</FileRef>
|
||||
</Workspace>
|
||||
@@ -1,8 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>IDEDidComputeMac32BitWarning</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
996
Carthage/Checkouts/Charts/Charts/Charts.xcodeproj/project.pbxproj
vendored
Normal file
996
Carthage/Checkouts/Charts/Charts/Charts.xcodeproj/project.pbxproj
vendored
Normal file
@@ -0,0 +1,996 @@
|
||||
// !$*UTF8*$!
|
||||
{
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 46;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
06A5D1861B78675500915098 /* UIGraphics+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 06A5D1851B78675500915098 /* UIGraphics+Extensions.swift */; };
|
||||
55E356531ADC63BF00A57971 /* BubbleChartView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55E356521ADC63BF00A57971 /* BubbleChartView.swift */; };
|
||||
55E356571ADC63CD00A57971 /* BubbleChartData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55E356541ADC63CD00A57971 /* BubbleChartData.swift */; };
|
||||
55E356581ADC63CD00A57971 /* BubbleChartDataEntry.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55E356551ADC63CD00A57971 /* BubbleChartDataEntry.swift */; };
|
||||
55E356591ADC63CD00A57971 /* BubbleChartDataSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55E356561ADC63CD00A57971 /* BubbleChartDataSet.swift */; };
|
||||
55E3565B1ADC63EB00A57971 /* BubbleChartRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55E3565A1ADC63EB00A57971 /* BubbleChartRenderer.swift */; };
|
||||
5B0032451B6524AD00B6A2FE /* ChartHighlight.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B0032441B6524AD00B6A2FE /* ChartHighlight.swift */; };
|
||||
5B0032471B6524D300B6A2FE /* ChartRange.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B0032461B6524D300B6A2FE /* ChartRange.swift */; };
|
||||
5B0032491B6525FC00B6A2FE /* ChartHighlighter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B0032481B6525FC00B6A2FE /* ChartHighlighter.swift */; };
|
||||
5B00324B1B652BF900B6A2FE /* BarChartHighlighter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B00324A1B652BF900B6A2FE /* BarChartHighlighter.swift */; };
|
||||
5B00324D1B65351C00B6A2FE /* HorizontalBarChartHighlighter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B00324C1B65351C00B6A2FE /* HorizontalBarChartHighlighter.swift */; };
|
||||
5B378F171AD500A4009414A4 /* ChartAnimationEasing.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B378F161AD500A4009414A4 /* ChartAnimationEasing.swift */; };
|
||||
5B4BCD401AA9C4930063F019 /* ChartTransformer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B4BCD3F1AA9C4930063F019 /* ChartTransformer.swift */; };
|
||||
5B6556F71AB72BA000FFBFD3 /* ChartComponentBase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6556F61AB72BA000FFBFD3 /* ChartComponentBase.swift */; };
|
||||
5B6654D91BB0A86F00890030 /* ChartDefaultXAxisValueFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6654D51BB0A86F00890030 /* ChartDefaultXAxisValueFormatter.swift */; settings = {ASSET_TAGS = (); }; };
|
||||
5B6654DA1BB0A86F00890030 /* ChartFillFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6654D61BB0A86F00890030 /* ChartFillFormatter.swift */; settings = {ASSET_TAGS = (); }; };
|
||||
5B6654DB1BB0A86F00890030 /* ChartXAxisValueFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6654D71BB0A86F00890030 /* ChartXAxisValueFormatter.swift */; settings = {ASSET_TAGS = (); }; };
|
||||
5B680D1D1A9D16F90026A057 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5B680D1C1A9D16F90026A057 /* UIKit.framework */; };
|
||||
5B680D1F1A9D17C30026A057 /* ChartAxisBase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BA8EC6A1A9D151C00CE82E1 /* ChartAxisBase.swift */; };
|
||||
5B680D201A9D17C30026A057 /* ChartLegend.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BA8EC6B1A9D151C00CE82E1 /* ChartLegend.swift */; };
|
||||
5B680D211A9D17C30026A057 /* ChartLimitLine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BA8EC6C1A9D151C00CE82E1 /* ChartLimitLine.swift */; };
|
||||
5B680D221A9D17C30026A057 /* ChartXAxis.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BA8EC6D1A9D151C00CE82E1 /* ChartXAxis.swift */; };
|
||||
5B680D231A9D17C30026A057 /* ChartYAxis.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BA8EC6E1A9D151C00CE82E1 /* ChartYAxis.swift */; };
|
||||
5B680D271A9D17C30026A057 /* ChartColorTemplates.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BA8EC791A9D151C00CE82E1 /* ChartColorTemplates.swift */; };
|
||||
5B680D291A9D17C30026A057 /* ChartSelectionDetail.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BA8EC7B1A9D151C00CE82E1 /* ChartSelectionDetail.swift */; };
|
||||
5B680D2A1A9D17C30026A057 /* ChartUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BA8EC7C1A9D151C00CE82E1 /* ChartUtils.swift */; };
|
||||
5B680D3D1A9D1AD90026A057 /* Charts.h in Headers */ = {isa = PBXBuildFile; fileRef = 5B680D3C1A9D1AD90026A057 /* Charts.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
5B6A546B1AA5C23F000F57C2 /* ChartMarker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6A546A1AA5C23F000F57C2 /* ChartMarker.swift */; };
|
||||
5B6A546E1AA5D2DC000F57C2 /* ChartAnimator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6A546D1AA5D2DC000F57C2 /* ChartAnimator.swift */; };
|
||||
5B6A54701AA5DB34000F57C2 /* ChartRendererBase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6A546F1AA5DB34000F57C2 /* ChartRendererBase.swift */; };
|
||||
5B6A54741AA5DEDC000F57C2 /* ChartXAxisRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6A54731AA5DEDC000F57C2 /* ChartXAxisRenderer.swift */; };
|
||||
5B6A54761AA5DEE3000F57C2 /* ChartXAxisRendererBarChart.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6A54751AA5DEE3000F57C2 /* ChartXAxisRendererBarChart.swift */; };
|
||||
5B6A54781AA5DEF0000F57C2 /* ChartXAxisRendererRadarChart.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6A54771AA5DEF0000F57C2 /* ChartXAxisRendererRadarChart.swift */; };
|
||||
5B6A547C1AA5DF02000F57C2 /* ChartXAxisRendererHorizontalBarChart.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6A547B1AA5DF02000F57C2 /* ChartXAxisRendererHorizontalBarChart.swift */; };
|
||||
5B6A547E1AA5DF1A000F57C2 /* ChartYAxisRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6A547D1AA5DF1A000F57C2 /* ChartYAxisRenderer.swift */; };
|
||||
5B6A54801AA5DF28000F57C2 /* ChartYAxisRendererHorizontalBarChart.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6A547F1AA5DF28000F57C2 /* ChartYAxisRendererHorizontalBarChart.swift */; };
|
||||
5B6A54821AA5DF34000F57C2 /* ChartYAxisRendererRadarChart.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6A54811AA5DF34000F57C2 /* ChartYAxisRendererRadarChart.swift */; };
|
||||
5B6A54851AA669C9000F57C2 /* ScatterChartRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6A54841AA669C9000F57C2 /* ScatterChartRenderer.swift */; };
|
||||
5B6A54871AA669F4000F57C2 /* RadarChartRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6A54861AA669F4000F57C2 /* RadarChartRenderer.swift */; };
|
||||
5B6A54891AA66A1A000F57C2 /* PieChartRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6A54881AA66A1A000F57C2 /* PieChartRenderer.swift */; };
|
||||
5B6A548B1AA66A3D000F57C2 /* LineChartRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6A548A1AA66A3D000F57C2 /* LineChartRenderer.swift */; };
|
||||
5B6A548D1AA66A60000F57C2 /* ChartLegendRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6A548C1AA66A60000F57C2 /* ChartLegendRenderer.swift */; };
|
||||
5B6A548F1AA66A7A000F57C2 /* HorizontalBarChartRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6A548E1AA66A7A000F57C2 /* HorizontalBarChartRenderer.swift */; };
|
||||
5B6A54911AA66A8D000F57C2 /* ChartDataRendererBase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6A54901AA66A8D000F57C2 /* ChartDataRendererBase.swift */; };
|
||||
5B6A54931AA66AAB000F57C2 /* CombinedChartRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6A54921AA66AAB000F57C2 /* CombinedChartRenderer.swift */; };
|
||||
5B6A54951AA66AC0000F57C2 /* CandleStickChartRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6A54941AA66AC0000F57C2 /* CandleStickChartRenderer.swift */; };
|
||||
5B6A54971AA66AD2000F57C2 /* BarChartRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6A54961AA66AD2000F57C2 /* BarChartRenderer.swift */; };
|
||||
5B6A54991AA66B14000F57C2 /* BarChartView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6A54981AA66B14000F57C2 /* BarChartView.swift */; };
|
||||
5B6A549B1AA66B2C000F57C2 /* BarLineChartViewBase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6A549A1AA66B2C000F57C2 /* BarLineChartViewBase.swift */; };
|
||||
5B6A549D1AA66B3C000F57C2 /* CandleStickChartView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6A549C1AA66B3C000F57C2 /* CandleStickChartView.swift */; };
|
||||
5B6A549F1AA66B59000F57C2 /* CombinedChartView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6A549E1AA66B59000F57C2 /* CombinedChartView.swift */; };
|
||||
5B6A54A31AA66B7C000F57C2 /* LineChartView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6A54A21AA66B7C000F57C2 /* LineChartView.swift */; };
|
||||
5B6A54A51AA66B92000F57C2 /* PieChartView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6A54A41AA66B92000F57C2 /* PieChartView.swift */; };
|
||||
5B6A54A71AA66BA7000F57C2 /* PieRadarChartViewBase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6A54A61AA66BA7000F57C2 /* PieRadarChartViewBase.swift */; };
|
||||
5B6A54A91AA66BBA000F57C2 /* RadarChartView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6A54A81AA66BBA000F57C2 /* RadarChartView.swift */; };
|
||||
5B6A54AB1AA66BC8000F57C2 /* ScatterChartView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6A54AA1AA66BC8000F57C2 /* ScatterChartView.swift */; };
|
||||
5B6A54AC1AA66C1E000F57C2 /* ChartAxisRendererBase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6A54711AA5DCA8000F57C2 /* ChartAxisRendererBase.swift */; };
|
||||
5B6A54CC1AA74516000F57C2 /* BarChartData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6A54B71AA74516000F57C2 /* BarChartData.swift */; };
|
||||
5B6A54CD1AA74516000F57C2 /* BarChartDataEntry.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6A54B81AA74516000F57C2 /* BarChartDataEntry.swift */; };
|
||||
5B6A54CE1AA74516000F57C2 /* BarChartDataSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6A54B91AA74516000F57C2 /* BarChartDataSet.swift */; };
|
||||
5B6A54CF1AA74516000F57C2 /* BarLineScatterCandleBubbleChartData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6A54BA1AA74516000F57C2 /* BarLineScatterCandleBubbleChartData.swift */; };
|
||||
5B6A54D01AA74516000F57C2 /* BarLineScatterCandleBubbleChartDataSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6A54BB1AA74516000F57C2 /* BarLineScatterCandleBubbleChartDataSet.swift */; };
|
||||
5B6A54D11AA74516000F57C2 /* CandleChartData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6A54BC1AA74516000F57C2 /* CandleChartData.swift */; };
|
||||
5B6A54D21AA74516000F57C2 /* CandleChartDataEntry.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6A54BD1AA74516000F57C2 /* CandleChartDataEntry.swift */; };
|
||||
5B6A54D31AA74516000F57C2 /* CandleChartDataSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6A54BE1AA74516000F57C2 /* CandleChartDataSet.swift */; };
|
||||
5B6A54D41AA74516000F57C2 /* CombinedChartData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6A54BF1AA74516000F57C2 /* CombinedChartData.swift */; };
|
||||
5B6A54D51AA74516000F57C2 /* ChartData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6A54C01AA74516000F57C2 /* ChartData.swift */; };
|
||||
5B6A54D61AA74516000F57C2 /* ChartDataEntry.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6A54C11AA74516000F57C2 /* ChartDataEntry.swift */; };
|
||||
5B6A54D71AA74516000F57C2 /* ChartDataSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6A54C21AA74516000F57C2 /* ChartDataSet.swift */; };
|
||||
5B6A54D81AA74516000F57C2 /* LineChartData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6A54C31AA74516000F57C2 /* LineChartData.swift */; };
|
||||
5B6A54D91AA74516000F57C2 /* LineChartDataSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6A54C41AA74516000F57C2 /* LineChartDataSet.swift */; };
|
||||
5B6A54DA1AA74516000F57C2 /* LineRadarChartDataSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6A54C51AA74516000F57C2 /* LineRadarChartDataSet.swift */; };
|
||||
5B6A54DB1AA74516000F57C2 /* PieChartData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6A54C61AA74516000F57C2 /* PieChartData.swift */; };
|
||||
5B6A54DC1AA74516000F57C2 /* PieChartDataSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6A54C71AA74516000F57C2 /* PieChartDataSet.swift */; };
|
||||
5B6A54DD1AA74516000F57C2 /* RadarChartData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6A54C81AA74516000F57C2 /* RadarChartData.swift */; };
|
||||
5B6A54DE1AA74516000F57C2 /* RadarChartDataSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6A54C91AA74516000F57C2 /* RadarChartDataSet.swift */; };
|
||||
5B6A54DF1AA74516000F57C2 /* ScatterChartData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6A54CA1AA74516000F57C2 /* ScatterChartData.swift */; };
|
||||
5B6A54E01AA74516000F57C2 /* ScatterChartDataSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6A54CB1AA74516000F57C2 /* ScatterChartDataSet.swift */; };
|
||||
5B8FE2AF1B68F8F600910C9E /* LineScatterCandleChartDataSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B8FE2AE1B68F8F600910C9E /* LineScatterCandleChartDataSet.swift */; };
|
||||
5B8FE2B11B68FFF900910C9E /* LineScatterCandleRadarChartRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B8FE2B01B68FFF900910C9E /* LineScatterCandleRadarChartRenderer.swift */; };
|
||||
5BA8EC7D1A9D151C00CE82E1 /* ChartViewBase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BA8EC671A9D151C00CE82E1 /* ChartViewBase.swift */; };
|
||||
5BA8EC881A9D151C00CE82E1 /* ChartDataApproximatorFilter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BA8EC751A9D151C00CE82E1 /* ChartDataApproximatorFilter.swift */; };
|
||||
5BA8EC891A9D151C00CE82E1 /* ChartDataBaseFilter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BA8EC761A9D151C00CE82E1 /* ChartDataBaseFilter.swift */; };
|
||||
5BAAA8561BB08E1D00B20D4D /* CombinedHighlighter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BAAA8551BB08E1D00B20D4D /* CombinedHighlighter.swift */; settings = {ASSET_TAGS = (); }; };
|
||||
5BB6EC1D1ACC28AB006E9C25 /* ChartTransformerHorizontalBarChart.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BB6EC1C1ACC28AB006E9C25 /* ChartTransformerHorizontalBarChart.swift */; };
|
||||
5BD8F06D1AB897D500566E05 /* ChartViewPortHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BD8F06C1AB897D500566E05 /* ChartViewPortHandler.swift */; };
|
||||
5BD8F06E1AB89AD800566E05 /* HorizontalBarChartView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6A54A01AA66B6A000F57C2 /* HorizontalBarChartView.swift */; };
|
||||
A52C5C3A1BAC5CA400594CDD /* ChartsTV.h in Headers */ = {isa = PBXBuildFile; fileRef = A52C5C391BAC5CA400594CDD /* ChartsTV.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
A52C5C3F1BAC5D1100594CDD /* ChartAnimator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6A546D1AA5D2DC000F57C2 /* ChartAnimator.swift */; };
|
||||
A52C5C401BAC5D1100594CDD /* ChartAnimationEasing.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B378F161AD500A4009414A4 /* ChartAnimationEasing.swift */; };
|
||||
A52C5C411BAC5D1100594CDD /* BarChartView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6A54981AA66B14000F57C2 /* BarChartView.swift */; };
|
||||
A52C5C421BAC5D1100594CDD /* BarLineChartViewBase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6A549A1AA66B2C000F57C2 /* BarLineChartViewBase.swift */; };
|
||||
A52C5C431BAC5D1100594CDD /* BubbleChartView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55E356521ADC63BF00A57971 /* BubbleChartView.swift */; };
|
||||
A52C5C441BAC5D1100594CDD /* CandleStickChartView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6A549C1AA66B3C000F57C2 /* CandleStickChartView.swift */; };
|
||||
A52C5C451BAC5D1100594CDD /* ChartViewBase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BA8EC671A9D151C00CE82E1 /* ChartViewBase.swift */; };
|
||||
A52C5C461BAC5D1100594CDD /* CombinedChartView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6A549E1AA66B59000F57C2 /* CombinedChartView.swift */; };
|
||||
A52C5C471BAC5D1100594CDD /* HorizontalBarChartView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6A54A01AA66B6A000F57C2 /* HorizontalBarChartView.swift */; };
|
||||
A52C5C481BAC5D1100594CDD /* LineChartView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6A54A21AA66B7C000F57C2 /* LineChartView.swift */; };
|
||||
A52C5C491BAC5D1100594CDD /* PieChartView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6A54A41AA66B92000F57C2 /* PieChartView.swift */; };
|
||||
A52C5C4A1BAC5D1100594CDD /* PieRadarChartViewBase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6A54A61AA66BA7000F57C2 /* PieRadarChartViewBase.swift */; };
|
||||
A52C5C4B1BAC5D1100594CDD /* RadarChartView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6A54A81AA66BBA000F57C2 /* RadarChartView.swift */; };
|
||||
A52C5C4C1BAC5D1100594CDD /* ScatterChartView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6A54AA1AA66BC8000F57C2 /* ScatterChartView.swift */; };
|
||||
A52C5C4D1BAC5D1100594CDD /* ChartAxisBase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BA8EC6A1A9D151C00CE82E1 /* ChartAxisBase.swift */; };
|
||||
A52C5C4E1BAC5D1100594CDD /* ChartComponentBase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6556F61AB72BA000FFBFD3 /* ChartComponentBase.swift */; };
|
||||
A52C5C4F1BAC5D1100594CDD /* ChartLegend.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BA8EC6B1A9D151C00CE82E1 /* ChartLegend.swift */; };
|
||||
A52C5C501BAC5D1100594CDD /* ChartLimitLine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BA8EC6C1A9D151C00CE82E1 /* ChartLimitLine.swift */; };
|
||||
A52C5C511BAC5D1100594CDD /* ChartMarker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6A546A1AA5C23F000F57C2 /* ChartMarker.swift */; };
|
||||
A52C5C521BAC5D1100594CDD /* ChartXAxis.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BA8EC6D1A9D151C00CE82E1 /* ChartXAxis.swift */; };
|
||||
A52C5C531BAC5D1100594CDD /* ChartYAxis.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BA8EC6E1A9D151C00CE82E1 /* ChartYAxis.swift */; };
|
||||
A52C5C541BAC5D1100594CDD /* BarChartData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6A54B71AA74516000F57C2 /* BarChartData.swift */; };
|
||||
A52C5C551BAC5D1100594CDD /* BarChartDataEntry.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6A54B81AA74516000F57C2 /* BarChartDataEntry.swift */; };
|
||||
A52C5C561BAC5D1100594CDD /* BarChartDataSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6A54B91AA74516000F57C2 /* BarChartDataSet.swift */; };
|
||||
A52C5C571BAC5D1100594CDD /* BarLineScatterCandleChartData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6A54BA1AA74516000F57C2 /* BarLineScatterCandleChartData.swift */; };
|
||||
A52C5C581BAC5D1100594CDD /* BarLineScatterCandleChartDataSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6A54BB1AA74516000F57C2 /* BarLineScatterCandleChartDataSet.swift */; };
|
||||
A52C5C591BAC5D1100594CDD /* BubbleChartData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55E356541ADC63CD00A57971 /* BubbleChartData.swift */; };
|
||||
A52C5C5A1BAC5D1100594CDD /* BubbleChartDataEntry.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55E356551ADC63CD00A57971 /* BubbleChartDataEntry.swift */; };
|
||||
A52C5C5B1BAC5D1100594CDD /* BubbleChartDataSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55E356561ADC63CD00A57971 /* BubbleChartDataSet.swift */; };
|
||||
A52C5C5C1BAC5D1100594CDD /* CandleChartData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6A54BC1AA74516000F57C2 /* CandleChartData.swift */; };
|
||||
A52C5C5D1BAC5D1100594CDD /* CandleChartDataEntry.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6A54BD1AA74516000F57C2 /* CandleChartDataEntry.swift */; };
|
||||
A52C5C5E1BAC5D1100594CDD /* CandleChartDataSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6A54BE1AA74516000F57C2 /* CandleChartDataSet.swift */; };
|
||||
A52C5C5F1BAC5D1100594CDD /* CombinedChartData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6A54BF1AA74516000F57C2 /* CombinedChartData.swift */; };
|
||||
A52C5C601BAC5D1100594CDD /* ChartData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6A54C01AA74516000F57C2 /* ChartData.swift */; };
|
||||
A52C5C611BAC5D1100594CDD /* ChartDataEntry.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6A54C11AA74516000F57C2 /* ChartDataEntry.swift */; };
|
||||
A52C5C621BAC5D1100594CDD /* ChartDataSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6A54C21AA74516000F57C2 /* ChartDataSet.swift */; };
|
||||
A52C5C631BAC5D1100594CDD /* LineChartData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6A54C31AA74516000F57C2 /* LineChartData.swift */; };
|
||||
A52C5C641BAC5D1100594CDD /* LineChartDataSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6A54C41AA74516000F57C2 /* LineChartDataSet.swift */; };
|
||||
A52C5C651BAC5D1100594CDD /* LineRadarChartDataSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6A54C51AA74516000F57C2 /* LineRadarChartDataSet.swift */; };
|
||||
A52C5C661BAC5D1100594CDD /* LineScatterCandleChartDataSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B8FE2AE1B68F8F600910C9E /* LineScatterCandleChartDataSet.swift */; };
|
||||
A52C5C671BAC5D1100594CDD /* PieChartData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6A54C61AA74516000F57C2 /* PieChartData.swift */; };
|
||||
A52C5C681BAC5D1100594CDD /* PieChartDataSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6A54C71AA74516000F57C2 /* PieChartDataSet.swift */; };
|
||||
A52C5C691BAC5D1100594CDD /* RadarChartData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6A54C81AA74516000F57C2 /* RadarChartData.swift */; };
|
||||
A52C5C6A1BAC5D1100594CDD /* RadarChartDataSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6A54C91AA74516000F57C2 /* RadarChartDataSet.swift */; };
|
||||
A52C5C6B1BAC5D1100594CDD /* ScatterChartData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6A54CA1AA74516000F57C2 /* ScatterChartData.swift */; };
|
||||
A52C5C6C1BAC5D1100594CDD /* ScatterChartDataSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6A54CB1AA74516000F57C2 /* ScatterChartDataSet.swift */; };
|
||||
A52C5C6D1BAC5D1100594CDD /* ChartDataApproximatorFilter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BA8EC751A9D151C00CE82E1 /* ChartDataApproximatorFilter.swift */; };
|
||||
A52C5C6E1BAC5D1100594CDD /* ChartDataBaseFilter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BA8EC761A9D151C00CE82E1 /* ChartDataBaseFilter.swift */; };
|
||||
A52C5C6F1BAC5D1100594CDD /* ChartHighlight.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B0032441B6524AD00B6A2FE /* ChartHighlight.swift */; };
|
||||
A52C5C701BAC5D1100594CDD /* ChartRange.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B0032461B6524D300B6A2FE /* ChartRange.swift */; };
|
||||
A52C5C711BAC5D1100594CDD /* ChartHighlighter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B0032481B6525FC00B6A2FE /* ChartHighlighter.swift */; };
|
||||
A52C5C721BAC5D1100594CDD /* BarChartHighlighter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B00324A1B652BF900B6A2FE /* BarChartHighlighter.swift */; };
|
||||
A52C5C731BAC5D1100594CDD /* HorizontalBarChartHighlighter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B00324C1B65351C00B6A2FE /* HorizontalBarChartHighlighter.swift */; };
|
||||
A52C5C741BAC5D1100594CDD /* ChartAxisRendererBase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6A54711AA5DCA8000F57C2 /* ChartAxisRendererBase.swift */; };
|
||||
A52C5C751BAC5D1100594CDD /* BarChartRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6A54961AA66AD2000F57C2 /* BarChartRenderer.swift */; };
|
||||
A52C5C761BAC5D1100594CDD /* BubbleChartRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55E3565A1ADC63EB00A57971 /* BubbleChartRenderer.swift */; };
|
||||
A52C5C771BAC5D1100594CDD /* CandleStickChartRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6A54941AA66AC0000F57C2 /* CandleStickChartRenderer.swift */; };
|
||||
A52C5C781BAC5D1100594CDD /* CombinedChartRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6A54921AA66AAB000F57C2 /* CombinedChartRenderer.swift */; };
|
||||
A52C5C791BAC5D1100594CDD /* ChartDataRendererBase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6A54901AA66A8D000F57C2 /* ChartDataRendererBase.swift */; };
|
||||
A52C5C7A1BAC5D1200594CDD /* HorizontalBarChartRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6A548E1AA66A7A000F57C2 /* HorizontalBarChartRenderer.swift */; };
|
||||
A52C5C7B1BAC5D1200594CDD /* ChartLegendRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6A548C1AA66A60000F57C2 /* ChartLegendRenderer.swift */; };
|
||||
A52C5C7C1BAC5D1200594CDD /* LineChartRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6A548A1AA66A3D000F57C2 /* LineChartRenderer.swift */; };
|
||||
A52C5C7D1BAC5D1200594CDD /* LineScatterCandleRadarChartRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B8FE2B01B68FFF900910C9E /* LineScatterCandleRadarChartRenderer.swift */; };
|
||||
A52C5C7E1BAC5D1200594CDD /* PieChartRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6A54881AA66A1A000F57C2 /* PieChartRenderer.swift */; };
|
||||
A52C5C7F1BAC5D1200594CDD /* RadarChartRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6A54861AA669F4000F57C2 /* RadarChartRenderer.swift */; };
|
||||
A52C5C801BAC5D1200594CDD /* ChartRendererBase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6A546F1AA5DB34000F57C2 /* ChartRendererBase.swift */; };
|
||||
A52C5C811BAC5D1200594CDD /* ScatterChartRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6A54841AA669C9000F57C2 /* ScatterChartRenderer.swift */; };
|
||||
A52C5C821BAC5D1200594CDD /* ChartXAxisRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6A54731AA5DEDC000F57C2 /* ChartXAxisRenderer.swift */; };
|
||||
A52C5C831BAC5D1200594CDD /* ChartXAxisRendererBarChart.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6A54751AA5DEE3000F57C2 /* ChartXAxisRendererBarChart.swift */; };
|
||||
A52C5C841BAC5D1200594CDD /* ChartXAxisRendererHorizontalBarChart.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6A547B1AA5DF02000F57C2 /* ChartXAxisRendererHorizontalBarChart.swift */; };
|
||||
A52C5C851BAC5D1200594CDD /* ChartXAxisRendererRadarChart.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6A54771AA5DEF0000F57C2 /* ChartXAxisRendererRadarChart.swift */; };
|
||||
A52C5C861BAC5D1200594CDD /* ChartYAxisRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6A547D1AA5DF1A000F57C2 /* ChartYAxisRenderer.swift */; };
|
||||
A52C5C871BAC5D1200594CDD /* ChartYAxisRendererHorizontalBarChart.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6A547F1AA5DF28000F57C2 /* ChartYAxisRendererHorizontalBarChart.swift */; };
|
||||
A52C5C881BAC5D1200594CDD /* ChartYAxisRendererRadarChart.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B6A54811AA5DF34000F57C2 /* ChartYAxisRendererRadarChart.swift */; };
|
||||
A52C5C891BAC5D1200594CDD /* ChartColorTemplates.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BA8EC791A9D151C00CE82E1 /* ChartColorTemplates.swift */; };
|
||||
A52C5C8A1BAC5D1200594CDD /* ChartFillFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B4BCD3D1AA9C0A60063F019 /* ChartFillFormatter.swift */; };
|
||||
A52C5C8B1BAC5D1200594CDD /* ChartSelectionDetail.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BA8EC7B1A9D151C00CE82E1 /* ChartSelectionDetail.swift */; };
|
||||
A52C5C8C1BAC5D1200594CDD /* ChartTransformer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B4BCD3F1AA9C4930063F019 /* ChartTransformer.swift */; };
|
||||
A52C5C8D1BAC5D1200594CDD /* ChartTransformerHorizontalBarChart.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BB6EC1C1ACC28AB006E9C25 /* ChartTransformerHorizontalBarChart.swift */; };
|
||||
A52C5C8E1BAC5D1200594CDD /* ChartUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BA8EC7C1A9D151C00CE82E1 /* ChartUtils.swift */; };
|
||||
A52C5C8F1BAC5D1200594CDD /* ChartViewPortHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BD8F06C1AB897D500566E05 /* ChartViewPortHandler.swift */; };
|
||||
A52C5C901BAC5D1200594CDD /* UIGraphics+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 06A5D1851B78675500915098 /* UIGraphics+Extensions.swift */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
06A5D1851B78675500915098 /* UIGraphics+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIGraphics+Extensions.swift"; sourceTree = "<group>"; };
|
||||
55E356521ADC63BF00A57971 /* BubbleChartView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BubbleChartView.swift; sourceTree = "<group>"; };
|
||||
55E356541ADC63CD00A57971 /* BubbleChartData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BubbleChartData.swift; sourceTree = "<group>"; };
|
||||
55E356551ADC63CD00A57971 /* BubbleChartDataEntry.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BubbleChartDataEntry.swift; sourceTree = "<group>"; };
|
||||
55E356561ADC63CD00A57971 /* BubbleChartDataSet.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BubbleChartDataSet.swift; sourceTree = "<group>"; };
|
||||
55E3565A1ADC63EB00A57971 /* BubbleChartRenderer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BubbleChartRenderer.swift; sourceTree = "<group>"; };
|
||||
5B0032441B6524AD00B6A2FE /* ChartHighlight.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChartHighlight.swift; sourceTree = "<group>"; };
|
||||
5B0032461B6524D300B6A2FE /* ChartRange.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChartRange.swift; sourceTree = "<group>"; };
|
||||
5B0032481B6525FC00B6A2FE /* ChartHighlighter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChartHighlighter.swift; sourceTree = "<group>"; };
|
||||
5B00324A1B652BF900B6A2FE /* BarChartHighlighter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BarChartHighlighter.swift; sourceTree = "<group>"; };
|
||||
5B00324C1B65351C00B6A2FE /* HorizontalBarChartHighlighter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HorizontalBarChartHighlighter.swift; sourceTree = "<group>"; };
|
||||
5B378F161AD500A4009414A4 /* ChartAnimationEasing.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChartAnimationEasing.swift; sourceTree = "<group>"; };
|
||||
5B4BCD3F1AA9C4930063F019 /* ChartTransformer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChartTransformer.swift; sourceTree = "<group>"; };
|
||||
5B6556F61AB72BA000FFBFD3 /* ChartComponentBase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChartComponentBase.swift; sourceTree = "<group>"; };
|
||||
5B6654D51BB0A86F00890030 /* ChartDefaultXAxisValueFormatter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChartDefaultXAxisValueFormatter.swift; sourceTree = "<group>"; };
|
||||
5B6654D61BB0A86F00890030 /* ChartFillFormatter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChartFillFormatter.swift; sourceTree = "<group>"; };
|
||||
5B6654D71BB0A86F00890030 /* ChartXAxisValueFormatter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChartXAxisValueFormatter.swift; sourceTree = "<group>"; };
|
||||
5B680D1C1A9D16F90026A057 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
|
||||
5B680D3C1A9D1AD90026A057 /* Charts.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Charts.h; sourceTree = "<group>"; };
|
||||
5B6A546A1AA5C23F000F57C2 /* ChartMarker.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChartMarker.swift; sourceTree = "<group>"; };
|
||||
5B6A546D1AA5D2DC000F57C2 /* ChartAnimator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChartAnimator.swift; sourceTree = "<group>"; };
|
||||
5B6A546F1AA5DB34000F57C2 /* ChartRendererBase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChartRendererBase.swift; sourceTree = "<group>"; };
|
||||
5B6A54711AA5DCA8000F57C2 /* ChartAxisRendererBase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChartAxisRendererBase.swift; sourceTree = "<group>"; };
|
||||
5B6A54731AA5DEDC000F57C2 /* ChartXAxisRenderer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChartXAxisRenderer.swift; sourceTree = "<group>"; };
|
||||
5B6A54751AA5DEE3000F57C2 /* ChartXAxisRendererBarChart.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChartXAxisRendererBarChart.swift; sourceTree = "<group>"; };
|
||||
5B6A54771AA5DEF0000F57C2 /* ChartXAxisRendererRadarChart.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChartXAxisRendererRadarChart.swift; sourceTree = "<group>"; };
|
||||
5B6A547B1AA5DF02000F57C2 /* ChartXAxisRendererHorizontalBarChart.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChartXAxisRendererHorizontalBarChart.swift; sourceTree = "<group>"; };
|
||||
5B6A547D1AA5DF1A000F57C2 /* ChartYAxisRenderer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChartYAxisRenderer.swift; sourceTree = "<group>"; };
|
||||
5B6A547F1AA5DF28000F57C2 /* ChartYAxisRendererHorizontalBarChart.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChartYAxisRendererHorizontalBarChart.swift; sourceTree = "<group>"; };
|
||||
5B6A54811AA5DF34000F57C2 /* ChartYAxisRendererRadarChart.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChartYAxisRendererRadarChart.swift; sourceTree = "<group>"; };
|
||||
5B6A54841AA669C9000F57C2 /* ScatterChartRenderer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ScatterChartRenderer.swift; sourceTree = "<group>"; };
|
||||
5B6A54861AA669F4000F57C2 /* RadarChartRenderer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RadarChartRenderer.swift; sourceTree = "<group>"; };
|
||||
5B6A54881AA66A1A000F57C2 /* PieChartRenderer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PieChartRenderer.swift; sourceTree = "<group>"; };
|
||||
5B6A548A1AA66A3D000F57C2 /* LineChartRenderer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LineChartRenderer.swift; sourceTree = "<group>"; };
|
||||
5B6A548C1AA66A60000F57C2 /* ChartLegendRenderer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChartLegendRenderer.swift; sourceTree = "<group>"; };
|
||||
5B6A548E1AA66A7A000F57C2 /* HorizontalBarChartRenderer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HorizontalBarChartRenderer.swift; sourceTree = "<group>"; };
|
||||
5B6A54901AA66A8D000F57C2 /* ChartDataRendererBase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChartDataRendererBase.swift; sourceTree = "<group>"; };
|
||||
5B6A54921AA66AAB000F57C2 /* CombinedChartRenderer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CombinedChartRenderer.swift; sourceTree = "<group>"; };
|
||||
5B6A54941AA66AC0000F57C2 /* CandleStickChartRenderer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CandleStickChartRenderer.swift; sourceTree = "<group>"; };
|
||||
5B6A54961AA66AD2000F57C2 /* BarChartRenderer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = BarChartRenderer.swift; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.swift; };
|
||||
5B6A54981AA66B14000F57C2 /* BarChartView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BarChartView.swift; sourceTree = "<group>"; };
|
||||
5B6A549A1AA66B2C000F57C2 /* BarLineChartViewBase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = BarLineChartViewBase.swift; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.swift; };
|
||||
5B6A549C1AA66B3C000F57C2 /* CandleStickChartView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CandleStickChartView.swift; sourceTree = "<group>"; };
|
||||
5B6A549E1AA66B59000F57C2 /* CombinedChartView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CombinedChartView.swift; sourceTree = "<group>"; };
|
||||
5B6A54A01AA66B6A000F57C2 /* HorizontalBarChartView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HorizontalBarChartView.swift; sourceTree = "<group>"; };
|
||||
5B6A54A21AA66B7C000F57C2 /* LineChartView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LineChartView.swift; sourceTree = "<group>"; };
|
||||
5B6A54A41AA66B92000F57C2 /* PieChartView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PieChartView.swift; sourceTree = "<group>"; };
|
||||
5B6A54A61AA66BA7000F57C2 /* PieRadarChartViewBase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PieRadarChartViewBase.swift; sourceTree = "<group>"; };
|
||||
5B6A54A81AA66BBA000F57C2 /* RadarChartView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RadarChartView.swift; sourceTree = "<group>"; };
|
||||
5B6A54AA1AA66BC8000F57C2 /* ScatterChartView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ScatterChartView.swift; sourceTree = "<group>"; };
|
||||
5B6A54B71AA74516000F57C2 /* BarChartData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BarChartData.swift; sourceTree = "<group>"; };
|
||||
5B6A54B81AA74516000F57C2 /* BarChartDataEntry.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BarChartDataEntry.swift; sourceTree = "<group>"; };
|
||||
5B6A54B91AA74516000F57C2 /* BarChartDataSet.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BarChartDataSet.swift; sourceTree = "<group>"; };
|
||||
5B6A54BA1AA74516000F57C2 /* BarLineScatterCandleBubbleChartData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BarLineScatterCandleBubbleChartData.swift; sourceTree = "<group>"; };
|
||||
5B6A54BB1AA74516000F57C2 /* BarLineScatterCandleBubbleChartDataSet.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BarLineScatterCandleBubbleChartDataSet.swift; sourceTree = "<group>"; };
|
||||
5B6A54BC1AA74516000F57C2 /* CandleChartData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CandleChartData.swift; sourceTree = "<group>"; };
|
||||
5B6A54BD1AA74516000F57C2 /* CandleChartDataEntry.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CandleChartDataEntry.swift; sourceTree = "<group>"; };
|
||||
5B6A54BE1AA74516000F57C2 /* CandleChartDataSet.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CandleChartDataSet.swift; sourceTree = "<group>"; };
|
||||
5B6A54BF1AA74516000F57C2 /* CombinedChartData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CombinedChartData.swift; sourceTree = "<group>"; };
|
||||
5B6A54C01AA74516000F57C2 /* ChartData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChartData.swift; sourceTree = "<group>"; };
|
||||
5B6A54C11AA74516000F57C2 /* ChartDataEntry.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChartDataEntry.swift; sourceTree = "<group>"; };
|
||||
5B6A54C21AA74516000F57C2 /* ChartDataSet.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChartDataSet.swift; sourceTree = "<group>"; };
|
||||
5B6A54C31AA74516000F57C2 /* LineChartData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LineChartData.swift; sourceTree = "<group>"; };
|
||||
5B6A54C41AA74516000F57C2 /* LineChartDataSet.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LineChartDataSet.swift; sourceTree = "<group>"; };
|
||||
5B6A54C51AA74516000F57C2 /* LineRadarChartDataSet.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LineRadarChartDataSet.swift; sourceTree = "<group>"; };
|
||||
5B6A54C61AA74516000F57C2 /* PieChartData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PieChartData.swift; sourceTree = "<group>"; };
|
||||
5B6A54C71AA74516000F57C2 /* PieChartDataSet.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PieChartDataSet.swift; sourceTree = "<group>"; };
|
||||
5B6A54C81AA74516000F57C2 /* RadarChartData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RadarChartData.swift; sourceTree = "<group>"; };
|
||||
5B6A54C91AA74516000F57C2 /* RadarChartDataSet.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RadarChartDataSet.swift; sourceTree = "<group>"; };
|
||||
5B6A54CA1AA74516000F57C2 /* ScatterChartData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ScatterChartData.swift; sourceTree = "<group>"; };
|
||||
5B6A54CB1AA74516000F57C2 /* ScatterChartDataSet.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ScatterChartDataSet.swift; sourceTree = "<group>"; };
|
||||
5B8FE2AE1B68F8F600910C9E /* LineScatterCandleChartDataSet.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LineScatterCandleChartDataSet.swift; sourceTree = "<group>"; };
|
||||
5B8FE2B01B68FFF900910C9E /* LineScatterCandleRadarChartRenderer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LineScatterCandleRadarChartRenderer.swift; sourceTree = "<group>"; };
|
||||
5BA8EC401A9D14DC00CE82E1 /* Charts.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Charts.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
5BA8EC441A9D14DC00CE82E1 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
5BA8EC671A9D151C00CE82E1 /* ChartViewBase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChartViewBase.swift; sourceTree = "<group>"; };
|
||||
5BA8EC6A1A9D151C00CE82E1 /* ChartAxisBase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = ChartAxisBase.swift; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.swift; };
|
||||
5BA8EC6B1A9D151C00CE82E1 /* ChartLegend.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChartLegend.swift; sourceTree = "<group>"; };
|
||||
5BA8EC6C1A9D151C00CE82E1 /* ChartLimitLine.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChartLimitLine.swift; sourceTree = "<group>"; };
|
||||
5BA8EC6D1A9D151C00CE82E1 /* ChartXAxis.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChartXAxis.swift; sourceTree = "<group>"; };
|
||||
5BA8EC6E1A9D151C00CE82E1 /* ChartYAxis.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChartYAxis.swift; sourceTree = "<group>"; };
|
||||
5BA8EC751A9D151C00CE82E1 /* ChartDataApproximatorFilter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChartDataApproximatorFilter.swift; sourceTree = "<group>"; };
|
||||
5BA8EC761A9D151C00CE82E1 /* ChartDataBaseFilter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChartDataBaseFilter.swift; sourceTree = "<group>"; };
|
||||
5BA8EC791A9D151C00CE82E1 /* ChartColorTemplates.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChartColorTemplates.swift; sourceTree = "<group>"; };
|
||||
5BA8EC7B1A9D151C00CE82E1 /* ChartSelectionDetail.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChartSelectionDetail.swift; sourceTree = "<group>"; };
|
||||
5BA8EC7C1A9D151C00CE82E1 /* ChartUtils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChartUtils.swift; sourceTree = "<group>"; };
|
||||
5BAAA8551BB08E1D00B20D4D /* CombinedHighlighter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CombinedHighlighter.swift; sourceTree = "<group>"; };
|
||||
5BB6EC1C1ACC28AB006E9C25 /* ChartTransformerHorizontalBarChart.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChartTransformerHorizontalBarChart.swift; sourceTree = "<group>"; };
|
||||
5BD8F06C1AB897D500566E05 /* ChartViewPortHandler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChartViewPortHandler.swift; sourceTree = "<group>"; };
|
||||
A52C5C371BAC5CA400594CDD /* ChartsTV.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = ChartsTV.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
A52C5C391BAC5CA400594CDD /* ChartsTV.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ChartsTV.h; sourceTree = "<group>"; };
|
||||
A52C5C3B1BAC5CA400594CDD /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
5BA8EC3C1A9D14DC00CE82E1 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
5B680D1D1A9D16F90026A057 /* UIKit.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
A52C5C331BAC5CA400594CDD /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
5B0032431B65247600B6A2FE /* Highlight */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
5B0032441B6524AD00B6A2FE /* ChartHighlight.swift */,
|
||||
5B0032461B6524D300B6A2FE /* ChartRange.swift */,
|
||||
5B0032481B6525FC00B6A2FE /* ChartHighlighter.swift */,
|
||||
5B00324A1B652BF900B6A2FE /* BarChartHighlighter.swift */,
|
||||
5BAAA8551BB08E1D00B20D4D /* CombinedHighlighter.swift */,
|
||||
5B00324C1B65351C00B6A2FE /* HorizontalBarChartHighlighter.swift */,
|
||||
);
|
||||
path = Highlight;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
5B6654D41BB0A86F00890030 /* Formatters */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
5B6654D51BB0A86F00890030 /* ChartDefaultXAxisValueFormatter.swift */,
|
||||
5B6654D61BB0A86F00890030 /* ChartFillFormatter.swift */,
|
||||
5B6654D71BB0A86F00890030 /* ChartXAxisValueFormatter.swift */,
|
||||
);
|
||||
path = Formatters;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
5B680D1E1A9D170B0026A057 /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
5B680D1C1A9D16F90026A057 /* UIKit.framework */,
|
||||
);
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
5B6A546C1AA5D2D0000F57C2 /* Animation */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
5B6A546D1AA5D2DC000F57C2 /* ChartAnimator.swift */,
|
||||
5B378F161AD500A4009414A4 /* ChartAnimationEasing.swift */,
|
||||
);
|
||||
path = Animation;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
5B759ED41A9F98A90039D97F /* Renderers */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
5B6A54711AA5DCA8000F57C2 /* ChartAxisRendererBase.swift */,
|
||||
5B6A54961AA66AD2000F57C2 /* BarChartRenderer.swift */,
|
||||
55E3565A1ADC63EB00A57971 /* BubbleChartRenderer.swift */,
|
||||
5B6A54941AA66AC0000F57C2 /* CandleStickChartRenderer.swift */,
|
||||
5B6A54921AA66AAB000F57C2 /* CombinedChartRenderer.swift */,
|
||||
5B6A54901AA66A8D000F57C2 /* ChartDataRendererBase.swift */,
|
||||
5B6A548E1AA66A7A000F57C2 /* HorizontalBarChartRenderer.swift */,
|
||||
5B6A548C1AA66A60000F57C2 /* ChartLegendRenderer.swift */,
|
||||
5B6A548A1AA66A3D000F57C2 /* LineChartRenderer.swift */,
|
||||
5B8FE2B01B68FFF900910C9E /* LineScatterCandleRadarChartRenderer.swift */,
|
||||
5B6A54881AA66A1A000F57C2 /* PieChartRenderer.swift */,
|
||||
5B6A54861AA669F4000F57C2 /* RadarChartRenderer.swift */,
|
||||
5B6A546F1AA5DB34000F57C2 /* ChartRendererBase.swift */,
|
||||
5B6A54841AA669C9000F57C2 /* ScatterChartRenderer.swift */,
|
||||
5B6A54731AA5DEDC000F57C2 /* ChartXAxisRenderer.swift */,
|
||||
5B6A54751AA5DEE3000F57C2 /* ChartXAxisRendererBarChart.swift */,
|
||||
5B6A547B1AA5DF02000F57C2 /* ChartXAxisRendererHorizontalBarChart.swift */,
|
||||
5B6A54771AA5DEF0000F57C2 /* ChartXAxisRendererRadarChart.swift */,
|
||||
5B6A547D1AA5DF1A000F57C2 /* ChartYAxisRenderer.swift */,
|
||||
5B6A547F1AA5DF28000F57C2 /* ChartYAxisRendererHorizontalBarChart.swift */,
|
||||
5B6A54811AA5DF34000F57C2 /* ChartYAxisRendererRadarChart.swift */,
|
||||
);
|
||||
path = Renderers;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
5BA8EC361A9D14DC00CE82E1 = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
5BA8EC651A9D151C00CE82E1 /* Classes */,
|
||||
5BA8EC431A9D14DC00CE82E1 /* Supporting Files */,
|
||||
A52C5C381BAC5CA400594CDD /* ChartsTV */,
|
||||
5BA8EC411A9D14DC00CE82E1 /* Products */,
|
||||
5B680D1E1A9D170B0026A057 /* Frameworks */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
5BA8EC411A9D14DC00CE82E1 /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
5BA8EC401A9D14DC00CE82E1 /* Charts.framework */,
|
||||
A52C5C371BAC5CA400594CDD /* ChartsTV.framework */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
5BA8EC431A9D14DC00CE82E1 /* Supporting Files */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
5B680D3C1A9D1AD90026A057 /* Charts.h */,
|
||||
5BA8EC441A9D14DC00CE82E1 /* Info.plist */,
|
||||
);
|
||||
path = "Supporting Files";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
5BA8EC651A9D151C00CE82E1 /* Classes */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
5B6A546C1AA5D2D0000F57C2 /* Animation */,
|
||||
5BA8EC661A9D151C00CE82E1 /* Charts */,
|
||||
5BA8EC691A9D151C00CE82E1 /* Components */,
|
||||
5BA8EC6F1A9D151C00CE82E1 /* Data */,
|
||||
5BA8EC741A9D151C00CE82E1 /* Filters */,
|
||||
5B6654D41BB0A86F00890030 /* Formatters */,
|
||||
5B0032431B65247600B6A2FE /* Highlight */,
|
||||
5B759ED41A9F98A90039D97F /* Renderers */,
|
||||
5BA8EC781A9D151C00CE82E1 /* Utils */,
|
||||
);
|
||||
path = Classes;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
5BA8EC661A9D151C00CE82E1 /* Charts */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
5B6A54981AA66B14000F57C2 /* BarChartView.swift */,
|
||||
5B6A549A1AA66B2C000F57C2 /* BarLineChartViewBase.swift */,
|
||||
55E356521ADC63BF00A57971 /* BubbleChartView.swift */,
|
||||
5B6A549C1AA66B3C000F57C2 /* CandleStickChartView.swift */,
|
||||
5BA8EC671A9D151C00CE82E1 /* ChartViewBase.swift */,
|
||||
5B6A549E1AA66B59000F57C2 /* CombinedChartView.swift */,
|
||||
5B6A54A01AA66B6A000F57C2 /* HorizontalBarChartView.swift */,
|
||||
5B6A54A21AA66B7C000F57C2 /* LineChartView.swift */,
|
||||
5B6A54A41AA66B92000F57C2 /* PieChartView.swift */,
|
||||
5B6A54A61AA66BA7000F57C2 /* PieRadarChartViewBase.swift */,
|
||||
5B6A54A81AA66BBA000F57C2 /* RadarChartView.swift */,
|
||||
5B6A54AA1AA66BC8000F57C2 /* ScatterChartView.swift */,
|
||||
);
|
||||
path = Charts;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
5BA8EC691A9D151C00CE82E1 /* Components */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
5BA8EC6A1A9D151C00CE82E1 /* ChartAxisBase.swift */,
|
||||
5B6556F61AB72BA000FFBFD3 /* ChartComponentBase.swift */,
|
||||
5BA8EC6B1A9D151C00CE82E1 /* ChartLegend.swift */,
|
||||
5BA8EC6C1A9D151C00CE82E1 /* ChartLimitLine.swift */,
|
||||
5B6A546A1AA5C23F000F57C2 /* ChartMarker.swift */,
|
||||
5BA8EC6D1A9D151C00CE82E1 /* ChartXAxis.swift */,
|
||||
5BA8EC6E1A9D151C00CE82E1 /* ChartYAxis.swift */,
|
||||
);
|
||||
path = Components;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
5BA8EC6F1A9D151C00CE82E1 /* Data */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
5B6A54B71AA74516000F57C2 /* BarChartData.swift */,
|
||||
5B6A54B81AA74516000F57C2 /* BarChartDataEntry.swift */,
|
||||
5B6A54B91AA74516000F57C2 /* BarChartDataSet.swift */,
|
||||
5B6A54BA1AA74516000F57C2 /* BarLineScatterCandleBubbleChartData.swift */,
|
||||
5B6A54BB1AA74516000F57C2 /* BarLineScatterCandleBubbleChartDataSet.swift */,
|
||||
55E356541ADC63CD00A57971 /* BubbleChartData.swift */,
|
||||
55E356551ADC63CD00A57971 /* BubbleChartDataEntry.swift */,
|
||||
55E356561ADC63CD00A57971 /* BubbleChartDataSet.swift */,
|
||||
5B6A54BC1AA74516000F57C2 /* CandleChartData.swift */,
|
||||
5B6A54BD1AA74516000F57C2 /* CandleChartDataEntry.swift */,
|
||||
5B6A54BE1AA74516000F57C2 /* CandleChartDataSet.swift */,
|
||||
5B6A54BF1AA74516000F57C2 /* CombinedChartData.swift */,
|
||||
5B6A54C01AA74516000F57C2 /* ChartData.swift */,
|
||||
5B6A54C11AA74516000F57C2 /* ChartDataEntry.swift */,
|
||||
5B6A54C21AA74516000F57C2 /* ChartDataSet.swift */,
|
||||
5B6A54C31AA74516000F57C2 /* LineChartData.swift */,
|
||||
5B6A54C41AA74516000F57C2 /* LineChartDataSet.swift */,
|
||||
5B6A54C51AA74516000F57C2 /* LineRadarChartDataSet.swift */,
|
||||
5B8FE2AE1B68F8F600910C9E /* LineScatterCandleChartDataSet.swift */,
|
||||
5B6A54C61AA74516000F57C2 /* PieChartData.swift */,
|
||||
5B6A54C71AA74516000F57C2 /* PieChartDataSet.swift */,
|
||||
5B6A54C81AA74516000F57C2 /* RadarChartData.swift */,
|
||||
5B6A54C91AA74516000F57C2 /* RadarChartDataSet.swift */,
|
||||
5B6A54CA1AA74516000F57C2 /* ScatterChartData.swift */,
|
||||
5B6A54CB1AA74516000F57C2 /* ScatterChartDataSet.swift */,
|
||||
);
|
||||
path = Data;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
5BA8EC741A9D151C00CE82E1 /* Filters */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
5BA8EC751A9D151C00CE82E1 /* ChartDataApproximatorFilter.swift */,
|
||||
5BA8EC761A9D151C00CE82E1 /* ChartDataBaseFilter.swift */,
|
||||
);
|
||||
path = Filters;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
5BA8EC781A9D151C00CE82E1 /* Utils */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
5BA8EC791A9D151C00CE82E1 /* ChartColorTemplates.swift */,
|
||||
5BA8EC7B1A9D151C00CE82E1 /* ChartSelectionDetail.swift */,
|
||||
5B4BCD3F1AA9C4930063F019 /* ChartTransformer.swift */,
|
||||
5BB6EC1C1ACC28AB006E9C25 /* ChartTransformerHorizontalBarChart.swift */,
|
||||
5BA8EC7C1A9D151C00CE82E1 /* ChartUtils.swift */,
|
||||
5BD8F06C1AB897D500566E05 /* ChartViewPortHandler.swift */,
|
||||
06A5D1851B78675500915098 /* UIGraphics+Extensions.swift */,
|
||||
);
|
||||
path = Utils;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
A52C5C381BAC5CA400594CDD /* ChartsTV */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
A52C5C391BAC5CA400594CDD /* ChartsTV.h */,
|
||||
A52C5C3B1BAC5CA400594CDD /* Info.plist */,
|
||||
);
|
||||
path = ChartsTV;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXHeadersBuildPhase section */
|
||||
5BA8EC3D1A9D14DC00CE82E1 /* Headers */ = {
|
||||
isa = PBXHeadersBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
5B680D3D1A9D1AD90026A057 /* Charts.h in Headers */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
A52C5C341BAC5CA400594CDD /* Headers */ = {
|
||||
isa = PBXHeadersBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
A52C5C3A1BAC5CA400594CDD /* ChartsTV.h in Headers */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXHeadersBuildPhase section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
5BA8EC3F1A9D14DC00CE82E1 /* Charts */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 5BA8EC561A9D14DC00CE82E1 /* Build configuration list for PBXNativeTarget "Charts" */;
|
||||
buildPhases = (
|
||||
5BA8EC3B1A9D14DC00CE82E1 /* Sources */,
|
||||
5BA8EC3C1A9D14DC00CE82E1 /* Frameworks */,
|
||||
5BA8EC3D1A9D14DC00CE82E1 /* Headers */,
|
||||
5BA8EC3E1A9D14DC00CE82E1 /* Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = Charts;
|
||||
productName = Charts;
|
||||
productReference = 5BA8EC401A9D14DC00CE82E1 /* Charts.framework */;
|
||||
productType = "com.apple.product-type.framework";
|
||||
};
|
||||
A52C5C361BAC5CA400594CDD /* ChartsTV */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = A52C5C3E1BAC5CA400594CDD /* Build configuration list for PBXNativeTarget "ChartsTV" */;
|
||||
buildPhases = (
|
||||
A52C5C321BAC5CA400594CDD /* Sources */,
|
||||
A52C5C331BAC5CA400594CDD /* Frameworks */,
|
||||
A52C5C341BAC5CA400594CDD /* Headers */,
|
||||
A52C5C351BAC5CA400594CDD /* Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = ChartsTV;
|
||||
productName = ChartsTV;
|
||||
productReference = A52C5C371BAC5CA400594CDD /* ChartsTV.framework */;
|
||||
productType = "com.apple.product-type.framework";
|
||||
};
|
||||
/* End PBXNativeTarget section */
|
||||
|
||||
/* Begin PBXProject section */
|
||||
5BA8EC371A9D14DC00CE82E1 /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastSwiftMigration = 0700;
|
||||
LastSwiftUpdateCheck = 0700;
|
||||
LastUpgradeCheck = 0700;
|
||||
ORGANIZATIONNAME = dcg;
|
||||
TargetAttributes = {
|
||||
5BA8EC3F1A9D14DC00CE82E1 = {
|
||||
CreatedOnToolsVersion = 6.1.1;
|
||||
};
|
||||
A52C5C361BAC5CA400594CDD = {
|
||||
CreatedOnToolsVersion = 7.1;
|
||||
};
|
||||
};
|
||||
};
|
||||
buildConfigurationList = 5BA8EC3A1A9D14DC00CE82E1 /* Build configuration list for PBXProject "Charts" */;
|
||||
compatibilityVersion = "Xcode 3.2";
|
||||
developmentRegion = English;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
en,
|
||||
);
|
||||
mainGroup = 5BA8EC361A9D14DC00CE82E1;
|
||||
productRefGroup = 5BA8EC411A9D14DC00CE82E1 /* Products */;
|
||||
projectDirPath = "";
|
||||
projectRoot = "";
|
||||
targets = (
|
||||
5BA8EC3F1A9D14DC00CE82E1 /* Charts */,
|
||||
A52C5C361BAC5CA400594CDD /* ChartsTV */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
||||
/* Begin PBXResourcesBuildPhase section */
|
||||
5BA8EC3E1A9D14DC00CE82E1 /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
A52C5C351BAC5CA400594CDD /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
5BA8EC3B1A9D14DC00CE82E1 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
5B680D1F1A9D17C30026A057 /* ChartAxisBase.swift in Sources */,
|
||||
5B6A54DE1AA74516000F57C2 /* RadarChartDataSet.swift in Sources */,
|
||||
5B8FE2AF1B68F8F600910C9E /* LineScatterCandleChartDataSet.swift in Sources */,
|
||||
5BAAA8561BB08E1D00B20D4D /* CombinedHighlighter.swift in Sources */,
|
||||
5B680D211A9D17C30026A057 /* ChartLimitLine.swift in Sources */,
|
||||
5B6A54DB1AA74516000F57C2 /* PieChartData.swift in Sources */,
|
||||
5B6A54D91AA74516000F57C2 /* LineChartDataSet.swift in Sources */,
|
||||
5B6A54AC1AA66C1E000F57C2 /* ChartAxisRendererBase.swift in Sources */,
|
||||
5B6A54CF1AA74516000F57C2 /* BarLineScatterCandleBubbleChartData.swift in Sources */,
|
||||
5B6A54D11AA74516000F57C2 /* CandleChartData.swift in Sources */,
|
||||
5B6654DA1BB0A86F00890030 /* ChartFillFormatter.swift in Sources */,
|
||||
5B6A54AB1AA66BC8000F57C2 /* ScatterChartView.swift in Sources */,
|
||||
5B6A54E01AA74516000F57C2 /* ScatterChartDataSet.swift in Sources */,
|
||||
5B6A548B1AA66A3D000F57C2 /* LineChartRenderer.swift in Sources */,
|
||||
5B6A54D01AA74516000F57C2 /* BarLineScatterCandleBubbleChartDataSet.swift in Sources */,
|
||||
5B6A54821AA5DF34000F57C2 /* ChartYAxisRendererRadarChart.swift in Sources */,
|
||||
5B6A54931AA66AAB000F57C2 /* CombinedChartRenderer.swift in Sources */,
|
||||
5B680D221A9D17C30026A057 /* ChartXAxis.swift in Sources */,
|
||||
5BA8EC891A9D151C00CE82E1 /* ChartDataBaseFilter.swift in Sources */,
|
||||
5B6654DB1BB0A86F00890030 /* ChartXAxisValueFormatter.swift in Sources */,
|
||||
5B6A54A31AA66B7C000F57C2 /* LineChartView.swift in Sources */,
|
||||
5B6A54891AA66A1A000F57C2 /* PieChartRenderer.swift in Sources */,
|
||||
5B6A54DD1AA74516000F57C2 /* RadarChartData.swift in Sources */,
|
||||
5B6A54991AA66B14000F57C2 /* BarChartView.swift in Sources */,
|
||||
5B680D231A9D17C30026A057 /* ChartYAxis.swift in Sources */,
|
||||
5B6A54A91AA66BBA000F57C2 /* RadarChartView.swift in Sources */,
|
||||
5B378F171AD500A4009414A4 /* ChartAnimationEasing.swift in Sources */,
|
||||
5B6A548F1AA66A7A000F57C2 /* HorizontalBarChartRenderer.swift in Sources */,
|
||||
5B6A54741AA5DEDC000F57C2 /* ChartXAxisRenderer.swift in Sources */,
|
||||
5B6A547C1AA5DF02000F57C2 /* ChartXAxisRendererHorizontalBarChart.swift in Sources */,
|
||||
5B4BCD401AA9C4930063F019 /* ChartTransformer.swift in Sources */,
|
||||
5B6A54801AA5DF28000F57C2 /* ChartYAxisRendererHorizontalBarChart.swift in Sources */,
|
||||
5B6A54D21AA74516000F57C2 /* CandleChartDataEntry.swift in Sources */,
|
||||
5B6A54CC1AA74516000F57C2 /* BarChartData.swift in Sources */,
|
||||
5B00324D1B65351C00B6A2FE /* HorizontalBarChartHighlighter.swift in Sources */,
|
||||
5B6A54CE1AA74516000F57C2 /* BarChartDataSet.swift in Sources */,
|
||||
5B6A54871AA669F4000F57C2 /* RadarChartRenderer.swift in Sources */,
|
||||
5B6A548D1AA66A60000F57C2 /* ChartLegendRenderer.swift in Sources */,
|
||||
55E356591ADC63CD00A57971 /* BubbleChartDataSet.swift in Sources */,
|
||||
5BB6EC1D1ACC28AB006E9C25 /* ChartTransformerHorizontalBarChart.swift in Sources */,
|
||||
5B680D271A9D17C30026A057 /* ChartColorTemplates.swift in Sources */,
|
||||
5B6A54951AA66AC0000F57C2 /* CandleStickChartRenderer.swift in Sources */,
|
||||
5B680D291A9D17C30026A057 /* ChartSelectionDetail.swift in Sources */,
|
||||
5BA8EC7D1A9D151C00CE82E1 /* ChartViewBase.swift in Sources */,
|
||||
5B6A54DC1AA74516000F57C2 /* PieChartDataSet.swift in Sources */,
|
||||
5B6A54DA1AA74516000F57C2 /* LineRadarChartDataSet.swift in Sources */,
|
||||
06A5D1861B78675500915098 /* UIGraphics+Extensions.swift in Sources */,
|
||||
5B6A54701AA5DB34000F57C2 /* ChartRendererBase.swift in Sources */,
|
||||
5B6A54761AA5DEE3000F57C2 /* ChartXAxisRendererBarChart.swift in Sources */,
|
||||
5B6A54851AA669C9000F57C2 /* ScatterChartRenderer.swift in Sources */,
|
||||
5B6A549D1AA66B3C000F57C2 /* CandleStickChartView.swift in Sources */,
|
||||
5BA8EC881A9D151C00CE82E1 /* ChartDataApproximatorFilter.swift in Sources */,
|
||||
5B6A549B1AA66B2C000F57C2 /* BarLineChartViewBase.swift in Sources */,
|
||||
5B6A54A51AA66B92000F57C2 /* PieChartView.swift in Sources */,
|
||||
5B6A54D81AA74516000F57C2 /* LineChartData.swift in Sources */,
|
||||
55E356581ADC63CD00A57971 /* BubbleChartDataEntry.swift in Sources */,
|
||||
5B6A54911AA66A8D000F57C2 /* ChartDataRendererBase.swift in Sources */,
|
||||
5BD8F06D1AB897D500566E05 /* ChartViewPortHandler.swift in Sources */,
|
||||
5B8FE2B11B68FFF900910C9E /* LineScatterCandleRadarChartRenderer.swift in Sources */,
|
||||
5B6A54D51AA74516000F57C2 /* ChartData.swift in Sources */,
|
||||
5B6A54971AA66AD2000F57C2 /* BarChartRenderer.swift in Sources */,
|
||||
5B6A546B1AA5C23F000F57C2 /* ChartMarker.swift in Sources */,
|
||||
5B6A54D61AA74516000F57C2 /* ChartDataEntry.swift in Sources */,
|
||||
55E356571ADC63CD00A57971 /* BubbleChartData.swift in Sources */,
|
||||
5B6A54DF1AA74516000F57C2 /* ScatterChartData.swift in Sources */,
|
||||
5B6A54D31AA74516000F57C2 /* CandleChartDataSet.swift in Sources */,
|
||||
5B0032491B6525FC00B6A2FE /* ChartHighlighter.swift in Sources */,
|
||||
5B6A54D71AA74516000F57C2 /* ChartDataSet.swift in Sources */,
|
||||
5B00324B1B652BF900B6A2FE /* BarChartHighlighter.swift in Sources */,
|
||||
5B6A54781AA5DEF0000F57C2 /* ChartXAxisRendererRadarChart.swift in Sources */,
|
||||
5B6A54A71AA66BA7000F57C2 /* PieRadarChartViewBase.swift in Sources */,
|
||||
5B6A546E1AA5D2DC000F57C2 /* ChartAnimator.swift in Sources */,
|
||||
55E3565B1ADC63EB00A57971 /* BubbleChartRenderer.swift in Sources */,
|
||||
55E356531ADC63BF00A57971 /* BubbleChartView.swift in Sources */,
|
||||
5B6654D91BB0A86F00890030 /* ChartDefaultXAxisValueFormatter.swift in Sources */,
|
||||
5B6A547E1AA5DF1A000F57C2 /* ChartYAxisRenderer.swift in Sources */,
|
||||
5B6A549F1AA66B59000F57C2 /* CombinedChartView.swift in Sources */,
|
||||
5B6556F71AB72BA000FFBFD3 /* ChartComponentBase.swift in Sources */,
|
||||
5B6A54CD1AA74516000F57C2 /* BarChartDataEntry.swift in Sources */,
|
||||
5B6A54D41AA74516000F57C2 /* CombinedChartData.swift in Sources */,
|
||||
5B680D2A1A9D17C30026A057 /* ChartUtils.swift in Sources */,
|
||||
5B0032451B6524AD00B6A2FE /* ChartHighlight.swift in Sources */,
|
||||
5B680D201A9D17C30026A057 /* ChartLegend.swift in Sources */,
|
||||
5B0032471B6524D300B6A2FE /* ChartRange.swift in Sources */,
|
||||
5BD8F06E1AB89AD800566E05 /* HorizontalBarChartView.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
A52C5C321BAC5CA400594CDD /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
A52C5C3F1BAC5D1100594CDD /* ChartAnimator.swift in Sources */,
|
||||
A52C5C401BAC5D1100594CDD /* ChartAnimationEasing.swift in Sources */,
|
||||
A52C5C411BAC5D1100594CDD /* BarChartView.swift in Sources */,
|
||||
A52C5C421BAC5D1100594CDD /* BarLineChartViewBase.swift in Sources */,
|
||||
A52C5C431BAC5D1100594CDD /* BubbleChartView.swift in Sources */,
|
||||
A52C5C441BAC5D1100594CDD /* CandleStickChartView.swift in Sources */,
|
||||
A52C5C451BAC5D1100594CDD /* ChartViewBase.swift in Sources */,
|
||||
A52C5C461BAC5D1100594CDD /* CombinedChartView.swift in Sources */,
|
||||
A52C5C471BAC5D1100594CDD /* HorizontalBarChartView.swift in Sources */,
|
||||
A52C5C481BAC5D1100594CDD /* LineChartView.swift in Sources */,
|
||||
A52C5C491BAC5D1100594CDD /* PieChartView.swift in Sources */,
|
||||
A52C5C4A1BAC5D1100594CDD /* PieRadarChartViewBase.swift in Sources */,
|
||||
A52C5C4B1BAC5D1100594CDD /* RadarChartView.swift in Sources */,
|
||||
A52C5C4C1BAC5D1100594CDD /* ScatterChartView.swift in Sources */,
|
||||
A52C5C4D1BAC5D1100594CDD /* ChartAxisBase.swift in Sources */,
|
||||
A52C5C4E1BAC5D1100594CDD /* ChartComponentBase.swift in Sources */,
|
||||
A52C5C4F1BAC5D1100594CDD /* ChartLegend.swift in Sources */,
|
||||
A52C5C501BAC5D1100594CDD /* ChartLimitLine.swift in Sources */,
|
||||
A52C5C511BAC5D1100594CDD /* ChartMarker.swift in Sources */,
|
||||
A52C5C521BAC5D1100594CDD /* ChartXAxis.swift in Sources */,
|
||||
A52C5C531BAC5D1100594CDD /* ChartYAxis.swift in Sources */,
|
||||
A52C5C541BAC5D1100594CDD /* BarChartData.swift in Sources */,
|
||||
A52C5C551BAC5D1100594CDD /* BarChartDataEntry.swift in Sources */,
|
||||
A52C5C561BAC5D1100594CDD /* BarChartDataSet.swift in Sources */,
|
||||
A52C5C571BAC5D1100594CDD /* BarLineScatterCandleChartData.swift in Sources */,
|
||||
A52C5C581BAC5D1100594CDD /* BarLineScatterCandleChartDataSet.swift in Sources */,
|
||||
A52C5C591BAC5D1100594CDD /* BubbleChartData.swift in Sources */,
|
||||
A52C5C5A1BAC5D1100594CDD /* BubbleChartDataEntry.swift in Sources */,
|
||||
A52C5C5B1BAC5D1100594CDD /* BubbleChartDataSet.swift in Sources */,
|
||||
A52C5C5C1BAC5D1100594CDD /* CandleChartData.swift in Sources */,
|
||||
A52C5C5D1BAC5D1100594CDD /* CandleChartDataEntry.swift in Sources */,
|
||||
A52C5C5E1BAC5D1100594CDD /* CandleChartDataSet.swift in Sources */,
|
||||
A52C5C5F1BAC5D1100594CDD /* CombinedChartData.swift in Sources */,
|
||||
A52C5C601BAC5D1100594CDD /* ChartData.swift in Sources */,
|
||||
A52C5C611BAC5D1100594CDD /* ChartDataEntry.swift in Sources */,
|
||||
A52C5C621BAC5D1100594CDD /* ChartDataSet.swift in Sources */,
|
||||
A52C5C631BAC5D1100594CDD /* LineChartData.swift in Sources */,
|
||||
A52C5C641BAC5D1100594CDD /* LineChartDataSet.swift in Sources */,
|
||||
A52C5C651BAC5D1100594CDD /* LineRadarChartDataSet.swift in Sources */,
|
||||
A52C5C661BAC5D1100594CDD /* LineScatterCandleChartDataSet.swift in Sources */,
|
||||
A52C5C671BAC5D1100594CDD /* PieChartData.swift in Sources */,
|
||||
A52C5C681BAC5D1100594CDD /* PieChartDataSet.swift in Sources */,
|
||||
A52C5C691BAC5D1100594CDD /* RadarChartData.swift in Sources */,
|
||||
A52C5C6A1BAC5D1100594CDD /* RadarChartDataSet.swift in Sources */,
|
||||
A52C5C6B1BAC5D1100594CDD /* ScatterChartData.swift in Sources */,
|
||||
A52C5C6C1BAC5D1100594CDD /* ScatterChartDataSet.swift in Sources */,
|
||||
A52C5C6D1BAC5D1100594CDD /* ChartDataApproximatorFilter.swift in Sources */,
|
||||
A52C5C6E1BAC5D1100594CDD /* ChartDataBaseFilter.swift in Sources */,
|
||||
A52C5C6F1BAC5D1100594CDD /* ChartHighlight.swift in Sources */,
|
||||
A52C5C701BAC5D1100594CDD /* ChartRange.swift in Sources */,
|
||||
A52C5C711BAC5D1100594CDD /* ChartHighlighter.swift in Sources */,
|
||||
A52C5C721BAC5D1100594CDD /* BarChartHighlighter.swift in Sources */,
|
||||
A52C5C731BAC5D1100594CDD /* HorizontalBarChartHighlighter.swift in Sources */,
|
||||
A52C5C741BAC5D1100594CDD /* ChartAxisRendererBase.swift in Sources */,
|
||||
A52C5C751BAC5D1100594CDD /* BarChartRenderer.swift in Sources */,
|
||||
A52C5C761BAC5D1100594CDD /* BubbleChartRenderer.swift in Sources */,
|
||||
A52C5C771BAC5D1100594CDD /* CandleStickChartRenderer.swift in Sources */,
|
||||
A52C5C781BAC5D1100594CDD /* CombinedChartRenderer.swift in Sources */,
|
||||
A52C5C791BAC5D1100594CDD /* ChartDataRendererBase.swift in Sources */,
|
||||
A52C5C7A1BAC5D1200594CDD /* HorizontalBarChartRenderer.swift in Sources */,
|
||||
A52C5C7B1BAC5D1200594CDD /* ChartLegendRenderer.swift in Sources */,
|
||||
A52C5C7C1BAC5D1200594CDD /* LineChartRenderer.swift in Sources */,
|
||||
A52C5C7D1BAC5D1200594CDD /* LineScatterCandleRadarChartRenderer.swift in Sources */,
|
||||
A52C5C7E1BAC5D1200594CDD /* PieChartRenderer.swift in Sources */,
|
||||
A52C5C7F1BAC5D1200594CDD /* RadarChartRenderer.swift in Sources */,
|
||||
A52C5C801BAC5D1200594CDD /* ChartRendererBase.swift in Sources */,
|
||||
A52C5C811BAC5D1200594CDD /* ScatterChartRenderer.swift in Sources */,
|
||||
A52C5C821BAC5D1200594CDD /* ChartXAxisRenderer.swift in Sources */,
|
||||
A52C5C831BAC5D1200594CDD /* ChartXAxisRendererBarChart.swift in Sources */,
|
||||
A52C5C841BAC5D1200594CDD /* ChartXAxisRendererHorizontalBarChart.swift in Sources */,
|
||||
A52C5C851BAC5D1200594CDD /* ChartXAxisRendererRadarChart.swift in Sources */,
|
||||
A52C5C861BAC5D1200594CDD /* ChartYAxisRenderer.swift in Sources */,
|
||||
A52C5C871BAC5D1200594CDD /* ChartYAxisRendererHorizontalBarChart.swift in Sources */,
|
||||
A52C5C881BAC5D1200594CDD /* ChartYAxisRendererRadarChart.swift in Sources */,
|
||||
A52C5C891BAC5D1200594CDD /* ChartColorTemplates.swift in Sources */,
|
||||
A52C5C8A1BAC5D1200594CDD /* ChartFillFormatter.swift in Sources */,
|
||||
A52C5C8B1BAC5D1200594CDD /* ChartSelectionDetail.swift in Sources */,
|
||||
A52C5C8C1BAC5D1200594CDD /* ChartTransformer.swift in Sources */,
|
||||
A52C5C8D1BAC5D1200594CDD /* ChartTransformerHorizontalBarChart.swift in Sources */,
|
||||
A52C5C8E1BAC5D1200594CDD /* ChartUtils.swift in Sources */,
|
||||
A52C5C8F1BAC5D1200594CDD /* ChartViewPortHandler.swift in Sources */,
|
||||
A52C5C901BAC5D1200594CDD /* UIGraphics+Extensions.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
5BA8EC541A9D14DC00CE82E1 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"DEBUG=1",
|
||||
"$(inherited)",
|
||||
);
|
||||
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||
MTL_ENABLE_DEBUG_INFO = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = iphoneos;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
VERSION_INFO_PREFIX = "";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
5BA8EC551A9D14DC00CE82E1 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = YES;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
SDKROOT = iphoneos;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
VALIDATE_PRODUCT = YES;
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
VERSION_INFO_PREFIX = "";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
5BA8EC571A9D14DC00CE82E1 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
DEFINES_MODULE = YES;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
DYLIB_CURRENT_VERSION = 1;
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
INFOPLIST_FILE = "Supporting Files/Info.plist";
|
||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.dcg.$(PRODUCT_NAME:rfc1034identifier)";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
5BA8EC581A9D14DC00CE82E1 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
DEFINES_MODULE = YES;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
DYLIB_CURRENT_VERSION = 1;
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
INFOPLIST_FILE = "Supporting Files/Info.plist";
|
||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.dcg.$(PRODUCT_NAME:rfc1034identifier)";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
A52C5C3C1BAC5CA400594CDD /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
DEFINES_MODULE = YES;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
DYLIB_CURRENT_VERSION = 1;
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
INFOPLIST_FILE = ChartsTV/Info.plist;
|
||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.dcg.ChartsTV;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SDKROOT = appletvos;
|
||||
SKIP_INSTALL = YES;
|
||||
TARGETED_DEVICE_FAMILY = 3;
|
||||
TVOS_DEPLOYMENT_TARGET = 9.0;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
A52C5C3D1BAC5CA400594CDD /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
DEFINES_MODULE = YES;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
DYLIB_CURRENT_VERSION = 1;
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
INFOPLIST_FILE = ChartsTV/Info.plist;
|
||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.dcg.ChartsTV;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SDKROOT = appletvos;
|
||||
SKIP_INSTALL = YES;
|
||||
TARGETED_DEVICE_FAMILY = 3;
|
||||
TVOS_DEPLOYMENT_TARGET = 9.0;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
5BA8EC3A1A9D14DC00CE82E1 /* Build configuration list for PBXProject "Charts" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
5BA8EC541A9D14DC00CE82E1 /* Debug */,
|
||||
5BA8EC551A9D14DC00CE82E1 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
5BA8EC561A9D14DC00CE82E1 /* Build configuration list for PBXNativeTarget "Charts" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
5BA8EC571A9D14DC00CE82E1 /* Debug */,
|
||||
5BA8EC581A9D14DC00CE82E1 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
A52C5C3E1BAC5CA400594CDD /* Build configuration list for PBXNativeTarget "ChartsTV" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
A52C5C3C1BAC5CA400594CDD /* Debug */,
|
||||
A52C5C3D1BAC5CA400594CDD /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
};
|
||||
rootObject = 5BA8EC371A9D14DC00CE82E1 /* Project object */;
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1020"
|
||||
LastUpgradeVersion = "0700"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
@@ -14,7 +14,21 @@
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "F2749BD5443C1CB5FE2080C2"
|
||||
BlueprintIdentifier = "5BA8EC3F1A9D14DC00CE82E1"
|
||||
BuildableName = "Charts.framework"
|
||||
BlueprintName = "Charts"
|
||||
ReferencedContainer = "container:Charts.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "NO"
|
||||
buildForArchiving = "NO"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "5BA8EC4A1A9D14DC00CE82E1"
|
||||
BuildableName = "ChartsTests.xctest"
|
||||
BlueprintName = "ChartsTests"
|
||||
ReferencedContainer = "container:Charts.xcodeproj">
|
||||
@@ -23,32 +37,30 @@
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
codeCoverageEnabled = "YES"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
buildConfiguration = "Debug">
|
||||
<Testables>
|
||||
<TestableReference
|
||||
skipped = "NO">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "F2749BD5443C1CB5FE2080C2"
|
||||
BuildableName = "ChartsTests.xctest"
|
||||
BlueprintName = "ChartsTests"
|
||||
ReferencedContainer = "container:Charts.xcodeproj">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
</Testables>
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "5BA8EC3F1A9D14DC00CE82E1"
|
||||
BuildableName = "Charts.framework"
|
||||
BlueprintName = "Charts"
|
||||
ReferencedContainer = "container:Charts.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
buildConfiguration = "Debug"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
@@ -56,28 +68,30 @@
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "F2749BD5443C1CB5FE2080C2"
|
||||
BuildableName = "ChartsTests.xctest"
|
||||
BlueprintName = "ChartsTests"
|
||||
BlueprintIdentifier = "5BA8EC3F1A9D14DC00CE82E1"
|
||||
BuildableName = "Charts.framework"
|
||||
BlueprintName = "Charts"
|
||||
ReferencedContainer = "container:Charts.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<EnvironmentVariables>
|
||||
<EnvironmentVariable
|
||||
key = "FB_REFERENCE_IMAGE_DIR"
|
||||
value = "$(SOURCE_ROOT)/Tests/ReferenceImages"
|
||||
isEnabled = "YES">
|
||||
</EnvironmentVariable>
|
||||
</EnvironmentVariables>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
buildConfiguration = "Release"
|
||||
debugDocumentVersioning = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "5BA8EC3F1A9D14DC00CE82E1"
|
||||
BuildableName = "Charts.framework"
|
||||
BlueprintName = "Charts"
|
||||
ReferencedContainer = "container:Charts.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1020"
|
||||
LastUpgradeVersion = "0710"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
@@ -14,9 +14,9 @@
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "A58A4ED274A941CA248EA921"
|
||||
BuildableName = "Charts.framework"
|
||||
BlueprintName = "Charts"
|
||||
BlueprintIdentifier = "A52C5C361BAC5CA400594CDD"
|
||||
BuildableName = "ChartsTV.framework"
|
||||
BlueprintName = "ChartsTV"
|
||||
ReferencedContainer = "container:Charts.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
@@ -28,16 +28,6 @@
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
<TestableReference
|
||||
skipped = "NO">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "F2749BD5443C1CB5FE2080C2"
|
||||
BuildableName = "ChartsTests.xctest"
|
||||
BlueprintName = "ChartsTests"
|
||||
ReferencedContainer = "container:Charts.xcodeproj">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
</Testables>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
@@ -55,19 +45,12 @@
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "A58A4ED274A941CA248EA921"
|
||||
BuildableName = "Charts.framework"
|
||||
BlueprintName = "Charts"
|
||||
BlueprintIdentifier = "A52C5C361BAC5CA400594CDD"
|
||||
BuildableName = "ChartsTV.framework"
|
||||
BlueprintName = "ChartsTV"
|
||||
ReferencedContainer = "container:Charts.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<EnvironmentVariables>
|
||||
<EnvironmentVariable
|
||||
key = "FB_REFERENCE_IMAGE_DIR"
|
||||
value = "$(SOURCE_ROOT)/Tests/ReferenceImages"
|
||||
isEnabled = "YES">
|
||||
</EnvironmentVariable>
|
||||
</EnvironmentVariables>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</LaunchAction>
|
||||
@@ -77,6 +60,15 @@
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "A52C5C361BAC5CA400594CDD"
|
||||
BuildableName = "ChartsTV.framework"
|
||||
BlueprintName = "ChartsTV"
|
||||
ReferencedContainer = "container:Charts.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
19
Carthage/Checkouts/Charts/Charts/ChartsTV/ChartsTV.h
vendored
Normal file
19
Carthage/Checkouts/Charts/Charts/ChartsTV/ChartsTV.h
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
//
|
||||
// ChartsTV.h
|
||||
// ChartsTV
|
||||
//
|
||||
// Created by Tracy Keeling on 9/18/15.
|
||||
// Copyright © 2015 dcg. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
//! Project version number for ChartsTV.
|
||||
FOUNDATION_EXPORT double ChartsTVVersionNumber;
|
||||
|
||||
//! Project version string for ChartsTV.
|
||||
FOUNDATION_EXPORT const unsigned char ChartsTVVersionString[];
|
||||
|
||||
// In this header, you should import all the public headers of your framework using statements like #import <ChartsTV/PublicHeader.h>
|
||||
|
||||
|
||||
@@ -13,12 +13,14 @@
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>BNDL</string>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<string>$(CURRENT_PROJECT_VERSION)</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string></string>
|
||||
</dict>
|
||||
</plist>
|
||||
394
Carthage/Checkouts/Charts/Charts/Classes/Animation/ChartAnimationEasing.swift
vendored
Normal file
394
Carthage/Checkouts/Charts/Charts/Classes/Animation/ChartAnimationEasing.swift
vendored
Normal file
@@ -0,0 +1,394 @@
|
||||
//
|
||||
// ChartAnimationUtils.swift
|
||||
// Charts
|
||||
//
|
||||
// Created by Daniel Cohen Gindi on 23/2/15.
|
||||
|
||||
//
|
||||
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
|
||||
// A port of MPAndroidChart for iOS
|
||||
// Licensed under Apache License 2.0
|
||||
//
|
||||
// https://github.com/danielgindi/ios-charts
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import CoreGraphics
|
||||
|
||||
@objc
|
||||
public enum ChartEasingOption: Int
|
||||
{
|
||||
case Linear
|
||||
case EaseInQuad
|
||||
case EaseOutQuad
|
||||
case EaseInOutQuad
|
||||
case EaseInCubic
|
||||
case EaseOutCubic
|
||||
case EaseInOutCubic
|
||||
case EaseInQuart
|
||||
case EaseOutQuart
|
||||
case EaseInOutQuart
|
||||
case EaseInQuint
|
||||
case EaseOutQuint
|
||||
case EaseInOutQuint
|
||||
case EaseInSine
|
||||
case EaseOutSine
|
||||
case EaseInOutSine
|
||||
case EaseInExpo
|
||||
case EaseOutExpo
|
||||
case EaseInOutExpo
|
||||
case EaseInCirc
|
||||
case EaseOutCirc
|
||||
case EaseInOutCirc
|
||||
case EaseInElastic
|
||||
case EaseOutElastic
|
||||
case EaseInOutElastic
|
||||
case EaseInBack
|
||||
case EaseOutBack
|
||||
case EaseInOutBack
|
||||
case EaseInBounce
|
||||
case EaseOutBounce
|
||||
case EaseInOutBounce
|
||||
}
|
||||
|
||||
public typealias ChartEasingFunctionBlock = ((elapsed: NSTimeInterval, duration: NSTimeInterval) -> CGFloat)
|
||||
|
||||
internal func easingFunctionFromOption(easing: ChartEasingOption) -> ChartEasingFunctionBlock
|
||||
{
|
||||
switch easing
|
||||
{
|
||||
case .Linear:
|
||||
return EasingFunctions.Linear
|
||||
case .EaseInQuad:
|
||||
return EasingFunctions.EaseInQuad
|
||||
case .EaseOutQuad:
|
||||
return EasingFunctions.EaseOutQuad
|
||||
case .EaseInOutQuad:
|
||||
return EasingFunctions.EaseInOutQuad
|
||||
case .EaseInCubic:
|
||||
return EasingFunctions.EaseInCubic
|
||||
case .EaseOutCubic:
|
||||
return EasingFunctions.EaseOutCubic
|
||||
case .EaseInOutCubic:
|
||||
return EasingFunctions.EaseInOutCubic
|
||||
case .EaseInQuart:
|
||||
return EasingFunctions.EaseInQuart
|
||||
case .EaseOutQuart:
|
||||
return EasingFunctions.EaseOutQuart
|
||||
case .EaseInOutQuart:
|
||||
return EasingFunctions.EaseInOutQuart
|
||||
case .EaseInQuint:
|
||||
return EasingFunctions.EaseInQuint
|
||||
case .EaseOutQuint:
|
||||
return EasingFunctions.EaseOutQuint
|
||||
case .EaseInOutQuint:
|
||||
return EasingFunctions.EaseInOutQuint
|
||||
case .EaseInSine:
|
||||
return EasingFunctions.EaseInSine
|
||||
case .EaseOutSine:
|
||||
return EasingFunctions.EaseOutSine
|
||||
case .EaseInOutSine:
|
||||
return EasingFunctions.EaseInOutSine
|
||||
case .EaseInExpo:
|
||||
return EasingFunctions.EaseInExpo
|
||||
case .EaseOutExpo:
|
||||
return EasingFunctions.EaseOutExpo
|
||||
case .EaseInOutExpo:
|
||||
return EasingFunctions.EaseInOutExpo
|
||||
case .EaseInCirc:
|
||||
return EasingFunctions.EaseInCirc
|
||||
case .EaseOutCirc:
|
||||
return EasingFunctions.EaseOutCirc
|
||||
case .EaseInOutCirc:
|
||||
return EasingFunctions.EaseInOutCirc
|
||||
case .EaseInElastic:
|
||||
return EasingFunctions.EaseInElastic
|
||||
case .EaseOutElastic:
|
||||
return EasingFunctions.EaseOutElastic
|
||||
case .EaseInOutElastic:
|
||||
return EasingFunctions.EaseInOutElastic
|
||||
case .EaseInBack:
|
||||
return EasingFunctions.EaseInBack
|
||||
case .EaseOutBack:
|
||||
return EasingFunctions.EaseOutBack
|
||||
case .EaseInOutBack:
|
||||
return EasingFunctions.EaseInOutBack
|
||||
case .EaseInBounce:
|
||||
return EasingFunctions.EaseInBounce
|
||||
case .EaseOutBounce:
|
||||
return EasingFunctions.EaseOutBounce
|
||||
case .EaseInOutBounce:
|
||||
return EasingFunctions.EaseInOutBounce
|
||||
}
|
||||
}
|
||||
|
||||
internal struct EasingFunctions
|
||||
{
|
||||
internal static let Linear = { (elapsed: NSTimeInterval, duration: NSTimeInterval) -> CGFloat in return CGFloat(elapsed / duration); }
|
||||
|
||||
internal static let EaseInQuad = { (elapsed: NSTimeInterval, duration: NSTimeInterval) -> CGFloat in
|
||||
var position = CGFloat(elapsed / duration)
|
||||
return position * position
|
||||
}
|
||||
|
||||
internal static let EaseOutQuad = { (elapsed: NSTimeInterval, duration: NSTimeInterval) -> CGFloat in
|
||||
var position = CGFloat(elapsed / duration)
|
||||
return -position * (position - 2.0)
|
||||
}
|
||||
|
||||
internal static let EaseInOutQuad = { (elapsed: NSTimeInterval, duration: NSTimeInterval) -> CGFloat in
|
||||
var position = CGFloat(elapsed / (duration / 2.0))
|
||||
if (position < 1.0)
|
||||
{
|
||||
return 0.5 * position * position
|
||||
}
|
||||
return -0.5 * ((--position) * (position - 2.0) - 1.0)
|
||||
}
|
||||
|
||||
internal static let EaseInCubic = { (elapsed: NSTimeInterval, duration: NSTimeInterval) -> CGFloat in
|
||||
var position = CGFloat(elapsed / duration)
|
||||
return position * position * position
|
||||
}
|
||||
|
||||
internal static let EaseOutCubic = { (elapsed: NSTimeInterval, duration: NSTimeInterval) -> CGFloat in
|
||||
var position = CGFloat(elapsed / duration)
|
||||
position--
|
||||
return (position * position * position + 1.0)
|
||||
}
|
||||
|
||||
internal static let EaseInOutCubic = { (elapsed: NSTimeInterval, duration: NSTimeInterval) -> CGFloat in
|
||||
var position = CGFloat(elapsed / (duration / 2.0))
|
||||
if (position < 1.0)
|
||||
{
|
||||
return 0.5 * position * position * position
|
||||
}
|
||||
position -= 2.0
|
||||
return 0.5 * (position * position * position + 2.0)
|
||||
}
|
||||
|
||||
internal static let EaseInQuart = { (elapsed: NSTimeInterval, duration: NSTimeInterval) -> CGFloat in
|
||||
var position = CGFloat(elapsed / duration)
|
||||
return position * position * position * position
|
||||
}
|
||||
|
||||
internal static let EaseOutQuart = { (elapsed: NSTimeInterval, duration: NSTimeInterval) -> CGFloat in
|
||||
var position = CGFloat(elapsed / duration)
|
||||
position--
|
||||
return -(position * position * position * position - 1.0)
|
||||
}
|
||||
|
||||
internal static let EaseInOutQuart = { (elapsed: NSTimeInterval, duration: NSTimeInterval) -> CGFloat in
|
||||
var position = CGFloat(elapsed / (duration / 2.0))
|
||||
if (position < 1.0)
|
||||
{
|
||||
return 0.5 * position * position * position * position
|
||||
}
|
||||
position -= 2.0
|
||||
return -0.5 * (position * position * position * position - 2.0)
|
||||
}
|
||||
|
||||
internal static let EaseInQuint = { (elapsed: NSTimeInterval, duration: NSTimeInterval) -> CGFloat in
|
||||
var position = CGFloat(elapsed / duration)
|
||||
return position * position * position * position * position
|
||||
}
|
||||
|
||||
internal static let EaseOutQuint = { (elapsed: NSTimeInterval, duration: NSTimeInterval) -> CGFloat in
|
||||
var position = CGFloat(elapsed / duration)
|
||||
position--
|
||||
return (position * position * position * position * position + 1.0)
|
||||
}
|
||||
|
||||
internal static let EaseInOutQuint = { (elapsed: NSTimeInterval, duration: NSTimeInterval) -> CGFloat in
|
||||
var position = CGFloat(elapsed / (duration / 2.0))
|
||||
if (position < 1.0)
|
||||
{
|
||||
return 0.5 * position * position * position * position * position
|
||||
}
|
||||
else
|
||||
{
|
||||
position -= 2.0
|
||||
return 0.5 * (position * position * position * position * position + 2.0)
|
||||
}
|
||||
}
|
||||
|
||||
internal static let EaseInSine = { (elapsed: NSTimeInterval, duration: NSTimeInterval) -> CGFloat in
|
||||
var position: NSTimeInterval = elapsed / duration
|
||||
return CGFloat( -cos(position * M_PI_2) + 1.0 )
|
||||
}
|
||||
|
||||
internal static let EaseOutSine = { (elapsed: NSTimeInterval, duration: NSTimeInterval) -> CGFloat in
|
||||
var position: NSTimeInterval = elapsed / duration
|
||||
return CGFloat( sin(position * M_PI_2) )
|
||||
}
|
||||
|
||||
internal static let EaseInOutSine = { (elapsed: NSTimeInterval, duration: NSTimeInterval) -> CGFloat in
|
||||
var position: NSTimeInterval = elapsed / duration
|
||||
return CGFloat( -0.5 * (cos(M_PI * position) - 1.0) )
|
||||
}
|
||||
|
||||
internal static let EaseInExpo = { (elapsed: NSTimeInterval, duration: NSTimeInterval) -> CGFloat in
|
||||
return (elapsed == 0) ? 0.0 : CGFloat(pow(2.0, 10.0 * (elapsed / duration - 1.0)))
|
||||
}
|
||||
|
||||
internal static let EaseOutExpo = { (elapsed: NSTimeInterval, duration: NSTimeInterval) -> CGFloat in
|
||||
return (elapsed == duration) ? 1.0 : (-CGFloat(pow(2.0, -10.0 * elapsed / duration)) + 1.0)
|
||||
}
|
||||
|
||||
internal static let EaseInOutExpo = { (elapsed: NSTimeInterval, duration: NSTimeInterval) -> CGFloat in
|
||||
if (elapsed == 0)
|
||||
{
|
||||
return 0.0
|
||||
}
|
||||
if (elapsed == duration)
|
||||
{
|
||||
return 1.0
|
||||
}
|
||||
|
||||
var position: NSTimeInterval = elapsed / (duration / 2.0)
|
||||
if (position < 1.0)
|
||||
{
|
||||
return CGFloat( 0.5 * pow(2.0, 10.0 * (position - 1.0)) )
|
||||
}
|
||||
return CGFloat( 0.5 * (-pow(2.0, -10.0 * --position) + 2.0) )
|
||||
}
|
||||
|
||||
internal static let EaseInCirc = { (elapsed: NSTimeInterval, duration: NSTimeInterval) -> CGFloat in
|
||||
var position = CGFloat(elapsed / duration)
|
||||
return -(CGFloat(sqrt(1.0 - position * position)) - 1.0)
|
||||
}
|
||||
|
||||
internal static let EaseOutCirc = { (elapsed: NSTimeInterval, duration: NSTimeInterval) -> CGFloat in
|
||||
var position = CGFloat(elapsed / duration)
|
||||
position--
|
||||
return CGFloat( sqrt(1 - position * position) )
|
||||
}
|
||||
|
||||
internal static let EaseInOutCirc = { (elapsed: NSTimeInterval, duration: NSTimeInterval) -> CGFloat in
|
||||
var position: NSTimeInterval = elapsed / (duration / 2.0)
|
||||
if (position < 1.0)
|
||||
{
|
||||
return CGFloat( -0.5 * (sqrt(1.0 - position * position) - 1.0) )
|
||||
}
|
||||
position -= 2.0
|
||||
return CGFloat( 0.5 * (sqrt(1.0 - position * position) + 1.0) )
|
||||
}
|
||||
|
||||
internal static let EaseInElastic = { (elapsed: NSTimeInterval, duration: NSTimeInterval) -> CGFloat in
|
||||
if (elapsed == 0.0)
|
||||
{
|
||||
return 0.0
|
||||
}
|
||||
|
||||
var position: NSTimeInterval = elapsed / duration
|
||||
if (position == 1.0)
|
||||
{
|
||||
return 1.0
|
||||
}
|
||||
|
||||
var p = duration * 0.3
|
||||
var s = p / (2.0 * M_PI) * asin(1.0)
|
||||
position -= 1.0
|
||||
return CGFloat( -(pow(2.0, 10.0 * position) * sin((position * duration - s) * (2.0 * M_PI) / p)) )
|
||||
}
|
||||
|
||||
internal static let EaseOutElastic = { (elapsed: NSTimeInterval, duration: NSTimeInterval) -> CGFloat in
|
||||
if (elapsed == 0.0)
|
||||
{
|
||||
return 0.0
|
||||
}
|
||||
|
||||
var position: NSTimeInterval = elapsed / duration
|
||||
if (position == 1.0)
|
||||
{
|
||||
return 1.0
|
||||
}
|
||||
|
||||
var p = duration * 0.3
|
||||
var s = p / (2.0 * M_PI) * asin(1.0)
|
||||
return CGFloat( pow(2.0, -10.0 * position) * sin((position * duration - s) * (2.0 * M_PI) / p) + 1.0 )
|
||||
}
|
||||
|
||||
internal static let EaseInOutElastic = { (elapsed: NSTimeInterval, duration: NSTimeInterval) -> CGFloat in
|
||||
if (elapsed == 0.0)
|
||||
{
|
||||
return 0.0
|
||||
}
|
||||
|
||||
var position: NSTimeInterval = elapsed / (duration / 2.0)
|
||||
if (position == 2.0)
|
||||
{
|
||||
return 1.0
|
||||
}
|
||||
|
||||
var p = duration * (0.3 * 1.5)
|
||||
var s = p / (2.0 * M_PI) * asin(1.0)
|
||||
if (position < 1.0)
|
||||
{
|
||||
position -= 1.0
|
||||
return CGFloat( -0.5 * (pow(2.0, 10.0 * position) * sin((position * duration - s) * (2.0 * M_PI) / p)) )
|
||||
}
|
||||
position -= 1.0
|
||||
return CGFloat( pow(2.0, -10.0 * position) * sin((position * duration - s) * (2.0 * M_PI) / p) * 0.5 + 1.0 )
|
||||
}
|
||||
|
||||
internal static let EaseInBack = { (elapsed: NSTimeInterval, duration: NSTimeInterval) -> CGFloat in
|
||||
let s: NSTimeInterval = 1.70158
|
||||
var position: NSTimeInterval = elapsed / duration
|
||||
return CGFloat( position * position * ((s + 1.0) * position - s) )
|
||||
}
|
||||
|
||||
internal static let EaseOutBack = { (elapsed: NSTimeInterval, duration: NSTimeInterval) -> CGFloat in
|
||||
let s: NSTimeInterval = 1.70158
|
||||
var position: NSTimeInterval = elapsed / duration
|
||||
position--
|
||||
return CGFloat( (position * position * ((s + 1.0) * position + s) + 1.0) )
|
||||
}
|
||||
|
||||
internal static let EaseInOutBack = { (elapsed: NSTimeInterval, duration: NSTimeInterval) -> CGFloat in
|
||||
var s: NSTimeInterval = 1.70158
|
||||
var position: NSTimeInterval = elapsed / (duration / 2.0)
|
||||
if (position < 1.0)
|
||||
{
|
||||
s *= 1.525
|
||||
return CGFloat( 0.5 * (position * position * ((s + 1.0) * position - s)) )
|
||||
}
|
||||
s *= 1.525
|
||||
position -= 2.0
|
||||
return CGFloat( 0.5 * (position * position * ((s + 1.0) * position + s) + 2.0) )
|
||||
}
|
||||
|
||||
internal static let EaseInBounce = { (elapsed: NSTimeInterval, duration: NSTimeInterval) -> CGFloat in
|
||||
return 1.0 - EaseOutBounce(duration - elapsed, duration)
|
||||
}
|
||||
|
||||
internal static let EaseOutBounce = { (elapsed: NSTimeInterval, duration: NSTimeInterval) -> CGFloat in
|
||||
var position: NSTimeInterval = elapsed / duration
|
||||
if (position < (1.0 / 2.75))
|
||||
{
|
||||
return CGFloat( 7.5625 * position * position )
|
||||
}
|
||||
else if (position < (2.0 / 2.75))
|
||||
{
|
||||
position -= (1.5 / 2.75)
|
||||
return CGFloat( 7.5625 * position * position + 0.75 )
|
||||
}
|
||||
else if (position < (2.5 / 2.75))
|
||||
{
|
||||
position -= (2.25 / 2.75)
|
||||
return CGFloat( 7.5625 * position * position + 0.9375 )
|
||||
}
|
||||
else
|
||||
{
|
||||
position -= (2.625 / 2.75)
|
||||
return CGFloat( 7.5625 * position * position + 0.984375 )
|
||||
}
|
||||
}
|
||||
|
||||
internal static let EaseInOutBounce = { (elapsed: NSTimeInterval, duration: NSTimeInterval) -> CGFloat in
|
||||
if (elapsed < (duration / 2.0))
|
||||
{
|
||||
return EaseInBounce(elapsed * 2.0, duration) * 0.5
|
||||
}
|
||||
return EaseOutBounce(elapsed * 2.0 - duration, duration) * 0.5 + 0.5
|
||||
}
|
||||
}
|
||||
272
Carthage/Checkouts/Charts/Charts/Classes/Animation/ChartAnimator.swift
vendored
Normal file
272
Carthage/Checkouts/Charts/Charts/Classes/Animation/ChartAnimator.swift
vendored
Normal file
@@ -0,0 +1,272 @@
|
||||
//
|
||||
// ChartAnimator.swift
|
||||
// Charts
|
||||
//
|
||||
// Created by Daniel Cohen Gindi on 3/3/15.
|
||||
//
|
||||
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
|
||||
// A port of MPAndroidChart for iOS
|
||||
// Licensed under Apache License 2.0
|
||||
//
|
||||
// https://github.com/danielgindi/ios-charts
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import UIKit
|
||||
|
||||
@objc
|
||||
public protocol ChartAnimatorDelegate
|
||||
{
|
||||
/// Called when the Animator has stepped.
|
||||
func chartAnimatorUpdated(chartAnimator: ChartAnimator)
|
||||
|
||||
/// Called when the Animator has stopped.
|
||||
func chartAnimatorStopped(chartAnimator: ChartAnimator)
|
||||
}
|
||||
|
||||
public class ChartAnimator: NSObject
|
||||
{
|
||||
public weak var delegate: ChartAnimatorDelegate?
|
||||
public var updateBlock: (() -> Void)?
|
||||
public var stopBlock: (() -> Void)?
|
||||
|
||||
/// the phase that is animated and influences the drawn values on the y-axis
|
||||
public var phaseX: CGFloat = 1.0
|
||||
|
||||
/// the phase that is animated and influences the drawn values on the y-axis
|
||||
public var phaseY: CGFloat = 1.0
|
||||
|
||||
private var _startTime: NSTimeInterval = 0.0
|
||||
private var _displayLink: CADisplayLink!
|
||||
|
||||
private var _xDuration: NSTimeInterval = 0.0
|
||||
private var _yDuration: NSTimeInterval = 0.0
|
||||
|
||||
private var _endTimeX: NSTimeInterval = 0.0
|
||||
private var _endTimeY: NSTimeInterval = 0.0
|
||||
private var _endTime: NSTimeInterval = 0.0
|
||||
|
||||
private var _enabledX: Bool = false
|
||||
private var _enabledY: Bool = false
|
||||
|
||||
private var _easingX: ChartEasingFunctionBlock?
|
||||
private var _easingY: ChartEasingFunctionBlock?
|
||||
|
||||
public override init()
|
||||
{
|
||||
super.init()
|
||||
}
|
||||
|
||||
deinit
|
||||
{
|
||||
stop()
|
||||
}
|
||||
|
||||
public func stop()
|
||||
{
|
||||
if (_displayLink != nil)
|
||||
{
|
||||
_displayLink.removeFromRunLoop(NSRunLoop.mainRunLoop(), forMode: NSRunLoopCommonModes)
|
||||
_displayLink = nil
|
||||
|
||||
_enabledX = false
|
||||
_enabledY = false
|
||||
|
||||
if (delegate != nil)
|
||||
{
|
||||
delegate!.chartAnimatorStopped(self)
|
||||
}
|
||||
if (stopBlock != nil)
|
||||
{
|
||||
stopBlock?()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func updateAnimationPhases(currentTime: NSTimeInterval)
|
||||
{
|
||||
let elapsedTime: NSTimeInterval = currentTime - _startTime
|
||||
if (_enabledX)
|
||||
{
|
||||
let duration: NSTimeInterval = _xDuration
|
||||
var elapsed: NSTimeInterval = elapsedTime
|
||||
if (elapsed > duration)
|
||||
{
|
||||
elapsed = duration
|
||||
}
|
||||
|
||||
if (_easingX != nil)
|
||||
{
|
||||
phaseX = _easingX!(elapsed: elapsed, duration: duration)
|
||||
}
|
||||
else
|
||||
{
|
||||
phaseX = CGFloat(elapsed / duration)
|
||||
}
|
||||
}
|
||||
if (_enabledY)
|
||||
{
|
||||
let duration: NSTimeInterval = _yDuration
|
||||
var elapsed: NSTimeInterval = elapsedTime
|
||||
if (elapsed > duration)
|
||||
{
|
||||
elapsed = duration
|
||||
}
|
||||
|
||||
if (_easingY != nil)
|
||||
{
|
||||
phaseY = _easingY!(elapsed: elapsed, duration: duration)
|
||||
}
|
||||
else
|
||||
{
|
||||
phaseY = CGFloat(elapsed / duration)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@objc private func animationLoop()
|
||||
{
|
||||
let currentTime: NSTimeInterval = CACurrentMediaTime()
|
||||
|
||||
updateAnimationPhases(currentTime)
|
||||
|
||||
if (delegate != nil)
|
||||
{
|
||||
delegate!.chartAnimatorUpdated(self)
|
||||
}
|
||||
if (updateBlock != nil)
|
||||
{
|
||||
updateBlock!()
|
||||
}
|
||||
|
||||
if (currentTime >= _endTime)
|
||||
{
|
||||
stop()
|
||||
}
|
||||
}
|
||||
|
||||
/// Animates the drawing / rendering of the chart on both x- and y-axis with the specified animation time.
|
||||
/// If `animate(...)` is called, no further calling of `invalidate()` is necessary to refresh the chart.
|
||||
/// - parameter xAxisDuration: duration for animating the x axis
|
||||
/// - parameter yAxisDuration: duration for animating the y axis
|
||||
/// - parameter easingX: an easing function for the animation on the x axis
|
||||
/// - parameter easingY: an easing function for the animation on the y axis
|
||||
public func animate(xAxisDuration xAxisDuration: NSTimeInterval, yAxisDuration: NSTimeInterval, easingX: ChartEasingFunctionBlock?, easingY: ChartEasingFunctionBlock?)
|
||||
{
|
||||
stop()
|
||||
|
||||
_displayLink = CADisplayLink(target: self, selector: Selector("animationLoop"))
|
||||
|
||||
_startTime = CACurrentMediaTime()
|
||||
_xDuration = xAxisDuration
|
||||
_yDuration = yAxisDuration
|
||||
_endTimeX = _startTime + xAxisDuration
|
||||
_endTimeY = _startTime + yAxisDuration
|
||||
_endTime = _endTimeX > _endTimeY ? _endTimeX : _endTimeY
|
||||
_enabledX = xAxisDuration > 0.0
|
||||
_enabledY = yAxisDuration > 0.0
|
||||
|
||||
_easingX = easingX
|
||||
_easingY = easingY
|
||||
|
||||
// Take care of the first frame if rendering is already scheduled...
|
||||
updateAnimationPhases(_startTime)
|
||||
|
||||
if (_enabledX || _enabledY)
|
||||
{
|
||||
_displayLink.addToRunLoop(NSRunLoop.mainRunLoop(), forMode: NSRunLoopCommonModes)
|
||||
}
|
||||
}
|
||||
|
||||
/// Animates the drawing / rendering of the chart on both x- and y-axis with the specified animation time.
|
||||
/// If `animate(...)` is called, no further calling of `invalidate()` is necessary to refresh the chart.
|
||||
/// - parameter xAxisDuration: duration for animating the x axis
|
||||
/// - parameter yAxisDuration: duration for animating the y axis
|
||||
/// - parameter easingOptionX: the easing function for the animation on the x axis
|
||||
/// - parameter easingOptionY: the easing function for the animation on the y axis
|
||||
public func animate(xAxisDuration xAxisDuration: NSTimeInterval, yAxisDuration: NSTimeInterval, easingOptionX: ChartEasingOption, easingOptionY: ChartEasingOption)
|
||||
{
|
||||
animate(xAxisDuration: xAxisDuration, yAxisDuration: yAxisDuration, easingX: easingFunctionFromOption(easingOptionX), easingY: easingFunctionFromOption(easingOptionY))
|
||||
}
|
||||
|
||||
/// Animates the drawing / rendering of the chart on both x- and y-axis with the specified animation time.
|
||||
/// If `animate(...)` is called, no further calling of `invalidate()` is necessary to refresh the chart.
|
||||
/// - parameter xAxisDuration: duration for animating the x axis
|
||||
/// - parameter yAxisDuration: duration for animating the y axis
|
||||
/// - parameter easing: an easing function for the animation
|
||||
public func animate(xAxisDuration xAxisDuration: NSTimeInterval, yAxisDuration: NSTimeInterval, easing: ChartEasingFunctionBlock?)
|
||||
{
|
||||
animate(xAxisDuration: xAxisDuration, yAxisDuration: yAxisDuration, easingX: easing, easingY: easing)
|
||||
}
|
||||
|
||||
/// Animates the drawing / rendering of the chart on both x- and y-axis with the specified animation time.
|
||||
/// If `animate(...)` is called, no further calling of `invalidate()` is necessary to refresh the chart.
|
||||
/// - parameter xAxisDuration: duration for animating the x axis
|
||||
/// - parameter yAxisDuration: duration for animating the y axis
|
||||
/// - parameter easingOption: the easing function for the animation
|
||||
public func animate(xAxisDuration xAxisDuration: NSTimeInterval, yAxisDuration: NSTimeInterval, easingOption: ChartEasingOption)
|
||||
{
|
||||
animate(xAxisDuration: xAxisDuration, yAxisDuration: yAxisDuration, easing: easingFunctionFromOption(easingOption))
|
||||
}
|
||||
|
||||
/// Animates the drawing / rendering of the chart on both x- and y-axis with the specified animation time.
|
||||
/// If `animate(...)` is called, no further calling of `invalidate()` is necessary to refresh the chart.
|
||||
/// - parameter xAxisDuration: duration for animating the x axis
|
||||
/// - parameter yAxisDuration: duration for animating the y axis
|
||||
public func animate(xAxisDuration xAxisDuration: NSTimeInterval, yAxisDuration: NSTimeInterval)
|
||||
{
|
||||
animate(xAxisDuration: xAxisDuration, yAxisDuration: yAxisDuration, easingOption: .EaseInOutSine)
|
||||
}
|
||||
|
||||
/// Animates the drawing / rendering of the chart the x-axis with the specified animation time.
|
||||
/// If `animate(...)` is called, no further calling of `invalidate()` is necessary to refresh the chart.
|
||||
/// - parameter xAxisDuration: duration for animating the x axis
|
||||
/// - parameter easing: an easing function for the animation
|
||||
public func animate(xAxisDuration xAxisDuration: NSTimeInterval, easing: ChartEasingFunctionBlock?)
|
||||
{
|
||||
animate(xAxisDuration: xAxisDuration, yAxisDuration: 0.0, easing: easing)
|
||||
}
|
||||
|
||||
/// Animates the drawing / rendering of the chart the x-axis with the specified animation time.
|
||||
/// If `animate(...)` is called, no further calling of `invalidate()` is necessary to refresh the chart.
|
||||
/// - parameter xAxisDuration: duration for animating the x axis
|
||||
/// - parameter easingOption: the easing function for the animation
|
||||
public func animate(xAxisDuration xAxisDuration: NSTimeInterval, easingOption: ChartEasingOption)
|
||||
{
|
||||
animate(xAxisDuration: xAxisDuration, yAxisDuration: 0.0, easing: easingFunctionFromOption(easingOption))
|
||||
}
|
||||
|
||||
/// Animates the drawing / rendering of the chart the x-axis with the specified animation time.
|
||||
/// If `animate(...)` is called, no further calling of `invalidate()` is necessary to refresh the chart.
|
||||
/// - parameter xAxisDuration: duration for animating the x axis
|
||||
public func animate(xAxisDuration xAxisDuration: NSTimeInterval)
|
||||
{
|
||||
animate(xAxisDuration: xAxisDuration, yAxisDuration: 0.0, easingOption: .EaseInOutSine)
|
||||
}
|
||||
|
||||
/// Animates the drawing / rendering of the chart the y-axis with the specified animation time.
|
||||
/// If `animate(...)` is called, no further calling of `invalidate()` is necessary to refresh the chart.
|
||||
/// - parameter yAxisDuration: duration for animating the y axis
|
||||
/// - parameter easing: an easing function for the animation
|
||||
public func animate(yAxisDuration yAxisDuration: NSTimeInterval, easing: ChartEasingFunctionBlock?)
|
||||
{
|
||||
animate(xAxisDuration: 0.0, yAxisDuration: yAxisDuration, easing: easing)
|
||||
}
|
||||
|
||||
/// Animates the drawing / rendering of the chart the y-axis with the specified animation time.
|
||||
/// If `animate(...)` is called, no further calling of `invalidate()` is necessary to refresh the chart.
|
||||
/// - parameter yAxisDuration: duration for animating the y axis
|
||||
/// - parameter easingOption: the easing function for the animation
|
||||
public func animate(yAxisDuration yAxisDuration: NSTimeInterval, easingOption: ChartEasingOption)
|
||||
{
|
||||
animate(xAxisDuration: 0.0, yAxisDuration: yAxisDuration, easing: easingFunctionFromOption(easingOption))
|
||||
}
|
||||
|
||||
/// Animates the drawing / rendering of the chart the y-axis with the specified animation time.
|
||||
/// If `animate(...)` is called, no further calling of `invalidate()` is necessary to refresh the chart.
|
||||
/// - parameter yAxisDuration: duration for animating the y axis
|
||||
public func animate(yAxisDuration yAxisDuration: NSTimeInterval)
|
||||
{
|
||||
animate(xAxisDuration: 0.0, yAxisDuration: yAxisDuration, easingOption: .EaseInOutSine)
|
||||
}
|
||||
}
|
||||
231
Carthage/Checkouts/Charts/Charts/Classes/Charts/BarChartView.swift
vendored
Normal file
231
Carthage/Checkouts/Charts/Charts/Classes/Charts/BarChartView.swift
vendored
Normal file
@@ -0,0 +1,231 @@
|
||||
//
|
||||
// BarChartView.swift
|
||||
// Charts
|
||||
//
|
||||
// Created by Daniel Cohen Gindi on 4/3/15.
|
||||
//
|
||||
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
|
||||
// A port of MPAndroidChart for iOS
|
||||
// Licensed under Apache License 2.0
|
||||
//
|
||||
// https://github.com/danielgindi/ios-charts
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import CoreGraphics
|
||||
|
||||
/// Chart that draws bars.
|
||||
public class BarChartView: BarLineChartViewBase, BarChartRendererDelegate
|
||||
{
|
||||
/// flag that enables or disables the highlighting arrow
|
||||
private var _drawHighlightArrowEnabled = false
|
||||
|
||||
/// if set to true, all values are drawn above their bars, instead of below their top
|
||||
private var _drawValueAboveBarEnabled = true
|
||||
|
||||
/// if set to true, a grey area is darawn behind each bar that indicates the maximum value
|
||||
private var _drawBarShadowEnabled = false
|
||||
|
||||
internal override func initialize()
|
||||
{
|
||||
super.initialize()
|
||||
|
||||
renderer = BarChartRenderer(delegate: self, animator: _animator, viewPortHandler: _viewPortHandler)
|
||||
_xAxisRenderer = ChartXAxisRendererBarChart(viewPortHandler: _viewPortHandler, xAxis: _xAxis, transformer: _leftAxisTransformer, chart: self)
|
||||
|
||||
_highlighter = BarChartHighlighter(chart: self)
|
||||
|
||||
_chartXMin = -0.5
|
||||
}
|
||||
|
||||
internal override func calcMinMax()
|
||||
{
|
||||
super.calcMinMax()
|
||||
|
||||
if (_data === nil)
|
||||
{
|
||||
return
|
||||
}
|
||||
|
||||
let barData = _data as! BarChartData
|
||||
|
||||
// increase deltax by 1 because the bars have a width of 1
|
||||
_deltaX += 0.5
|
||||
|
||||
// extend xDelta to make space for multiple datasets (if ther are one)
|
||||
_deltaX *= CGFloat(_data.dataSetCount)
|
||||
|
||||
let groupSpace = barData.groupSpace
|
||||
_deltaX += CGFloat(barData.xValCount) * groupSpace
|
||||
_chartXMax = Double(_deltaX) - _chartXMin
|
||||
}
|
||||
|
||||
/// - returns: the Highlight object (contains x-index and DataSet index) of the selected value at the given touch point inside the BarChart.
|
||||
public override func getHighlightByTouchPoint(pt: CGPoint) -> ChartHighlight?
|
||||
{
|
||||
if (_dataNotSet || _data === nil)
|
||||
{
|
||||
print("Can't select by touch. No data set.", terminator: "\n")
|
||||
return nil
|
||||
}
|
||||
|
||||
return _highlighter?.getHighlight(x: Double(pt.x), y: Double(pt.y))
|
||||
}
|
||||
|
||||
/// - returns: the bounding box of the specified Entry in the specified DataSet. Returns null if the Entry could not be found in the charts data.
|
||||
public func getBarBounds(e: BarChartDataEntry) -> CGRect!
|
||||
{
|
||||
let set = _data.getDataSetForEntry(e) as! BarChartDataSet!
|
||||
|
||||
if (set === nil)
|
||||
{
|
||||
return nil
|
||||
}
|
||||
|
||||
let barspace = set.barSpace
|
||||
let y = CGFloat(e.value)
|
||||
let x = CGFloat(e.xIndex)
|
||||
|
||||
let barWidth: CGFloat = 0.5
|
||||
|
||||
let spaceHalf = barspace / 2.0
|
||||
let left = x - barWidth + spaceHalf
|
||||
let right = x + barWidth - spaceHalf
|
||||
let top = y >= 0.0 ? y : 0.0
|
||||
let bottom = y <= 0.0 ? y : 0.0
|
||||
|
||||
var bounds = CGRect(x: left, y: top, width: right - left, height: bottom - top)
|
||||
|
||||
getTransformer(set.axisDependency).rectValueToPixel(&bounds)
|
||||
|
||||
return bounds
|
||||
}
|
||||
|
||||
public override var lowestVisibleXIndex: Int
|
||||
{
|
||||
let step = CGFloat(_data.dataSetCount)
|
||||
let div = (step <= 1.0) ? 1.0 : step + (_data as! BarChartData).groupSpace
|
||||
|
||||
var pt = CGPoint(x: _viewPortHandler.contentLeft, y: _viewPortHandler.contentBottom)
|
||||
getTransformer(ChartYAxis.AxisDependency.Left).pixelToValue(&pt)
|
||||
|
||||
return Int((pt.x <= CGFloat(chartXMin)) ? 0.0 : (pt.x / div) + 1.0)
|
||||
}
|
||||
|
||||
public override var highestVisibleXIndex: Int
|
||||
{
|
||||
let step = CGFloat(_data.dataSetCount)
|
||||
let div = (step <= 1.0) ? 1.0 : step + (_data as! BarChartData).groupSpace
|
||||
|
||||
var pt = CGPoint(x: _viewPortHandler.contentRight, y: _viewPortHandler.contentBottom)
|
||||
getTransformer(ChartYAxis.AxisDependency.Left).pixelToValue(&pt)
|
||||
|
||||
return Int((pt.x >= CGFloat(chartXMax)) ? CGFloat(chartXMax) / div : (pt.x / div))
|
||||
}
|
||||
|
||||
// MARK: Accessors
|
||||
|
||||
/// flag that enables or disables the highlighting arrow
|
||||
public var drawHighlightArrowEnabled: Bool
|
||||
{
|
||||
get { return _drawHighlightArrowEnabled; }
|
||||
set
|
||||
{
|
||||
_drawHighlightArrowEnabled = newValue
|
||||
setNeedsDisplay()
|
||||
}
|
||||
}
|
||||
|
||||
/// if set to true, all values are drawn above their bars, instead of below their top
|
||||
public var drawValueAboveBarEnabled: Bool
|
||||
{
|
||||
get { return _drawValueAboveBarEnabled; }
|
||||
set
|
||||
{
|
||||
_drawValueAboveBarEnabled = newValue
|
||||
setNeedsDisplay()
|
||||
}
|
||||
}
|
||||
|
||||
/// if set to true, a grey area is drawn behind each bar that indicates the maximum value
|
||||
public var drawBarShadowEnabled: Bool
|
||||
{
|
||||
get { return _drawBarShadowEnabled; }
|
||||
set
|
||||
{
|
||||
_drawBarShadowEnabled = newValue
|
||||
setNeedsDisplay()
|
||||
}
|
||||
}
|
||||
|
||||
/// - returns: true if drawing the highlighting arrow is enabled, false if not
|
||||
public var isDrawHighlightArrowEnabled: Bool { return drawHighlightArrowEnabled; }
|
||||
|
||||
/// - returns: true if drawing values above bars is enabled, false if not
|
||||
public var isDrawValueAboveBarEnabled: Bool { return drawValueAboveBarEnabled; }
|
||||
|
||||
/// - returns: true if drawing shadows (maxvalue) for each bar is enabled, false if not
|
||||
public var isDrawBarShadowEnabled: Bool { return drawBarShadowEnabled; }
|
||||
|
||||
// MARK: - BarChartRendererDelegate
|
||||
|
||||
public func barChartRendererData(renderer: BarChartRenderer) -> BarChartData!
|
||||
{
|
||||
return _data as! BarChartData!
|
||||
}
|
||||
|
||||
public func barChartRenderer(renderer: BarChartRenderer, transformerForAxis which: ChartYAxis.AxisDependency) -> ChartTransformer!
|
||||
{
|
||||
return getTransformer(which)
|
||||
}
|
||||
|
||||
public func barChartRendererMaxVisibleValueCount(renderer: BarChartRenderer) -> Int
|
||||
{
|
||||
return maxVisibleValueCount
|
||||
}
|
||||
|
||||
public func barChartDefaultRendererValueFormatter(renderer: BarChartRenderer) -> NSNumberFormatter!
|
||||
{
|
||||
return valueFormatter
|
||||
}
|
||||
|
||||
public func barChartRendererChartYMax(renderer: BarChartRenderer) -> Double
|
||||
{
|
||||
return chartYMax
|
||||
}
|
||||
|
||||
public func barChartRendererChartYMin(renderer: BarChartRenderer) -> Double
|
||||
{
|
||||
return chartYMin
|
||||
}
|
||||
|
||||
public func barChartRendererChartXMax(renderer: BarChartRenderer) -> Double
|
||||
{
|
||||
return chartXMax
|
||||
}
|
||||
|
||||
public func barChartRendererChartXMin(renderer: BarChartRenderer) -> Double
|
||||
{
|
||||
return chartXMin
|
||||
}
|
||||
|
||||
public func barChartIsDrawHighlightArrowEnabled(renderer: BarChartRenderer) -> Bool
|
||||
{
|
||||
return drawHighlightArrowEnabled
|
||||
}
|
||||
|
||||
public func barChartIsDrawValueAboveBarEnabled(renderer: BarChartRenderer) -> Bool
|
||||
{
|
||||
return drawValueAboveBarEnabled
|
||||
}
|
||||
|
||||
public func barChartIsDrawBarShadowEnabled(renderer: BarChartRenderer) -> Bool
|
||||
{
|
||||
return drawBarShadowEnabled
|
||||
}
|
||||
|
||||
public func barChartIsInverted(renderer: BarChartRenderer, axis: ChartYAxis.AxisDependency) -> Bool
|
||||
{
|
||||
return getAxis(axis).isInverted
|
||||
}
|
||||
}
|
||||
1739
Carthage/Checkouts/Charts/Charts/Classes/Charts/BarLineChartViewBase.swift
vendored
Normal file
1739
Carthage/Checkouts/Charts/Charts/Classes/Charts/BarLineChartViewBase.swift
vendored
Normal file
File diff suppressed because it is too large
Load Diff
105
Carthage/Checkouts/Charts/Charts/Classes/Charts/BubbleChartView.swift
vendored
Normal file
105
Carthage/Checkouts/Charts/Charts/Classes/Charts/BubbleChartView.swift
vendored
Normal file
@@ -0,0 +1,105 @@
|
||||
//
|
||||
// BubbleChartView.swift
|
||||
// Charts
|
||||
//
|
||||
// Bubble chart implementation:
|
||||
// Copyright 2015 Pierre-Marc Airoldi
|
||||
// Licensed under Apache License 2.0
|
||||
//
|
||||
// https://github.com/danielgindi/ios-charts
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import CoreGraphics
|
||||
|
||||
public class BubbleChartView: BarLineChartViewBase, BubbleChartRendererDelegate
|
||||
{
|
||||
public override func initialize()
|
||||
{
|
||||
super.initialize()
|
||||
|
||||
renderer = BubbleChartRenderer(delegate: self, animator: _animator, viewPortHandler: _viewPortHandler)
|
||||
}
|
||||
|
||||
public override func calcMinMax()
|
||||
{
|
||||
super.calcMinMax()
|
||||
|
||||
if (_deltaX == 0.0 && _data.yValCount > 0)
|
||||
{
|
||||
_deltaX = 1.0
|
||||
}
|
||||
|
||||
_chartXMin = -0.5
|
||||
_chartXMax = Double(_data.xVals.count) - 0.5
|
||||
|
||||
if renderer as? BubbleChartRenderer !== nil,
|
||||
let sets = _data.dataSets as? [BubbleChartDataSet]
|
||||
{
|
||||
for set in sets {
|
||||
|
||||
let xmin = set.xMin
|
||||
let xmax = set.xMax
|
||||
|
||||
if (xmin < _chartXMin)
|
||||
{
|
||||
_chartXMin = xmin
|
||||
}
|
||||
|
||||
if (xmax > _chartXMax)
|
||||
{
|
||||
_chartXMax = xmax
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_deltaX = CGFloat(abs(_chartXMax - _chartXMin))
|
||||
}
|
||||
|
||||
// MARK: - BubbleChartRendererDelegate
|
||||
|
||||
public func bubbleChartRendererData(renderer: BubbleChartRenderer) -> BubbleChartData!
|
||||
{
|
||||
return _data as! BubbleChartData!
|
||||
}
|
||||
|
||||
public func bubbleChartRenderer(renderer: BubbleChartRenderer, transformerForAxis which: ChartYAxis.AxisDependency) -> ChartTransformer!
|
||||
{
|
||||
return getTransformer(which)
|
||||
}
|
||||
|
||||
public func bubbleChartDefaultRendererValueFormatter(renderer: BubbleChartRenderer) -> NSNumberFormatter!
|
||||
{
|
||||
return self._defaultValueFormatter
|
||||
}
|
||||
|
||||
public func bubbleChartRendererChartYMax(renderer: BubbleChartRenderer) -> Double
|
||||
{
|
||||
return self.chartYMax
|
||||
}
|
||||
|
||||
public func bubbleChartRendererChartYMin(renderer: BubbleChartRenderer) -> Double
|
||||
{
|
||||
return self.chartYMin
|
||||
}
|
||||
|
||||
public func bubbleChartRendererChartXMax(renderer: BubbleChartRenderer) -> Double
|
||||
{
|
||||
return self.chartXMax
|
||||
}
|
||||
|
||||
public func bubbleChartRendererChartXMin(renderer: BubbleChartRenderer) -> Double
|
||||
{
|
||||
return self.chartXMin
|
||||
}
|
||||
|
||||
public func bubbleChartRendererMaxVisibleValueCount(renderer: BubbleChartRenderer) -> Int
|
||||
{
|
||||
return self.maxVisibleValueCount
|
||||
}
|
||||
|
||||
public func bubbleChartRendererXValCount(renderer: BubbleChartRenderer) -> Int
|
||||
{
|
||||
return _data.xValCount
|
||||
}
|
||||
}
|
||||
77
Carthage/Checkouts/Charts/Charts/Classes/Charts/CandleStickChartView.swift
vendored
Normal file
77
Carthage/Checkouts/Charts/Charts/Classes/Charts/CandleStickChartView.swift
vendored
Normal file
@@ -0,0 +1,77 @@
|
||||
//
|
||||
// CandleStickChartView.swift
|
||||
// Charts
|
||||
//
|
||||
// Created by Daniel Cohen Gindi on 4/3/15.
|
||||
//
|
||||
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
|
||||
// A port of MPAndroidChart for iOS
|
||||
// Licensed under Apache License 2.0
|
||||
//
|
||||
// https://github.com/danielgindi/ios-charts
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import CoreGraphics
|
||||
|
||||
/// Financial chart type that draws candle-sticks.
|
||||
public class CandleStickChartView: BarLineChartViewBase, CandleStickChartRendererDelegate
|
||||
{
|
||||
internal override func initialize()
|
||||
{
|
||||
super.initialize()
|
||||
|
||||
renderer = CandleStickChartRenderer(delegate: self, animator: _animator, viewPortHandler: _viewPortHandler)
|
||||
_chartXMin = -0.5
|
||||
}
|
||||
|
||||
internal override func calcMinMax()
|
||||
{
|
||||
super.calcMinMax()
|
||||
|
||||
_chartXMax += 0.5
|
||||
_deltaX = CGFloat(abs(_chartXMax - _chartXMin))
|
||||
}
|
||||
|
||||
// MARK: - CandleStickChartRendererDelegate
|
||||
|
||||
public func candleStickChartRendererCandleData(renderer: CandleStickChartRenderer) -> CandleChartData!
|
||||
{
|
||||
return _data as! CandleChartData!
|
||||
}
|
||||
|
||||
public func candleStickChartRenderer(renderer: CandleStickChartRenderer, transformerForAxis which: ChartYAxis.AxisDependency) -> ChartTransformer!
|
||||
{
|
||||
return self.getTransformer(which)
|
||||
}
|
||||
|
||||
public func candleStickChartDefaultRendererValueFormatter(renderer: CandleStickChartRenderer) -> NSNumberFormatter!
|
||||
{
|
||||
return self.valueFormatter
|
||||
}
|
||||
|
||||
public func candleStickChartRendererChartYMax(renderer: CandleStickChartRenderer) -> Double
|
||||
{
|
||||
return self.chartYMax
|
||||
}
|
||||
|
||||
public func candleStickChartRendererChartYMin(renderer: CandleStickChartRenderer) -> Double
|
||||
{
|
||||
return self.chartYMin
|
||||
}
|
||||
|
||||
public func candleStickChartRendererChartXMax(renderer: CandleStickChartRenderer) -> Double
|
||||
{
|
||||
return self.chartXMax
|
||||
}
|
||||
|
||||
public func candleStickChartRendererChartXMin(renderer: CandleStickChartRenderer) -> Double
|
||||
{
|
||||
return self.chartXMin
|
||||
}
|
||||
|
||||
public func candleStickChartRendererMaxVisibleValueCount(renderer: CandleStickChartRenderer) -> Int
|
||||
{
|
||||
return self.maxVisibleValueCount
|
||||
}
|
||||
}
|
||||
945
Carthage/Checkouts/Charts/Charts/Classes/Charts/ChartViewBase.swift
vendored
Executable file
945
Carthage/Checkouts/Charts/Charts/Classes/Charts/ChartViewBase.swift
vendored
Executable file
@@ -0,0 +1,945 @@
|
||||
//
|
||||
// ChartViewBase.swift
|
||||
// Charts
|
||||
//
|
||||
// Created by Daniel Cohen Gindi on 23/2/15.
|
||||
|
||||
//
|
||||
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
|
||||
// A port of MPAndroidChart for iOS
|
||||
// Licensed under Apache License 2.0
|
||||
//
|
||||
// https://github.com/danielgindi/ios-charts
|
||||
//
|
||||
// Based on https://github.com/PhilJay/MPAndroidChart/commit/c42b880
|
||||
|
||||
import Foundation
|
||||
import UIKit
|
||||
|
||||
@objc
|
||||
public protocol ChartViewDelegate
|
||||
{
|
||||
/// Called when a value has been selected inside the chart.
|
||||
/// - parameter entry: The selected Entry.
|
||||
/// - parameter dataSetIndex: The index in the datasets array of the data object the Entrys DataSet is in.
|
||||
optional func chartValueSelected(chartView: ChartViewBase, entry: ChartDataEntry, dataSetIndex: Int, highlight: ChartHighlight)
|
||||
|
||||
// Called when nothing has been selected or an "un-select" has been made.
|
||||
optional func chartValueNothingSelected(chartView: ChartViewBase)
|
||||
|
||||
// Callbacks when the chart is scaled / zoomed via pinch zoom gesture.
|
||||
optional func chartScaled(chartView: ChartViewBase, scaleX: CGFloat, scaleY: CGFloat)
|
||||
|
||||
// Callbacks when the chart is moved / translated via drag gesture.
|
||||
optional func chartTranslated(chartView: ChartViewBase, dX: CGFloat, dY: CGFloat)
|
||||
}
|
||||
|
||||
public class ChartViewBase: UIView, ChartAnimatorDelegate
|
||||
{
|
||||
// MARK: - Properties
|
||||
|
||||
/// custom formatter that is used instead of the auto-formatter if set
|
||||
internal var _valueFormatter = NSNumberFormatter()
|
||||
|
||||
/// the default value formatter
|
||||
internal var _defaultValueFormatter = NSNumberFormatter()
|
||||
|
||||
/// object that holds all data that was originally set for the chart, before it was modified or any filtering algorithms had been applied
|
||||
internal var _data: ChartData!
|
||||
|
||||
/// If set to true, chart continues to scroll after touch up
|
||||
public var dragDecelerationEnabled = true
|
||||
|
||||
/// Deceleration friction coefficient in [0 ; 1] interval, higher values indicate that speed will decrease slowly, for example if it set to 0, it will stop immediately.
|
||||
/// 1 is an invalid value, and will be converted to 0.999 automatically.
|
||||
private var _dragDecelerationFrictionCoef: CGFloat = 0.9
|
||||
|
||||
/// font object used for drawing the description text in the bottom right corner of the chart
|
||||
public var descriptionFont: UIFont? = UIFont(name: "HelveticaNeue", size: 9.0)
|
||||
public var descriptionTextColor: UIColor! = UIColor.blackColor()
|
||||
|
||||
/// font object for drawing the information text when there are no values in the chart
|
||||
public var infoFont: UIFont! = UIFont(name: "HelveticaNeue", size: 12.0)
|
||||
public var infoTextColor: UIColor! = UIColor(red: 247.0/255.0, green: 189.0/255.0, blue: 51.0/255.0, alpha: 1.0) // orange
|
||||
|
||||
/// description text that appears in the bottom right corner of the chart
|
||||
public var descriptionText = "Description"
|
||||
|
||||
/// flag that indicates if the chart has been fed with data yet
|
||||
internal var _dataNotSet = true
|
||||
|
||||
/// if true, units are drawn next to the values in the chart
|
||||
internal var _drawUnitInChart = false
|
||||
|
||||
/// the number of x-values the chart displays
|
||||
internal var _deltaX = CGFloat(1.0)
|
||||
|
||||
internal var _chartXMin = Double(0.0)
|
||||
internal var _chartXMax = Double(0.0)
|
||||
|
||||
/// the legend object containing all data associated with the legend
|
||||
internal var _legend: ChartLegend!
|
||||
|
||||
/// delegate to receive chart events
|
||||
public weak var delegate: ChartViewDelegate?
|
||||
|
||||
/// text that is displayed when the chart is empty
|
||||
public var noDataText = "No chart data available."
|
||||
|
||||
/// text that is displayed when the chart is empty that describes why the chart is empty
|
||||
public var noDataTextDescription: String?
|
||||
|
||||
internal var _legendRenderer: ChartLegendRenderer!
|
||||
|
||||
/// object responsible for rendering the data
|
||||
public var renderer: ChartDataRendererBase?
|
||||
|
||||
internal var _highlighter: ChartHighlighter?
|
||||
|
||||
/// object that manages the bounds and drawing constraints of the chart
|
||||
internal var _viewPortHandler: ChartViewPortHandler!
|
||||
|
||||
/// object responsible for animations
|
||||
internal var _animator: ChartAnimator!
|
||||
|
||||
/// flag that indicates if offsets calculation has already been done or not
|
||||
private var _offsetsCalculated = false
|
||||
|
||||
/// array of Highlight objects that reference the highlighted slices in the chart
|
||||
internal var _indicesToHightlight = [ChartHighlight]()
|
||||
|
||||
/// if set to true, the marker is drawn when a value is clicked
|
||||
public var drawMarkers = true
|
||||
|
||||
/// the view that represents the marker
|
||||
public var marker: ChartMarker?
|
||||
|
||||
private var _interceptTouchEvents = false
|
||||
|
||||
/// An extra offset to be appended to the viewport's top
|
||||
public var extraTopOffset: CGFloat = 0.0
|
||||
|
||||
/// An extra offset to be appended to the viewport's right
|
||||
public var extraRightOffset: CGFloat = 0.0
|
||||
|
||||
/// An extra offset to be appended to the viewport's bottom
|
||||
public var extraBottomOffset: CGFloat = 0.0
|
||||
|
||||
/// An extra offset to be appended to the viewport's left
|
||||
public var extraLeftOffset: CGFloat = 0.0
|
||||
|
||||
public func setExtraOffsets(left left: CGFloat, top: CGFloat, right: CGFloat, bottom: CGFloat)
|
||||
{
|
||||
extraLeftOffset = left
|
||||
extraTopOffset = top
|
||||
extraRightOffset = right
|
||||
extraBottomOffset = bottom
|
||||
}
|
||||
|
||||
// MARK: - Initializers
|
||||
|
||||
public override init(frame: CGRect)
|
||||
{
|
||||
super.init(frame: frame)
|
||||
self.backgroundColor = UIColor.clearColor()
|
||||
initialize()
|
||||
}
|
||||
|
||||
public required init?(coder aDecoder: NSCoder)
|
||||
{
|
||||
super.init(coder: aDecoder)
|
||||
initialize()
|
||||
}
|
||||
|
||||
deinit
|
||||
{
|
||||
self.removeObserver(self, forKeyPath: "bounds")
|
||||
self.removeObserver(self, forKeyPath: "frame")
|
||||
}
|
||||
|
||||
internal func initialize()
|
||||
{
|
||||
_animator = ChartAnimator()
|
||||
_animator.delegate = self
|
||||
|
||||
_viewPortHandler = ChartViewPortHandler()
|
||||
_viewPortHandler.setChartDimens(width: bounds.size.width, height: bounds.size.height)
|
||||
|
||||
_legend = ChartLegend()
|
||||
_legendRenderer = ChartLegendRenderer(viewPortHandler: _viewPortHandler, legend: _legend)
|
||||
|
||||
_defaultValueFormatter.minimumIntegerDigits = 1
|
||||
_defaultValueFormatter.maximumFractionDigits = 1
|
||||
_defaultValueFormatter.minimumFractionDigits = 1
|
||||
_defaultValueFormatter.usesGroupingSeparator = true
|
||||
|
||||
_valueFormatter = _defaultValueFormatter.copy() as! NSNumberFormatter
|
||||
|
||||
self.addObserver(self, forKeyPath: "bounds", options: .New, context: nil)
|
||||
self.addObserver(self, forKeyPath: "frame", options: .New, context: nil)
|
||||
}
|
||||
|
||||
// MARK: - ChartViewBase
|
||||
|
||||
/// The data for the chart
|
||||
public var data: ChartData?
|
||||
{
|
||||
get
|
||||
{
|
||||
return _data
|
||||
}
|
||||
set
|
||||
{
|
||||
if newValue == nil
|
||||
{
|
||||
print("Charts: data argument is nil on setData()", terminator: "\n")
|
||||
return
|
||||
}
|
||||
|
||||
_dataNotSet = false
|
||||
_offsetsCalculated = false
|
||||
_data = newValue
|
||||
|
||||
// calculate how many digits are needed
|
||||
calculateFormatter(min: _data.getYMin(), max: _data.getYMax())
|
||||
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
}
|
||||
|
||||
/// Clears the chart from all data (sets it to null) and refreshes it (by calling setNeedsDisplay()).
|
||||
public func clear()
|
||||
{
|
||||
_data = nil
|
||||
_dataNotSet = true
|
||||
_indicesToHightlight.removeAll()
|
||||
setNeedsDisplay()
|
||||
}
|
||||
|
||||
/// Removes all DataSets (and thereby Entries) from the chart. Does not remove the x-values. Also refreshes the chart by calling setNeedsDisplay().
|
||||
public func clearValues()
|
||||
{
|
||||
if (_data !== nil)
|
||||
{
|
||||
_data.clearValues()
|
||||
}
|
||||
setNeedsDisplay()
|
||||
}
|
||||
|
||||
/// - returns: true if the chart is empty (meaning it's data object is either null or contains no entries).
|
||||
public func isEmpty() -> Bool
|
||||
{
|
||||
if (_data == nil)
|
||||
{
|
||||
return true
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
if (_data.yValCount <= 0)
|
||||
{
|
||||
return true
|
||||
}
|
||||
else
|
||||
{
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Lets the chart know its underlying data has changed and should perform all necessary recalculations.
|
||||
/// It is crucial that this method is called everytime data is changed dynamically. Not calling this method can lead to crashes or unexpected behaviour.
|
||||
public func notifyDataSetChanged()
|
||||
{
|
||||
fatalError("notifyDataSetChanged() cannot be called on ChartViewBase")
|
||||
}
|
||||
|
||||
/// calculates the offsets of the chart to the border depending on the position of an eventual legend or depending on the length of the y-axis and x-axis labels and their position
|
||||
internal func calculateOffsets()
|
||||
{
|
||||
fatalError("calculateOffsets() cannot be called on ChartViewBase")
|
||||
}
|
||||
|
||||
/// calcualtes the y-min and y-max value and the y-delta and x-delta value
|
||||
internal func calcMinMax()
|
||||
{
|
||||
fatalError("calcMinMax() cannot be called on ChartViewBase")
|
||||
}
|
||||
|
||||
/// calculates the required number of digits for the values that might be drawn in the chart (if enabled), and creates the default value formatter
|
||||
internal func calculateFormatter(min min: Double, max: Double)
|
||||
{
|
||||
// check if a custom formatter is set or not
|
||||
var reference = Double(0.0)
|
||||
|
||||
if (_data == nil || _data.xValCount < 2)
|
||||
{
|
||||
let absMin = fabs(min)
|
||||
let absMax = fabs(max)
|
||||
reference = absMin > absMax ? absMin : absMax
|
||||
}
|
||||
else
|
||||
{
|
||||
reference = fabs(max - min)
|
||||
}
|
||||
|
||||
let digits = ChartUtils.decimals(reference)
|
||||
|
||||
_defaultValueFormatter.maximumFractionDigits = digits
|
||||
_defaultValueFormatter.minimumFractionDigits = digits
|
||||
}
|
||||
|
||||
public override func drawRect(rect: CGRect)
|
||||
{
|
||||
let context = UIGraphicsGetCurrentContext()
|
||||
let frame = self.bounds
|
||||
|
||||
if (_dataNotSet || _data === nil || _data.yValCount == 0)
|
||||
{ // check if there is data
|
||||
|
||||
CGContextSaveGState(context)
|
||||
|
||||
// if no data, inform the user
|
||||
|
||||
ChartUtils.drawText(context: context, text: noDataText, point: CGPoint(x: frame.width / 2.0, y: frame.height / 2.0), align: .Center, attributes: [NSFontAttributeName: infoFont, NSForegroundColorAttributeName: infoTextColor])
|
||||
|
||||
if (noDataTextDescription != nil && (noDataTextDescription!).characters.count > 0)
|
||||
{
|
||||
let textOffset = -infoFont.lineHeight / 2.0
|
||||
|
||||
ChartUtils.drawText(context: context, text: noDataTextDescription!, point: CGPoint(x: frame.width / 2.0, y: frame.height / 2.0 + textOffset), align: .Center, attributes: [NSFontAttributeName: infoFont, NSForegroundColorAttributeName: infoTextColor])
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if (!_offsetsCalculated)
|
||||
{
|
||||
calculateOffsets()
|
||||
_offsetsCalculated = true
|
||||
}
|
||||
}
|
||||
|
||||
/// draws the description text in the bottom right corner of the chart
|
||||
internal func drawDescription(context context: CGContext?)
|
||||
{
|
||||
if (descriptionText.lengthOfBytesUsingEncoding(NSUTF16StringEncoding) == 0)
|
||||
{
|
||||
return
|
||||
}
|
||||
|
||||
let frame = self.bounds
|
||||
|
||||
var attrs = [String : AnyObject]()
|
||||
|
||||
var font = descriptionFont
|
||||
|
||||
if (font == nil)
|
||||
{
|
||||
#if os(tvOS)
|
||||
// 23 is the smallest recommened font size on the TV
|
||||
font = UIFont.systemFontOfSize(23, weight: UIFontWeightMedium)
|
||||
#else
|
||||
font = UIFont.systemFontOfSize(UIFont.systemFontSize())
|
||||
#endif
|
||||
}
|
||||
|
||||
attrs[NSFontAttributeName] = font
|
||||
attrs[NSForegroundColorAttributeName] = descriptionTextColor
|
||||
|
||||
ChartUtils.drawText(context: context, text: descriptionText, point: CGPoint(x: frame.width - _viewPortHandler.offsetRight - 10.0, y: frame.height - _viewPortHandler.offsetBottom - 10.0 - font!.lineHeight), align: .Right, attributes: attrs)
|
||||
}
|
||||
|
||||
// MARK: - Highlighting
|
||||
|
||||
/// - returns: the array of currently highlighted values. This might an empty if nothing is highlighted.
|
||||
public var highlighted: [ChartHighlight]
|
||||
{
|
||||
return _indicesToHightlight
|
||||
}
|
||||
|
||||
/// Checks if the highlight array is null, has a length of zero or if the first object is null.
|
||||
/// - returns: true if there are values to highlight, false if there are no values to highlight.
|
||||
public func valuesToHighlight() -> Bool
|
||||
{
|
||||
return _indicesToHightlight.count > 0
|
||||
}
|
||||
|
||||
/// Highlights the values at the given indices in the given DataSets. Provide
|
||||
/// null or an empty array to undo all highlighting.
|
||||
/// This should be used to programmatically highlight values.
|
||||
/// This DOES NOT generate a callback to the delegate.
|
||||
public func highlightValues(highs: [ChartHighlight]?)
|
||||
{
|
||||
// set the indices to highlight
|
||||
_indicesToHightlight = highs ?? [ChartHighlight]()
|
||||
|
||||
if (_indicesToHightlight.isEmpty)
|
||||
{
|
||||
self.lastHighlighted = nil
|
||||
}
|
||||
|
||||
// redraw the chart
|
||||
setNeedsDisplay()
|
||||
}
|
||||
|
||||
/// Highlights the value at the given x-index in the given DataSet.
|
||||
/// Provide -1 as the x-index to undo all highlighting.
|
||||
public func highlightValue(xIndex xIndex: Int, dataSetIndex: Int, callDelegate: Bool)
|
||||
{
|
||||
if (xIndex < 0 || dataSetIndex < 0 || xIndex >= _data.xValCount || dataSetIndex >= _data.dataSetCount)
|
||||
{
|
||||
highlightValue(highlight: nil, callDelegate: callDelegate)
|
||||
}
|
||||
else
|
||||
{
|
||||
highlightValue(highlight: ChartHighlight(xIndex: xIndex, dataSetIndex: dataSetIndex), callDelegate: callDelegate)
|
||||
}
|
||||
}
|
||||
|
||||
/// Highlights the value selected by touch gesture.
|
||||
public func highlightValue(highlight highlight: ChartHighlight?, callDelegate: Bool)
|
||||
{
|
||||
var entry: ChartDataEntry?
|
||||
var h = highlight
|
||||
|
||||
if (h == nil)
|
||||
{
|
||||
_indicesToHightlight.removeAll(keepCapacity: false)
|
||||
}
|
||||
else
|
||||
{
|
||||
// set the indices to highlight
|
||||
entry = _data.getEntryForHighlight(h!)
|
||||
if (entry === nil || entry!.xIndex != h?.xIndex)
|
||||
{
|
||||
h = nil
|
||||
entry = nil
|
||||
_indicesToHightlight.removeAll(keepCapacity: false)
|
||||
}
|
||||
else
|
||||
{
|
||||
_indicesToHightlight = [h!]
|
||||
}
|
||||
}
|
||||
|
||||
// redraw the chart
|
||||
setNeedsDisplay()
|
||||
|
||||
if (callDelegate && delegate != nil)
|
||||
{
|
||||
if (h == nil)
|
||||
{
|
||||
delegate!.chartValueNothingSelected?(self)
|
||||
}
|
||||
else
|
||||
{
|
||||
// notify the listener
|
||||
delegate!.chartValueSelected?(self, entry: entry!, dataSetIndex: h!.dataSetIndex, highlight: h!)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The last value that was highlighted via touch.
|
||||
public var lastHighlighted: ChartHighlight?
|
||||
|
||||
// MARK: - Markers
|
||||
|
||||
/// draws all MarkerViews on the highlighted positions
|
||||
internal func drawMarkers(context context: CGContext?)
|
||||
{
|
||||
// if there is no marker view or drawing marker is disabled
|
||||
if (marker === nil || !drawMarkers || !valuesToHighlight())
|
||||
{
|
||||
return
|
||||
}
|
||||
|
||||
for (var i = 0, count = _indicesToHightlight.count; i < count; i++)
|
||||
{
|
||||
let highlight = _indicesToHightlight[i]
|
||||
let xIndex = highlight.xIndex
|
||||
|
||||
if (xIndex <= Int(_deltaX) && xIndex <= Int(_deltaX * _animator.phaseX))
|
||||
{
|
||||
let e = _data.getEntryForHighlight(highlight)
|
||||
if (e === nil || e!.xIndex != highlight.xIndex)
|
||||
{
|
||||
continue
|
||||
}
|
||||
|
||||
let pos = getMarkerPosition(entry: e!, highlight: highlight)
|
||||
|
||||
// check bounds
|
||||
if (!_viewPortHandler.isInBounds(x: pos.x, y: pos.y))
|
||||
{
|
||||
continue
|
||||
}
|
||||
|
||||
// callbacks to update the content
|
||||
marker!.refreshContent(entry: e!, highlight: highlight)
|
||||
|
||||
let markerSize = marker!.size
|
||||
if (pos.y - markerSize.height <= 0.0)
|
||||
{
|
||||
let y = markerSize.height - pos.y
|
||||
marker!.draw(context: context, point: CGPoint(x: pos.x, y: pos.y + y))
|
||||
}
|
||||
else
|
||||
{
|
||||
marker!.draw(context: context, point: pos)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// - returns: the actual position in pixels of the MarkerView for the given Entry in the given DataSet.
|
||||
public func getMarkerPosition(entry entry: ChartDataEntry, highlight: ChartHighlight) -> CGPoint
|
||||
{
|
||||
fatalError("getMarkerPosition() cannot be called on ChartViewBase")
|
||||
}
|
||||
|
||||
// MARK: - Animation
|
||||
|
||||
/// - returns: the animator responsible for animating chart values.
|
||||
public var animator: ChartAnimator!
|
||||
{
|
||||
return _animator
|
||||
}
|
||||
|
||||
/// Animates the drawing / rendering of the chart on both x- and y-axis with the specified animation time.
|
||||
/// If `animate(...)` is called, no further calling of `invalidate()` is necessary to refresh the chart.
|
||||
/// - parameter xAxisDuration: duration for animating the x axis
|
||||
/// - parameter yAxisDuration: duration for animating the y axis
|
||||
/// - parameter easingX: an easing function for the animation on the x axis
|
||||
/// - parameter easingY: an easing function for the animation on the y axis
|
||||
public func animate(xAxisDuration xAxisDuration: NSTimeInterval, yAxisDuration: NSTimeInterval, easingX: ChartEasingFunctionBlock?, easingY: ChartEasingFunctionBlock?)
|
||||
{
|
||||
_animator.animate(xAxisDuration: xAxisDuration, yAxisDuration: yAxisDuration, easingX: easingX, easingY: easingY)
|
||||
}
|
||||
|
||||
/// Animates the drawing / rendering of the chart on both x- and y-axis with the specified animation time.
|
||||
/// If `animate(...)` is called, no further calling of `invalidate()` is necessary to refresh the chart.
|
||||
/// - parameter xAxisDuration: duration for animating the x axis
|
||||
/// - parameter yAxisDuration: duration for animating the y axis
|
||||
/// - parameter easingOptionX: the easing function for the animation on the x axis
|
||||
/// - parameter easingOptionY: the easing function for the animation on the y axis
|
||||
public func animate(xAxisDuration xAxisDuration: NSTimeInterval, yAxisDuration: NSTimeInterval, easingOptionX: ChartEasingOption, easingOptionY: ChartEasingOption)
|
||||
{
|
||||
_animator.animate(xAxisDuration: xAxisDuration, yAxisDuration: yAxisDuration, easingOptionX: easingOptionX, easingOptionY: easingOptionY)
|
||||
}
|
||||
|
||||
/// Animates the drawing / rendering of the chart on both x- and y-axis with the specified animation time.
|
||||
/// If `animate(...)` is called, no further calling of `invalidate()` is necessary to refresh the chart.
|
||||
/// - parameter xAxisDuration: duration for animating the x axis
|
||||
/// - parameter yAxisDuration: duration for animating the y axis
|
||||
/// - parameter easing: an easing function for the animation
|
||||
public func animate(xAxisDuration xAxisDuration: NSTimeInterval, yAxisDuration: NSTimeInterval, easing: ChartEasingFunctionBlock?)
|
||||
{
|
||||
_animator.animate(xAxisDuration: xAxisDuration, yAxisDuration: yAxisDuration, easing: easing)
|
||||
}
|
||||
|
||||
/// Animates the drawing / rendering of the chart on both x- and y-axis with the specified animation time.
|
||||
/// If `animate(...)` is called, no further calling of `invalidate()` is necessary to refresh the chart.
|
||||
/// - parameter xAxisDuration: duration for animating the x axis
|
||||
/// - parameter yAxisDuration: duration for animating the y axis
|
||||
/// - parameter easingOption: the easing function for the animation
|
||||
public func animate(xAxisDuration xAxisDuration: NSTimeInterval, yAxisDuration: NSTimeInterval, easingOption: ChartEasingOption)
|
||||
{
|
||||
_animator.animate(xAxisDuration: xAxisDuration, yAxisDuration: yAxisDuration, easingOption: easingOption)
|
||||
}
|
||||
|
||||
/// Animates the drawing / rendering of the chart on both x- and y-axis with the specified animation time.
|
||||
/// If `animate(...)` is called, no further calling of `invalidate()` is necessary to refresh the chart.
|
||||
/// - parameter xAxisDuration: duration for animating the x axis
|
||||
/// - parameter yAxisDuration: duration for animating the y axis
|
||||
public func animate(xAxisDuration xAxisDuration: NSTimeInterval, yAxisDuration: NSTimeInterval)
|
||||
{
|
||||
_animator.animate(xAxisDuration: xAxisDuration, yAxisDuration: yAxisDuration)
|
||||
}
|
||||
|
||||
/// Animates the drawing / rendering of the chart the x-axis with the specified animation time.
|
||||
/// If `animate(...)` is called, no further calling of `invalidate()` is necessary to refresh the chart.
|
||||
/// - parameter xAxisDuration: duration for animating the x axis
|
||||
/// - parameter easing: an easing function for the animation
|
||||
public func animate(xAxisDuration xAxisDuration: NSTimeInterval, easing: ChartEasingFunctionBlock?)
|
||||
{
|
||||
_animator.animate(xAxisDuration: xAxisDuration, easing: easing)
|
||||
}
|
||||
|
||||
/// Animates the drawing / rendering of the chart the x-axis with the specified animation time.
|
||||
/// If `animate(...)` is called, no further calling of `invalidate()` is necessary to refresh the chart.
|
||||
/// - parameter xAxisDuration: duration for animating the x axis
|
||||
/// - parameter easingOption: the easing function for the animation
|
||||
public func animate(xAxisDuration xAxisDuration: NSTimeInterval, easingOption: ChartEasingOption)
|
||||
{
|
||||
_animator.animate(xAxisDuration: xAxisDuration, easingOption: easingOption)
|
||||
}
|
||||
|
||||
/// Animates the drawing / rendering of the chart the x-axis with the specified animation time.
|
||||
/// If `animate(...)` is called, no further calling of `invalidate()` is necessary to refresh the chart.
|
||||
/// - parameter xAxisDuration: duration for animating the x axis
|
||||
public func animate(xAxisDuration xAxisDuration: NSTimeInterval)
|
||||
{
|
||||
_animator.animate(xAxisDuration: xAxisDuration)
|
||||
}
|
||||
|
||||
/// Animates the drawing / rendering of the chart the y-axis with the specified animation time.
|
||||
/// If `animate(...)` is called, no further calling of `invalidate()` is necessary to refresh the chart.
|
||||
/// - parameter yAxisDuration: duration for animating the y axis
|
||||
/// - parameter easing: an easing function for the animation
|
||||
public func animate(yAxisDuration yAxisDuration: NSTimeInterval, easing: ChartEasingFunctionBlock?)
|
||||
{
|
||||
_animator.animate(yAxisDuration: yAxisDuration, easing: easing)
|
||||
}
|
||||
|
||||
/// Animates the drawing / rendering of the chart the y-axis with the specified animation time.
|
||||
/// If `animate(...)` is called, no further calling of `invalidate()` is necessary to refresh the chart.
|
||||
/// - parameter yAxisDuration: duration for animating the y axis
|
||||
/// - parameter easingOption: the easing function for the animation
|
||||
public func animate(yAxisDuration yAxisDuration: NSTimeInterval, easingOption: ChartEasingOption)
|
||||
{
|
||||
_animator.animate(yAxisDuration: yAxisDuration, easingOption: easingOption)
|
||||
}
|
||||
|
||||
/// Animates the drawing / rendering of the chart the y-axis with the specified animation time.
|
||||
/// If `animate(...)` is called, no further calling of `invalidate()` is necessary to refresh the chart.
|
||||
/// - parameter yAxisDuration: duration for animating the y axis
|
||||
public func animate(yAxisDuration yAxisDuration: NSTimeInterval)
|
||||
{
|
||||
_animator.animate(yAxisDuration: yAxisDuration)
|
||||
}
|
||||
|
||||
// MARK: - Accessors
|
||||
|
||||
/// - returns: the current y-max value across all DataSets
|
||||
public var chartYMax: Double
|
||||
{
|
||||
return _data.yMax
|
||||
}
|
||||
|
||||
/// - returns: the current y-min value across all DataSets
|
||||
public var chartYMin: Double
|
||||
{
|
||||
return _data.yMin
|
||||
}
|
||||
|
||||
public var chartXMax: Double
|
||||
{
|
||||
return _chartXMax
|
||||
}
|
||||
|
||||
public var chartXMin: Double
|
||||
{
|
||||
return _chartXMin
|
||||
}
|
||||
|
||||
/// - returns: the total number of (y) values the chart holds (across all DataSets)
|
||||
public var getValueCount: Int
|
||||
{
|
||||
return _data.yValCount
|
||||
}
|
||||
|
||||
/// *Note: (Equivalent of getCenter() in MPAndroidChart, as center is already a standard in iOS that returns the center point relative to superview, and MPAndroidChart returns relative to self)*
|
||||
/// - returns: the center point of the chart (the whole View) in pixels.
|
||||
public var midPoint: CGPoint
|
||||
{
|
||||
let bounds = self.bounds
|
||||
return CGPoint(x: bounds.origin.x + bounds.size.width / 2.0, y: bounds.origin.y + bounds.size.height / 2.0)
|
||||
}
|
||||
|
||||
/// - returns: the center of the chart taking offsets under consideration. (returns the center of the content rectangle)
|
||||
public var centerOffsets: CGPoint
|
||||
{
|
||||
return _viewPortHandler.contentCenter
|
||||
}
|
||||
|
||||
/// - returns: the Legend object of the chart. This method can be used to get an instance of the legend in order to customize the automatically generated Legend.
|
||||
public var legend: ChartLegend
|
||||
{
|
||||
return _legend
|
||||
}
|
||||
|
||||
/// - returns: the renderer object responsible for rendering / drawing the Legend.
|
||||
public var legendRenderer: ChartLegendRenderer!
|
||||
{
|
||||
return _legendRenderer
|
||||
}
|
||||
|
||||
/// - returns: the rectangle that defines the borders of the chart-value surface (into which the actual values are drawn).
|
||||
public var contentRect: CGRect
|
||||
{
|
||||
return _viewPortHandler.contentRect
|
||||
}
|
||||
|
||||
/// Sets the formatter to be used for drawing the values inside the chart.
|
||||
/// If no formatter is set, the chart will automatically determine a reasonable
|
||||
/// formatting (concerning decimals) for all the values that are drawn inside
|
||||
/// the chart. Set this to nil to re-enable auto formatting.
|
||||
public var valueFormatter: NSNumberFormatter!
|
||||
{
|
||||
get
|
||||
{
|
||||
return _valueFormatter
|
||||
}
|
||||
set
|
||||
{
|
||||
if (newValue === nil)
|
||||
{
|
||||
_valueFormatter = _defaultValueFormatter.copy() as! NSNumberFormatter
|
||||
}
|
||||
else
|
||||
{
|
||||
_valueFormatter = newValue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// - returns: the x-value at the given index
|
||||
public func getXValue(index: Int) -> String!
|
||||
{
|
||||
if (_data == nil || _data.xValCount <= index)
|
||||
{
|
||||
return nil
|
||||
}
|
||||
else
|
||||
{
|
||||
return _data.xVals[index]
|
||||
}
|
||||
}
|
||||
|
||||
/// Get all Entry objects at the given index across all DataSets.
|
||||
public func getEntriesAtIndex(xIndex: Int) -> [ChartDataEntry]
|
||||
{
|
||||
var vals = [ChartDataEntry]()
|
||||
|
||||
for (var i = 0, count = _data.dataSetCount; i < count; i++)
|
||||
{
|
||||
let set = _data.getDataSetByIndex(i)
|
||||
let e = set.entryForXIndex(xIndex)
|
||||
if (e !== nil)
|
||||
{
|
||||
vals.append(e!)
|
||||
}
|
||||
}
|
||||
|
||||
return vals
|
||||
}
|
||||
|
||||
/// - returns: the percentage the given value has of the total y-value sum
|
||||
public func percentOfTotal(val: Double) -> Double
|
||||
{
|
||||
return val / _data.yValueSum * 100.0
|
||||
}
|
||||
|
||||
/// - returns: the ViewPortHandler of the chart that is responsible for the
|
||||
/// content area of the chart and its offsets and dimensions.
|
||||
public var viewPortHandler: ChartViewPortHandler!
|
||||
{
|
||||
return _viewPortHandler
|
||||
}
|
||||
|
||||
/// - returns: the bitmap that represents the chart.
|
||||
public func getChartImage(transparent transparent: Bool) -> UIImage
|
||||
{
|
||||
UIGraphicsBeginImageContextWithOptions(bounds.size, opaque || !transparent, UIScreen.mainScreen().scale)
|
||||
|
||||
let context = UIGraphicsGetCurrentContext()
|
||||
let rect = CGRect(origin: CGPoint(x: 0, y: 0), size: bounds.size)
|
||||
|
||||
if (opaque || !transparent)
|
||||
{
|
||||
// Background color may be partially transparent, we must fill with white if we want to output an opaque image
|
||||
CGContextSetFillColorWithColor(context, UIColor.whiteColor().CGColor)
|
||||
CGContextFillRect(context, rect)
|
||||
|
||||
if (self.backgroundColor !== nil)
|
||||
{
|
||||
CGContextSetFillColorWithColor(context, self.backgroundColor?.CGColor)
|
||||
CGContextFillRect(context, rect)
|
||||
}
|
||||
}
|
||||
|
||||
if let context = context
|
||||
{
|
||||
layer.renderInContext(context)
|
||||
}
|
||||
|
||||
let image = UIGraphicsGetImageFromCurrentImageContext()
|
||||
|
||||
UIGraphicsEndImageContext()
|
||||
|
||||
return image
|
||||
}
|
||||
|
||||
public enum ImageFormat
|
||||
{
|
||||
case JPEG
|
||||
case PNG
|
||||
}
|
||||
|
||||
/// Saves the current chart state with the given name to the given path on
|
||||
/// the sdcard leaving the path empty "" will put the saved file directly on
|
||||
/// the SD card chart is saved as a PNG image, example:
|
||||
/// saveToPath("myfilename", "foldername1/foldername2")
|
||||
///
|
||||
/// - parameter filePath: path to the image to save
|
||||
/// - parameter format: the format to save
|
||||
/// - parameter compressionQuality: compression quality for lossless formats (JPEG)
|
||||
///
|
||||
/// - returns: true if the image was saved successfully
|
||||
public func saveToPath(path: String, format: ImageFormat, compressionQuality: Double) -> Bool
|
||||
{
|
||||
let image = getChartImage(transparent: format != .JPEG)
|
||||
|
||||
var imageData: NSData!
|
||||
switch (format)
|
||||
{
|
||||
case .PNG:
|
||||
imageData = UIImagePNGRepresentation(image)
|
||||
break
|
||||
|
||||
case .JPEG:
|
||||
imageData = UIImageJPEGRepresentation(image, CGFloat(compressionQuality))
|
||||
break
|
||||
}
|
||||
|
||||
return imageData.writeToFile(path, atomically: true)
|
||||
}
|
||||
|
||||
#if !os(tvOS)
|
||||
/// Saves the current state of the chart to the camera roll
|
||||
public func saveToCameraRoll()
|
||||
{
|
||||
UIImageWriteToSavedPhotosAlbum(getChartImage(transparent: false), nil, nil, nil)
|
||||
}
|
||||
#endif
|
||||
|
||||
internal typealias VoidClosureType = () -> ()
|
||||
internal var _sizeChangeEventActions = [VoidClosureType]()
|
||||
|
||||
public override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>)
|
||||
{
|
||||
if (keyPath == "bounds" || keyPath == "frame")
|
||||
{
|
||||
let bounds = self.bounds
|
||||
|
||||
if (_viewPortHandler !== nil &&
|
||||
(bounds.size.width != _viewPortHandler.chartWidth ||
|
||||
bounds.size.height != _viewPortHandler.chartHeight))
|
||||
{
|
||||
_viewPortHandler.setChartDimens(width: bounds.size.width, height: bounds.size.height)
|
||||
|
||||
// Finish any pending viewport changes
|
||||
while (!_sizeChangeEventActions.isEmpty)
|
||||
{
|
||||
_sizeChangeEventActions.removeAtIndex(0)()
|
||||
}
|
||||
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public func clearPendingViewPortChanges()
|
||||
{
|
||||
_sizeChangeEventActions.removeAll(keepCapacity: false)
|
||||
}
|
||||
|
||||
/// if true, value highlighting is enabled
|
||||
public var highlightEnabled: Bool
|
||||
{
|
||||
get
|
||||
{
|
||||
return _data === nil ? true : _data.highlightEnabled
|
||||
}
|
||||
set
|
||||
{
|
||||
if (_data !== nil)
|
||||
{
|
||||
_data.highlightEnabled = newValue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// if true, value highlightning is enabled
|
||||
public var isHighlightEnabled: Bool { return highlightEnabled }
|
||||
|
||||
/// **default**: true
|
||||
/// - returns: true if chart continues to scroll after touch up, false if not.
|
||||
public var isDragDecelerationEnabled: Bool
|
||||
{
|
||||
return dragDecelerationEnabled
|
||||
}
|
||||
|
||||
/// Deceleration friction coefficient in [0 ; 1] interval, higher values indicate that speed will decrease slowly, for example if it set to 0, it will stop immediately.
|
||||
/// 1 is an invalid value, and will be converted to 0.999 automatically.
|
||||
///
|
||||
/// **default**: true
|
||||
public var dragDecelerationFrictionCoef: CGFloat
|
||||
{
|
||||
get
|
||||
{
|
||||
return _dragDecelerationFrictionCoef
|
||||
}
|
||||
set
|
||||
{
|
||||
var val = newValue
|
||||
if (val < 0.0)
|
||||
{
|
||||
val = 0.0
|
||||
}
|
||||
if (val >= 1.0)
|
||||
{
|
||||
val = 0.999
|
||||
}
|
||||
|
||||
_dragDecelerationFrictionCoef = val
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - ChartAnimatorDelegate
|
||||
|
||||
public func chartAnimatorUpdated(chartAnimator: ChartAnimator)
|
||||
{
|
||||
setNeedsDisplay()
|
||||
}
|
||||
|
||||
public func chartAnimatorStopped(chartAnimator: ChartAnimator)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
// MARK: - Touches
|
||||
|
||||
public override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?)
|
||||
{
|
||||
if (!_interceptTouchEvents)
|
||||
{
|
||||
super.touchesBegan(touches, withEvent: event)
|
||||
}
|
||||
}
|
||||
|
||||
public override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?)
|
||||
{
|
||||
if (!_interceptTouchEvents)
|
||||
{
|
||||
super.touchesMoved(touches, withEvent: event)
|
||||
}
|
||||
}
|
||||
|
||||
public override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?)
|
||||
{
|
||||
if (!_interceptTouchEvents)
|
||||
{
|
||||
super.touchesEnded(touches, withEvent: event)
|
||||
}
|
||||
}
|
||||
|
||||
public override func touchesCancelled(touches: Set<UITouch>?, withEvent event: UIEvent?)
|
||||
{
|
||||
if (!_interceptTouchEvents)
|
||||
{
|
||||
super.touchesCancelled(touches, withEvent: event)
|
||||
}
|
||||
}
|
||||
}
|
||||
214
Carthage/Checkouts/Charts/Charts/Classes/Charts/CombinedChartView.swift
vendored
Normal file
214
Carthage/Checkouts/Charts/Charts/Classes/Charts/CombinedChartView.swift
vendored
Normal file
@@ -0,0 +1,214 @@
|
||||
//
|
||||
// CombinedChartView.swift
|
||||
// Charts
|
||||
//
|
||||
// Created by Daniel Cohen Gindi on 4/3/15.
|
||||
//
|
||||
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
|
||||
// A port of MPAndroidChart for iOS
|
||||
// Licensed under Apache License 2.0
|
||||
//
|
||||
// https://github.com/danielgindi/ios-charts
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import CoreGraphics
|
||||
|
||||
/// This chart class allows the combination of lines, bars, scatter and candle data all displayed in one chart area.
|
||||
public class CombinedChartView: BarLineChartViewBase
|
||||
{
|
||||
/// the fill-formatter used for determining the position of the fill-line
|
||||
internal var _fillFormatter: ChartFillFormatter!
|
||||
|
||||
/// enum that allows to specify the order in which the different data objects for the combined-chart are drawn
|
||||
@objc
|
||||
public enum CombinedChartDrawOrder: Int
|
||||
{
|
||||
case Bar
|
||||
case Bubble
|
||||
case Line
|
||||
case Candle
|
||||
case Scatter
|
||||
}
|
||||
|
||||
public override func initialize()
|
||||
{
|
||||
super.initialize()
|
||||
|
||||
_highlighter = CombinedHighlighter(chart: self)
|
||||
|
||||
/// WORKAROUND: Swift 2.0 compiler malfunctions when optimizations are enabled, and assigning directly to _fillFormatter causes a crash with a EXC_BAD_ACCESS. See https://github.com/danielgindi/ios-charts/issues/406
|
||||
let workaroundFormatter = BarLineChartFillFormatter(chart: self)
|
||||
_fillFormatter = workaroundFormatter
|
||||
|
||||
renderer = CombinedChartRenderer(chart: self, animator: _animator, viewPortHandler: _viewPortHandler)
|
||||
}
|
||||
|
||||
override func calcMinMax()
|
||||
{
|
||||
super.calcMinMax()
|
||||
|
||||
if (self.barData !== nil || self.candleData !== nil || self.bubbleData !== nil)
|
||||
{
|
||||
_chartXMin = -0.5
|
||||
_chartXMax = Double(_data.xVals.count) - 0.5
|
||||
|
||||
if (self.bubbleData !== nil)
|
||||
{
|
||||
for set in self.bubbleData.dataSets as! [BubbleChartDataSet]
|
||||
{
|
||||
let xmin = set.xMin
|
||||
let xmax = set.xMax
|
||||
|
||||
if (xmin < chartXMin)
|
||||
{
|
||||
_chartXMin = xmin
|
||||
}
|
||||
|
||||
if (xmax > chartXMax)
|
||||
{
|
||||
_chartXMax = xmax
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_deltaX = CGFloat(abs(_chartXMax - _chartXMin))
|
||||
}
|
||||
}
|
||||
|
||||
public override var data: ChartData?
|
||||
{
|
||||
get
|
||||
{
|
||||
return super.data
|
||||
}
|
||||
set
|
||||
{
|
||||
super.data = newValue
|
||||
(renderer as! CombinedChartRenderer?)!.createRenderers()
|
||||
}
|
||||
}
|
||||
|
||||
public var fillFormatter: ChartFillFormatter
|
||||
{
|
||||
get
|
||||
{
|
||||
return _fillFormatter
|
||||
}
|
||||
set
|
||||
{
|
||||
_fillFormatter = newValue
|
||||
if (_fillFormatter === nil)
|
||||
{
|
||||
_fillFormatter = BarLineChartFillFormatter(chart: self)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public var lineData: LineChartData!
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_data === nil)
|
||||
{
|
||||
return nil
|
||||
}
|
||||
return (_data as! CombinedChartData!).lineData
|
||||
}
|
||||
}
|
||||
|
||||
public var barData: BarChartData!
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_data === nil)
|
||||
{
|
||||
return nil
|
||||
}
|
||||
return (_data as! CombinedChartData!).barData
|
||||
}
|
||||
}
|
||||
|
||||
public var scatterData: ScatterChartData!
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_data === nil)
|
||||
{
|
||||
return nil
|
||||
}
|
||||
return (_data as! CombinedChartData!).scatterData
|
||||
}
|
||||
}
|
||||
|
||||
public var candleData: CandleChartData!
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_data === nil)
|
||||
{
|
||||
return nil
|
||||
}
|
||||
return (_data as! CombinedChartData!).candleData
|
||||
}
|
||||
}
|
||||
|
||||
public var bubbleData: BubbleChartData!
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_data === nil)
|
||||
{
|
||||
return nil
|
||||
}
|
||||
return (_data as! CombinedChartData!).bubbleData
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Accessors
|
||||
|
||||
/// flag that enables or disables the highlighting arrow
|
||||
public var drawHighlightArrowEnabled: Bool
|
||||
{
|
||||
get { return (renderer as! CombinedChartRenderer!).drawHighlightArrowEnabled; }
|
||||
set { (renderer as! CombinedChartRenderer!).drawHighlightArrowEnabled = newValue; }
|
||||
}
|
||||
|
||||
/// if set to true, all values are drawn above their bars, instead of below their top
|
||||
public var drawValueAboveBarEnabled: Bool
|
||||
{
|
||||
get { return (renderer as! CombinedChartRenderer!).drawValueAboveBarEnabled; }
|
||||
set { (renderer as! CombinedChartRenderer!).drawValueAboveBarEnabled = newValue; }
|
||||
}
|
||||
|
||||
/// if set to true, a grey area is darawn behind each bar that indicates the maximum value
|
||||
public var drawBarShadowEnabled: Bool
|
||||
{
|
||||
get { return (renderer as! CombinedChartRenderer!).drawBarShadowEnabled; }
|
||||
set { (renderer as! CombinedChartRenderer!).drawBarShadowEnabled = newValue; }
|
||||
}
|
||||
|
||||
/// - returns: true if drawing the highlighting arrow is enabled, false if not
|
||||
public var isDrawHighlightArrowEnabled: Bool { return (renderer as! CombinedChartRenderer!).drawHighlightArrowEnabled; }
|
||||
|
||||
/// - returns: true if drawing values above bars is enabled, false if not
|
||||
public var isDrawValueAboveBarEnabled: Bool { return (renderer as! CombinedChartRenderer!).drawValueAboveBarEnabled; }
|
||||
|
||||
/// - returns: true if drawing shadows (maxvalue) for each bar is enabled, false if not
|
||||
public var isDrawBarShadowEnabled: Bool { return (renderer as! CombinedChartRenderer!).drawBarShadowEnabled; }
|
||||
|
||||
/// the order in which the provided data objects should be drawn.
|
||||
/// The earlier you place them in the provided array, the further they will be in the background.
|
||||
/// e.g. if you provide [DrawOrder.Bar, DrawOrder.Line], the bars will be drawn behind the lines.
|
||||
public var drawOrder: [Int]
|
||||
{
|
||||
get
|
||||
{
|
||||
return (renderer as! CombinedChartRenderer!).drawOrder.map { $0.rawValue }
|
||||
}
|
||||
set
|
||||
{
|
||||
(renderer as! CombinedChartRenderer!).drawOrder = newValue.map { CombinedChartDrawOrder(rawValue: $0)! }
|
||||
}
|
||||
}
|
||||
}
|
||||
208
Carthage/Checkouts/Charts/Charts/Classes/Charts/HorizontalBarChartView.swift
vendored
Normal file
208
Carthage/Checkouts/Charts/Charts/Classes/Charts/HorizontalBarChartView.swift
vendored
Normal file
@@ -0,0 +1,208 @@
|
||||
//
|
||||
// HorizontalBarChartView.swift
|
||||
// Charts
|
||||
//
|
||||
// Created by Daniel Cohen Gindi on 4/3/15.
|
||||
//
|
||||
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
|
||||
// A port of MPAndroidChart for iOS
|
||||
// Licensed under Apache License 2.0
|
||||
//
|
||||
// https://github.com/danielgindi/ios-charts
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import UIKit
|
||||
|
||||
/// BarChart with horizontal bar orientation. In this implementation, x- and y-axis are switched.
|
||||
public class HorizontalBarChartView: BarChartView
|
||||
{
|
||||
internal override func initialize()
|
||||
{
|
||||
super.initialize()
|
||||
|
||||
_leftAxisTransformer = ChartTransformerHorizontalBarChart(viewPortHandler: _viewPortHandler)
|
||||
_rightAxisTransformer = ChartTransformerHorizontalBarChart(viewPortHandler: _viewPortHandler)
|
||||
|
||||
renderer = HorizontalBarChartRenderer(delegate: self, animator: _animator, viewPortHandler: _viewPortHandler)
|
||||
_leftYAxisRenderer = ChartYAxisRendererHorizontalBarChart(viewPortHandler: _viewPortHandler, yAxis: _leftAxis, transformer: _leftAxisTransformer)
|
||||
_rightYAxisRenderer = ChartYAxisRendererHorizontalBarChart(viewPortHandler: _viewPortHandler, yAxis: _rightAxis, transformer: _rightAxisTransformer)
|
||||
_xAxisRenderer = ChartXAxisRendererHorizontalBarChart(viewPortHandler: _viewPortHandler, xAxis: _xAxis, transformer: _leftAxisTransformer, chart: self)
|
||||
|
||||
_highlighter = HorizontalBarChartHighlighter(chart: self)
|
||||
}
|
||||
|
||||
internal override func calculateOffsets()
|
||||
{
|
||||
var offsetLeft: CGFloat = 0.0,
|
||||
offsetRight: CGFloat = 0.0,
|
||||
offsetTop: CGFloat = 0.0,
|
||||
offsetBottom: CGFloat = 0.0
|
||||
|
||||
// setup offsets for legend
|
||||
if (_legend !== nil && _legend.isEnabled)
|
||||
{
|
||||
if (_legend.position == .RightOfChart
|
||||
|| _legend.position == .RightOfChartCenter)
|
||||
{
|
||||
offsetRight += min(_legend.neededWidth, _viewPortHandler.chartWidth * _legend.maxSizePercent) + _legend.xOffset * 2.0
|
||||
}
|
||||
else if (_legend.position == .LeftOfChart
|
||||
|| _legend.position == .LeftOfChartCenter)
|
||||
{
|
||||
offsetLeft += min(_legend.neededWidth, _viewPortHandler.chartWidth * _legend.maxSizePercent) + _legend.xOffset * 2.0
|
||||
}
|
||||
else if (_legend.position == .BelowChartLeft
|
||||
|| _legend.position == .BelowChartRight
|
||||
|| _legend.position == .BelowChartCenter)
|
||||
{
|
||||
// It's possible that we do not need this offset anymore as it
|
||||
// is available through the extraOffsets, but changing it can mean
|
||||
// changing default visibility for existing apps.
|
||||
let yOffset = _legend.textHeightMax
|
||||
|
||||
offsetBottom += min(_legend.neededHeight + yOffset, _viewPortHandler.chartHeight * _legend.maxSizePercent)
|
||||
}
|
||||
else if (_legend.position == .AboveChartLeft
|
||||
|| _legend.position == .AboveChartRight
|
||||
|| _legend.position == .AboveChartCenter)
|
||||
{
|
||||
// It's possible that we do not need this offset anymore as it
|
||||
// is available through the extraOffsets, but changing it can mean
|
||||
// changing default visibility for existing apps.
|
||||
let yOffset = _legend.textHeightMax
|
||||
|
||||
offsetTop += min(_legend.neededHeight + yOffset, _viewPortHandler.chartHeight * _legend.maxSizePercent)
|
||||
}
|
||||
}
|
||||
|
||||
// offsets for y-labels
|
||||
if (_leftAxis.needsOffset)
|
||||
{
|
||||
offsetTop += _leftAxis.getRequiredHeightSpace()
|
||||
}
|
||||
|
||||
if (_rightAxis.needsOffset)
|
||||
{
|
||||
offsetBottom += _rightAxis.getRequiredHeightSpace()
|
||||
}
|
||||
|
||||
let xlabelwidth = _xAxis.labelWidth
|
||||
|
||||
if (_xAxis.isEnabled)
|
||||
{
|
||||
// offsets for x-labels
|
||||
if (_xAxis.labelPosition == .Bottom)
|
||||
{
|
||||
offsetLeft += xlabelwidth
|
||||
}
|
||||
else if (_xAxis.labelPosition == .Top)
|
||||
{
|
||||
offsetRight += xlabelwidth
|
||||
}
|
||||
else if (_xAxis.labelPosition == .BothSided)
|
||||
{
|
||||
offsetLeft += xlabelwidth
|
||||
offsetRight += xlabelwidth
|
||||
}
|
||||
}
|
||||
|
||||
offsetTop += self.extraTopOffset
|
||||
offsetRight += self.extraRightOffset
|
||||
offsetBottom += self.extraBottomOffset
|
||||
offsetLeft += self.extraLeftOffset
|
||||
|
||||
_viewPortHandler.restrainViewPort(
|
||||
offsetLeft: max(self.minOffset, offsetLeft),
|
||||
offsetTop: max(self.minOffset, offsetTop),
|
||||
offsetRight: max(self.minOffset, offsetRight),
|
||||
offsetBottom: max(self.minOffset, offsetBottom))
|
||||
|
||||
prepareOffsetMatrix()
|
||||
prepareValuePxMatrix()
|
||||
}
|
||||
|
||||
internal override func prepareValuePxMatrix()
|
||||
{
|
||||
_rightAxisTransformer.prepareMatrixValuePx(chartXMin: _rightAxis.axisMinimum, deltaX: CGFloat(_rightAxis.axisRange), deltaY: _deltaX, chartYMin: _chartXMin)
|
||||
_leftAxisTransformer.prepareMatrixValuePx(chartXMin: _leftAxis.axisMinimum, deltaX: CGFloat(_leftAxis.axisRange), deltaY: _deltaX, chartYMin: _chartXMin)
|
||||
}
|
||||
|
||||
internal override func calcModulus()
|
||||
{
|
||||
_xAxis.axisLabelModulus = Int(ceil((CGFloat(_data.xValCount) * _xAxis.labelHeight) / (_viewPortHandler.contentHeight * viewPortHandler.touchMatrix.d)))
|
||||
|
||||
if (_xAxis.axisLabelModulus < 1)
|
||||
{
|
||||
_xAxis.axisLabelModulus = 1
|
||||
}
|
||||
}
|
||||
|
||||
public override func getBarBounds(e: BarChartDataEntry) -> CGRect!
|
||||
{
|
||||
let set = _data.getDataSetForEntry(e) as! BarChartDataSet!
|
||||
|
||||
if (set === nil)
|
||||
{
|
||||
return nil
|
||||
}
|
||||
|
||||
let barspace = set.barSpace
|
||||
let y = CGFloat(e.value)
|
||||
let x = CGFloat(e.xIndex)
|
||||
|
||||
let spaceHalf = barspace / 2.0
|
||||
let top = x - 0.5 + spaceHalf
|
||||
let bottom = x + 0.5 - spaceHalf
|
||||
let left = y >= 0.0 ? y : 0.0
|
||||
let right = y <= 0.0 ? y : 0.0
|
||||
|
||||
var bounds = CGRect(x: left, y: top, width: right - left, height: bottom - top)
|
||||
|
||||
getTransformer(set.axisDependency).rectValueToPixel(&bounds)
|
||||
|
||||
return bounds
|
||||
}
|
||||
|
||||
public override func getPosition(e: ChartDataEntry, axis: ChartYAxis.AxisDependency) -> CGPoint
|
||||
{
|
||||
var vals = CGPoint(x: CGFloat(e.value), y: CGFloat(e.xIndex))
|
||||
|
||||
getTransformer(axis).pointValueToPixel(&vals)
|
||||
|
||||
return vals
|
||||
}
|
||||
|
||||
public override func getHighlightByTouchPoint(pt: CGPoint) -> ChartHighlight?
|
||||
{
|
||||
if (_dataNotSet || _data === nil)
|
||||
{
|
||||
print("Can't select by touch. No data set.", terminator: "\n")
|
||||
return nil
|
||||
}
|
||||
|
||||
return _highlighter?.getHighlight(x: Double(pt.y), y: Double(pt.x))
|
||||
}
|
||||
|
||||
public override var lowestVisibleXIndex: Int
|
||||
{
|
||||
let step = CGFloat(_data.dataSetCount)
|
||||
let div = (step <= 1.0) ? 1.0 : step + (_data as! BarChartData).groupSpace
|
||||
|
||||
var pt = CGPoint(x: _viewPortHandler.contentLeft, y: _viewPortHandler.contentBottom)
|
||||
getTransformer(ChartYAxis.AxisDependency.Left).pixelToValue(&pt)
|
||||
|
||||
return Int(((pt.y <= 0.0) ? 0.0 : pt.y / div) + 1.0)
|
||||
}
|
||||
|
||||
public override var highestVisibleXIndex: Int
|
||||
{
|
||||
let step = CGFloat(_data.dataSetCount)
|
||||
let div = (step <= 1.0) ? 1.0 : step + (_data as! BarChartData).groupSpace
|
||||
|
||||
var pt = CGPoint(x: _viewPortHandler.contentLeft, y: _viewPortHandler.contentTop)
|
||||
getTransformer(ChartYAxis.AxisDependency.Left).pixelToValue(&pt)
|
||||
|
||||
return Int((pt.y >= CGFloat(chartXMax)) ? CGFloat(chartXMax) / div : (pt.y / div))
|
||||
}
|
||||
}
|
||||
106
Carthage/Checkouts/Charts/Charts/Classes/Charts/LineChartView.swift
vendored
Normal file
106
Carthage/Checkouts/Charts/Charts/Classes/Charts/LineChartView.swift
vendored
Normal file
@@ -0,0 +1,106 @@
|
||||
//
|
||||
// LineChartView.swift
|
||||
// Charts
|
||||
//
|
||||
// Created by Daniel Cohen Gindi on 4/3/15.
|
||||
//
|
||||
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
|
||||
// A port of MPAndroidChart for iOS
|
||||
// Licensed under Apache License 2.0
|
||||
//
|
||||
// https://github.com/danielgindi/ios-charts
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import CoreGraphics
|
||||
|
||||
/// Chart that draws lines, surfaces, circles, ...
|
||||
public class LineChartView: BarLineChartViewBase, LineChartRendererDelegate
|
||||
{
|
||||
private var _fillFormatter: ChartFillFormatter!
|
||||
|
||||
internal override func initialize()
|
||||
{
|
||||
super.initialize()
|
||||
|
||||
renderer = LineChartRenderer(delegate: self, animator: _animator, viewPortHandler: _viewPortHandler)
|
||||
|
||||
_fillFormatter = BarLineChartFillFormatter(chart: self)
|
||||
}
|
||||
|
||||
internal override func calcMinMax()
|
||||
{
|
||||
super.calcMinMax()
|
||||
|
||||
if (_deltaX == 0.0 && _data.yValCount > 0)
|
||||
{
|
||||
_deltaX = 1.0
|
||||
}
|
||||
}
|
||||
|
||||
public var fillFormatter: ChartFillFormatter!
|
||||
{
|
||||
get
|
||||
{
|
||||
return _fillFormatter
|
||||
}
|
||||
set
|
||||
{
|
||||
if (newValue === nil)
|
||||
{
|
||||
_fillFormatter = BarLineChartFillFormatter(chart: self)
|
||||
}
|
||||
else
|
||||
{
|
||||
_fillFormatter = newValue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - LineChartRendererDelegate
|
||||
|
||||
public func lineChartRendererData(renderer: LineChartRenderer) -> LineChartData!
|
||||
{
|
||||
return _data as! LineChartData!
|
||||
}
|
||||
|
||||
public func lineChartRenderer(renderer: LineChartRenderer, transformerForAxis which: ChartYAxis.AxisDependency) -> ChartTransformer!
|
||||
{
|
||||
return self.getTransformer(which)
|
||||
}
|
||||
|
||||
public func lineChartRendererFillFormatter(renderer: LineChartRenderer) -> ChartFillFormatter
|
||||
{
|
||||
return self.fillFormatter
|
||||
}
|
||||
|
||||
public func lineChartDefaultRendererValueFormatter(renderer: LineChartRenderer) -> NSNumberFormatter!
|
||||
{
|
||||
return self._defaultValueFormatter
|
||||
}
|
||||
|
||||
public func lineChartRendererChartYMax(renderer: LineChartRenderer) -> Double
|
||||
{
|
||||
return self.chartYMax
|
||||
}
|
||||
|
||||
public func lineChartRendererChartYMin(renderer: LineChartRenderer) -> Double
|
||||
{
|
||||
return self.chartYMin
|
||||
}
|
||||
|
||||
public func lineChartRendererChartXMax(renderer: LineChartRenderer) -> Double
|
||||
{
|
||||
return self.chartXMax
|
||||
}
|
||||
|
||||
public func lineChartRendererChartXMin(renderer: LineChartRenderer) -> Double
|
||||
{
|
||||
return self.chartXMin
|
||||
}
|
||||
|
||||
public func lineChartRendererMaxVisibleValueCount(renderer: LineChartRenderer) -> Int
|
||||
{
|
||||
return self.maxVisibleValueCount
|
||||
}
|
||||
}
|
||||
505
Carthage/Checkouts/Charts/Charts/Classes/Charts/PieChartView.swift
vendored
Executable file
505
Carthage/Checkouts/Charts/Charts/Classes/Charts/PieChartView.swift
vendored
Executable file
@@ -0,0 +1,505 @@
|
||||
//
|
||||
// PieChartView.swift
|
||||
// Charts
|
||||
//
|
||||
// Created by Daniel Cohen Gindi on 4/3/15.
|
||||
//
|
||||
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
|
||||
// A port of MPAndroidChart for iOS
|
||||
// Licensed under Apache License 2.0
|
||||
//
|
||||
// https://github.com/danielgindi/ios-charts
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import UIKit
|
||||
|
||||
/// View that represents a pie chart. Draws cake like slices.
|
||||
public class PieChartView: PieRadarChartViewBase
|
||||
{
|
||||
/// rect object that represents the bounds of the piechart, needed for drawing the circle
|
||||
private var _circleBox = CGRect()
|
||||
|
||||
/// array that holds the width of each pie-slice in degrees
|
||||
private var _drawAngles = [CGFloat]()
|
||||
|
||||
/// array that holds the absolute angle in degrees of each slice
|
||||
private var _absoluteAngles = [CGFloat]()
|
||||
|
||||
public override init(frame: CGRect)
|
||||
{
|
||||
super.init(frame: frame)
|
||||
}
|
||||
|
||||
public required init?(coder aDecoder: NSCoder)
|
||||
{
|
||||
super.init(coder: aDecoder)
|
||||
}
|
||||
|
||||
internal override func initialize()
|
||||
{
|
||||
super.initialize()
|
||||
|
||||
renderer = PieChartRenderer(chart: self, animator: _animator, viewPortHandler: _viewPortHandler)
|
||||
}
|
||||
|
||||
public override func drawRect(rect: CGRect)
|
||||
{
|
||||
super.drawRect(rect)
|
||||
|
||||
if (_dataNotSet)
|
||||
{
|
||||
return
|
||||
}
|
||||
|
||||
let context = UIGraphicsGetCurrentContext()
|
||||
|
||||
renderer!.drawData(context: context)
|
||||
|
||||
if (valuesToHighlight())
|
||||
{
|
||||
renderer!.drawHighlighted(context: context, indices: _indicesToHightlight)
|
||||
}
|
||||
|
||||
renderer!.drawExtras(context: context)
|
||||
|
||||
renderer!.drawValues(context: context)
|
||||
|
||||
_legendRenderer.renderLegend(context: context)
|
||||
|
||||
drawDescription(context: context)
|
||||
|
||||
drawMarkers(context: context)
|
||||
}
|
||||
|
||||
internal override func calculateOffsets()
|
||||
{
|
||||
super.calculateOffsets()
|
||||
|
||||
// prevent nullpointer when no data set
|
||||
if (_dataNotSet)
|
||||
{
|
||||
return
|
||||
}
|
||||
|
||||
let radius = diameter / 2.0
|
||||
|
||||
let c = centerOffsets
|
||||
|
||||
let dataSets = data?.dataSets as? [PieChartDataSet]
|
||||
|
||||
let maxShift = dataSets?.reduce(0.0, combine: { shift, dataSet in
|
||||
return dataSet.selectionShift > shift ? dataSet.selectionShift : shift
|
||||
}) ?? 0.0
|
||||
|
||||
// create the circle box that will contain the pie-chart (the bounds of the pie-chart)
|
||||
_circleBox.origin.x = (c.x - radius) + (maxShift / 2.0)
|
||||
_circleBox.origin.y = (c.y - radius) + (maxShift / 2.0)
|
||||
_circleBox.size.width = diameter - maxShift
|
||||
_circleBox.size.height = diameter - maxShift
|
||||
}
|
||||
|
||||
internal override func calcMinMax()
|
||||
{
|
||||
super.calcMinMax()
|
||||
|
||||
calcAngles()
|
||||
}
|
||||
|
||||
public override func getMarkerPosition(entry e: ChartDataEntry, highlight: ChartHighlight) -> CGPoint
|
||||
{
|
||||
let center = self.centerCircleBox
|
||||
var r = self.radius
|
||||
|
||||
var off = r / 10.0 * 3.6
|
||||
|
||||
if self.isDrawHoleEnabled
|
||||
{
|
||||
off = (r - (r * self.holeRadiusPercent)) / 2.0
|
||||
}
|
||||
|
||||
r -= off // offset to keep things inside the chart
|
||||
|
||||
let rotationAngle = self.rotationAngle
|
||||
|
||||
let i = e.xIndex
|
||||
|
||||
// offset needed to center the drawn text in the slice
|
||||
let offset = drawAngles[i] / 2.0
|
||||
|
||||
// calculate the text position
|
||||
let x: CGFloat = (r * cos(((rotationAngle + absoluteAngles[i] - offset) * _animator.phaseY) * ChartUtils.Math.FDEG2RAD) + center.x)
|
||||
let y: CGFloat = (r * sin(((rotationAngle + absoluteAngles[i] - offset) * _animator.phaseY) * ChartUtils.Math.FDEG2RAD) + center.y)
|
||||
|
||||
return CGPoint(x: x, y: y)
|
||||
}
|
||||
|
||||
/// calculates the needed angles for the chart slices
|
||||
private func calcAngles()
|
||||
{
|
||||
_drawAngles = [CGFloat]()
|
||||
_absoluteAngles = [CGFloat]()
|
||||
|
||||
_drawAngles.reserveCapacity(_data.yValCount)
|
||||
_absoluteAngles.reserveCapacity(_data.yValCount)
|
||||
|
||||
var dataSets = _data.dataSets
|
||||
|
||||
var cnt = 0
|
||||
|
||||
for (var i = 0; i < _data.dataSetCount; i++)
|
||||
{
|
||||
let set = dataSets[i]
|
||||
var entries = set.yVals
|
||||
|
||||
for (var j = 0; j < entries.count; j++)
|
||||
{
|
||||
_drawAngles.append(calcAngle(abs(entries[j].value)))
|
||||
|
||||
if (cnt == 0)
|
||||
{
|
||||
_absoluteAngles.append(_drawAngles[cnt])
|
||||
}
|
||||
else
|
||||
{
|
||||
_absoluteAngles.append(_absoluteAngles[cnt - 1] + _drawAngles[cnt])
|
||||
}
|
||||
|
||||
cnt++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// checks if the given index in the given DataSet is set for highlighting or not
|
||||
public func needsHighlight(xIndex xIndex: Int, dataSetIndex: Int) -> Bool
|
||||
{
|
||||
// no highlight
|
||||
if (!valuesToHighlight() || dataSetIndex < 0)
|
||||
{
|
||||
return false
|
||||
}
|
||||
|
||||
for (var i = 0; i < _indicesToHightlight.count; i++)
|
||||
{
|
||||
// check if the xvalue for the given dataset needs highlight
|
||||
if (_indicesToHightlight[i].xIndex == xIndex
|
||||
&& _indicesToHightlight[i].dataSetIndex == dataSetIndex)
|
||||
{
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
/// calculates the needed angle for a given value
|
||||
private func calcAngle(value: Double) -> CGFloat
|
||||
{
|
||||
return CGFloat(value) / CGFloat(_data.yValueSum) * 360.0
|
||||
}
|
||||
|
||||
public override func indexForAngle(angle: CGFloat) -> Int
|
||||
{
|
||||
// take the current angle of the chart into consideration
|
||||
let a = ChartUtils.normalizedAngleFromAngle(angle - self.rotationAngle)
|
||||
for (var i = 0; i < _absoluteAngles.count; i++)
|
||||
{
|
||||
if (_absoluteAngles[i] > a)
|
||||
{
|
||||
return i
|
||||
}
|
||||
}
|
||||
|
||||
return -1; // return -1 if no index found
|
||||
}
|
||||
|
||||
/// - returns: the index of the DataSet this x-index belongs to.
|
||||
public func dataSetIndexForIndex(xIndex: Int) -> Int
|
||||
{
|
||||
var dataSets = _data.dataSets
|
||||
|
||||
for (var i = 0; i < dataSets.count; i++)
|
||||
{
|
||||
if (dataSets[i].entryForXIndex(xIndex) !== nil)
|
||||
{
|
||||
return i
|
||||
}
|
||||
}
|
||||
|
||||
return -1
|
||||
}
|
||||
|
||||
/// - returns: an integer array of all the different angles the chart slices
|
||||
/// have the angles in the returned array determine how much space (of 360°)
|
||||
/// each slice takes
|
||||
public var drawAngles: [CGFloat]
|
||||
{
|
||||
return _drawAngles
|
||||
}
|
||||
|
||||
/// - returns: the absolute angles of the different chart slices (where the
|
||||
/// slices end)
|
||||
public var absoluteAngles: [CGFloat]
|
||||
{
|
||||
return _absoluteAngles
|
||||
}
|
||||
|
||||
/// Sets the color for the hole that is drawn in the center of the PieChart (if enabled).
|
||||
///
|
||||
/// *Note: Use holeTransparent with holeColor = nil to make the hole transparent.*
|
||||
public var holeColor: UIColor?
|
||||
{
|
||||
get
|
||||
{
|
||||
return (renderer as! PieChartRenderer).holeColor!
|
||||
}
|
||||
set
|
||||
{
|
||||
(renderer as! PieChartRenderer).holeColor = newValue
|
||||
setNeedsDisplay()
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the hole in the center of the PieChart transparent
|
||||
public var holeTransparent: Bool
|
||||
{
|
||||
get
|
||||
{
|
||||
return (renderer as! PieChartRenderer).holeTransparent
|
||||
}
|
||||
set
|
||||
{
|
||||
(renderer as! PieChartRenderer).holeTransparent = newValue
|
||||
setNeedsDisplay()
|
||||
}
|
||||
}
|
||||
|
||||
/// - returns: true if the hole in the center of the PieChart is transparent, false if not.
|
||||
public var isHoleTransparent: Bool
|
||||
{
|
||||
return (renderer as! PieChartRenderer).holeTransparent
|
||||
}
|
||||
|
||||
/// true if the hole in the center of the pie-chart is set to be visible, false if not
|
||||
public var drawHoleEnabled: Bool
|
||||
{
|
||||
get
|
||||
{
|
||||
return (renderer as! PieChartRenderer).drawHoleEnabled
|
||||
}
|
||||
set
|
||||
{
|
||||
(renderer as! PieChartRenderer).drawHoleEnabled = newValue
|
||||
setNeedsDisplay()
|
||||
}
|
||||
}
|
||||
|
||||
/// - returns: true if the hole in the center of the pie-chart is set to be visible, false if not
|
||||
public var isDrawHoleEnabled: Bool
|
||||
{
|
||||
get
|
||||
{
|
||||
return (renderer as! PieChartRenderer).drawHoleEnabled
|
||||
}
|
||||
}
|
||||
|
||||
/// the text that is displayed in the center of the pie-chart. By default, the text is "Total value + sum of all values"
|
||||
public var centerText: String!
|
||||
{
|
||||
get
|
||||
{
|
||||
return (renderer as! PieChartRenderer).centerText
|
||||
}
|
||||
set
|
||||
{
|
||||
(renderer as! PieChartRenderer).centerText = newValue
|
||||
setNeedsDisplay()
|
||||
}
|
||||
}
|
||||
|
||||
/// true if drawing the center text is enabled
|
||||
public var drawCenterTextEnabled: Bool
|
||||
{
|
||||
get
|
||||
{
|
||||
return (renderer as! PieChartRenderer).drawCenterTextEnabled
|
||||
}
|
||||
set
|
||||
{
|
||||
(renderer as! PieChartRenderer).drawCenterTextEnabled = newValue
|
||||
setNeedsDisplay()
|
||||
}
|
||||
}
|
||||
|
||||
/// - returns: true if drawing the center text is enabled
|
||||
public var isDrawCenterTextEnabled: Bool
|
||||
{
|
||||
get
|
||||
{
|
||||
return (renderer as! PieChartRenderer).drawCenterTextEnabled
|
||||
}
|
||||
}
|
||||
|
||||
internal override var requiredLegendOffset: CGFloat
|
||||
{
|
||||
return _legend.font.pointSize * 2.0
|
||||
}
|
||||
|
||||
internal override var requiredBaseOffset: CGFloat
|
||||
{
|
||||
return 0.0
|
||||
}
|
||||
|
||||
public override var radius: CGFloat
|
||||
{
|
||||
return _circleBox.width / 2.0
|
||||
}
|
||||
|
||||
/// - returns: the circlebox, the boundingbox of the pie-chart slices
|
||||
public var circleBox: CGRect
|
||||
{
|
||||
return _circleBox
|
||||
}
|
||||
|
||||
/// - returns: the center of the circlebox
|
||||
public var centerCircleBox: CGPoint
|
||||
{
|
||||
return CGPoint(x: _circleBox.midX, y: _circleBox.midY)
|
||||
}
|
||||
|
||||
/// Sets the font of the center text of the piechart.
|
||||
public var centerTextFont: UIFont
|
||||
{
|
||||
get
|
||||
{
|
||||
return (renderer as! PieChartRenderer).centerTextFont
|
||||
}
|
||||
set
|
||||
{
|
||||
(renderer as! PieChartRenderer).centerTextFont = newValue
|
||||
setNeedsDisplay()
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets the color of the center text of the piechart.
|
||||
public var centerTextColor: UIColor
|
||||
{
|
||||
get
|
||||
{
|
||||
return (renderer as! PieChartRenderer).centerTextColor
|
||||
}
|
||||
set
|
||||
{
|
||||
(renderer as! PieChartRenderer).centerTextColor = newValue
|
||||
setNeedsDisplay()
|
||||
}
|
||||
}
|
||||
|
||||
/// the radius of the hole in the center of the piechart in percent of the maximum radius (max = the radius of the whole chart)
|
||||
///
|
||||
/// **default**: 0.5 (50%) (half the pie)
|
||||
public var holeRadiusPercent: CGFloat
|
||||
{
|
||||
get
|
||||
{
|
||||
return (renderer as! PieChartRenderer).holeRadiusPercent
|
||||
}
|
||||
set
|
||||
{
|
||||
(renderer as! PieChartRenderer).holeRadiusPercent = newValue
|
||||
setNeedsDisplay()
|
||||
}
|
||||
}
|
||||
|
||||
/// the radius of the transparent circle that is drawn next to the hole in the piechart in percent of the maximum radius (max = the radius of the whole chart)
|
||||
///
|
||||
/// **default**: 0.55 (55%) -> means 5% larger than the center-hole by default
|
||||
public var transparentCircleRadiusPercent: CGFloat
|
||||
{
|
||||
get
|
||||
{
|
||||
return (renderer as! PieChartRenderer).transparentCircleRadiusPercent
|
||||
}
|
||||
set
|
||||
{
|
||||
(renderer as! PieChartRenderer).transparentCircleRadiusPercent = newValue
|
||||
setNeedsDisplay()
|
||||
}
|
||||
}
|
||||
|
||||
/// set this to true to draw the x-value text into the pie slices
|
||||
public var drawSliceTextEnabled: Bool
|
||||
{
|
||||
get
|
||||
{
|
||||
return (renderer as! PieChartRenderer).drawXLabelsEnabled
|
||||
}
|
||||
set
|
||||
{
|
||||
(renderer as! PieChartRenderer).drawXLabelsEnabled = newValue
|
||||
setNeedsDisplay()
|
||||
}
|
||||
}
|
||||
|
||||
/// - returns: true if drawing x-values is enabled, false if not
|
||||
public var isDrawSliceTextEnabled: Bool
|
||||
{
|
||||
get
|
||||
{
|
||||
return (renderer as! PieChartRenderer).drawXLabelsEnabled
|
||||
}
|
||||
}
|
||||
|
||||
/// If this is enabled, values inside the PieChart are drawn in percent and not with their original value. Values provided for the ValueFormatter to format are then provided in percent.
|
||||
public var usePercentValuesEnabled: Bool
|
||||
{
|
||||
get
|
||||
{
|
||||
return (renderer as! PieChartRenderer).usePercentValuesEnabled
|
||||
}
|
||||
set
|
||||
{
|
||||
(renderer as! PieChartRenderer).usePercentValuesEnabled = newValue
|
||||
setNeedsDisplay()
|
||||
}
|
||||
}
|
||||
|
||||
/// - returns: true if drawing x-values is enabled, false if not
|
||||
public var isUsePercentValuesEnabled: Bool
|
||||
{
|
||||
get
|
||||
{
|
||||
return (renderer as! PieChartRenderer).usePercentValuesEnabled
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// the line break mode for center text.
|
||||
/// note that different line break modes give different performance results - Clipping being the fastest, WordWrapping being the slowst.
|
||||
public var centerTextLineBreakMode: NSLineBreakMode
|
||||
{
|
||||
get
|
||||
{
|
||||
return (renderer as! PieChartRenderer).centerTextLineBreakMode
|
||||
}
|
||||
set
|
||||
{
|
||||
(renderer as! PieChartRenderer).centerTextLineBreakMode = newValue
|
||||
setNeedsDisplay()
|
||||
}
|
||||
}
|
||||
|
||||
/// the rectangular radius of the bounding box for the center text, as a percentage of the pie hole
|
||||
public var centerTextRadiusPercent: CGFloat
|
||||
{
|
||||
get
|
||||
{
|
||||
return (renderer as! PieChartRenderer).centerTextRadiusPercent
|
||||
}
|
||||
set
|
||||
{
|
||||
(renderer as! PieChartRenderer).centerTextRadiusPercent = newValue
|
||||
setNeedsDisplay()
|
||||
}
|
||||
}
|
||||
}
|
||||
853
Carthage/Checkouts/Charts/Charts/Classes/Charts/PieRadarChartViewBase.swift
vendored
Executable file
853
Carthage/Checkouts/Charts/Charts/Classes/Charts/PieRadarChartViewBase.swift
vendored
Executable file
@@ -0,0 +1,853 @@
|
||||
//
|
||||
// PieRadarChartViewBase.swift
|
||||
// Charts
|
||||
//
|
||||
// Created by Daniel Cohen Gindi on 4/3/15.
|
||||
//
|
||||
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
|
||||
// A port of MPAndroidChart for iOS
|
||||
// Licensed under Apache License 2.0
|
||||
//
|
||||
// https://github.com/danielgindi/ios-charts
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import CoreGraphics
|
||||
import UIKit
|
||||
|
||||
/// Base class of PieChartView and RadarChartView.
|
||||
public class PieRadarChartViewBase: ChartViewBase
|
||||
{
|
||||
/// holds the normalized version of the current rotation angle of the chart
|
||||
private var _rotationAngle = CGFloat(270.0)
|
||||
|
||||
/// holds the raw version of the current rotation angle of the chart
|
||||
private var _rawRotationAngle = CGFloat(270.0)
|
||||
|
||||
/// flag that indicates if rotation is enabled or not
|
||||
public var rotationEnabled = true
|
||||
|
||||
/// Sets the minimum offset (padding) around the chart, defaults to 10
|
||||
public var minOffset = CGFloat(10.0)
|
||||
|
||||
private var _rotationWithTwoFingers = false
|
||||
|
||||
private var _tapGestureRecognizer: UITapGestureRecognizer!
|
||||
#if !os(tvOS)
|
||||
private var _rotationGestureRecognizer: UIRotationGestureRecognizer!
|
||||
#endif
|
||||
|
||||
public override init(frame: CGRect)
|
||||
{
|
||||
super.init(frame: frame)
|
||||
}
|
||||
|
||||
public required init?(coder aDecoder: NSCoder)
|
||||
{
|
||||
super.init(coder: aDecoder)
|
||||
}
|
||||
|
||||
deinit
|
||||
{
|
||||
stopDeceleration()
|
||||
}
|
||||
|
||||
internal override func initialize()
|
||||
{
|
||||
super.initialize()
|
||||
|
||||
_tapGestureRecognizer = UITapGestureRecognizer(target: self, action: Selector("tapGestureRecognized:"))
|
||||
|
||||
self.addGestureRecognizer(_tapGestureRecognizer)
|
||||
|
||||
#if !os(tvOS)
|
||||
_rotationGestureRecognizer = UIRotationGestureRecognizer(target: self, action: Selector("rotationGestureRecognized:"))
|
||||
self.addGestureRecognizer(_rotationGestureRecognizer)
|
||||
_rotationGestureRecognizer.enabled = rotationWithTwoFingers
|
||||
#endif
|
||||
}
|
||||
|
||||
internal override func calcMinMax()
|
||||
{
|
||||
_deltaX = CGFloat(_data.xVals.count - 1)
|
||||
}
|
||||
|
||||
public override func notifyDataSetChanged()
|
||||
{
|
||||
if (_dataNotSet)
|
||||
{
|
||||
return
|
||||
}
|
||||
|
||||
calcMinMax()
|
||||
|
||||
if (_legend !== nil)
|
||||
{
|
||||
_legendRenderer.computeLegend(_data)
|
||||
}
|
||||
|
||||
calculateOffsets()
|
||||
|
||||
setNeedsDisplay()
|
||||
}
|
||||
|
||||
internal override func calculateOffsets()
|
||||
{
|
||||
var legendLeft = CGFloat(0.0)
|
||||
var legendRight = CGFloat(0.0)
|
||||
var legendBottom = CGFloat(0.0)
|
||||
var legendTop = CGFloat(0.0)
|
||||
|
||||
if (_legend != nil && _legend.enabled)
|
||||
{
|
||||
var fullLegendWidth = min(_legend.neededWidth, _viewPortHandler.chartWidth * _legend.maxSizePercent)
|
||||
fullLegendWidth += _legend.formSize + _legend.formToTextSpace
|
||||
|
||||
if (_legend.position == .RightOfChartCenter)
|
||||
{
|
||||
// this is the space between the legend and the chart
|
||||
let spacing = CGFloat(13.0)
|
||||
|
||||
legendRight = fullLegendWidth + spacing
|
||||
}
|
||||
else if (_legend.position == .RightOfChart)
|
||||
{
|
||||
// this is the space between the legend and the chart
|
||||
let spacing = CGFloat(8.0)
|
||||
|
||||
let legendWidth = fullLegendWidth + spacing
|
||||
let legendHeight = _legend.neededHeight + _legend.textHeightMax
|
||||
|
||||
let c = self.midPoint
|
||||
|
||||
let bottomRight = CGPoint(x: self.bounds.width - legendWidth + 15.0, y: legendHeight + 15)
|
||||
let distLegend = distanceToCenter(x: bottomRight.x, y: bottomRight.y)
|
||||
|
||||
let reference = getPosition(center: c, dist: self.radius,
|
||||
angle: angleForPoint(x: bottomRight.x, y: bottomRight.y))
|
||||
|
||||
let distReference = distanceToCenter(x: reference.x, y: reference.y)
|
||||
let minOffset = CGFloat(5.0)
|
||||
|
||||
if (distLegend < distReference)
|
||||
{
|
||||
let diff = distReference - distLegend
|
||||
legendRight = minOffset + diff
|
||||
}
|
||||
|
||||
if (bottomRight.y >= c.y && self.bounds.height - legendWidth > self.bounds.width)
|
||||
{
|
||||
legendRight = legendWidth
|
||||
}
|
||||
}
|
||||
else if (_legend.position == .LeftOfChartCenter)
|
||||
{
|
||||
// this is the space between the legend and the chart
|
||||
let spacing = CGFloat(13.0)
|
||||
|
||||
legendLeft = fullLegendWidth + spacing
|
||||
}
|
||||
else if (_legend.position == .LeftOfChart)
|
||||
{
|
||||
|
||||
// this is the space between the legend and the chart
|
||||
let spacing = CGFloat(8.0)
|
||||
|
||||
let legendWidth = fullLegendWidth + spacing
|
||||
let legendHeight = _legend.neededHeight + _legend.textHeightMax
|
||||
|
||||
let c = self.midPoint
|
||||
|
||||
let bottomLeft = CGPoint(x: legendWidth - 15.0, y: legendHeight + 15)
|
||||
let distLegend = distanceToCenter(x: bottomLeft.x, y: bottomLeft.y)
|
||||
|
||||
let reference = getPosition(center: c, dist: self.radius,
|
||||
angle: angleForPoint(x: bottomLeft.x, y: bottomLeft.y))
|
||||
|
||||
let distReference = distanceToCenter(x: reference.x, y: reference.y)
|
||||
let min = CGFloat(5.0)
|
||||
|
||||
if (distLegend < distReference)
|
||||
{
|
||||
let diff = distReference - distLegend
|
||||
legendLeft = min + diff
|
||||
}
|
||||
|
||||
if (bottomLeft.y >= c.y && self.bounds.height - legendWidth > self.bounds.width)
|
||||
{
|
||||
legendLeft = legendWidth
|
||||
}
|
||||
}
|
||||
else if (_legend.position == .BelowChartLeft
|
||||
|| _legend.position == .BelowChartRight
|
||||
|| _legend.position == .BelowChartCenter)
|
||||
{
|
||||
// It's possible that we do not need this offset anymore as it
|
||||
// is available through the extraOffsets, but changing it can mean
|
||||
// changing default visibility for existing apps.
|
||||
let yOffset = self.requiredLegendOffset
|
||||
|
||||
legendBottom = min(_legend.neededHeight + yOffset, _viewPortHandler.chartHeight * _legend.maxSizePercent)
|
||||
}
|
||||
else if (_legend.position == .AboveChartLeft
|
||||
|| _legend.position == .AboveChartRight
|
||||
|| _legend.position == .AboveChartCenter)
|
||||
{
|
||||
// It's possible that we do not need this offset anymore as it
|
||||
// is available through the extraOffsets, but changing it can mean
|
||||
// changing default visibility for existing apps.
|
||||
let yOffset = self.requiredLegendOffset
|
||||
|
||||
legendTop = min(_legend.neededHeight + yOffset, _viewPortHandler.chartHeight * _legend.maxSizePercent)
|
||||
}
|
||||
|
||||
legendLeft += self.requiredBaseOffset
|
||||
legendRight += self.requiredBaseOffset
|
||||
legendTop += self.requiredBaseOffset
|
||||
}
|
||||
|
||||
legendTop += self.extraTopOffset
|
||||
legendRight += self.extraRightOffset
|
||||
legendBottom += self.extraBottomOffset
|
||||
legendLeft += self.extraLeftOffset
|
||||
|
||||
var minOffset = self.minOffset
|
||||
|
||||
if (self.isKindOfClass(RadarChartView))
|
||||
{
|
||||
let x = (self as! RadarChartView).xAxis
|
||||
|
||||
if x.isEnabled && x.drawLabelsEnabled
|
||||
{
|
||||
minOffset = max(minOffset, x.labelWidth)
|
||||
}
|
||||
}
|
||||
|
||||
let offsetLeft = max(minOffset, legendLeft)
|
||||
let offsetTop = max(minOffset, legendTop)
|
||||
let offsetRight = max(minOffset, legendRight)
|
||||
let offsetBottom = max(minOffset, max(self.requiredBaseOffset, legendBottom))
|
||||
|
||||
_viewPortHandler.restrainViewPort(offsetLeft: offsetLeft, offsetTop: offsetTop, offsetRight: offsetRight, offsetBottom: offsetBottom)
|
||||
}
|
||||
|
||||
/// - returns: the angle relative to the chart center for the given point on the chart in degrees.
|
||||
/// The angle is always between 0 and 360°, 0° is NORTH, 90° is EAST, ...
|
||||
public func angleForPoint(x x: CGFloat, y: CGFloat) -> CGFloat
|
||||
{
|
||||
let c = centerOffsets
|
||||
|
||||
let tx = Double(x - c.x)
|
||||
let ty = Double(y - c.y)
|
||||
let length = sqrt(tx * tx + ty * ty)
|
||||
let r = acos(ty / length)
|
||||
|
||||
var angle = r * ChartUtils.Math.RAD2DEG
|
||||
|
||||
if (x > c.x)
|
||||
{
|
||||
angle = 360.0 - angle
|
||||
}
|
||||
|
||||
// add 90° because chart starts EAST
|
||||
angle = angle + 90.0
|
||||
|
||||
// neutralize overflow
|
||||
if (angle > 360.0)
|
||||
{
|
||||
angle = angle - 360.0
|
||||
}
|
||||
|
||||
return CGFloat(angle)
|
||||
}
|
||||
|
||||
/// Calculates the position around a center point, depending on the distance
|
||||
/// from the center, and the angle of the position around the center.
|
||||
internal func getPosition(center center: CGPoint, dist: CGFloat, angle: CGFloat) -> CGPoint
|
||||
{
|
||||
return CGPoint(x: center.x + dist * cos(angle * ChartUtils.Math.FDEG2RAD),
|
||||
y: center.y + dist * sin(angle * ChartUtils.Math.FDEG2RAD))
|
||||
}
|
||||
|
||||
/// - returns: the distance of a certain point on the chart to the center of the chart.
|
||||
public func distanceToCenter(x x: CGFloat, y: CGFloat) -> CGFloat
|
||||
{
|
||||
let c = self.centerOffsets
|
||||
|
||||
var dist = CGFloat(0.0)
|
||||
|
||||
var xDist = CGFloat(0.0)
|
||||
var yDist = CGFloat(0.0)
|
||||
|
||||
if (x > c.x)
|
||||
{
|
||||
xDist = x - c.x
|
||||
}
|
||||
else
|
||||
{
|
||||
xDist = c.x - x
|
||||
}
|
||||
|
||||
if (y > c.y)
|
||||
{
|
||||
yDist = y - c.y
|
||||
}
|
||||
else
|
||||
{
|
||||
yDist = c.y - y
|
||||
}
|
||||
|
||||
// pythagoras
|
||||
dist = sqrt(pow(xDist, 2.0) + pow(yDist, 2.0))
|
||||
|
||||
return dist
|
||||
}
|
||||
|
||||
/// - returns: the xIndex for the given angle around the center of the chart.
|
||||
/// -1 if not found / outofbounds.
|
||||
public func indexForAngle(angle: CGFloat) -> Int
|
||||
{
|
||||
fatalError("indexForAngle() cannot be called on PieRadarChartViewBase")
|
||||
}
|
||||
|
||||
/// current rotation angle of the pie chart
|
||||
///
|
||||
/// **default**: 270 --> top (NORTH)
|
||||
/// - returns: will always return a normalized value, which will be between 0.0 < 360.0
|
||||
public var rotationAngle: CGFloat
|
||||
{
|
||||
get
|
||||
{
|
||||
return _rotationAngle
|
||||
}
|
||||
set
|
||||
{
|
||||
_rawRotationAngle = newValue
|
||||
_rotationAngle = ChartUtils.normalizedAngleFromAngle(newValue)
|
||||
setNeedsDisplay()
|
||||
}
|
||||
}
|
||||
|
||||
/// gets the raw version of the current rotation angle of the pie chart the returned value could be any value, negative or positive, outside of the 360 degrees.
|
||||
/// this is used when working with rotation direction, mainly by gestures and animations.
|
||||
public var rawRotationAngle: CGFloat
|
||||
{
|
||||
return _rawRotationAngle
|
||||
}
|
||||
|
||||
/// - returns: the diameter of the pie- or radar-chart
|
||||
public var diameter: CGFloat
|
||||
{
|
||||
let content = _viewPortHandler.contentRect
|
||||
return min(content.width, content.height)
|
||||
}
|
||||
|
||||
/// - returns: the radius of the chart in pixels.
|
||||
public var radius: CGFloat
|
||||
{
|
||||
fatalError("radius cannot be called on PieRadarChartViewBase")
|
||||
}
|
||||
|
||||
/// - returns: the required offset for the chart legend.
|
||||
internal var requiredLegendOffset: CGFloat
|
||||
{
|
||||
fatalError("requiredLegendOffset cannot be called on PieRadarChartViewBase")
|
||||
}
|
||||
|
||||
/// - returns: the base offset needed for the chart without calculating the
|
||||
/// legend size.
|
||||
internal var requiredBaseOffset: CGFloat
|
||||
{
|
||||
fatalError("requiredBaseOffset cannot be called on PieRadarChartViewBase")
|
||||
}
|
||||
|
||||
public override var chartXMax: Double
|
||||
{
|
||||
return 0.0
|
||||
}
|
||||
|
||||
public override var chartXMin: Double
|
||||
{
|
||||
getSelectionDetailsAtIndex(1);
|
||||
return 0.0
|
||||
}
|
||||
|
||||
/// The SelectionDetail objects give information about the value at the selected index and the DataSet it belongs to.
|
||||
/// - returns: an array of SelectionDetail objects for the given x-index.
|
||||
public func getSelectionDetailsAtIndex(xIndex: Int) -> [ChartSelectionDetail]
|
||||
{
|
||||
var vals = [ChartSelectionDetail]()
|
||||
|
||||
for (var i = 0; i < _data.dataSetCount; i++)
|
||||
{
|
||||
let dataSet = _data.getDataSetByIndex(i)
|
||||
if (dataSet === nil || !dataSet.isHighlightEnabled)
|
||||
{
|
||||
continue
|
||||
}
|
||||
|
||||
// extract all y-values from all DataSets at the given x-index
|
||||
let yVal = dataSet!.yValForXIndex(xIndex)
|
||||
if (yVal.isNaN)
|
||||
{
|
||||
continue
|
||||
}
|
||||
|
||||
vals.append(ChartSelectionDetail(value: yVal, dataSetIndex: i, dataSet: dataSet!))
|
||||
}
|
||||
|
||||
return vals
|
||||
}
|
||||
|
||||
public var isRotationEnabled: Bool { return rotationEnabled; }
|
||||
|
||||
/// flag that indicates if rotation is done with two fingers or one.
|
||||
/// when the chart is inside a scrollview, you need a two-finger rotation because a one-finger rotation eats up all touch events.
|
||||
///
|
||||
/// **default**: false
|
||||
public var rotationWithTwoFingers: Bool
|
||||
{
|
||||
get
|
||||
{
|
||||
return _rotationWithTwoFingers
|
||||
}
|
||||
set
|
||||
{
|
||||
_rotationWithTwoFingers = newValue
|
||||
#if !os(tvOS)
|
||||
_rotationGestureRecognizer.enabled = _rotationWithTwoFingers
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/// flag that indicates if rotation is done with two fingers or one.
|
||||
/// when the chart is inside a scrollview, you need a two-finger rotation because a one-finger rotation eats up all touch events.
|
||||
///
|
||||
/// **default**: false
|
||||
public var isRotationWithTwoFingers: Bool
|
||||
{
|
||||
return _rotationWithTwoFingers
|
||||
}
|
||||
|
||||
// MARK: - Animation
|
||||
|
||||
private var _spinAnimator: ChartAnimator!
|
||||
|
||||
/// Applys a spin animation to the Chart.
|
||||
public func spin(duration duration: NSTimeInterval, fromAngle: CGFloat, toAngle: CGFloat, easing: ChartEasingFunctionBlock?)
|
||||
{
|
||||
if (_spinAnimator != nil)
|
||||
{
|
||||
_spinAnimator.stop()
|
||||
}
|
||||
|
||||
_spinAnimator = ChartAnimator()
|
||||
_spinAnimator.updateBlock = {
|
||||
self.rotationAngle = (toAngle - fromAngle) * self._spinAnimator.phaseX + fromAngle
|
||||
}
|
||||
_spinAnimator.stopBlock = { self._spinAnimator = nil; }
|
||||
|
||||
_spinAnimator.animate(xAxisDuration: duration, easing: easing)
|
||||
}
|
||||
|
||||
public func spin(duration duration: NSTimeInterval, fromAngle: CGFloat, toAngle: CGFloat, easingOption: ChartEasingOption)
|
||||
{
|
||||
spin(duration: duration, fromAngle: fromAngle, toAngle: toAngle, easing: easingFunctionFromOption(easingOption))
|
||||
}
|
||||
|
||||
public func spin(duration duration: NSTimeInterval, fromAngle: CGFloat, toAngle: CGFloat)
|
||||
{
|
||||
spin(duration: duration, fromAngle: fromAngle, toAngle: toAngle, easing: nil)
|
||||
}
|
||||
|
||||
public func stopSpinAnimation()
|
||||
{
|
||||
if (_spinAnimator != nil)
|
||||
{
|
||||
_spinAnimator.stop()
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Gestures
|
||||
|
||||
private var _touchStartPoint: CGPoint!
|
||||
private var _isRotating = false
|
||||
private var _defaultTouchEventsWereEnabled = false
|
||||
private var _startAngle = CGFloat(0.0)
|
||||
|
||||
private struct AngularVelocitySample
|
||||
{
|
||||
var time: NSTimeInterval
|
||||
var angle: CGFloat
|
||||
}
|
||||
|
||||
private var _velocitySamples = [AngularVelocitySample]()
|
||||
|
||||
private var _decelerationLastTime: NSTimeInterval = 0.0
|
||||
private var _decelerationDisplayLink: CADisplayLink!
|
||||
private var _decelerationAngularVelocity: CGFloat = 0.0
|
||||
|
||||
public override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?)
|
||||
{
|
||||
// if rotation by touch is enabled
|
||||
if (rotationEnabled)
|
||||
{
|
||||
stopDeceleration()
|
||||
|
||||
if (!rotationWithTwoFingers)
|
||||
{
|
||||
let touch = touches.first as UITouch!
|
||||
|
||||
let touchLocation = touch.locationInView(self)
|
||||
|
||||
self.resetVelocity()
|
||||
|
||||
if (rotationEnabled)
|
||||
{
|
||||
self.sampleVelocity(touchLocation: touchLocation)
|
||||
}
|
||||
|
||||
self.setGestureStartAngle(x: touchLocation.x, y: touchLocation.y)
|
||||
|
||||
_touchStartPoint = touchLocation
|
||||
}
|
||||
}
|
||||
|
||||
if (!_isRotating)
|
||||
{
|
||||
super.touchesBegan(touches, withEvent: event)
|
||||
}
|
||||
}
|
||||
|
||||
public override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?)
|
||||
{
|
||||
if (rotationEnabled && !rotationWithTwoFingers)
|
||||
{
|
||||
let touch = touches.first as UITouch!
|
||||
|
||||
let touchLocation = touch.locationInView(self)
|
||||
|
||||
if (isDragDecelerationEnabled)
|
||||
{
|
||||
sampleVelocity(touchLocation: touchLocation)
|
||||
}
|
||||
|
||||
if (!_isRotating && distance(eventX: touchLocation.x, startX: _touchStartPoint.x, eventY: touchLocation.y, startY: _touchStartPoint.y) > CGFloat(8.0))
|
||||
{
|
||||
_isRotating = true
|
||||
}
|
||||
else
|
||||
{
|
||||
self.updateGestureRotation(x: touchLocation.x, y: touchLocation.y)
|
||||
setNeedsDisplay()
|
||||
}
|
||||
}
|
||||
|
||||
if (!_isRotating)
|
||||
{
|
||||
super.touchesMoved(touches, withEvent: event)
|
||||
}
|
||||
}
|
||||
|
||||
public override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?)
|
||||
{
|
||||
if (!_isRotating)
|
||||
{
|
||||
super.touchesEnded(touches, withEvent: event)
|
||||
}
|
||||
|
||||
if (rotationEnabled && !rotationWithTwoFingers)
|
||||
{
|
||||
let touch = touches.first as UITouch!
|
||||
|
||||
let touchLocation = touch.locationInView(self)
|
||||
|
||||
if (isDragDecelerationEnabled)
|
||||
{
|
||||
stopDeceleration()
|
||||
|
||||
sampleVelocity(touchLocation: touchLocation)
|
||||
|
||||
_decelerationAngularVelocity = calculateVelocity()
|
||||
|
||||
if (_decelerationAngularVelocity != 0.0)
|
||||
{
|
||||
_decelerationLastTime = CACurrentMediaTime()
|
||||
_decelerationDisplayLink = CADisplayLink(target: self, selector: Selector("decelerationLoop"))
|
||||
_decelerationDisplayLink.addToRunLoop(NSRunLoop.mainRunLoop(), forMode: NSRunLoopCommonModes)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_isRotating)
|
||||
{
|
||||
_isRotating = false
|
||||
}
|
||||
}
|
||||
|
||||
public override func touchesCancelled(touches: Set<UITouch>?, withEvent event: UIEvent?)
|
||||
{
|
||||
super.touchesCancelled(touches, withEvent: event)
|
||||
|
||||
if (_isRotating)
|
||||
{
|
||||
_isRotating = false
|
||||
}
|
||||
}
|
||||
|
||||
private func resetVelocity()
|
||||
{
|
||||
_velocitySamples.removeAll(keepCapacity: false)
|
||||
}
|
||||
|
||||
private func sampleVelocity(touchLocation touchLocation: CGPoint)
|
||||
{
|
||||
let currentTime = CACurrentMediaTime()
|
||||
|
||||
_velocitySamples.append(AngularVelocitySample(time: currentTime, angle: angleForPoint(x: touchLocation.x, y: touchLocation.y)))
|
||||
|
||||
// Remove samples older than our sample time - 1 seconds
|
||||
for (var i = 0, count = _velocitySamples.count; i < count - 2; i++)
|
||||
{
|
||||
if (currentTime - _velocitySamples[i].time > 1.0)
|
||||
{
|
||||
_velocitySamples.removeAtIndex(0)
|
||||
i--
|
||||
count--
|
||||
}
|
||||
else
|
||||
{
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func calculateVelocity() -> CGFloat
|
||||
{
|
||||
if (_velocitySamples.isEmpty)
|
||||
{
|
||||
return 0.0
|
||||
}
|
||||
|
||||
var firstSample = _velocitySamples[0]
|
||||
var lastSample = _velocitySamples[_velocitySamples.count - 1]
|
||||
|
||||
// Look for a sample that's closest to the latest sample, but not the same, so we can deduce the direction
|
||||
var beforeLastSample = firstSample
|
||||
for (var i = _velocitySamples.count - 1; i >= 0; i--)
|
||||
{
|
||||
beforeLastSample = _velocitySamples[i]
|
||||
if (beforeLastSample.angle != lastSample.angle)
|
||||
{
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate the sampling time
|
||||
var timeDelta = lastSample.time - firstSample.time
|
||||
if (timeDelta == 0.0)
|
||||
{
|
||||
timeDelta = 0.1
|
||||
}
|
||||
|
||||
// Calculate clockwise/ccw by choosing two values that should be closest to each other,
|
||||
// so if the angles are two far from each other we know they are inverted "for sure"
|
||||
var clockwise = lastSample.angle >= beforeLastSample.angle
|
||||
if (abs(lastSample.angle - beforeLastSample.angle) > 270.0)
|
||||
{
|
||||
clockwise = !clockwise
|
||||
}
|
||||
|
||||
// Now if the "gesture" is over a too big of an angle - then we know the angles are inverted, and we need to move them closer to each other from both sides of the 360.0 wrapping point
|
||||
if (lastSample.angle - firstSample.angle > 180.0)
|
||||
{
|
||||
firstSample.angle += 360.0
|
||||
}
|
||||
else if (firstSample.angle - lastSample.angle > 180.0)
|
||||
{
|
||||
lastSample.angle += 360.0
|
||||
}
|
||||
|
||||
// The velocity
|
||||
var velocity = abs((lastSample.angle - firstSample.angle) / CGFloat(timeDelta))
|
||||
|
||||
// Direction?
|
||||
if (!clockwise)
|
||||
{
|
||||
velocity = -velocity
|
||||
}
|
||||
|
||||
return velocity
|
||||
}
|
||||
|
||||
/// sets the starting angle of the rotation, this is only used by the touch listener, x and y is the touch position
|
||||
private func setGestureStartAngle(x x: CGFloat, y: CGFloat)
|
||||
{
|
||||
_startAngle = angleForPoint(x: x, y: y)
|
||||
|
||||
// take the current angle into consideration when starting a new drag
|
||||
_startAngle -= _rotationAngle
|
||||
}
|
||||
|
||||
/// updates the view rotation depending on the given touch position, also takes the starting angle into consideration
|
||||
private func updateGestureRotation(x x: CGFloat, y: CGFloat)
|
||||
{
|
||||
self.rotationAngle = angleForPoint(x: x, y: y) - _startAngle
|
||||
}
|
||||
|
||||
public func stopDeceleration()
|
||||
{
|
||||
if (_decelerationDisplayLink !== nil)
|
||||
{
|
||||
_decelerationDisplayLink.removeFromRunLoop(NSRunLoop.mainRunLoop(), forMode: NSRunLoopCommonModes)
|
||||
_decelerationDisplayLink = nil
|
||||
}
|
||||
}
|
||||
|
||||
@objc private func decelerationLoop()
|
||||
{
|
||||
let currentTime = CACurrentMediaTime()
|
||||
|
||||
_decelerationAngularVelocity *= self.dragDecelerationFrictionCoef
|
||||
|
||||
let timeInterval = CGFloat(currentTime - _decelerationLastTime)
|
||||
|
||||
self.rotationAngle += _decelerationAngularVelocity * timeInterval
|
||||
|
||||
_decelerationLastTime = currentTime
|
||||
|
||||
if(abs(_decelerationAngularVelocity) < 0.001)
|
||||
{
|
||||
stopDeceleration()
|
||||
}
|
||||
}
|
||||
|
||||
/// - returns: the distance between two points
|
||||
private func distance(eventX eventX: CGFloat, startX: CGFloat, eventY: CGFloat, startY: CGFloat) -> CGFloat
|
||||
{
|
||||
let dx = eventX - startX
|
||||
let dy = eventY - startY
|
||||
return sqrt(dx * dx + dy * dy)
|
||||
}
|
||||
|
||||
/// - returns: the distance between two points
|
||||
private func distance(from from: CGPoint, to: CGPoint) -> CGFloat
|
||||
{
|
||||
let dx = from.x - to.x
|
||||
let dy = from.y - to.y
|
||||
return sqrt(dx * dx + dy * dy)
|
||||
}
|
||||
|
||||
/// reference to the last highlighted object
|
||||
private var _lastHighlight: ChartHighlight!
|
||||
|
||||
@objc private func tapGestureRecognized(recognizer: UITapGestureRecognizer)
|
||||
{
|
||||
if (recognizer.state == UIGestureRecognizerState.Ended)
|
||||
{
|
||||
let location = recognizer.locationInView(self)
|
||||
let distance = distanceToCenter(x: location.x, y: location.y)
|
||||
|
||||
// check if a slice was touched
|
||||
if (distance > self.radius)
|
||||
{
|
||||
// if no slice was touched, highlight nothing
|
||||
self.highlightValues(nil)
|
||||
_lastHighlight = nil
|
||||
_lastHighlight = nil
|
||||
}
|
||||
else
|
||||
{
|
||||
var angle = angleForPoint(x: location.x, y: location.y)
|
||||
|
||||
if (self.isKindOfClass(PieChartView))
|
||||
{
|
||||
angle /= _animator.phaseY
|
||||
}
|
||||
|
||||
let index = indexForAngle(angle)
|
||||
|
||||
// check if the index could be found
|
||||
if (index < 0)
|
||||
{
|
||||
self.highlightValues(nil)
|
||||
_lastHighlight = nil
|
||||
}
|
||||
else
|
||||
{
|
||||
let valsAtIndex = getSelectionDetailsAtIndex(index)
|
||||
|
||||
var dataSetIndex = 0
|
||||
|
||||
// get the dataset that is closest to the selection (PieChart only has one DataSet)
|
||||
if (self.isKindOfClass(RadarChartView))
|
||||
{
|
||||
dataSetIndex = ChartUtils.closestDataSetIndex(valsAtIndex, value: Double(distance / (self as! RadarChartView).factor), axis: nil)
|
||||
}
|
||||
|
||||
if (dataSetIndex < 0)
|
||||
{
|
||||
self.highlightValues(nil)
|
||||
_lastHighlight = nil
|
||||
}
|
||||
else
|
||||
{
|
||||
let h = ChartHighlight(xIndex: index, dataSetIndex: dataSetIndex)
|
||||
|
||||
if (_lastHighlight !== nil && h == _lastHighlight)
|
||||
{
|
||||
self.highlightValue(highlight: nil, callDelegate: true)
|
||||
_lastHighlight = nil
|
||||
}
|
||||
else
|
||||
{
|
||||
self.highlightValue(highlight: h, callDelegate: true)
|
||||
_lastHighlight = h
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if !os(tvOS)
|
||||
@objc private func rotationGestureRecognized(recognizer: UIRotationGestureRecognizer)
|
||||
{
|
||||
if (recognizer.state == UIGestureRecognizerState.Began)
|
||||
{
|
||||
stopDeceleration()
|
||||
|
||||
_startAngle = self.rawRotationAngle
|
||||
}
|
||||
|
||||
if (recognizer.state == UIGestureRecognizerState.Began || recognizer.state == UIGestureRecognizerState.Changed)
|
||||
{
|
||||
let angle = ChartUtils.Math.FRAD2DEG * recognizer.rotation
|
||||
|
||||
self.rotationAngle = _startAngle + angle
|
||||
setNeedsDisplay()
|
||||
}
|
||||
else if (recognizer.state == UIGestureRecognizerState.Ended)
|
||||
{
|
||||
let angle = ChartUtils.Math.FRAD2DEG * recognizer.rotation
|
||||
|
||||
self.rotationAngle = _startAngle + angle
|
||||
setNeedsDisplay()
|
||||
|
||||
if (isDragDecelerationEnabled)
|
||||
{
|
||||
stopDeceleration()
|
||||
|
||||
_decelerationAngularVelocity = ChartUtils.Math.FRAD2DEG * recognizer.velocity
|
||||
|
||||
if (_decelerationAngularVelocity != 0.0)
|
||||
{
|
||||
_decelerationLastTime = CACurrentMediaTime()
|
||||
_decelerationDisplayLink = CADisplayLink(target: self, selector: Selector("decelerationLoop"))
|
||||
_decelerationDisplayLink.addToRunLoop(NSRunLoop.mainRunLoop(), forMode: NSRunLoopCommonModes)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
283
Carthage/Checkouts/Charts/Charts/Classes/Charts/RadarChartView.swift
vendored
Normal file
283
Carthage/Checkouts/Charts/Charts/Classes/Charts/RadarChartView.swift
vendored
Normal file
@@ -0,0 +1,283 @@
|
||||
//
|
||||
// RadarChartView.swift
|
||||
// Charts
|
||||
//
|
||||
// Created by Daniel Cohen Gindi on 4/3/15.
|
||||
//
|
||||
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
|
||||
// A port of MPAndroidChart for iOS
|
||||
// Licensed under Apache License 2.0
|
||||
//
|
||||
// https://github.com/danielgindi/ios-charts
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import CoreGraphics
|
||||
import UIKit
|
||||
|
||||
/// Implementation of the RadarChart, a "spidernet"-like chart. It works best
|
||||
/// when displaying 5-10 entries per DataSet.
|
||||
public class RadarChartView: PieRadarChartViewBase
|
||||
{
|
||||
/// width of the web lines that come from the center.
|
||||
public var webLineWidth = CGFloat(1.5)
|
||||
|
||||
/// width of the web lines that are in between the lines coming from the center
|
||||
public var innerWebLineWidth = CGFloat(0.75)
|
||||
|
||||
/// color for the web lines that come from the center
|
||||
public var webColor = UIColor(red: 122/255.0, green: 122/255.0, blue: 122.0/255.0, alpha: 1.0)
|
||||
|
||||
/// color for the web lines in between the lines that come from the center.
|
||||
public var innerWebColor = UIColor(red: 122/255.0, green: 122/255.0, blue: 122.0/255.0, alpha: 1.0)
|
||||
|
||||
/// transparency the grid is drawn with (0.0 - 1.0)
|
||||
public var webAlpha: CGFloat = 150.0 / 255.0
|
||||
|
||||
/// flag indicating if the web lines should be drawn or not
|
||||
public var drawWeb = true
|
||||
|
||||
/// modulus that determines how many labels and web-lines are skipped before the next is drawn
|
||||
private var _skipWebLineCount = 1
|
||||
|
||||
/// the object reprsenting the y-axis labels
|
||||
private var _yAxis: ChartYAxis!
|
||||
|
||||
/// the object representing the x-axis labels
|
||||
private var _xAxis: ChartXAxis!
|
||||
|
||||
internal var _yAxisRenderer: ChartYAxisRendererRadarChart!
|
||||
internal var _xAxisRenderer: ChartXAxisRendererRadarChart!
|
||||
|
||||
public override init(frame: CGRect)
|
||||
{
|
||||
super.init(frame: frame)
|
||||
}
|
||||
|
||||
public required init?(coder aDecoder: NSCoder)
|
||||
{
|
||||
super.init(coder: aDecoder)
|
||||
}
|
||||
|
||||
internal override func initialize()
|
||||
{
|
||||
super.initialize()
|
||||
|
||||
_yAxis = ChartYAxis(position: .Left)
|
||||
_xAxis = ChartXAxis()
|
||||
_xAxis.spaceBetweenLabels = 0
|
||||
|
||||
renderer = RadarChartRenderer(chart: self, animator: _animator, viewPortHandler: _viewPortHandler)
|
||||
|
||||
_yAxisRenderer = ChartYAxisRendererRadarChart(viewPortHandler: _viewPortHandler, yAxis: _yAxis, chart: self)
|
||||
_xAxisRenderer = ChartXAxisRendererRadarChart(viewPortHandler: _viewPortHandler, xAxis: _xAxis, chart: self)
|
||||
}
|
||||
|
||||
internal override func calcMinMax()
|
||||
{
|
||||
super.calcMinMax()
|
||||
|
||||
let minLeft = _data.getYMin(.Left)
|
||||
let maxLeft = _data.getYMax(.Left)
|
||||
|
||||
_chartXMax = Double(_data.xVals.count) - 1.0
|
||||
_deltaX = CGFloat(abs(_chartXMax - _chartXMin))
|
||||
|
||||
let leftRange = CGFloat(abs(maxLeft - (_yAxis.isStartAtZeroEnabled ? 0.0 : minLeft)))
|
||||
|
||||
let topSpaceLeft = Double(leftRange * _yAxis.spaceTop)
|
||||
let bottomSpaceLeft = Double(leftRange * _yAxis.spaceBottom)
|
||||
|
||||
// Consider sticking one of the edges of the axis to zero (0.0)
|
||||
|
||||
if _yAxis.isStartAtZeroEnabled
|
||||
{
|
||||
if minLeft < 0.0 && maxLeft < 0.0
|
||||
{
|
||||
// If the values are all negative, let's stay in the negative zone
|
||||
_yAxis.axisMinimum = min(0.0, !isnan(_yAxis.customAxisMin) ? _yAxis.customAxisMin : (minLeft - bottomSpaceLeft))
|
||||
_yAxis.axisMaximum = 0.0
|
||||
}
|
||||
else if minLeft >= 0.0
|
||||
{
|
||||
// We have positive values only, stay in the positive zone
|
||||
_yAxis.axisMinimum = 0.0
|
||||
_yAxis.axisMaximum = max(0.0, !isnan(_yAxis.customAxisMax) ? _yAxis.customAxisMax : (maxLeft + topSpaceLeft))
|
||||
}
|
||||
else
|
||||
{
|
||||
// Stick the minimum to 0.0 or less, and maximum to 0.0 or more (startAtZero for negative/positive at the same time)
|
||||
_yAxis.axisMinimum = min(0.0, !isnan(_yAxis.customAxisMin) ? _yAxis.customAxisMin : (minLeft - bottomSpaceLeft))
|
||||
_yAxis.axisMaximum = max(0.0, !isnan(_yAxis.customAxisMax) ? _yAxis.customAxisMax : (maxLeft + topSpaceLeft))
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Use the values as they are
|
||||
_yAxis.axisMinimum = !isnan(_yAxis.customAxisMin) ? _yAxis.customAxisMin : (minLeft - bottomSpaceLeft)
|
||||
_yAxis.axisMaximum = !isnan(_yAxis.customAxisMax) ? _yAxis.customAxisMax : (maxLeft + topSpaceLeft)
|
||||
}
|
||||
|
||||
_chartXMax = Double(_data.xVals.count) - 1.0
|
||||
_deltaX = CGFloat(abs(_chartXMax - _chartXMin))
|
||||
|
||||
_yAxis.axisRange = abs(_yAxis.axisMaximum - _yAxis.axisMinimum)
|
||||
}
|
||||
|
||||
public override func getMarkerPosition(entry entry: ChartDataEntry, highlight: ChartHighlight) -> CGPoint
|
||||
{
|
||||
let angle = self.sliceAngle * CGFloat(entry.xIndex) + self.rotationAngle
|
||||
let val = CGFloat(entry.value) * self.factor
|
||||
let c = self.centerOffsets
|
||||
|
||||
let p = CGPoint(x: c.x + val * cos(angle * ChartUtils.Math.FDEG2RAD),
|
||||
y: c.y + val * sin(angle * ChartUtils.Math.FDEG2RAD))
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
public override func notifyDataSetChanged()
|
||||
{
|
||||
if (_dataNotSet)
|
||||
{
|
||||
return
|
||||
}
|
||||
|
||||
calcMinMax()
|
||||
|
||||
_yAxis?._defaultValueFormatter = _defaultValueFormatter
|
||||
|
||||
_yAxisRenderer?.computeAxis(yMin: _yAxis.axisMinimum, yMax: _yAxis.axisMaximum)
|
||||
_xAxisRenderer?.computeAxis(xValAverageLength: _data.xValAverageLength, xValues: _data.xVals)
|
||||
|
||||
if (_legend !== nil && !_legend.isLegendCustom)
|
||||
{
|
||||
_legendRenderer?.computeLegend(_data)
|
||||
}
|
||||
|
||||
calculateOffsets()
|
||||
|
||||
setNeedsDisplay()
|
||||
}
|
||||
|
||||
public override func drawRect(rect: CGRect)
|
||||
{
|
||||
super.drawRect(rect)
|
||||
|
||||
if (_dataNotSet)
|
||||
{
|
||||
return
|
||||
}
|
||||
|
||||
let context = UIGraphicsGetCurrentContext()
|
||||
|
||||
_xAxisRenderer?.renderAxisLabels(context: context)
|
||||
|
||||
if (drawWeb)
|
||||
{
|
||||
renderer!.drawExtras(context: context)
|
||||
}
|
||||
|
||||
_yAxisRenderer.renderLimitLines(context: context)
|
||||
|
||||
renderer!.drawData(context: context)
|
||||
|
||||
if (valuesToHighlight())
|
||||
{
|
||||
renderer!.drawHighlighted(context: context, indices: _indicesToHightlight)
|
||||
}
|
||||
|
||||
_yAxisRenderer.renderAxisLabels(context: context)
|
||||
|
||||
renderer!.drawValues(context: context)
|
||||
|
||||
_legendRenderer.renderLegend(context: context)
|
||||
|
||||
drawDescription(context: context)
|
||||
|
||||
drawMarkers(context: context)
|
||||
}
|
||||
|
||||
/// - returns: the factor that is needed to transform values into pixels.
|
||||
public var factor: CGFloat
|
||||
{
|
||||
let content = _viewPortHandler.contentRect
|
||||
return min(content.width / 2.0, content.height / 2.0)
|
||||
/ CGFloat(_yAxis.axisRange)
|
||||
}
|
||||
|
||||
/// - returns: the angle that each slice in the radar chart occupies.
|
||||
public var sliceAngle: CGFloat
|
||||
{
|
||||
return 360.0 / CGFloat(_data.xValCount)
|
||||
}
|
||||
|
||||
public override func indexForAngle(angle: CGFloat) -> Int
|
||||
{
|
||||
// take the current angle of the chart into consideration
|
||||
let a = ChartUtils.normalizedAngleFromAngle(angle - self.rotationAngle)
|
||||
|
||||
let sliceAngle = self.sliceAngle
|
||||
|
||||
for (var i = 0; i < _data.xValCount; i++)
|
||||
{
|
||||
if (sliceAngle * CGFloat(i + 1) - sliceAngle / 2.0 > a)
|
||||
{
|
||||
return i
|
||||
}
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
/// - returns: the object that represents all y-labels of the RadarChart.
|
||||
public var yAxis: ChartYAxis
|
||||
{
|
||||
return _yAxis
|
||||
}
|
||||
|
||||
/// - returns: the object that represents all x-labels that are placed around the RadarChart.
|
||||
public var xAxis: ChartXAxis
|
||||
{
|
||||
return _xAxis
|
||||
}
|
||||
|
||||
/// Sets the number of web-lines that should be skipped on chart web before the next one is drawn. This targets the lines that come from the center of the RadarChart.
|
||||
/// if count = 1 -> 1 line is skipped in between
|
||||
public var skipWebLineCount: Int
|
||||
{
|
||||
get
|
||||
{
|
||||
return _skipWebLineCount
|
||||
}
|
||||
set
|
||||
{
|
||||
_skipWebLineCount = max(0, newValue)
|
||||
}
|
||||
}
|
||||
|
||||
internal override var requiredLegendOffset: CGFloat
|
||||
{
|
||||
return _legend.font.pointSize * 4.0
|
||||
}
|
||||
|
||||
internal override var requiredBaseOffset: CGFloat
|
||||
{
|
||||
return _xAxis.isEnabled && _xAxis.isDrawLabelsEnabled ? _xAxis.labelWidth : 10.0
|
||||
}
|
||||
|
||||
public override var radius: CGFloat
|
||||
{
|
||||
let content = _viewPortHandler.contentRect
|
||||
return min(content.width / 2.0, content.height / 2.0)
|
||||
}
|
||||
|
||||
/// - returns: the maximum value this chart can display on it's y-axis.
|
||||
public override var chartYMax: Double { return _yAxis.axisMaximum; }
|
||||
|
||||
/// - returns: the minimum value this chart can display on it's y-axis.
|
||||
public override var chartYMin: Double { return _yAxis.axisMinimum; }
|
||||
|
||||
/// - returns: the range of y-values this chart can display.
|
||||
public var yRange: Double { return _yAxis.axisRange}
|
||||
}
|
||||
82
Carthage/Checkouts/Charts/Charts/Classes/Charts/ScatterChartView.swift
vendored
Normal file
82
Carthage/Checkouts/Charts/Charts/Classes/Charts/ScatterChartView.swift
vendored
Normal file
@@ -0,0 +1,82 @@
|
||||
//
|
||||
// ScatterChartView.swift
|
||||
// Charts
|
||||
//
|
||||
// Created by Daniel Cohen Gindi on 4/3/15.
|
||||
//
|
||||
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
|
||||
// A port of MPAndroidChart for iOS
|
||||
// Licensed under Apache License 2.0
|
||||
//
|
||||
// https://github.com/danielgindi/ios-charts
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import CoreGraphics
|
||||
|
||||
/// The ScatterChart. Draws dots, triangles, squares and custom shapes into the chartview.
|
||||
public class ScatterChartView: BarLineChartViewBase, ScatterChartRendererDelegate
|
||||
{
|
||||
public override func initialize()
|
||||
{
|
||||
super.initialize()
|
||||
|
||||
renderer = ScatterChartRenderer(delegate: self, animator: _animator, viewPortHandler: _viewPortHandler)
|
||||
_chartXMin = -0.5
|
||||
}
|
||||
|
||||
public override func calcMinMax()
|
||||
{
|
||||
super.calcMinMax()
|
||||
|
||||
if (_deltaX == 0.0 && _data.yValCount > 0)
|
||||
{
|
||||
_deltaX = 1.0
|
||||
}
|
||||
|
||||
_chartXMax += 0.5
|
||||
_deltaX = CGFloat(abs(_chartXMax - _chartXMin))
|
||||
}
|
||||
|
||||
// MARK: - ScatterChartRendererDelegate
|
||||
|
||||
public func scatterChartRendererData(renderer: ScatterChartRenderer) -> ScatterChartData!
|
||||
{
|
||||
return _data as! ScatterChartData!
|
||||
}
|
||||
|
||||
public func scatterChartRenderer(renderer: ScatterChartRenderer, transformerForAxis which: ChartYAxis.AxisDependency) -> ChartTransformer!
|
||||
{
|
||||
return getTransformer(which)
|
||||
}
|
||||
|
||||
public func scatterChartDefaultRendererValueFormatter(renderer: ScatterChartRenderer) -> NSNumberFormatter!
|
||||
{
|
||||
return self._defaultValueFormatter
|
||||
}
|
||||
|
||||
public func scatterChartRendererChartYMax(renderer: ScatterChartRenderer) -> Double
|
||||
{
|
||||
return self.chartYMax
|
||||
}
|
||||
|
||||
public func scatterChartRendererChartYMin(renderer: ScatterChartRenderer) -> Double
|
||||
{
|
||||
return self.chartYMin
|
||||
}
|
||||
|
||||
public func scatterChartRendererChartXMax(renderer: ScatterChartRenderer) -> Double
|
||||
{
|
||||
return self.chartXMax
|
||||
}
|
||||
|
||||
public func scatterChartRendererChartXMin(renderer: ScatterChartRenderer) -> Double
|
||||
{
|
||||
return self.chartXMin
|
||||
}
|
||||
|
||||
public func scatterChartRendererMaxVisibleValueCount(renderer: ScatterChartRenderer) -> Int
|
||||
{
|
||||
return self.maxVisibleValueCount
|
||||
}
|
||||
}
|
||||
106
Carthage/Checkouts/Charts/Charts/Classes/Components/ChartAxisBase.swift
vendored
Normal file
106
Carthage/Checkouts/Charts/Charts/Classes/Components/ChartAxisBase.swift
vendored
Normal file
@@ -0,0 +1,106 @@
|
||||
//
|
||||
// ChartAxisBase.swift
|
||||
// Charts
|
||||
//
|
||||
// Created by Daniel Cohen Gindi on 23/2/15.
|
||||
|
||||
//
|
||||
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
|
||||
// A port of MPAndroidChart for iOS
|
||||
// Licensed under Apache License 2.0
|
||||
//
|
||||
// https://github.com/danielgindi/ios-charts
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import UIKit
|
||||
|
||||
public class ChartAxisBase: ChartComponentBase
|
||||
{
|
||||
public var labelFont = UIFont.systemFontOfSize(10.0)
|
||||
public var labelTextColor = UIColor.blackColor()
|
||||
|
||||
public var axisLineColor = UIColor.grayColor()
|
||||
public var axisLineWidth = CGFloat(0.5)
|
||||
public var axisLineDashPhase = CGFloat(0.0)
|
||||
public var axisLineDashLengths: [CGFloat]!
|
||||
|
||||
public var gridColor = UIColor.grayColor().colorWithAlphaComponent(0.9)
|
||||
public var gridLineWidth = CGFloat(0.5)
|
||||
public var gridLineDashPhase = CGFloat(0.0)
|
||||
public var gridLineDashLengths: [CGFloat]!
|
||||
|
||||
public var drawGridLinesEnabled = true
|
||||
public var drawAxisLineEnabled = true
|
||||
|
||||
/// flag that indicates of the labels of this axis should be drawn or not
|
||||
public var drawLabelsEnabled = true
|
||||
|
||||
/// Sets the used x-axis offset for the labels on this axis.
|
||||
/// **default**: 5.0
|
||||
public var xOffset = CGFloat(5.0)
|
||||
|
||||
/// Sets the used y-axis offset for the labels on this axis.
|
||||
/// **default**: 5.0 (or 0.0 on ChartYAxis)
|
||||
public var yOffset = CGFloat(5.0)
|
||||
|
||||
/// array of limitlines that can be set for the axis
|
||||
private var _limitLines = [ChartLimitLine]()
|
||||
|
||||
/// Are the LimitLines drawn behind the data or in front of the data?
|
||||
///
|
||||
/// **default**: false
|
||||
public var drawLimitLinesBehindDataEnabled = false
|
||||
|
||||
public override init()
|
||||
{
|
||||
super.init()
|
||||
}
|
||||
|
||||
public func getLongestLabel() -> String
|
||||
{
|
||||
fatalError("getLongestLabel() cannot be called on ChartAxisBase")
|
||||
}
|
||||
|
||||
public var isDrawGridLinesEnabled: Bool { return drawGridLinesEnabled; }
|
||||
|
||||
public var isDrawAxisLineEnabled: Bool { return drawAxisLineEnabled; }
|
||||
|
||||
public var isDrawLabelsEnabled: Bool { return drawLabelsEnabled; }
|
||||
|
||||
/// Are the LimitLines drawn behind the data or in front of the data?
|
||||
///
|
||||
/// **default**: false
|
||||
public var isDrawLimitLinesBehindDataEnabled: Bool { return drawLimitLinesBehindDataEnabled; }
|
||||
|
||||
/// Adds a new ChartLimitLine to this axis.
|
||||
public func addLimitLine(line: ChartLimitLine)
|
||||
{
|
||||
_limitLines.append(line)
|
||||
}
|
||||
|
||||
/// Removes the specified ChartLimitLine from the axis.
|
||||
public func removeLimitLine(line: ChartLimitLine)
|
||||
{
|
||||
for (var i = 0; i < _limitLines.count; i++)
|
||||
{
|
||||
if (_limitLines[i] === line)
|
||||
{
|
||||
_limitLines.removeAtIndex(i)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Removes all LimitLines from the axis.
|
||||
public func removeAllLimitLines()
|
||||
{
|
||||
_limitLines.removeAll(keepCapacity: false)
|
||||
}
|
||||
|
||||
/// - returns: the LimitLines of this axis.
|
||||
public var limitLines : [ChartLimitLine]
|
||||
{
|
||||
return _limitLines
|
||||
}
|
||||
}
|
||||
29
Carthage/Checkouts/Charts/Charts/Classes/Components/ChartComponentBase.swift
vendored
Normal file
29
Carthage/Checkouts/Charts/Charts/Classes/Components/ChartComponentBase.swift
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
//
|
||||
// ChartComponentBase.swift
|
||||
// Charts
|
||||
//
|
||||
// Created by Daniel Cohen Gindi on 16/3/15.
|
||||
//
|
||||
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
|
||||
// A port of MPAndroidChart for iOS
|
||||
// Licensed under Apache License 2.0
|
||||
//
|
||||
// https://github.com/danielgindi/ios-charts
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import UIKit
|
||||
|
||||
/// This class encapsulates everything both Axis and Legend have in common.
|
||||
public class ChartComponentBase: NSObject
|
||||
{
|
||||
/// flag that indicates if this component is enabled or not
|
||||
public var enabled = true
|
||||
|
||||
public override init()
|
||||
{
|
||||
super.init()
|
||||
}
|
||||
|
||||
public var isEnabled: Bool { return enabled; }
|
||||
}
|
||||
462
Carthage/Checkouts/Charts/Charts/Classes/Components/ChartLegend.swift
vendored
Normal file
462
Carthage/Checkouts/Charts/Charts/Classes/Components/ChartLegend.swift
vendored
Normal file
@@ -0,0 +1,462 @@
|
||||
//
|
||||
// ChartLegend.swift
|
||||
// Charts
|
||||
//
|
||||
// Created by Daniel Cohen Gindi on 24/2/15.
|
||||
|
||||
//
|
||||
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
|
||||
// A port of MPAndroidChart for iOS
|
||||
// Licensed under Apache License 2.0
|
||||
//
|
||||
// https://github.com/danielgindi/ios-charts
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import UIKit
|
||||
|
||||
public class ChartLegend: ChartComponentBase
|
||||
{
|
||||
@objc
|
||||
public enum ChartLegendPosition: Int
|
||||
{
|
||||
case RightOfChart
|
||||
case RightOfChartCenter
|
||||
case RightOfChartInside
|
||||
case LeftOfChart
|
||||
case LeftOfChartCenter
|
||||
case LeftOfChartInside
|
||||
case BelowChartLeft
|
||||
case BelowChartRight
|
||||
case BelowChartCenter
|
||||
case AboveChartLeft
|
||||
case AboveChartRight
|
||||
case AboveChartCenter
|
||||
case PiechartCenter
|
||||
}
|
||||
|
||||
@objc
|
||||
public enum ChartLegendForm: Int
|
||||
{
|
||||
case Square
|
||||
case Circle
|
||||
case Line
|
||||
}
|
||||
|
||||
@objc
|
||||
public enum ChartLegendDirection: Int
|
||||
{
|
||||
case LeftToRight
|
||||
case RightToLeft
|
||||
}
|
||||
|
||||
/// the legend colors array, each color is for the form drawn at the same index
|
||||
public var colors = [UIColor?]()
|
||||
|
||||
// the legend text array. a nil label will start a group.
|
||||
public var labels = [String?]()
|
||||
|
||||
internal var _extraColors = [UIColor?]()
|
||||
internal var _extraLabels = [String?]()
|
||||
|
||||
/// colors that will be appended to the end of the colors array after calculating the legend.
|
||||
public var extraColors: [UIColor?] { return _extraColors; }
|
||||
|
||||
/// labels that will be appended to the end of the labels array after calculating the legend. a nil label will start a group.
|
||||
public var extraLabels: [String?] { return _extraLabels; }
|
||||
|
||||
/// Are the legend labels/colors a custom value or auto calculated? If false, then it's auto, if true, then custom.
|
||||
///
|
||||
/// **default**: false (automatic legend)
|
||||
private var _isLegendCustom = false
|
||||
|
||||
public var position = ChartLegendPosition.BelowChartLeft
|
||||
public var direction = ChartLegendDirection.LeftToRight
|
||||
|
||||
public var font: UIFont = UIFont.systemFontOfSize(10.0)
|
||||
public var textColor = UIColor.blackColor()
|
||||
|
||||
public var form = ChartLegendForm.Square
|
||||
public var formSize = CGFloat(8.0)
|
||||
public var formLineWidth = CGFloat(1.5)
|
||||
|
||||
public var xEntrySpace = CGFloat(6.0)
|
||||
public var yEntrySpace = CGFloat(0.0)
|
||||
public var formToTextSpace = CGFloat(5.0)
|
||||
public var stackSpace = CGFloat(3.0)
|
||||
|
||||
/// Sets the x offset fo the legend.
|
||||
/// Higher offset means the legend as a whole will be placed further away from the left/right.
|
||||
/// Positive value will move the legend to the right when LTR, and to the left when RTL.
|
||||
public var xOffset = CGFloat(5.0)
|
||||
|
||||
/// Sets the y offset fo the legend.
|
||||
/// Higher offset means the legend as a whole will be placed further away from the top.
|
||||
public var yOffset = CGFloat(7.0)
|
||||
|
||||
public var calculatedLabelSizes = [CGSize]()
|
||||
public var calculatedLabelBreakPoints = [Bool]()
|
||||
public var calculatedLineSizes = [CGSize]()
|
||||
|
||||
public override init()
|
||||
{
|
||||
super.init()
|
||||
}
|
||||
|
||||
public init(colors: [UIColor?], labels: [String?])
|
||||
{
|
||||
super.init()
|
||||
|
||||
self.colors = colors
|
||||
self.labels = labels
|
||||
}
|
||||
|
||||
public init(colors: [NSObject], labels: [NSObject])
|
||||
{
|
||||
super.init()
|
||||
|
||||
self.colorsObjc = colors
|
||||
self.labelsObjc = labels
|
||||
}
|
||||
|
||||
public func getMaximumEntrySize(font: UIFont) -> CGSize
|
||||
{
|
||||
var maxW = CGFloat(0.0)
|
||||
var maxH = CGFloat(0.0)
|
||||
|
||||
var labels = self.labels
|
||||
for (var i = 0; i < labels.count; i++)
|
||||
{
|
||||
if (labels[i] == nil)
|
||||
{
|
||||
continue
|
||||
}
|
||||
|
||||
let size = (labels[i] as NSString!).sizeWithAttributes([NSFontAttributeName: font])
|
||||
|
||||
if (size.width > maxW)
|
||||
{
|
||||
maxW = size.width
|
||||
}
|
||||
if (size.height > maxH)
|
||||
{
|
||||
maxH = size.height
|
||||
}
|
||||
}
|
||||
|
||||
return CGSize(
|
||||
width: maxW + formSize + formToTextSpace,
|
||||
height: maxH
|
||||
)
|
||||
}
|
||||
|
||||
public func getLabel(index: Int) -> String?
|
||||
{
|
||||
return labels[index]
|
||||
}
|
||||
|
||||
public func getFullSize(labelFont: UIFont) -> CGSize
|
||||
{
|
||||
var width = CGFloat(0.0)
|
||||
var height = CGFloat(0.0)
|
||||
|
||||
var labels = self.labels
|
||||
for (var i = 0, count = labels.count; i < count; i++)
|
||||
{
|
||||
if (labels[i] != nil)
|
||||
{
|
||||
// make a step to the left
|
||||
if (colors[i] != nil)
|
||||
{
|
||||
width += formSize + formToTextSpace
|
||||
}
|
||||
|
||||
let size = (labels[i] as NSString!).sizeWithAttributes([NSFontAttributeName: labelFont])
|
||||
|
||||
width += size.width
|
||||
height += size.height
|
||||
|
||||
if (i < count - 1)
|
||||
{
|
||||
width += xEntrySpace
|
||||
height += yEntrySpace
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
width += formSize + stackSpace
|
||||
|
||||
if (i < count - 1)
|
||||
{
|
||||
width += stackSpace
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return CGSize(width: width, height: height)
|
||||
}
|
||||
|
||||
public var neededWidth = CGFloat(0.0)
|
||||
public var neededHeight = CGFloat(0.0)
|
||||
public var textWidthMax = CGFloat(0.0)
|
||||
public var textHeightMax = CGFloat(0.0)
|
||||
|
||||
/// flag that indicates if word wrapping is enabled
|
||||
/// this is currently supported only for: `BelowChartLeft`, `BelowChartRight`, `BelowChartCenter`.
|
||||
/// note that word wrapping a legend takes a toll on performance.
|
||||
/// you may want to set maxSizePercent when word wrapping, to set the point where the text wraps.
|
||||
///
|
||||
/// **default**: false
|
||||
public var wordWrapEnabled = false
|
||||
|
||||
/// if this is set, then word wrapping the legend is enabled.
|
||||
public var isWordWrapEnabled: Bool { return wordWrapEnabled }
|
||||
|
||||
/// The maximum relative size out of the whole chart view in percent.
|
||||
/// If the legend is to the right/left of the chart, then this affects the width of the legend.
|
||||
/// If the legend is to the top/bottom of the chart, then this affects the height of the legend.
|
||||
/// If the legend is the center of the piechart, then this defines the size of the rectangular bounds out of the size of the "hole".
|
||||
///
|
||||
/// **default**: 0.95 (95%)
|
||||
public var maxSizePercent: CGFloat = 0.95
|
||||
|
||||
public func calculateDimensions(labelFont labelFont: UIFont, viewPortHandler: ChartViewPortHandler)
|
||||
{
|
||||
if (position == .RightOfChart
|
||||
|| position == .RightOfChartCenter
|
||||
|| position == .LeftOfChart
|
||||
|| position == .LeftOfChartCenter
|
||||
|| position == .PiechartCenter)
|
||||
{
|
||||
let maxEntrySize = getMaximumEntrySize(labelFont)
|
||||
let fullSize = getFullSize(labelFont)
|
||||
|
||||
neededWidth = maxEntrySize.width
|
||||
neededHeight = fullSize.height
|
||||
textWidthMax = maxEntrySize.width
|
||||
textHeightMax = maxEntrySize.height
|
||||
}
|
||||
else if (position == .BelowChartLeft
|
||||
|| position == .BelowChartRight
|
||||
|| position == .BelowChartCenter
|
||||
|| position == .AboveChartLeft
|
||||
|| position == .AboveChartRight
|
||||
|| position == .AboveChartCenter)
|
||||
{
|
||||
var labels = self.labels
|
||||
var colors = self.colors
|
||||
let labelCount = labels.count
|
||||
|
||||
let labelLineHeight = labelFont.lineHeight
|
||||
let formSize = self.formSize
|
||||
let formToTextSpace = self.formToTextSpace
|
||||
let xEntrySpace = self.xEntrySpace
|
||||
let stackSpace = self.stackSpace
|
||||
let wordWrapEnabled = self.wordWrapEnabled
|
||||
|
||||
let contentWidth: CGFloat = viewPortHandler.contentWidth
|
||||
|
||||
// Prepare arrays for calculated layout
|
||||
if (calculatedLabelSizes.count != labelCount)
|
||||
{
|
||||
calculatedLabelSizes = [CGSize](count: labelCount, repeatedValue: CGSize())
|
||||
}
|
||||
|
||||
if (calculatedLabelBreakPoints.count != labelCount)
|
||||
{
|
||||
calculatedLabelBreakPoints = [Bool](count: labelCount, repeatedValue: false)
|
||||
}
|
||||
|
||||
calculatedLineSizes.removeAll(keepCapacity: true)
|
||||
|
||||
// Start calculating layout
|
||||
|
||||
let labelAttrs = [NSFontAttributeName: labelFont]
|
||||
var maxLineWidth: CGFloat = 0.0
|
||||
var currentLineWidth: CGFloat = 0.0
|
||||
var requiredWidth: CGFloat = 0.0
|
||||
var stackedStartIndex: Int = -1
|
||||
|
||||
for (var i = 0; i < labelCount; i++)
|
||||
{
|
||||
let drawingForm = colors[i] != nil
|
||||
|
||||
calculatedLabelBreakPoints[i] = false
|
||||
|
||||
if (stackedStartIndex == -1)
|
||||
{
|
||||
// we are not stacking, so required width is for this label only
|
||||
requiredWidth = 0.0
|
||||
}
|
||||
else
|
||||
{
|
||||
// add the spacing appropriate for stacked labels/forms
|
||||
requiredWidth += stackSpace
|
||||
}
|
||||
|
||||
// grouped forms have null labels
|
||||
if (labels[i] != nil)
|
||||
{
|
||||
calculatedLabelSizes[i] = (labels[i] as NSString!).sizeWithAttributes(labelAttrs)
|
||||
requiredWidth += drawingForm ? formToTextSpace + formSize : 0.0
|
||||
requiredWidth += calculatedLabelSizes[i].width
|
||||
}
|
||||
else
|
||||
{
|
||||
calculatedLabelSizes[i] = CGSize()
|
||||
requiredWidth += drawingForm ? formSize : 0.0
|
||||
|
||||
if (stackedStartIndex == -1)
|
||||
{
|
||||
// mark this index as we might want to break here later
|
||||
stackedStartIndex = i
|
||||
}
|
||||
}
|
||||
|
||||
if (labels[i] != nil || i == labelCount - 1)
|
||||
{
|
||||
let requiredSpacing = currentLineWidth == 0.0 ? 0.0 : xEntrySpace
|
||||
|
||||
if (!wordWrapEnabled || // No word wrapping, it must fit.
|
||||
currentLineWidth == 0.0 || // The line is empty, it must fit.
|
||||
(contentWidth - currentLineWidth >= requiredSpacing + requiredWidth)) // It simply fits
|
||||
{
|
||||
// Expand current line
|
||||
currentLineWidth += requiredSpacing + requiredWidth
|
||||
}
|
||||
else
|
||||
{ // It doesn't fit, we need to wrap a line
|
||||
|
||||
// Add current line size to array
|
||||
calculatedLineSizes.append(CGSize(width: currentLineWidth, height: labelLineHeight))
|
||||
maxLineWidth = max(maxLineWidth, currentLineWidth)
|
||||
|
||||
// Start a new line
|
||||
calculatedLabelBreakPoints[stackedStartIndex > -1 ? stackedStartIndex : i] = true
|
||||
currentLineWidth = requiredWidth
|
||||
}
|
||||
|
||||
if (i == labelCount - 1)
|
||||
{ // Add last line size to array
|
||||
calculatedLineSizes.append(CGSize(width: currentLineWidth, height: labelLineHeight))
|
||||
maxLineWidth = max(maxLineWidth, currentLineWidth)
|
||||
}
|
||||
}
|
||||
|
||||
stackedStartIndex = labels[i] != nil ? -1 : stackedStartIndex
|
||||
}
|
||||
|
||||
let maxEntrySize = getMaximumEntrySize(labelFont)
|
||||
|
||||
textWidthMax = maxEntrySize.width
|
||||
textHeightMax = maxEntrySize.height
|
||||
neededWidth = maxLineWidth
|
||||
neededHeight = labelLineHeight * CGFloat(calculatedLineSizes.count) +
|
||||
yEntrySpace * CGFloat(calculatedLineSizes.count == 0 ? 0 : (calculatedLineSizes.count - 1))
|
||||
}
|
||||
else
|
||||
{
|
||||
let maxEntrySize = getMaximumEntrySize(labelFont)
|
||||
let fullSize = getFullSize(labelFont)
|
||||
|
||||
/* RightOfChartInside, LeftOfChartInside */
|
||||
neededWidth = fullSize.width
|
||||
neededHeight = maxEntrySize.height
|
||||
textWidthMax = maxEntrySize.width
|
||||
textHeightMax = maxEntrySize.height
|
||||
}
|
||||
}
|
||||
|
||||
/// MARK: - Custom legend
|
||||
|
||||
/// colors and labels that will be appended to the end of the auto calculated colors and labels after calculating the legend.
|
||||
/// (if the legend has already been calculated, you will need to call notifyDataSetChanged() to let the changes take effect)
|
||||
public func setExtra(colors colors: [UIColor?], labels: [String?])
|
||||
{
|
||||
self._extraLabels = labels
|
||||
self._extraColors = colors
|
||||
}
|
||||
|
||||
/// Sets a custom legend's labels and colors arrays.
|
||||
/// The colors count should match the labels count.
|
||||
/// * Each color is for the form drawn at the same index.
|
||||
/// * A nil label will start a group.
|
||||
/// * A nil color will avoid drawing a form, and a clearColor will leave a space for the form.
|
||||
/// This will disable the feature that automatically calculates the legend labels and colors from the datasets.
|
||||
/// Call `resetCustom(...)` to re-enable automatic calculation (and then `notifyDataSetChanged()` is needed).
|
||||
public func setCustom(colors colors: [UIColor?], labels: [String?])
|
||||
{
|
||||
self.labels = labels
|
||||
self.colors = colors
|
||||
_isLegendCustom = true
|
||||
}
|
||||
|
||||
/// Calling this will disable the custom legend labels (set by `setLegend(...)`). Instead, the labels will again be calculated automatically (after `notifyDataSetChanged()` is called).
|
||||
public func resetCustom()
|
||||
{
|
||||
_isLegendCustom = false
|
||||
}
|
||||
|
||||
/// **default**: false (automatic legend)
|
||||
/// - returns: true if a custom legend labels and colors has been set
|
||||
public var isLegendCustom: Bool
|
||||
{
|
||||
return _isLegendCustom
|
||||
}
|
||||
|
||||
/// MARK: - ObjC compatibility
|
||||
|
||||
/// colors that will be appended to the end of the colors array after calculating the legend.
|
||||
public var extraColorsObjc: [NSObject] { return ChartUtils.bridgedObjCGetUIColorArray(swift: _extraColors); }
|
||||
|
||||
/// labels that will be appended to the end of the labels array after calculating the legend. a nil label will start a group.
|
||||
public var extraLabelsObjc: [NSObject] { return ChartUtils.bridgedObjCGetStringArray(swift: _extraLabels); }
|
||||
|
||||
/// the legend colors array, each color is for the form drawn at the same index
|
||||
/// (ObjC bridging functions, as Swift 1.2 does not bridge optionals in array to `NSNull`s)
|
||||
public var colorsObjc: [NSObject]
|
||||
{
|
||||
get { return ChartUtils.bridgedObjCGetUIColorArray(swift: colors); }
|
||||
set { self.colors = ChartUtils.bridgedObjCGetUIColorArray(objc: newValue); }
|
||||
}
|
||||
|
||||
// the legend text array. a nil label will start a group.
|
||||
/// (ObjC bridging functions, as Swift 1.2 does not bridge optionals in array to `NSNull`s)
|
||||
public var labelsObjc: [NSObject]
|
||||
{
|
||||
get { return ChartUtils.bridgedObjCGetStringArray(swift: labels); }
|
||||
set { self.labels = ChartUtils.bridgedObjCGetStringArray(objc: newValue); }
|
||||
}
|
||||
|
||||
/// colors and labels that will be appended to the end of the auto calculated colors and labels after calculating the legend.
|
||||
/// (if the legend has already been calculated, you will need to call `notifyDataSetChanged()` to let the changes take effect)
|
||||
public func setExtra(colors colors: [NSObject], labels: [NSObject])
|
||||
{
|
||||
if (colors.count != labels.count)
|
||||
{
|
||||
fatalError("ChartLegend:setExtra() - colors array and labels array need to be of same size")
|
||||
}
|
||||
|
||||
self._extraLabels = ChartUtils.bridgedObjCGetStringArray(objc: labels)
|
||||
self._extraColors = ChartUtils.bridgedObjCGetUIColorArray(objc: colors)
|
||||
}
|
||||
|
||||
/// Sets a custom legend's labels and colors arrays.
|
||||
/// The colors count should match the labels count.
|
||||
/// * Each color is for the form drawn at the same index.
|
||||
/// * A nil label will start a group.
|
||||
/// * A nil color will avoid drawing a form, and a clearColor will leave a space for the form.
|
||||
/// This will disable the feature that automatically calculates the legend labels and colors from the datasets.
|
||||
/// Call `resetLegendToAuto(...)` to re-enable automatic calculation, and then if needed - call `notifyDataSetChanged()` on the chart to make it refresh the data.
|
||||
public func setCustom(colors colors: [NSObject], labels: [NSObject])
|
||||
{
|
||||
if (colors.count != labels.count)
|
||||
{
|
||||
fatalError("ChartLegend:setCustom() - colors array and labels array need to be of same size")
|
||||
}
|
||||
|
||||
self.labelsObjc = labels
|
||||
self.colorsObjc = colors
|
||||
_isLegendCustom = true
|
||||
}
|
||||
}
|
||||
84
Carthage/Checkouts/Charts/Charts/Classes/Components/ChartLimitLine.swift
vendored
Normal file
84
Carthage/Checkouts/Charts/Charts/Classes/Components/ChartLimitLine.swift
vendored
Normal file
@@ -0,0 +1,84 @@
|
||||
//
|
||||
// ChartLimitLine.swift
|
||||
// Charts
|
||||
//
|
||||
// Created by Daniel Cohen Gindi on 23/2/15.
|
||||
|
||||
//
|
||||
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
|
||||
// A port of MPAndroidChart for iOS
|
||||
// Licensed under Apache License 2.0
|
||||
//
|
||||
// https://github.com/danielgindi/ios-charts
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import UIKit
|
||||
|
||||
/// The limit line is an additional feature for all Line, Bar and ScatterCharts.
|
||||
/// It allows the displaying of an additional line in the chart that marks a certain maximum / limit on the specified axis (x- or y-axis).
|
||||
public class ChartLimitLine: ChartComponentBase
|
||||
{
|
||||
@objc
|
||||
public enum ChartLimitLabelPosition: Int
|
||||
{
|
||||
case LeftTop
|
||||
case LeftBottom
|
||||
case RightTop
|
||||
case RightBottom
|
||||
}
|
||||
|
||||
/// limit / maximum (the y-value or xIndex)
|
||||
public var limit = Double(0.0)
|
||||
|
||||
private var _lineWidth = CGFloat(2.0)
|
||||
public var lineColor = UIColor(red: 237.0/255.0, green: 91.0/255.0, blue: 91.0/255.0, alpha: 1.0)
|
||||
public var lineDashPhase = CGFloat(0.0)
|
||||
public var lineDashLengths: [CGFloat]?
|
||||
public var valueTextColor = UIColor.blackColor()
|
||||
public var valueFont = UIFont.systemFontOfSize(13.0)
|
||||
public var label = ""
|
||||
public var labelPosition = ChartLimitLabelPosition.RightTop
|
||||
|
||||
public override init()
|
||||
{
|
||||
super.init()
|
||||
}
|
||||
|
||||
public init(limit: Double)
|
||||
{
|
||||
super.init()
|
||||
self.limit = limit
|
||||
}
|
||||
|
||||
public init(limit: Double, label: String)
|
||||
{
|
||||
super.init()
|
||||
self.limit = limit
|
||||
self.label = label
|
||||
}
|
||||
|
||||
/// set the line width of the chart (min = 0.2, max = 12); default 2
|
||||
public var lineWidth: CGFloat
|
||||
{
|
||||
get
|
||||
{
|
||||
return _lineWidth
|
||||
}
|
||||
set
|
||||
{
|
||||
if (newValue < 0.2)
|
||||
{
|
||||
_lineWidth = 0.2
|
||||
}
|
||||
else if (newValue > 12.0)
|
||||
{
|
||||
_lineWidth = 12.0
|
||||
}
|
||||
else
|
||||
{
|
||||
_lineWidth = newValue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
59
Carthage/Checkouts/Charts/Charts/Classes/Components/ChartMarker.swift
vendored
Normal file
59
Carthage/Checkouts/Charts/Charts/Classes/Components/ChartMarker.swift
vendored
Normal file
@@ -0,0 +1,59 @@
|
||||
//
|
||||
// ChartMarker.swift
|
||||
// Charts
|
||||
//
|
||||
// Created by Daniel Cohen Gindi on 3/3/15.
|
||||
//
|
||||
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
|
||||
// A port of MPAndroidChart for iOS
|
||||
// Licensed under Apache License 2.0
|
||||
//
|
||||
// https://github.com/danielgindi/ios-charts
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import UIKit
|
||||
|
||||
public class ChartMarker: ChartComponentBase
|
||||
{
|
||||
/// The marker image to render
|
||||
public var image: UIImage?
|
||||
|
||||
/// Use this to return the desired offset you wish the MarkerView to have on the x-axis.
|
||||
public var offset: CGPoint = CGPoint()
|
||||
|
||||
/// The marker's size
|
||||
public var size: CGSize
|
||||
{
|
||||
get
|
||||
{
|
||||
return image!.size
|
||||
}
|
||||
}
|
||||
|
||||
public override init()
|
||||
{
|
||||
super.init()
|
||||
}
|
||||
|
||||
/// Draws the ChartMarker on the given position on the given context
|
||||
public func draw(context context: CGContext?, point: CGPoint)
|
||||
{
|
||||
let offset = self.offset
|
||||
let size = self.size
|
||||
|
||||
let rect = CGRect(x: point.x + offset.x, y: point.y + offset.y, width: size.width, height: size.height)
|
||||
|
||||
UIGraphicsPushContext(context)
|
||||
image!.drawInRect(rect)
|
||||
UIGraphicsPopContext()
|
||||
}
|
||||
|
||||
/// This method enables a custom ChartMarker to update it's content everytime the MarkerView is redrawn according to the data entry it points to.
|
||||
///
|
||||
/// - parameter highlight: the highlight object contains information about the highlighted value such as it's dataset-index, the selected range or stack-index (only stacked bar entries).
|
||||
public func refreshContent(entry entry: ChartDataEntry, highlight: ChartHighlight)
|
||||
{
|
||||
// Do nothing here...
|
||||
}
|
||||
}
|
||||
151
Carthage/Checkouts/Charts/Charts/Classes/Components/ChartXAxis.swift
vendored
Normal file
151
Carthage/Checkouts/Charts/Charts/Classes/Components/ChartXAxis.swift
vendored
Normal file
@@ -0,0 +1,151 @@
|
||||
//
|
||||
// ChartXAxis.swift
|
||||
// Charts
|
||||
//
|
||||
// Created by Daniel Cohen Gindi on 23/2/15.
|
||||
|
||||
//
|
||||
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
|
||||
// A port of MPAndroidChart for iOS
|
||||
// Licensed under Apache License 2.0
|
||||
//
|
||||
// https://github.com/danielgindi/ios-charts
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import UIKit
|
||||
|
||||
public class ChartXAxis: ChartAxisBase
|
||||
{
|
||||
@objc
|
||||
public enum XAxisLabelPosition: Int
|
||||
{
|
||||
case Top
|
||||
case Bottom
|
||||
case BothSided
|
||||
case TopInside
|
||||
case BottomInside
|
||||
}
|
||||
|
||||
public var values = [String?]()
|
||||
public var labelWidth = CGFloat(1.0)
|
||||
public var labelHeight = CGFloat(1.0)
|
||||
|
||||
/// the space that should be left out (in characters) between the x-axis labels
|
||||
/// This only applies if the number of labels that will be skipped in between drawn axis labels is not custom set.
|
||||
///
|
||||
/// **default**: 4
|
||||
public var spaceBetweenLabels = Int(4)
|
||||
|
||||
/// the modulus that indicates if a value at a specified index in an array(list) for the x-axis-labels is drawn or not. Draw when `(index % modulus) == 0`.
|
||||
public var axisLabelModulus = Int(1)
|
||||
|
||||
/// Is axisLabelModulus a custom value or auto calculated? If false, then it's auto, if true, then custom.
|
||||
///
|
||||
/// **default**: false (automatic modulus)
|
||||
private var _isAxisModulusCustom = false
|
||||
|
||||
/// the modulus that indicates if a value at a specified index in an array(list) for the y-axis-labels is drawn or not. Draw when `(index % modulus) == 0`.
|
||||
/// Used only for Horizontal BarChart
|
||||
public var yAxisLabelModulus = Int(1)
|
||||
|
||||
/// if set to true, the chart will avoid that the first and last label entry in the chart "clip" off the edge of the chart
|
||||
public var avoidFirstLastClippingEnabled = false
|
||||
|
||||
/// Custom formatter for adjusting x-value strings
|
||||
private var _xAxisValueFormatter: ChartXAxisValueFormatter = ChartDefaultXAxisValueFormatter()
|
||||
|
||||
/// Custom XValueFormatter for the data object that allows custom-formatting of all x-values before rendering them.
|
||||
/// Provide null to reset back to the default formatting.
|
||||
public var valueFormatter: ChartXAxisValueFormatter?
|
||||
{
|
||||
get
|
||||
{
|
||||
return _xAxisValueFormatter
|
||||
}
|
||||
set
|
||||
{
|
||||
_xAxisValueFormatter = newValue ?? ChartDefaultXAxisValueFormatter()
|
||||
}
|
||||
}
|
||||
|
||||
/// the position of the x-labels relative to the chart
|
||||
public var labelPosition = XAxisLabelPosition.Top
|
||||
|
||||
/// if set to true, word wrapping the labels will be enabled.
|
||||
/// word wrapping is done using `(value width * labelWidth)`
|
||||
///
|
||||
/// *Note: currently supports all charts except pie/radar/horizontal-bar*
|
||||
public var wordWrapEnabled = false
|
||||
|
||||
/// - returns: true if word wrapping the labels is enabled
|
||||
public var isWordWrapEnabled: Bool { return wordWrapEnabled }
|
||||
|
||||
/// the width for wrapping the labels, as percentage out of one value width.
|
||||
/// used only when isWordWrapEnabled = true.
|
||||
///
|
||||
/// **default**: 1.0
|
||||
public var wordWrapWidthPercent: CGFloat = 1.0
|
||||
|
||||
public override init()
|
||||
{
|
||||
super.init()
|
||||
}
|
||||
|
||||
public override func getLongestLabel() -> String
|
||||
{
|
||||
var longest = ""
|
||||
|
||||
for (var i = 0; i < values.count; i++)
|
||||
{
|
||||
let text = values[i]
|
||||
|
||||
if (text != nil && longest.characters.count < (text!).characters.count)
|
||||
{
|
||||
longest = text!
|
||||
}
|
||||
}
|
||||
|
||||
return longest
|
||||
}
|
||||
|
||||
public var isAvoidFirstLastClippingEnabled: Bool
|
||||
{
|
||||
return avoidFirstLastClippingEnabled
|
||||
}
|
||||
|
||||
/// Sets the number of labels that should be skipped on the axis before the next label is drawn.
|
||||
/// This will disable the feature that automatically calculates an adequate space between the axis labels and set the number of labels to be skipped to the fixed number provided by this method.
|
||||
/// Call `resetLabelsToSkip(...)` to re-enable automatic calculation.
|
||||
public func setLabelsToSkip(count: Int)
|
||||
{
|
||||
_isAxisModulusCustom = true
|
||||
|
||||
if (count < 0)
|
||||
{
|
||||
axisLabelModulus = 1
|
||||
}
|
||||
else
|
||||
{
|
||||
axisLabelModulus = count + 1
|
||||
}
|
||||
}
|
||||
|
||||
/// Calling this will disable a custom number of labels to be skipped (set by `setLabelsToSkip(...)`) while drawing the x-axis. Instead, the number of values to skip will again be calculated automatically.
|
||||
public func resetLabelsToSkip()
|
||||
{
|
||||
_isAxisModulusCustom = false
|
||||
}
|
||||
|
||||
/// - returns: true if a custom axis-modulus has been set that determines the number of labels to skip when drawing.
|
||||
public var isAxisModulusCustom: Bool
|
||||
{
|
||||
return _isAxisModulusCustom
|
||||
}
|
||||
|
||||
public var valuesObjc: [NSObject]
|
||||
{
|
||||
get { return ChartUtils.bridgedObjCGetStringArray(swift: values); }
|
||||
set { self.values = ChartUtils.bridgedObjCGetStringArray(objc: newValue); }
|
||||
}
|
||||
}
|
||||
246
Carthage/Checkouts/Charts/Charts/Classes/Components/ChartYAxis.swift
vendored
Normal file
246
Carthage/Checkouts/Charts/Charts/Classes/Components/ChartYAxis.swift
vendored
Normal file
@@ -0,0 +1,246 @@
|
||||
//
|
||||
// ChartYAxis.swift
|
||||
// Charts
|
||||
//
|
||||
// Created by Daniel Cohen Gindi on 23/2/15.
|
||||
|
||||
//
|
||||
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
|
||||
// A port of MPAndroidChart for iOS
|
||||
// Licensed under Apache License 2.0
|
||||
//
|
||||
// https://github.com/danielgindi/ios-charts
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import UIKit
|
||||
|
||||
/// Class representing the y-axis labels settings and its entries.
|
||||
/// Be aware that not all features the YLabels class provides are suitable for the RadarChart.
|
||||
/// Customizations that affect the value range of the axis need to be applied before setting data for the chart.
|
||||
public class ChartYAxis: ChartAxisBase
|
||||
{
|
||||
@objc
|
||||
public enum YAxisLabelPosition: Int
|
||||
{
|
||||
case OutsideChart
|
||||
case InsideChart
|
||||
}
|
||||
|
||||
/// Enum that specifies the axis a DataSet should be plotted against, either Left or Right.
|
||||
@objc
|
||||
public enum AxisDependency: Int
|
||||
{
|
||||
case Left
|
||||
case Right
|
||||
}
|
||||
|
||||
public var entries = [Double]()
|
||||
public var entryCount: Int { return entries.count; }
|
||||
|
||||
/// the number of y-label entries the y-labels should have, default 6
|
||||
private var _labelCount = Int(6)
|
||||
|
||||
/// indicates if the top y-label entry is drawn or not
|
||||
public var drawTopYLabelEntryEnabled = true
|
||||
|
||||
/// if true, the y-labels show only the minimum and maximum value
|
||||
public var showOnlyMinMaxEnabled = false
|
||||
|
||||
/// flag that indicates if the axis is inverted or not
|
||||
public var inverted = false
|
||||
|
||||
/// if true, the y-label entries will always start at zero
|
||||
public var startAtZeroEnabled = true
|
||||
|
||||
/// if true, the set number of y-labels will be forced
|
||||
public var forceLabelsEnabled = false
|
||||
|
||||
/// the formatter used to customly format the y-labels
|
||||
public var valueFormatter: NSNumberFormatter?
|
||||
|
||||
/// the formatter used to customly format the y-labels
|
||||
internal var _defaultValueFormatter = NSNumberFormatter()
|
||||
|
||||
/// A custom minimum value for this axis.
|
||||
/// If set, this value will not be calculated automatically depending on the provided data.
|
||||
/// Use `resetCustomAxisMin()` to undo this.
|
||||
/// Do not forget to set startAtZeroEnabled = false if you use this method.
|
||||
/// Otherwise, the axis-minimum value will still be forced to 0.
|
||||
public var customAxisMin = Double.NaN
|
||||
|
||||
/// Set a custom maximum value for this axis.
|
||||
/// If set, this value will not be calculated automatically depending on the provided data.
|
||||
/// Use `resetCustomAxisMax()` to undo this.
|
||||
public var customAxisMax = Double.NaN
|
||||
|
||||
/// axis space from the largest value to the top in percent of the total axis range
|
||||
public var spaceTop = CGFloat(0.1)
|
||||
|
||||
/// axis space from the smallest value to the bottom in percent of the total axis range
|
||||
public var spaceBottom = CGFloat(0.1)
|
||||
|
||||
public var axisMaximum = Double(0)
|
||||
public var axisMinimum = Double(0)
|
||||
|
||||
/// the total range of values this axis covers
|
||||
public var axisRange = Double(0)
|
||||
|
||||
/// the position of the y-labels relative to the chart
|
||||
public var labelPosition = YAxisLabelPosition.OutsideChart
|
||||
|
||||
/// the side this axis object represents
|
||||
private var _axisDependency = AxisDependency.Left
|
||||
|
||||
/// the minimum width that the axis should take
|
||||
///
|
||||
/// **default**: 0.0
|
||||
public var minWidth = CGFloat(0)
|
||||
|
||||
/// the maximum width that the axis can take.
|
||||
/// use zero for disabling the maximum
|
||||
///
|
||||
/// **default**: 0.0 (no maximum specified)
|
||||
public var maxWidth = CGFloat(0)
|
||||
|
||||
public override init()
|
||||
{
|
||||
super.init()
|
||||
|
||||
_defaultValueFormatter.minimumIntegerDigits = 1
|
||||
_defaultValueFormatter.maximumFractionDigits = 1
|
||||
_defaultValueFormatter.minimumFractionDigits = 1
|
||||
_defaultValueFormatter.usesGroupingSeparator = true
|
||||
self.yOffset = 0.0
|
||||
}
|
||||
|
||||
public init(position: AxisDependency)
|
||||
{
|
||||
super.init()
|
||||
|
||||
_axisDependency = position
|
||||
|
||||
_defaultValueFormatter.minimumIntegerDigits = 1
|
||||
_defaultValueFormatter.maximumFractionDigits = 1
|
||||
_defaultValueFormatter.minimumFractionDigits = 1
|
||||
_defaultValueFormatter.usesGroupingSeparator = true
|
||||
self.yOffset = 0.0
|
||||
}
|
||||
|
||||
public var axisDependency: AxisDependency
|
||||
{
|
||||
return _axisDependency
|
||||
}
|
||||
|
||||
public func setLabelCount(count: Int, force: Bool)
|
||||
{
|
||||
_labelCount = count
|
||||
|
||||
if (_labelCount > 25)
|
||||
{
|
||||
_labelCount = 25
|
||||
}
|
||||
if (_labelCount < 2)
|
||||
{
|
||||
_labelCount = 2
|
||||
}
|
||||
|
||||
forceLabelsEnabled = force
|
||||
}
|
||||
|
||||
/// the number of label entries the y-axis should have
|
||||
/// max = 25,
|
||||
/// min = 2,
|
||||
/// default = 6,
|
||||
/// be aware that this number is not fixed and can only be approximated
|
||||
public var labelCount: Int
|
||||
{
|
||||
get
|
||||
{
|
||||
return _labelCount
|
||||
}
|
||||
set
|
||||
{
|
||||
setLabelCount(newValue, force: false);
|
||||
}
|
||||
}
|
||||
|
||||
/// By calling this method, any custom minimum value that has been previously set is reseted, and the calculation is done automatically.
|
||||
public func resetCustomAxisMin()
|
||||
{
|
||||
customAxisMin = Double.NaN
|
||||
}
|
||||
|
||||
/// By calling this method, any custom maximum value that has been previously set is reseted, and the calculation is done automatically.
|
||||
public func resetCustomAxisMax()
|
||||
{
|
||||
customAxisMax = Double.NaN
|
||||
}
|
||||
|
||||
public func requiredSize() -> CGSize
|
||||
{
|
||||
let label = getLongestLabel() as NSString
|
||||
var size = label.sizeWithAttributes([NSFontAttributeName: labelFont])
|
||||
size.width += xOffset * 2.0
|
||||
size.height += yOffset * 2.0
|
||||
size.width = max(minWidth, min(size.width, maxWidth > 0.0 ? maxWidth : size.width))
|
||||
return size
|
||||
}
|
||||
|
||||
public func getRequiredHeightSpace() -> CGFloat
|
||||
{
|
||||
return requiredSize().height + 2.5 * 2.0 + yOffset
|
||||
}
|
||||
|
||||
public override func getLongestLabel() -> String
|
||||
{
|
||||
var longest = ""
|
||||
|
||||
for (var i = 0; i < entries.count; i++)
|
||||
{
|
||||
let text = getFormattedLabel(i)
|
||||
|
||||
if (longest.characters.count < text.characters.count)
|
||||
{
|
||||
longest = text
|
||||
}
|
||||
}
|
||||
|
||||
return longest
|
||||
}
|
||||
|
||||
/// - returns: the formatted y-label at the specified index. This will either use the auto-formatter or the custom formatter (if one is set).
|
||||
public func getFormattedLabel(index: Int) -> String
|
||||
{
|
||||
if (index < 0 || index >= entries.count)
|
||||
{
|
||||
return ""
|
||||
}
|
||||
|
||||
return (valueFormatter ?? _defaultValueFormatter).stringFromNumber(entries[index])!
|
||||
}
|
||||
|
||||
/// - returns: true if this axis needs horizontal offset, false if no offset is needed.
|
||||
public var needsOffset: Bool
|
||||
{
|
||||
if (isEnabled && isDrawLabelsEnabled && labelPosition == .OutsideChart)
|
||||
{
|
||||
return true
|
||||
}
|
||||
else
|
||||
{
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
public var isInverted: Bool { return inverted; }
|
||||
|
||||
public var isStartAtZeroEnabled: Bool { return startAtZeroEnabled; }
|
||||
|
||||
/// - returns: true if focing the y-label count is enabled. Default: false
|
||||
public var isForceLabelsEnabled: Bool { return forceLabelsEnabled }
|
||||
|
||||
public var isShowOnlyMinMaxEnabled: Bool { return showOnlyMinMaxEnabled; }
|
||||
|
||||
public var isDrawTopYLabelEntryEnabled: Bool { return drawTopYLabelEntryEnabled; }
|
||||
}
|
||||
58
Carthage/Checkouts/Charts/Charts/Classes/Data/BarChartData.swift
vendored
Normal file
58
Carthage/Checkouts/Charts/Charts/Classes/Data/BarChartData.swift
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
//
|
||||
// BarChartData.swift
|
||||
// Charts
|
||||
//
|
||||
// Created by Daniel Cohen Gindi on 26/2/15.
|
||||
//
|
||||
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
|
||||
// A port of MPAndroidChart for iOS
|
||||
// Licensed under Apache License 2.0
|
||||
//
|
||||
// https://github.com/danielgindi/ios-charts
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import CoreGraphics
|
||||
|
||||
public class BarChartData: BarLineScatterCandleBubbleChartData
|
||||
{
|
||||
public override init()
|
||||
{
|
||||
super.init()
|
||||
}
|
||||
|
||||
public override init(xVals: [String?]?, dataSets: [ChartDataSet]?)
|
||||
{
|
||||
super.init(xVals: xVals, dataSets: dataSets)
|
||||
}
|
||||
|
||||
public override init(xVals: [NSObject]?, dataSets: [ChartDataSet]?)
|
||||
{
|
||||
super.init(xVals: xVals, dataSets: dataSets)
|
||||
}
|
||||
|
||||
private var _groupSpace = CGFloat(0.8)
|
||||
|
||||
/// The spacing is relative to a full bar width
|
||||
public var groupSpace: CGFloat
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_dataSets.count <= 1)
|
||||
{
|
||||
return 0.0
|
||||
}
|
||||
return _groupSpace
|
||||
}
|
||||
set
|
||||
{
|
||||
_groupSpace = newValue
|
||||
}
|
||||
}
|
||||
|
||||
/// - returns: true if this BarData object contains grouped DataSets (more than 1 DataSet).
|
||||
public var isGrouped: Bool
|
||||
{
|
||||
return _dataSets.count > 1 ? true : false
|
||||
}
|
||||
}
|
||||
166
Carthage/Checkouts/Charts/Charts/Classes/Data/BarChartDataEntry.swift
vendored
Normal file
166
Carthage/Checkouts/Charts/Charts/Classes/Data/BarChartDataEntry.swift
vendored
Normal file
@@ -0,0 +1,166 @@
|
||||
//
|
||||
// BarChartDataEntry.swift
|
||||
// Charts
|
||||
//
|
||||
// Created by Daniel Cohen Gindi on 4/3/15.
|
||||
//
|
||||
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
|
||||
// A port of MPAndroidChart for iOS
|
||||
// Licensed under Apache License 2.0
|
||||
//
|
||||
// https://github.com/danielgindi/ios-charts
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
public class BarChartDataEntry: ChartDataEntry
|
||||
{
|
||||
/// the values the stacked barchart holds
|
||||
private var _values: [Double]?
|
||||
|
||||
/// the sum of all negative values this entry (if stacked) contains
|
||||
private var _negativeSum: Double = 0.0
|
||||
|
||||
/// the sum of all positive values this entry (if stacked) contains
|
||||
private var _positiveSum: Double = 0.0
|
||||
|
||||
public required init()
|
||||
{
|
||||
super.init()
|
||||
}
|
||||
|
||||
/// Constructor for stacked bar entries.
|
||||
public init(values: [Double], xIndex: Int)
|
||||
{
|
||||
super.init(value: BarChartDataEntry.calcSum(values), xIndex: xIndex)
|
||||
self.values = values
|
||||
calcPosNegSum()
|
||||
}
|
||||
|
||||
/// Constructor for normal bars (not stacked).
|
||||
public override init(value: Double, xIndex: Int)
|
||||
{
|
||||
super.init(value: value, xIndex: xIndex)
|
||||
}
|
||||
|
||||
/// Constructor for stacked bar entries.
|
||||
public init(values: [Double], xIndex: Int, label: String)
|
||||
{
|
||||
super.init(value: BarChartDataEntry.calcSum(values), xIndex: xIndex, data: label)
|
||||
self.values = values
|
||||
}
|
||||
|
||||
/// Constructor for normal bars (not stacked).
|
||||
public override init(value: Double, xIndex: Int, data: AnyObject?)
|
||||
{
|
||||
super.init(value: value, xIndex: xIndex, data: data)
|
||||
}
|
||||
|
||||
public func getBelowSum(stackIndex :Int) -> Double
|
||||
{
|
||||
if (values == nil)
|
||||
{
|
||||
return 0
|
||||
}
|
||||
|
||||
var remainder: Double = 0.0
|
||||
var index = values!.count - 1
|
||||
|
||||
while (index > stackIndex && index >= 0)
|
||||
{
|
||||
remainder += values![index]
|
||||
index--
|
||||
}
|
||||
|
||||
return remainder
|
||||
}
|
||||
|
||||
/// - returns: the sum of all negative values this entry (if stacked) contains. (this is a positive number)
|
||||
public var negativeSum: Double
|
||||
{
|
||||
return _negativeSum
|
||||
}
|
||||
|
||||
/// - returns: the sum of all positive values this entry (if stacked) contains.
|
||||
public var positiveSum: Double
|
||||
{
|
||||
return _positiveSum
|
||||
}
|
||||
|
||||
public func calcPosNegSum()
|
||||
{
|
||||
if _values == nil
|
||||
{
|
||||
_positiveSum = 0.0
|
||||
_negativeSum = 0.0
|
||||
return
|
||||
}
|
||||
|
||||
var sumNeg: Double = 0.0
|
||||
var sumPos: Double = 0.0
|
||||
|
||||
for f in _values!
|
||||
{
|
||||
if f < 0.0
|
||||
{
|
||||
sumNeg += -f
|
||||
}
|
||||
else
|
||||
{
|
||||
sumPos += f
|
||||
}
|
||||
}
|
||||
|
||||
_negativeSum = sumNeg
|
||||
_positiveSum = sumPos
|
||||
}
|
||||
|
||||
// MARK: Accessors
|
||||
|
||||
/// the values the stacked barchart holds
|
||||
public var isStacked: Bool { return _values != nil }
|
||||
|
||||
/// the values the stacked barchart holds
|
||||
public var values: [Double]?
|
||||
{
|
||||
get { return self._values }
|
||||
set
|
||||
{
|
||||
self.value = BarChartDataEntry.calcSum(newValue)
|
||||
self._values = newValue
|
||||
calcPosNegSum()
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: NSCopying
|
||||
|
||||
public override func copyWithZone(zone: NSZone) -> AnyObject
|
||||
{
|
||||
let copy = super.copyWithZone(zone) as! BarChartDataEntry
|
||||
copy._values = _values
|
||||
copy.value = value
|
||||
copy._negativeSum = _negativeSum
|
||||
return copy
|
||||
}
|
||||
|
||||
/// Calculates the sum across all values of the given stack.
|
||||
///
|
||||
/// - parameter vals:
|
||||
/// - returns:
|
||||
private static func calcSum(vals: [Double]?) -> Double
|
||||
{
|
||||
if vals == nil
|
||||
{
|
||||
return 0.0
|
||||
}
|
||||
|
||||
var sum = 0.0
|
||||
|
||||
for f in vals!
|
||||
{
|
||||
sum += f
|
||||
}
|
||||
|
||||
return sum
|
||||
}
|
||||
}
|
||||
188
Carthage/Checkouts/Charts/Charts/Classes/Data/BarChartDataSet.swift
vendored
Normal file
188
Carthage/Checkouts/Charts/Charts/Classes/Data/BarChartDataSet.swift
vendored
Normal file
@@ -0,0 +1,188 @@
|
||||
//
|
||||
// BarChartDataSet.swift
|
||||
// Charts
|
||||
//
|
||||
// Created by Daniel Cohen Gindi on 4/3/15.
|
||||
//
|
||||
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
|
||||
// A port of MPAndroidChart for iOS
|
||||
// Licensed under Apache License 2.0
|
||||
//
|
||||
// https://github.com/danielgindi/ios-charts
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import CoreGraphics
|
||||
import UIKit
|
||||
|
||||
public class BarChartDataSet: BarLineScatterCandleBubbleChartDataSet
|
||||
{
|
||||
/// space indicator between the bars in percentage of the whole width of one value (0.15 == 15% of bar width)
|
||||
public var barSpace: CGFloat = 0.15
|
||||
|
||||
/// the maximum number of bars that are stacked upon each other, this value
|
||||
/// is calculated from the Entries that are added to the DataSet
|
||||
private var _stackSize = 1
|
||||
|
||||
/// the color used for drawing the bar-shadows. The bar shadows is a surface behind the bar that indicates the maximum value
|
||||
public var barShadowColor = UIColor(red: 215.0/255.0, green: 215.0/255.0, blue: 215.0/255.0, alpha: 1.0)
|
||||
|
||||
/// the alpha value (transparency) that is used for drawing the highlight indicator bar. min = 0.0 (fully transparent), max = 1.0 (fully opaque)
|
||||
public var highLightAlpha = CGFloat(120.0 / 255.0)
|
||||
|
||||
/// the overall entry count, including counting each stack-value individually
|
||||
private var _entryCountStacks = 0
|
||||
|
||||
/// array of labels used to describe the different values of the stacked bars
|
||||
public var stackLabels: [String] = ["Stack"]
|
||||
|
||||
public required init()
|
||||
{
|
||||
super.init()
|
||||
}
|
||||
|
||||
public override init(yVals: [ChartDataEntry]?, label: String?)
|
||||
{
|
||||
super.init(yVals: yVals, label: label)
|
||||
|
||||
self.highlightColor = UIColor.blackColor()
|
||||
|
||||
self.calcStackSize(yVals as! [BarChartDataEntry]?)
|
||||
self.calcEntryCountIncludingStacks(yVals as! [BarChartDataEntry]?)
|
||||
}
|
||||
|
||||
// MARK: NSCopying
|
||||
|
||||
public override func copyWithZone(zone: NSZone) -> AnyObject
|
||||
{
|
||||
let copy = super.copyWithZone(zone) as! BarChartDataSet
|
||||
copy.barSpace = barSpace
|
||||
copy._stackSize = _stackSize
|
||||
copy.barShadowColor = barShadowColor
|
||||
copy.highLightAlpha = highLightAlpha
|
||||
copy._entryCountStacks = _entryCountStacks
|
||||
copy.stackLabels = stackLabels
|
||||
return copy
|
||||
}
|
||||
|
||||
/// Calculates the total number of entries this DataSet represents, including
|
||||
/// stacks. All values belonging to a stack are calculated separately.
|
||||
private func calcEntryCountIncludingStacks(yVals: [BarChartDataEntry]!)
|
||||
{
|
||||
_entryCountStacks = 0
|
||||
|
||||
for (var i = 0; i < yVals.count; i++)
|
||||
{
|
||||
let vals = yVals[i].values
|
||||
|
||||
if (vals == nil)
|
||||
{
|
||||
_entryCountStacks++
|
||||
}
|
||||
else
|
||||
{
|
||||
_entryCountStacks += vals!.count
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// calculates the maximum stacksize that occurs in the Entries array of this DataSet
|
||||
private func calcStackSize(yVals: [BarChartDataEntry]!)
|
||||
{
|
||||
for (var i = 0; i < yVals.count; i++)
|
||||
{
|
||||
if let vals = yVals[i].values
|
||||
{
|
||||
if vals.count > _stackSize
|
||||
{
|
||||
_stackSize = vals.count
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal override func calcMinMax(start start : Int, end: Int)
|
||||
{
|
||||
let yValCount = _yVals.count
|
||||
|
||||
if yValCount == 0
|
||||
{
|
||||
return
|
||||
}
|
||||
|
||||
var endValue : Int
|
||||
|
||||
if end == 0 || end >= yValCount
|
||||
{
|
||||
endValue = yValCount - 1
|
||||
}
|
||||
else
|
||||
{
|
||||
endValue = end
|
||||
}
|
||||
|
||||
_lastStart = start
|
||||
_lastEnd = endValue
|
||||
|
||||
_yMin = DBL_MAX
|
||||
_yMax = -DBL_MAX
|
||||
|
||||
for (var i = start; i <= endValue; i++)
|
||||
{
|
||||
if let e = _yVals[i] as? BarChartDataEntry
|
||||
{
|
||||
if !e.value.isNaN
|
||||
{
|
||||
if e.values == nil
|
||||
{
|
||||
if e.value < _yMin
|
||||
{
|
||||
_yMin = e.value
|
||||
}
|
||||
|
||||
if e.value > _yMax
|
||||
{
|
||||
_yMax = e.value
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if -e.negativeSum < _yMin
|
||||
{
|
||||
_yMin = -e.negativeSum
|
||||
}
|
||||
|
||||
if e.positiveSum > _yMax
|
||||
{
|
||||
_yMax = e.positiveSum
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_yMin == DBL_MAX)
|
||||
{
|
||||
_yMin = 0.0
|
||||
_yMax = 0.0
|
||||
}
|
||||
}
|
||||
|
||||
/// - returns: the maximum number of bars that can be stacked upon another in this DataSet.
|
||||
public var stackSize: Int
|
||||
{
|
||||
return _stackSize
|
||||
}
|
||||
|
||||
/// - returns: true if this DataSet is stacked (stacksize > 1) or not.
|
||||
public var isStacked: Bool
|
||||
{
|
||||
return _stackSize > 1 ? true : false
|
||||
}
|
||||
|
||||
/// - returns: the overall entry count, including counting each stack-value individually
|
||||
public var entryCountStacks: Int
|
||||
{
|
||||
return _entryCountStacks
|
||||
}
|
||||
}
|
||||
32
Carthage/Checkouts/Charts/Charts/Classes/Data/BarLineScatterCandleBubbleChartData.swift
vendored
Normal file
32
Carthage/Checkouts/Charts/Charts/Classes/Data/BarLineScatterCandleBubbleChartData.swift
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
//
|
||||
// BarLineScatterCandleBubbleChartData.swift
|
||||
// Charts
|
||||
//
|
||||
// Created by Daniel Cohen Gindi on 26/2/15.
|
||||
//
|
||||
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
|
||||
// A port of MPAndroidChart for iOS
|
||||
// Licensed under Apache License 2.0
|
||||
//
|
||||
// https://github.com/danielgindi/ios-charts
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
public class BarLineScatterCandleBubbleChartData: ChartData
|
||||
{
|
||||
public override init()
|
||||
{
|
||||
super.init()
|
||||
}
|
||||
|
||||
public override init(xVals: [String?]?, dataSets: [ChartDataSet]?)
|
||||
{
|
||||
super.init(xVals: xVals, dataSets: dataSets)
|
||||
}
|
||||
|
||||
public override init(xVals: [NSObject]?, dataSets: [ChartDataSet]?)
|
||||
{
|
||||
super.init(xVals: xVals, dataSets: dataSets)
|
||||
}
|
||||
}
|
||||
35
Carthage/Checkouts/Charts/Charts/Classes/Data/BarLineScatterCandleBubbleChartDataSet.swift
vendored
Normal file
35
Carthage/Checkouts/Charts/Charts/Classes/Data/BarLineScatterCandleBubbleChartDataSet.swift
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
//
|
||||
// BarLineScatterCandleBubbleChartDataSet.swift
|
||||
// Charts
|
||||
//
|
||||
// Created by Daniel Cohen Gindi on 26/2/15.
|
||||
//
|
||||
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
|
||||
// A port of MPAndroidChart for iOS
|
||||
// Licensed under Apache License 2.0
|
||||
//
|
||||
// https://github.com/danielgindi/ios-charts
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import UIKit
|
||||
|
||||
public class BarLineScatterCandleBubbleChartDataSet: ChartDataSet
|
||||
{
|
||||
public var highlightColor = UIColor(red: 255.0/255.0, green: 187.0/255.0, blue: 115.0/255.0, alpha: 1.0)
|
||||
public var highlightLineWidth = CGFloat(0.5)
|
||||
public var highlightLineDashPhase = CGFloat(0.0)
|
||||
public var highlightLineDashLengths: [CGFloat]?
|
||||
|
||||
// MARK: NSCopying
|
||||
|
||||
public override func copyWithZone(zone: NSZone) -> AnyObject
|
||||
{
|
||||
let copy = super.copyWithZone(zone) as! BarLineScatterCandleBubbleChartDataSet
|
||||
copy.highlightColor = highlightColor
|
||||
copy.highlightLineWidth = highlightLineWidth
|
||||
copy.highlightLineDashPhase = highlightLineDashPhase
|
||||
copy.highlightLineDashLengths = highlightLineDashLengths
|
||||
return copy
|
||||
}
|
||||
}
|
||||
40
Carthage/Checkouts/Charts/Charts/Classes/Data/BubbleChartData.swift
vendored
Normal file
40
Carthage/Checkouts/Charts/Charts/Classes/Data/BubbleChartData.swift
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
//
|
||||
// BubbleChartData.swift
|
||||
// Charts
|
||||
//
|
||||
// Bubble chart implementation:
|
||||
// Copyright 2015 Pierre-Marc Airoldi
|
||||
// Licensed under Apache License 2.0
|
||||
//
|
||||
// https://github.com/danielgindi/ios-charts
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import CoreGraphics
|
||||
|
||||
public class BubbleChartData: BarLineScatterCandleBubbleChartData
|
||||
{
|
||||
public override init()
|
||||
{
|
||||
super.init()
|
||||
}
|
||||
|
||||
public override init(xVals: [String?]?, dataSets: [ChartDataSet]?)
|
||||
{
|
||||
super.init(xVals: xVals, dataSets: dataSets)
|
||||
}
|
||||
|
||||
public override init(xVals: [NSObject]?, dataSets: [ChartDataSet]?)
|
||||
{
|
||||
super.init(xVals: xVals, dataSets: dataSets)
|
||||
}
|
||||
|
||||
/// Sets the width of the circle that surrounds the bubble when highlighted for all DataSet objects this data object contains
|
||||
public func setHighlightCircleWidth(width: CGFloat)
|
||||
{
|
||||
for set in _dataSets as! [BubbleChartDataSet]!
|
||||
{
|
||||
set.highlightCircleWidth = width
|
||||
}
|
||||
}
|
||||
}
|
||||
54
Carthage/Checkouts/Charts/Charts/Classes/Data/BubbleChartDataEntry.swift
vendored
Normal file
54
Carthage/Checkouts/Charts/Charts/Classes/Data/BubbleChartDataEntry.swift
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
//
|
||||
// BubbleDataEntry.swift
|
||||
// Charts
|
||||
//
|
||||
// Bubble chart implementation:
|
||||
// Copyright 2015 Pierre-Marc Airoldi
|
||||
// Licensed under Apache License 2.0
|
||||
//
|
||||
// https://github.com/danielgindi/ios-charts
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import CoreGraphics
|
||||
|
||||
public class BubbleChartDataEntry: ChartDataEntry
|
||||
{
|
||||
/// The size of the bubble.
|
||||
public var size = CGFloat(0.0)
|
||||
|
||||
public required init()
|
||||
{
|
||||
super.init()
|
||||
}
|
||||
|
||||
/// - parameter xIndex: The index on the x-axis.
|
||||
/// - parameter val: The value on the y-axis.
|
||||
/// - parameter size: The size of the bubble.
|
||||
public init(xIndex: Int, value: Double, size: CGFloat)
|
||||
{
|
||||
super.init(value: value, xIndex: xIndex)
|
||||
|
||||
self.size = size
|
||||
}
|
||||
|
||||
/// - parameter xIndex: The index on the x-axis.
|
||||
/// - parameter val: The value on the y-axis.
|
||||
/// - parameter size: The size of the bubble.
|
||||
/// - parameter data: Spot for additional data this Entry represents.
|
||||
public init(xIndex: Int, value: Double, size: CGFloat, data: AnyObject?)
|
||||
{
|
||||
super.init(value: value, xIndex: xIndex, data: data)
|
||||
|
||||
self.size = size
|
||||
}
|
||||
|
||||
// MARK: NSCopying
|
||||
|
||||
public override func copyWithZone(zone: NSZone) -> AnyObject
|
||||
{
|
||||
let copy = super.copyWithZone(zone) as! BubbleChartDataEntry
|
||||
copy.size = size
|
||||
return copy
|
||||
}
|
||||
}
|
||||
125
Carthage/Checkouts/Charts/Charts/Classes/Data/BubbleChartDataSet.swift
vendored
Normal file
125
Carthage/Checkouts/Charts/Charts/Classes/Data/BubbleChartDataSet.swift
vendored
Normal file
@@ -0,0 +1,125 @@
|
||||
//
|
||||
// BubbleChartDataSet.swift
|
||||
// Charts
|
||||
//
|
||||
// Bubble chart implementation:
|
||||
// Copyright 2015 Pierre-Marc Airoldi
|
||||
// Licensed under Apache License 2.0
|
||||
//
|
||||
// https://github.com/danielgindi/ios-charts
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import CoreGraphics
|
||||
import UIKit
|
||||
|
||||
public class BubbleChartDataSet: BarLineScatterCandleBubbleChartDataSet
|
||||
{
|
||||
internal var _xMax = Double(0.0)
|
||||
internal var _xMin = Double(0.0)
|
||||
internal var _maxSize = CGFloat(0.0)
|
||||
|
||||
public var xMin: Double { return _xMin }
|
||||
public var xMax: Double { return _xMax }
|
||||
public var maxSize: CGFloat { return _maxSize }
|
||||
|
||||
public func setColor(color: UIColor, alpha: CGFloat)
|
||||
{
|
||||
super.setColor(color.colorWithAlphaComponent(alpha))
|
||||
}
|
||||
|
||||
internal override func calcMinMax(start start: Int, end: Int)
|
||||
{
|
||||
if (yVals.count == 0)
|
||||
{
|
||||
return
|
||||
}
|
||||
|
||||
let entries = yVals as! [BubbleChartDataEntry]
|
||||
|
||||
// need chart width to guess this properly
|
||||
|
||||
var endValue : Int
|
||||
|
||||
if end == 0
|
||||
{
|
||||
endValue = entries.count - 1
|
||||
}
|
||||
else
|
||||
{
|
||||
endValue = end
|
||||
}
|
||||
|
||||
_lastStart = start
|
||||
_lastEnd = end
|
||||
|
||||
_yMin = yMin(entries[start])
|
||||
_yMax = yMax(entries[start])
|
||||
|
||||
for (var i = start; i <= endValue; i++)
|
||||
{
|
||||
let entry = entries[i]
|
||||
|
||||
let ymin = yMin(entry)
|
||||
let ymax = yMax(entry)
|
||||
|
||||
if (ymin < _yMin)
|
||||
{
|
||||
_yMin = ymin
|
||||
}
|
||||
|
||||
if (ymax > _yMax)
|
||||
{
|
||||
_yMax = ymax
|
||||
}
|
||||
|
||||
let xmin = xMin(entry)
|
||||
let xmax = xMax(entry)
|
||||
|
||||
if (xmin < _xMin)
|
||||
{
|
||||
_xMin = xmin
|
||||
}
|
||||
|
||||
if (xmax > _xMax)
|
||||
{
|
||||
_xMax = xmax
|
||||
}
|
||||
|
||||
let size = largestSize(entry)
|
||||
|
||||
if (size > _maxSize)
|
||||
{
|
||||
_maxSize = size
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets/gets the width of the circle that surrounds the bubble when highlighted
|
||||
public var highlightCircleWidth: CGFloat = 2.5
|
||||
|
||||
private func yMin(entry: BubbleChartDataEntry) -> Double
|
||||
{
|
||||
return entry.value
|
||||
}
|
||||
|
||||
private func yMax(entry: BubbleChartDataEntry) -> Double
|
||||
{
|
||||
return entry.value
|
||||
}
|
||||
|
||||
private func xMin(entry: BubbleChartDataEntry) -> Double
|
||||
{
|
||||
return Double(entry.xIndex)
|
||||
}
|
||||
|
||||
private func xMax(entry: BubbleChartDataEntry) -> Double
|
||||
{
|
||||
return Double(entry.xIndex)
|
||||
}
|
||||
|
||||
private func largestSize(entry: BubbleChartDataEntry) -> CGFloat
|
||||
{
|
||||
return entry.size
|
||||
}
|
||||
}
|
||||
32
Carthage/Checkouts/Charts/Charts/Classes/Data/CandleChartData.swift
vendored
Normal file
32
Carthage/Checkouts/Charts/Charts/Classes/Data/CandleChartData.swift
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
//
|
||||
// CandleChartData.swift
|
||||
// Charts
|
||||
//
|
||||
// Created by Daniel Cohen Gindi on 26/2/15.
|
||||
//
|
||||
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
|
||||
// A port of MPAndroidChart for iOS
|
||||
// Licensed under Apache License 2.0
|
||||
//
|
||||
// https://github.com/danielgindi/ios-charts
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
public class CandleChartData: BarLineScatterCandleBubbleChartData
|
||||
{
|
||||
public override init()
|
||||
{
|
||||
super.init()
|
||||
}
|
||||
|
||||
public override init(xVals: [String?]?, dataSets: [ChartDataSet]?)
|
||||
{
|
||||
super.init(xVals: xVals, dataSets: dataSets)
|
||||
}
|
||||
|
||||
public override init(xVals: [NSObject]?, dataSets: [ChartDataSet]?)
|
||||
{
|
||||
super.init(xVals: xVals, dataSets: dataSets)
|
||||
}
|
||||
}
|
||||
91
Carthage/Checkouts/Charts/Charts/Classes/Data/CandleChartDataEntry.swift
vendored
Normal file
91
Carthage/Checkouts/Charts/Charts/Classes/Data/CandleChartDataEntry.swift
vendored
Normal file
@@ -0,0 +1,91 @@
|
||||
//
|
||||
// CandleChartDataEntry.swift
|
||||
// Charts
|
||||
//
|
||||
// Created by Daniel Cohen Gindi on 4/3/15.
|
||||
//
|
||||
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
|
||||
// A port of MPAndroidChart for iOS
|
||||
// Licensed under Apache License 2.0
|
||||
//
|
||||
// https://github.com/danielgindi/ios-charts
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
public class CandleChartDataEntry: ChartDataEntry
|
||||
{
|
||||
/// shadow-high value
|
||||
public var high = Double(0.0)
|
||||
|
||||
/// shadow-low value
|
||||
public var low = Double(0.0)
|
||||
|
||||
/// close value
|
||||
public var close = Double(0.0)
|
||||
|
||||
/// open value
|
||||
public var open = Double(0.0)
|
||||
|
||||
public required init()
|
||||
{
|
||||
super.init()
|
||||
}
|
||||
|
||||
public init(xIndex: Int, shadowH: Double, shadowL: Double, open: Double, close: Double)
|
||||
{
|
||||
super.init(value: (shadowH + shadowL) / 2.0, xIndex: xIndex)
|
||||
|
||||
self.high = shadowH
|
||||
self.low = shadowL
|
||||
self.open = open
|
||||
self.close = close
|
||||
}
|
||||
|
||||
public init(xIndex: Int, shadowH: Double, shadowL: Double, open: Double, close: Double, data: AnyObject?)
|
||||
{
|
||||
super.init(value: (shadowH + shadowL) / 2.0, xIndex: xIndex, data: data)
|
||||
|
||||
self.high = shadowH
|
||||
self.low = shadowL
|
||||
self.open = open
|
||||
self.close = close
|
||||
}
|
||||
|
||||
/// - returns: the overall range (difference) between shadow-high and shadow-low.
|
||||
public var shadowRange: Double
|
||||
{
|
||||
return abs(high - low)
|
||||
}
|
||||
|
||||
/// - returns: the body size (difference between open and close).
|
||||
public var bodyRange: Double
|
||||
{
|
||||
return abs(open - close)
|
||||
}
|
||||
|
||||
/// the center value of the candle. (Middle value between high and low)
|
||||
public override var value: Double
|
||||
{
|
||||
get
|
||||
{
|
||||
return super.value
|
||||
}
|
||||
set
|
||||
{
|
||||
super.value = (high + low) / 2.0
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: NSCopying
|
||||
|
||||
public override func copyWithZone(zone: NSZone) -> AnyObject
|
||||
{
|
||||
let copy = super.copyWithZone(zone) as! CandleChartDataEntry
|
||||
copy.high = high
|
||||
copy.high = low
|
||||
copy.high = open
|
||||
copy.high = close
|
||||
return copy
|
||||
}
|
||||
}
|
||||
133
Carthage/Checkouts/Charts/Charts/Classes/Data/CandleChartDataSet.swift
vendored
Normal file
133
Carthage/Checkouts/Charts/Charts/Classes/Data/CandleChartDataSet.swift
vendored
Normal file
@@ -0,0 +1,133 @@
|
||||
//
|
||||
// CandleChartDataSet.swift
|
||||
// Charts
|
||||
//
|
||||
// Created by Daniel Cohen Gindi on 4/3/15.
|
||||
//
|
||||
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
|
||||
// A port of MPAndroidChart for iOS
|
||||
// Licensed under Apache License 2.0
|
||||
//
|
||||
// https://github.com/danielgindi/ios-charts
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import CoreGraphics
|
||||
import UIKit
|
||||
|
||||
public class CandleChartDataSet: LineScatterCandleChartDataSet
|
||||
{
|
||||
/// the width of the candle-shadow-line in pixels.
|
||||
///
|
||||
/// **default**: 3.0
|
||||
public var shadowWidth = CGFloat(1.5)
|
||||
|
||||
/// the space between the candle entries
|
||||
///
|
||||
/// **default**: 0.1 (10%)
|
||||
private var _bodySpace = CGFloat(0.1)
|
||||
|
||||
/// the color of the shadow line
|
||||
public var shadowColor: UIColor?
|
||||
|
||||
/// use candle color for the shadow
|
||||
public var shadowColorSameAsCandle = false
|
||||
|
||||
/// color for open <= close
|
||||
public var decreasingColor: UIColor?
|
||||
|
||||
/// color for open > close
|
||||
public var increasingColor: UIColor?
|
||||
|
||||
/// Are decreasing values drawn as filled?
|
||||
public var decreasingFilled = false
|
||||
|
||||
/// Are increasing values drawn as filled?
|
||||
public var increasingFilled = true
|
||||
|
||||
public required init()
|
||||
{
|
||||
super.init()
|
||||
}
|
||||
|
||||
public override init(yVals: [ChartDataEntry]?, label: String?)
|
||||
{
|
||||
super.init(yVals: yVals, label: label)
|
||||
}
|
||||
|
||||
internal override func calcMinMax(start start: Int, end: Int)
|
||||
{
|
||||
if (yVals.count == 0)
|
||||
{
|
||||
return
|
||||
}
|
||||
|
||||
var entries = yVals as! [CandleChartDataEntry]
|
||||
|
||||
var endValue : Int
|
||||
|
||||
if end == 0 || end >= entries.count
|
||||
{
|
||||
endValue = entries.count - 1
|
||||
}
|
||||
else
|
||||
{
|
||||
endValue = end
|
||||
}
|
||||
|
||||
_lastStart = start
|
||||
_lastEnd = end
|
||||
|
||||
_yMin = entries[start].low
|
||||
_yMax = entries[start].high
|
||||
|
||||
for (var i = start + 1; i <= endValue; i++)
|
||||
{
|
||||
let e = entries[i]
|
||||
|
||||
if (e.low < _yMin)
|
||||
{
|
||||
_yMin = e.low
|
||||
}
|
||||
|
||||
if (e.high > _yMax)
|
||||
{
|
||||
_yMax = e.high
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// the space that is left out on the left and right side of each candle,
|
||||
/// **default**: 0.1 (10%), max 0.45, min 0.0
|
||||
public var bodySpace: CGFloat
|
||||
{
|
||||
set
|
||||
{
|
||||
if (newValue < 0.0)
|
||||
{
|
||||
_bodySpace = 0.0
|
||||
}
|
||||
else if (newValue > 0.45)
|
||||
{
|
||||
_bodySpace = 0.45
|
||||
}
|
||||
else
|
||||
{
|
||||
_bodySpace = newValue
|
||||
}
|
||||
}
|
||||
get
|
||||
{
|
||||
return _bodySpace
|
||||
}
|
||||
}
|
||||
|
||||
/// Is the shadow color same as the candle color?
|
||||
public var isShadowColorSameAsCandle: Bool { return shadowColorSameAsCandle }
|
||||
|
||||
/// Are increasing values drawn as filled?
|
||||
public var isIncreasingFilled: Bool { return increasingFilled; }
|
||||
|
||||
/// Are decreasing values drawn as filled?
|
||||
public var isDecreasingFilled: Bool { return decreasingFilled; }
|
||||
}
|
||||
949
Carthage/Checkouts/Charts/Charts/Classes/Data/ChartData.swift
vendored
Normal file
949
Carthage/Checkouts/Charts/Charts/Classes/Data/ChartData.swift
vendored
Normal file
@@ -0,0 +1,949 @@
|
||||
//
|
||||
// ChartData.swift
|
||||
// Charts
|
||||
//
|
||||
// Created by Daniel Cohen Gindi on 23/2/15.
|
||||
|
||||
//
|
||||
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
|
||||
// A port of MPAndroidChart for iOS
|
||||
// Licensed under Apache License 2.0
|
||||
//
|
||||
// https://github.com/danielgindi/ios-charts
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import UIKit
|
||||
|
||||
public class ChartData: NSObject
|
||||
{
|
||||
internal var _yMax = Double(0.0)
|
||||
internal var _yMin = Double(0.0)
|
||||
internal var _leftAxisMax = Double(0.0)
|
||||
internal var _leftAxisMin = Double(0.0)
|
||||
internal var _rightAxisMax = Double(0.0)
|
||||
internal var _rightAxisMin = Double(0.0)
|
||||
private var _yValueSum = Double(0.0)
|
||||
private var _yValCount = Int(0)
|
||||
|
||||
/// the last start value used for calcMinMax
|
||||
internal var _lastStart: Int = 0
|
||||
|
||||
/// the last end value used for calcMinMax
|
||||
internal var _lastEnd: Int = 0
|
||||
|
||||
/// the average length (in characters) across all x-value strings
|
||||
private var _xValAverageLength = Double(0.0)
|
||||
|
||||
internal var _xVals: [String?]!
|
||||
internal var _dataSets: [ChartDataSet]!
|
||||
|
||||
public override init()
|
||||
{
|
||||
super.init()
|
||||
|
||||
_xVals = [String?]()
|
||||
_dataSets = [ChartDataSet]()
|
||||
}
|
||||
|
||||
public init(xVals: [String?]?, dataSets: [ChartDataSet]?)
|
||||
{
|
||||
super.init()
|
||||
|
||||
_xVals = xVals == nil ? [String?]() : xVals
|
||||
_dataSets = dataSets == nil ? [ChartDataSet]() : dataSets
|
||||
|
||||
self.initialize(_dataSets)
|
||||
}
|
||||
|
||||
public init(xVals: [NSObject]?, dataSets: [ChartDataSet]?)
|
||||
{
|
||||
super.init()
|
||||
|
||||
_xVals = xVals == nil ? [String?]() : ChartUtils.bridgedObjCGetStringArray(objc: xVals!)
|
||||
_dataSets = dataSets == nil ? [ChartDataSet]() : dataSets
|
||||
|
||||
self.initialize(_dataSets)
|
||||
}
|
||||
|
||||
public convenience init(xVals: [String?]?)
|
||||
{
|
||||
self.init(xVals: xVals, dataSets: [ChartDataSet]())
|
||||
}
|
||||
|
||||
public convenience init(xVals: [NSObject]?)
|
||||
{
|
||||
self.init(xVals: xVals, dataSets: [ChartDataSet]())
|
||||
}
|
||||
|
||||
public convenience init(xVals: [String?]?, dataSet: ChartDataSet?)
|
||||
{
|
||||
self.init(xVals: xVals, dataSets: dataSet === nil ? nil : [dataSet!])
|
||||
}
|
||||
|
||||
public convenience init(xVals: [NSObject]?, dataSet: ChartDataSet?)
|
||||
{
|
||||
self.init(xVals: xVals, dataSets: dataSet === nil ? nil : [dataSet!])
|
||||
}
|
||||
|
||||
internal func initialize(dataSets: [ChartDataSet])
|
||||
{
|
||||
checkIsLegal(dataSets)
|
||||
|
||||
calcMinMax(start: _lastStart, end: _lastEnd)
|
||||
calcYValueSum()
|
||||
calcYValueCount()
|
||||
|
||||
calcXValAverageLength()
|
||||
}
|
||||
|
||||
// calculates the average length (in characters) across all x-value strings
|
||||
internal func calcXValAverageLength()
|
||||
{
|
||||
if (_xVals.count == 0)
|
||||
{
|
||||
_xValAverageLength = 1
|
||||
return
|
||||
}
|
||||
|
||||
var sum = 1
|
||||
|
||||
for (var i = 0; i < _xVals.count; i++)
|
||||
{
|
||||
sum += _xVals[i] == nil ? 0 : (_xVals[i]!).characters.count
|
||||
}
|
||||
|
||||
_xValAverageLength = Double(sum) / Double(_xVals.count)
|
||||
}
|
||||
|
||||
// Checks if the combination of x-values array and DataSet array is legal or not.
|
||||
// :param: dataSets
|
||||
internal func checkIsLegal(dataSets: [ChartDataSet]!)
|
||||
{
|
||||
if (dataSets == nil)
|
||||
{
|
||||
return
|
||||
}
|
||||
|
||||
if self is ScatterChartData
|
||||
{ // In scatter chart it makes sense to have more than one y-value value for an x-index
|
||||
return
|
||||
}
|
||||
|
||||
for (var i = 0; i < dataSets.count; i++)
|
||||
{
|
||||
if (dataSets[i].yVals.count > _xVals.count)
|
||||
{
|
||||
print("One or more of the DataSet Entry arrays are longer than the x-values array of this Data object.", terminator: "\n")
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public func notifyDataChanged()
|
||||
{
|
||||
initialize(_dataSets)
|
||||
}
|
||||
|
||||
/// calc minimum and maximum y value over all datasets
|
||||
internal func calcMinMax(start start: Int, end: Int)
|
||||
{
|
||||
|
||||
if (_dataSets == nil || _dataSets.count < 1)
|
||||
{
|
||||
_yMax = 0.0
|
||||
_yMin = 0.0
|
||||
}
|
||||
else
|
||||
{
|
||||
_lastStart = start
|
||||
_lastEnd = end
|
||||
|
||||
_yMin = DBL_MAX
|
||||
_yMax = -DBL_MAX
|
||||
|
||||
for (var i = 0; i < _dataSets.count; i++)
|
||||
{
|
||||
_dataSets[i].calcMinMax(start: start, end: end)
|
||||
|
||||
if (_dataSets[i].yMin < _yMin)
|
||||
{
|
||||
_yMin = _dataSets[i].yMin
|
||||
}
|
||||
|
||||
if (_dataSets[i].yMax > _yMax)
|
||||
{
|
||||
_yMax = _dataSets[i].yMax
|
||||
}
|
||||
}
|
||||
|
||||
if (_yMin == DBL_MAX)
|
||||
{
|
||||
_yMin = 0.0
|
||||
_yMax = 0.0
|
||||
}
|
||||
|
||||
// left axis
|
||||
let firstLeft = getFirstLeft()
|
||||
|
||||
if (firstLeft !== nil)
|
||||
{
|
||||
_leftAxisMax = firstLeft!.yMax
|
||||
_leftAxisMin = firstLeft!.yMin
|
||||
|
||||
for dataSet in _dataSets
|
||||
{
|
||||
if (dataSet.axisDependency == .Left)
|
||||
{
|
||||
if (dataSet.yMin < _leftAxisMin)
|
||||
{
|
||||
_leftAxisMin = dataSet.yMin
|
||||
}
|
||||
|
||||
if (dataSet.yMax > _leftAxisMax)
|
||||
{
|
||||
_leftAxisMax = dataSet.yMax
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// right axis
|
||||
let firstRight = getFirstRight()
|
||||
|
||||
if (firstRight !== nil)
|
||||
{
|
||||
_rightAxisMax = firstRight!.yMax
|
||||
_rightAxisMin = firstRight!.yMin
|
||||
|
||||
for dataSet in _dataSets
|
||||
{
|
||||
if (dataSet.axisDependency == .Right)
|
||||
{
|
||||
if (dataSet.yMin < _rightAxisMin)
|
||||
{
|
||||
_rightAxisMin = dataSet.yMin
|
||||
}
|
||||
|
||||
if (dataSet.yMax > _rightAxisMax)
|
||||
{
|
||||
_rightAxisMax = dataSet.yMax
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// in case there is only one axis, adjust the second axis
|
||||
handleEmptyAxis(firstLeft, firstRight: firstRight)
|
||||
}
|
||||
}
|
||||
|
||||
/// calculates the sum of all y-values in all datasets
|
||||
internal func calcYValueSum()
|
||||
{
|
||||
_yValueSum = 0
|
||||
|
||||
if (_dataSets == nil)
|
||||
{
|
||||
return
|
||||
}
|
||||
|
||||
for (var i = 0; i < _dataSets.count; i++)
|
||||
{
|
||||
_yValueSum += fabs(_dataSets[i].yValueSum)
|
||||
}
|
||||
}
|
||||
|
||||
/// Calculates the total number of y-values across all ChartDataSets the ChartData represents.
|
||||
internal func calcYValueCount()
|
||||
{
|
||||
_yValCount = 0
|
||||
|
||||
if (_dataSets == nil)
|
||||
{
|
||||
return
|
||||
}
|
||||
|
||||
var count = 0
|
||||
|
||||
for (var i = 0; i < _dataSets.count; i++)
|
||||
{
|
||||
count += _dataSets[i].entryCount
|
||||
}
|
||||
|
||||
_yValCount = count
|
||||
}
|
||||
|
||||
/// - returns: the number of LineDataSets this object contains
|
||||
public var dataSetCount: Int
|
||||
{
|
||||
if (_dataSets == nil)
|
||||
{
|
||||
return 0
|
||||
}
|
||||
return _dataSets.count
|
||||
}
|
||||
|
||||
/// - returns: the average value across all entries in this Data object (all entries from the DataSets this data object holds)
|
||||
public var average: Double
|
||||
{
|
||||
return yValueSum / Double(yValCount)
|
||||
}
|
||||
|
||||
/// - returns: the smallest y-value the data object contains.
|
||||
public var yMin: Double
|
||||
{
|
||||
return _yMin
|
||||
}
|
||||
|
||||
public func getYMin() -> Double
|
||||
{
|
||||
return _yMin
|
||||
}
|
||||
|
||||
public func getYMin(axis: ChartYAxis.AxisDependency) -> Double
|
||||
{
|
||||
if (axis == .Left)
|
||||
{
|
||||
return _leftAxisMin
|
||||
}
|
||||
else
|
||||
{
|
||||
return _rightAxisMin
|
||||
}
|
||||
}
|
||||
|
||||
/// - returns: the greatest y-value the data object contains.
|
||||
public var yMax: Double
|
||||
{
|
||||
return _yMax
|
||||
}
|
||||
|
||||
public func getYMax() -> Double
|
||||
{
|
||||
return _yMax
|
||||
}
|
||||
|
||||
public func getYMax(axis: ChartYAxis.AxisDependency) -> Double
|
||||
{
|
||||
if (axis == .Left)
|
||||
{
|
||||
return _leftAxisMax
|
||||
}
|
||||
else
|
||||
{
|
||||
return _rightAxisMax
|
||||
}
|
||||
}
|
||||
|
||||
/// - returns: the average length (in characters) across all values in the x-vals array
|
||||
public var xValAverageLength: Double
|
||||
{
|
||||
return _xValAverageLength
|
||||
}
|
||||
|
||||
/// - returns: the total y-value sum across all DataSet objects the this object represents.
|
||||
public var yValueSum: Double
|
||||
{
|
||||
return _yValueSum
|
||||
}
|
||||
|
||||
/// - returns: the total number of y-values across all DataSet objects the this object represents.
|
||||
public var yValCount: Int
|
||||
{
|
||||
return _yValCount
|
||||
}
|
||||
|
||||
/// - returns: the x-values the chart represents
|
||||
public var xVals: [String?]
|
||||
{
|
||||
return _xVals
|
||||
}
|
||||
|
||||
///Adds a new x-value to the chart data.
|
||||
public func addXValue(xVal: String?)
|
||||
{
|
||||
_xVals.append(xVal)
|
||||
}
|
||||
|
||||
/// Removes the x-value at the specified index.
|
||||
public func removeXValue(index: Int)
|
||||
{
|
||||
_xVals.removeAtIndex(index)
|
||||
}
|
||||
|
||||
/// - returns: the array of ChartDataSets this object holds.
|
||||
public var dataSets: [ChartDataSet]
|
||||
{
|
||||
get
|
||||
{
|
||||
return _dataSets
|
||||
}
|
||||
set
|
||||
{
|
||||
_dataSets = newValue
|
||||
}
|
||||
}
|
||||
|
||||
/// Retrieve the index of a ChartDataSet with a specific label from the ChartData. Search can be case sensitive or not.
|
||||
///
|
||||
/// **IMPORTANT: This method does calculations at runtime, do not over-use in performance critical situations.**
|
||||
///
|
||||
/// - parameter dataSets: the DataSet array to search
|
||||
/// - parameter type:
|
||||
/// - parameter ignorecase: if true, the search is not case-sensitive
|
||||
/// - returns: the index of the DataSet Object with the given label. Sensitive or not.
|
||||
internal func getDataSetIndexByLabel(label: String, ignorecase: Bool) -> Int
|
||||
{
|
||||
if (ignorecase)
|
||||
{
|
||||
for (var i = 0; i < dataSets.count; i++)
|
||||
{
|
||||
if (dataSets[i].label == nil)
|
||||
{
|
||||
continue
|
||||
}
|
||||
if (label.caseInsensitiveCompare(dataSets[i].label!) == NSComparisonResult.OrderedSame)
|
||||
{
|
||||
return i
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (var i = 0; i < dataSets.count; i++)
|
||||
{
|
||||
if (label == dataSets[i].label)
|
||||
{
|
||||
return i
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return -1
|
||||
}
|
||||
|
||||
/// - returns: the total number of x-values this ChartData object represents (the size of the x-values array)
|
||||
public var xValCount: Int
|
||||
{
|
||||
return _xVals.count
|
||||
}
|
||||
|
||||
/// - returns: the labels of all DataSets as a string array.
|
||||
internal func dataSetLabels() -> [String]
|
||||
{
|
||||
var types = [String]()
|
||||
|
||||
for (var i = 0; i < _dataSets.count; i++)
|
||||
{
|
||||
if (dataSets[i].label == nil)
|
||||
{
|
||||
continue
|
||||
}
|
||||
|
||||
types[i] = _dataSets[i].label!
|
||||
}
|
||||
|
||||
return types
|
||||
}
|
||||
|
||||
/// Get the Entry for a corresponding highlight object
|
||||
///
|
||||
/// - parameter highlight:
|
||||
/// - returns: the entry that is highlighted
|
||||
public func getEntryForHighlight(highlight: ChartHighlight) -> ChartDataEntry?
|
||||
{
|
||||
if highlight.dataSetIndex >= dataSets.count
|
||||
{
|
||||
return nil
|
||||
}
|
||||
else
|
||||
{
|
||||
return _dataSets[highlight.dataSetIndex].entryForXIndex(highlight.xIndex)
|
||||
}
|
||||
}
|
||||
|
||||
/// **IMPORTANT: This method does calculations at runtime. Use with care in performance critical situations.**
|
||||
///
|
||||
/// - parameter label:
|
||||
/// - parameter ignorecase:
|
||||
/// - returns: the DataSet Object with the given label. Sensitive or not.
|
||||
public func getDataSetByLabel(label: String, ignorecase: Bool) -> ChartDataSet?
|
||||
{
|
||||
let index = getDataSetIndexByLabel(label, ignorecase: ignorecase)
|
||||
|
||||
if (index < 0 || index >= _dataSets.count)
|
||||
{
|
||||
return nil
|
||||
}
|
||||
else
|
||||
{
|
||||
return _dataSets[index]
|
||||
}
|
||||
}
|
||||
|
||||
public func getDataSetByIndex(index: Int) -> ChartDataSet!
|
||||
{
|
||||
if (_dataSets == nil || index < 0 || index >= _dataSets.count)
|
||||
{
|
||||
return nil
|
||||
}
|
||||
|
||||
return _dataSets[index]
|
||||
}
|
||||
|
||||
public func addDataSet(d: ChartDataSet!)
|
||||
{
|
||||
if (_dataSets == nil)
|
||||
{
|
||||
return
|
||||
}
|
||||
|
||||
_yValCount += d.entryCount
|
||||
_yValueSum += d.yValueSum
|
||||
|
||||
if (_dataSets.count == 0)
|
||||
{
|
||||
_yMax = d.yMax
|
||||
_yMin = d.yMin
|
||||
|
||||
if (d.axisDependency == .Left)
|
||||
{
|
||||
_leftAxisMax = d.yMax
|
||||
_leftAxisMin = d.yMin
|
||||
}
|
||||
else
|
||||
{
|
||||
_rightAxisMax = d.yMax
|
||||
_rightAxisMin = d.yMin
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_yMax < d.yMax)
|
||||
{
|
||||
_yMax = d.yMax
|
||||
}
|
||||
if (_yMin > d.yMin)
|
||||
{
|
||||
_yMin = d.yMin
|
||||
}
|
||||
|
||||
if (d.axisDependency == .Left)
|
||||
{
|
||||
if (_leftAxisMax < d.yMax)
|
||||
{
|
||||
_leftAxisMax = d.yMax
|
||||
}
|
||||
if (_leftAxisMin > d.yMin)
|
||||
{
|
||||
_leftAxisMin = d.yMin
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_rightAxisMax < d.yMax)
|
||||
{
|
||||
_rightAxisMax = d.yMax
|
||||
}
|
||||
if (_rightAxisMin > d.yMin)
|
||||
{
|
||||
_rightAxisMin = d.yMin
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_dataSets.append(d)
|
||||
|
||||
handleEmptyAxis(getFirstLeft(), firstRight: getFirstRight())
|
||||
}
|
||||
|
||||
public func handleEmptyAxis(firstLeft: ChartDataSet?, firstRight: ChartDataSet?)
|
||||
{
|
||||
// in case there is only one axis, adjust the second axis
|
||||
if (firstLeft === nil)
|
||||
{
|
||||
_leftAxisMax = _rightAxisMax
|
||||
_leftAxisMin = _rightAxisMin
|
||||
}
|
||||
else if (firstRight === nil)
|
||||
{
|
||||
_rightAxisMax = _leftAxisMax
|
||||
_rightAxisMin = _leftAxisMin
|
||||
}
|
||||
}
|
||||
|
||||
/// Removes the given DataSet from this data object.
|
||||
/// Also recalculates all minimum and maximum values.
|
||||
///
|
||||
/// - returns: true if a DataSet was removed, false if no DataSet could be removed.
|
||||
public func removeDataSet(dataSet: ChartDataSet!) -> Bool
|
||||
{
|
||||
if (_dataSets == nil || dataSet === nil)
|
||||
{
|
||||
return false
|
||||
}
|
||||
|
||||
for (var i = 0; i < _dataSets.count; i++)
|
||||
{
|
||||
if (_dataSets[i] === dataSet)
|
||||
{
|
||||
return removeDataSetByIndex(i)
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
/// Removes the DataSet at the given index in the DataSet array from the data object.
|
||||
/// Also recalculates all minimum and maximum values.
|
||||
///
|
||||
/// - returns: true if a DataSet was removed, false if no DataSet could be removed.
|
||||
public func removeDataSetByIndex(index: Int) -> Bool
|
||||
{
|
||||
if (_dataSets == nil || index >= _dataSets.count || index < 0)
|
||||
{
|
||||
return false
|
||||
}
|
||||
|
||||
let d = _dataSets.removeAtIndex(index)
|
||||
_yValCount -= d.entryCount
|
||||
_yValueSum -= d.yValueSum
|
||||
|
||||
calcMinMax(start: _lastStart, end: _lastEnd)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
/// Adds an Entry to the DataSet at the specified index. Entries are added to the end of the list.
|
||||
public func addEntry(e: ChartDataEntry, dataSetIndex: Int)
|
||||
{
|
||||
if (_dataSets != nil && _dataSets.count > dataSetIndex && dataSetIndex >= 0)
|
||||
{
|
||||
let val = e.value
|
||||
let set = _dataSets[dataSetIndex]
|
||||
|
||||
if (_yValCount == 0)
|
||||
{
|
||||
_yMin = val
|
||||
_yMax = val
|
||||
|
||||
if (set.axisDependency == .Left)
|
||||
{
|
||||
_leftAxisMax = e.value
|
||||
_leftAxisMin = e.value
|
||||
}
|
||||
else
|
||||
{
|
||||
_rightAxisMax = e.value
|
||||
_rightAxisMin = e.value
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_yMax < val)
|
||||
{
|
||||
_yMax = val
|
||||
}
|
||||
if (_yMin > val)
|
||||
{
|
||||
_yMin = val
|
||||
}
|
||||
|
||||
if (set.axisDependency == .Left)
|
||||
{
|
||||
if (_leftAxisMax < e.value)
|
||||
{
|
||||
_leftAxisMax = e.value
|
||||
}
|
||||
if (_leftAxisMin > e.value)
|
||||
{
|
||||
_leftAxisMin = e.value
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_rightAxisMax < e.value)
|
||||
{
|
||||
_rightAxisMax = e.value
|
||||
}
|
||||
if (_rightAxisMin > e.value)
|
||||
{
|
||||
_rightAxisMin = e.value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_yValCount += 1
|
||||
_yValueSum += val
|
||||
|
||||
handleEmptyAxis(getFirstLeft(), firstRight: getFirstRight())
|
||||
|
||||
set.addEntry(e)
|
||||
}
|
||||
else
|
||||
{
|
||||
print("ChartData.addEntry() - dataSetIndex our of range.", terminator: "\n")
|
||||
}
|
||||
}
|
||||
|
||||
/// Removes the given Entry object from the DataSet at the specified index.
|
||||
public func removeEntry(entry: ChartDataEntry!, dataSetIndex: Int) -> Bool
|
||||
{
|
||||
// entry null, outofbounds
|
||||
if (entry === nil || dataSetIndex >= _dataSets.count)
|
||||
{
|
||||
return false
|
||||
}
|
||||
|
||||
// remove the entry from the dataset
|
||||
let removed = _dataSets[dataSetIndex].removeEntry(xIndex: entry.xIndex)
|
||||
|
||||
if (removed)
|
||||
{
|
||||
let val = entry.value
|
||||
|
||||
_yValCount -= 1
|
||||
_yValueSum -= val
|
||||
|
||||
calcMinMax(start: _lastStart, end: _lastEnd)
|
||||
}
|
||||
|
||||
return removed
|
||||
}
|
||||
|
||||
/// Removes the Entry object at the given xIndex from the ChartDataSet at the
|
||||
/// specified index.
|
||||
/// - returns: true if an entry was removed, false if no Entry was found that meets the specified requirements.
|
||||
public func removeEntryByXIndex(xIndex: Int, dataSetIndex: Int) -> Bool
|
||||
{
|
||||
if (dataSetIndex >= _dataSets.count)
|
||||
{
|
||||
return false
|
||||
}
|
||||
|
||||
let entry = _dataSets[dataSetIndex].entryForXIndex(xIndex)
|
||||
|
||||
if (entry?.xIndex != xIndex)
|
||||
{
|
||||
return false
|
||||
}
|
||||
|
||||
return removeEntry(entry, dataSetIndex: dataSetIndex)
|
||||
}
|
||||
|
||||
/// - returns: the DataSet that contains the provided Entry, or null, if no DataSet contains this entry.
|
||||
public func getDataSetForEntry(e: ChartDataEntry!) -> ChartDataSet?
|
||||
{
|
||||
if (e == nil)
|
||||
{
|
||||
return nil
|
||||
}
|
||||
|
||||
for (var i = 0; i < _dataSets.count; i++)
|
||||
{
|
||||
let set = _dataSets[i]
|
||||
|
||||
for (var j = 0; j < set.entryCount; j++)
|
||||
{
|
||||
if (e === set.entryForXIndex(e.xIndex))
|
||||
{
|
||||
return set
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
/// - returns: the index of the provided DataSet inside the DataSets array of this data object. -1 if the DataSet was not found.
|
||||
public func indexOfDataSet(dataSet: ChartDataSet) -> Int
|
||||
{
|
||||
for (var i = 0; i < _dataSets.count; i++)
|
||||
{
|
||||
if (_dataSets[i] === dataSet)
|
||||
{
|
||||
return i
|
||||
}
|
||||
}
|
||||
|
||||
return -1
|
||||
}
|
||||
|
||||
/// - returns: the first DataSet from the datasets-array that has it's dependency on the left axis. Returns null if no DataSet with left dependency could be found.
|
||||
public func getFirstLeft() -> ChartDataSet?
|
||||
{
|
||||
for dataSet in _dataSets
|
||||
{
|
||||
if (dataSet.axisDependency == .Left)
|
||||
{
|
||||
return dataSet
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
/// - returns: the first DataSet from the datasets-array that has it's dependency on the right axis. Returns null if no DataSet with right dependency could be found.
|
||||
public func getFirstRight() -> ChartDataSet?
|
||||
{
|
||||
for dataSet in _dataSets
|
||||
{
|
||||
if (dataSet.axisDependency == .Right)
|
||||
{
|
||||
return dataSet
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
/// - returns: all colors used across all DataSet objects this object represents.
|
||||
public func getColors() -> [UIColor]?
|
||||
{
|
||||
if (_dataSets == nil)
|
||||
{
|
||||
return nil
|
||||
}
|
||||
|
||||
var clrcnt = 0
|
||||
|
||||
for (var i = 0; i < _dataSets.count; i++)
|
||||
{
|
||||
clrcnt += _dataSets[i].colors.count
|
||||
}
|
||||
|
||||
var colors = [UIColor]()
|
||||
|
||||
for (var i = 0; i < _dataSets.count; i++)
|
||||
{
|
||||
let clrs = _dataSets[i].colors
|
||||
|
||||
for clr in clrs
|
||||
{
|
||||
colors.append(clr)
|
||||
}
|
||||
}
|
||||
|
||||
return colors
|
||||
}
|
||||
|
||||
/// Generates an x-values array filled with numbers in range specified by the parameters. Can be used for convenience.
|
||||
public func generateXVals(from: Int, to: Int) -> [String]
|
||||
{
|
||||
var xvals = [String]()
|
||||
|
||||
for (var i = from; i < to; i++)
|
||||
{
|
||||
xvals.append(String(i))
|
||||
}
|
||||
|
||||
return xvals
|
||||
}
|
||||
|
||||
/// Sets a custom ValueFormatter for all DataSets this data object contains.
|
||||
public func setValueFormatter(formatter: NSNumberFormatter!)
|
||||
{
|
||||
for set in dataSets
|
||||
{
|
||||
set.valueFormatter = formatter
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets the color of the value-text (color in which the value-labels are drawn) for all DataSets this data object contains.
|
||||
public func setValueTextColor(color: UIColor!)
|
||||
{
|
||||
for set in dataSets
|
||||
{
|
||||
set.valueTextColor = color ?? set.valueTextColor
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets the font for all value-labels for all DataSets this data object contains.
|
||||
public func setValueFont(font: UIFont!)
|
||||
{
|
||||
for set in dataSets
|
||||
{
|
||||
set.valueFont = font ?? set.valueFont
|
||||
}
|
||||
}
|
||||
|
||||
/// Enables / disables drawing values (value-text) for all DataSets this data object contains.
|
||||
public func setDrawValues(enabled: Bool)
|
||||
{
|
||||
for set in dataSets
|
||||
{
|
||||
set.drawValuesEnabled = enabled
|
||||
}
|
||||
}
|
||||
|
||||
/// Enables / disables highlighting values for all DataSets this data object contains.
|
||||
public var highlightEnabled: Bool
|
||||
{
|
||||
get
|
||||
{
|
||||
for set in dataSets
|
||||
{
|
||||
if (!set.highlightEnabled)
|
||||
{
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
set
|
||||
{
|
||||
for set in dataSets
|
||||
{
|
||||
set.highlightEnabled = newValue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// if true, value highlightning is enabled
|
||||
public var isHighlightEnabled: Bool { return highlightEnabled }
|
||||
|
||||
/// Clears this data object from all DataSets and removes all Entries.
|
||||
/// Don't forget to invalidate the chart after this.
|
||||
public func clearValues()
|
||||
{
|
||||
dataSets.removeAll(keepCapacity: false)
|
||||
notifyDataChanged()
|
||||
}
|
||||
|
||||
/// Checks if this data object contains the specified Entry.
|
||||
/// - returns: true if so, false if not.
|
||||
public func contains(entry entry: ChartDataEntry) -> Bool
|
||||
{
|
||||
for set in dataSets
|
||||
{
|
||||
if (set.contains(entry))
|
||||
{
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
/// Checks if this data object contains the specified DataSet.
|
||||
/// - returns: true if so, false if not.
|
||||
public func contains(dataSet dataSet: ChartDataSet) -> Bool
|
||||
{
|
||||
for set in dataSets
|
||||
{
|
||||
if (set.isEqual(dataSet))
|
||||
{
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
/// MARK: - ObjC compatibility
|
||||
|
||||
/// - returns: the average length (in characters) across all values in the x-vals array
|
||||
public var xValsObjc: [NSObject] { return ChartUtils.bridgedObjCGetStringArray(swift: _xVals); }
|
||||
}
|
||||
131
Carthage/Checkouts/Charts/Charts/Classes/Data/ChartDataEntry.swift
vendored
Normal file
131
Carthage/Checkouts/Charts/Charts/Classes/Data/ChartDataEntry.swift
vendored
Normal file
@@ -0,0 +1,131 @@
|
||||
//
|
||||
// ChartDataEntry.swift
|
||||
// Charts
|
||||
//
|
||||
// Created by Daniel Cohen Gindi on 23/2/15.
|
||||
|
||||
//
|
||||
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
|
||||
// A port of MPAndroidChart for iOS
|
||||
// Licensed under Apache License 2.0
|
||||
//
|
||||
// https://github.com/danielgindi/ios-charts
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
public class ChartDataEntry: NSObject
|
||||
{
|
||||
/// the actual value (y axis)
|
||||
public var value = Double(0.0)
|
||||
|
||||
/// the index on the x-axis
|
||||
public var xIndex = Int(0)
|
||||
|
||||
/// optional spot for additional data this Entry represents
|
||||
public var data: AnyObject?
|
||||
|
||||
public override required init()
|
||||
{
|
||||
super.init()
|
||||
}
|
||||
|
||||
public init(value: Double, xIndex: Int)
|
||||
{
|
||||
super.init()
|
||||
|
||||
self.value = value
|
||||
self.xIndex = xIndex
|
||||
}
|
||||
|
||||
public init(value: Double, xIndex: Int, data: AnyObject?)
|
||||
{
|
||||
super.init()
|
||||
|
||||
self.value = value
|
||||
self.xIndex = xIndex
|
||||
self.data = data
|
||||
}
|
||||
|
||||
// MARK: NSObject
|
||||
|
||||
public override func isEqual(object: AnyObject?) -> Bool
|
||||
{
|
||||
if (object === nil)
|
||||
{
|
||||
return false
|
||||
}
|
||||
|
||||
if (!object!.isKindOfClass(self.dynamicType))
|
||||
{
|
||||
return false
|
||||
}
|
||||
|
||||
if (object!.data !== data && !object!.data.isEqual(self.data))
|
||||
{
|
||||
return false
|
||||
}
|
||||
|
||||
if (object!.xIndex != xIndex)
|
||||
{
|
||||
return false
|
||||
}
|
||||
|
||||
if (fabs(object!.value - value) > 0.00001)
|
||||
{
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// MARK: NSObject
|
||||
|
||||
public override var description: String
|
||||
{
|
||||
return "ChartDataEntry, xIndex: \(xIndex), value \(value)"
|
||||
}
|
||||
|
||||
// MARK: NSCopying
|
||||
|
||||
public func copyWithZone(zone: NSZone) -> AnyObject
|
||||
{
|
||||
let copy = self.dynamicType.init()
|
||||
|
||||
copy.value = value
|
||||
copy.xIndex = xIndex
|
||||
copy.data = data
|
||||
|
||||
return copy
|
||||
}
|
||||
}
|
||||
|
||||
public func ==(lhs: ChartDataEntry, rhs: ChartDataEntry) -> Bool
|
||||
{
|
||||
if (lhs === rhs)
|
||||
{
|
||||
return true
|
||||
}
|
||||
|
||||
if (!lhs.isKindOfClass(rhs.dynamicType))
|
||||
{
|
||||
return false
|
||||
}
|
||||
|
||||
if (lhs.data !== rhs.data && !lhs.data!.isEqual(rhs.data))
|
||||
{
|
||||
return false
|
||||
}
|
||||
|
||||
if (lhs.xIndex != rhs.xIndex)
|
||||
{
|
||||
return false
|
||||
}
|
||||
|
||||
if (fabs(lhs.value - rhs.value) > 0.00001)
|
||||
{
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
550
Carthage/Checkouts/Charts/Charts/Classes/Data/ChartDataSet.swift
vendored
Normal file
550
Carthage/Checkouts/Charts/Charts/Classes/Data/ChartDataSet.swift
vendored
Normal file
@@ -0,0 +1,550 @@
|
||||
//
|
||||
// ChartDataSet.swift
|
||||
// Charts
|
||||
//
|
||||
// Created by Daniel Cohen Gindi on 23/2/15.
|
||||
|
||||
//
|
||||
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
|
||||
// A port of MPAndroidChart for iOS
|
||||
// Licensed under Apache License 2.0
|
||||
//
|
||||
// https://github.com/danielgindi/ios-charts
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import UIKit
|
||||
|
||||
public class ChartDataSet: NSObject
|
||||
{
|
||||
public var colors = [UIColor]()
|
||||
internal var _yVals: [ChartDataEntry]!
|
||||
internal var _yMax = Double(0.0)
|
||||
internal var _yMin = Double(0.0)
|
||||
internal var _yValueSum = Double(0.0)
|
||||
|
||||
/// the last start value used for calcMinMax
|
||||
internal var _lastStart: Int = 0
|
||||
|
||||
/// the last end value used for calcMinMax
|
||||
internal var _lastEnd: Int = 0
|
||||
|
||||
public var label: String? = "DataSet"
|
||||
public var visible = true
|
||||
public var drawValuesEnabled = true
|
||||
|
||||
/// the color used for the value-text
|
||||
public var valueTextColor: UIColor = UIColor.blackColor()
|
||||
|
||||
/// the font for the value-text labels
|
||||
public var valueFont: UIFont = UIFont.systemFontOfSize(7.0)
|
||||
|
||||
/// the formatter used to customly format the values
|
||||
public var valueFormatter: NSNumberFormatter?
|
||||
|
||||
/// the axis this DataSet should be plotted against.
|
||||
public var axisDependency = ChartYAxis.AxisDependency.Left
|
||||
|
||||
public var yVals: [ChartDataEntry] { return _yVals }
|
||||
public var yValueSum: Double { return _yValueSum }
|
||||
public var yMin: Double { return _yMin }
|
||||
public var yMax: Double { return _yMax }
|
||||
|
||||
/// if true, value highlighting is enabled
|
||||
public var highlightEnabled = true
|
||||
|
||||
/// - returns: true if value highlighting is enabled for this dataset
|
||||
public var isHighlightEnabled: Bool { return highlightEnabled }
|
||||
|
||||
public override required init()
|
||||
{
|
||||
super.init()
|
||||
}
|
||||
|
||||
public init(yVals: [ChartDataEntry]?, label: String?)
|
||||
{
|
||||
super.init()
|
||||
|
||||
self.label = label
|
||||
_yVals = yVals == nil ? [ChartDataEntry]() : yVals
|
||||
|
||||
// default color
|
||||
colors.append(UIColor(red: 140.0/255.0, green: 234.0/255.0, blue: 255.0/255.0, alpha: 1.0))
|
||||
|
||||
self.calcMinMax(start: _lastStart, end: _lastEnd)
|
||||
self.calcYValueSum()
|
||||
}
|
||||
|
||||
public convenience init(yVals: [ChartDataEntry]?)
|
||||
{
|
||||
self.init(yVals: yVals, label: "DataSet")
|
||||
}
|
||||
|
||||
/// Use this method to tell the data set that the underlying data has changed
|
||||
public func notifyDataSetChanged()
|
||||
{
|
||||
calcMinMax(start: _lastStart, end: _lastEnd)
|
||||
calcYValueSum()
|
||||
}
|
||||
|
||||
internal func calcMinMax(start start : Int, end: Int)
|
||||
{
|
||||
let yValCount = _yVals.count
|
||||
|
||||
if yValCount == 0
|
||||
{
|
||||
return
|
||||
}
|
||||
|
||||
var endValue : Int
|
||||
|
||||
if end == 0 || end >= yValCount
|
||||
{
|
||||
endValue = yValCount - 1
|
||||
}
|
||||
else
|
||||
{
|
||||
endValue = end
|
||||
}
|
||||
|
||||
_lastStart = start
|
||||
_lastEnd = endValue
|
||||
|
||||
_yMin = DBL_MAX
|
||||
_yMax = -DBL_MAX
|
||||
|
||||
for (var i = start; i <= endValue; i++)
|
||||
{
|
||||
let e = _yVals[i]
|
||||
|
||||
if (!e.value.isNaN)
|
||||
{
|
||||
if (e.value < _yMin)
|
||||
{
|
||||
_yMin = e.value
|
||||
}
|
||||
if (e.value > _yMax)
|
||||
{
|
||||
_yMax = e.value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_yMin == DBL_MAX)
|
||||
{
|
||||
_yMin = 0.0
|
||||
_yMax = 0.0
|
||||
}
|
||||
}
|
||||
|
||||
private func calcYValueSum()
|
||||
{
|
||||
_yValueSum = 0
|
||||
|
||||
for var i = 0; i < _yVals.count; i++
|
||||
{
|
||||
_yValueSum += fabs(_yVals[i].value)
|
||||
}
|
||||
}
|
||||
|
||||
/// - returns: the average value across all entries in this DataSet.
|
||||
public var average: Double
|
||||
{
|
||||
return yValueSum / Double(valueCount)
|
||||
}
|
||||
|
||||
public var entryCount: Int { return _yVals!.count; }
|
||||
|
||||
public func yValForXIndex(x: Int) -> Double
|
||||
{
|
||||
let e = self.entryForXIndex(x)
|
||||
|
||||
if (e !== nil && e!.xIndex == x) { return e!.value }
|
||||
else { return Double.NaN }
|
||||
}
|
||||
|
||||
/// - returns: the first Entry object found at the given xIndex with binary search.
|
||||
/// If the no Entry at the specifed x-index is found, this method returns the Entry at the closest x-index.
|
||||
/// nil if no Entry object at that index.
|
||||
public func entryForXIndex(x: Int) -> ChartDataEntry?
|
||||
{
|
||||
let index = self.entryIndex(xIndex: x)
|
||||
if (index > -1)
|
||||
{
|
||||
return _yVals[index]
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
public func entriesForXIndex(x: Int) -> [ChartDataEntry]
|
||||
{
|
||||
var entries = [ChartDataEntry]()
|
||||
|
||||
var low = 0
|
||||
var high = _yVals.count - 1
|
||||
|
||||
while (low <= high)
|
||||
{
|
||||
var m = Int((high + low) / 2)
|
||||
var entry = _yVals[m]
|
||||
|
||||
if (x == entry.xIndex)
|
||||
{
|
||||
while (m > 0 && _yVals[m - 1].xIndex == x)
|
||||
{
|
||||
m--
|
||||
}
|
||||
|
||||
high = _yVals.count
|
||||
for (; m < high; m++)
|
||||
{
|
||||
entry = _yVals[m]
|
||||
if (entry.xIndex == x)
|
||||
{
|
||||
entries.append(entry)
|
||||
}
|
||||
else
|
||||
{
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (x > _yVals[m].xIndex)
|
||||
{
|
||||
low = m + 1
|
||||
}
|
||||
else
|
||||
{
|
||||
high = m - 1
|
||||
}
|
||||
}
|
||||
|
||||
return entries
|
||||
}
|
||||
|
||||
public func entryIndex(xIndex x: Int) -> Int
|
||||
{
|
||||
var low = 0
|
||||
var high = _yVals.count - 1
|
||||
var closest = -1
|
||||
|
||||
while (low <= high)
|
||||
{
|
||||
var m = (high + low) / 2
|
||||
let entry = _yVals[m]
|
||||
|
||||
if (x == entry.xIndex)
|
||||
{
|
||||
while (m > 0 && _yVals[m - 1].xIndex == x)
|
||||
{
|
||||
m--
|
||||
}
|
||||
|
||||
return m
|
||||
}
|
||||
|
||||
if (x > entry.xIndex)
|
||||
{
|
||||
low = m + 1
|
||||
}
|
||||
else
|
||||
{
|
||||
high = m - 1
|
||||
}
|
||||
|
||||
closest = m
|
||||
}
|
||||
|
||||
return closest
|
||||
}
|
||||
|
||||
public func entryIndex(entry e: ChartDataEntry, isEqual: Bool) -> Int
|
||||
{
|
||||
if (isEqual)
|
||||
{
|
||||
for (var i = 0; i < _yVals.count; i++)
|
||||
{
|
||||
if (_yVals[i].isEqual(e))
|
||||
{
|
||||
return i
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (var i = 0; i < _yVals.count; i++)
|
||||
{
|
||||
if (_yVals[i] === e)
|
||||
{
|
||||
return i
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return -1
|
||||
}
|
||||
|
||||
/// - returns: the number of entries this DataSet holds.
|
||||
public var valueCount: Int { return _yVals.count; }
|
||||
|
||||
/// Adds an Entry to the DataSet dynamically.
|
||||
/// Entries are added to the end of the list.
|
||||
/// This will also recalculate the current minimum and maximum values of the DataSet and the value-sum.
|
||||
/// - parameter e: the entry to add
|
||||
public func addEntry(e: ChartDataEntry)
|
||||
{
|
||||
let val = e.value
|
||||
|
||||
if (_yVals == nil)
|
||||
{
|
||||
_yVals = [ChartDataEntry]()
|
||||
}
|
||||
|
||||
if (_yVals.count == 0)
|
||||
{
|
||||
_yMax = val
|
||||
_yMin = val
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_yMax < val)
|
||||
{
|
||||
_yMax = val
|
||||
}
|
||||
if (_yMin > val)
|
||||
{
|
||||
_yMin = val
|
||||
}
|
||||
}
|
||||
|
||||
_yValueSum += val
|
||||
|
||||
_yVals.append(e)
|
||||
}
|
||||
|
||||
/// Adds an Entry to the DataSet dynamically.
|
||||
/// Entries are added to their appropriate index respective to it's x-index.
|
||||
/// This will also recalculate the current minimum and maximum values of the DataSet and the value-sum.
|
||||
/// - parameter e: the entry to add
|
||||
public func addEntryOrdered(e: ChartDataEntry)
|
||||
{
|
||||
let val = e.value
|
||||
|
||||
if (_yVals == nil)
|
||||
{
|
||||
_yVals = [ChartDataEntry]()
|
||||
}
|
||||
|
||||
if (_yVals.count == 0)
|
||||
{
|
||||
_yMax = val
|
||||
_yMin = val
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_yMax < val)
|
||||
{
|
||||
_yMax = val
|
||||
}
|
||||
if (_yMin > val)
|
||||
{
|
||||
_yMin = val
|
||||
}
|
||||
}
|
||||
|
||||
_yValueSum += val
|
||||
|
||||
if _yVals.last?.xIndex > e.xIndex
|
||||
{
|
||||
var closestIndex = entryIndex(xIndex: e.xIndex)
|
||||
if _yVals[closestIndex].xIndex < e.xIndex
|
||||
{
|
||||
closestIndex++
|
||||
}
|
||||
_yVals.insert(e, atIndex: closestIndex)
|
||||
return;
|
||||
}
|
||||
|
||||
_yVals.append(e)
|
||||
}
|
||||
|
||||
public func removeEntry(entry: ChartDataEntry) -> Bool
|
||||
{
|
||||
var removed = false
|
||||
|
||||
for (var i = 0; i < _yVals.count; i++)
|
||||
{
|
||||
if (_yVals[i] === entry)
|
||||
{
|
||||
_yVals.removeAtIndex(i)
|
||||
removed = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if (removed)
|
||||
{
|
||||
_yValueSum -= entry.value
|
||||
calcMinMax(start: _lastStart, end: _lastEnd)
|
||||
}
|
||||
|
||||
return removed
|
||||
}
|
||||
|
||||
public func removeEntry(xIndex xIndex: Int) -> Bool
|
||||
{
|
||||
let index = self.entryIndex(xIndex: xIndex)
|
||||
if (index > -1)
|
||||
{
|
||||
let e = _yVals.removeAtIndex(index)
|
||||
|
||||
_yValueSum -= e.value
|
||||
calcMinMax(start: _lastStart, end: _lastEnd)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
/// Removes the first Entry (at index 0) of this DataSet from the entries array.
|
||||
///
|
||||
/// - returns: true if successful, false if not.
|
||||
public func removeFirst() -> Bool
|
||||
{
|
||||
let entry: ChartDataEntry? = _yVals.isEmpty ? nil : _yVals.removeFirst()
|
||||
|
||||
let removed = entry != nil
|
||||
|
||||
if (removed)
|
||||
{
|
||||
|
||||
let val = entry!.value
|
||||
_yValueSum -= val
|
||||
|
||||
calcMinMax(start: _lastStart, end: _lastEnd)
|
||||
}
|
||||
|
||||
return removed;
|
||||
}
|
||||
|
||||
/// Removes the last Entry (at index size-1) of this DataSet from the entries array.
|
||||
///
|
||||
/// - returns: true if successful, false if not.
|
||||
public func removeLast() -> Bool
|
||||
{
|
||||
let entry: ChartDataEntry? = _yVals.isEmpty ? nil : _yVals.removeLast()
|
||||
|
||||
let removed = entry != nil
|
||||
|
||||
if (removed)
|
||||
{
|
||||
|
||||
let val = entry!.value
|
||||
_yValueSum -= val
|
||||
|
||||
calcMinMax(start: _lastStart, end: _lastEnd)
|
||||
}
|
||||
|
||||
return removed;
|
||||
}
|
||||
|
||||
public func resetColors()
|
||||
{
|
||||
colors.removeAll(keepCapacity: false)
|
||||
}
|
||||
|
||||
public func addColor(color: UIColor)
|
||||
{
|
||||
colors.append(color)
|
||||
}
|
||||
|
||||
public func setColor(color: UIColor)
|
||||
{
|
||||
colors.removeAll(keepCapacity: false)
|
||||
colors.append(color)
|
||||
}
|
||||
|
||||
public func colorAt(var index: Int) -> UIColor
|
||||
{
|
||||
if (index < 0)
|
||||
{
|
||||
index = 0
|
||||
}
|
||||
return colors[index % colors.count]
|
||||
}
|
||||
|
||||
public var isVisible: Bool
|
||||
{
|
||||
return visible
|
||||
}
|
||||
|
||||
public var isDrawValuesEnabled: Bool
|
||||
{
|
||||
return drawValuesEnabled
|
||||
}
|
||||
|
||||
/// Checks if this DataSet contains the specified Entry.
|
||||
/// - returns: true if contains the entry, false if not.
|
||||
public func contains(e: ChartDataEntry) -> Bool
|
||||
{
|
||||
for entry in _yVals
|
||||
{
|
||||
if (entry.isEqual(e))
|
||||
{
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
/// Removes all values from this DataSet and recalculates min and max value.
|
||||
public func clear()
|
||||
{
|
||||
_yVals.removeAll(keepCapacity: true)
|
||||
_lastStart = 0
|
||||
_lastEnd = 0
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
|
||||
// MARK: NSObject
|
||||
|
||||
public override var description: String
|
||||
{
|
||||
return String(format: "ChartDataSet, label: %@, %i entries", arguments: [self.label ?? "", _yVals.count])
|
||||
}
|
||||
|
||||
public override var debugDescription: String
|
||||
{
|
||||
var desc = description + ":"
|
||||
|
||||
for (var i = 0; i < _yVals.count; i++)
|
||||
{
|
||||
desc += "\n" + _yVals[i].description
|
||||
}
|
||||
|
||||
return desc
|
||||
}
|
||||
|
||||
// MARK: NSCopying
|
||||
|
||||
public func copyWithZone(zone: NSZone) -> AnyObject
|
||||
{
|
||||
let copy = self.dynamicType.init()
|
||||
|
||||
copy.colors = colors
|
||||
copy._yVals = _yVals
|
||||
copy._yMax = _yMax
|
||||
copy._yMin = _yMin
|
||||
copy._yValueSum = _yValueSum
|
||||
copy._lastStart = _lastStart
|
||||
copy._lastEnd = _lastEnd
|
||||
copy.label = label
|
||||
|
||||
return copy
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
213
Carthage/Checkouts/Charts/Charts/Classes/Data/CombinedChartData.swift
vendored
Normal file
213
Carthage/Checkouts/Charts/Charts/Classes/Data/CombinedChartData.swift
vendored
Normal file
@@ -0,0 +1,213 @@
|
||||
//
|
||||
// CombinedChartData.swift
|
||||
// Charts
|
||||
//
|
||||
// Created by Daniel Cohen Gindi on 26/2/15.
|
||||
//
|
||||
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
|
||||
// A port of MPAndroidChart for iOS
|
||||
// Licensed under Apache License 2.0
|
||||
//
|
||||
// https://github.com/danielgindi/ios-charts
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
public class CombinedChartData: BarLineScatterCandleBubbleChartData
|
||||
{
|
||||
private var _lineData: LineChartData!
|
||||
private var _barData: BarChartData!
|
||||
private var _scatterData: ScatterChartData!
|
||||
private var _candleData: CandleChartData!
|
||||
private var _bubbleData: BubbleChartData!
|
||||
|
||||
public override init()
|
||||
{
|
||||
super.init()
|
||||
}
|
||||
|
||||
public override init(xVals: [String?]?, dataSets: [ChartDataSet]?)
|
||||
{
|
||||
super.init(xVals: xVals, dataSets: dataSets)
|
||||
}
|
||||
|
||||
public override init(xVals: [NSObject]?, dataSets: [ChartDataSet]?)
|
||||
{
|
||||
super.init(xVals: xVals, dataSets: dataSets)
|
||||
}
|
||||
|
||||
public var lineData: LineChartData!
|
||||
{
|
||||
get
|
||||
{
|
||||
return _lineData
|
||||
}
|
||||
set
|
||||
{
|
||||
_lineData = newValue
|
||||
for dataSet in newValue.dataSets
|
||||
{
|
||||
_dataSets.append(dataSet)
|
||||
}
|
||||
|
||||
checkIsLegal(newValue.dataSets)
|
||||
|
||||
calcMinMax(start: _lastStart, end: _lastEnd)
|
||||
calcYValueSum()
|
||||
calcYValueCount()
|
||||
|
||||
calcXValAverageLength()
|
||||
}
|
||||
}
|
||||
|
||||
public var barData: BarChartData!
|
||||
{
|
||||
get
|
||||
{
|
||||
return _barData
|
||||
}
|
||||
set
|
||||
{
|
||||
_barData = newValue
|
||||
for dataSet in newValue.dataSets
|
||||
{
|
||||
_dataSets.append(dataSet)
|
||||
}
|
||||
|
||||
checkIsLegal(newValue.dataSets)
|
||||
|
||||
calcMinMax(start: _lastStart, end: _lastEnd)
|
||||
calcYValueSum()
|
||||
calcYValueCount()
|
||||
|
||||
calcXValAverageLength()
|
||||
}
|
||||
}
|
||||
|
||||
public var scatterData: ScatterChartData!
|
||||
{
|
||||
get
|
||||
{
|
||||
return _scatterData
|
||||
}
|
||||
set
|
||||
{
|
||||
_scatterData = newValue
|
||||
for dataSet in newValue.dataSets
|
||||
{
|
||||
_dataSets.append(dataSet)
|
||||
}
|
||||
|
||||
checkIsLegal(newValue.dataSets)
|
||||
|
||||
calcMinMax(start: _lastStart, end: _lastEnd)
|
||||
calcYValueSum()
|
||||
calcYValueCount()
|
||||
|
||||
calcXValAverageLength()
|
||||
}
|
||||
}
|
||||
|
||||
public var candleData: CandleChartData!
|
||||
{
|
||||
get
|
||||
{
|
||||
return _candleData
|
||||
}
|
||||
set
|
||||
{
|
||||
_candleData = newValue
|
||||
for dataSet in newValue.dataSets
|
||||
{
|
||||
_dataSets.append(dataSet)
|
||||
}
|
||||
|
||||
checkIsLegal(newValue.dataSets)
|
||||
|
||||
calcMinMax(start: _lastStart, end: _lastEnd)
|
||||
calcYValueSum()
|
||||
calcYValueCount()
|
||||
|
||||
calcXValAverageLength()
|
||||
}
|
||||
}
|
||||
|
||||
public var bubbleData: BubbleChartData!
|
||||
{
|
||||
get
|
||||
{
|
||||
return _bubbleData
|
||||
}
|
||||
set
|
||||
{
|
||||
_bubbleData = newValue
|
||||
for dataSet in newValue.dataSets
|
||||
{
|
||||
_dataSets.append(dataSet)
|
||||
}
|
||||
|
||||
checkIsLegal(newValue.dataSets)
|
||||
|
||||
calcMinMax(start: _lastStart, end: _lastEnd)
|
||||
calcYValueSum()
|
||||
calcYValueCount()
|
||||
|
||||
calcXValAverageLength()
|
||||
}
|
||||
}
|
||||
|
||||
/// - returns: all data objects in row: line-bar-scatter-candle-bubble if not null.
|
||||
public var allData: [ChartData]
|
||||
{
|
||||
var data = [ChartData]()
|
||||
|
||||
if lineData !== nil
|
||||
{
|
||||
data.append(lineData)
|
||||
}
|
||||
if barData !== nil
|
||||
{
|
||||
data.append(barData)
|
||||
}
|
||||
if scatterData !== nil
|
||||
{
|
||||
data.append(scatterData)
|
||||
}
|
||||
if candleData !== nil
|
||||
{
|
||||
data.append(candleData)
|
||||
}
|
||||
if bubbleData !== nil
|
||||
{
|
||||
data.append(bubbleData)
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
public override func notifyDataChanged()
|
||||
{
|
||||
if (_lineData !== nil)
|
||||
{
|
||||
_lineData.notifyDataChanged()
|
||||
}
|
||||
if (_barData !== nil)
|
||||
{
|
||||
_barData.notifyDataChanged()
|
||||
}
|
||||
if (_scatterData !== nil)
|
||||
{
|
||||
_scatterData.notifyDataChanged()
|
||||
}
|
||||
if (_candleData !== nil)
|
||||
{
|
||||
_candleData.notifyDataChanged()
|
||||
}
|
||||
if (_bubbleData !== nil)
|
||||
{
|
||||
_bubbleData.notifyDataChanged()
|
||||
}
|
||||
|
||||
super.notifyDataChanged() // recalculate everything
|
||||
}
|
||||
}
|
||||
33
Carthage/Checkouts/Charts/Charts/Classes/Data/LineChartData.swift
vendored
Normal file
33
Carthage/Checkouts/Charts/Charts/Classes/Data/LineChartData.swift
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
//
|
||||
// LineChartData.swift
|
||||
// Charts
|
||||
//
|
||||
// Created by Daniel Cohen Gindi on 26/2/15.
|
||||
//
|
||||
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
|
||||
// A port of MPAndroidChart for iOS
|
||||
// Licensed under Apache License 2.0
|
||||
//
|
||||
// https://github.com/danielgindi/ios-charts
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
/// Data object that encapsulates all data associated with a LineChart.
|
||||
public class LineChartData: ChartData
|
||||
{
|
||||
public override init()
|
||||
{
|
||||
super.init()
|
||||
}
|
||||
|
||||
public override init(xVals: [String?]?, dataSets: [ChartDataSet]?)
|
||||
{
|
||||
super.init(xVals: xVals, dataSets: dataSets)
|
||||
}
|
||||
|
||||
public override init(xVals: [NSObject]?, dataSets: [ChartDataSet]?)
|
||||
{
|
||||
super.init(xVals: xVals, dataSets: dataSets)
|
||||
}
|
||||
}
|
||||
119
Carthage/Checkouts/Charts/Charts/Classes/Data/LineChartDataSet.swift
vendored
Normal file
119
Carthage/Checkouts/Charts/Charts/Classes/Data/LineChartDataSet.swift
vendored
Normal file
@@ -0,0 +1,119 @@
|
||||
//
|
||||
// LineChartDataSet.swift
|
||||
// Charts
|
||||
//
|
||||
// Created by Daniel Cohen Gindi on 26/2/15.
|
||||
//
|
||||
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
|
||||
// A port of MPAndroidChart for iOS
|
||||
// Licensed under Apache License 2.0
|
||||
//
|
||||
// https://github.com/danielgindi/ios-charts
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import CoreGraphics
|
||||
import UIKit
|
||||
|
||||
public class LineChartDataSet: LineRadarChartDataSet
|
||||
{
|
||||
public var circleColors = [UIColor]()
|
||||
public var circleHoleColor = UIColor.whiteColor()
|
||||
public var circleRadius = CGFloat(8.0)
|
||||
|
||||
private var _cubicIntensity = CGFloat(0.2)
|
||||
|
||||
public var lineDashPhase = CGFloat(0.0)
|
||||
public var lineDashLengths: [CGFloat]!
|
||||
|
||||
/// if true, drawing circles is enabled
|
||||
public var drawCirclesEnabled = true
|
||||
|
||||
/// if true, cubic lines are drawn instead of linear
|
||||
public var drawCubicEnabled = false
|
||||
|
||||
public var drawCircleHoleEnabled = true
|
||||
|
||||
public required init()
|
||||
{
|
||||
super.init()
|
||||
circleColors.append(UIColor(red: 140.0/255.0, green: 234.0/255.0, blue: 255.0/255.0, alpha: 1.0))
|
||||
}
|
||||
|
||||
public override init(yVals: [ChartDataEntry]?, label: String?)
|
||||
{
|
||||
super.init(yVals: yVals, label: label)
|
||||
circleColors.append(UIColor(red: 140.0/255.0, green: 234.0/255.0, blue: 255.0/255.0, alpha: 1.0))
|
||||
}
|
||||
|
||||
/// intensity for cubic lines (min = 0.05, max = 1)
|
||||
///
|
||||
/// **default**: 0.2
|
||||
public var cubicIntensity: CGFloat
|
||||
{
|
||||
get
|
||||
{
|
||||
return _cubicIntensity
|
||||
}
|
||||
set
|
||||
{
|
||||
_cubicIntensity = newValue
|
||||
if (_cubicIntensity > 1.0)
|
||||
{
|
||||
_cubicIntensity = 1.0
|
||||
}
|
||||
if (_cubicIntensity < 0.05)
|
||||
{
|
||||
_cubicIntensity = 0.05
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// - returns: the color at the given index of the DataSet's circle-color array.
|
||||
/// Performs a IndexOutOfBounds check by modulus.
|
||||
public func getCircleColor(var index: Int) -> UIColor?
|
||||
{
|
||||
let size = circleColors.count
|
||||
index = index % size
|
||||
if (index >= size)
|
||||
{
|
||||
return nil
|
||||
}
|
||||
return circleColors[index]
|
||||
}
|
||||
|
||||
/// Sets the one and ONLY color that should be used for this DataSet.
|
||||
/// Internally, this recreates the colors array and adds the specified color.
|
||||
public func setCircleColor(color: UIColor)
|
||||
{
|
||||
circleColors.removeAll(keepCapacity: false)
|
||||
circleColors.append(color)
|
||||
}
|
||||
|
||||
/// resets the circle-colors array and creates a new one
|
||||
public func resetCircleColors(index: Int)
|
||||
{
|
||||
circleColors.removeAll(keepCapacity: false)
|
||||
}
|
||||
|
||||
public var isDrawCirclesEnabled: Bool { return drawCirclesEnabled; }
|
||||
|
||||
public var isDrawCubicEnabled: Bool { return drawCubicEnabled; }
|
||||
|
||||
public var isDrawCircleHoleEnabled: Bool { return drawCircleHoleEnabled; }
|
||||
|
||||
// MARK: NSCopying
|
||||
|
||||
public override func copyWithZone(zone: NSZone) -> AnyObject
|
||||
{
|
||||
let copy = super.copyWithZone(zone) as! LineChartDataSet
|
||||
copy.circleColors = circleColors
|
||||
copy.circleRadius = circleRadius
|
||||
copy.cubicIntensity = cubicIntensity
|
||||
copy.lineDashPhase = lineDashPhase
|
||||
copy.lineDashLengths = lineDashLengths
|
||||
copy.drawCirclesEnabled = drawCirclesEnabled
|
||||
copy.drawCubicEnabled = drawCubicEnabled
|
||||
return copy
|
||||
}
|
||||
}
|
||||
66
Carthage/Checkouts/Charts/Charts/Classes/Data/LineRadarChartDataSet.swift
vendored
Normal file
66
Carthage/Checkouts/Charts/Charts/Classes/Data/LineRadarChartDataSet.swift
vendored
Normal file
@@ -0,0 +1,66 @@
|
||||
//
|
||||
// LineRadarChartDataSet.swift
|
||||
// Charts
|
||||
//
|
||||
// Created by Daniel Cohen Gindi on 26/2/15.
|
||||
//
|
||||
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
|
||||
// A port of MPAndroidChart for iOS
|
||||
// Licensed under Apache License 2.0
|
||||
//
|
||||
// https://github.com/danielgindi/ios-charts
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import CoreGraphics
|
||||
import UIKit
|
||||
|
||||
public class LineRadarChartDataSet: LineScatterCandleChartDataSet
|
||||
{
|
||||
public var fillColor = UIColor(red: 140.0/255.0, green: 234.0/255.0, blue: 255.0/255.0, alpha: 1.0)
|
||||
public var fillAlpha = CGFloat(0.33)
|
||||
private var _lineWidth = CGFloat(1.0)
|
||||
public var drawFilledEnabled = false
|
||||
|
||||
/// line width of the chart (min = 0.2, max = 10)
|
||||
///
|
||||
/// **default**: 1
|
||||
public var lineWidth: CGFloat
|
||||
{
|
||||
get
|
||||
{
|
||||
return _lineWidth
|
||||
}
|
||||
set
|
||||
{
|
||||
if (newValue < 0.2)
|
||||
{
|
||||
_lineWidth = 0.2
|
||||
}
|
||||
else if (newValue > 10.0)
|
||||
{
|
||||
_lineWidth = 10.0
|
||||
}
|
||||
else
|
||||
{
|
||||
_lineWidth = newValue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public var isDrawFilledEnabled: Bool
|
||||
{
|
||||
return drawFilledEnabled
|
||||
}
|
||||
|
||||
// MARK: NSCopying
|
||||
|
||||
public override func copyWithZone(zone: NSZone) -> AnyObject
|
||||
{
|
||||
let copy = super.copyWithZone(zone) as! LineRadarChartDataSet
|
||||
copy.fillColor = fillColor
|
||||
copy._lineWidth = _lineWidth
|
||||
copy.drawFilledEnabled = drawFilledEnabled
|
||||
return copy
|
||||
}
|
||||
}
|
||||
45
Carthage/Checkouts/Charts/Charts/Classes/Data/LineScatterCandleChartDataSet.swift
vendored
Normal file
45
Carthage/Checkouts/Charts/Charts/Classes/Data/LineScatterCandleChartDataSet.swift
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
//
|
||||
// LineScatterCandleChartDataSet.swift
|
||||
// Charts
|
||||
//
|
||||
// Created by Daniel Cohen Gindi on 29/7/15.
|
||||
//
|
||||
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
|
||||
// A port of MPAndroidChart for iOS
|
||||
// Licensed under Apache License 2.0
|
||||
//
|
||||
// https://github.com/danielgindi/ios-charts
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import UIKit
|
||||
|
||||
public class LineScatterCandleChartDataSet: BarLineScatterCandleBubbleChartDataSet
|
||||
{
|
||||
/// Enables / disables the horizontal highlight-indicator. If disabled, the indicator is not drawn.
|
||||
public var drawHorizontalHighlightIndicatorEnabled = true
|
||||
|
||||
/// Enables / disables the vertical highlight-indicator. If disabled, the indicator is not drawn.
|
||||
public var drawVerticalHighlightIndicatorEnabled = true
|
||||
|
||||
public var isHorizontalHighlightIndicatorEnabled: Bool { return drawHorizontalHighlightIndicatorEnabled }
|
||||
public var isVerticalHighlightIndicatorEnabled: Bool { return drawVerticalHighlightIndicatorEnabled }
|
||||
|
||||
/// Enables / disables both vertical and horizontal highlight-indicators.
|
||||
/// :param: enabled
|
||||
public func setDrawHighlightIndicators(enabled: Bool)
|
||||
{
|
||||
drawHorizontalHighlightIndicatorEnabled = enabled
|
||||
drawVerticalHighlightIndicatorEnabled = enabled
|
||||
}
|
||||
|
||||
// MARK: NSCopying
|
||||
|
||||
public override func copyWithZone(zone: NSZone) -> AnyObject
|
||||
{
|
||||
let copy = super.copyWithZone(zone) as! LineScatterCandleChartDataSet
|
||||
copy.drawHorizontalHighlightIndicatorEnabled = drawHorizontalHighlightIndicatorEnabled
|
||||
copy.drawVerticalHighlightIndicatorEnabled = drawVerticalHighlightIndicatorEnabled
|
||||
return copy
|
||||
}
|
||||
}
|
||||
84
Carthage/Checkouts/Charts/Charts/Classes/Data/PieChartData.swift
vendored
Normal file
84
Carthage/Checkouts/Charts/Charts/Classes/Data/PieChartData.swift
vendored
Normal file
@@ -0,0 +1,84 @@
|
||||
//
|
||||
// PieData.swift
|
||||
// Charts
|
||||
//
|
||||
// Created by Daniel Cohen Gindi on 24/2/15.
|
||||
//
|
||||
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
|
||||
// A port of MPAndroidChart for iOS
|
||||
// Licensed under Apache License 2.0
|
||||
//
|
||||
// https://github.com/danielgindi/ios-charts
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
public class PieChartData: ChartData
|
||||
{
|
||||
public override init()
|
||||
{
|
||||
super.init()
|
||||
}
|
||||
|
||||
public override init(xVals: [String?]?, dataSets: [ChartDataSet]?)
|
||||
{
|
||||
super.init(xVals: xVals, dataSets: dataSets)
|
||||
}
|
||||
|
||||
public override init(xVals: [NSObject]?, dataSets: [ChartDataSet]?)
|
||||
{
|
||||
super.init(xVals: xVals, dataSets: dataSets)
|
||||
}
|
||||
|
||||
var dataSet: PieChartDataSet?
|
||||
{
|
||||
get
|
||||
{
|
||||
return dataSets.count > 0 ? dataSets[0] as? PieChartDataSet : nil
|
||||
}
|
||||
set
|
||||
{
|
||||
if (newValue != nil)
|
||||
{
|
||||
dataSets = [newValue!]
|
||||
}
|
||||
else
|
||||
{
|
||||
dataSets = []
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override func getDataSetByIndex(index: Int) -> ChartDataSet?
|
||||
{
|
||||
if (index != 0)
|
||||
{
|
||||
return nil
|
||||
}
|
||||
return super.getDataSetByIndex(index)
|
||||
}
|
||||
|
||||
public override func getDataSetByLabel(label: String, ignorecase: Bool) -> ChartDataSet?
|
||||
{
|
||||
if (dataSets.count == 0 || dataSets[0].label == nil)
|
||||
{
|
||||
return nil
|
||||
}
|
||||
|
||||
if (ignorecase)
|
||||
{
|
||||
if (label.caseInsensitiveCompare(dataSets[0].label!) == NSComparisonResult.OrderedSame)
|
||||
{
|
||||
return dataSets[0]
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (label == dataSets[0].label)
|
||||
{
|
||||
return dataSets[0]
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
73
Carthage/Checkouts/Charts/Charts/Classes/Data/PieChartDataSet.swift
vendored
Normal file
73
Carthage/Checkouts/Charts/Charts/Classes/Data/PieChartDataSet.swift
vendored
Normal file
@@ -0,0 +1,73 @@
|
||||
//
|
||||
// PieChartDataSet.swift
|
||||
// Charts
|
||||
//
|
||||
// Created by Daniel Cohen Gindi on 24/2/15.
|
||||
|
||||
//
|
||||
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
|
||||
// A port of MPAndroidChart for iOS
|
||||
// Licensed under Apache License 2.0
|
||||
//
|
||||
// https://github.com/danielgindi/ios-charts
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import CoreGraphics
|
||||
import UIKit
|
||||
|
||||
public class PieChartDataSet: ChartDataSet
|
||||
{
|
||||
private var _sliceSpace = CGFloat(0.0)
|
||||
|
||||
/// indicates the selection distance of a pie slice
|
||||
public var selectionShift = CGFloat(18.0)
|
||||
|
||||
public required init()
|
||||
{
|
||||
super.init()
|
||||
|
||||
self.valueTextColor = UIColor.whiteColor()
|
||||
self.valueFont = UIFont.systemFontOfSize(13.0)
|
||||
}
|
||||
|
||||
public override init(yVals: [ChartDataEntry]?, label: String?)
|
||||
{
|
||||
super.init(yVals: yVals, label: label)
|
||||
|
||||
self.valueTextColor = UIColor.whiteColor()
|
||||
self.valueFont = UIFont.systemFontOfSize(13.0)
|
||||
}
|
||||
|
||||
/// the space that is left out between the piechart-slices, default: 0°
|
||||
/// --> no space, maximum 45, minimum 0 (no space)
|
||||
public var sliceSpace: CGFloat
|
||||
{
|
||||
get
|
||||
{
|
||||
return _sliceSpace
|
||||
}
|
||||
set
|
||||
{
|
||||
_sliceSpace = newValue
|
||||
if (_sliceSpace > 45.0)
|
||||
{
|
||||
_sliceSpace = 45.0
|
||||
}
|
||||
if (_sliceSpace < 0.0)
|
||||
{
|
||||
_sliceSpace = 0.0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: NSCopying
|
||||
|
||||
public override func copyWithZone(zone: NSZone) -> AnyObject
|
||||
{
|
||||
let copy = super.copyWithZone(zone) as! PieChartDataSet
|
||||
copy._sliceSpace = _sliceSpace
|
||||
copy.selectionShift = selectionShift
|
||||
return copy
|
||||
}
|
||||
}
|
||||
39
Carthage/Checkouts/Charts/Charts/Classes/Data/RadarChartData.swift
vendored
Normal file
39
Carthage/Checkouts/Charts/Charts/Classes/Data/RadarChartData.swift
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
//
|
||||
// RadarChartData.swift
|
||||
// Charts
|
||||
//
|
||||
// Created by Daniel Cohen Gindi on 26/2/15.
|
||||
//
|
||||
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
|
||||
// A port of MPAndroidChart for iOS
|
||||
// Licensed under Apache License 2.0
|
||||
//
|
||||
// https://github.com/danielgindi/ios-charts
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import CoreGraphics
|
||||
import UIKit
|
||||
|
||||
public class RadarChartData: ChartData
|
||||
{
|
||||
public var highlightColor = UIColor(red: 255.0/255.0, green: 187.0/255.0, blue: 115.0/255.0, alpha: 1.0)
|
||||
public var highlightLineWidth = CGFloat(1.0)
|
||||
public var highlightLineDashPhase = CGFloat(0.0)
|
||||
public var highlightLineDashLengths: [CGFloat]?
|
||||
|
||||
public override init()
|
||||
{
|
||||
super.init()
|
||||
}
|
||||
|
||||
public override init(xVals: [String?]?, dataSets: [ChartDataSet]?)
|
||||
{
|
||||
super.init(xVals: xVals, dataSets: dataSets)
|
||||
}
|
||||
|
||||
public override init(xVals: [NSObject]?, dataSets: [ChartDataSet]?)
|
||||
{
|
||||
super.init(xVals: xVals, dataSets: dataSets)
|
||||
}
|
||||
}
|
||||
33
Carthage/Checkouts/Charts/Charts/Classes/Data/RadarChartDataSet.swift
vendored
Normal file
33
Carthage/Checkouts/Charts/Charts/Classes/Data/RadarChartDataSet.swift
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
//
|
||||
// RadarChartDataSet.swift
|
||||
// Charts
|
||||
//
|
||||
// Created by Daniel Cohen Gindi on 24/2/15.
|
||||
|
||||
//
|
||||
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
|
||||
// A port of MPAndroidChart for iOS
|
||||
// Licensed under Apache License 2.0
|
||||
//
|
||||
// https://github.com/danielgindi/ios-charts
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import UIKit
|
||||
|
||||
public class RadarChartDataSet: LineRadarChartDataSet
|
||||
{
|
||||
public required init()
|
||||
{
|
||||
super.init()
|
||||
|
||||
self.valueFont = UIFont.systemFontOfSize(13.0)
|
||||
}
|
||||
|
||||
public override init(yVals: [ChartDataEntry]?, label: String?)
|
||||
{
|
||||
super.init(yVals: yVals, label: label)
|
||||
|
||||
self.valueFont = UIFont.systemFontOfSize(13.0)
|
||||
}
|
||||
}
|
||||
59
Carthage/Checkouts/Charts/Charts/Classes/Data/ScatterChartData.swift
vendored
Normal file
59
Carthage/Checkouts/Charts/Charts/Classes/Data/ScatterChartData.swift
vendored
Normal file
@@ -0,0 +1,59 @@
|
||||
//
|
||||
// ScatterChartData.swift
|
||||
// Charts
|
||||
//
|
||||
// Created by Daniel Cohen Gindi on 26/2/15.
|
||||
//
|
||||
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
|
||||
// A port of MPAndroidChart for iOS
|
||||
// Licensed under Apache License 2.0
|
||||
//
|
||||
// https://github.com/danielgindi/ios-charts
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
public class ScatterChartData: BarLineScatterCandleBubbleChartData
|
||||
{
|
||||
public override init()
|
||||
{
|
||||
super.init()
|
||||
}
|
||||
|
||||
public override init(xVals: [String?]?, dataSets: [ChartDataSet]?)
|
||||
{
|
||||
super.init(xVals: xVals, dataSets: dataSets)
|
||||
}
|
||||
|
||||
public override init(xVals: [NSObject]?, dataSets: [ChartDataSet]?)
|
||||
{
|
||||
super.init(xVals: xVals, dataSets: dataSets)
|
||||
}
|
||||
|
||||
/// - returns: the maximum shape-size across all DataSets.
|
||||
public func getGreatestShapeSize() -> CGFloat
|
||||
{
|
||||
var max = CGFloat(0.0)
|
||||
|
||||
for set in _dataSets
|
||||
{
|
||||
let scatterDataSet = set as? ScatterChartDataSet
|
||||
|
||||
if (scatterDataSet == nil)
|
||||
{
|
||||
print("ScatterChartData: Found a DataSet which is not a ScatterChartDataSet", terminator: "\n")
|
||||
}
|
||||
else
|
||||
{
|
||||
let size = scatterDataSet!.scatterShapeSize
|
||||
|
||||
if (size > max)
|
||||
{
|
||||
max = size
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return max
|
||||
}
|
||||
}
|
||||
43
Carthage/Checkouts/Charts/Charts/Classes/Data/ScatterChartDataSet.swift
vendored
Normal file
43
Carthage/Checkouts/Charts/Charts/Classes/Data/ScatterChartDataSet.swift
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
//
|
||||
// ScatterChartDataSet.swift
|
||||
// Charts
|
||||
//
|
||||
// Created by Daniel Cohen Gindi on 26/2/15.
|
||||
//
|
||||
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
|
||||
// A port of MPAndroidChart for iOS
|
||||
// Licensed under Apache License 2.0
|
||||
//
|
||||
// https://github.com/danielgindi/ios-charts
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import CoreGraphics
|
||||
|
||||
public class ScatterChartDataSet: LineScatterCandleChartDataSet
|
||||
{
|
||||
@objc
|
||||
public enum ScatterShape: Int
|
||||
{
|
||||
case Cross
|
||||
case Triangle
|
||||
case Circle
|
||||
case Square
|
||||
case Custom
|
||||
}
|
||||
|
||||
public var scatterShapeSize = CGFloat(15.0)
|
||||
public var scatterShape = ScatterShape.Square
|
||||
public var customScatterShape: CGPath?
|
||||
|
||||
// MARK: NSCopying
|
||||
|
||||
public override func copyWithZone(zone: NSZone) -> AnyObject
|
||||
{
|
||||
let copy = super.copyWithZone(zone) as! ScatterChartDataSet
|
||||
copy.scatterShapeSize = scatterShapeSize
|
||||
copy.scatterShape = scatterShape
|
||||
copy.customScatterShape = customScatterShape
|
||||
return copy
|
||||
}
|
||||
}
|
||||
214
Carthage/Checkouts/Charts/Charts/Classes/Filters/ChartDataApproximatorFilter.swift
vendored
Normal file
214
Carthage/Checkouts/Charts/Charts/Classes/Filters/ChartDataApproximatorFilter.swift
vendored
Normal file
@@ -0,0 +1,214 @@
|
||||
//
|
||||
// ChartDataApproximator.swift
|
||||
// Charts
|
||||
//
|
||||
// Created by Daniel Cohen Gindi on 23/2/15.
|
||||
|
||||
//
|
||||
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
|
||||
// A port of MPAndroidChart for iOS
|
||||
// Licensed under Apache License 2.0
|
||||
//
|
||||
// https://github.com/danielgindi/ios-charts
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
public class ChartDataApproximatorFilter: ChartDataBaseFilter
|
||||
{
|
||||
@objc
|
||||
public enum ApproximatorType: Int
|
||||
{
|
||||
case None
|
||||
case RamerDouglasPeucker
|
||||
}
|
||||
|
||||
/// the type of filtering algorithm to use
|
||||
public var type = ApproximatorType.None
|
||||
|
||||
/// the tolerance to be filtered with
|
||||
/// When using the Douglas-Peucker-Algorithm, the tolerance is an angle in degrees, that will trigger the filtering
|
||||
public var tolerance = Double(0.0)
|
||||
|
||||
public var scaleRatio = Double(1.0)
|
||||
public var deltaRatio = Double(1.0)
|
||||
|
||||
public override init()
|
||||
{
|
||||
super.init()
|
||||
}
|
||||
|
||||
/// Initializes the approximator with the given type and tolerance.
|
||||
/// If toleranec <= 0, no filtering will be done.
|
||||
public init(type: ApproximatorType, tolerance: Double)
|
||||
{
|
||||
super.init()
|
||||
|
||||
setup(type, tolerance: tolerance)
|
||||
}
|
||||
|
||||
/// Sets type and tolerance.
|
||||
/// If tolerance <= 0, no filtering will be done.
|
||||
public func setup(type: ApproximatorType, tolerance: Double)
|
||||
{
|
||||
self.type = type
|
||||
self.tolerance = tolerance
|
||||
}
|
||||
|
||||
/// Sets the ratios for x- and y-axis, as well as the ratio of the scale levels
|
||||
public func setRatios(deltaRatio: Double, scaleRatio: Double)
|
||||
{
|
||||
self.deltaRatio = deltaRatio
|
||||
self.scaleRatio = scaleRatio
|
||||
}
|
||||
|
||||
/// Filters according to type. Uses the pre set set tolerance
|
||||
///
|
||||
/// - parameter points: the points to filter
|
||||
public override func filter(points: [ChartDataEntry]) -> [ChartDataEntry]
|
||||
{
|
||||
return filter(points, tolerance: tolerance)
|
||||
}
|
||||
|
||||
/// Filters according to type.
|
||||
///
|
||||
/// - parameter points: the points to filter
|
||||
/// - parameter tolerance: the angle in degrees that will trigger the filtering
|
||||
public func filter(points: [ChartDataEntry], tolerance: Double) -> [ChartDataEntry]
|
||||
{
|
||||
if (tolerance <= 0)
|
||||
{
|
||||
return points
|
||||
}
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case .RamerDouglasPeucker:
|
||||
return reduceWithDouglasPeuker(points, epsilon: tolerance)
|
||||
case .None:
|
||||
return points
|
||||
}
|
||||
}
|
||||
|
||||
/// uses the douglas peuker algorithm to reduce the given arraylist of entries
|
||||
private func reduceWithDouglasPeuker(entries: [ChartDataEntry], epsilon: Double) -> [ChartDataEntry]
|
||||
{
|
||||
// if a shape has 2 or less points it cannot be reduced
|
||||
if (epsilon <= 0 || entries.count < 3)
|
||||
{
|
||||
return entries
|
||||
}
|
||||
|
||||
var keep = [Bool](count: entries.count, repeatedValue: false)
|
||||
|
||||
// first and last always stay
|
||||
keep[0] = true
|
||||
keep[entries.count - 1] = true
|
||||
|
||||
// first and last entry are entry point to recursion
|
||||
algorithmDouglasPeucker(entries, epsilon: epsilon, start: 0, end: entries.count - 1, keep: &keep)
|
||||
|
||||
// create a new array with series, only take the kept ones
|
||||
var reducedEntries = [ChartDataEntry]()
|
||||
for (var i = 0; i < entries.count; i++)
|
||||
{
|
||||
if (keep[i])
|
||||
{
|
||||
let curEntry = entries[i]
|
||||
reducedEntries.append(ChartDataEntry(value: curEntry.value, xIndex: curEntry.xIndex))
|
||||
}
|
||||
}
|
||||
|
||||
return reducedEntries
|
||||
}
|
||||
|
||||
/// apply the Douglas-Peucker-Reduction to an ArrayList of Entry with a given epsilon (tolerance)
|
||||
///
|
||||
/// - parameter entries:
|
||||
/// - parameter epsilon: as y-value
|
||||
/// - parameter start:
|
||||
/// - parameter end:
|
||||
private func algorithmDouglasPeucker(entries: [ChartDataEntry], epsilon: Double, start: Int, end: Int, inout keep: [Bool])
|
||||
{
|
||||
if (end <= start + 1)
|
||||
{
|
||||
// recursion finished
|
||||
return
|
||||
}
|
||||
|
||||
// find the greatest distance between start and endpoint
|
||||
var maxDistIndex = Int(0)
|
||||
var distMax = Double(0.0)
|
||||
|
||||
let firstEntry = entries[start]
|
||||
let lastEntry = entries[end]
|
||||
|
||||
for (var i = start + 1; i < end; i++)
|
||||
{
|
||||
let dist = calcAngleBetweenLines(firstEntry, end1: lastEntry, start2: firstEntry, end2: entries[i])
|
||||
|
||||
// keep the point with the greatest distance
|
||||
if (dist > distMax)
|
||||
{
|
||||
distMax = dist
|
||||
maxDistIndex = i
|
||||
}
|
||||
}
|
||||
|
||||
if (distMax > epsilon)
|
||||
{
|
||||
// keep max dist point
|
||||
keep[maxDistIndex] = true
|
||||
|
||||
// recursive call
|
||||
algorithmDouglasPeucker(entries, epsilon: epsilon, start: start, end: maxDistIndex, keep: &keep)
|
||||
algorithmDouglasPeucker(entries, epsilon: epsilon, start: maxDistIndex, end: end, keep: &keep)
|
||||
} // else don't keep the point...
|
||||
}
|
||||
|
||||
/// calculate the distance between a line between two entries and an entry (point)
|
||||
///
|
||||
/// - parameter startEntry: line startpoint
|
||||
/// - parameter endEntry: line endpoint
|
||||
/// - parameter entryPoint: the point to which the distance is measured from the line
|
||||
private func calcPointToLineDistance(startEntry: ChartDataEntry, endEntry: ChartDataEntry, entryPoint: ChartDataEntry) -> Double
|
||||
{
|
||||
let xDiffEndStart = Double(endEntry.xIndex) - Double(startEntry.xIndex)
|
||||
let xDiffEntryStart = Double(entryPoint.xIndex) - Double(startEntry.xIndex)
|
||||
|
||||
let normalLength = sqrt((xDiffEndStart)
|
||||
* (xDiffEndStart)
|
||||
+ (endEntry.value - startEntry.value)
|
||||
* (endEntry.value - startEntry.value))
|
||||
|
||||
return Double(fabs((xDiffEntryStart)
|
||||
* (endEntry.value - startEntry.value)
|
||||
- (entryPoint.value - startEntry.value)
|
||||
* (xDiffEndStart))) / Double(normalLength)
|
||||
}
|
||||
|
||||
/// Calculates the angle between two given lines. The provided entries mark the starting and end points of the lines.
|
||||
private func calcAngleBetweenLines(start1: ChartDataEntry, end1: ChartDataEntry, start2: ChartDataEntry, end2: ChartDataEntry) -> Double
|
||||
{
|
||||
let angle1 = calcAngleWithRatios(start1, p2: end1)
|
||||
let angle2 = calcAngleWithRatios(start2, p2: end2)
|
||||
|
||||
return fabs(angle1 - angle2)
|
||||
}
|
||||
|
||||
/// calculates the angle between two entries (points) in the chart taking ratios into consideration
|
||||
private func calcAngleWithRatios(p1: ChartDataEntry, p2: ChartDataEntry) -> Double
|
||||
{
|
||||
let dx = Double(p2.xIndex) * Double(deltaRatio) - Double(p1.xIndex) * Double(deltaRatio)
|
||||
let dy = p2.value * scaleRatio - p1.value * scaleRatio
|
||||
return atan2(Double(dy), dx) * ChartUtils.Math.RAD2DEG
|
||||
}
|
||||
|
||||
// calculates the angle between two entries (points) in the chart
|
||||
private func calcAngle(p1: ChartDataEntry, p2: ChartDataEntry) -> Double
|
||||
{
|
||||
let dx = p2.xIndex - p1.xIndex
|
||||
let dy = p2.value - p1.value
|
||||
return atan2(Double(dy), Double(dx)) * ChartUtils.Math.RAD2DEG
|
||||
}
|
||||
}
|
||||
28
Carthage/Checkouts/Charts/Charts/Classes/Filters/ChartDataBaseFilter.swift
vendored
Normal file
28
Carthage/Checkouts/Charts/Charts/Classes/Filters/ChartDataBaseFilter.swift
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
//
|
||||
// ChartDataFilter.swift
|
||||
// Charts
|
||||
//
|
||||
// Created by Daniel Cohen Gindi on 23/2/15.
|
||||
|
||||
//
|
||||
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
|
||||
// A port of MPAndroidChart for iOS
|
||||
// Licensed under Apache License 2.0
|
||||
//
|
||||
// https://github.com/danielgindi/ios-charts
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
public class ChartDataBaseFilter: NSObject
|
||||
{
|
||||
public override init()
|
||||
{
|
||||
super.init()
|
||||
}
|
||||
|
||||
public func filter(points: [ChartDataEntry]) -> [ChartDataEntry]
|
||||
{
|
||||
fatalError("filter() cannot be called on ChartDataBaseFilter")
|
||||
}
|
||||
}
|
||||
25
Carthage/Checkouts/Charts/Charts/Classes/Formatters/ChartDefaultXAxisValueFormatter.swift
vendored
Normal file
25
Carthage/Checkouts/Charts/Charts/Classes/Formatters/ChartDefaultXAxisValueFormatter.swift
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
//
|
||||
// ChartDefaultXAxisValueFormatter.swift
|
||||
// Charts
|
||||
//
|
||||
// Created by Daniel Cohen Gindi on 27/2/15.
|
||||
//
|
||||
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
|
||||
// A port of MPAndroidChart for iOS
|
||||
// Licensed under Apache License 2.0
|
||||
//
|
||||
// https://github.com/danielgindi/ios-charts
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
/// An interface for providing custom x-axis Strings.
|
||||
public class ChartDefaultXAxisValueFormatter: NSObject, ChartXAxisValueFormatter
|
||||
{
|
||||
|
||||
public func stringForXValue(index: Int, original: String, viewPortHandler: ChartViewPortHandler) -> String
|
||||
{
|
||||
return original // just return original, no adjustments
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,21 +1,23 @@
|
||||
//
|
||||
// IFillFormatter.swift
|
||||
// ChartFillFormatter.swift
|
||||
// Charts
|
||||
//
|
||||
// Created by Daniel Cohen Gindi on 6/3/15.
|
||||
//
|
||||
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
|
||||
// A port of MPAndroidChart for iOS
|
||||
// Licensed under Apache License 2.0
|
||||
//
|
||||
// https://github.com/danielgindi/Charts
|
||||
// https://github.com/danielgindi/ios-charts
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import CoreGraphics
|
||||
|
||||
/// Protocol for providing a custom logic to where the filling line of a LineDataSet should end. This of course only works if setFillEnabled(...) is set to true.
|
||||
@objc(IChartFillFormatter)
|
||||
public protocol IFillFormatter
|
||||
@objc
|
||||
public protocol ChartFillFormatter
|
||||
{
|
||||
/// - Returns: The vertical (y-axis) position where the filled-line of the LineDataSet should end.
|
||||
func getFillLinePosition(dataSet: ILineChartDataSet, dataProvider: LineChartDataProvider) -> CGFloat
|
||||
/// - returns: the vertical (y-axis) position where the filled-line of the LineDataSet should end.
|
||||
func getFillLinePosition(dataSet dataSet: LineChartDataSet, data: LineChartData, chartMaxY: Double, chartMinY: Double) -> CGFloat
|
||||
}
|
||||
30
Carthage/Checkouts/Charts/Charts/Classes/Formatters/ChartXAxisValueFormatter.swift
vendored
Normal file
30
Carthage/Checkouts/Charts/Charts/Classes/Formatters/ChartXAxisValueFormatter.swift
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
//
|
||||
// ChartXAxisValueFormatter.swift
|
||||
// Charts
|
||||
//
|
||||
// Created by Daniel Cohen Gindi on 27/2/15.
|
||||
//
|
||||
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
|
||||
// A port of MPAndroidChart for iOS
|
||||
// Licensed under Apache License 2.0
|
||||
//
|
||||
// https://github.com/danielgindi/ios-charts
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
/// An interface for providing custom x-axis Strings.
|
||||
@objc
|
||||
public protocol ChartXAxisValueFormatter
|
||||
{
|
||||
|
||||
/// For performance reasons, avoid excessive calculations and memory allocations inside this method.
|
||||
///
|
||||
/// - returns: the customized label that is drawn on the x-axis.
|
||||
/// - parameter index: the x-index that is currently being drawn
|
||||
/// - parameter original: the original x-axis label to be drawn
|
||||
/// - parameter viewPortHandler: provides information about the current chart state (scale, translation, ...)
|
||||
///
|
||||
func stringForXValue(index: Int, original: String, viewPortHandler: ChartViewPortHandler) -> String
|
||||
|
||||
}
|
||||
244
Carthage/Checkouts/Charts/Charts/Classes/Highlight/BarChartHighlighter.swift
vendored
Normal file
244
Carthage/Checkouts/Charts/Charts/Classes/Highlight/BarChartHighlighter.swift
vendored
Normal file
@@ -0,0 +1,244 @@
|
||||
//
|
||||
// ChartBarHighlighter.swift
|
||||
// Charts
|
||||
//
|
||||
// Created by Daniel Cohen Gindi on 26/7/15.
|
||||
|
||||
//
|
||||
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
|
||||
// A port of MPAndroidChart for iOS
|
||||
// Licensed under Apache License 2.0
|
||||
//
|
||||
// https://github.com/danielgindi/ios-charts
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import CoreGraphics
|
||||
|
||||
internal class BarChartHighlighter: ChartHighlighter
|
||||
{
|
||||
internal init(chart: BarChartView)
|
||||
{
|
||||
super.init(chart: chart)
|
||||
}
|
||||
|
||||
internal override func getHighlight(x x: Double, y: Double) -> ChartHighlight?
|
||||
{
|
||||
let h = super.getHighlight(x: x, y: y)
|
||||
|
||||
if h === nil
|
||||
{
|
||||
return h
|
||||
}
|
||||
else
|
||||
{
|
||||
if let set = _chart?.data?.getDataSetByIndex(h!.dataSetIndex) as? BarChartDataSet
|
||||
{
|
||||
if set.isStacked
|
||||
{
|
||||
// create an array of the touch-point
|
||||
var pt = CGPoint()
|
||||
pt.y = CGFloat(y)
|
||||
|
||||
// take any transformer to determine the x-axis value
|
||||
_chart?.getTransformer(set.axisDependency).pixelToValue(&pt)
|
||||
|
||||
return getStackedHighlight(old: h, set: set, xIndex: h!.xIndex, dataSetIndex: h!.dataSetIndex, yValue: Double(pt.y))
|
||||
}
|
||||
}
|
||||
|
||||
return h
|
||||
}
|
||||
}
|
||||
|
||||
internal override func getXIndex(x: Double) -> Int
|
||||
{
|
||||
if let barChartData = _chart?.data as? BarChartData
|
||||
{
|
||||
if !barChartData.isGrouped
|
||||
{
|
||||
return super.getXIndex(x)
|
||||
}
|
||||
else
|
||||
{
|
||||
let baseNoSpace = getBase(x)
|
||||
|
||||
let setCount = barChartData.dataSetCount
|
||||
var xIndex = Int(baseNoSpace) / setCount
|
||||
|
||||
let valCount = barChartData.xValCount
|
||||
|
||||
if xIndex < 0
|
||||
{
|
||||
xIndex = 0
|
||||
}
|
||||
else if xIndex >= valCount
|
||||
{
|
||||
xIndex = valCount - 1
|
||||
}
|
||||
|
||||
return xIndex
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
internal override func getDataSetIndex(xIndex xIndex: Int, x: Double, y: Double) -> Int
|
||||
{
|
||||
if let barChartData = _chart?.data as? BarChartData
|
||||
{
|
||||
if !barChartData.isGrouped
|
||||
{
|
||||
return 0
|
||||
}
|
||||
else
|
||||
{
|
||||
let baseNoSpace = getBase(x)
|
||||
|
||||
let setCount = barChartData.dataSetCount
|
||||
var dataSetIndex = Int(baseNoSpace) % setCount
|
||||
|
||||
if dataSetIndex < 0
|
||||
{
|
||||
dataSetIndex = 0
|
||||
}
|
||||
else if dataSetIndex >= setCount
|
||||
{
|
||||
dataSetIndex = setCount - 1
|
||||
}
|
||||
|
||||
return dataSetIndex
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
/// This method creates the Highlight object that also indicates which value of a stacked BarEntry has been selected.
|
||||
/// - parameter old: the old highlight object before looking for stacked values
|
||||
/// - parameter set:
|
||||
/// - parameter xIndex:
|
||||
/// - parameter dataSetIndex:
|
||||
/// - parameter yValue:
|
||||
/// - returns:
|
||||
internal func getStackedHighlight(old old: ChartHighlight?, set: BarChartDataSet, xIndex: Int, dataSetIndex: Int, yValue: Double) -> ChartHighlight?
|
||||
{
|
||||
let entry = set.entryForXIndex(xIndex) as? BarChartDataEntry
|
||||
|
||||
if entry?.values === nil
|
||||
{
|
||||
return old
|
||||
}
|
||||
|
||||
if let ranges = getRanges(entry: entry!)
|
||||
{
|
||||
let stackIndex = getClosestStackIndex(ranges: ranges, value: yValue)
|
||||
let h = ChartHighlight(xIndex: xIndex, dataSetIndex: dataSetIndex, stackIndex: stackIndex, range: ranges[stackIndex])
|
||||
return h
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
/// Returns the index of the closest value inside the values array / ranges (stacked barchart) to the value given as a parameter.
|
||||
/// - parameter entry:
|
||||
/// - parameter value:
|
||||
/// - returns:
|
||||
internal func getClosestStackIndex(ranges ranges: [ChartRange]?, value: Double) -> Int
|
||||
{
|
||||
if ranges == nil
|
||||
{
|
||||
return 0
|
||||
}
|
||||
|
||||
var stackIndex = 0
|
||||
|
||||
for range in ranges!
|
||||
{
|
||||
if range.contains(value)
|
||||
{
|
||||
return stackIndex
|
||||
}
|
||||
else
|
||||
{
|
||||
stackIndex++
|
||||
}
|
||||
}
|
||||
|
||||
let length = ranges!.count - 1
|
||||
|
||||
return (value > ranges![length].to) ? length : 0
|
||||
}
|
||||
|
||||
/// Returns the base x-value to the corresponding x-touch value in pixels.
|
||||
/// - parameter x:
|
||||
/// - returns:
|
||||
internal func getBase(x: Double) -> Double
|
||||
{
|
||||
if let barChartData = _chart?.data as? BarChartData
|
||||
{
|
||||
// create an array of the touch-point
|
||||
var pt = CGPoint()
|
||||
pt.x = CGFloat(x)
|
||||
|
||||
// take any transformer to determine the x-axis value
|
||||
_chart?.getTransformer(ChartYAxis.AxisDependency.Left).pixelToValue(&pt)
|
||||
let xVal = Double(pt.x)
|
||||
|
||||
let setCount = barChartData.dataSetCount ?? 0
|
||||
|
||||
// calculate how often the group-space appears
|
||||
let steps = Int(xVal / (Double(setCount) + Double(barChartData.groupSpace)))
|
||||
|
||||
let groupSpaceSum = Double(barChartData.groupSpace) * Double(steps)
|
||||
|
||||
let baseNoSpace = xVal - groupSpaceSum
|
||||
|
||||
return baseNoSpace
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0.0
|
||||
}
|
||||
}
|
||||
|
||||
/// Splits up the stack-values of the given bar-entry into Range objects.
|
||||
/// - parameter entry:
|
||||
/// - returns:
|
||||
internal func getRanges(entry entry: BarChartDataEntry) -> [ChartRange]?
|
||||
{
|
||||
let values = entry.values
|
||||
if (values == nil)
|
||||
{
|
||||
return nil
|
||||
}
|
||||
|
||||
var negRemain = -entry.negativeSum
|
||||
var posRemain: Double = 0.0
|
||||
|
||||
var ranges = [ChartRange]()
|
||||
ranges.reserveCapacity(values!.count)
|
||||
|
||||
for (var i = 0, count = values!.count; i < count; i++)
|
||||
{
|
||||
let value = values![i]
|
||||
|
||||
if value < 0
|
||||
{
|
||||
ranges.append(ChartRange(from: negRemain, to: negRemain + abs(value)))
|
||||
negRemain += abs(value)
|
||||
}
|
||||
else
|
||||
{
|
||||
ranges.append(ChartRange(from: posRemain, to: posRemain+value))
|
||||
posRemain += value
|
||||
}
|
||||
}
|
||||
|
||||
return ranges
|
||||
}
|
||||
}
|
||||
141
Carthage/Checkouts/Charts/Charts/Classes/Highlight/ChartHighlight.swift
vendored
Normal file
141
Carthage/Checkouts/Charts/Charts/Classes/Highlight/ChartHighlight.swift
vendored
Normal file
@@ -0,0 +1,141 @@
|
||||
//
|
||||
// ChartHighlight.swift
|
||||
// Charts
|
||||
//
|
||||
// Created by Daniel Cohen Gindi on 23/2/15.
|
||||
|
||||
//
|
||||
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
|
||||
// A port of MPAndroidChart for iOS
|
||||
// Licensed under Apache License 2.0
|
||||
//
|
||||
// https://github.com/danielgindi/ios-charts
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
public class ChartHighlight: NSObject
|
||||
{
|
||||
/// the x-index of the highlighted value
|
||||
private var _xIndex = Int(0)
|
||||
|
||||
/// the index of the dataset the highlighted value is in
|
||||
private var _dataSetIndex = Int(0)
|
||||
|
||||
/// index which value of a stacked bar entry is highlighted
|
||||
///
|
||||
/// **default**: -1
|
||||
private var _stackIndex = Int(-1)
|
||||
|
||||
/// the range of the bar that is selected (only for stacked-barchart)
|
||||
private var _range: ChartRange?
|
||||
|
||||
public override init()
|
||||
{
|
||||
super.init()
|
||||
}
|
||||
|
||||
public init(xIndex x: Int, dataSetIndex: Int)
|
||||
{
|
||||
super.init()
|
||||
|
||||
_xIndex = x
|
||||
_dataSetIndex = dataSetIndex
|
||||
}
|
||||
|
||||
public init(xIndex x: Int, dataSetIndex: Int, stackIndex: Int)
|
||||
{
|
||||
super.init()
|
||||
|
||||
_xIndex = x
|
||||
_dataSetIndex = dataSetIndex
|
||||
_stackIndex = stackIndex
|
||||
}
|
||||
|
||||
/// Constructor, only used for stacked-barchart.
|
||||
///
|
||||
/// - parameter x: the index of the highlighted value on the x-axis
|
||||
/// - parameter dataSet: the index of the DataSet the highlighted value belongs to
|
||||
/// - parameter stackIndex: references which value of a stacked-bar entry has been selected
|
||||
/// - parameter range: the range the selected stack-value is in
|
||||
public convenience init(xIndex x: Int, dataSetIndex: Int, stackIndex: Int, range: ChartRange)
|
||||
{
|
||||
self.init(xIndex: x, dataSetIndex: dataSetIndex, stackIndex: stackIndex)
|
||||
|
||||
_range = range
|
||||
}
|
||||
|
||||
public var dataSetIndex: Int { return _dataSetIndex; }
|
||||
public var xIndex: Int { return _xIndex; }
|
||||
public var stackIndex: Int { return _stackIndex; }
|
||||
|
||||
/// - returns: the range of values the selected value of a stacked bar is in. (this is only relevant for stacked-barchart)
|
||||
public var range: ChartRange? { return _range }
|
||||
|
||||
// MARK: NSObject
|
||||
|
||||
public override var description: String
|
||||
{
|
||||
return "Highlight, xIndex: \(_xIndex), dataSetIndex: \(_dataSetIndex), stackIndex (only stacked barentry): \(_stackIndex)"
|
||||
}
|
||||
|
||||
public override func isEqual(object: AnyObject?) -> Bool
|
||||
{
|
||||
if (object === nil)
|
||||
{
|
||||
return false
|
||||
}
|
||||
|
||||
if (!object!.isKindOfClass(self.dynamicType))
|
||||
{
|
||||
return false
|
||||
}
|
||||
|
||||
if (object!.xIndex != _xIndex)
|
||||
{
|
||||
return false
|
||||
}
|
||||
|
||||
if (object!.dataSetIndex != _dataSetIndex)
|
||||
{
|
||||
return false
|
||||
}
|
||||
|
||||
if (object!.stackIndex != _stackIndex)
|
||||
{
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
func ==(lhs: ChartHighlight, rhs: ChartHighlight) -> Bool
|
||||
{
|
||||
if (lhs === rhs)
|
||||
{
|
||||
return true
|
||||
}
|
||||
|
||||
if (!lhs.isKindOfClass(rhs.dynamicType))
|
||||
{
|
||||
return false
|
||||
}
|
||||
|
||||
if (lhs._xIndex != rhs._xIndex)
|
||||
{
|
||||
return false
|
||||
}
|
||||
|
||||
if (lhs._dataSetIndex != rhs._dataSetIndex)
|
||||
{
|
||||
return false
|
||||
}
|
||||
|
||||
if (lhs._stackIndex != rhs._stackIndex)
|
||||
{
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
119
Carthage/Checkouts/Charts/Charts/Classes/Highlight/ChartHighlighter.swift
vendored
Normal file
119
Carthage/Checkouts/Charts/Charts/Classes/Highlight/ChartHighlighter.swift
vendored
Normal file
@@ -0,0 +1,119 @@
|
||||
//
|
||||
// ChartHighlighter.swift
|
||||
// Charts
|
||||
//
|
||||
// Created by Daniel Cohen Gindi on 26/7/15.
|
||||
|
||||
//
|
||||
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
|
||||
// A port of MPAndroidChart for iOS
|
||||
// Licensed under Apache License 2.0
|
||||
//
|
||||
// https://github.com/danielgindi/ios-charts
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import CoreGraphics
|
||||
|
||||
internal class ChartHighlighter
|
||||
{
|
||||
/// instance of the data-provider
|
||||
internal weak var _chart: BarLineChartViewBase?;
|
||||
|
||||
internal init(chart: BarLineChartViewBase)
|
||||
{
|
||||
_chart = chart;
|
||||
}
|
||||
|
||||
/// Returns a Highlight object corresponding to the given x- and y- touch positions in pixels.
|
||||
/// - parameter x:
|
||||
/// - parameter y:
|
||||
/// - returns:
|
||||
internal func getHighlight(x x: Double, y: Double) -> ChartHighlight?
|
||||
{
|
||||
let xIndex = getXIndex(x)
|
||||
if (xIndex == -Int.max)
|
||||
{
|
||||
return nil
|
||||
}
|
||||
|
||||
let dataSetIndex = getDataSetIndex(xIndex: xIndex, x: x, y: y)
|
||||
if (dataSetIndex == -Int.max)
|
||||
{
|
||||
return nil
|
||||
}
|
||||
|
||||
return ChartHighlight(xIndex: xIndex, dataSetIndex: dataSetIndex)
|
||||
}
|
||||
|
||||
/// Returns the corresponding x-index for a given touch-position in pixels.
|
||||
/// - parameter x:
|
||||
/// - returns:
|
||||
internal func getXIndex(x: Double) -> Int
|
||||
{
|
||||
// create an array of the touch-point
|
||||
var pt = CGPoint(x: x, y: 0.0)
|
||||
|
||||
// take any transformer to determine the x-axis value
|
||||
_chart?.getTransformer(ChartYAxis.AxisDependency.Left).pixelToValue(&pt)
|
||||
|
||||
return Int(round(pt.x))
|
||||
}
|
||||
|
||||
/// Returns the corresponding dataset-index for a given xIndex and xy-touch position in pixels.
|
||||
/// - parameter xIndex:
|
||||
/// - parameter x:
|
||||
/// - parameter y:
|
||||
/// - returns:
|
||||
internal func getDataSetIndex(xIndex xIndex: Int, x: Double, y: Double) -> Int
|
||||
{
|
||||
let valsAtIndex = getSelectionDetailsAtIndex(xIndex)
|
||||
|
||||
let leftdist = ChartUtils.getMinimumDistance(valsAtIndex, val: y, axis: ChartYAxis.AxisDependency.Left)
|
||||
let rightdist = ChartUtils.getMinimumDistance(valsAtIndex, val: y, axis: ChartYAxis.AxisDependency.Right)
|
||||
|
||||
let axis = leftdist < rightdist ? ChartYAxis.AxisDependency.Left : ChartYAxis.AxisDependency.Right
|
||||
|
||||
let dataSetIndex = ChartUtils.closestDataSetIndex(valsAtIndex, value: y, axis: axis)
|
||||
|
||||
return dataSetIndex
|
||||
}
|
||||
|
||||
/// Returns a list of SelectionDetail object corresponding to the given xIndex.
|
||||
/// - parameter xIndex:
|
||||
/// - returns:
|
||||
internal func getSelectionDetailsAtIndex(xIndex: Int) -> [ChartSelectionDetail]
|
||||
{
|
||||
var vals = [ChartSelectionDetail]()
|
||||
var pt = CGPoint()
|
||||
|
||||
for (var i = 0, dataSetCount = _chart?.data?.dataSetCount; i < dataSetCount; i++)
|
||||
{
|
||||
let dataSet = _chart!.data!.getDataSetByIndex(i)
|
||||
|
||||
// dont include datasets that cannot be highlighted
|
||||
if !dataSet.isHighlightEnabled
|
||||
{
|
||||
continue
|
||||
}
|
||||
|
||||
// extract all y-values from all DataSets at the given x-index
|
||||
let yVal: Double = dataSet.yValForXIndex(xIndex)
|
||||
if yVal.isNaN
|
||||
{
|
||||
continue
|
||||
}
|
||||
|
||||
pt.y = CGFloat(yVal)
|
||||
|
||||
_chart!.getTransformer(dataSet.axisDependency).pointValueToPixel(&pt)
|
||||
|
||||
if !pt.y.isNaN
|
||||
{
|
||||
vals.append(ChartSelectionDetail(value: Double(pt.y), dataSetIndex: i, dataSet: dataSet))
|
||||
}
|
||||
}
|
||||
|
||||
return vals
|
||||
}
|
||||
}
|
||||
53
Carthage/Checkouts/Charts/Charts/Classes/Highlight/ChartRange.swift
vendored
Normal file
53
Carthage/Checkouts/Charts/Charts/Classes/Highlight/ChartRange.swift
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
//
|
||||
// ChartRange.swift
|
||||
// Charts
|
||||
//
|
||||
// Created by Daniel Cohen Gindi on 26/7/15.
|
||||
|
||||
//
|
||||
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
|
||||
// A port of MPAndroidChart for iOS
|
||||
// Licensed under Apache License 2.0
|
||||
//
|
||||
// https://github.com/danielgindi/ios-charts
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
public class ChartRange: NSObject
|
||||
{
|
||||
public var from: Double
|
||||
public var to: Double
|
||||
|
||||
public init(from: Double, to: Double)
|
||||
{
|
||||
self.from = from
|
||||
self.to = to
|
||||
|
||||
super.init()
|
||||
}
|
||||
|
||||
/// Returns true if this range contains (if the value is in between) the given value, false if not.
|
||||
/// - parameter value:
|
||||
public func contains(value: Double) -> Bool
|
||||
{
|
||||
if value > from && value <= to
|
||||
{
|
||||
return true
|
||||
}
|
||||
else
|
||||
{
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
public func isLarger(value: Double) -> Bool
|
||||
{
|
||||
return value > to
|
||||
}
|
||||
|
||||
public func isSmaller(value: Double) -> Bool
|
||||
{
|
||||
return value < from
|
||||
}
|
||||
}
|
||||
72
Carthage/Checkouts/Charts/Charts/Classes/Highlight/CombinedHighlighter.swift
vendored
Normal file
72
Carthage/Checkouts/Charts/Charts/Classes/Highlight/CombinedHighlighter.swift
vendored
Normal file
@@ -0,0 +1,72 @@
|
||||
//
|
||||
// CombinedHighlighter.swift
|
||||
// Charts
|
||||
//
|
||||
// Created by Daniel Cohen Gindi on 26/7/15.
|
||||
|
||||
//
|
||||
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
|
||||
// A port of MPAndroidChart for iOS
|
||||
// Licensed under Apache License 2.0
|
||||
//
|
||||
// https://github.com/danielgindi/ios-charts
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import CoreGraphics
|
||||
|
||||
internal class CombinedHighlighter: ChartHighlighter
|
||||
{
|
||||
internal init(chart: CombinedChartView)
|
||||
{
|
||||
super.init(chart: chart)
|
||||
}
|
||||
|
||||
/// Returns a list of SelectionDetail object corresponding to the given xIndex.
|
||||
/// - parameter xIndex:
|
||||
/// - returns:
|
||||
internal override func getSelectionDetailsAtIndex(xIndex: Int) -> [ChartSelectionDetail]
|
||||
{
|
||||
var vals = [ChartSelectionDetail]()
|
||||
|
||||
if let data = _chart?.data as? CombinedChartData
|
||||
{
|
||||
// get all chartdata objects
|
||||
var dataObjects = data.allData
|
||||
|
||||
var pt = CGPoint()
|
||||
|
||||
for var i = 0; i < dataObjects.count; i++
|
||||
{
|
||||
for var j = 0; j < dataObjects[i].dataSetCount; j++
|
||||
{
|
||||
let dataSet = dataObjects[i].getDataSetByIndex(j)
|
||||
|
||||
// dont include datasets that cannot be highlighted
|
||||
if !dataSet.isHighlightEnabled
|
||||
{
|
||||
continue
|
||||
}
|
||||
|
||||
// extract all y-values from all DataSets at the given x-index
|
||||
let yVal = dataSet.yValForXIndex(xIndex)
|
||||
if yVal.isNaN
|
||||
{
|
||||
continue
|
||||
}
|
||||
|
||||
pt.y = CGFloat(yVal)
|
||||
|
||||
_chart!.getTransformer(dataSet.axisDependency).pointValueToPixel(&pt)
|
||||
|
||||
if !pt.y.isNaN
|
||||
{
|
||||
vals.append(ChartSelectionDetail(value: Double(pt.y), dataSetIndex: j, dataSet: dataSet))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return vals
|
||||
}
|
||||
}
|
||||
121
Carthage/Checkouts/Charts/Charts/Classes/Highlight/HorizontalBarChartHighlighter.swift
vendored
Normal file
121
Carthage/Checkouts/Charts/Charts/Classes/Highlight/HorizontalBarChartHighlighter.swift
vendored
Normal file
@@ -0,0 +1,121 @@
|
||||
//
|
||||
// HorizontalBarChartHighlighter.swift
|
||||
// Charts
|
||||
//
|
||||
// Created by Daniel Cohen Gindi on 26/7/15.
|
||||
|
||||
//
|
||||
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
|
||||
// A port of MPAndroidChart for iOS
|
||||
// Licensed under Apache License 2.0
|
||||
//
|
||||
// https://github.com/danielgindi/ios-charts
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import CoreGraphics
|
||||
|
||||
internal class HorizontalBarChartHighlighter: BarChartHighlighter
|
||||
{
|
||||
internal override func getHighlight(x x: Double, y: Double) -> ChartHighlight?
|
||||
{
|
||||
let h = super.getHighlight(x: x, y: y)
|
||||
|
||||
if h === nil
|
||||
{
|
||||
return h
|
||||
}
|
||||
else
|
||||
{
|
||||
if let set = _chart?.data?.getDataSetByIndex(h!.dataSetIndex) as? BarChartDataSet
|
||||
{
|
||||
if set.isStacked
|
||||
{
|
||||
// create an array of the touch-point
|
||||
var pt = CGPoint()
|
||||
pt.x = CGFloat(y)
|
||||
|
||||
// take any transformer to determine the x-axis value
|
||||
_chart?.getTransformer(set.axisDependency).pixelToValue(&pt)
|
||||
|
||||
return getStackedHighlight(old: h, set: set, xIndex: h!.xIndex, dataSetIndex: h!.dataSetIndex, yValue: Double(pt.x))
|
||||
}
|
||||
}
|
||||
|
||||
return h
|
||||
}
|
||||
}
|
||||
|
||||
internal override func getXIndex(x: Double) -> Int
|
||||
{
|
||||
if let barChartData = _chart?.data as? BarChartData
|
||||
{
|
||||
if !barChartData.isGrouped
|
||||
{
|
||||
// create an array of the touch-point
|
||||
var pt = CGPoint(x: 0.0, y: x)
|
||||
|
||||
// take any transformer to determine the x-axis value
|
||||
_chart?.getTransformer(ChartYAxis.AxisDependency.Left).pixelToValue(&pt)
|
||||
|
||||
return Int(round(pt.y))
|
||||
}
|
||||
else
|
||||
{
|
||||
let baseNoSpace = getBase(x)
|
||||
|
||||
let setCount = barChartData.dataSetCount
|
||||
var xIndex = Int(baseNoSpace) / setCount
|
||||
|
||||
let valCount = barChartData.xValCount
|
||||
|
||||
if xIndex < 0
|
||||
{
|
||||
xIndex = 0
|
||||
}
|
||||
else if xIndex >= valCount
|
||||
{
|
||||
xIndex = valCount - 1
|
||||
}
|
||||
|
||||
return xIndex
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the base y-value to the corresponding x-touch value in pixels.
|
||||
/// - parameter y:
|
||||
/// - returns:
|
||||
internal override func getBase(y: Double) -> Double
|
||||
{
|
||||
if let barChartData = _chart?.data as? BarChartData
|
||||
{
|
||||
// create an array of the touch-point
|
||||
var pt = CGPoint()
|
||||
pt.y = CGFloat(y)
|
||||
|
||||
// take any transformer to determine the x-axis value
|
||||
_chart?.getTransformer(ChartYAxis.AxisDependency.Left).pixelToValue(&pt)
|
||||
let yVal = Double(pt.y)
|
||||
|
||||
let setCount = barChartData.dataSetCount ?? 0
|
||||
|
||||
// calculate how often the group-space appears
|
||||
let steps = Int(yVal / (Double(setCount) + Double(barChartData.groupSpace)))
|
||||
|
||||
let groupSpaceSum = Double(barChartData.groupSpace) * Double(steps)
|
||||
|
||||
let baseNoSpace = yVal - groupSpaceSum
|
||||
|
||||
return baseNoSpace
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0.0
|
||||
}
|
||||
}
|
||||
}
|
||||
589
Carthage/Checkouts/Charts/Charts/Classes/Renderers/BarChartRenderer.swift
vendored
Normal file
589
Carthage/Checkouts/Charts/Charts/Classes/Renderers/BarChartRenderer.swift
vendored
Normal file
@@ -0,0 +1,589 @@
|
||||
//
|
||||
// BarChartRenderer.swift
|
||||
// Charts
|
||||
//
|
||||
// Created by Daniel Cohen Gindi on 4/3/15.
|
||||
//
|
||||
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
|
||||
// A port of MPAndroidChart for iOS
|
||||
// Licensed under Apache License 2.0
|
||||
//
|
||||
// https://github.com/danielgindi/ios-charts
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import CoreGraphics
|
||||
import UIKit
|
||||
|
||||
@objc
|
||||
public protocol BarChartRendererDelegate
|
||||
{
|
||||
func barChartRendererData(renderer: BarChartRenderer) -> BarChartData!
|
||||
func barChartRenderer(renderer: BarChartRenderer, transformerForAxis which: ChartYAxis.AxisDependency) -> ChartTransformer!
|
||||
func barChartRendererMaxVisibleValueCount(renderer: BarChartRenderer) -> Int
|
||||
func barChartDefaultRendererValueFormatter(renderer: BarChartRenderer) -> NSNumberFormatter!
|
||||
func barChartRendererChartYMax(renderer: BarChartRenderer) -> Double
|
||||
func barChartRendererChartYMin(renderer: BarChartRenderer) -> Double
|
||||
func barChartRendererChartXMax(renderer: BarChartRenderer) -> Double
|
||||
func barChartRendererChartXMin(renderer: BarChartRenderer) -> Double
|
||||
func barChartIsDrawHighlightArrowEnabled(renderer: BarChartRenderer) -> Bool
|
||||
func barChartIsDrawValueAboveBarEnabled(renderer: BarChartRenderer) -> Bool
|
||||
func barChartIsDrawBarShadowEnabled(renderer: BarChartRenderer) -> Bool
|
||||
func barChartIsInverted(renderer: BarChartRenderer, axis: ChartYAxis.AxisDependency) -> Bool
|
||||
}
|
||||
|
||||
public class BarChartRenderer: ChartDataRendererBase
|
||||
{
|
||||
public weak var delegate: BarChartRendererDelegate?
|
||||
|
||||
public init(delegate: BarChartRendererDelegate?, animator: ChartAnimator?, viewPortHandler: ChartViewPortHandler)
|
||||
{
|
||||
super.init(animator: animator, viewPortHandler: viewPortHandler)
|
||||
|
||||
self.delegate = delegate
|
||||
}
|
||||
|
||||
public override func drawData(context context: CGContext?)
|
||||
{
|
||||
let barData = delegate!.barChartRendererData(self)
|
||||
|
||||
if (barData === nil)
|
||||
{
|
||||
return
|
||||
}
|
||||
|
||||
for (var i = 0; i < barData.dataSetCount; i++)
|
||||
{
|
||||
let set = barData.getDataSetByIndex(i)
|
||||
|
||||
if set !== nil && set!.isVisible && set.entryCount > 0
|
||||
{
|
||||
drawDataSet(context: context, dataSet: set as! BarChartDataSet, index: i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal func drawDataSet(context context: CGContext?, dataSet: BarChartDataSet, index: Int)
|
||||
{
|
||||
CGContextSaveGState(context)
|
||||
|
||||
let barData = delegate!.barChartRendererData(self)
|
||||
|
||||
let trans = delegate!.barChartRenderer(self, transformerForAxis: dataSet.axisDependency)
|
||||
|
||||
let drawBarShadowEnabled: Bool = delegate!.barChartIsDrawBarShadowEnabled(self)
|
||||
let dataSetOffset = (barData.dataSetCount - 1)
|
||||
let groupSpace = barData.groupSpace
|
||||
let groupSpaceHalf = groupSpace / 2.0
|
||||
let barSpace = dataSet.barSpace
|
||||
let barSpaceHalf = barSpace / 2.0
|
||||
let containsStacks = dataSet.isStacked
|
||||
let isInverted = delegate!.barChartIsInverted(self, axis: dataSet.axisDependency)
|
||||
var entries = dataSet.yVals as! [BarChartDataEntry]
|
||||
let barWidth: CGFloat = 0.5
|
||||
let phaseY = _animator.phaseY
|
||||
var barRect = CGRect()
|
||||
var barShadow = CGRect()
|
||||
var y: Double
|
||||
|
||||
// do the drawing
|
||||
for (var j = 0, count = Int(ceil(CGFloat(dataSet.entryCount) * _animator.phaseX)); j < count; j++)
|
||||
{
|
||||
let e = entries[j]
|
||||
|
||||
// calculate the x-position, depending on datasetcount
|
||||
let x = CGFloat(e.xIndex + e.xIndex * dataSetOffset) + CGFloat(index)
|
||||
+ groupSpace * CGFloat(e.xIndex) + groupSpaceHalf
|
||||
var vals = e.values
|
||||
|
||||
if (!containsStacks || vals == nil)
|
||||
{
|
||||
y = e.value
|
||||
|
||||
let left = x - barWidth + barSpaceHalf
|
||||
let right = x + barWidth - barSpaceHalf
|
||||
var top = isInverted ? (y <= 0.0 ? CGFloat(y) : 0) : (y >= 0.0 ? CGFloat(y) : 0)
|
||||
var bottom = isInverted ? (y >= 0.0 ? CGFloat(y) : 0) : (y <= 0.0 ? CGFloat(y) : 0)
|
||||
|
||||
// multiply the height of the rect with the phase
|
||||
if (top > 0)
|
||||
{
|
||||
top *= phaseY
|
||||
}
|
||||
else
|
||||
{
|
||||
bottom *= phaseY
|
||||
}
|
||||
|
||||
barRect.origin.x = left
|
||||
barRect.size.width = right - left
|
||||
barRect.origin.y = top
|
||||
barRect.size.height = bottom - top
|
||||
|
||||
trans.rectValueToPixel(&barRect)
|
||||
|
||||
if (!viewPortHandler.isInBoundsLeft(barRect.origin.x + barRect.size.width))
|
||||
{
|
||||
continue
|
||||
}
|
||||
|
||||
if (!viewPortHandler.isInBoundsRight(barRect.origin.x))
|
||||
{
|
||||
break
|
||||
}
|
||||
|
||||
// if drawing the bar shadow is enabled
|
||||
if (drawBarShadowEnabled)
|
||||
{
|
||||
barShadow.origin.x = barRect.origin.x
|
||||
barShadow.origin.y = viewPortHandler.contentTop
|
||||
barShadow.size.width = barRect.size.width
|
||||
barShadow.size.height = viewPortHandler.contentHeight
|
||||
|
||||
CGContextSetFillColorWithColor(context, dataSet.barShadowColor.CGColor)
|
||||
CGContextFillRect(context, barShadow)
|
||||
}
|
||||
|
||||
// Set the color for the currently drawn value. If the index is out of bounds, reuse colors.
|
||||
CGContextSetFillColorWithColor(context, dataSet.colorAt(j).CGColor)
|
||||
CGContextFillRect(context, barRect)
|
||||
}
|
||||
else
|
||||
{
|
||||
var posY = 0.0
|
||||
var negY = -e.negativeSum
|
||||
var yStart = 0.0
|
||||
|
||||
// if drawing the bar shadow is enabled
|
||||
if (drawBarShadowEnabled)
|
||||
{
|
||||
y = e.value
|
||||
|
||||
let left = x - barWidth + barSpaceHalf
|
||||
let right = x + barWidth - barSpaceHalf
|
||||
var top = isInverted ? (y <= 0.0 ? CGFloat(y) : 0) : (y >= 0.0 ? CGFloat(y) : 0)
|
||||
var bottom = isInverted ? (y >= 0.0 ? CGFloat(y) : 0) : (y <= 0.0 ? CGFloat(y) : 0)
|
||||
|
||||
// multiply the height of the rect with the phase
|
||||
if (top > 0)
|
||||
{
|
||||
top *= phaseY
|
||||
}
|
||||
else
|
||||
{
|
||||
bottom *= phaseY
|
||||
}
|
||||
|
||||
barRect.origin.x = left
|
||||
barRect.size.width = right - left
|
||||
barRect.origin.y = top
|
||||
barRect.size.height = bottom - top
|
||||
|
||||
trans.rectValueToPixel(&barRect)
|
||||
|
||||
barShadow.origin.x = barRect.origin.x
|
||||
barShadow.origin.y = viewPortHandler.contentTop
|
||||
barShadow.size.width = barRect.size.width
|
||||
barShadow.size.height = viewPortHandler.contentHeight
|
||||
|
||||
CGContextSetFillColorWithColor(context, dataSet.barShadowColor.CGColor)
|
||||
CGContextFillRect(context, barShadow)
|
||||
}
|
||||
|
||||
// fill the stack
|
||||
for (var k = 0; k < vals!.count; k++)
|
||||
{
|
||||
let value = vals![k]
|
||||
|
||||
if value >= 0.0
|
||||
{
|
||||
y = posY
|
||||
yStart = posY + value
|
||||
posY = yStart
|
||||
}
|
||||
else
|
||||
{
|
||||
y = negY
|
||||
yStart = negY + abs(value)
|
||||
negY += abs(value)
|
||||
}
|
||||
|
||||
let left = x - barWidth + barSpaceHalf
|
||||
let right = x + barWidth - barSpaceHalf
|
||||
var top: CGFloat, bottom: CGFloat
|
||||
if isInverted
|
||||
{
|
||||
bottom = y >= yStart ? CGFloat(y) : CGFloat(yStart)
|
||||
top = y <= yStart ? CGFloat(y) : CGFloat(yStart)
|
||||
}
|
||||
else
|
||||
{
|
||||
top = y >= yStart ? CGFloat(y) : CGFloat(yStart)
|
||||
bottom = y <= yStart ? CGFloat(y) : CGFloat(yStart)
|
||||
}
|
||||
|
||||
// multiply the height of the rect with the phase
|
||||
top *= phaseY
|
||||
bottom *= phaseY
|
||||
|
||||
barRect.origin.x = left
|
||||
barRect.size.width = right - left
|
||||
barRect.origin.y = top
|
||||
barRect.size.height = bottom - top
|
||||
|
||||
trans.rectValueToPixel(&barRect)
|
||||
|
||||
if (k == 0 && !viewPortHandler.isInBoundsLeft(barRect.origin.x + barRect.size.width))
|
||||
{
|
||||
// Skip to next bar
|
||||
break
|
||||
}
|
||||
|
||||
// avoid drawing outofbounds values
|
||||
if (!viewPortHandler.isInBoundsRight(barRect.origin.x))
|
||||
{
|
||||
break
|
||||
}
|
||||
|
||||
// Set the color for the currently drawn value. If the index is out of bounds, reuse colors.
|
||||
CGContextSetFillColorWithColor(context, dataSet.colorAt(k).CGColor)
|
||||
CGContextFillRect(context, barRect)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CGContextRestoreGState(context)
|
||||
}
|
||||
|
||||
/// Prepares a bar for being highlighted.
|
||||
internal func prepareBarHighlight(x x: CGFloat, y1: Double, y2: Double, barspacehalf: CGFloat, trans: ChartTransformer, inout rect: CGRect)
|
||||
{
|
||||
let barWidth: CGFloat = 0.5
|
||||
|
||||
let left = x - barWidth + barspacehalf
|
||||
let right = x + barWidth - barspacehalf
|
||||
let top = CGFloat(y1)
|
||||
let bottom = CGFloat(y2)
|
||||
|
||||
rect.origin.x = left
|
||||
rect.origin.y = top
|
||||
rect.size.width = right - left
|
||||
rect.size.height = bottom - top
|
||||
|
||||
trans.rectValueToPixel(&rect, phaseY: _animator.phaseY)
|
||||
}
|
||||
|
||||
public override func drawValues(context context: CGContext?)
|
||||
{
|
||||
// if values are drawn
|
||||
if (passesCheck())
|
||||
{
|
||||
let barData = delegate!.barChartRendererData(self)
|
||||
|
||||
let defaultValueFormatter = delegate!.barChartDefaultRendererValueFormatter(self)
|
||||
|
||||
var dataSets = barData.dataSets
|
||||
|
||||
let drawValueAboveBar = delegate!.barChartIsDrawValueAboveBarEnabled(self)
|
||||
|
||||
var posOffset: CGFloat
|
||||
var negOffset: CGFloat
|
||||
|
||||
for (var i = 0, count = barData.dataSetCount; i < count; i++)
|
||||
{
|
||||
let dataSet = dataSets[i] as! BarChartDataSet
|
||||
|
||||
if !dataSet.isDrawValuesEnabled || dataSet.entryCount == 0
|
||||
{
|
||||
continue
|
||||
}
|
||||
|
||||
let isInverted = delegate!.barChartIsInverted(self, axis: dataSet.axisDependency)
|
||||
|
||||
// calculate the correct offset depending on the draw position of the value
|
||||
let valueOffsetPlus: CGFloat = 4.5
|
||||
let valueFont = dataSet.valueFont
|
||||
let valueTextHeight = valueFont.lineHeight
|
||||
posOffset = (drawValueAboveBar ? -(valueTextHeight + valueOffsetPlus) : valueOffsetPlus)
|
||||
negOffset = (drawValueAboveBar ? valueOffsetPlus : -(valueTextHeight + valueOffsetPlus))
|
||||
|
||||
if (isInverted)
|
||||
{
|
||||
posOffset = -posOffset - valueTextHeight
|
||||
negOffset = -negOffset - valueTextHeight
|
||||
}
|
||||
|
||||
let valueTextColor = dataSet.valueTextColor
|
||||
|
||||
var formatter = dataSet.valueFormatter
|
||||
if (formatter === nil)
|
||||
{
|
||||
formatter = defaultValueFormatter
|
||||
}
|
||||
|
||||
let trans = delegate!.barChartRenderer(self, transformerForAxis: dataSet.axisDependency)
|
||||
|
||||
var entries = dataSet.yVals as! [BarChartDataEntry]
|
||||
|
||||
var valuePoints = getTransformedValues(trans: trans, entries: entries, dataSetIndex: i)
|
||||
|
||||
// if only single values are drawn (sum)
|
||||
if (!dataSet.isStacked)
|
||||
{
|
||||
for (var j = 0, count = Int(ceil(CGFloat(valuePoints.count) * _animator.phaseX)); j < count; j++)
|
||||
{
|
||||
if (!viewPortHandler.isInBoundsRight(valuePoints[j].x))
|
||||
{
|
||||
break
|
||||
}
|
||||
|
||||
if (!viewPortHandler.isInBoundsY(valuePoints[j].y)
|
||||
|| !viewPortHandler.isInBoundsLeft(valuePoints[j].x))
|
||||
{
|
||||
continue
|
||||
}
|
||||
|
||||
let val = entries[j].value
|
||||
|
||||
drawValue(context: context,
|
||||
value: formatter!.stringFromNumber(val)!,
|
||||
xPos: valuePoints[j].x,
|
||||
yPos: valuePoints[j].y + (val >= 0.0 ? posOffset : negOffset),
|
||||
font: valueFont,
|
||||
align: .Center,
|
||||
color: valueTextColor)
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// if we have stacks
|
||||
|
||||
for (var j = 0, count = Int(ceil(CGFloat(valuePoints.count) * _animator.phaseX)); j < count; j++)
|
||||
{
|
||||
let e = entries[j]
|
||||
|
||||
let values = e.values
|
||||
|
||||
// we still draw stacked bars, but there is one non-stacked in between
|
||||
if (values == nil)
|
||||
{
|
||||
if (!viewPortHandler.isInBoundsRight(valuePoints[j].x))
|
||||
{
|
||||
break
|
||||
}
|
||||
|
||||
if (!viewPortHandler.isInBoundsY(valuePoints[j].y)
|
||||
|| !viewPortHandler.isInBoundsLeft(valuePoints[j].x))
|
||||
{
|
||||
continue
|
||||
}
|
||||
|
||||
drawValue(context: context,
|
||||
value: formatter!.stringFromNumber(e.value)!,
|
||||
xPos: valuePoints[j].x,
|
||||
yPos: valuePoints[j].y + (e.value >= 0.0 ? posOffset : negOffset),
|
||||
font: valueFont,
|
||||
align: .Center,
|
||||
color: valueTextColor)
|
||||
}
|
||||
else
|
||||
{
|
||||
// draw stack values
|
||||
|
||||
let vals = values!
|
||||
var transformed = [CGPoint]()
|
||||
|
||||
var posY = 0.0
|
||||
var negY = -e.negativeSum
|
||||
|
||||
for (var k = 0; k < vals.count; k++)
|
||||
{
|
||||
let value = vals[k]
|
||||
var y: Double
|
||||
|
||||
if value >= 0.0
|
||||
{
|
||||
posY += value
|
||||
y = posY
|
||||
}
|
||||
else
|
||||
{
|
||||
y = negY
|
||||
negY -= value
|
||||
}
|
||||
|
||||
transformed.append(CGPoint(x: 0.0, y: CGFloat(y) * _animator.phaseY))
|
||||
}
|
||||
|
||||
trans.pointValuesToPixel(&transformed)
|
||||
|
||||
for (var k = 0; k < transformed.count; k++)
|
||||
{
|
||||
let x = valuePoints[j].x
|
||||
let y = transformed[k].y + (vals[k] >= 0 ? posOffset : negOffset)
|
||||
|
||||
if (!viewPortHandler.isInBoundsRight(x))
|
||||
{
|
||||
break
|
||||
}
|
||||
|
||||
if (!viewPortHandler.isInBoundsY(y) || !viewPortHandler.isInBoundsLeft(x))
|
||||
{
|
||||
continue
|
||||
}
|
||||
|
||||
drawValue(context: context,
|
||||
value: formatter!.stringFromNumber(vals[k])!,
|
||||
xPos: x,
|
||||
yPos: y,
|
||||
font: valueFont,
|
||||
align: .Center,
|
||||
color: valueTextColor)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Draws a value at the specified x and y position.
|
||||
internal func drawValue(context context: CGContext?, value: String, xPos: CGFloat, yPos: CGFloat, font: UIFont, align: NSTextAlignment, color: UIColor)
|
||||
{
|
||||
ChartUtils.drawText(context: context, text: value, point: CGPoint(x: xPos, y: yPos), align: align, attributes: [NSFontAttributeName: font, NSForegroundColorAttributeName: color])
|
||||
}
|
||||
|
||||
public override func drawExtras(context context: CGContext?)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private var _highlightArrowPtsBuffer = [CGPoint](count: 3, repeatedValue: CGPoint())
|
||||
|
||||
public override func drawHighlighted(context context: CGContext?, indices: [ChartHighlight])
|
||||
{
|
||||
let barData = delegate!.barChartRendererData(self)
|
||||
if (barData === nil)
|
||||
{
|
||||
return
|
||||
}
|
||||
|
||||
CGContextSaveGState(context)
|
||||
|
||||
let setCount = barData.dataSetCount
|
||||
let drawHighlightArrowEnabled = delegate!.barChartIsDrawHighlightArrowEnabled(self)
|
||||
var barRect = CGRect()
|
||||
|
||||
for (var i = 0; i < indices.count; i++)
|
||||
{
|
||||
let h = indices[i]
|
||||
let index = h.xIndex
|
||||
|
||||
let dataSetIndex = h.dataSetIndex
|
||||
let set = barData.getDataSetByIndex(dataSetIndex) as! BarChartDataSet!
|
||||
|
||||
if (set === nil || !set.isHighlightEnabled)
|
||||
{
|
||||
continue
|
||||
}
|
||||
|
||||
let barspaceHalf = set.barSpace / 2.0
|
||||
|
||||
let trans = delegate!.barChartRenderer(self, transformerForAxis: set.axisDependency)
|
||||
|
||||
CGContextSetFillColorWithColor(context, set.highlightColor.CGColor)
|
||||
CGContextSetAlpha(context, set.highLightAlpha)
|
||||
|
||||
// check outofbounds
|
||||
if (CGFloat(index) < (CGFloat(delegate!.barChartRendererChartXMax(self)) * _animator.phaseX) / CGFloat(setCount))
|
||||
{
|
||||
let e = set.entryForXIndex(index) as! BarChartDataEntry!
|
||||
|
||||
if (e === nil || e.xIndex != index)
|
||||
{
|
||||
continue
|
||||
}
|
||||
|
||||
let groupspace = barData.groupSpace
|
||||
let isStack = h.stackIndex < 0 ? false : true
|
||||
|
||||
// calculate the correct x-position
|
||||
let x = CGFloat(index * setCount + dataSetIndex) + groupspace / 2.0 + groupspace * CGFloat(index)
|
||||
|
||||
let y1: Double
|
||||
let y2: Double
|
||||
|
||||
if (isStack)
|
||||
{
|
||||
y1 = h.range?.from ?? 0.0
|
||||
y2 = h.range?.to ?? 0.0
|
||||
}
|
||||
else
|
||||
{
|
||||
y1 = e.value
|
||||
y2 = 0.0
|
||||
}
|
||||
|
||||
prepareBarHighlight(x: x, y1: y1, y2: y2, barspacehalf: barspaceHalf, trans: trans, rect: &barRect)
|
||||
|
||||
CGContextFillRect(context, barRect)
|
||||
|
||||
if (drawHighlightArrowEnabled)
|
||||
{
|
||||
CGContextSetAlpha(context, 1.0)
|
||||
|
||||
// distance between highlight arrow and bar
|
||||
let offsetY = _animator.phaseY * 0.07
|
||||
|
||||
CGContextSaveGState(context)
|
||||
|
||||
let pixelToValueMatrix = trans.pixelToValueMatrix
|
||||
let xToYRel = abs(sqrt(pixelToValueMatrix.b * pixelToValueMatrix.b + pixelToValueMatrix.d * pixelToValueMatrix.d) / sqrt(pixelToValueMatrix.a * pixelToValueMatrix.a + pixelToValueMatrix.c * pixelToValueMatrix.c))
|
||||
|
||||
let arrowWidth = set.barSpace / 2.0
|
||||
let arrowHeight = arrowWidth * xToYRel
|
||||
|
||||
let yArrow = (y1 > -y2 ? y1 : y1) * Double(_animator.phaseY)
|
||||
|
||||
_highlightArrowPtsBuffer[0].x = CGFloat(x) + 0.4
|
||||
_highlightArrowPtsBuffer[0].y = CGFloat(yArrow) + offsetY
|
||||
_highlightArrowPtsBuffer[1].x = CGFloat(x) + 0.4 + arrowWidth
|
||||
_highlightArrowPtsBuffer[1].y = CGFloat(yArrow) + offsetY - arrowHeight
|
||||
_highlightArrowPtsBuffer[2].x = CGFloat(x) + 0.4 + arrowWidth
|
||||
_highlightArrowPtsBuffer[2].y = CGFloat(yArrow) + offsetY + arrowHeight
|
||||
|
||||
trans.pointValuesToPixel(&_highlightArrowPtsBuffer)
|
||||
|
||||
CGContextBeginPath(context)
|
||||
CGContextMoveToPoint(context, _highlightArrowPtsBuffer[0].x, _highlightArrowPtsBuffer[0].y)
|
||||
CGContextAddLineToPoint(context, _highlightArrowPtsBuffer[1].x, _highlightArrowPtsBuffer[1].y)
|
||||
CGContextAddLineToPoint(context, _highlightArrowPtsBuffer[2].x, _highlightArrowPtsBuffer[2].y)
|
||||
CGContextClosePath(context)
|
||||
|
||||
CGContextFillPath(context)
|
||||
|
||||
CGContextRestoreGState(context)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CGContextRestoreGState(context)
|
||||
}
|
||||
|
||||
public func getTransformedValues(trans trans: ChartTransformer, entries: [BarChartDataEntry], dataSetIndex: Int) -> [CGPoint]
|
||||
{
|
||||
return trans.generateTransformedValuesBarChart(entries, dataSet: dataSetIndex, barData: delegate!.barChartRendererData(self)!, phaseY: _animator.phaseY)
|
||||
}
|
||||
|
||||
internal func passesCheck() -> Bool
|
||||
{
|
||||
let barData = delegate!.barChartRendererData(self)
|
||||
|
||||
if (barData === nil)
|
||||
{
|
||||
return false
|
||||
}
|
||||
|
||||
return CGFloat(barData.yValCount) < CGFloat(delegate!.barChartRendererMaxVisibleValueCount(self)) * viewPortHandler.scaleX
|
||||
}
|
||||
}
|
||||
306
Carthage/Checkouts/Charts/Charts/Classes/Renderers/BubbleChartRenderer.swift
vendored
Normal file
306
Carthage/Checkouts/Charts/Charts/Classes/Renderers/BubbleChartRenderer.swift
vendored
Normal file
@@ -0,0 +1,306 @@
|
||||
//
|
||||
// BubbleChartRenderer.swift
|
||||
// Charts
|
||||
//
|
||||
// Bubble chart implementation:
|
||||
// Copyright 2015 Pierre-Marc Airoldi
|
||||
// Licensed under Apache License 2.0
|
||||
//
|
||||
// https://github.com/danielgindi/ios-charts
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import CoreGraphics
|
||||
import UIKit
|
||||
|
||||
@objc
|
||||
public protocol BubbleChartRendererDelegate
|
||||
{
|
||||
func bubbleChartRendererData(renderer: BubbleChartRenderer) -> BubbleChartData!
|
||||
func bubbleChartRenderer(renderer: BubbleChartRenderer, transformerForAxis which: ChartYAxis.AxisDependency) -> ChartTransformer!
|
||||
func bubbleChartDefaultRendererValueFormatter(renderer: BubbleChartRenderer) -> NSNumberFormatter!
|
||||
func bubbleChartRendererChartYMax(renderer: BubbleChartRenderer) -> Double
|
||||
func bubbleChartRendererChartYMin(renderer: BubbleChartRenderer) -> Double
|
||||
func bubbleChartRendererChartXMax(renderer: BubbleChartRenderer) -> Double
|
||||
func bubbleChartRendererChartXMin(renderer: BubbleChartRenderer) -> Double
|
||||
func bubbleChartRendererMaxVisibleValueCount(renderer: BubbleChartRenderer) -> Int
|
||||
func bubbleChartRendererXValCount(renderer: BubbleChartRenderer) -> Int
|
||||
}
|
||||
|
||||
public class BubbleChartRenderer: ChartDataRendererBase
|
||||
{
|
||||
public weak var delegate: BubbleChartRendererDelegate?
|
||||
|
||||
public init(delegate: BubbleChartRendererDelegate?, animator: ChartAnimator?, viewPortHandler: ChartViewPortHandler)
|
||||
{
|
||||
super.init(animator: animator, viewPortHandler: viewPortHandler)
|
||||
|
||||
self.delegate = delegate
|
||||
}
|
||||
|
||||
public override func drawData(context context: CGContext?)
|
||||
{
|
||||
let bubbleData = delegate!.bubbleChartRendererData(self)
|
||||
|
||||
for set in bubbleData.dataSets as! [BubbleChartDataSet]
|
||||
{
|
||||
if set.isVisible && set.entryCount > 0
|
||||
{
|
||||
drawDataSet(context: context, dataSet: set)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func getShapeSize(entrySize entrySize: CGFloat, maxSize: CGFloat, reference: CGFloat) -> CGFloat
|
||||
{
|
||||
let factor: CGFloat = (maxSize == 0.0) ? 1.0 : sqrt(entrySize / maxSize)
|
||||
let shapeSize: CGFloat = reference * factor
|
||||
return shapeSize
|
||||
}
|
||||
|
||||
private var _pointBuffer = CGPoint()
|
||||
private var _sizeBuffer = [CGPoint](count: 2, repeatedValue: CGPoint())
|
||||
|
||||
internal func drawDataSet(context context: CGContext?, dataSet: BubbleChartDataSet)
|
||||
{
|
||||
let trans = delegate!.bubbleChartRenderer(self, transformerForAxis: dataSet.axisDependency)
|
||||
|
||||
let phaseX = _animator.phaseX
|
||||
let phaseY = _animator.phaseY
|
||||
|
||||
let entries = dataSet.yVals as! [BubbleChartDataEntry]
|
||||
|
||||
let valueToPixelMatrix = trans.valueToPixelMatrix
|
||||
|
||||
CGContextSaveGState(context)
|
||||
|
||||
let entryFrom = dataSet.entryForXIndex(_minX)
|
||||
let entryTo = dataSet.entryForXIndex(_maxX)
|
||||
|
||||
let minx = max(dataSet.entryIndex(entry: entryFrom!, isEqual: true), 0)
|
||||
let maxx = min(dataSet.entryIndex(entry: entryTo!, isEqual: true) + 1, entries.count)
|
||||
|
||||
_sizeBuffer[0].x = 0.0
|
||||
_sizeBuffer[0].y = 0.0
|
||||
_sizeBuffer[1].x = 1.0
|
||||
_sizeBuffer[1].y = 0.0
|
||||
|
||||
trans.pointValuesToPixel(&_sizeBuffer)
|
||||
|
||||
// calcualte the full width of 1 step on the x-axis
|
||||
let maxBubbleWidth: CGFloat = abs(_sizeBuffer[1].x - _sizeBuffer[0].x)
|
||||
let maxBubbleHeight: CGFloat = abs(viewPortHandler.contentBottom - viewPortHandler.contentTop)
|
||||
let referenceSize: CGFloat = min(maxBubbleHeight, maxBubbleWidth)
|
||||
|
||||
for (var j = minx; j < maxx; j++)
|
||||
{
|
||||
let entry = entries[j]
|
||||
|
||||
_pointBuffer.x = CGFloat(entry.xIndex - minx) * phaseX + CGFloat(minx)
|
||||
_pointBuffer.y = CGFloat(entry.value) * phaseY
|
||||
_pointBuffer = CGPointApplyAffineTransform(_pointBuffer, valueToPixelMatrix)
|
||||
|
||||
let shapeSize = getShapeSize(entrySize: entry.size, maxSize: dataSet.maxSize, reference: referenceSize)
|
||||
let shapeHalf = shapeSize / 2.0
|
||||
|
||||
if (!viewPortHandler.isInBoundsTop(_pointBuffer.y + shapeHalf)
|
||||
|| !viewPortHandler.isInBoundsBottom(_pointBuffer.y - shapeHalf))
|
||||
{
|
||||
continue
|
||||
}
|
||||
|
||||
if (!viewPortHandler.isInBoundsLeft(_pointBuffer.x + shapeHalf))
|
||||
{
|
||||
continue
|
||||
}
|
||||
|
||||
if (!viewPortHandler.isInBoundsRight(_pointBuffer.x - shapeHalf))
|
||||
{
|
||||
break
|
||||
}
|
||||
|
||||
let color = dataSet.colorAt(entry.xIndex)
|
||||
|
||||
let rect = CGRect(
|
||||
x: _pointBuffer.x - shapeHalf,
|
||||
y: _pointBuffer.y - shapeHalf,
|
||||
width: shapeSize,
|
||||
height: shapeSize
|
||||
)
|
||||
|
||||
CGContextSetFillColorWithColor(context, color.CGColor)
|
||||
CGContextFillEllipseInRect(context, rect)
|
||||
}
|
||||
|
||||
CGContextRestoreGState(context)
|
||||
}
|
||||
|
||||
public override func drawValues(context context: CGContext?)
|
||||
{
|
||||
let bubbleData = delegate!.bubbleChartRendererData(self)
|
||||
if (bubbleData === nil)
|
||||
{
|
||||
return
|
||||
}
|
||||
|
||||
let defaultValueFormatter = delegate!.bubbleChartDefaultRendererValueFormatter(self)
|
||||
|
||||
// if values are drawn
|
||||
if (bubbleData.yValCount < Int(ceil(CGFloat(delegate!.bubbleChartRendererMaxVisibleValueCount(self)) * viewPortHandler.scaleX)))
|
||||
{
|
||||
let dataSets = bubbleData.dataSets as! [BubbleChartDataSet]
|
||||
|
||||
for dataSet in dataSets
|
||||
{
|
||||
if !dataSet.isDrawValuesEnabled || dataSet.entryCount == 0
|
||||
{
|
||||
continue
|
||||
}
|
||||
|
||||
let phaseX = _animator.phaseX
|
||||
let phaseY = _animator.phaseY
|
||||
|
||||
let alpha = phaseX == 1 ? phaseY : phaseX
|
||||
let valueTextColor = dataSet.valueTextColor.colorWithAlphaComponent(alpha)
|
||||
|
||||
let formatter = dataSet.valueFormatter === nil ? defaultValueFormatter : dataSet.valueFormatter
|
||||
|
||||
let entries = dataSet.yVals
|
||||
|
||||
let entryFrom = dataSet.entryForXIndex(_minX)
|
||||
let entryTo = dataSet.entryForXIndex(_maxX)
|
||||
|
||||
let minx = max(dataSet.entryIndex(entry: entryFrom!, isEqual: true), 0)
|
||||
let maxx = min(dataSet.entryIndex(entry: entryTo!, isEqual: true) + 1, entries.count)
|
||||
|
||||
let positions = delegate!.bubbleChartRenderer(self, transformerForAxis: dataSet.axisDependency).generateTransformedValuesBubble(entries, phaseX: phaseX, phaseY: phaseY, from: minx, to: maxx)
|
||||
|
||||
for (var j = 0, count = positions.count; j < count; j++)
|
||||
{
|
||||
if (!viewPortHandler.isInBoundsRight(positions[j].x))
|
||||
{
|
||||
break
|
||||
}
|
||||
|
||||
if ((!viewPortHandler.isInBoundsLeft(positions[j].x) || !viewPortHandler.isInBoundsY(positions[j].y)))
|
||||
{
|
||||
continue
|
||||
}
|
||||
|
||||
let entry = entries[j + minx] as! BubbleChartDataEntry
|
||||
|
||||
let val = entry.size
|
||||
|
||||
let text = formatter!.stringFromNumber(val)
|
||||
|
||||
// Larger font for larger bubbles?
|
||||
let valueFont = dataSet.valueFont
|
||||
let lineHeight = valueFont.lineHeight
|
||||
|
||||
ChartUtils.drawText(context: context, text: text!, point: CGPoint(x: positions[j].x, y: positions[j].y - ( 0.5 * lineHeight)), align: .Center, attributes: [NSFontAttributeName: valueFont, NSForegroundColorAttributeName: valueTextColor])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override func drawExtras(context context: CGContext?)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override func drawHighlighted(context context: CGContext?, indices: [ChartHighlight])
|
||||
{
|
||||
let bubbleData = delegate!.bubbleChartRendererData(self)
|
||||
|
||||
CGContextSaveGState(context)
|
||||
|
||||
let phaseX = _animator.phaseX
|
||||
let phaseY = _animator.phaseY
|
||||
|
||||
for indice in indices
|
||||
{
|
||||
let dataSet = bubbleData.getDataSetByIndex(indice.dataSetIndex) as! BubbleChartDataSet!
|
||||
|
||||
if (dataSet === nil || !dataSet.isHighlightEnabled)
|
||||
{
|
||||
continue
|
||||
}
|
||||
|
||||
let entryFrom = dataSet.entryForXIndex(_minX)
|
||||
let entryTo = dataSet.entryForXIndex(_maxX)
|
||||
|
||||
let minx = max(dataSet.entryIndex(entry: entryFrom!, isEqual: true), 0)
|
||||
let maxx = min(dataSet.entryIndex(entry: entryTo!, isEqual: true) + 1, dataSet.entryCount)
|
||||
|
||||
let entry: BubbleChartDataEntry! = bubbleData.getEntryForHighlight(indice) as! BubbleChartDataEntry
|
||||
if (entry === nil || entry.xIndex != indice.xIndex)
|
||||
{
|
||||
continue
|
||||
}
|
||||
|
||||
let trans = delegate!.bubbleChartRenderer(self, transformerForAxis: dataSet.axisDependency)
|
||||
|
||||
_sizeBuffer[0].x = 0.0
|
||||
_sizeBuffer[0].y = 0.0
|
||||
_sizeBuffer[1].x = 1.0
|
||||
_sizeBuffer[1].y = 0.0
|
||||
|
||||
trans.pointValuesToPixel(&_sizeBuffer)
|
||||
|
||||
// calcualte the full width of 1 step on the x-axis
|
||||
let maxBubbleWidth: CGFloat = abs(_sizeBuffer[1].x - _sizeBuffer[0].x)
|
||||
let maxBubbleHeight: CGFloat = abs(viewPortHandler.contentBottom - viewPortHandler.contentTop)
|
||||
let referenceSize: CGFloat = min(maxBubbleHeight, maxBubbleWidth)
|
||||
|
||||
_pointBuffer.x = CGFloat(entry.xIndex - minx) * phaseX + CGFloat(minx)
|
||||
_pointBuffer.y = CGFloat(entry.value) * phaseY
|
||||
trans.pointValueToPixel(&_pointBuffer)
|
||||
|
||||
let shapeSize = getShapeSize(entrySize: entry.size, maxSize: dataSet.maxSize, reference: referenceSize)
|
||||
let shapeHalf = shapeSize / 2.0
|
||||
|
||||
if (!viewPortHandler.isInBoundsTop(_pointBuffer.y + shapeHalf)
|
||||
|| !viewPortHandler.isInBoundsBottom(_pointBuffer.y - shapeHalf))
|
||||
{
|
||||
continue
|
||||
}
|
||||
|
||||
if (!viewPortHandler.isInBoundsLeft(_pointBuffer.x + shapeHalf))
|
||||
{
|
||||
continue
|
||||
}
|
||||
|
||||
if (!viewPortHandler.isInBoundsRight(_pointBuffer.x - shapeHalf))
|
||||
{
|
||||
break
|
||||
}
|
||||
|
||||
if (indice.xIndex < minx || indice.xIndex >= maxx)
|
||||
{
|
||||
continue
|
||||
}
|
||||
|
||||
let originalColor = dataSet.colorAt(entry.xIndex)
|
||||
|
||||
var h: CGFloat = 0.0
|
||||
var s: CGFloat = 0.0
|
||||
var b: CGFloat = 0.0
|
||||
var a: CGFloat = 0.0
|
||||
|
||||
originalColor.getHue(&h, saturation: &s, brightness: &b, alpha: &a)
|
||||
|
||||
let color = UIColor(hue: h, saturation: s, brightness: b * 0.5, alpha: a)
|
||||
let rect = CGRect(
|
||||
x: _pointBuffer.x - shapeHalf,
|
||||
y: _pointBuffer.y - shapeHalf,
|
||||
width: shapeSize,
|
||||
height: shapeSize)
|
||||
|
||||
CGContextSetLineWidth(context, dataSet.highlightCircleWidth)
|
||||
CGContextSetStrokeColorWithColor(context, color.CGColor)
|
||||
CGContextStrokeEllipseInRect(context, rect)
|
||||
}
|
||||
|
||||
CGContextRestoreGState(context)
|
||||
}
|
||||
}
|
||||
299
Carthage/Checkouts/Charts/Charts/Classes/Renderers/CandleStickChartRenderer.swift
vendored
Normal file
299
Carthage/Checkouts/Charts/Charts/Classes/Renderers/CandleStickChartRenderer.swift
vendored
Normal file
@@ -0,0 +1,299 @@
|
||||
//
|
||||
// CandleStickChartRenderer.swift
|
||||
// Charts
|
||||
//
|
||||
// Created by Daniel Cohen Gindi on 4/3/15.
|
||||
//
|
||||
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
|
||||
// A port of MPAndroidChart for iOS
|
||||
// Licensed under Apache License 2.0
|
||||
//
|
||||
// https://github.com/danielgindi/ios-charts
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import CoreGraphics
|
||||
import UIKit
|
||||
|
||||
@objc
|
||||
public protocol CandleStickChartRendererDelegate
|
||||
{
|
||||
func candleStickChartRendererCandleData(renderer: CandleStickChartRenderer) -> CandleChartData!
|
||||
func candleStickChartRenderer(renderer: CandleStickChartRenderer, transformerForAxis which: ChartYAxis.AxisDependency) -> ChartTransformer!
|
||||
func candleStickChartDefaultRendererValueFormatter(renderer: CandleStickChartRenderer) -> NSNumberFormatter!
|
||||
func candleStickChartRendererChartYMax(renderer: CandleStickChartRenderer) -> Double
|
||||
func candleStickChartRendererChartYMin(renderer: CandleStickChartRenderer) -> Double
|
||||
func candleStickChartRendererChartXMax(renderer: CandleStickChartRenderer) -> Double
|
||||
func candleStickChartRendererChartXMin(renderer: CandleStickChartRenderer) -> Double
|
||||
func candleStickChartRendererMaxVisibleValueCount(renderer: CandleStickChartRenderer) -> Int
|
||||
}
|
||||
|
||||
public class CandleStickChartRenderer: LineScatterCandleRadarChartRenderer
|
||||
{
|
||||
public weak var delegate: CandleStickChartRendererDelegate?
|
||||
|
||||
public init(delegate: CandleStickChartRendererDelegate?, animator: ChartAnimator?, viewPortHandler: ChartViewPortHandler)
|
||||
{
|
||||
super.init(animator: animator, viewPortHandler: viewPortHandler)
|
||||
|
||||
self.delegate = delegate
|
||||
}
|
||||
|
||||
public override func drawData(context context: CGContext?)
|
||||
{
|
||||
let candleData = delegate!.candleStickChartRendererCandleData(self)
|
||||
|
||||
for set in candleData.dataSets as! [CandleChartDataSet]
|
||||
{
|
||||
if set.isVisible && set.entryCount > 0
|
||||
{
|
||||
drawDataSet(context: context, dataSet: set)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private var _shadowPoints = [CGPoint](count: 2, repeatedValue: CGPoint())
|
||||
private var _bodyRect = CGRect()
|
||||
private var _lineSegments = [CGPoint](count: 2, repeatedValue: CGPoint())
|
||||
|
||||
internal func drawDataSet(context context: CGContext?, dataSet: CandleChartDataSet)
|
||||
{
|
||||
let trans = delegate!.candleStickChartRenderer(self, transformerForAxis: dataSet.axisDependency)
|
||||
|
||||
let phaseX = _animator.phaseX
|
||||
let phaseY = _animator.phaseY
|
||||
let bodySpace = dataSet.bodySpace
|
||||
|
||||
var entries = dataSet.yVals as! [CandleChartDataEntry]
|
||||
|
||||
let minx = max(_minX, 0)
|
||||
let maxx = min(_maxX + 1, entries.count)
|
||||
|
||||
CGContextSaveGState(context)
|
||||
|
||||
CGContextSetLineWidth(context, dataSet.shadowWidth)
|
||||
|
||||
for (var j = minx, count = Int(ceil(CGFloat(maxx - minx) * phaseX + CGFloat(minx))); j < count; j++)
|
||||
{
|
||||
// get the entry
|
||||
let e = entries[j]
|
||||
|
||||
if (e.xIndex < _minX || e.xIndex > _maxX)
|
||||
{
|
||||
continue
|
||||
}
|
||||
|
||||
// calculate the shadow
|
||||
|
||||
_shadowPoints[0].x = CGFloat(e.xIndex)
|
||||
_shadowPoints[0].y = CGFloat(e.high) * phaseY
|
||||
_shadowPoints[1].x = CGFloat(e.xIndex)
|
||||
_shadowPoints[1].y = CGFloat(e.low) * phaseY
|
||||
|
||||
trans.pointValuesToPixel(&_shadowPoints)
|
||||
|
||||
// draw the shadow
|
||||
|
||||
var shadowColor: UIColor! = nil
|
||||
if (dataSet.shadowColorSameAsCandle)
|
||||
{
|
||||
if (e.open > e.close)
|
||||
{
|
||||
shadowColor = dataSet.decreasingColor ?? dataSet.colorAt(j)
|
||||
}
|
||||
else if (e.open < e.close)
|
||||
{
|
||||
shadowColor = dataSet.increasingColor ?? dataSet.colorAt(j)
|
||||
}
|
||||
}
|
||||
|
||||
if (shadowColor === nil)
|
||||
{
|
||||
shadowColor = dataSet.shadowColor ?? dataSet.colorAt(j);
|
||||
}
|
||||
|
||||
CGContextSetStrokeColorWithColor(context, shadowColor.CGColor)
|
||||
CGContextStrokeLineSegments(context, _shadowPoints, 2)
|
||||
|
||||
// calculate the body
|
||||
|
||||
_bodyRect.origin.x = CGFloat(e.xIndex) - 0.5 + bodySpace
|
||||
_bodyRect.origin.y = CGFloat(e.close) * phaseY
|
||||
_bodyRect.size.width = (CGFloat(e.xIndex) + 0.5 - bodySpace) - _bodyRect.origin.x
|
||||
_bodyRect.size.height = (CGFloat(e.open) * phaseY) - _bodyRect.origin.y
|
||||
|
||||
trans.rectValueToPixel(&_bodyRect)
|
||||
|
||||
// draw body differently for increasing and decreasing entry
|
||||
|
||||
if (e.open > e.close)
|
||||
{
|
||||
let color = dataSet.decreasingColor ?? dataSet.colorAt(j)
|
||||
|
||||
if (dataSet.isDecreasingFilled)
|
||||
{
|
||||
CGContextSetFillColorWithColor(context, color.CGColor)
|
||||
CGContextFillRect(context, _bodyRect)
|
||||
}
|
||||
else
|
||||
{
|
||||
CGContextSetStrokeColorWithColor(context, color.CGColor)
|
||||
CGContextStrokeRect(context, _bodyRect)
|
||||
}
|
||||
}
|
||||
else if (e.open < e.close)
|
||||
{
|
||||
let color = dataSet.increasingColor ?? dataSet.colorAt(j)
|
||||
|
||||
if (dataSet.isIncreasingFilled)
|
||||
{
|
||||
CGContextSetFillColorWithColor(context, color.CGColor)
|
||||
CGContextFillRect(context, _bodyRect)
|
||||
}
|
||||
else
|
||||
{
|
||||
CGContextSetStrokeColorWithColor(context, color.CGColor)
|
||||
CGContextStrokeRect(context, _bodyRect)
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
CGContextSetStrokeColorWithColor(context, shadowColor.CGColor)
|
||||
CGContextStrokeRect(context, _bodyRect)
|
||||
}
|
||||
}
|
||||
|
||||
CGContextRestoreGState(context)
|
||||
}
|
||||
|
||||
public override func drawValues(context context: CGContext?)
|
||||
{
|
||||
let candleData = delegate!.candleStickChartRendererCandleData(self)
|
||||
if (candleData === nil)
|
||||
{
|
||||
return
|
||||
}
|
||||
|
||||
let defaultValueFormatter = delegate!.candleStickChartDefaultRendererValueFormatter(self)
|
||||
|
||||
// if values are drawn
|
||||
if (candleData.yValCount < Int(ceil(CGFloat(delegate!.candleStickChartRendererMaxVisibleValueCount(self)) * viewPortHandler.scaleX)))
|
||||
{
|
||||
var dataSets = candleData.dataSets
|
||||
|
||||
for (var i = 0; i < dataSets.count; i++)
|
||||
{
|
||||
let dataSet = dataSets[i]
|
||||
|
||||
if !dataSet.isDrawValuesEnabled || dataSet.entryCount == 0
|
||||
{
|
||||
continue
|
||||
}
|
||||
|
||||
let valueFont = dataSet.valueFont
|
||||
let valueTextColor = dataSet.valueTextColor
|
||||
|
||||
var formatter = dataSet.valueFormatter
|
||||
if (formatter === nil)
|
||||
{
|
||||
formatter = defaultValueFormatter
|
||||
}
|
||||
|
||||
let trans = delegate!.candleStickChartRenderer(self, transformerForAxis: dataSet.axisDependency)
|
||||
|
||||
var entries = dataSet.yVals as! [CandleChartDataEntry]
|
||||
|
||||
let minx = max(_minX, 0)
|
||||
let maxx = min(_maxX + 1, entries.count)
|
||||
|
||||
var positions = trans.generateTransformedValuesCandle(entries, phaseY: _animator.phaseY)
|
||||
|
||||
let lineHeight = valueFont.lineHeight
|
||||
let yOffset: CGFloat = lineHeight + 5.0
|
||||
|
||||
for (var j = minx, count = Int(ceil(CGFloat(maxx - minx) * _animator.phaseX + CGFloat(minx))); j < count; j++)
|
||||
{
|
||||
let x = positions[j].x
|
||||
let y = positions[j].y
|
||||
|
||||
if (!viewPortHandler.isInBoundsRight(x))
|
||||
{
|
||||
break
|
||||
}
|
||||
|
||||
if (!viewPortHandler.isInBoundsLeft(x) || !viewPortHandler.isInBoundsY(y))
|
||||
{
|
||||
continue
|
||||
}
|
||||
|
||||
let val = entries[j].high
|
||||
|
||||
ChartUtils.drawText(context: context, text: formatter!.stringFromNumber(val)!, point: CGPoint(x: x, y: y - yOffset), align: .Center, attributes: [NSFontAttributeName: valueFont, NSForegroundColorAttributeName: valueTextColor])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override func drawExtras(context context: CGContext?)
|
||||
{
|
||||
}
|
||||
|
||||
private var _highlightPointBuffer = CGPoint()
|
||||
|
||||
public override func drawHighlighted(context context: CGContext?, indices: [ChartHighlight])
|
||||
{
|
||||
let candleData = delegate!.candleStickChartRendererCandleData(self)
|
||||
if (candleData === nil)
|
||||
{
|
||||
return
|
||||
}
|
||||
|
||||
CGContextSaveGState(context)
|
||||
|
||||
for (var i = 0; i < indices.count; i++)
|
||||
{
|
||||
let xIndex = indices[i].xIndex; // get the x-position
|
||||
|
||||
let set = candleData.getDataSetByIndex(indices[i].dataSetIndex) as! CandleChartDataSet!
|
||||
|
||||
if (set === nil || !set.isHighlightEnabled)
|
||||
{
|
||||
continue
|
||||
}
|
||||
|
||||
let e = set.entryForXIndex(xIndex) as! CandleChartDataEntry!
|
||||
|
||||
if (e === nil || e.xIndex != xIndex)
|
||||
{
|
||||
continue
|
||||
}
|
||||
|
||||
let trans = delegate!.candleStickChartRenderer(self, transformerForAxis: set.axisDependency)
|
||||
|
||||
CGContextSetStrokeColorWithColor(context, set.highlightColor.CGColor)
|
||||
CGContextSetLineWidth(context, set.highlightLineWidth)
|
||||
if (set.highlightLineDashLengths != nil)
|
||||
{
|
||||
CGContextSetLineDash(context, set.highlightLineDashPhase, set.highlightLineDashLengths!, set.highlightLineDashLengths!.count)
|
||||
}
|
||||
else
|
||||
{
|
||||
CGContextSetLineDash(context, 0.0, nil, 0)
|
||||
}
|
||||
|
||||
let low = CGFloat(e.low) * _animator.phaseY
|
||||
let high = CGFloat(e.high) * _animator.phaseY
|
||||
let y = (low + high) / 2.0
|
||||
|
||||
_highlightPointBuffer.x = CGFloat(xIndex)
|
||||
_highlightPointBuffer.y = y
|
||||
|
||||
trans.pointValueToPixel(&_highlightPointBuffer)
|
||||
|
||||
// draw the lines
|
||||
drawHighlightLines(context: context, point: _highlightPointBuffer, set: set)
|
||||
}
|
||||
|
||||
CGContextRestoreGState(context)
|
||||
}
|
||||
}
|
||||
56
Carthage/Checkouts/Charts/Charts/Classes/Renderers/ChartAxisRendererBase.swift
vendored
Normal file
56
Carthage/Checkouts/Charts/Charts/Classes/Renderers/ChartAxisRendererBase.swift
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
//
|
||||
// ChartAxisRendererBase.swift
|
||||
// Charts
|
||||
//
|
||||
// Created by Daniel Cohen Gindi on 3/3/15.
|
||||
//
|
||||
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
|
||||
// A port of MPAndroidChart for iOS
|
||||
// Licensed under Apache License 2.0
|
||||
//
|
||||
// https://github.com/danielgindi/ios-charts
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import UIKit
|
||||
|
||||
public class ChartAxisRendererBase: ChartRendererBase
|
||||
{
|
||||
internal var transformer: ChartTransformer!
|
||||
|
||||
public override init()
|
||||
{
|
||||
super.init()
|
||||
}
|
||||
|
||||
public init(viewPortHandler: ChartViewPortHandler, transformer: ChartTransformer!)
|
||||
{
|
||||
super.init(viewPortHandler: viewPortHandler)
|
||||
|
||||
self.transformer = transformer
|
||||
}
|
||||
|
||||
/// Draws the axis labels on the specified context
|
||||
public func renderAxisLabels(context context: CGContext?)
|
||||
{
|
||||
fatalError("renderAxisLabels() cannot be called on ChartAxisRendererBase")
|
||||
}
|
||||
|
||||
/// Draws the grid lines belonging to the axis.
|
||||
public func renderGridLines(context context: CGContext?)
|
||||
{
|
||||
fatalError("renderGridLines() cannot be called on ChartAxisRendererBase")
|
||||
}
|
||||
|
||||
/// Draws the line that goes alongside the axis.
|
||||
public func renderAxisLine(context context: CGContext?)
|
||||
{
|
||||
fatalError("renderAxisLine() cannot be called on ChartAxisRendererBase")
|
||||
}
|
||||
|
||||
/// Draws the LimitLines associated with this axis to the screen.
|
||||
public func renderLimitLines(context context: CGContext?)
|
||||
{
|
||||
fatalError("renderLimitLines() cannot be called on ChartAxisRendererBase")
|
||||
}
|
||||
}
|
||||
49
Carthage/Checkouts/Charts/Charts/Classes/Renderers/ChartDataRendererBase.swift
vendored
Normal file
49
Carthage/Checkouts/Charts/Charts/Classes/Renderers/ChartDataRendererBase.swift
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
//
|
||||
// ChartDataRendererBase.swift
|
||||
// Charts
|
||||
//
|
||||
// Created by Daniel Cohen Gindi on 4/3/15.
|
||||
//
|
||||
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
|
||||
// A port of MPAndroidChart for iOS
|
||||
// Licensed under Apache License 2.0
|
||||
//
|
||||
// https://github.com/danielgindi/ios-charts
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import CoreGraphics
|
||||
|
||||
public class ChartDataRendererBase: ChartRendererBase
|
||||
{
|
||||
internal var _animator: ChartAnimator!
|
||||
|
||||
public init(animator: ChartAnimator?, viewPortHandler: ChartViewPortHandler)
|
||||
{
|
||||
super.init(viewPortHandler: viewPortHandler)
|
||||
_animator = animator
|
||||
}
|
||||
|
||||
public func drawData(context context: CGContext?)
|
||||
{
|
||||
fatalError("drawData() cannot be called on ChartDataRendererBase")
|
||||
}
|
||||
|
||||
public func drawValues(context context: CGContext?)
|
||||
{
|
||||
fatalError("drawValues() cannot be called on ChartDataRendererBase")
|
||||
}
|
||||
|
||||
public func drawExtras(context context: CGContext?)
|
||||
{
|
||||
fatalError("drawExtras() cannot be called on ChartDataRendererBase")
|
||||
}
|
||||
|
||||
/// Draws all highlight indicators for the values that are currently highlighted.
|
||||
///
|
||||
/// - parameter indices: the highlighted values
|
||||
public func drawHighlighted(context context: CGContext?, indices: [ChartHighlight])
|
||||
{
|
||||
fatalError("drawHighlighted() cannot be called on ChartDataRendererBase")
|
||||
}
|
||||
}
|
||||
426
Carthage/Checkouts/Charts/Charts/Classes/Renderers/ChartLegendRenderer.swift
vendored
Executable file
426
Carthage/Checkouts/Charts/Charts/Classes/Renderers/ChartLegendRenderer.swift
vendored
Executable file
@@ -0,0 +1,426 @@
|
||||
//
|
||||
// ChartLegendRenderer.swift
|
||||
// Charts
|
||||
//
|
||||
// Created by Daniel Cohen Gindi on 4/3/15.
|
||||
//
|
||||
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
|
||||
// A port of MPAndroidChart for iOS
|
||||
// Licensed under Apache License 2.0
|
||||
//
|
||||
// https://github.com/danielgindi/ios-charts
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import CoreGraphics
|
||||
import UIKit
|
||||
|
||||
public class ChartLegendRenderer: ChartRendererBase
|
||||
{
|
||||
/// the legend object this renderer renders
|
||||
internal var _legend: ChartLegend!
|
||||
|
||||
public init(viewPortHandler: ChartViewPortHandler, legend: ChartLegend?)
|
||||
{
|
||||
super.init(viewPortHandler: viewPortHandler)
|
||||
_legend = legend
|
||||
}
|
||||
|
||||
/// Prepares the legend and calculates all needed forms, labels and colors.
|
||||
public func computeLegend(data: ChartData)
|
||||
{
|
||||
if (!_legend.isLegendCustom)
|
||||
{
|
||||
var labels = [String?]()
|
||||
var colors = [UIColor?]()
|
||||
|
||||
// loop for building up the colors and labels used in the legend
|
||||
for (var i = 0, count = data.dataSetCount; i < count; i++)
|
||||
{
|
||||
let dataSet = data.getDataSetByIndex(i)!
|
||||
|
||||
var clrs: [UIColor] = dataSet.colors
|
||||
let entryCount = dataSet.entryCount
|
||||
|
||||
// if we have a barchart with stacked bars
|
||||
if (dataSet.isKindOfClass(BarChartDataSet) && (dataSet as! BarChartDataSet).isStacked)
|
||||
{
|
||||
let bds = dataSet as! BarChartDataSet
|
||||
var sLabels = bds.stackLabels
|
||||
|
||||
for (var j = 0; j < clrs.count && j < bds.stackSize; j++)
|
||||
{
|
||||
labels.append(sLabels[j % sLabels.count])
|
||||
colors.append(clrs[j])
|
||||
}
|
||||
|
||||
if (bds.label != nil)
|
||||
{
|
||||
// add the legend description label
|
||||
colors.append(nil)
|
||||
labels.append(bds.label)
|
||||
}
|
||||
}
|
||||
else if (dataSet.isKindOfClass(PieChartDataSet))
|
||||
{
|
||||
var xVals = data.xVals
|
||||
let pds = dataSet as! PieChartDataSet
|
||||
|
||||
for (var j = 0; j < clrs.count && j < entryCount && j < xVals.count; j++)
|
||||
{
|
||||
labels.append(xVals[j])
|
||||
colors.append(clrs[j])
|
||||
}
|
||||
|
||||
if (pds.label != nil)
|
||||
{
|
||||
// add the legend description label
|
||||
colors.append(nil)
|
||||
labels.append(pds.label)
|
||||
}
|
||||
}
|
||||
else
|
||||
{ // all others
|
||||
|
||||
for (var j = 0; j < clrs.count && j < entryCount; j++)
|
||||
{
|
||||
// if multiple colors are set for a DataSet, group them
|
||||
if (j < clrs.count - 1 && j < entryCount - 1)
|
||||
{
|
||||
labels.append(nil)
|
||||
}
|
||||
else
|
||||
{ // add label to the last entry
|
||||
labels.append(dataSet.label)
|
||||
}
|
||||
|
||||
colors.append(clrs[j])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_legend.colors = colors + _legend._extraColors
|
||||
_legend.labels = labels + _legend._extraLabels
|
||||
}
|
||||
|
||||
// calculate all dimensions of the legend
|
||||
_legend.calculateDimensions(labelFont: _legend.font, viewPortHandler: viewPortHandler)
|
||||
}
|
||||
|
||||
public func renderLegend(context context: CGContext?)
|
||||
{
|
||||
if (_legend === nil || !_legend.enabled)
|
||||
{
|
||||
return
|
||||
}
|
||||
|
||||
let labelFont = _legend.font
|
||||
let labelTextColor = _legend.textColor
|
||||
let labelLineHeight = labelFont.lineHeight
|
||||
let formYOffset = labelLineHeight / 2.0
|
||||
|
||||
var labels = _legend.labels
|
||||
var colors = _legend.colors
|
||||
|
||||
let formSize = _legend.formSize
|
||||
let formToTextSpace = _legend.formToTextSpace
|
||||
let xEntrySpace = _legend.xEntrySpace
|
||||
let direction = _legend.direction
|
||||
|
||||
// space between the entries
|
||||
let stackSpace = _legend.stackSpace
|
||||
|
||||
let yoffset = _legend.yOffset
|
||||
let xoffset = _legend.xOffset
|
||||
|
||||
let legendPosition = _legend.position
|
||||
|
||||
switch (legendPosition)
|
||||
{
|
||||
case .BelowChartLeft: fallthrough
|
||||
case .BelowChartRight: fallthrough
|
||||
case .BelowChartCenter: fallthrough
|
||||
case .AboveChartLeft: fallthrough
|
||||
case .AboveChartRight: fallthrough
|
||||
case .AboveChartCenter:
|
||||
|
||||
let contentWidth: CGFloat = viewPortHandler.contentWidth
|
||||
|
||||
var originPosX: CGFloat
|
||||
|
||||
if (legendPosition == .BelowChartLeft || legendPosition == .AboveChartLeft)
|
||||
{
|
||||
originPosX = viewPortHandler.contentLeft + xoffset
|
||||
|
||||
if (direction == .RightToLeft)
|
||||
{
|
||||
originPosX += _legend.neededWidth
|
||||
}
|
||||
}
|
||||
else if (legendPosition == .BelowChartRight || legendPosition == .AboveChartRight)
|
||||
{
|
||||
originPosX = viewPortHandler.contentRight - xoffset
|
||||
|
||||
if (direction == .LeftToRight)
|
||||
{
|
||||
originPosX -= _legend.neededWidth
|
||||
}
|
||||
}
|
||||
else // .BelowChartCenter || .AboveChartCenter
|
||||
{
|
||||
originPosX = viewPortHandler.contentLeft + contentWidth / 2.0
|
||||
}
|
||||
|
||||
var calculatedLineSizes = _legend.calculatedLineSizes
|
||||
var calculatedLabelSizes = _legend.calculatedLabelSizes
|
||||
var calculatedLabelBreakPoints = _legend.calculatedLabelBreakPoints
|
||||
|
||||
var posX: CGFloat = originPosX
|
||||
var posY: CGFloat
|
||||
|
||||
if (legendPosition == .AboveChartLeft
|
||||
|| legendPosition == .AboveChartRight
|
||||
|| legendPosition == .AboveChartCenter)
|
||||
{
|
||||
posY = 0
|
||||
}
|
||||
else
|
||||
{
|
||||
posY = viewPortHandler.chartHeight - yoffset - _legend.neededHeight
|
||||
}
|
||||
|
||||
var lineIndex: Int = 0
|
||||
|
||||
for (var i = 0, count = labels.count; i < count; i++)
|
||||
{
|
||||
if (i < calculatedLabelBreakPoints.count && calculatedLabelBreakPoints[i])
|
||||
{
|
||||
posX = originPosX
|
||||
posY += labelLineHeight
|
||||
}
|
||||
|
||||
if (posX == originPosX && legendPosition == .BelowChartCenter && lineIndex < calculatedLineSizes.count)
|
||||
{
|
||||
posX += (direction == .RightToLeft ? calculatedLineSizes[lineIndex].width : -calculatedLineSizes[lineIndex].width) / 2.0
|
||||
lineIndex++
|
||||
}
|
||||
|
||||
let drawingForm = colors[i] != nil
|
||||
let isStacked = labels[i] == nil; // grouped forms have null labels
|
||||
|
||||
if (drawingForm)
|
||||
{
|
||||
if (direction == .RightToLeft)
|
||||
{
|
||||
posX -= formSize
|
||||
}
|
||||
|
||||
drawForm(context, x: posX, y: posY + formYOffset, colorIndex: i, legend: _legend)
|
||||
|
||||
if (direction == .LeftToRight)
|
||||
{
|
||||
posX += formSize
|
||||
}
|
||||
}
|
||||
|
||||
if (!isStacked)
|
||||
{
|
||||
if (drawingForm)
|
||||
{
|
||||
posX += direction == .RightToLeft ? -formToTextSpace : formToTextSpace
|
||||
}
|
||||
|
||||
if (direction == .RightToLeft)
|
||||
{
|
||||
posX -= calculatedLabelSizes[i].width
|
||||
}
|
||||
|
||||
drawLabel(context, x: posX, y: posY, label: labels[i]!, font: labelFont, textColor: labelTextColor)
|
||||
|
||||
if (direction == .LeftToRight)
|
||||
{
|
||||
posX += calculatedLabelSizes[i].width
|
||||
}
|
||||
|
||||
posX += direction == .RightToLeft ? -xEntrySpace : xEntrySpace
|
||||
}
|
||||
else
|
||||
{
|
||||
posX += direction == .RightToLeft ? -stackSpace : stackSpace
|
||||
}
|
||||
}
|
||||
|
||||
break
|
||||
|
||||
case .PiechartCenter: fallthrough
|
||||
case .RightOfChart: fallthrough
|
||||
case .RightOfChartCenter: fallthrough
|
||||
case .RightOfChartInside: fallthrough
|
||||
case .LeftOfChart: fallthrough
|
||||
case .LeftOfChartCenter: fallthrough
|
||||
case .LeftOfChartInside:
|
||||
|
||||
// contains the stacked legend size in pixels
|
||||
var stack = CGFloat(0.0)
|
||||
var wasStacked = false
|
||||
var posX: CGFloat = 0.0, posY: CGFloat = 0.0
|
||||
|
||||
if (legendPosition == .PiechartCenter)
|
||||
{
|
||||
posX = viewPortHandler.chartWidth / 2.0 + (direction == .LeftToRight ? -_legend.textWidthMax / 2.0 : _legend.textWidthMax / 2.0)
|
||||
posY = viewPortHandler.chartHeight / 2.0 - _legend.neededHeight / 2.0 + _legend.yOffset
|
||||
}
|
||||
else
|
||||
{
|
||||
let isRightAligned = legendPosition == .RightOfChart ||
|
||||
legendPosition == .RightOfChartCenter ||
|
||||
legendPosition == .RightOfChartInside
|
||||
|
||||
if (isRightAligned)
|
||||
{
|
||||
posX = viewPortHandler.chartWidth - xoffset
|
||||
if (direction == .LeftToRight)
|
||||
{
|
||||
posX -= _legend.textWidthMax
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
posX = xoffset
|
||||
if (direction == .RightToLeft)
|
||||
{
|
||||
posX += _legend.textWidthMax
|
||||
}
|
||||
}
|
||||
|
||||
if (legendPosition == .RightOfChart ||
|
||||
legendPosition == .LeftOfChart)
|
||||
{
|
||||
posY = viewPortHandler.contentTop + yoffset
|
||||
}
|
||||
else if (legendPosition == .RightOfChartCenter ||
|
||||
legendPosition == .LeftOfChartCenter)
|
||||
{
|
||||
posY = viewPortHandler.chartHeight / 2.0 - _legend.neededHeight / 2.0
|
||||
}
|
||||
else /*if (legend.position == .RightOfChartInside ||
|
||||
legend.position == .LeftOfChartInside)*/
|
||||
{
|
||||
posY = viewPortHandler.contentTop + yoffset
|
||||
}
|
||||
}
|
||||
|
||||
for (var i = 0; i < labels.count; i++)
|
||||
{
|
||||
let drawingForm = colors[i] != nil
|
||||
var x = posX
|
||||
|
||||
if (drawingForm)
|
||||
{
|
||||
if (direction == .LeftToRight)
|
||||
{
|
||||
x += stack
|
||||
}
|
||||
else
|
||||
{
|
||||
x -= formSize - stack
|
||||
}
|
||||
|
||||
drawForm(context, x: x, y: posY + formYOffset, colorIndex: i, legend: _legend)
|
||||
|
||||
if (direction == .LeftToRight)
|
||||
{
|
||||
x += formSize
|
||||
}
|
||||
}
|
||||
|
||||
if (labels[i] != nil)
|
||||
{
|
||||
if (drawingForm && !wasStacked)
|
||||
{
|
||||
x += direction == .LeftToRight ? formToTextSpace : -formToTextSpace
|
||||
}
|
||||
else if (wasStacked)
|
||||
{
|
||||
x = posX
|
||||
}
|
||||
|
||||
if (direction == .RightToLeft)
|
||||
{
|
||||
x -= (labels[i] as NSString!).sizeWithAttributes([NSFontAttributeName: labelFont]).width
|
||||
}
|
||||
|
||||
if (!wasStacked)
|
||||
{
|
||||
drawLabel(context, x: x, y: posY, label: labels[i]!, font: labelFont, textColor: labelTextColor)
|
||||
}
|
||||
else
|
||||
{
|
||||
posY += labelLineHeight
|
||||
drawLabel(context, x: x, y: posY, label: labels[i]!, font: labelFont, textColor: labelTextColor)
|
||||
}
|
||||
|
||||
// make a step down
|
||||
posY += labelLineHeight
|
||||
stack = 0.0
|
||||
}
|
||||
else
|
||||
{
|
||||
stack += formSize + stackSpace
|
||||
wasStacked = true
|
||||
}
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
private var _formLineSegmentsBuffer = [CGPoint](count: 2, repeatedValue: CGPoint())
|
||||
|
||||
/// Draws the Legend-form at the given position with the color at the given index.
|
||||
internal func drawForm(context: CGContext?, x: CGFloat, y: CGFloat, colorIndex: Int, legend: ChartLegend)
|
||||
{
|
||||
let formColor = legend.colors[colorIndex]
|
||||
|
||||
if (formColor === nil || formColor == UIColor.clearColor())
|
||||
{
|
||||
return
|
||||
}
|
||||
|
||||
let formsize = legend.formSize
|
||||
|
||||
CGContextSaveGState(context)
|
||||
|
||||
switch (legend.form)
|
||||
{
|
||||
case .Circle:
|
||||
CGContextSetFillColorWithColor(context, formColor!.CGColor)
|
||||
CGContextFillEllipseInRect(context, CGRect(x: x, y: y - formsize / 2.0, width: formsize, height: formsize))
|
||||
break
|
||||
case .Square:
|
||||
CGContextSetFillColorWithColor(context, formColor!.CGColor)
|
||||
CGContextFillRect(context, CGRect(x: x, y: y - formsize / 2.0, width: formsize, height: formsize))
|
||||
break
|
||||
case .Line:
|
||||
|
||||
CGContextSetLineWidth(context, legend.formLineWidth)
|
||||
CGContextSetStrokeColorWithColor(context, formColor!.CGColor)
|
||||
|
||||
_formLineSegmentsBuffer[0].x = x
|
||||
_formLineSegmentsBuffer[0].y = y
|
||||
_formLineSegmentsBuffer[1].x = x + formsize
|
||||
_formLineSegmentsBuffer[1].y = y
|
||||
CGContextStrokeLineSegments(context, _formLineSegmentsBuffer, 2)
|
||||
|
||||
break
|
||||
}
|
||||
|
||||
CGContextRestoreGState(context)
|
||||
}
|
||||
|
||||
/// Draws the provided label at the given position.
|
||||
internal func drawLabel(context: CGContext?, x: CGFloat, y: CGFloat, label: String, font: UIFont, textColor: UIColor)
|
||||
{
|
||||
ChartUtils.drawText(context: context, text: label, point: CGPoint(x: x, y: y), align: .Left, attributes: [NSFontAttributeName: font, NSForegroundColorAttributeName: textColor])
|
||||
}
|
||||
}
|
||||
64
Carthage/Checkouts/Charts/Charts/Classes/Renderers/ChartRendererBase.swift
vendored
Normal file
64
Carthage/Checkouts/Charts/Charts/Classes/Renderers/ChartRendererBase.swift
vendored
Normal file
@@ -0,0 +1,64 @@
|
||||
//
|
||||
// ChartRendererBase.swift
|
||||
// Charts
|
||||
//
|
||||
// Created by Daniel Cohen Gindi on 3/3/15.
|
||||
//
|
||||
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
|
||||
// A port of MPAndroidChart for iOS
|
||||
// Licensed under Apache License 2.0
|
||||
//
|
||||
// https://github.com/danielgindi/ios-charts
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import CoreGraphics
|
||||
|
||||
public class ChartRendererBase: NSObject
|
||||
{
|
||||
/// the component that handles the drawing area of the chart and it's offsets
|
||||
public var viewPortHandler: ChartViewPortHandler!
|
||||
|
||||
/// the minimum value on the x-axis that should be plotted
|
||||
internal var _minX: Int = 0
|
||||
|
||||
/// the maximum value on the x-axis that should be plotted
|
||||
internal var _maxX: Int = 0
|
||||
|
||||
public override init()
|
||||
{
|
||||
super.init()
|
||||
}
|
||||
|
||||
public init(viewPortHandler: ChartViewPortHandler)
|
||||
{
|
||||
super.init()
|
||||
self.viewPortHandler = viewPortHandler
|
||||
}
|
||||
|
||||
/// - returns: true if the specified value fits in between the provided min and max bounds, false if not.
|
||||
internal func fitsBounds(val: Double, min: Double, max: Double) -> Bool
|
||||
{
|
||||
if (val < min || val > max)
|
||||
{
|
||||
return false
|
||||
}
|
||||
else
|
||||
{
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
/// Calculates the minimum and maximum x-value the chart can currently display (with the given zoom level).
|
||||
public func calcXBounds(chart chart: BarLineChartViewBase, xAxisModulus: Int)
|
||||
{
|
||||
let low = chart.lowestVisibleXIndex
|
||||
let high = chart.highestVisibleXIndex
|
||||
|
||||
let subLow = (low % xAxisModulus == 0) ? xAxisModulus : 0
|
||||
|
||||
_minX = max((low / xAxisModulus) * (xAxisModulus) - subLow, 0)
|
||||
_maxX = min((high / xAxisModulus) * (xAxisModulus) + xAxisModulus, Int(chart.chartXMax))
|
||||
}
|
||||
}
|
||||
|
||||
339
Carthage/Checkouts/Charts/Charts/Classes/Renderers/ChartXAxisRenderer.swift
vendored
Normal file
339
Carthage/Checkouts/Charts/Charts/Classes/Renderers/ChartXAxisRenderer.swift
vendored
Normal file
@@ -0,0 +1,339 @@
|
||||
//
|
||||
// ChartXAxisRenderer.swift
|
||||
// Charts
|
||||
//
|
||||
// Created by Daniel Cohen Gindi on 3/3/15.
|
||||
//
|
||||
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
|
||||
// A port of MPAndroidChart for iOS
|
||||
// Licensed under Apache License 2.0
|
||||
//
|
||||
// https://github.com/danielgindi/ios-charts
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import CoreGraphics
|
||||
import UIKit
|
||||
|
||||
public class ChartXAxisRenderer: ChartAxisRendererBase
|
||||
{
|
||||
internal var _xAxis: ChartXAxis!
|
||||
|
||||
public init(viewPortHandler: ChartViewPortHandler, xAxis: ChartXAxis, transformer: ChartTransformer!)
|
||||
{
|
||||
super.init(viewPortHandler: viewPortHandler, transformer: transformer)
|
||||
|
||||
_xAxis = xAxis
|
||||
}
|
||||
|
||||
public func computeAxis(xValAverageLength xValAverageLength: Double, xValues: [String?])
|
||||
{
|
||||
var a = ""
|
||||
|
||||
let max = Int(round(xValAverageLength + Double(_xAxis.spaceBetweenLabels)))
|
||||
|
||||
for (var i = 0; i < max; i++)
|
||||
{
|
||||
a += "h"
|
||||
}
|
||||
|
||||
let widthText = a as NSString
|
||||
|
||||
_xAxis.labelWidth = widthText.sizeWithAttributes([NSFontAttributeName: _xAxis.labelFont]).width
|
||||
_xAxis.labelHeight = _xAxis.labelFont.lineHeight
|
||||
_xAxis.values = xValues
|
||||
}
|
||||
|
||||
public override func renderAxisLabels(context context: CGContext?)
|
||||
{
|
||||
if (!_xAxis.isEnabled || !_xAxis.isDrawLabelsEnabled)
|
||||
{
|
||||
return
|
||||
}
|
||||
|
||||
let yoffset = CGFloat(4.0)
|
||||
|
||||
if (_xAxis.labelPosition == .Top)
|
||||
{
|
||||
drawLabels(context: context, pos: viewPortHandler.offsetTop - _xAxis.labelHeight - yoffset)
|
||||
}
|
||||
else if (_xAxis.labelPosition == .Bottom)
|
||||
{
|
||||
drawLabels(context: context, pos: viewPortHandler.contentBottom + yoffset * 1.5)
|
||||
}
|
||||
else if (_xAxis.labelPosition == .BottomInside)
|
||||
{
|
||||
drawLabels(context: context, pos: viewPortHandler.contentBottom - _xAxis.labelHeight - yoffset)
|
||||
}
|
||||
else if (_xAxis.labelPosition == .TopInside)
|
||||
{
|
||||
drawLabels(context: context, pos: viewPortHandler.offsetTop + yoffset)
|
||||
}
|
||||
else
|
||||
{ // BOTH SIDED
|
||||
drawLabels(context: context, pos: viewPortHandler.offsetTop - _xAxis.labelHeight - yoffset)
|
||||
drawLabels(context: context, pos: viewPortHandler.contentBottom + yoffset * 1.6)
|
||||
}
|
||||
}
|
||||
|
||||
private var _axisLineSegmentsBuffer = [CGPoint](count: 2, repeatedValue: CGPoint())
|
||||
|
||||
public override func renderAxisLine(context context: CGContext?)
|
||||
{
|
||||
if (!_xAxis.isEnabled || !_xAxis.isDrawAxisLineEnabled)
|
||||
{
|
||||
return
|
||||
}
|
||||
|
||||
CGContextSaveGState(context)
|
||||
|
||||
CGContextSetStrokeColorWithColor(context, _xAxis.axisLineColor.CGColor)
|
||||
CGContextSetLineWidth(context, _xAxis.axisLineWidth)
|
||||
if (_xAxis.axisLineDashLengths != nil)
|
||||
{
|
||||
CGContextSetLineDash(context, _xAxis.axisLineDashPhase, _xAxis.axisLineDashLengths, _xAxis.axisLineDashLengths.count)
|
||||
}
|
||||
else
|
||||
{
|
||||
CGContextSetLineDash(context, 0.0, nil, 0)
|
||||
}
|
||||
|
||||
if (_xAxis.labelPosition == .Top
|
||||
|| _xAxis.labelPosition == .TopInside
|
||||
|| _xAxis.labelPosition == .BothSided)
|
||||
{
|
||||
_axisLineSegmentsBuffer[0].x = viewPortHandler.contentLeft
|
||||
_axisLineSegmentsBuffer[0].y = viewPortHandler.contentTop
|
||||
_axisLineSegmentsBuffer[1].x = viewPortHandler.contentRight
|
||||
_axisLineSegmentsBuffer[1].y = viewPortHandler.contentTop
|
||||
CGContextStrokeLineSegments(context, _axisLineSegmentsBuffer, 2)
|
||||
}
|
||||
|
||||
if (_xAxis.labelPosition == .Bottom
|
||||
|| _xAxis.labelPosition == .BottomInside
|
||||
|| _xAxis.labelPosition == .BothSided)
|
||||
{
|
||||
_axisLineSegmentsBuffer[0].x = viewPortHandler.contentLeft
|
||||
_axisLineSegmentsBuffer[0].y = viewPortHandler.contentBottom
|
||||
_axisLineSegmentsBuffer[1].x = viewPortHandler.contentRight
|
||||
_axisLineSegmentsBuffer[1].y = viewPortHandler.contentBottom
|
||||
CGContextStrokeLineSegments(context, _axisLineSegmentsBuffer, 2)
|
||||
}
|
||||
|
||||
CGContextRestoreGState(context)
|
||||
}
|
||||
|
||||
/// draws the x-labels on the specified y-position
|
||||
internal func drawLabels(context context: CGContext?, pos: CGFloat)
|
||||
{
|
||||
let paraStyle = NSParagraphStyle.defaultParagraphStyle().mutableCopy() as! NSMutableParagraphStyle
|
||||
paraStyle.alignment = .Center
|
||||
|
||||
let labelAttrs = [NSFontAttributeName: _xAxis.labelFont,
|
||||
NSForegroundColorAttributeName: _xAxis.labelTextColor,
|
||||
NSParagraphStyleAttributeName: paraStyle]
|
||||
|
||||
let valueToPixelMatrix = transformer.valueToPixelMatrix
|
||||
|
||||
var position = CGPoint(x: 0.0, y: 0.0)
|
||||
|
||||
var labelMaxSize = CGSize()
|
||||
|
||||
if (_xAxis.isWordWrapEnabled)
|
||||
{
|
||||
labelMaxSize.width = _xAxis.wordWrapWidthPercent * valueToPixelMatrix.a
|
||||
}
|
||||
|
||||
for (var i = _minX, maxX = min(_maxX + 1, _xAxis.values.count); i < maxX; i += _xAxis.axisLabelModulus)
|
||||
{
|
||||
let label = _xAxis.values[i]
|
||||
if (label == nil)
|
||||
{
|
||||
continue
|
||||
}
|
||||
|
||||
position.x = CGFloat(i)
|
||||
position.y = 0.0
|
||||
position = CGPointApplyAffineTransform(position, valueToPixelMatrix)
|
||||
|
||||
if (viewPortHandler.isInBoundsX(position.x))
|
||||
{
|
||||
let labelns = label! as NSString
|
||||
|
||||
if (_xAxis.isAvoidFirstLastClippingEnabled)
|
||||
{
|
||||
// avoid clipping of the last
|
||||
if (i == _xAxis.values.count - 1 && _xAxis.values.count > 1)
|
||||
{
|
||||
let width = labelns.boundingRectWithSize(labelMaxSize, options: .UsesLineFragmentOrigin, attributes: labelAttrs, context: nil).size.width
|
||||
|
||||
if (width > viewPortHandler.offsetRight * 2.0
|
||||
&& position.x + width > viewPortHandler.chartWidth)
|
||||
{
|
||||
position.x -= width / 2.0
|
||||
}
|
||||
}
|
||||
else if (i == 0)
|
||||
{ // avoid clipping of the first
|
||||
let width = labelns.boundingRectWithSize(labelMaxSize, options: .UsesLineFragmentOrigin, attributes: labelAttrs, context: nil).size.width
|
||||
position.x += width / 2.0
|
||||
}
|
||||
}
|
||||
|
||||
drawLabel(context: context, label: label!, xIndex: i, x: position.x, y: pos, align: .Center, attributes: labelAttrs, constrainedToSize: labelMaxSize)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal func drawLabel(context context: CGContext?, label: String, xIndex: Int, x: CGFloat, y: CGFloat, align: NSTextAlignment, attributes: [String: NSObject], constrainedToSize: CGSize)
|
||||
{
|
||||
let formattedLabel = _xAxis.valueFormatter?.stringForXValue(xIndex, original: label, viewPortHandler: viewPortHandler) ?? label
|
||||
ChartUtils.drawMultilineText(context: context, text: formattedLabel, point: CGPoint(x: x, y: y), align: align, attributes: attributes, constrainedToSize: constrainedToSize)
|
||||
}
|
||||
|
||||
private var _gridLineSegmentsBuffer = [CGPoint](count: 2, repeatedValue: CGPoint())
|
||||
|
||||
public override func renderGridLines(context context: CGContext?)
|
||||
{
|
||||
if (!_xAxis.isDrawGridLinesEnabled || !_xAxis.isEnabled)
|
||||
{
|
||||
return
|
||||
}
|
||||
|
||||
CGContextSaveGState(context)
|
||||
|
||||
CGContextSetStrokeColorWithColor(context, _xAxis.gridColor.CGColor)
|
||||
CGContextSetLineWidth(context, _xAxis.gridLineWidth)
|
||||
if (_xAxis.gridLineDashLengths != nil)
|
||||
{
|
||||
CGContextSetLineDash(context, _xAxis.gridLineDashPhase, _xAxis.gridLineDashLengths, _xAxis.gridLineDashLengths.count)
|
||||
}
|
||||
else
|
||||
{
|
||||
CGContextSetLineDash(context, 0.0, nil, 0)
|
||||
}
|
||||
|
||||
let valueToPixelMatrix = transformer.valueToPixelMatrix
|
||||
|
||||
var position = CGPoint(x: 0.0, y: 0.0)
|
||||
|
||||
for (var i = _minX; i <= _maxX; i += _xAxis.axisLabelModulus)
|
||||
{
|
||||
position.x = CGFloat(i)
|
||||
position.y = 0.0
|
||||
position = CGPointApplyAffineTransform(position, valueToPixelMatrix)
|
||||
|
||||
if (position.x >= viewPortHandler.offsetLeft
|
||||
&& position.x <= viewPortHandler.chartWidth)
|
||||
{
|
||||
_gridLineSegmentsBuffer[0].x = position.x
|
||||
_gridLineSegmentsBuffer[0].y = viewPortHandler.contentTop
|
||||
_gridLineSegmentsBuffer[1].x = position.x
|
||||
_gridLineSegmentsBuffer[1].y = viewPortHandler.contentBottom
|
||||
CGContextStrokeLineSegments(context, _gridLineSegmentsBuffer, 2)
|
||||
}
|
||||
}
|
||||
|
||||
CGContextRestoreGState(context)
|
||||
}
|
||||
|
||||
private var _limitLineSegmentsBuffer = [CGPoint](count: 2, repeatedValue: CGPoint())
|
||||
|
||||
public override func renderLimitLines(context context: CGContext?)
|
||||
{
|
||||
var limitLines = _xAxis.limitLines
|
||||
|
||||
if (limitLines.count == 0)
|
||||
{
|
||||
return
|
||||
}
|
||||
|
||||
CGContextSaveGState(context)
|
||||
|
||||
let trans = transformer.valueToPixelMatrix
|
||||
|
||||
var position = CGPoint(x: 0.0, y: 0.0)
|
||||
|
||||
for (var i = 0; i < limitLines.count; i++)
|
||||
{
|
||||
let l = limitLines[i]
|
||||
|
||||
position.x = CGFloat(l.limit)
|
||||
position.y = 0.0
|
||||
position = CGPointApplyAffineTransform(position, trans)
|
||||
|
||||
_limitLineSegmentsBuffer[0].x = position.x
|
||||
_limitLineSegmentsBuffer[0].y = viewPortHandler.contentTop
|
||||
_limitLineSegmentsBuffer[1].x = position.x
|
||||
_limitLineSegmentsBuffer[1].y = viewPortHandler.contentBottom
|
||||
|
||||
CGContextSetStrokeColorWithColor(context, l.lineColor.CGColor)
|
||||
CGContextSetLineWidth(context, l.lineWidth)
|
||||
if (l.lineDashLengths != nil)
|
||||
{
|
||||
CGContextSetLineDash(context, l.lineDashPhase, l.lineDashLengths!, l.lineDashLengths!.count)
|
||||
}
|
||||
else
|
||||
{
|
||||
CGContextSetLineDash(context, 0.0, nil, 0)
|
||||
}
|
||||
|
||||
CGContextStrokeLineSegments(context, _limitLineSegmentsBuffer, 2)
|
||||
|
||||
let label = l.label
|
||||
|
||||
// if drawing the limit-value label is enabled
|
||||
if (label.characters.count > 0)
|
||||
{
|
||||
let labelLineHeight = l.valueFont.lineHeight
|
||||
|
||||
let add = CGFloat(4.0)
|
||||
let xOffset: CGFloat = l.lineWidth
|
||||
let yOffset: CGFloat = add / 2.0
|
||||
|
||||
if (l.labelPosition == .RightTop)
|
||||
{
|
||||
ChartUtils.drawText(context: context,
|
||||
text: label,
|
||||
point: CGPoint(
|
||||
x: position.x + xOffset,
|
||||
y: viewPortHandler.contentTop + yOffset),
|
||||
align: .Left,
|
||||
attributes: [NSFontAttributeName: l.valueFont, NSForegroundColorAttributeName: l.valueTextColor])
|
||||
}
|
||||
else if (l.labelPosition == .RightBottom)
|
||||
{
|
||||
ChartUtils.drawText(context: context,
|
||||
text: label,
|
||||
point: CGPoint(
|
||||
x: position.x + xOffset,
|
||||
y: viewPortHandler.contentBottom - labelLineHeight - yOffset),
|
||||
align: .Left,
|
||||
attributes: [NSFontAttributeName: l.valueFont, NSForegroundColorAttributeName: l.valueTextColor])
|
||||
}
|
||||
else if (l.labelPosition == .LeftTop)
|
||||
{
|
||||
ChartUtils.drawText(context: context,
|
||||
text: label,
|
||||
point: CGPoint(
|
||||
x: position.x - xOffset,
|
||||
y: viewPortHandler.contentTop + yOffset),
|
||||
align: .Right,
|
||||
attributes: [NSFontAttributeName: l.valueFont, NSForegroundColorAttributeName: l.valueTextColor])
|
||||
}
|
||||
else
|
||||
{
|
||||
ChartUtils.drawText(context: context,
|
||||
text: label,
|
||||
point: CGPoint(
|
||||
x: position.x - xOffset,
|
||||
y: viewPortHandler.contentBottom - labelLineHeight - yOffset),
|
||||
align: .Right,
|
||||
attributes: [NSFontAttributeName: l.valueFont, NSForegroundColorAttributeName: l.valueTextColor])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CGContextRestoreGState(context)
|
||||
}
|
||||
}
|
||||
151
Carthage/Checkouts/Charts/Charts/Classes/Renderers/ChartXAxisRendererBarChart.swift
vendored
Normal file
151
Carthage/Checkouts/Charts/Charts/Classes/Renderers/ChartXAxisRendererBarChart.swift
vendored
Normal file
@@ -0,0 +1,151 @@
|
||||
//
|
||||
// ChartXAxisRendererBarChart.swift
|
||||
// Charts
|
||||
//
|
||||
// Created by Daniel Cohen Gindi on 3/3/15.
|
||||
//
|
||||
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
|
||||
// A port of MPAndroidChart for iOS
|
||||
// Licensed under Apache License 2.0
|
||||
//
|
||||
// https://github.com/danielgindi/ios-charts
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import CoreGraphics
|
||||
import UIKit
|
||||
|
||||
public class ChartXAxisRendererBarChart: ChartXAxisRenderer
|
||||
{
|
||||
internal weak var _chart: BarChartView!
|
||||
|
||||
public init(viewPortHandler: ChartViewPortHandler, xAxis: ChartXAxis, transformer: ChartTransformer!, chart: BarChartView)
|
||||
{
|
||||
super.init(viewPortHandler: viewPortHandler, xAxis: xAxis, transformer: transformer)
|
||||
|
||||
self._chart = chart
|
||||
}
|
||||
|
||||
/// draws the x-labels on the specified y-position
|
||||
internal override func drawLabels(context context: CGContext?, pos: CGFloat)
|
||||
{
|
||||
if (_chart.data === nil)
|
||||
{
|
||||
return
|
||||
}
|
||||
|
||||
let paraStyle = NSParagraphStyle.defaultParagraphStyle().mutableCopy() as! NSMutableParagraphStyle
|
||||
paraStyle.alignment = .Center
|
||||
|
||||
let labelAttrs = [NSFontAttributeName: _xAxis.labelFont,
|
||||
NSForegroundColorAttributeName: _xAxis.labelTextColor,
|
||||
NSParagraphStyleAttributeName: paraStyle]
|
||||
|
||||
let barData = _chart.data as! BarChartData
|
||||
let step = barData.dataSetCount
|
||||
|
||||
let valueToPixelMatrix = transformer.valueToPixelMatrix
|
||||
|
||||
var position = CGPoint(x: 0.0, y: 0.0)
|
||||
|
||||
var labelMaxSize = CGSize()
|
||||
|
||||
if (_xAxis.isWordWrapEnabled)
|
||||
{
|
||||
labelMaxSize.width = _xAxis.wordWrapWidthPercent * valueToPixelMatrix.a
|
||||
}
|
||||
|
||||
for (var i = _minX, maxX = min(_maxX + 1, _xAxis.values.count); i < maxX; i += _xAxis.axisLabelModulus)
|
||||
{
|
||||
let label = i >= 0 && i < _xAxis.values.count ? _xAxis.values[i] : nil
|
||||
if (label == nil)
|
||||
{
|
||||
continue
|
||||
}
|
||||
|
||||
position.x = CGFloat(i * step) + CGFloat(i) * barData.groupSpace + barData.groupSpace / 2.0
|
||||
position.y = 0.0
|
||||
|
||||
// consider groups (center label for each group)
|
||||
if (step > 1)
|
||||
{
|
||||
position.x += (CGFloat(step) - 1.0) / 2.0
|
||||
}
|
||||
|
||||
position = CGPointApplyAffineTransform(position, valueToPixelMatrix)
|
||||
|
||||
if (viewPortHandler.isInBoundsX(position.x))
|
||||
{
|
||||
if (_xAxis.isAvoidFirstLastClippingEnabled)
|
||||
{
|
||||
// avoid clipping of the last
|
||||
if (i == _xAxis.values.count - 1)
|
||||
{
|
||||
let width = label!.sizeWithAttributes(labelAttrs).width
|
||||
|
||||
if (width > viewPortHandler.offsetRight * 2.0
|
||||
&& position.x + width > viewPortHandler.chartWidth)
|
||||
{
|
||||
position.x -= width / 2.0
|
||||
}
|
||||
}
|
||||
else if (i == 0)
|
||||
{ // avoid clipping of the first
|
||||
let width = label!.sizeWithAttributes(labelAttrs).width
|
||||
position.x += width / 2.0
|
||||
}
|
||||
}
|
||||
|
||||
drawLabel(context: context, label: label!, xIndex: i, x: position.x, y: pos, align: .Center, attributes: labelAttrs, constrainedToSize: labelMaxSize)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private var _gridLineSegmentsBuffer = [CGPoint](count: 2, repeatedValue: CGPoint())
|
||||
|
||||
public override func renderGridLines(context context: CGContext?)
|
||||
{
|
||||
if (!_xAxis.isDrawGridLinesEnabled || !_xAxis.isEnabled)
|
||||
{
|
||||
return
|
||||
}
|
||||
|
||||
let barData = _chart.data as! BarChartData
|
||||
let step = barData.dataSetCount
|
||||
|
||||
CGContextSaveGState(context)
|
||||
|
||||
CGContextSetStrokeColorWithColor(context, _xAxis.gridColor.CGColor)
|
||||
CGContextSetLineWidth(context, _xAxis.gridLineWidth)
|
||||
if (_xAxis.gridLineDashLengths != nil)
|
||||
{
|
||||
CGContextSetLineDash(context, _xAxis.gridLineDashPhase, _xAxis.gridLineDashLengths, _xAxis.gridLineDashLengths.count)
|
||||
}
|
||||
else
|
||||
{
|
||||
CGContextSetLineDash(context, 0.0, nil, 0)
|
||||
}
|
||||
|
||||
let valueToPixelMatrix = transformer.valueToPixelMatrix
|
||||
|
||||
var position = CGPoint(x: 0.0, y: 0.0)
|
||||
|
||||
for (var i = _minX; i < _maxX; i += _xAxis.axisLabelModulus)
|
||||
{
|
||||
position.x = CGFloat(i * step) + CGFloat(i) * barData.groupSpace - 0.5
|
||||
position.y = 0.0
|
||||
position = CGPointApplyAffineTransform(position, valueToPixelMatrix)
|
||||
|
||||
if (viewPortHandler.isInBoundsX(position.x))
|
||||
{
|
||||
_gridLineSegmentsBuffer[0].x = position.x
|
||||
_gridLineSegmentsBuffer[0].y = viewPortHandler.contentTop
|
||||
_gridLineSegmentsBuffer[1].x = position.x
|
||||
_gridLineSegmentsBuffer[1].y = viewPortHandler.contentBottom
|
||||
CGContextStrokeLineSegments(context, _gridLineSegmentsBuffer, 2)
|
||||
}
|
||||
}
|
||||
|
||||
CGContextRestoreGState(context)
|
||||
}
|
||||
}
|
||||
307
Carthage/Checkouts/Charts/Charts/Classes/Renderers/ChartXAxisRendererHorizontalBarChart.swift
vendored
Normal file
307
Carthage/Checkouts/Charts/Charts/Classes/Renderers/ChartXAxisRendererHorizontalBarChart.swift
vendored
Normal file
@@ -0,0 +1,307 @@
|
||||
//
|
||||
// ChartXAxisRendererHorizontalBarChart.swift
|
||||
// Charts
|
||||
//
|
||||
// Created by Daniel Cohen Gindi on 3/3/15.
|
||||
//
|
||||
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
|
||||
// A port of MPAndroidChart for iOS
|
||||
// Licensed under Apache License 2.0
|
||||
//
|
||||
// https://github.com/danielgindi/ios-charts
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import CoreGraphics
|
||||
import UIKit
|
||||
|
||||
public class ChartXAxisRendererHorizontalBarChart: ChartXAxisRendererBarChart
|
||||
{
|
||||
public override init(viewPortHandler: ChartViewPortHandler, xAxis: ChartXAxis, transformer: ChartTransformer!, chart: BarChartView)
|
||||
{
|
||||
super.init(viewPortHandler: viewPortHandler, xAxis: xAxis, transformer: transformer, chart: chart)
|
||||
}
|
||||
|
||||
public override func computeAxis(xValAverageLength xValAverageLength: Double, xValues: [String?])
|
||||
{
|
||||
_xAxis.values = xValues
|
||||
|
||||
let longest = _xAxis.getLongestLabel() as NSString
|
||||
let longestSize = longest.sizeWithAttributes([NSFontAttributeName: _xAxis.labelFont])
|
||||
_xAxis.labelWidth = floor(longestSize.width + _xAxis.xOffset * 3.5)
|
||||
_xAxis.labelHeight = longestSize.height
|
||||
}
|
||||
|
||||
public override func renderAxisLabels(context context: CGContext?)
|
||||
{
|
||||
if (!_xAxis.isEnabled || !_xAxis.isDrawLabelsEnabled || _chart.data === nil)
|
||||
{
|
||||
return
|
||||
}
|
||||
|
||||
let xoffset = _xAxis.xOffset
|
||||
|
||||
if (_xAxis.labelPosition == .Top)
|
||||
{
|
||||
drawLabels(context: context, pos: viewPortHandler.contentRight + xoffset, align: .Left)
|
||||
}
|
||||
else if (_xAxis.labelPosition == .Bottom)
|
||||
{
|
||||
drawLabels(context: context, pos: viewPortHandler.contentLeft - xoffset, align: .Right)
|
||||
}
|
||||
else if (_xAxis.labelPosition == .BottomInside)
|
||||
{
|
||||
drawLabels(context: context, pos: viewPortHandler.contentLeft + xoffset, align: .Left)
|
||||
}
|
||||
else if (_xAxis.labelPosition == .TopInside)
|
||||
{
|
||||
drawLabels(context: context, pos: viewPortHandler.contentRight - xoffset, align: .Right)
|
||||
}
|
||||
else
|
||||
{ // BOTH SIDED
|
||||
drawLabels(context: context, pos: viewPortHandler.contentLeft - xoffset, align: .Right)
|
||||
drawLabels(context: context, pos: viewPortHandler.contentRight + xoffset, align: .Left)
|
||||
}
|
||||
}
|
||||
|
||||
/// draws the x-labels on the specified y-position
|
||||
internal func drawLabels(context context: CGContext?, pos: CGFloat, align: NSTextAlignment)
|
||||
{
|
||||
let labelFont = _xAxis.labelFont
|
||||
let labelTextColor = _xAxis.labelTextColor
|
||||
|
||||
// pre allocate to save performance (dont allocate in loop)
|
||||
var position = CGPoint(x: 0.0, y: 0.0)
|
||||
|
||||
let bd = _chart.data as! BarChartData
|
||||
let step = bd.dataSetCount
|
||||
|
||||
for (var i = _minX, maxX = min(_maxX + 1, _xAxis.values.count); i < maxX; i += _xAxis.axisLabelModulus)
|
||||
{
|
||||
let label = _xAxis.values[i]
|
||||
|
||||
if (label == nil)
|
||||
{
|
||||
continue
|
||||
}
|
||||
|
||||
position.x = 0.0
|
||||
position.y = CGFloat(i * step) + CGFloat(i) * bd.groupSpace + bd.groupSpace / 2.0
|
||||
|
||||
// consider groups (center label for each group)
|
||||
if (step > 1)
|
||||
{
|
||||
position.y += (CGFloat(step) - 1.0) / 2.0
|
||||
}
|
||||
|
||||
transformer.pointValueToPixel(&position)
|
||||
|
||||
if (viewPortHandler.isInBoundsY(position.y))
|
||||
{
|
||||
drawLabel(context: context, label: label!, xIndex: i, x: pos, y: position.y - _xAxis.labelHeight / 2.0, align: align, attributes: [NSFontAttributeName: labelFont, NSForegroundColorAttributeName: labelTextColor])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal func drawLabel(context context: CGContext?, label: String, xIndex: Int, x: CGFloat, y: CGFloat, align: NSTextAlignment, attributes: [String: NSObject])
|
||||
{
|
||||
let formattedLabel = _xAxis.valueFormatter?.stringForXValue(xIndex, original: label, viewPortHandler: viewPortHandler) ?? label
|
||||
ChartUtils.drawText(context: context, text: formattedLabel, point: CGPoint(x: x, y: y), align: align, attributes: attributes)
|
||||
}
|
||||
|
||||
private var _gridLineSegmentsBuffer = [CGPoint](count: 2, repeatedValue: CGPoint())
|
||||
|
||||
public override func renderGridLines(context context: CGContext?)
|
||||
{
|
||||
if (!_xAxis.isEnabled || !_xAxis.isDrawGridLinesEnabled || _chart.data === nil)
|
||||
{
|
||||
return
|
||||
}
|
||||
|
||||
CGContextSaveGState(context)
|
||||
|
||||
CGContextSetStrokeColorWithColor(context, _xAxis.gridColor.CGColor)
|
||||
CGContextSetLineWidth(context, _xAxis.gridLineWidth)
|
||||
if (_xAxis.gridLineDashLengths != nil)
|
||||
{
|
||||
CGContextSetLineDash(context, _xAxis.gridLineDashPhase, _xAxis.gridLineDashLengths, _xAxis.gridLineDashLengths.count)
|
||||
}
|
||||
else
|
||||
{
|
||||
CGContextSetLineDash(context, 0.0, nil, 0)
|
||||
}
|
||||
|
||||
var position = CGPoint(x: 0.0, y: 0.0)
|
||||
|
||||
let bd = _chart.data as! BarChartData
|
||||
|
||||
// take into consideration that multiple DataSets increase _deltaX
|
||||
let step = bd.dataSetCount
|
||||
|
||||
for (var i = _minX, maxX = min(_maxX + 1, _xAxis.values.count); i < maxX; i += _xAxis.axisLabelModulus)
|
||||
{
|
||||
position.x = 0.0
|
||||
position.y = CGFloat(i * step) + CGFloat(i) * bd.groupSpace - 0.5
|
||||
|
||||
transformer.pointValueToPixel(&position)
|
||||
|
||||
if (viewPortHandler.isInBoundsY(position.y))
|
||||
{
|
||||
_gridLineSegmentsBuffer[0].x = viewPortHandler.contentLeft
|
||||
_gridLineSegmentsBuffer[0].y = position.y
|
||||
_gridLineSegmentsBuffer[1].x = viewPortHandler.contentRight
|
||||
_gridLineSegmentsBuffer[1].y = position.y
|
||||
CGContextStrokeLineSegments(context, _gridLineSegmentsBuffer, 2)
|
||||
}
|
||||
}
|
||||
|
||||
CGContextRestoreGState(context)
|
||||
}
|
||||
|
||||
private var _axisLineSegmentsBuffer = [CGPoint](count: 2, repeatedValue: CGPoint())
|
||||
|
||||
public override func renderAxisLine(context context: CGContext?)
|
||||
{
|
||||
if (!_xAxis.isEnabled || !_xAxis.isDrawAxisLineEnabled)
|
||||
{
|
||||
return
|
||||
}
|
||||
|
||||
CGContextSaveGState(context)
|
||||
|
||||
CGContextSetStrokeColorWithColor(context, _xAxis.axisLineColor.CGColor)
|
||||
CGContextSetLineWidth(context, _xAxis.axisLineWidth)
|
||||
if (_xAxis.axisLineDashLengths != nil)
|
||||
{
|
||||
CGContextSetLineDash(context, _xAxis.axisLineDashPhase, _xAxis.axisLineDashLengths, _xAxis.axisLineDashLengths.count)
|
||||
}
|
||||
else
|
||||
{
|
||||
CGContextSetLineDash(context, 0.0, nil, 0)
|
||||
}
|
||||
|
||||
if (_xAxis.labelPosition == .Top
|
||||
|| _xAxis.labelPosition == .TopInside
|
||||
|| _xAxis.labelPosition == .BothSided)
|
||||
{
|
||||
_axisLineSegmentsBuffer[0].x = viewPortHandler.contentRight
|
||||
_axisLineSegmentsBuffer[0].y = viewPortHandler.contentTop
|
||||
_axisLineSegmentsBuffer[1].x = viewPortHandler.contentRight
|
||||
_axisLineSegmentsBuffer[1].y = viewPortHandler.contentBottom
|
||||
CGContextStrokeLineSegments(context, _axisLineSegmentsBuffer, 2)
|
||||
}
|
||||
|
||||
if (_xAxis.labelPosition == .Bottom
|
||||
|| _xAxis.labelPosition == .BottomInside
|
||||
|| _xAxis.labelPosition == .BothSided)
|
||||
{
|
||||
_axisLineSegmentsBuffer[0].x = viewPortHandler.contentLeft
|
||||
_axisLineSegmentsBuffer[0].y = viewPortHandler.contentTop
|
||||
_axisLineSegmentsBuffer[1].x = viewPortHandler.contentLeft
|
||||
_axisLineSegmentsBuffer[1].y = viewPortHandler.contentBottom
|
||||
CGContextStrokeLineSegments(context, _axisLineSegmentsBuffer, 2)
|
||||
}
|
||||
|
||||
CGContextRestoreGState(context)
|
||||
}
|
||||
|
||||
private var _limitLineSegmentsBuffer = [CGPoint](count: 2, repeatedValue: CGPoint())
|
||||
|
||||
public override func renderLimitLines(context context: CGContext?)
|
||||
{
|
||||
var limitLines = _xAxis.limitLines
|
||||
|
||||
if (limitLines.count == 0)
|
||||
{
|
||||
return
|
||||
}
|
||||
|
||||
CGContextSaveGState(context)
|
||||
|
||||
let trans = transformer.valueToPixelMatrix
|
||||
|
||||
var position = CGPoint(x: 0.0, y: 0.0)
|
||||
|
||||
for (var i = 0; i < limitLines.count; i++)
|
||||
{
|
||||
let l = limitLines[i]
|
||||
|
||||
position.x = 0.0
|
||||
position.y = CGFloat(l.limit)
|
||||
position = CGPointApplyAffineTransform(position, trans)
|
||||
|
||||
_limitLineSegmentsBuffer[0].x = viewPortHandler.contentLeft
|
||||
_limitLineSegmentsBuffer[0].y = position.y
|
||||
_limitLineSegmentsBuffer[1].x = viewPortHandler.contentRight
|
||||
_limitLineSegmentsBuffer[1].y = position.y
|
||||
|
||||
CGContextSetStrokeColorWithColor(context, l.lineColor.CGColor)
|
||||
CGContextSetLineWidth(context, l.lineWidth)
|
||||
if (l.lineDashLengths != nil)
|
||||
{
|
||||
CGContextSetLineDash(context, l.lineDashPhase, l.lineDashLengths!, l.lineDashLengths!.count)
|
||||
}
|
||||
else
|
||||
{
|
||||
CGContextSetLineDash(context, 0.0, nil, 0)
|
||||
}
|
||||
|
||||
CGContextStrokeLineSegments(context, _limitLineSegmentsBuffer, 2)
|
||||
|
||||
let label = l.label
|
||||
|
||||
// if drawing the limit-value label is enabled
|
||||
if (label.characters.count > 0)
|
||||
{
|
||||
let labelLineHeight = l.valueFont.lineHeight
|
||||
|
||||
let add = CGFloat(4.0)
|
||||
let xOffset: CGFloat = add
|
||||
let yOffset: CGFloat = l.lineWidth + labelLineHeight
|
||||
|
||||
if (l.labelPosition == .RightTop)
|
||||
{
|
||||
ChartUtils.drawText(context: context,
|
||||
text: label,
|
||||
point: CGPoint(
|
||||
x: viewPortHandler.contentRight - xOffset,
|
||||
y: position.y - yOffset),
|
||||
align: .Right,
|
||||
attributes: [NSFontAttributeName: l.valueFont, NSForegroundColorAttributeName: l.valueTextColor])
|
||||
}
|
||||
else if (l.labelPosition == .RightBottom)
|
||||
{
|
||||
ChartUtils.drawText(context: context,
|
||||
text: label,
|
||||
point: CGPoint(
|
||||
x: viewPortHandler.contentRight - xOffset,
|
||||
y: position.y + yOffset - labelLineHeight),
|
||||
align: .Right,
|
||||
attributes: [NSFontAttributeName: l.valueFont, NSForegroundColorAttributeName: l.valueTextColor])
|
||||
}
|
||||
else if (l.labelPosition == .LeftTop)
|
||||
{
|
||||
ChartUtils.drawText(context: context,
|
||||
text: label,
|
||||
point: CGPoint(
|
||||
x: viewPortHandler.contentLeft + xOffset,
|
||||
y: position.y - yOffset),
|
||||
align: .Left,
|
||||
attributes: [NSFontAttributeName: l.valueFont, NSForegroundColorAttributeName: l.valueTextColor])
|
||||
}
|
||||
else
|
||||
{
|
||||
ChartUtils.drawText(context: context,
|
||||
text: label,
|
||||
point: CGPoint(
|
||||
x: viewPortHandler.contentLeft + xOffset,
|
||||
y: position.y + yOffset - labelLineHeight),
|
||||
align: .Left,
|
||||
attributes: [NSFontAttributeName: l.valueFont, NSForegroundColorAttributeName: l.valueTextColor])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CGContextRestoreGState(context)
|
||||
}
|
||||
}
|
||||
74
Carthage/Checkouts/Charts/Charts/Classes/Renderers/ChartXAxisRendererRadarChart.swift
vendored
Normal file
74
Carthage/Checkouts/Charts/Charts/Classes/Renderers/ChartXAxisRendererRadarChart.swift
vendored
Normal file
@@ -0,0 +1,74 @@
|
||||
//
|
||||
// ChartXAxisRendererRadarChart.swift
|
||||
// Charts
|
||||
//
|
||||
// Created by Daniel Cohen Gindi on 3/3/15.
|
||||
//
|
||||
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
|
||||
// A port of MPAndroidChart for iOS
|
||||
// Licensed under Apache License 2.0
|
||||
//
|
||||
// https://github.com/danielgindi/ios-charts
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import CoreGraphics
|
||||
import UIKit
|
||||
|
||||
public class ChartXAxisRendererRadarChart: ChartXAxisRenderer
|
||||
{
|
||||
private weak var _chart: RadarChartView!
|
||||
|
||||
public init(viewPortHandler: ChartViewPortHandler, xAxis: ChartXAxis, chart: RadarChartView)
|
||||
{
|
||||
super.init(viewPortHandler: viewPortHandler, xAxis: xAxis, transformer: nil)
|
||||
|
||||
_chart = chart
|
||||
}
|
||||
|
||||
public override func renderAxisLabels(context context: CGContext?)
|
||||
{
|
||||
if (!_xAxis.isEnabled || !_xAxis.isDrawLabelsEnabled)
|
||||
{
|
||||
return
|
||||
}
|
||||
|
||||
let labelFont = _xAxis.labelFont
|
||||
let labelTextColor = _xAxis.labelTextColor
|
||||
|
||||
let sliceangle = _chart.sliceAngle
|
||||
|
||||
// calculate the factor that is needed for transforming the value to pixels
|
||||
let factor = _chart.factor
|
||||
|
||||
let center = _chart.centerOffsets
|
||||
|
||||
let modulus = _xAxis.axisLabelModulus
|
||||
for var i = 0, count = _xAxis.values.count; i < count; i += modulus
|
||||
{
|
||||
let label = _xAxis.values[i]
|
||||
|
||||
if (label == nil)
|
||||
{
|
||||
continue
|
||||
}
|
||||
|
||||
let angle = (sliceangle * CGFloat(i) + _chart.rotationAngle) % 360.0
|
||||
|
||||
let p = ChartUtils.getPosition(center: center, dist: CGFloat(_chart.yRange) * factor + _xAxis.labelWidth / 2.0, angle: angle)
|
||||
|
||||
drawLabel(context: context, label: label!, xIndex: i, x: p.x, y: p.y - _xAxis.labelHeight / 2.0, align: .Center, attributes: [NSFontAttributeName: labelFont, NSForegroundColorAttributeName: labelTextColor])
|
||||
}
|
||||
}
|
||||
|
||||
internal func drawLabel(context context: CGContext?, label: String, xIndex: Int, x: CGFloat, y: CGFloat, align: NSTextAlignment, attributes: [String: NSObject])
|
||||
{
|
||||
let formattedLabel = _xAxis.valueFormatter?.stringForXValue(xIndex, original: label, viewPortHandler: viewPortHandler) ?? label
|
||||
ChartUtils.drawText(context: context, text: formattedLabel, point: CGPoint(x: x, y: y), align: align, attributes: attributes)
|
||||
}
|
||||
|
||||
public override func renderLimitLines(context context: CGContext?)
|
||||
{
|
||||
/// XAxis LimitLines on RadarChart not yet supported.
|
||||
}
|
||||
}
|
||||
409
Carthage/Checkouts/Charts/Charts/Classes/Renderers/ChartYAxisRenderer.swift
vendored
Normal file
409
Carthage/Checkouts/Charts/Charts/Classes/Renderers/ChartYAxisRenderer.swift
vendored
Normal file
@@ -0,0 +1,409 @@
|
||||
//
|
||||
// ChartYAxisRenderer.swift
|
||||
// Charts
|
||||
//
|
||||
// Created by Daniel Cohen Gindi on 3/3/15.
|
||||
//
|
||||
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
|
||||
// A port of MPAndroidChart for iOS
|
||||
// Licensed under Apache License 2.0
|
||||
//
|
||||
// https://github.com/danielgindi/ios-charts
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import CoreGraphics
|
||||
import UIKit
|
||||
|
||||
public class ChartYAxisRenderer: ChartAxisRendererBase
|
||||
{
|
||||
internal var _yAxis: ChartYAxis!
|
||||
|
||||
public init(viewPortHandler: ChartViewPortHandler, yAxis: ChartYAxis, transformer: ChartTransformer!)
|
||||
{
|
||||
super.init(viewPortHandler: viewPortHandler, transformer: transformer)
|
||||
|
||||
_yAxis = yAxis
|
||||
}
|
||||
|
||||
/// Computes the axis values.
|
||||
public func computeAxis(var yMin yMin: Double, var yMax: Double)
|
||||
{
|
||||
// calculate the starting and entry point of the y-labels (depending on
|
||||
// zoom / contentrect bounds)
|
||||
if (viewPortHandler.contentWidth > 10.0 && !viewPortHandler.isFullyZoomedOutY)
|
||||
{
|
||||
let p1 = transformer.getValueByTouchPoint(CGPoint(x: viewPortHandler.contentLeft, y: viewPortHandler.contentTop))
|
||||
let p2 = transformer.getValueByTouchPoint(CGPoint(x: viewPortHandler.contentLeft, y: viewPortHandler.contentBottom))
|
||||
|
||||
if (!_yAxis.isInverted)
|
||||
{
|
||||
yMin = Double(p2.y)
|
||||
yMax = Double(p1.y)
|
||||
}
|
||||
else
|
||||
{
|
||||
yMin = Double(p1.y)
|
||||
yMax = Double(p2.y)
|
||||
}
|
||||
}
|
||||
|
||||
computeAxisValues(min: yMin, max: yMax)
|
||||
}
|
||||
|
||||
/// Sets up the y-axis labels. Computes the desired number of labels between
|
||||
/// the two given extremes. Unlike the papareXLabels() method, this method
|
||||
/// needs to be called upon every refresh of the view.
|
||||
internal func computeAxisValues(min min: Double, max: Double)
|
||||
{
|
||||
let yMin = min
|
||||
let yMax = max
|
||||
|
||||
let labelCount = _yAxis.labelCount
|
||||
let range = abs(yMax - yMin)
|
||||
|
||||
if (labelCount == 0 || range <= 0)
|
||||
{
|
||||
_yAxis.entries = [Double]()
|
||||
return
|
||||
}
|
||||
|
||||
let rawInterval = range / Double(labelCount)
|
||||
var interval = ChartUtils.roundToNextSignificant(number: Double(rawInterval))
|
||||
let intervalMagnitude = pow(10.0, round(log10(interval)))
|
||||
let intervalSigDigit = (interval / intervalMagnitude)
|
||||
if (intervalSigDigit > 5)
|
||||
{
|
||||
// Use one order of magnitude higher, to avoid intervals like 0.9 or 90
|
||||
interval = floor(10.0 * intervalMagnitude)
|
||||
}
|
||||
|
||||
// force label count
|
||||
if _yAxis.isForceLabelsEnabled
|
||||
{
|
||||
let step = Double(range) / Double(labelCount - 1)
|
||||
|
||||
if _yAxis.entries.count < labelCount
|
||||
{
|
||||
// Ensure stops contains at least numStops elements.
|
||||
_yAxis.entries.removeAll(keepCapacity: true)
|
||||
}
|
||||
else
|
||||
{
|
||||
_yAxis.entries = [Double]()
|
||||
_yAxis.entries.reserveCapacity(labelCount)
|
||||
}
|
||||
|
||||
var v = yMin
|
||||
|
||||
for (var i = 0; i < labelCount; i++)
|
||||
{
|
||||
_yAxis.entries.append(v)
|
||||
v += step
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
// no forced count
|
||||
|
||||
// if the labels should only show min and max
|
||||
if (_yAxis.isShowOnlyMinMaxEnabled)
|
||||
{
|
||||
_yAxis.entries = [yMin, yMax]
|
||||
}
|
||||
else
|
||||
{
|
||||
let first = ceil(Double(yMin) / interval) * interval
|
||||
let last = ChartUtils.nextUp(floor(Double(yMax) / interval) * interval)
|
||||
|
||||
var f: Double
|
||||
var i: Int
|
||||
var n = 0
|
||||
for (f = first; f <= last; f += interval)
|
||||
{
|
||||
++n
|
||||
}
|
||||
|
||||
if (_yAxis.entries.count < n)
|
||||
{
|
||||
// Ensure stops contains at least numStops elements.
|
||||
_yAxis.entries = [Double](count: n, repeatedValue: 0.0)
|
||||
}
|
||||
else if (_yAxis.entries.count > n)
|
||||
{
|
||||
_yAxis.entries.removeRange(n..<_yAxis.entries.count)
|
||||
}
|
||||
|
||||
for (f = first, i = 0; i < n; f += interval, ++i)
|
||||
{
|
||||
_yAxis.entries[i] = Double(f)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// draws the y-axis labels to the screen
|
||||
public override func renderAxisLabels(context context: CGContext?)
|
||||
{
|
||||
if (!_yAxis.isEnabled || !_yAxis.isDrawLabelsEnabled)
|
||||
{
|
||||
return
|
||||
}
|
||||
|
||||
let xoffset = _yAxis.xOffset
|
||||
let yoffset = _yAxis.labelFont.lineHeight / 2.5 + _yAxis.yOffset
|
||||
|
||||
let dependency = _yAxis.axisDependency
|
||||
let labelPosition = _yAxis.labelPosition
|
||||
|
||||
var xPos = CGFloat(0.0)
|
||||
|
||||
var textAlign: NSTextAlignment
|
||||
|
||||
if (dependency == .Left)
|
||||
{
|
||||
if (labelPosition == .OutsideChart)
|
||||
{
|
||||
textAlign = .Right
|
||||
xPos = viewPortHandler.offsetLeft - xoffset
|
||||
}
|
||||
else
|
||||
{
|
||||
textAlign = .Left
|
||||
xPos = viewPortHandler.offsetLeft + xoffset
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
if (labelPosition == .OutsideChart)
|
||||
{
|
||||
textAlign = .Left
|
||||
xPos = viewPortHandler.contentRight + xoffset
|
||||
}
|
||||
else
|
||||
{
|
||||
textAlign = .Right
|
||||
xPos = viewPortHandler.contentRight - xoffset
|
||||
}
|
||||
}
|
||||
|
||||
drawYLabels(context: context, fixedPosition: xPos, offset: yoffset - _yAxis.labelFont.lineHeight, textAlign: textAlign)
|
||||
}
|
||||
|
||||
private var _axisLineSegmentsBuffer = [CGPoint](count: 2, repeatedValue: CGPoint())
|
||||
|
||||
public override func renderAxisLine(context context: CGContext?)
|
||||
{
|
||||
if (!_yAxis.isEnabled || !_yAxis.drawAxisLineEnabled)
|
||||
{
|
||||
return
|
||||
}
|
||||
|
||||
CGContextSaveGState(context)
|
||||
|
||||
CGContextSetStrokeColorWithColor(context, _yAxis.axisLineColor.CGColor)
|
||||
CGContextSetLineWidth(context, _yAxis.axisLineWidth)
|
||||
if (_yAxis.axisLineDashLengths != nil)
|
||||
{
|
||||
CGContextSetLineDash(context, _yAxis.axisLineDashPhase, _yAxis.axisLineDashLengths, _yAxis.axisLineDashLengths.count)
|
||||
}
|
||||
else
|
||||
{
|
||||
CGContextSetLineDash(context, 0.0, nil, 0)
|
||||
}
|
||||
|
||||
if (_yAxis.axisDependency == .Left)
|
||||
{
|
||||
_axisLineSegmentsBuffer[0].x = viewPortHandler.contentLeft
|
||||
_axisLineSegmentsBuffer[0].y = viewPortHandler.contentTop
|
||||
_axisLineSegmentsBuffer[1].x = viewPortHandler.contentLeft
|
||||
_axisLineSegmentsBuffer[1].y = viewPortHandler.contentBottom
|
||||
CGContextStrokeLineSegments(context, _axisLineSegmentsBuffer, 2)
|
||||
}
|
||||
else
|
||||
{
|
||||
_axisLineSegmentsBuffer[0].x = viewPortHandler.contentRight
|
||||
_axisLineSegmentsBuffer[0].y = viewPortHandler.contentTop
|
||||
_axisLineSegmentsBuffer[1].x = viewPortHandler.contentRight
|
||||
_axisLineSegmentsBuffer[1].y = viewPortHandler.contentBottom
|
||||
CGContextStrokeLineSegments(context, _axisLineSegmentsBuffer, 2)
|
||||
}
|
||||
|
||||
CGContextRestoreGState(context)
|
||||
}
|
||||
|
||||
/// draws the y-labels on the specified x-position
|
||||
internal func drawYLabels(context context: CGContext?, fixedPosition: CGFloat, offset: CGFloat, textAlign: NSTextAlignment)
|
||||
{
|
||||
let labelFont = _yAxis.labelFont
|
||||
let labelTextColor = _yAxis.labelTextColor
|
||||
|
||||
let valueToPixelMatrix = transformer.valueToPixelMatrix
|
||||
|
||||
var pt = CGPoint()
|
||||
|
||||
for (var i = 0; i < _yAxis.entryCount; i++)
|
||||
{
|
||||
let text = _yAxis.getFormattedLabel(i)
|
||||
|
||||
if (!_yAxis.isDrawTopYLabelEntryEnabled && i >= _yAxis.entryCount - 1)
|
||||
{
|
||||
break
|
||||
}
|
||||
|
||||
pt.x = 0
|
||||
pt.y = CGFloat(_yAxis.entries[i])
|
||||
pt = CGPointApplyAffineTransform(pt, valueToPixelMatrix)
|
||||
|
||||
pt.x = fixedPosition
|
||||
pt.y += offset
|
||||
|
||||
ChartUtils.drawText(context: context, text: text, point: pt, align: textAlign, attributes: [NSFontAttributeName: labelFont, NSForegroundColorAttributeName: labelTextColor])
|
||||
}
|
||||
}
|
||||
|
||||
private var _gridLineBuffer = [CGPoint](count: 2, repeatedValue: CGPoint())
|
||||
|
||||
public override func renderGridLines(context context: CGContext?)
|
||||
{
|
||||
if (!_yAxis.isDrawGridLinesEnabled || !_yAxis.isEnabled)
|
||||
{
|
||||
return
|
||||
}
|
||||
|
||||
CGContextSaveGState(context)
|
||||
|
||||
CGContextSetStrokeColorWithColor(context, _yAxis.gridColor.CGColor)
|
||||
CGContextSetLineWidth(context, _yAxis.gridLineWidth)
|
||||
if (_yAxis.gridLineDashLengths != nil)
|
||||
{
|
||||
CGContextSetLineDash(context, _yAxis.gridLineDashPhase, _yAxis.gridLineDashLengths, _yAxis.gridLineDashLengths.count)
|
||||
}
|
||||
else
|
||||
{
|
||||
CGContextSetLineDash(context, 0.0, nil, 0)
|
||||
}
|
||||
|
||||
let valueToPixelMatrix = transformer.valueToPixelMatrix
|
||||
|
||||
var position = CGPoint(x: 0.0, y: 0.0)
|
||||
|
||||
// draw the horizontal grid
|
||||
for (var i = 0, count = _yAxis.entryCount; i < count; i++)
|
||||
{
|
||||
position.x = 0.0
|
||||
position.y = CGFloat(_yAxis.entries[i])
|
||||
position = CGPointApplyAffineTransform(position, valueToPixelMatrix)
|
||||
|
||||
_gridLineBuffer[0].x = viewPortHandler.contentLeft
|
||||
_gridLineBuffer[0].y = position.y
|
||||
_gridLineBuffer[1].x = viewPortHandler.contentRight
|
||||
_gridLineBuffer[1].y = position.y
|
||||
CGContextStrokeLineSegments(context, _gridLineBuffer, 2)
|
||||
}
|
||||
|
||||
CGContextRestoreGState(context)
|
||||
}
|
||||
|
||||
private var _limitLineSegmentsBuffer = [CGPoint](count: 2, repeatedValue: CGPoint())
|
||||
|
||||
public override func renderLimitLines(context context: CGContext?)
|
||||
{
|
||||
var limitLines = _yAxis.limitLines
|
||||
|
||||
if (limitLines.count == 0)
|
||||
{
|
||||
return
|
||||
}
|
||||
|
||||
CGContextSaveGState(context)
|
||||
|
||||
let trans = transformer.valueToPixelMatrix
|
||||
|
||||
var position = CGPoint(x: 0.0, y: 0.0)
|
||||
|
||||
for (var i = 0; i < limitLines.count; i++)
|
||||
{
|
||||
let l = limitLines[i]
|
||||
|
||||
position.x = 0.0
|
||||
position.y = CGFloat(l.limit)
|
||||
position = CGPointApplyAffineTransform(position, trans)
|
||||
|
||||
_limitLineSegmentsBuffer[0].x = viewPortHandler.contentLeft
|
||||
_limitLineSegmentsBuffer[0].y = position.y
|
||||
_limitLineSegmentsBuffer[1].x = viewPortHandler.contentRight
|
||||
_limitLineSegmentsBuffer[1].y = position.y
|
||||
|
||||
CGContextSetStrokeColorWithColor(context, l.lineColor.CGColor)
|
||||
CGContextSetLineWidth(context, l.lineWidth)
|
||||
if (l.lineDashLengths != nil)
|
||||
{
|
||||
CGContextSetLineDash(context, l.lineDashPhase, l.lineDashLengths!, l.lineDashLengths!.count)
|
||||
}
|
||||
else
|
||||
{
|
||||
CGContextSetLineDash(context, 0.0, nil, 0)
|
||||
}
|
||||
|
||||
CGContextStrokeLineSegments(context, _limitLineSegmentsBuffer, 2)
|
||||
|
||||
let label = l.label
|
||||
|
||||
// if drawing the limit-value label is enabled
|
||||
if (label.characters.count > 0)
|
||||
{
|
||||
let labelLineHeight = l.valueFont.lineHeight
|
||||
|
||||
let add = CGFloat(4.0)
|
||||
let xOffset: CGFloat = add
|
||||
let yOffset: CGFloat = l.lineWidth + labelLineHeight
|
||||
|
||||
if (l.labelPosition == .RightTop)
|
||||
{
|
||||
ChartUtils.drawText(context: context,
|
||||
text: label,
|
||||
point: CGPoint(
|
||||
x: viewPortHandler.contentRight - xOffset,
|
||||
y: position.y - yOffset),
|
||||
align: .Right,
|
||||
attributes: [NSFontAttributeName: l.valueFont, NSForegroundColorAttributeName: l.valueTextColor])
|
||||
}
|
||||
else if (l.labelPosition == .RightBottom)
|
||||
{
|
||||
ChartUtils.drawText(context: context,
|
||||
text: label,
|
||||
point: CGPoint(
|
||||
x: viewPortHandler.contentRight - xOffset,
|
||||
y: position.y + yOffset - labelLineHeight),
|
||||
align: .Right,
|
||||
attributes: [NSFontAttributeName: l.valueFont, NSForegroundColorAttributeName: l.valueTextColor])
|
||||
}
|
||||
else if (l.labelPosition == .LeftTop)
|
||||
{
|
||||
ChartUtils.drawText(context: context,
|
||||
text: label,
|
||||
point: CGPoint(
|
||||
x: viewPortHandler.contentLeft + xOffset,
|
||||
y: position.y - yOffset),
|
||||
align: .Left,
|
||||
attributes: [NSFontAttributeName: l.valueFont, NSForegroundColorAttributeName: l.valueTextColor])
|
||||
}
|
||||
else
|
||||
{
|
||||
ChartUtils.drawText(context: context,
|
||||
text: label,
|
||||
point: CGPoint(
|
||||
x: viewPortHandler.contentLeft + xOffset,
|
||||
y: position.y + yOffset - labelLineHeight),
|
||||
align: .Left,
|
||||
attributes: [NSFontAttributeName: l.valueFont, NSForegroundColorAttributeName: l.valueTextColor])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CGContextRestoreGState(context)
|
||||
}
|
||||
}
|
||||
304
Carthage/Checkouts/Charts/Charts/Classes/Renderers/ChartYAxisRendererHorizontalBarChart.swift
vendored
Normal file
304
Carthage/Checkouts/Charts/Charts/Classes/Renderers/ChartYAxisRendererHorizontalBarChart.swift
vendored
Normal file
@@ -0,0 +1,304 @@
|
||||
//
|
||||
// ChartYAxisRendererHorizontalBarChart.swift
|
||||
// Charts
|
||||
//
|
||||
// Created by Daniel Cohen Gindi on 3/3/15.
|
||||
//
|
||||
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
|
||||
// A port of MPAndroidChart for iOS
|
||||
// Licensed under Apache License 2.0
|
||||
//
|
||||
// https://github.com/danielgindi/ios-charts
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import CoreGraphics
|
||||
import UIKit
|
||||
|
||||
public class ChartYAxisRendererHorizontalBarChart: ChartYAxisRenderer
|
||||
{
|
||||
public override init(viewPortHandler: ChartViewPortHandler, yAxis: ChartYAxis, transformer: ChartTransformer!)
|
||||
{
|
||||
super.init(viewPortHandler: viewPortHandler, yAxis: yAxis, transformer: transformer)
|
||||
}
|
||||
|
||||
/// Computes the axis values.
|
||||
public override func computeAxis(var yMin yMin: Double, var yMax: Double)
|
||||
{
|
||||
// calculate the starting and entry point of the y-labels (depending on zoom / contentrect bounds)
|
||||
if (viewPortHandler.contentHeight > 10.0 && !viewPortHandler.isFullyZoomedOutX)
|
||||
{
|
||||
let p1 = transformer.getValueByTouchPoint(CGPoint(x: viewPortHandler.contentLeft, y: viewPortHandler.contentTop))
|
||||
let p2 = transformer.getValueByTouchPoint(CGPoint(x: viewPortHandler.contentRight, y: viewPortHandler.contentTop))
|
||||
|
||||
if (!_yAxis.isInverted)
|
||||
{
|
||||
yMin = Double(p1.x)
|
||||
yMax = Double(p2.x)
|
||||
}
|
||||
else
|
||||
{
|
||||
yMin = Double(p2.x)
|
||||
yMax = Double(p1.x)
|
||||
}
|
||||
}
|
||||
|
||||
computeAxisValues(min: yMin, max: yMax)
|
||||
}
|
||||
|
||||
/// draws the y-axis labels to the screen
|
||||
public override func renderAxisLabels(context context: CGContext?)
|
||||
{
|
||||
if (!_yAxis.isEnabled || !_yAxis.isDrawLabelsEnabled)
|
||||
{
|
||||
return
|
||||
}
|
||||
|
||||
var positions = [CGPoint]()
|
||||
positions.reserveCapacity(_yAxis.entries.count)
|
||||
|
||||
for (var i = 0; i < _yAxis.entries.count; i++)
|
||||
{
|
||||
positions.append(CGPoint(x: CGFloat(_yAxis.entries[i]), y: 0.0))
|
||||
}
|
||||
|
||||
transformer.pointValuesToPixel(&positions)
|
||||
|
||||
let lineHeight = _yAxis.labelFont.lineHeight
|
||||
let baseYOffset: CGFloat = 2.5
|
||||
|
||||
let dependency = _yAxis.axisDependency
|
||||
let labelPosition = _yAxis.labelPosition
|
||||
|
||||
var yPos: CGFloat = 0.0
|
||||
|
||||
if (dependency == .Left)
|
||||
{
|
||||
if (labelPosition == .OutsideChart)
|
||||
{
|
||||
yPos = viewPortHandler.contentTop - baseYOffset
|
||||
}
|
||||
else
|
||||
{
|
||||
yPos = viewPortHandler.contentTop - baseYOffset
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (labelPosition == .OutsideChart)
|
||||
{
|
||||
yPos = viewPortHandler.contentBottom + lineHeight + baseYOffset
|
||||
}
|
||||
else
|
||||
{
|
||||
yPos = viewPortHandler.contentBottom + lineHeight + baseYOffset
|
||||
}
|
||||
}
|
||||
|
||||
// For compatibility with Android code, we keep above calculation the same,
|
||||
// And here we pull the line back up
|
||||
yPos -= lineHeight
|
||||
|
||||
drawYLabels(context: context, fixedPosition: yPos, positions: positions, offset: _yAxis.yOffset)
|
||||
}
|
||||
|
||||
private var _axisLineSegmentsBuffer = [CGPoint](count: 2, repeatedValue: CGPoint())
|
||||
|
||||
public override func renderAxisLine(context context: CGContext?)
|
||||
{
|
||||
if (!_yAxis.isEnabled || !_yAxis.drawAxisLineEnabled)
|
||||
{
|
||||
return
|
||||
}
|
||||
|
||||
CGContextSaveGState(context)
|
||||
|
||||
CGContextSetStrokeColorWithColor(context, _yAxis.axisLineColor.CGColor)
|
||||
CGContextSetLineWidth(context, _yAxis.axisLineWidth)
|
||||
if (_yAxis.axisLineDashLengths != nil)
|
||||
{
|
||||
CGContextSetLineDash(context, _yAxis.axisLineDashPhase, _yAxis.axisLineDashLengths, _yAxis.axisLineDashLengths.count)
|
||||
}
|
||||
else
|
||||
{
|
||||
CGContextSetLineDash(context, 0.0, nil, 0)
|
||||
}
|
||||
|
||||
if (_yAxis.axisDependency == .Left)
|
||||
{
|
||||
_axisLineSegmentsBuffer[0].x = viewPortHandler.contentLeft
|
||||
_axisLineSegmentsBuffer[0].y = viewPortHandler.contentTop
|
||||
_axisLineSegmentsBuffer[1].x = viewPortHandler.contentRight
|
||||
_axisLineSegmentsBuffer[1].y = viewPortHandler.contentTop
|
||||
CGContextStrokeLineSegments(context, _axisLineSegmentsBuffer, 2)
|
||||
}
|
||||
else
|
||||
{
|
||||
_axisLineSegmentsBuffer[0].x = viewPortHandler.contentLeft
|
||||
_axisLineSegmentsBuffer[0].y = viewPortHandler.contentBottom
|
||||
_axisLineSegmentsBuffer[1].x = viewPortHandler.contentRight
|
||||
_axisLineSegmentsBuffer[1].y = viewPortHandler.contentBottom
|
||||
CGContextStrokeLineSegments(context, _axisLineSegmentsBuffer, 2)
|
||||
}
|
||||
|
||||
CGContextRestoreGState(context)
|
||||
}
|
||||
|
||||
/// draws the y-labels on the specified x-position
|
||||
internal func drawYLabels(context context: CGContext?, fixedPosition: CGFloat, positions: [CGPoint], offset: CGFloat)
|
||||
{
|
||||
let labelFont = _yAxis.labelFont
|
||||
let labelTextColor = _yAxis.labelTextColor
|
||||
|
||||
for (var i = 0; i < _yAxis.entryCount; i++)
|
||||
{
|
||||
let text = _yAxis.getFormattedLabel(i)
|
||||
|
||||
if (!_yAxis.isDrawTopYLabelEntryEnabled && i >= _yAxis.entryCount - 1)
|
||||
{
|
||||
return
|
||||
}
|
||||
|
||||
ChartUtils.drawText(context: context, text: text, point: CGPoint(x: positions[i].x, y: fixedPosition - offset), align: .Center, attributes: [NSFontAttributeName: labelFont, NSForegroundColorAttributeName: labelTextColor])
|
||||
}
|
||||
}
|
||||
|
||||
public override func renderGridLines(context context: CGContext?)
|
||||
{
|
||||
if (!_yAxis.isEnabled || !_yAxis.isDrawGridLinesEnabled)
|
||||
{
|
||||
return
|
||||
}
|
||||
|
||||
CGContextSaveGState(context)
|
||||
|
||||
// pre alloc
|
||||
var position = CGPoint()
|
||||
|
||||
CGContextSetStrokeColorWithColor(context, _yAxis.gridColor.CGColor)
|
||||
CGContextSetLineWidth(context, _yAxis.gridLineWidth)
|
||||
if (_yAxis.gridLineDashLengths != nil)
|
||||
{
|
||||
CGContextSetLineDash(context, _yAxis.gridLineDashPhase, _yAxis.gridLineDashLengths, _yAxis.gridLineDashLengths.count)
|
||||
}
|
||||
else
|
||||
{
|
||||
CGContextSetLineDash(context, 0.0, nil, 0)
|
||||
}
|
||||
|
||||
// draw the horizontal grid
|
||||
for (var i = 0; i < _yAxis.entryCount; i++)
|
||||
{
|
||||
position.x = CGFloat(_yAxis.entries[i])
|
||||
position.y = 0.0
|
||||
transformer.pointValueToPixel(&position)
|
||||
|
||||
CGContextBeginPath(context)
|
||||
CGContextMoveToPoint(context, position.x, viewPortHandler.contentTop)
|
||||
CGContextAddLineToPoint(context, position.x, viewPortHandler.contentBottom)
|
||||
CGContextStrokePath(context)
|
||||
}
|
||||
|
||||
CGContextRestoreGState(context)
|
||||
}
|
||||
|
||||
private var _limitLineSegmentsBuffer = [CGPoint](count: 2, repeatedValue: CGPoint())
|
||||
|
||||
public override func renderLimitLines(context context: CGContext?)
|
||||
{
|
||||
var limitLines = _yAxis.limitLines
|
||||
|
||||
if (limitLines.count <= 0)
|
||||
{
|
||||
return
|
||||
}
|
||||
|
||||
CGContextSaveGState(context)
|
||||
|
||||
let trans = transformer.valueToPixelMatrix
|
||||
|
||||
var position = CGPoint(x: 0.0, y: 0.0)
|
||||
|
||||
for (var i = 0; i < limitLines.count; i++)
|
||||
{
|
||||
let l = limitLines[i]
|
||||
|
||||
position.x = CGFloat(l.limit)
|
||||
position.y = 0.0
|
||||
position = CGPointApplyAffineTransform(position, trans)
|
||||
|
||||
_limitLineSegmentsBuffer[0].x = position.x
|
||||
_limitLineSegmentsBuffer[0].y = viewPortHandler.contentTop
|
||||
_limitLineSegmentsBuffer[1].x = position.x
|
||||
_limitLineSegmentsBuffer[1].y = viewPortHandler.contentBottom
|
||||
|
||||
CGContextSetStrokeColorWithColor(context, l.lineColor.CGColor)
|
||||
CGContextSetLineWidth(context, l.lineWidth)
|
||||
if (l.lineDashLengths != nil)
|
||||
{
|
||||
CGContextSetLineDash(context, l.lineDashPhase, l.lineDashLengths!, l.lineDashLengths!.count)
|
||||
}
|
||||
else
|
||||
{
|
||||
CGContextSetLineDash(context, 0.0, nil, 0)
|
||||
}
|
||||
|
||||
CGContextStrokeLineSegments(context, _limitLineSegmentsBuffer, 2)
|
||||
|
||||
let label = l.label
|
||||
|
||||
// if drawing the limit-value label is enabled
|
||||
if (label.characters.count > 0)
|
||||
{
|
||||
let labelLineHeight = l.valueFont.lineHeight
|
||||
|
||||
let add = CGFloat(4.0)
|
||||
let xOffset: CGFloat = l.lineWidth
|
||||
let yOffset: CGFloat = add / 2.0
|
||||
|
||||
if (l.labelPosition == .RightTop)
|
||||
{
|
||||
ChartUtils.drawText(context: context,
|
||||
text: label,
|
||||
point: CGPoint(
|
||||
x: position.x + xOffset,
|
||||
y: viewPortHandler.contentTop + yOffset),
|
||||
align: .Left,
|
||||
attributes: [NSFontAttributeName: l.valueFont, NSForegroundColorAttributeName: l.valueTextColor])
|
||||
}
|
||||
else if (l.labelPosition == .RightBottom)
|
||||
{
|
||||
ChartUtils.drawText(context: context,
|
||||
text: label,
|
||||
point: CGPoint(
|
||||
x: position.x + xOffset,
|
||||
y: viewPortHandler.contentBottom - labelLineHeight - yOffset),
|
||||
align: .Left,
|
||||
attributes: [NSFontAttributeName: l.valueFont, NSForegroundColorAttributeName: l.valueTextColor])
|
||||
}
|
||||
else if (l.labelPosition == .LeftTop)
|
||||
{
|
||||
ChartUtils.drawText(context: context,
|
||||
text: label,
|
||||
point: CGPoint(
|
||||
x: position.x - xOffset,
|
||||
y: viewPortHandler.contentTop + yOffset),
|
||||
align: .Right,
|
||||
attributes: [NSFontAttributeName: l.valueFont, NSForegroundColorAttributeName: l.valueTextColor])
|
||||
}
|
||||
else
|
||||
{
|
||||
ChartUtils.drawText(context: context,
|
||||
text: label,
|
||||
point: CGPoint(
|
||||
x: position.x - xOffset,
|
||||
y: viewPortHandler.contentBottom - labelLineHeight - yOffset),
|
||||
align: .Right,
|
||||
attributes: [NSFontAttributeName: l.valueFont, NSForegroundColorAttributeName: l.valueTextColor])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CGContextRestoreGState(context)
|
||||
}
|
||||
}
|
||||
244
Carthage/Checkouts/Charts/Charts/Classes/Renderers/ChartYAxisRendererRadarChart.swift
vendored
Normal file
244
Carthage/Checkouts/Charts/Charts/Classes/Renderers/ChartYAxisRendererRadarChart.swift
vendored
Normal file
@@ -0,0 +1,244 @@
|
||||
//
|
||||
// ChartYAxisRendererRadarChart.swift
|
||||
// Charts
|
||||
//
|
||||
// Created by Daniel Cohen Gindi on 3/3/15.
|
||||
//
|
||||
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
|
||||
// A port of MPAndroidChart for iOS
|
||||
// Licensed under Apache License 2.0
|
||||
//
|
||||
// https://github.com/danielgindi/ios-charts
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import CoreGraphics
|
||||
import UIKit
|
||||
|
||||
public class ChartYAxisRendererRadarChart: ChartYAxisRenderer
|
||||
{
|
||||
private weak var _chart: RadarChartView!
|
||||
|
||||
public init(viewPortHandler: ChartViewPortHandler, yAxis: ChartYAxis, chart: RadarChartView)
|
||||
{
|
||||
super.init(viewPortHandler: viewPortHandler, yAxis: yAxis, transformer: nil)
|
||||
|
||||
_chart = chart
|
||||
}
|
||||
|
||||
public override func computeAxis(yMin yMin: Double, yMax: Double)
|
||||
{
|
||||
computeAxisValues(min: yMin, max: yMax)
|
||||
}
|
||||
|
||||
internal override func computeAxisValues(min yMin: Double, max yMax: Double)
|
||||
{
|
||||
let labelCount = _yAxis.labelCount
|
||||
let range = abs(yMax - yMin)
|
||||
|
||||
if (labelCount == 0 || range <= 0)
|
||||
{
|
||||
_yAxis.entries = [Double]()
|
||||
return
|
||||
}
|
||||
|
||||
let rawInterval = range / Double(labelCount)
|
||||
var interval = ChartUtils.roundToNextSignificant(number: Double(rawInterval))
|
||||
let intervalMagnitude = pow(10.0, round(log10(interval)))
|
||||
let intervalSigDigit = Int(interval / intervalMagnitude)
|
||||
|
||||
if (intervalSigDigit > 5)
|
||||
{
|
||||
// Use one order of magnitude higher, to avoid intervals like 0.9 or
|
||||
// 90
|
||||
interval = floor(10 * intervalMagnitude)
|
||||
}
|
||||
|
||||
// force label count
|
||||
if _yAxis.isForceLabelsEnabled
|
||||
{
|
||||
let step = Double(range) / Double(labelCount - 1)
|
||||
|
||||
if _yAxis.entries.count < labelCount
|
||||
{
|
||||
// Ensure stops contains at least numStops elements.
|
||||
_yAxis.entries.removeAll(keepCapacity: true)
|
||||
}
|
||||
else
|
||||
{
|
||||
_yAxis.entries = [Double]()
|
||||
_yAxis.entries.reserveCapacity(labelCount)
|
||||
}
|
||||
|
||||
var v = yMin
|
||||
|
||||
for (var i = 0; i < labelCount; i++)
|
||||
{
|
||||
_yAxis.entries.append(v)
|
||||
v += step
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
// no forced count
|
||||
|
||||
// clean old values
|
||||
if (_yAxis.entries.count > 0)
|
||||
{
|
||||
_yAxis.entries.removeAll(keepCapacity: false)
|
||||
}
|
||||
|
||||
// if the labels should only show min and max
|
||||
if (_yAxis.isShowOnlyMinMaxEnabled)
|
||||
{
|
||||
_yAxis.entries = [Double]()
|
||||
_yAxis.entries.append(yMin)
|
||||
_yAxis.entries.append(yMax)
|
||||
}
|
||||
else
|
||||
{
|
||||
let rawCount = Double(yMin) / interval
|
||||
var first = rawCount < 0.0 ? floor(rawCount) * interval : ceil(rawCount) * interval;
|
||||
|
||||
if (first < yMin && _yAxis.isStartAtZeroEnabled)
|
||||
{ // Force the first label to be at the 0 (or smallest negative value)
|
||||
first = yMin
|
||||
}
|
||||
|
||||
if (first == 0.0)
|
||||
{ // Fix for IEEE negative zero case (Where value == -0.0, and 0.0 == -0.0)
|
||||
first = 0.0
|
||||
}
|
||||
|
||||
let last = ChartUtils.nextUp(floor(Double(yMax) / interval) * interval)
|
||||
|
||||
var f: Double
|
||||
var i: Int
|
||||
var n = 0
|
||||
for (f = first; f <= last; f += interval)
|
||||
{
|
||||
++n
|
||||
}
|
||||
|
||||
if (isnan(_yAxis.customAxisMax))
|
||||
{
|
||||
n += 1
|
||||
}
|
||||
|
||||
if (_yAxis.entries.count < n)
|
||||
{
|
||||
// Ensure stops contains at least numStops elements.
|
||||
_yAxis.entries = [Double](count: n, repeatedValue: 0.0)
|
||||
}
|
||||
|
||||
for (f = first, i = 0; i < n; f += interval, ++i)
|
||||
{
|
||||
_yAxis.entries[i] = Double(f)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !_yAxis.isStartAtZeroEnabled && _yAxis.entries[0] < yMin
|
||||
{
|
||||
// If startAtZero is disabled, and the first label is lower that the axis minimum,
|
||||
// Then adjust the axis minimum
|
||||
_yAxis.axisMinimum = _yAxis.entries[0]
|
||||
}
|
||||
_yAxis.axisMaximum = _yAxis.entries[_yAxis.entryCount - 1]
|
||||
_yAxis.axisRange = abs(_yAxis.axisMaximum - _yAxis.axisMinimum)
|
||||
}
|
||||
|
||||
public override func renderAxisLabels(context context: CGContext?)
|
||||
{
|
||||
if (!_yAxis.isEnabled || !_yAxis.isDrawLabelsEnabled)
|
||||
{
|
||||
return
|
||||
}
|
||||
|
||||
let labelFont = _yAxis.labelFont
|
||||
let labelTextColor = _yAxis.labelTextColor
|
||||
|
||||
let center = _chart.centerOffsets
|
||||
let factor = _chart.factor
|
||||
|
||||
let labelCount = _yAxis.entryCount
|
||||
|
||||
let labelLineHeight = _yAxis.labelFont.lineHeight
|
||||
|
||||
for (var j = 0; j < labelCount; j++)
|
||||
{
|
||||
if (j == labelCount - 1 && _yAxis.isDrawTopYLabelEntryEnabled == false)
|
||||
{
|
||||
break
|
||||
}
|
||||
|
||||
let r = CGFloat(_yAxis.entries[j] - _yAxis.axisMinimum) * factor
|
||||
|
||||
let p = ChartUtils.getPosition(center: center, dist: r, angle: _chart.rotationAngle)
|
||||
|
||||
let label = _yAxis.getFormattedLabel(j)
|
||||
|
||||
ChartUtils.drawText(context: context, text: label, point: CGPoint(x: p.x + 10.0, y: p.y - labelLineHeight), align: .Left, attributes: [NSFontAttributeName: labelFont, NSForegroundColorAttributeName: labelTextColor])
|
||||
}
|
||||
}
|
||||
|
||||
public override func renderLimitLines(context context: CGContext?)
|
||||
{
|
||||
var limitLines = _yAxis.limitLines
|
||||
|
||||
if (limitLines.count == 0)
|
||||
{
|
||||
return
|
||||
}
|
||||
|
||||
CGContextSaveGState(context)
|
||||
|
||||
let sliceangle = _chart.sliceAngle
|
||||
|
||||
// calculate the factor that is needed for transforming the value to pixels
|
||||
let factor = _chart.factor
|
||||
|
||||
let center = _chart.centerOffsets
|
||||
|
||||
for (var i = 0; i < limitLines.count; i++)
|
||||
{
|
||||
let l = limitLines[i]
|
||||
|
||||
CGContextSetStrokeColorWithColor(context, l.lineColor.CGColor)
|
||||
CGContextSetLineWidth(context, l.lineWidth)
|
||||
if (l.lineDashLengths != nil)
|
||||
{
|
||||
CGContextSetLineDash(context, l.lineDashPhase, l.lineDashLengths!, l.lineDashLengths!.count)
|
||||
}
|
||||
else
|
||||
{
|
||||
CGContextSetLineDash(context, 0.0, nil, 0)
|
||||
}
|
||||
|
||||
let r = CGFloat(l.limit - _chart.chartYMin) * factor
|
||||
|
||||
CGContextBeginPath(context)
|
||||
|
||||
for (var j = 0, count = _chart.data!.xValCount; j < count; j++)
|
||||
{
|
||||
let p = ChartUtils.getPosition(center: center, dist: r, angle: sliceangle * CGFloat(j) + _chart.rotationAngle)
|
||||
|
||||
if (j == 0)
|
||||
{
|
||||
CGContextMoveToPoint(context, p.x, p.y)
|
||||
}
|
||||
else
|
||||
{
|
||||
CGContextAddLineToPoint(context, p.x, p.y)
|
||||
}
|
||||
}
|
||||
|
||||
CGContextClosePath(context)
|
||||
|
||||
CGContextStrokePath(context)
|
||||
}
|
||||
|
||||
CGContextRestoreGState(context)
|
||||
}
|
||||
}
|
||||
424
Carthage/Checkouts/Charts/Charts/Classes/Renderers/CombinedChartRenderer.swift
vendored
Normal file
424
Carthage/Checkouts/Charts/Charts/Classes/Renderers/CombinedChartRenderer.swift
vendored
Normal file
@@ -0,0 +1,424 @@
|
||||
//
|
||||
// CombinedChartRenderer.swift
|
||||
// Charts
|
||||
//
|
||||
// Created by Daniel Cohen Gindi on 4/3/15.
|
||||
//
|
||||
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
|
||||
// A port of MPAndroidChart for iOS
|
||||
// Licensed under Apache License 2.0
|
||||
//
|
||||
// https://github.com/danielgindi/ios-charts
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import CoreGraphics
|
||||
|
||||
public class CombinedChartRenderer: ChartDataRendererBase,
|
||||
LineChartRendererDelegate,
|
||||
BarChartRendererDelegate,
|
||||
ScatterChartRendererDelegate,
|
||||
CandleStickChartRendererDelegate,
|
||||
BubbleChartRendererDelegate
|
||||
{
|
||||
private weak var _chart: CombinedChartView!
|
||||
|
||||
/// flag that enables or disables the highlighting arrow
|
||||
public var drawHighlightArrowEnabled = false
|
||||
|
||||
/// if set to true, all values are drawn above their bars, instead of below their top
|
||||
public var drawValueAboveBarEnabled = true
|
||||
|
||||
/// if set to true, a grey area is darawn behind each bar that indicates the maximum value
|
||||
public var drawBarShadowEnabled = true
|
||||
|
||||
internal var _renderers = [ChartDataRendererBase]()
|
||||
|
||||
internal var _drawOrder: [CombinedChartView.CombinedChartDrawOrder] = [.Bar, .Bubble, .Line, .Candle, .Scatter]
|
||||
|
||||
public init(chart: CombinedChartView, animator: ChartAnimator, viewPortHandler: ChartViewPortHandler)
|
||||
{
|
||||
super.init(animator: animator, viewPortHandler: viewPortHandler)
|
||||
|
||||
_chart = chart
|
||||
|
||||
createRenderers()
|
||||
}
|
||||
|
||||
/// Creates the renderers needed for this combined-renderer in the required order. Also takes the DrawOrder into consideration.
|
||||
internal func createRenderers()
|
||||
{
|
||||
_renderers = [ChartDataRendererBase]()
|
||||
|
||||
for order in drawOrder
|
||||
{
|
||||
switch (order)
|
||||
{
|
||||
case .Bar:
|
||||
if (_chart.barData !== nil)
|
||||
{
|
||||
_renderers.append(BarChartRenderer(delegate: self, animator: _animator, viewPortHandler: viewPortHandler))
|
||||
}
|
||||
break
|
||||
|
||||
case .Line:
|
||||
if (_chart.lineData !== nil)
|
||||
{
|
||||
_renderers.append(LineChartRenderer(delegate: self, animator: _animator, viewPortHandler: viewPortHandler))
|
||||
}
|
||||
break
|
||||
|
||||
case .Candle:
|
||||
if (_chart.candleData !== nil)
|
||||
{
|
||||
_renderers.append(CandleStickChartRenderer(delegate: self, animator: _animator, viewPortHandler: viewPortHandler))
|
||||
}
|
||||
break
|
||||
|
||||
case .Scatter:
|
||||
if (_chart.scatterData !== nil)
|
||||
{
|
||||
_renderers.append(ScatterChartRenderer(delegate: self, animator: _animator, viewPortHandler: viewPortHandler))
|
||||
}
|
||||
break
|
||||
|
||||
case .Bubble:
|
||||
if (_chart.bubbleData !== nil)
|
||||
{
|
||||
_renderers.append(BubbleChartRenderer(delegate: self, animator: _animator, viewPortHandler: viewPortHandler))
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public override func drawData(context context: CGContext?)
|
||||
{
|
||||
for renderer in _renderers
|
||||
{
|
||||
renderer.drawData(context: context)
|
||||
}
|
||||
}
|
||||
|
||||
public override func drawValues(context context: CGContext?)
|
||||
{
|
||||
for renderer in _renderers
|
||||
{
|
||||
renderer.drawValues(context: context)
|
||||
}
|
||||
}
|
||||
|
||||
public override func drawExtras(context context: CGContext?)
|
||||
{
|
||||
for renderer in _renderers
|
||||
{
|
||||
renderer.drawExtras(context: context)
|
||||
}
|
||||
}
|
||||
|
||||
public override func drawHighlighted(context context: CGContext?, indices: [ChartHighlight])
|
||||
{
|
||||
for renderer in _renderers
|
||||
{
|
||||
renderer.drawHighlighted(context: context, indices: indices)
|
||||
}
|
||||
}
|
||||
|
||||
public override func calcXBounds(chart chart: BarLineChartViewBase, xAxisModulus: Int)
|
||||
{
|
||||
for renderer in _renderers
|
||||
{
|
||||
renderer.calcXBounds(chart: chart, xAxisModulus: xAxisModulus)
|
||||
}
|
||||
}
|
||||
|
||||
/// - returns: the sub-renderer object at the specified index.
|
||||
public func getSubRenderer(index index: Int) -> ChartDataRendererBase?
|
||||
{
|
||||
if (index >= _renderers.count || index < 0)
|
||||
{
|
||||
return nil
|
||||
}
|
||||
else
|
||||
{
|
||||
return _renderers[index]
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns all sub-renderers.
|
||||
public var subRenderers: [ChartDataRendererBase]
|
||||
{
|
||||
get { return _renderers }
|
||||
set { _renderers = newValue }
|
||||
}
|
||||
|
||||
// MARK: - LineChartRendererDelegate
|
||||
|
||||
public func lineChartRendererData(renderer: LineChartRenderer) -> LineChartData!
|
||||
{
|
||||
return _chart.lineData
|
||||
}
|
||||
|
||||
public func lineChartRenderer(renderer: LineChartRenderer, transformerForAxis which: ChartYAxis.AxisDependency) -> ChartTransformer!
|
||||
{
|
||||
return _chart.getTransformer(which)
|
||||
}
|
||||
|
||||
public func lineChartRendererFillFormatter(renderer: LineChartRenderer) -> ChartFillFormatter
|
||||
{
|
||||
return _chart.fillFormatter
|
||||
}
|
||||
|
||||
public func lineChartDefaultRendererValueFormatter(renderer: LineChartRenderer) -> NSNumberFormatter!
|
||||
{
|
||||
return _chart._defaultValueFormatter
|
||||
}
|
||||
|
||||
public func lineChartRendererChartYMax(renderer: LineChartRenderer) -> Double
|
||||
{
|
||||
return _chart.chartYMax
|
||||
}
|
||||
|
||||
public func lineChartRendererChartYMin(renderer: LineChartRenderer) -> Double
|
||||
{
|
||||
return _chart.chartYMin
|
||||
}
|
||||
|
||||
public func lineChartRendererChartXMax(renderer: LineChartRenderer) -> Double
|
||||
{
|
||||
return _chart.chartXMax
|
||||
}
|
||||
|
||||
public func lineChartRendererChartXMin(renderer: LineChartRenderer) -> Double
|
||||
{
|
||||
return _chart.chartXMin
|
||||
}
|
||||
|
||||
public func lineChartRendererMaxVisibleValueCount(renderer: LineChartRenderer) -> Int
|
||||
{
|
||||
return _chart.maxVisibleValueCount
|
||||
}
|
||||
|
||||
// MARK: - BarChartRendererDelegate
|
||||
|
||||
public func barChartRendererData(renderer: BarChartRenderer) -> BarChartData!
|
||||
{
|
||||
return _chart.barData
|
||||
}
|
||||
|
||||
public func barChartRenderer(renderer: BarChartRenderer, transformerForAxis which: ChartYAxis.AxisDependency) -> ChartTransformer!
|
||||
{
|
||||
return _chart.getTransformer(which)
|
||||
}
|
||||
|
||||
public func barChartRendererMaxVisibleValueCount(renderer: BarChartRenderer) -> Int
|
||||
{
|
||||
return _chart.maxVisibleValueCount
|
||||
}
|
||||
|
||||
public func barChartDefaultRendererValueFormatter(renderer: BarChartRenderer) -> NSNumberFormatter!
|
||||
{
|
||||
return _chart._defaultValueFormatter
|
||||
}
|
||||
|
||||
public func barChartRendererChartYMax(renderer: BarChartRenderer) -> Double
|
||||
{
|
||||
return _chart.chartYMax
|
||||
}
|
||||
|
||||
public func barChartRendererChartYMin(renderer: BarChartRenderer) -> Double
|
||||
{
|
||||
return _chart.chartYMin
|
||||
}
|
||||
|
||||
public func barChartRendererChartXMax(renderer: BarChartRenderer) -> Double
|
||||
{
|
||||
return _chart.chartXMax
|
||||
}
|
||||
|
||||
public func barChartRendererChartXMin(renderer: BarChartRenderer) -> Double
|
||||
{
|
||||
return _chart.chartXMin
|
||||
}
|
||||
|
||||
public func barChartIsDrawHighlightArrowEnabled(renderer: BarChartRenderer) -> Bool
|
||||
{
|
||||
return drawHighlightArrowEnabled
|
||||
}
|
||||
|
||||
public func barChartIsDrawValueAboveBarEnabled(renderer: BarChartRenderer) -> Bool
|
||||
{
|
||||
return drawValueAboveBarEnabled
|
||||
}
|
||||
|
||||
public func barChartIsDrawBarShadowEnabled(renderer: BarChartRenderer) -> Bool
|
||||
{
|
||||
return drawBarShadowEnabled
|
||||
}
|
||||
|
||||
public func barChartIsInverted(renderer: BarChartRenderer, axis: ChartYAxis.AxisDependency) -> Bool
|
||||
{
|
||||
return _chart.getAxis(axis).isInverted
|
||||
}
|
||||
|
||||
// MARK: - ScatterChartRendererDelegate
|
||||
|
||||
public func scatterChartRendererData(renderer: ScatterChartRenderer) -> ScatterChartData!
|
||||
{
|
||||
return _chart.scatterData
|
||||
}
|
||||
|
||||
public func scatterChartRenderer(renderer: ScatterChartRenderer, transformerForAxis which: ChartYAxis.AxisDependency) -> ChartTransformer!
|
||||
{
|
||||
return _chart.getTransformer(which)
|
||||
}
|
||||
|
||||
public func scatterChartDefaultRendererValueFormatter(renderer: ScatterChartRenderer) -> NSNumberFormatter!
|
||||
{
|
||||
return _chart._defaultValueFormatter
|
||||
}
|
||||
|
||||
public func scatterChartRendererChartYMax(renderer: ScatterChartRenderer) -> Double
|
||||
{
|
||||
return _chart.chartYMax
|
||||
}
|
||||
|
||||
public func scatterChartRendererChartYMin(renderer: ScatterChartRenderer) -> Double
|
||||
{
|
||||
return _chart.chartYMin
|
||||
}
|
||||
|
||||
public func scatterChartRendererChartXMax(renderer: ScatterChartRenderer) -> Double
|
||||
{
|
||||
return _chart.chartXMax
|
||||
}
|
||||
|
||||
public func scatterChartRendererChartXMin(renderer: ScatterChartRenderer) -> Double
|
||||
{
|
||||
return _chart.chartXMin
|
||||
}
|
||||
|
||||
public func scatterChartRendererMaxVisibleValueCount(renderer: ScatterChartRenderer) -> Int
|
||||
{
|
||||
return _chart.maxVisibleValueCount
|
||||
}
|
||||
|
||||
// MARK: - CandleStickChartRendererDelegate
|
||||
|
||||
public func candleStickChartRendererCandleData(renderer: CandleStickChartRenderer) -> CandleChartData!
|
||||
{
|
||||
return _chart.candleData
|
||||
}
|
||||
|
||||
public func candleStickChartRenderer(renderer: CandleStickChartRenderer, transformerForAxis which: ChartYAxis.AxisDependency) -> ChartTransformer!
|
||||
{
|
||||
return _chart.getTransformer(which)
|
||||
}
|
||||
|
||||
public func candleStickChartDefaultRendererValueFormatter(renderer: CandleStickChartRenderer) -> NSNumberFormatter!
|
||||
{
|
||||
return _chart._defaultValueFormatter
|
||||
}
|
||||
|
||||
public func candleStickChartRendererChartYMax(renderer: CandleStickChartRenderer) -> Double
|
||||
{
|
||||
return _chart.chartYMax
|
||||
}
|
||||
|
||||
public func candleStickChartRendererChartYMin(renderer: CandleStickChartRenderer) -> Double
|
||||
{
|
||||
return _chart.chartYMin
|
||||
}
|
||||
|
||||
public func candleStickChartRendererChartXMax(renderer: CandleStickChartRenderer) -> Double
|
||||
{
|
||||
return _chart.chartXMax
|
||||
}
|
||||
|
||||
public func candleStickChartRendererChartXMin(renderer: CandleStickChartRenderer) -> Double
|
||||
{
|
||||
return _chart.chartXMin
|
||||
}
|
||||
|
||||
public func candleStickChartRendererMaxVisibleValueCount(renderer: CandleStickChartRenderer) -> Int
|
||||
{
|
||||
return _chart.maxVisibleValueCount
|
||||
}
|
||||
|
||||
// MARK: - BubbleChartRendererDelegate
|
||||
|
||||
public func bubbleChartRendererData(renderer: BubbleChartRenderer) -> BubbleChartData!
|
||||
{
|
||||
return _chart.bubbleData
|
||||
}
|
||||
|
||||
public func bubbleChartRenderer(renderer: BubbleChartRenderer, transformerForAxis which: ChartYAxis.AxisDependency) -> ChartTransformer!
|
||||
{
|
||||
return _chart.getTransformer(which)
|
||||
}
|
||||
|
||||
public func bubbleChartDefaultRendererValueFormatter(renderer: BubbleChartRenderer) -> NSNumberFormatter!
|
||||
{
|
||||
return _chart._defaultValueFormatter
|
||||
}
|
||||
|
||||
public func bubbleChartRendererChartYMax(renderer: BubbleChartRenderer) -> Double
|
||||
{
|
||||
return _chart.chartYMax
|
||||
}
|
||||
|
||||
public func bubbleChartRendererChartYMin(renderer: BubbleChartRenderer) -> Double
|
||||
{
|
||||
return _chart.chartYMin
|
||||
}
|
||||
|
||||
public func bubbleChartRendererChartXMax(renderer: BubbleChartRenderer) -> Double
|
||||
{
|
||||
return _chart.chartXMax
|
||||
}
|
||||
|
||||
public func bubbleChartRendererChartXMin(renderer: BubbleChartRenderer) -> Double
|
||||
{
|
||||
return _chart.chartXMin
|
||||
}
|
||||
|
||||
public func bubbleChartRendererMaxVisibleValueCount(renderer: BubbleChartRenderer) -> Int
|
||||
{
|
||||
return _chart.maxVisibleValueCount
|
||||
}
|
||||
|
||||
public func bubbleChartRendererXValCount(renderer: BubbleChartRenderer) -> Int
|
||||
{
|
||||
return _chart.data!.xValCount
|
||||
}
|
||||
|
||||
// MARK: Accessors
|
||||
|
||||
/// - returns: true if drawing the highlighting arrow is enabled, false if not
|
||||
public var isDrawHighlightArrowEnabled: Bool { return drawHighlightArrowEnabled; }
|
||||
|
||||
/// - returns: true if drawing values above bars is enabled, false if not
|
||||
public var isDrawValueAboveBarEnabled: Bool { return drawValueAboveBarEnabled; }
|
||||
|
||||
/// - returns: true if drawing shadows (maxvalue) for each bar is enabled, false if not
|
||||
public var isDrawBarShadowEnabled: Bool { return drawBarShadowEnabled; }
|
||||
|
||||
/// the order in which the provided data objects should be drawn.
|
||||
/// The earlier you place them in the provided array, the further they will be in the background.
|
||||
/// e.g. if you provide [DrawOrder.Bar, DrawOrder.Line], the bars will be drawn behind the lines.
|
||||
public var drawOrder: [CombinedChartView.CombinedChartDrawOrder]
|
||||
{
|
||||
get
|
||||
{
|
||||
return _drawOrder
|
||||
}
|
||||
set
|
||||
{
|
||||
if (newValue.count > 0)
|
||||
{
|
||||
_drawOrder = newValue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
470
Carthage/Checkouts/Charts/Charts/Classes/Renderers/HorizontalBarChartRenderer.swift
vendored
Normal file
470
Carthage/Checkouts/Charts/Charts/Classes/Renderers/HorizontalBarChartRenderer.swift
vendored
Normal file
@@ -0,0 +1,470 @@
|
||||
//
|
||||
// HorizontalBarChartRenderer.swift
|
||||
// Charts
|
||||
//
|
||||
// Created by Daniel Cohen Gindi on 4/3/15.
|
||||
//
|
||||
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
|
||||
// A port of MPAndroidChart for iOS
|
||||
// Licensed under Apache License 2.0
|
||||
//
|
||||
// https://github.com/danielgindi/ios-charts
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import CoreGraphics
|
||||
import UIKit
|
||||
|
||||
public class HorizontalBarChartRenderer: BarChartRenderer
|
||||
{
|
||||
public override init(delegate: BarChartRendererDelegate?, animator: ChartAnimator?, viewPortHandler: ChartViewPortHandler)
|
||||
{
|
||||
super.init(delegate: delegate, animator: animator, viewPortHandler: viewPortHandler)
|
||||
}
|
||||
|
||||
internal override func drawDataSet(context context: CGContext?, dataSet: BarChartDataSet, index: Int)
|
||||
{
|
||||
CGContextSaveGState(context)
|
||||
|
||||
let barData = delegate!.barChartRendererData(self)
|
||||
|
||||
let trans = delegate!.barChartRenderer(self, transformerForAxis: dataSet.axisDependency)
|
||||
|
||||
let drawBarShadowEnabled: Bool = delegate!.barChartIsDrawBarShadowEnabled(self)
|
||||
let dataSetOffset = (barData.dataSetCount - 1)
|
||||
let groupSpace = barData.groupSpace
|
||||
let groupSpaceHalf = groupSpace / 2.0
|
||||
let barSpace = dataSet.barSpace
|
||||
let barSpaceHalf = barSpace / 2.0
|
||||
let containsStacks = dataSet.isStacked
|
||||
let isInverted = delegate!.barChartIsInverted(self, axis: dataSet.axisDependency)
|
||||
var entries = dataSet.yVals as! [BarChartDataEntry]
|
||||
let barWidth: CGFloat = 0.5
|
||||
let phaseY = _animator.phaseY
|
||||
var barRect = CGRect()
|
||||
var barShadow = CGRect()
|
||||
var y: Double
|
||||
|
||||
// do the drawing
|
||||
for (var j = 0, count = Int(ceil(CGFloat(dataSet.entryCount) * _animator.phaseX)); j < count; j++)
|
||||
{
|
||||
let e = entries[j]
|
||||
|
||||
// calculate the x-position, depending on datasetcount
|
||||
let x = CGFloat(e.xIndex + e.xIndex * dataSetOffset) + CGFloat(index)
|
||||
+ groupSpace * CGFloat(e.xIndex) + groupSpaceHalf
|
||||
let values = e.values
|
||||
|
||||
if (!containsStacks || values == nil)
|
||||
{
|
||||
y = e.value
|
||||
|
||||
let bottom = x - barWidth + barSpaceHalf
|
||||
let top = x + barWidth - barSpaceHalf
|
||||
var right = isInverted ? (y <= 0.0 ? CGFloat(y) : 0) : (y >= 0.0 ? CGFloat(y) : 0)
|
||||
var left = isInverted ? (y >= 0.0 ? CGFloat(y) : 0) : (y <= 0.0 ? CGFloat(y) : 0)
|
||||
|
||||
// multiply the height of the rect with the phase
|
||||
if (right > 0)
|
||||
{
|
||||
right *= phaseY
|
||||
}
|
||||
else
|
||||
{
|
||||
left *= phaseY
|
||||
}
|
||||
|
||||
barRect.origin.x = left
|
||||
barRect.size.width = right - left
|
||||
barRect.origin.y = top
|
||||
barRect.size.height = bottom - top
|
||||
|
||||
trans.rectValueToPixel(&barRect)
|
||||
|
||||
if (!viewPortHandler.isInBoundsLeft(barRect.origin.x + barRect.size.width))
|
||||
{
|
||||
continue
|
||||
}
|
||||
|
||||
if (!viewPortHandler.isInBoundsRight(barRect.origin.x))
|
||||
{
|
||||
break
|
||||
}
|
||||
|
||||
// if drawing the bar shadow is enabled
|
||||
if (drawBarShadowEnabled)
|
||||
{
|
||||
barShadow.origin.x = viewPortHandler.contentLeft
|
||||
barShadow.origin.y = barRect.origin.y
|
||||
barShadow.size.width = viewPortHandler.contentWidth
|
||||
barShadow.size.height = barRect.size.height
|
||||
|
||||
CGContextSetFillColorWithColor(context, dataSet.barShadowColor.CGColor)
|
||||
CGContextFillRect(context, barShadow)
|
||||
}
|
||||
|
||||
// Set the color for the currently drawn value. If the index is out of bounds, reuse colors.
|
||||
CGContextSetFillColorWithColor(context, dataSet.colorAt(j).CGColor)
|
||||
CGContextFillRect(context, barRect)
|
||||
}
|
||||
else
|
||||
{
|
||||
let vals = values!
|
||||
var posY = 0.0
|
||||
var negY = -e.negativeSum
|
||||
var yStart = 0.0
|
||||
|
||||
// if drawing the bar shadow is enabled
|
||||
if (drawBarShadowEnabled)
|
||||
{
|
||||
y = e.value
|
||||
|
||||
let bottom = x - barWidth + barSpaceHalf
|
||||
let top = x + barWidth - barSpaceHalf
|
||||
var right = isInverted ? (y <= 0.0 ? CGFloat(y) : 0) : (y >= 0.0 ? CGFloat(y) : 0)
|
||||
var left = isInverted ? (y >= 0.0 ? CGFloat(y) : 0) : (y <= 0.0 ? CGFloat(y) : 0)
|
||||
|
||||
// multiply the height of the rect with the phase
|
||||
if (right > 0)
|
||||
{
|
||||
right *= phaseY
|
||||
}
|
||||
else
|
||||
{
|
||||
left *= phaseY
|
||||
}
|
||||
|
||||
barRect.origin.x = left
|
||||
barRect.size.width = right - left
|
||||
barRect.origin.y = top
|
||||
barRect.size.height = bottom - top
|
||||
|
||||
trans.rectValueToPixel(&barRect)
|
||||
|
||||
barShadow.origin.x = viewPortHandler.contentLeft
|
||||
barShadow.origin.y = barRect.origin.y
|
||||
barShadow.size.width = viewPortHandler.contentWidth
|
||||
barShadow.size.height = barRect.size.height
|
||||
|
||||
CGContextSetFillColorWithColor(context, dataSet.barShadowColor.CGColor)
|
||||
CGContextFillRect(context, barShadow)
|
||||
}
|
||||
|
||||
// fill the stack
|
||||
for (var k = 0; k < vals.count; k++)
|
||||
{
|
||||
let value = vals[k]
|
||||
|
||||
if value >= 0.0
|
||||
{
|
||||
y = posY
|
||||
yStart = posY + value
|
||||
posY = yStart
|
||||
}
|
||||
else
|
||||
{
|
||||
y = negY
|
||||
yStart = negY + abs(value)
|
||||
negY += abs(value)
|
||||
}
|
||||
|
||||
let bottom = x - barWidth + barSpaceHalf
|
||||
let top = x + barWidth - barSpaceHalf
|
||||
var right: CGFloat, left: CGFloat
|
||||
if isInverted
|
||||
{
|
||||
left = y >= yStart ? CGFloat(y) : CGFloat(yStart)
|
||||
right = y <= yStart ? CGFloat(y) : CGFloat(yStart)
|
||||
}
|
||||
else
|
||||
{
|
||||
right = y >= yStart ? CGFloat(y) : CGFloat(yStart)
|
||||
left = y <= yStart ? CGFloat(y) : CGFloat(yStart)
|
||||
}
|
||||
|
||||
// multiply the height of the rect with the phase
|
||||
right *= phaseY
|
||||
left *= phaseY
|
||||
|
||||
barRect.origin.x = left
|
||||
barRect.size.width = right - left
|
||||
barRect.origin.y = top
|
||||
barRect.size.height = bottom - top
|
||||
|
||||
trans.rectValueToPixel(&barRect)
|
||||
|
||||
if (k == 0 && !viewPortHandler.isInBoundsTop(barRect.origin.y + barRect.size.height))
|
||||
{
|
||||
// Skip to next bar
|
||||
break
|
||||
}
|
||||
|
||||
// avoid drawing outofbounds values
|
||||
if (!viewPortHandler.isInBoundsBottom(barRect.origin.y))
|
||||
{
|
||||
break
|
||||
}
|
||||
|
||||
// Set the color for the currently drawn value. If the index is out of bounds, reuse colors.
|
||||
CGContextSetFillColorWithColor(context, dataSet.colorAt(k).CGColor)
|
||||
CGContextFillRect(context, barRect)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CGContextRestoreGState(context)
|
||||
}
|
||||
|
||||
internal override func prepareBarHighlight(x x: CGFloat, y1: Double, y2: Double, barspacehalf: CGFloat, trans: ChartTransformer, inout rect: CGRect)
|
||||
{
|
||||
let barWidth: CGFloat = 0.5
|
||||
|
||||
let top = x - barWidth + barspacehalf
|
||||
let bottom = x + barWidth - barspacehalf
|
||||
let left = CGFloat(y1)
|
||||
let right = CGFloat(y2)
|
||||
|
||||
rect.origin.x = left
|
||||
rect.origin.y = top
|
||||
rect.size.width = right - left
|
||||
rect.size.height = bottom - top
|
||||
|
||||
trans.rectValueToPixelHorizontal(&rect, phaseY: _animator.phaseY)
|
||||
}
|
||||
|
||||
public override func getTransformedValues(trans trans: ChartTransformer, entries: [BarChartDataEntry], dataSetIndex: Int) -> [CGPoint]
|
||||
{
|
||||
return trans.generateTransformedValuesHorizontalBarChart(entries, dataSet: dataSetIndex, barData: delegate!.barChartRendererData(self)!, phaseY: _animator.phaseY)
|
||||
}
|
||||
|
||||
public override func drawValues(context context: CGContext?)
|
||||
{
|
||||
// if values are drawn
|
||||
if (passesCheck())
|
||||
{
|
||||
let barData = delegate!.barChartRendererData(self)
|
||||
|
||||
let defaultValueFormatter = delegate!.barChartDefaultRendererValueFormatter(self)
|
||||
|
||||
var dataSets = barData.dataSets
|
||||
|
||||
let drawValueAboveBar = delegate!.barChartIsDrawValueAboveBarEnabled(self)
|
||||
|
||||
let textAlign = drawValueAboveBar ? NSTextAlignment.Left : NSTextAlignment.Right
|
||||
|
||||
let valueOffsetPlus: CGFloat = 5.0
|
||||
var posOffset: CGFloat
|
||||
var negOffset: CGFloat
|
||||
|
||||
for (var i = 0, count = barData.dataSetCount; i < count; i++)
|
||||
{
|
||||
let dataSet = dataSets[i] as! BarChartDataSet
|
||||
|
||||
if !dataSet.isDrawValuesEnabled || dataSet.entryCount == 0
|
||||
{
|
||||
continue
|
||||
}
|
||||
|
||||
let isInverted = delegate!.barChartIsInverted(self, axis: dataSet.axisDependency)
|
||||
|
||||
let valueFont = dataSet.valueFont
|
||||
let valueTextColor = dataSet.valueTextColor
|
||||
let yOffset = -valueFont.lineHeight / 2.0
|
||||
|
||||
var formatter = dataSet.valueFormatter
|
||||
if (formatter === nil)
|
||||
{
|
||||
formatter = defaultValueFormatter
|
||||
}
|
||||
|
||||
let trans = delegate!.barChartRenderer(self, transformerForAxis: dataSet.axisDependency)
|
||||
|
||||
var entries = dataSet.yVals as! [BarChartDataEntry]
|
||||
|
||||
var valuePoints = getTransformedValues(trans: trans, entries: entries, dataSetIndex: i)
|
||||
|
||||
// if only single values are drawn (sum)
|
||||
if (!dataSet.isStacked)
|
||||
{
|
||||
for (var j = 0, count = Int(ceil(CGFloat(valuePoints.count) * _animator.phaseX)); j < count; j++)
|
||||
{
|
||||
if (!viewPortHandler.isInBoundsTop(valuePoints[j].y))
|
||||
{
|
||||
break
|
||||
}
|
||||
|
||||
if (!viewPortHandler.isInBoundsX(valuePoints[j].x))
|
||||
{
|
||||
continue
|
||||
}
|
||||
|
||||
if (!viewPortHandler.isInBoundsBottom(valuePoints[j].y))
|
||||
{
|
||||
continue
|
||||
}
|
||||
|
||||
let val = entries[j].value
|
||||
let valueText = formatter!.stringFromNumber(val)!
|
||||
|
||||
// calculate the correct offset depending on the draw position of the value
|
||||
let valueTextWidth = valueText.sizeWithAttributes([NSFontAttributeName: valueFont]).width
|
||||
posOffset = (drawValueAboveBar ? valueOffsetPlus : -(valueTextWidth + valueOffsetPlus))
|
||||
negOffset = (drawValueAboveBar ? -(valueTextWidth + valueOffsetPlus) : valueOffsetPlus)
|
||||
|
||||
if (isInverted)
|
||||
{
|
||||
posOffset = -posOffset - valueTextWidth
|
||||
negOffset = -negOffset - valueTextWidth
|
||||
}
|
||||
|
||||
drawValue(
|
||||
context: context,
|
||||
value: valueText,
|
||||
xPos: valuePoints[j].x + (val >= 0.0 ? posOffset : negOffset),
|
||||
yPos: valuePoints[j].y + yOffset,
|
||||
font: valueFont,
|
||||
align: textAlign,
|
||||
color: valueTextColor)
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// if each value of a potential stack should be drawn
|
||||
|
||||
for (var j = 0, count = Int(ceil(CGFloat(valuePoints.count) * _animator.phaseX)); j < count; j++)
|
||||
{
|
||||
let e = entries[j]
|
||||
|
||||
let values = e.values
|
||||
|
||||
// we still draw stacked bars, but there is one non-stacked in between
|
||||
if (values == nil)
|
||||
{
|
||||
if (!viewPortHandler.isInBoundsTop(valuePoints[j].y))
|
||||
{
|
||||
break
|
||||
}
|
||||
|
||||
if (!viewPortHandler.isInBoundsX(valuePoints[j].x))
|
||||
{
|
||||
continue
|
||||
}
|
||||
|
||||
if (!viewPortHandler.isInBoundsBottom(valuePoints[j].y))
|
||||
{
|
||||
continue
|
||||
}
|
||||
|
||||
let val = e.value
|
||||
let valueText = formatter!.stringFromNumber(val)!
|
||||
|
||||
// calculate the correct offset depending on the draw position of the value
|
||||
let valueTextWidth = valueText.sizeWithAttributes([NSFontAttributeName: valueFont]).width
|
||||
posOffset = (drawValueAboveBar ? valueOffsetPlus : -(valueTextWidth + valueOffsetPlus))
|
||||
negOffset = (drawValueAboveBar ? -(valueTextWidth + valueOffsetPlus) : valueOffsetPlus)
|
||||
|
||||
if (isInverted)
|
||||
{
|
||||
posOffset = -posOffset - valueTextWidth
|
||||
negOffset = -negOffset - valueTextWidth
|
||||
}
|
||||
|
||||
drawValue(
|
||||
context: context,
|
||||
value: valueText,
|
||||
xPos: valuePoints[j].x + (val >= 0.0 ? posOffset : negOffset),
|
||||
yPos: valuePoints[j].y + yOffset,
|
||||
font: valueFont,
|
||||
align: textAlign,
|
||||
color: valueTextColor)
|
||||
}
|
||||
else
|
||||
{
|
||||
let vals = values!
|
||||
var transformed = [CGPoint]()
|
||||
|
||||
var posY = 0.0
|
||||
var negY = -e.negativeSum
|
||||
|
||||
for (var k = 0; k < vals.count; k++)
|
||||
{
|
||||
let value = vals[k]
|
||||
var y: Double
|
||||
|
||||
if value >= 0.0
|
||||
{
|
||||
posY += value
|
||||
y = posY
|
||||
}
|
||||
else
|
||||
{
|
||||
y = negY
|
||||
negY -= value
|
||||
}
|
||||
|
||||
transformed.append(CGPoint(x: CGFloat(y) * _animator.phaseY, y: 0.0))
|
||||
}
|
||||
|
||||
trans.pointValuesToPixel(&transformed)
|
||||
|
||||
for (var k = 0; k < transformed.count; k++)
|
||||
{
|
||||
let val = vals[k]
|
||||
let valueText = formatter!.stringFromNumber(val)!
|
||||
|
||||
// calculate the correct offset depending on the draw position of the value
|
||||
let valueTextWidth = valueText.sizeWithAttributes([NSFontAttributeName: valueFont]).width
|
||||
posOffset = (drawValueAboveBar ? valueOffsetPlus : -(valueTextWidth + valueOffsetPlus))
|
||||
negOffset = (drawValueAboveBar ? -(valueTextWidth + valueOffsetPlus) : valueOffsetPlus)
|
||||
|
||||
if (isInverted)
|
||||
{
|
||||
posOffset = -posOffset - valueTextWidth
|
||||
negOffset = -negOffset - valueTextWidth
|
||||
}
|
||||
|
||||
let x = transformed[k].x + (val >= 0 ? posOffset : negOffset)
|
||||
let y = valuePoints[j].y
|
||||
|
||||
if (!viewPortHandler.isInBoundsTop(y))
|
||||
{
|
||||
break
|
||||
}
|
||||
|
||||
if (!viewPortHandler.isInBoundsX(x))
|
||||
{
|
||||
continue
|
||||
}
|
||||
|
||||
if (!viewPortHandler.isInBoundsBottom(y))
|
||||
{
|
||||
continue
|
||||
}
|
||||
|
||||
drawValue(context: context,
|
||||
value: valueText,
|
||||
xPos: x,
|
||||
yPos: y + yOffset,
|
||||
font: valueFont,
|
||||
align: textAlign,
|
||||
color: valueTextColor)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal override func passesCheck() -> Bool
|
||||
{
|
||||
let barData = delegate!.barChartRendererData(self)
|
||||
|
||||
if (barData === nil)
|
||||
{
|
||||
return false
|
||||
}
|
||||
|
||||
return CGFloat(barData.yValCount) < CGFloat(delegate!.barChartRendererMaxVisibleValueCount(self)) * viewPortHandler.scaleY
|
||||
}
|
||||
}
|
||||
628
Carthage/Checkouts/Charts/Charts/Classes/Renderers/LineChartRenderer.swift
vendored
Normal file
628
Carthage/Checkouts/Charts/Charts/Classes/Renderers/LineChartRenderer.swift
vendored
Normal file
@@ -0,0 +1,628 @@
|
||||
//
|
||||
// LineChartRenderer.swift
|
||||
// Charts
|
||||
//
|
||||
// Created by Daniel Cohen Gindi on 4/3/15.
|
||||
//
|
||||
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
|
||||
// A port of MPAndroidChart for iOS
|
||||
// Licensed under Apache License 2.0
|
||||
//
|
||||
// https://github.com/danielgindi/ios-charts
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import CoreGraphics
|
||||
import UIKit
|
||||
|
||||
@objc
|
||||
public protocol LineChartRendererDelegate
|
||||
{
|
||||
func lineChartRendererData(renderer: LineChartRenderer) -> LineChartData!
|
||||
func lineChartRenderer(renderer: LineChartRenderer, transformerForAxis which: ChartYAxis.AxisDependency) -> ChartTransformer!
|
||||
func lineChartRendererFillFormatter(renderer: LineChartRenderer) -> ChartFillFormatter
|
||||
func lineChartDefaultRendererValueFormatter(renderer: LineChartRenderer) -> NSNumberFormatter!
|
||||
func lineChartRendererChartYMax(renderer: LineChartRenderer) -> Double
|
||||
func lineChartRendererChartYMin(renderer: LineChartRenderer) -> Double
|
||||
func lineChartRendererChartXMax(renderer: LineChartRenderer) -> Double
|
||||
func lineChartRendererChartXMin(renderer: LineChartRenderer) -> Double
|
||||
func lineChartRendererMaxVisibleValueCount(renderer: LineChartRenderer) -> Int
|
||||
}
|
||||
|
||||
public class LineChartRenderer: LineScatterCandleRadarChartRenderer
|
||||
{
|
||||
public weak var delegate: LineChartRendererDelegate?
|
||||
|
||||
public init(delegate: LineChartRendererDelegate?, animator: ChartAnimator?, viewPortHandler: ChartViewPortHandler)
|
||||
{
|
||||
super.init(animator: animator, viewPortHandler: viewPortHandler)
|
||||
|
||||
self.delegate = delegate
|
||||
}
|
||||
|
||||
public override func drawData(context context: CGContext?)
|
||||
{
|
||||
let lineData = delegate!.lineChartRendererData(self)
|
||||
|
||||
if (lineData === nil)
|
||||
{
|
||||
return
|
||||
}
|
||||
|
||||
for (var i = 0; i < lineData.dataSetCount; i++)
|
||||
{
|
||||
let set = lineData.getDataSetByIndex(i)
|
||||
|
||||
if (set !== nil && set!.isVisible)
|
||||
{
|
||||
drawDataSet(context: context, dataSet: set as! LineChartDataSet)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal struct CGCPoint
|
||||
{
|
||||
internal var x: CGFloat = 0.0
|
||||
internal var y: CGFloat = 0.0
|
||||
|
||||
/// x-axis distance
|
||||
internal var dx: CGFloat = 0.0
|
||||
/// y-axis distance
|
||||
internal var dy: CGFloat = 0.0
|
||||
|
||||
internal init(x: CGFloat, y: CGFloat)
|
||||
{
|
||||
self.x = x
|
||||
self.y = y
|
||||
}
|
||||
}
|
||||
|
||||
internal func drawDataSet(context context: CGContext?, dataSet: LineChartDataSet)
|
||||
{
|
||||
let entries = dataSet.yVals
|
||||
|
||||
if (entries.count < 1)
|
||||
{
|
||||
return
|
||||
}
|
||||
|
||||
CGContextSaveGState(context)
|
||||
|
||||
CGContextSetLineWidth(context, dataSet.lineWidth)
|
||||
if (dataSet.lineDashLengths != nil)
|
||||
{
|
||||
CGContextSetLineDash(context, dataSet.lineDashPhase, dataSet.lineDashLengths, dataSet.lineDashLengths.count)
|
||||
}
|
||||
else
|
||||
{
|
||||
CGContextSetLineDash(context, 0.0, nil, 0)
|
||||
}
|
||||
|
||||
// if drawing cubic lines is enabled
|
||||
if (dataSet.isDrawCubicEnabled)
|
||||
{
|
||||
drawCubic(context: context, dataSet: dataSet, entries: entries)
|
||||
}
|
||||
else
|
||||
{ // draw normal (straight) lines
|
||||
drawLinear(context: context, dataSet: dataSet, entries: entries)
|
||||
}
|
||||
|
||||
CGContextRestoreGState(context)
|
||||
}
|
||||
|
||||
internal func drawCubic(context context: CGContext?, dataSet: LineChartDataSet, entries: [ChartDataEntry])
|
||||
{
|
||||
let trans = delegate?.lineChartRenderer(self, transformerForAxis: dataSet.axisDependency)
|
||||
|
||||
let entryFrom = dataSet.entryForXIndex(_minX)
|
||||
let entryTo = dataSet.entryForXIndex(_maxX)
|
||||
|
||||
let minx = max(dataSet.entryIndex(entry: entryFrom!, isEqual: true), 0)
|
||||
let maxx = min(dataSet.entryIndex(entry: entryTo!, isEqual: true) + 1, entries.count)
|
||||
|
||||
let phaseX = _animator.phaseX
|
||||
let phaseY = _animator.phaseY
|
||||
|
||||
// get the color that is specified for this position from the DataSet
|
||||
let drawingColor = dataSet.colors.first!
|
||||
|
||||
let intensity = dataSet.cubicIntensity
|
||||
|
||||
// the path for the cubic-spline
|
||||
let cubicPath = CGPathCreateMutable()
|
||||
|
||||
var valueToPixelMatrix = trans!.valueToPixelMatrix
|
||||
|
||||
let size = Int(ceil(CGFloat(maxx - minx) * phaseX + CGFloat(minx)))
|
||||
|
||||
if (size - minx >= 2)
|
||||
{
|
||||
var prevDx: CGFloat = 0.0
|
||||
var prevDy: CGFloat = 0.0
|
||||
var curDx: CGFloat = 0.0
|
||||
var curDy: CGFloat = 0.0
|
||||
|
||||
var prevPrev = entries[minx]
|
||||
var prev = entries[minx]
|
||||
var cur = entries[minx]
|
||||
var next = entries[minx + 1]
|
||||
|
||||
// let the spline start
|
||||
CGPathMoveToPoint(cubicPath, &valueToPixelMatrix, CGFloat(cur.xIndex), CGFloat(cur.value) * phaseY)
|
||||
|
||||
prevDx = CGFloat(cur.xIndex - prev.xIndex) * intensity
|
||||
prevDy = CGFloat(cur.value - prev.value) * intensity
|
||||
|
||||
curDx = CGFloat(next.xIndex - cur.xIndex) * intensity
|
||||
curDy = CGFloat(next.value - cur.value) * intensity
|
||||
|
||||
// the first cubic
|
||||
CGPathAddCurveToPoint(cubicPath, &valueToPixelMatrix,
|
||||
CGFloat(prev.xIndex) + prevDx, (CGFloat(prev.value) + prevDy) * phaseY,
|
||||
CGFloat(cur.xIndex) - curDx, (CGFloat(cur.value) - curDy) * phaseY,
|
||||
CGFloat(cur.xIndex), CGFloat(cur.value) * phaseY)
|
||||
|
||||
for (var j = minx + 1, count = min(size, entries.count - 1); j < count; j++)
|
||||
{
|
||||
prevPrev = entries[j == 1 ? 0 : j - 2]
|
||||
prev = entries[j - 1]
|
||||
cur = entries[j]
|
||||
next = entries[j + 1]
|
||||
|
||||
prevDx = CGFloat(cur.xIndex - prevPrev.xIndex) * intensity
|
||||
prevDy = CGFloat(cur.value - prevPrev.value) * intensity
|
||||
curDx = CGFloat(next.xIndex - prev.xIndex) * intensity
|
||||
curDy = CGFloat(next.value - prev.value) * intensity
|
||||
|
||||
CGPathAddCurveToPoint(cubicPath, &valueToPixelMatrix, CGFloat(prev.xIndex) + prevDx, (CGFloat(prev.value) + prevDy) * phaseY,
|
||||
CGFloat(cur.xIndex) - curDx,
|
||||
(CGFloat(cur.value) - curDy) * phaseY, CGFloat(cur.xIndex), CGFloat(cur.value) * phaseY)
|
||||
}
|
||||
|
||||
if (size > entries.count - 1)
|
||||
{
|
||||
prevPrev = entries[entries.count - (entries.count >= 3 ? 3 : 2)]
|
||||
prev = entries[entries.count - 2]
|
||||
cur = entries[entries.count - 1]
|
||||
next = cur
|
||||
|
||||
prevDx = CGFloat(cur.xIndex - prevPrev.xIndex) * intensity
|
||||
prevDy = CGFloat(cur.value - prevPrev.value) * intensity
|
||||
curDx = CGFloat(next.xIndex - prev.xIndex) * intensity
|
||||
curDy = CGFloat(next.value - prev.value) * intensity
|
||||
|
||||
// the last cubic
|
||||
CGPathAddCurveToPoint(cubicPath, &valueToPixelMatrix, CGFloat(prev.xIndex) + prevDx, (CGFloat(prev.value) + prevDy) * phaseY,
|
||||
CGFloat(cur.xIndex) - curDx,
|
||||
(CGFloat(cur.value) - curDy) * phaseY, CGFloat(cur.xIndex), CGFloat(cur.value) * phaseY)
|
||||
}
|
||||
}
|
||||
|
||||
CGContextSaveGState(context)
|
||||
|
||||
if (dataSet.isDrawFilledEnabled)
|
||||
{
|
||||
drawCubicFill(context: context, dataSet: dataSet, spline: cubicPath, matrix: valueToPixelMatrix, from: minx, to: size)
|
||||
}
|
||||
|
||||
CGContextBeginPath(context)
|
||||
CGContextAddPath(context, cubicPath)
|
||||
CGContextSetStrokeColorWithColor(context, drawingColor.CGColor)
|
||||
CGContextStrokePath(context)
|
||||
|
||||
CGContextRestoreGState(context)
|
||||
}
|
||||
|
||||
internal func drawCubicFill(context context: CGContext?, dataSet: LineChartDataSet, spline: CGMutablePath, matrix: CGAffineTransform, from: Int, to: Int)
|
||||
{
|
||||
if to - from <= 1
|
||||
{
|
||||
return
|
||||
}
|
||||
|
||||
CGContextSaveGState(context)
|
||||
|
||||
let fillMin = delegate!.lineChartRendererFillFormatter(self).getFillLinePosition(
|
||||
dataSet: dataSet,
|
||||
data: delegate!.lineChartRendererData(self),
|
||||
chartMaxY: delegate!.lineChartRendererChartYMax(self),
|
||||
chartMinY: delegate!.lineChartRendererChartYMin(self))
|
||||
|
||||
var pt1 = CGPoint(x: CGFloat(to - 1), y: fillMin)
|
||||
var pt2 = CGPoint(x: CGFloat(from), y: fillMin)
|
||||
pt1 = CGPointApplyAffineTransform(pt1, matrix)
|
||||
pt2 = CGPointApplyAffineTransform(pt2, matrix)
|
||||
|
||||
CGContextBeginPath(context)
|
||||
CGContextAddPath(context, spline)
|
||||
CGContextAddLineToPoint(context, pt1.x, pt1.y)
|
||||
CGContextAddLineToPoint(context, pt2.x, pt2.y)
|
||||
CGContextClosePath(context)
|
||||
|
||||
CGContextSetFillColorWithColor(context, dataSet.fillColor.CGColor)
|
||||
CGContextSetAlpha(context, dataSet.fillAlpha)
|
||||
CGContextFillPath(context)
|
||||
|
||||
CGContextRestoreGState(context)
|
||||
}
|
||||
|
||||
private var _lineSegments = [CGPoint](count: 2, repeatedValue: CGPoint())
|
||||
|
||||
internal func drawLinear(context context: CGContext?, dataSet: LineChartDataSet, entries: [ChartDataEntry])
|
||||
{
|
||||
let trans = delegate!.lineChartRenderer(self, transformerForAxis: dataSet.axisDependency)
|
||||
let valueToPixelMatrix = trans.valueToPixelMatrix
|
||||
|
||||
let phaseX = _animator.phaseX
|
||||
let phaseY = _animator.phaseY
|
||||
|
||||
CGContextSaveGState(context)
|
||||
|
||||
let entryFrom = dataSet.entryForXIndex(_minX)
|
||||
let entryTo = dataSet.entryForXIndex(_maxX)
|
||||
|
||||
let minx = max(dataSet.entryIndex(entry: entryFrom!, isEqual: true), 0)
|
||||
let maxx = min(dataSet.entryIndex(entry: entryTo!, isEqual: true) + 1, entries.count)
|
||||
|
||||
// more than 1 color
|
||||
if (dataSet.colors.count > 1)
|
||||
{
|
||||
if (_lineSegments.count != 2)
|
||||
{
|
||||
_lineSegments = [CGPoint](count: 2, repeatedValue: CGPoint())
|
||||
}
|
||||
|
||||
for (var j = minx, count = Int(ceil(CGFloat(maxx - minx) * phaseX + CGFloat(minx))); j < count; j++)
|
||||
{
|
||||
if (count > 1 && j == count - 1)
|
||||
{ // Last point, we have already drawn a line to this point
|
||||
break
|
||||
}
|
||||
|
||||
var e = entries[j]
|
||||
|
||||
_lineSegments[0].x = CGFloat(e.xIndex)
|
||||
_lineSegments[0].y = CGFloat(e.value) * phaseY
|
||||
_lineSegments[0] = CGPointApplyAffineTransform(_lineSegments[0], valueToPixelMatrix)
|
||||
if (j + 1 < count)
|
||||
{
|
||||
e = entries[j + 1]
|
||||
|
||||
_lineSegments[1].x = CGFloat(e.xIndex)
|
||||
_lineSegments[1].y = CGFloat(e.value) * phaseY
|
||||
_lineSegments[1] = CGPointApplyAffineTransform(_lineSegments[1], valueToPixelMatrix)
|
||||
}
|
||||
else
|
||||
{
|
||||
_lineSegments[1] = _lineSegments[0]
|
||||
}
|
||||
|
||||
if (!viewPortHandler.isInBoundsRight(_lineSegments[0].x))
|
||||
{
|
||||
break
|
||||
}
|
||||
|
||||
// make sure the lines don't do shitty things outside bounds
|
||||
if (!viewPortHandler.isInBoundsLeft(_lineSegments[1].x)
|
||||
|| (!viewPortHandler.isInBoundsTop(_lineSegments[0].y) && !viewPortHandler.isInBoundsBottom(_lineSegments[1].y))
|
||||
|| (!viewPortHandler.isInBoundsTop(_lineSegments[0].y) && !viewPortHandler.isInBoundsBottom(_lineSegments[1].y)))
|
||||
{
|
||||
continue
|
||||
}
|
||||
|
||||
// get the color that is set for this line-segment
|
||||
CGContextSetStrokeColorWithColor(context, dataSet.colorAt(j).CGColor)
|
||||
CGContextStrokeLineSegments(context, _lineSegments, 2)
|
||||
}
|
||||
}
|
||||
else
|
||||
{ // only one color per dataset
|
||||
|
||||
var e1: ChartDataEntry!
|
||||
var e2: ChartDataEntry!
|
||||
|
||||
if (_lineSegments.count != max((entries.count - 1) * 2, 2))
|
||||
{
|
||||
_lineSegments = [CGPoint](count: max((entries.count - 1) * 2, 2), repeatedValue: CGPoint())
|
||||
}
|
||||
|
||||
e1 = entries[minx]
|
||||
|
||||
let count = Int(ceil(CGFloat(maxx - minx) * phaseX + CGFloat(minx)))
|
||||
|
||||
for (var x = count > 1 ? minx + 1 : minx, j = 0; x < count; x++)
|
||||
{
|
||||
e1 = entries[x == 0 ? 0 : (x - 1)]
|
||||
e2 = entries[x]
|
||||
|
||||
_lineSegments[j++] = CGPointApplyAffineTransform(CGPoint(x: CGFloat(e1.xIndex), y: CGFloat(e1.value) * phaseY), valueToPixelMatrix)
|
||||
_lineSegments[j++] = CGPointApplyAffineTransform(CGPoint(x: CGFloat(e2.xIndex), y: CGFloat(e2.value) * phaseY), valueToPixelMatrix)
|
||||
}
|
||||
|
||||
let size = max((count - minx - 1) * 2, 2)
|
||||
CGContextSetStrokeColorWithColor(context, dataSet.colorAt(0).CGColor)
|
||||
CGContextStrokeLineSegments(context, _lineSegments, size)
|
||||
}
|
||||
|
||||
CGContextRestoreGState(context)
|
||||
|
||||
// if drawing filled is enabled
|
||||
if (dataSet.isDrawFilledEnabled && entries.count > 0)
|
||||
{
|
||||
drawLinearFill(context: context, dataSet: dataSet, entries: entries, minx: minx, maxx: maxx, trans: trans)
|
||||
}
|
||||
}
|
||||
|
||||
internal func drawLinearFill(context context: CGContext?, dataSet: LineChartDataSet, entries: [ChartDataEntry], minx: Int, maxx: Int, trans: ChartTransformer)
|
||||
{
|
||||
CGContextSaveGState(context)
|
||||
|
||||
CGContextSetFillColorWithColor(context, dataSet.fillColor.CGColor)
|
||||
|
||||
// filled is usually drawn with less alpha
|
||||
CGContextSetAlpha(context, dataSet.fillAlpha)
|
||||
|
||||
let filled = generateFilledPath(
|
||||
entries,
|
||||
fillMin: delegate!.lineChartRendererFillFormatter(self).getFillLinePosition(
|
||||
dataSet: dataSet,
|
||||
data: delegate!.lineChartRendererData(self),
|
||||
chartMaxY: delegate!.lineChartRendererChartYMax(self),
|
||||
chartMinY: delegate!.lineChartRendererChartYMin(self)),
|
||||
from: minx,
|
||||
to: maxx,
|
||||
matrix: trans.valueToPixelMatrix)
|
||||
|
||||
CGContextBeginPath(context)
|
||||
CGContextAddPath(context, filled)
|
||||
CGContextFillPath(context)
|
||||
|
||||
CGContextRestoreGState(context)
|
||||
}
|
||||
|
||||
/// Generates the path that is used for filled drawing.
|
||||
private func generateFilledPath(entries: [ChartDataEntry], fillMin: CGFloat, from: Int, to: Int, var matrix: CGAffineTransform) -> CGPath
|
||||
{
|
||||
let phaseX = _animator.phaseX
|
||||
let phaseY = _animator.phaseY
|
||||
|
||||
let filled = CGPathCreateMutable()
|
||||
CGPathMoveToPoint(filled, &matrix, CGFloat(entries[from].xIndex), fillMin)
|
||||
CGPathAddLineToPoint(filled, &matrix, CGFloat(entries[from].xIndex), CGFloat(entries[from].value) * phaseY)
|
||||
|
||||
// create a new path
|
||||
for (var x = from + 1, count = Int(ceil(CGFloat(to - from) * phaseX + CGFloat(from))); x < count; x++)
|
||||
{
|
||||
let e = entries[x]
|
||||
CGPathAddLineToPoint(filled, &matrix, CGFloat(e.xIndex), CGFloat(e.value) * phaseY)
|
||||
}
|
||||
|
||||
// close up
|
||||
CGPathAddLineToPoint(filled, &matrix, CGFloat(entries[max(min(Int(ceil(CGFloat(to - from) * phaseX + CGFloat(from))) - 1, entries.count - 1), 0)].xIndex), fillMin)
|
||||
CGPathCloseSubpath(filled)
|
||||
|
||||
return filled
|
||||
}
|
||||
|
||||
public override func drawValues(context context: CGContext?)
|
||||
{
|
||||
let lineData = delegate!.lineChartRendererData(self)
|
||||
if (lineData === nil)
|
||||
{
|
||||
return
|
||||
}
|
||||
|
||||
let defaultValueFormatter = delegate!.lineChartDefaultRendererValueFormatter(self)
|
||||
|
||||
if (CGFloat(lineData.yValCount) < CGFloat(delegate!.lineChartRendererMaxVisibleValueCount(self)) * viewPortHandler.scaleX)
|
||||
{
|
||||
var dataSets = lineData.dataSets
|
||||
|
||||
for (var i = 0; i < dataSets.count; i++)
|
||||
{
|
||||
let dataSet = dataSets[i] as! LineChartDataSet
|
||||
|
||||
if !dataSet.isDrawValuesEnabled || dataSet.entryCount == 0
|
||||
{
|
||||
continue
|
||||
}
|
||||
|
||||
let valueFont = dataSet.valueFont
|
||||
let valueTextColor = dataSet.valueTextColor
|
||||
|
||||
var formatter = dataSet.valueFormatter
|
||||
if (formatter === nil)
|
||||
{
|
||||
formatter = defaultValueFormatter
|
||||
}
|
||||
|
||||
let trans = delegate!.lineChartRenderer(self, transformerForAxis: dataSet.axisDependency)
|
||||
|
||||
// make sure the values do not interfear with the circles
|
||||
var valOffset = Int(dataSet.circleRadius * 1.75)
|
||||
|
||||
if (!dataSet.isDrawCirclesEnabled)
|
||||
{
|
||||
valOffset = valOffset / 2
|
||||
}
|
||||
|
||||
var entries = dataSet.yVals
|
||||
|
||||
let entryFrom = dataSet.entryForXIndex(_minX)
|
||||
let entryTo = dataSet.entryForXIndex(_maxX)
|
||||
|
||||
let minx = max(dataSet.entryIndex(entry: entryFrom!, isEqual: true), 0)
|
||||
let maxx = min(dataSet.entryIndex(entry: entryTo!, isEqual: true) + 1, entries.count)
|
||||
|
||||
var positions = trans.generateTransformedValuesLine(
|
||||
entries,
|
||||
phaseX: _animator.phaseX,
|
||||
phaseY: _animator.phaseY,
|
||||
from: minx,
|
||||
to: maxx)
|
||||
|
||||
for (var j = 0, count = positions.count; j < count; j++)
|
||||
{
|
||||
if (!viewPortHandler.isInBoundsRight(positions[j].x))
|
||||
{
|
||||
break
|
||||
}
|
||||
|
||||
if (!viewPortHandler.isInBoundsLeft(positions[j].x) || !viewPortHandler.isInBoundsY(positions[j].y))
|
||||
{
|
||||
continue
|
||||
}
|
||||
|
||||
let val = entries[j + minx].value
|
||||
|
||||
ChartUtils.drawText(context: context, text: formatter!.stringFromNumber(val)!, point: CGPoint(x: positions[j].x, y: positions[j].y - CGFloat(valOffset) - valueFont.lineHeight), align: .Center, attributes: [NSFontAttributeName: valueFont, NSForegroundColorAttributeName: valueTextColor])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override func drawExtras(context context: CGContext?)
|
||||
{
|
||||
drawCircles(context: context)
|
||||
}
|
||||
|
||||
private func drawCircles(context context: CGContext?)
|
||||
{
|
||||
let phaseX = _animator.phaseX
|
||||
let phaseY = _animator.phaseY
|
||||
|
||||
let lineData = delegate!.lineChartRendererData(self)
|
||||
|
||||
let dataSets = lineData.dataSets
|
||||
|
||||
var pt = CGPoint()
|
||||
var rect = CGRect()
|
||||
|
||||
CGContextSaveGState(context)
|
||||
|
||||
for (var i = 0, count = dataSets.count; i < count; i++)
|
||||
{
|
||||
let dataSet = lineData.getDataSetByIndex(i) as! LineChartDataSet!
|
||||
|
||||
if (!dataSet.isVisible || !dataSet.isDrawCirclesEnabled)
|
||||
{
|
||||
continue
|
||||
}
|
||||
|
||||
let trans = delegate!.lineChartRenderer(self, transformerForAxis: dataSet.axisDependency)
|
||||
let valueToPixelMatrix = trans.valueToPixelMatrix
|
||||
|
||||
var entries = dataSet.yVals
|
||||
|
||||
let circleRadius = dataSet.circleRadius
|
||||
let circleDiameter = circleRadius * 2.0
|
||||
let circleHoleDiameter = circleRadius
|
||||
let circleHoleRadius = circleHoleDiameter / 2.0
|
||||
let isDrawCircleHoleEnabled = dataSet.isDrawCircleHoleEnabled
|
||||
|
||||
let entryFrom = dataSet.entryForXIndex(_minX)!
|
||||
let entryTo = dataSet.entryForXIndex(_maxX)!
|
||||
|
||||
let minx = max(dataSet.entryIndex(entry: entryFrom, isEqual: true), 0)
|
||||
let maxx = min(dataSet.entryIndex(entry: entryTo, isEqual: true) + 1, entries.count)
|
||||
|
||||
for (var j = minx, count = Int(ceil(CGFloat(maxx - minx) * phaseX + CGFloat(minx))); j < count; j++)
|
||||
{
|
||||
let e = entries[j]
|
||||
pt.x = CGFloat(e.xIndex)
|
||||
pt.y = CGFloat(e.value) * phaseY
|
||||
pt = CGPointApplyAffineTransform(pt, valueToPixelMatrix)
|
||||
|
||||
if (!viewPortHandler.isInBoundsRight(pt.x))
|
||||
{
|
||||
break
|
||||
}
|
||||
|
||||
// make sure the circles don't do shitty things outside bounds
|
||||
if (!viewPortHandler.isInBoundsLeft(pt.x) || !viewPortHandler.isInBoundsY(pt.y))
|
||||
{
|
||||
continue
|
||||
}
|
||||
|
||||
CGContextSetFillColorWithColor(context, dataSet.getCircleColor(j)!.CGColor)
|
||||
|
||||
rect.origin.x = pt.x - circleRadius
|
||||
rect.origin.y = pt.y - circleRadius
|
||||
rect.size.width = circleDiameter
|
||||
rect.size.height = circleDiameter
|
||||
CGContextFillEllipseInRect(context, rect)
|
||||
|
||||
if (isDrawCircleHoleEnabled)
|
||||
{
|
||||
CGContextSetFillColorWithColor(context, dataSet.circleHoleColor.CGColor)
|
||||
|
||||
rect.origin.x = pt.x - circleHoleRadius
|
||||
rect.origin.y = pt.y - circleHoleRadius
|
||||
rect.size.width = circleHoleDiameter
|
||||
rect.size.height = circleHoleDiameter
|
||||
CGContextFillEllipseInRect(context, rect)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CGContextRestoreGState(context)
|
||||
}
|
||||
|
||||
private var _highlightPointBuffer = CGPoint()
|
||||
|
||||
public override func drawHighlighted(context context: CGContext?, indices: [ChartHighlight])
|
||||
{
|
||||
let lineData = delegate!.lineChartRendererData(self)
|
||||
let chartXMax = delegate!.lineChartRendererChartXMax(self)
|
||||
CGContextSaveGState(context)
|
||||
|
||||
for (var i = 0; i < indices.count; i++)
|
||||
{
|
||||
let set = lineData.getDataSetByIndex(indices[i].dataSetIndex) as! LineChartDataSet!
|
||||
|
||||
if (set === nil || !set.isHighlightEnabled)
|
||||
{
|
||||
continue
|
||||
}
|
||||
|
||||
CGContextSetStrokeColorWithColor(context, set.highlightColor.CGColor)
|
||||
CGContextSetLineWidth(context, set.highlightLineWidth)
|
||||
if (set.highlightLineDashLengths != nil)
|
||||
{
|
||||
CGContextSetLineDash(context, set.highlightLineDashPhase, set.highlightLineDashLengths!, set.highlightLineDashLengths!.count)
|
||||
}
|
||||
else
|
||||
{
|
||||
CGContextSetLineDash(context, 0.0, nil, 0)
|
||||
}
|
||||
|
||||
let xIndex = indices[i].xIndex; // get the x-position
|
||||
|
||||
if (CGFloat(xIndex) > CGFloat(chartXMax) * _animator.phaseX)
|
||||
{
|
||||
continue
|
||||
}
|
||||
|
||||
let yValue = set.yValForXIndex(xIndex)
|
||||
if (yValue.isNaN)
|
||||
{
|
||||
continue
|
||||
}
|
||||
|
||||
let y = CGFloat(yValue) * _animator.phaseY; // get the y-position
|
||||
|
||||
_highlightPointBuffer.x = CGFloat(xIndex)
|
||||
_highlightPointBuffer.y = y
|
||||
|
||||
let trans = delegate!.lineChartRenderer(self, transformerForAxis: set.axisDependency)
|
||||
|
||||
trans.pointValueToPixel(&_highlightPointBuffer)
|
||||
|
||||
// draw the lines
|
||||
drawHighlightLines(context: context, point: _highlightPointBuffer, set: set)
|
||||
}
|
||||
|
||||
CGContextRestoreGState(context)
|
||||
}
|
||||
}
|
||||
50
Carthage/Checkouts/Charts/Charts/Classes/Renderers/LineScatterCandleRadarChartRenderer.swift
vendored
Normal file
50
Carthage/Checkouts/Charts/Charts/Classes/Renderers/LineScatterCandleRadarChartRenderer.swift
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
//
|
||||
// LineScatterCandleRadarChartRenderer.swift
|
||||
// Charts
|
||||
//
|
||||
// Created by Daniel Cohen Gindi on 29/7/15.
|
||||
//
|
||||
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
|
||||
// A port of MPAndroidChart for iOS
|
||||
// Licensed under Apache License 2.0
|
||||
//
|
||||
// https://github.com/danielgindi/ios-charts
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import CoreGraphics
|
||||
import UIKit
|
||||
|
||||
public class LineScatterCandleRadarChartRenderer: ChartDataRendererBase
|
||||
{
|
||||
public override init(animator: ChartAnimator?, viewPortHandler: ChartViewPortHandler)
|
||||
{
|
||||
super.init(animator: animator, viewPortHandler: viewPortHandler)
|
||||
}
|
||||
|
||||
/// Draws vertical & horizontal highlight-lines if enabled.
|
||||
/// :param: context
|
||||
/// :param: points
|
||||
/// :param: horizontal
|
||||
/// :param: vertical
|
||||
public func drawHighlightLines(context context: CGContext?, point: CGPoint, set: LineScatterCandleChartDataSet)
|
||||
{
|
||||
// draw vertical highlight lines
|
||||
if set.isVerticalHighlightIndicatorEnabled
|
||||
{
|
||||
CGContextBeginPath(context)
|
||||
CGContextMoveToPoint(context, point.x, viewPortHandler.contentTop)
|
||||
CGContextAddLineToPoint(context, point.x, viewPortHandler.contentBottom)
|
||||
CGContextStrokePath(context)
|
||||
}
|
||||
|
||||
// draw horizontal highlight lines
|
||||
if set.isHorizontalHighlightIndicatorEnabled
|
||||
{
|
||||
CGContextBeginPath(context)
|
||||
CGContextMoveToPoint(context, viewPortHandler.contentLeft, point.y)
|
||||
CGContextAddLineToPoint(context, viewPortHandler.contentRight, point.y)
|
||||
CGContextStrokePath(context)
|
||||
}
|
||||
}
|
||||
}
|
||||
391
Carthage/Checkouts/Charts/Charts/Classes/Renderers/PieChartRenderer.swift
vendored
Executable file
391
Carthage/Checkouts/Charts/Charts/Classes/Renderers/PieChartRenderer.swift
vendored
Executable file
@@ -0,0 +1,391 @@
|
||||
//
|
||||
// PieChartRenderer.swift
|
||||
// Charts
|
||||
//
|
||||
// Created by Daniel Cohen Gindi on 4/3/15.
|
||||
//
|
||||
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
|
||||
// A port of MPAndroidChart for iOS
|
||||
// Licensed under Apache License 2.0
|
||||
//
|
||||
// https://github.com/danielgindi/ios-charts
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import CoreGraphics
|
||||
import UIKit
|
||||
|
||||
public class PieChartRenderer: ChartDataRendererBase
|
||||
{
|
||||
internal weak var _chart: PieChartView!
|
||||
|
||||
public var drawHoleEnabled = true
|
||||
public var holeTransparent = true
|
||||
public var holeColor: UIColor? = UIColor.whiteColor()
|
||||
public var holeRadiusPercent = CGFloat(0.5)
|
||||
public var transparentCircleRadiusPercent = CGFloat(0.55)
|
||||
public var centerTextColor = UIColor.blackColor()
|
||||
public var centerTextFont = UIFont.systemFontOfSize(12.0)
|
||||
public var drawXLabelsEnabled = true
|
||||
public var usePercentValuesEnabled = false
|
||||
public var centerText: String!
|
||||
public var drawCenterTextEnabled = true
|
||||
public var centerTextLineBreakMode = NSLineBreakMode.ByTruncatingTail
|
||||
public var centerTextRadiusPercent: CGFloat = 1.0
|
||||
|
||||
public init(chart: PieChartView, animator: ChartAnimator?, viewPortHandler: ChartViewPortHandler)
|
||||
{
|
||||
super.init(animator: animator, viewPortHandler: viewPortHandler)
|
||||
|
||||
_chart = chart
|
||||
}
|
||||
|
||||
public override func drawData(context context: CGContext?)
|
||||
{
|
||||
if (_chart !== nil)
|
||||
{
|
||||
let pieData = _chart.data
|
||||
|
||||
if (pieData != nil)
|
||||
{
|
||||
for set in pieData!.dataSets as! [PieChartDataSet]
|
||||
{
|
||||
if set.isVisible && set.entryCount > 0
|
||||
{
|
||||
drawDataSet(context: context, dataSet: set)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal func drawDataSet(context context: CGContext?, dataSet: PieChartDataSet)
|
||||
{
|
||||
var angle = _chart.rotationAngle
|
||||
|
||||
var cnt = 0
|
||||
|
||||
var entries = dataSet.yVals
|
||||
var drawAngles = _chart.drawAngles
|
||||
let circleBox = _chart.circleBox
|
||||
let radius = _chart.radius
|
||||
let innerRadius = drawHoleEnabled && holeTransparent ? radius * holeRadiusPercent : 0.0
|
||||
|
||||
CGContextSaveGState(context)
|
||||
|
||||
for (var j = 0; j < entries.count; j++)
|
||||
{
|
||||
let newangle = drawAngles[cnt]
|
||||
let sliceSpace = dataSet.sliceSpace
|
||||
|
||||
let e = entries[j]
|
||||
|
||||
// draw only if the value is greater than zero
|
||||
if ((abs(e.value) > 0.000001))
|
||||
{
|
||||
if (!_chart.needsHighlight(xIndex: e.xIndex,
|
||||
dataSetIndex: _chart.data!.indexOfDataSet(dataSet)))
|
||||
{
|
||||
let startAngle = angle + sliceSpace / 2.0
|
||||
var sweepAngle = newangle * _animator.phaseY
|
||||
- sliceSpace / 2.0
|
||||
if (sweepAngle < 0.0)
|
||||
{
|
||||
sweepAngle = 0.0
|
||||
}
|
||||
let endAngle = startAngle + sweepAngle
|
||||
|
||||
let path = CGPathCreateMutable()
|
||||
CGPathMoveToPoint(path, nil, circleBox.midX, circleBox.midY)
|
||||
CGPathAddArc(path, nil, circleBox.midX, circleBox.midY, radius, startAngle * ChartUtils.Math.FDEG2RAD, endAngle * ChartUtils.Math.FDEG2RAD, false)
|
||||
CGPathCloseSubpath(path)
|
||||
|
||||
if (innerRadius > 0.0)
|
||||
{
|
||||
CGPathMoveToPoint(path, nil, circleBox.midX, circleBox.midY)
|
||||
CGPathAddArc(path, nil, circleBox.midX, circleBox.midY, innerRadius, startAngle * ChartUtils.Math.FDEG2RAD, endAngle * ChartUtils.Math.FDEG2RAD, false)
|
||||
CGPathCloseSubpath(path)
|
||||
}
|
||||
|
||||
CGContextBeginPath(context)
|
||||
CGContextAddPath(context, path)
|
||||
CGContextSetFillColorWithColor(context, dataSet.colorAt(j).CGColor)
|
||||
CGContextEOFillPath(context)
|
||||
}
|
||||
}
|
||||
|
||||
angle += newangle * _animator.phaseX
|
||||
cnt++
|
||||
}
|
||||
|
||||
CGContextRestoreGState(context)
|
||||
}
|
||||
|
||||
public override func drawValues(context context: CGContext?)
|
||||
{
|
||||
let center = _chart.centerCircleBox
|
||||
|
||||
// get whole the radius
|
||||
var r = _chart.radius
|
||||
let rotationAngle = _chart.rotationAngle
|
||||
var drawAngles = _chart.drawAngles
|
||||
var absoluteAngles = _chart.absoluteAngles
|
||||
|
||||
var off = r / 10.0 * 3.0
|
||||
|
||||
if (drawHoleEnabled)
|
||||
{
|
||||
off = (r - (r * _chart.holeRadiusPercent)) / 2.0
|
||||
}
|
||||
|
||||
r -= off; // offset to keep things inside the chart
|
||||
|
||||
let data: ChartData! = _chart.data
|
||||
if (data === nil)
|
||||
{
|
||||
return
|
||||
}
|
||||
|
||||
let defaultValueFormatter = _chart.valueFormatter
|
||||
|
||||
var dataSets = data.dataSets
|
||||
let drawXVals = drawXLabelsEnabled
|
||||
|
||||
var cnt = 0
|
||||
|
||||
for (var i = 0; i < dataSets.count; i++)
|
||||
{
|
||||
let dataSet = dataSets[i] as! PieChartDataSet
|
||||
|
||||
let drawYVals = dataSet.isDrawValuesEnabled
|
||||
|
||||
if (!drawYVals && !drawXVals)
|
||||
{
|
||||
continue
|
||||
}
|
||||
|
||||
let valueFont = dataSet.valueFont
|
||||
let valueTextColor = dataSet.valueTextColor
|
||||
|
||||
var formatter = dataSet.valueFormatter
|
||||
if (formatter === nil)
|
||||
{
|
||||
formatter = defaultValueFormatter
|
||||
}
|
||||
|
||||
var entries = dataSet.yVals
|
||||
|
||||
for (var j = 0, maxEntry = Int(min(ceil(CGFloat(entries.count) * _animator.phaseX), CGFloat(entries.count))); j < maxEntry; j++)
|
||||
{
|
||||
if (drawXVals && !drawYVals && (j >= data.xValCount || data.xVals[j] == nil))
|
||||
{
|
||||
continue
|
||||
}
|
||||
|
||||
// offset needed to center the drawn text in the slice
|
||||
let offset = drawAngles[cnt] / 2.0
|
||||
|
||||
// calculate the text position
|
||||
let x = (r * cos(((rotationAngle + absoluteAngles[cnt] - offset) * _animator.phaseY) * ChartUtils.Math.FDEG2RAD) + center.x)
|
||||
var y = (r * sin(((rotationAngle + absoluteAngles[cnt] - offset) * _animator.phaseY) * ChartUtils.Math.FDEG2RAD) + center.y)
|
||||
|
||||
let value = usePercentValuesEnabled ? entries[j].value / data.yValueSum * 100.0 : entries[j].value
|
||||
|
||||
let val = formatter!.stringFromNumber(value)!
|
||||
|
||||
let lineHeight = valueFont.lineHeight
|
||||
y -= lineHeight
|
||||
|
||||
// draw everything, depending on settings
|
||||
if (drawXVals && drawYVals)
|
||||
{
|
||||
ChartUtils.drawText(context: context, text: val, point: CGPoint(x: x, y: y), align: .Center, attributes: [NSFontAttributeName: valueFont, NSForegroundColorAttributeName: valueTextColor])
|
||||
|
||||
if (j < data.xValCount && data.xVals[j] != nil)
|
||||
{
|
||||
ChartUtils.drawText(context: context, text: data.xVals[j]!, point: CGPoint(x: x, y: y + lineHeight), align: .Center, attributes: [NSFontAttributeName: valueFont, NSForegroundColorAttributeName: valueTextColor])
|
||||
}
|
||||
}
|
||||
else if (drawXVals && !drawYVals)
|
||||
{
|
||||
ChartUtils.drawText(context: context, text: data.xVals[j]!, point: CGPoint(x: x, y: y + lineHeight / 2.0), align: .Center, attributes: [NSFontAttributeName: valueFont, NSForegroundColorAttributeName: valueTextColor])
|
||||
}
|
||||
else if (!drawXVals && drawYVals)
|
||||
{
|
||||
ChartUtils.drawText(context: context, text: val, point: CGPoint(x: x, y: y + lineHeight / 2.0), align: .Center, attributes: [NSFontAttributeName: valueFont, NSForegroundColorAttributeName: valueTextColor])
|
||||
}
|
||||
|
||||
cnt++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override func drawExtras(context context: CGContext?)
|
||||
{
|
||||
drawHole(context: context)
|
||||
drawCenterText(context: context)
|
||||
}
|
||||
|
||||
/// draws the hole in the center of the chart and the transparent circle / hole
|
||||
private func drawHole(context context: CGContext?)
|
||||
{
|
||||
if (_chart.drawHoleEnabled)
|
||||
{
|
||||
CGContextSaveGState(context)
|
||||
|
||||
let radius = _chart.radius
|
||||
let holeRadius = radius * holeRadiusPercent
|
||||
let center = _chart.centerCircleBox
|
||||
|
||||
if (holeColor !== nil && holeColor != UIColor.clearColor())
|
||||
{
|
||||
// draw the hole-circle
|
||||
CGContextSetFillColorWithColor(context, holeColor!.CGColor)
|
||||
CGContextFillEllipseInRect(context, CGRect(x: center.x - holeRadius, y: center.y - holeRadius, width: holeRadius * 2.0, height: holeRadius * 2.0))
|
||||
}
|
||||
|
||||
if (transparentCircleRadiusPercent > holeRadiusPercent)
|
||||
{
|
||||
let secondHoleRadius = radius * transparentCircleRadiusPercent
|
||||
|
||||
// make transparent
|
||||
CGContextSetFillColorWithColor(context, holeColor!.colorWithAlphaComponent(CGFloat(0x60) / CGFloat(0xFF)).CGColor)
|
||||
|
||||
// draw the transparent-circle
|
||||
CGContextFillEllipseInRect(context, CGRect(x: center.x - secondHoleRadius, y: center.y - secondHoleRadius, width: secondHoleRadius * 2.0, height: secondHoleRadius * 2.0))
|
||||
}
|
||||
|
||||
CGContextRestoreGState(context)
|
||||
}
|
||||
}
|
||||
|
||||
/// draws the description text in the center of the pie chart makes most sense when center-hole is enabled
|
||||
private func drawCenterText(context context: CGContext?)
|
||||
{
|
||||
if (drawCenterTextEnabled && centerText != nil && centerText.characters.count > 0)
|
||||
{
|
||||
let center = _chart.centerCircleBox
|
||||
let innerRadius = drawHoleEnabled && holeTransparent ? _chart.radius * holeRadiusPercent : _chart.radius
|
||||
let holeRect = CGRect(x: center.x - innerRadius, y: center.y - innerRadius, width: innerRadius * 2.0, height: innerRadius * 2.0)
|
||||
var boundingRect = holeRect
|
||||
|
||||
if (centerTextRadiusPercent > 0.0)
|
||||
{
|
||||
boundingRect = CGRectInset(boundingRect, (boundingRect.width - boundingRect.width * centerTextRadiusPercent) / 2.0, (boundingRect.height - boundingRect.height * centerTextRadiusPercent) / 2.0)
|
||||
}
|
||||
|
||||
let centerTextNs = self.centerText as NSString
|
||||
|
||||
let paragraphStyle = NSParagraphStyle.defaultParagraphStyle().mutableCopy() as! NSMutableParagraphStyle
|
||||
paragraphStyle.lineBreakMode = centerTextLineBreakMode
|
||||
paragraphStyle.alignment = .Center
|
||||
|
||||
let drawingAttrs = [NSFontAttributeName: centerTextFont, NSParagraphStyleAttributeName: paragraphStyle, NSForegroundColorAttributeName: centerTextColor]
|
||||
|
||||
let textBounds = centerTextNs.boundingRectWithSize(boundingRect.size, options: [.UsesLineFragmentOrigin, .UsesFontLeading, .TruncatesLastVisibleLine], attributes: drawingAttrs, context: nil)
|
||||
|
||||
var drawingRect = boundingRect
|
||||
drawingRect.origin.x += (boundingRect.size.width - textBounds.size.width) / 2.0
|
||||
drawingRect.origin.y += (boundingRect.size.height - textBounds.size.height) / 2.0
|
||||
drawingRect.size = textBounds.size
|
||||
|
||||
CGContextSaveGState(context)
|
||||
|
||||
let clippingPath = CGPathCreateWithEllipseInRect(holeRect, nil)
|
||||
CGContextBeginPath(context)
|
||||
CGContextAddPath(context, clippingPath)
|
||||
CGContextClip(context)
|
||||
|
||||
centerTextNs.drawWithRect(drawingRect, options: [.UsesLineFragmentOrigin, .UsesFontLeading, .TruncatesLastVisibleLine], attributes: drawingAttrs, context: nil)
|
||||
|
||||
CGContextRestoreGState(context)
|
||||
}
|
||||
}
|
||||
|
||||
public override func drawHighlighted(context context: CGContext?, indices: [ChartHighlight])
|
||||
{
|
||||
if (_chart.data === nil)
|
||||
{
|
||||
return
|
||||
}
|
||||
|
||||
CGContextSaveGState(context)
|
||||
|
||||
let rotationAngle = _chart.rotationAngle
|
||||
var angle = CGFloat(0.0)
|
||||
|
||||
var drawAngles = _chart.drawAngles
|
||||
var absoluteAngles = _chart.absoluteAngles
|
||||
|
||||
let innerRadius = drawHoleEnabled && holeTransparent ? _chart.radius * holeRadiusPercent : 0.0
|
||||
|
||||
for (var i = 0; i < indices.count; i++)
|
||||
{
|
||||
// get the index to highlight
|
||||
let xIndex = indices[i].xIndex
|
||||
if (xIndex >= drawAngles.count)
|
||||
{
|
||||
continue
|
||||
}
|
||||
|
||||
let set = _chart.data?.getDataSetByIndex(indices[i].dataSetIndex) as! PieChartDataSet!
|
||||
|
||||
if (set === nil || !set.isHighlightEnabled)
|
||||
{
|
||||
continue
|
||||
}
|
||||
|
||||
if (xIndex == 0)
|
||||
{
|
||||
angle = rotationAngle
|
||||
}
|
||||
else
|
||||
{
|
||||
angle = rotationAngle + absoluteAngles[xIndex - 1]
|
||||
}
|
||||
|
||||
angle *= _animator.phaseY
|
||||
|
||||
let sliceDegrees = drawAngles[xIndex]
|
||||
|
||||
let shift = set.selectionShift
|
||||
let circleBox = _chart.circleBox
|
||||
|
||||
let highlighted = CGRect(
|
||||
x: circleBox.origin.x - shift,
|
||||
y: circleBox.origin.y - shift,
|
||||
width: circleBox.size.width + shift * 2.0,
|
||||
height: circleBox.size.height + shift * 2.0)
|
||||
|
||||
CGContextSetFillColorWithColor(context, set.colorAt(xIndex).CGColor)
|
||||
|
||||
// redefine the rect that contains the arc so that the highlighted pie is not cut off
|
||||
|
||||
let startAngle = angle + set.sliceSpace / 2.0
|
||||
var sweepAngle = sliceDegrees * _animator.phaseY - set.sliceSpace / 2.0
|
||||
if (sweepAngle < 0.0)
|
||||
{
|
||||
sweepAngle = 0.0
|
||||
}
|
||||
let endAngle = startAngle + sweepAngle
|
||||
|
||||
let path = CGPathCreateMutable()
|
||||
CGPathMoveToPoint(path, nil, highlighted.midX, highlighted.midY)
|
||||
CGPathAddArc(path, nil, highlighted.midX, highlighted.midY, highlighted.size.width / 2.0, startAngle * ChartUtils.Math.FDEG2RAD, endAngle * ChartUtils.Math.FDEG2RAD, false)
|
||||
CGPathCloseSubpath(path)
|
||||
|
||||
if (innerRadius > 0.0)
|
||||
{
|
||||
CGPathMoveToPoint(path, nil, highlighted.midX, highlighted.midY)
|
||||
CGPathAddArc(path, nil, highlighted.midX, highlighted.midY, innerRadius, startAngle * ChartUtils.Math.FDEG2RAD, endAngle * ChartUtils.Math.FDEG2RAD, false)
|
||||
CGPathCloseSubpath(path)
|
||||
}
|
||||
|
||||
CGContextBeginPath(context)
|
||||
CGContextAddPath(context, path)
|
||||
CGContextEOFillPath(context)
|
||||
}
|
||||
|
||||
CGContextRestoreGState(context)
|
||||
}
|
||||
}
|
||||
294
Carthage/Checkouts/Charts/Charts/Classes/Renderers/RadarChartRenderer.swift
vendored
Normal file
294
Carthage/Checkouts/Charts/Charts/Classes/Renderers/RadarChartRenderer.swift
vendored
Normal file
@@ -0,0 +1,294 @@
|
||||
//
|
||||
// RadarChartRenderer.swift
|
||||
// Charts
|
||||
//
|
||||
// Created by Daniel Cohen Gindi on 4/3/15.
|
||||
//
|
||||
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
|
||||
// A port of MPAndroidChart for iOS
|
||||
// Licensed under Apache License 2.0
|
||||
//
|
||||
// https://github.com/danielgindi/ios-charts
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import CoreGraphics
|
||||
import UIKit
|
||||
|
||||
public class RadarChartRenderer: LineScatterCandleRadarChartRenderer
|
||||
{
|
||||
internal weak var _chart: RadarChartView!
|
||||
|
||||
public init(chart: RadarChartView, animator: ChartAnimator?, viewPortHandler: ChartViewPortHandler)
|
||||
{
|
||||
super.init(animator: animator, viewPortHandler: viewPortHandler)
|
||||
|
||||
_chart = chart
|
||||
}
|
||||
|
||||
public override func drawData(context context: CGContext?)
|
||||
{
|
||||
if (_chart !== nil)
|
||||
{
|
||||
let radarData = _chart.data
|
||||
|
||||
if (radarData != nil)
|
||||
{
|
||||
for set in radarData!.dataSets as! [RadarChartDataSet]
|
||||
{
|
||||
if set.isVisible && set.entryCount > 0
|
||||
{
|
||||
drawDataSet(context: context, dataSet: set)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal func drawDataSet(context context: CGContext?, dataSet: RadarChartDataSet)
|
||||
{
|
||||
CGContextSaveGState(context)
|
||||
|
||||
let sliceangle = _chart.sliceAngle
|
||||
|
||||
// calculate the factor that is needed for transforming the value to pixels
|
||||
let factor = _chart.factor
|
||||
|
||||
let center = _chart.centerOffsets
|
||||
var entries = dataSet.yVals
|
||||
let path = CGPathCreateMutable()
|
||||
var hasMovedToPoint = false
|
||||
|
||||
for (var j = 0; j < entries.count; j++)
|
||||
{
|
||||
let e = entries[j]
|
||||
|
||||
let p = ChartUtils.getPosition(center: center, dist: CGFloat(e.value - _chart.chartYMin) * factor, angle: sliceangle * CGFloat(j) + _chart.rotationAngle)
|
||||
|
||||
if (p.x.isNaN)
|
||||
{
|
||||
continue
|
||||
}
|
||||
|
||||
if (!hasMovedToPoint)
|
||||
{
|
||||
CGPathMoveToPoint(path, nil, p.x, p.y)
|
||||
hasMovedToPoint = true
|
||||
}
|
||||
else
|
||||
{
|
||||
CGPathAddLineToPoint(path, nil, p.x, p.y)
|
||||
}
|
||||
}
|
||||
|
||||
CGPathCloseSubpath(path)
|
||||
|
||||
// draw filled
|
||||
if (dataSet.isDrawFilledEnabled)
|
||||
{
|
||||
CGContextSetFillColorWithColor(context, dataSet.colorAt(0).CGColor)
|
||||
CGContextSetAlpha(context, dataSet.fillAlpha)
|
||||
|
||||
CGContextBeginPath(context)
|
||||
CGContextAddPath(context, path)
|
||||
CGContextFillPath(context)
|
||||
}
|
||||
|
||||
// draw the line (only if filled is disabled or alpha is below 255)
|
||||
if (!dataSet.isDrawFilledEnabled || dataSet.fillAlpha < 1.0)
|
||||
{
|
||||
CGContextSetStrokeColorWithColor(context, dataSet.colorAt(0).CGColor)
|
||||
CGContextSetLineWidth(context, dataSet.lineWidth)
|
||||
CGContextSetAlpha(context, 1.0)
|
||||
|
||||
CGContextBeginPath(context)
|
||||
CGContextAddPath(context, path)
|
||||
CGContextStrokePath(context)
|
||||
}
|
||||
|
||||
CGContextRestoreGState(context)
|
||||
}
|
||||
|
||||
public override func drawValues(context context: CGContext?)
|
||||
{
|
||||
if (_chart.data === nil)
|
||||
{
|
||||
return
|
||||
}
|
||||
|
||||
let data = _chart.data!
|
||||
|
||||
let defaultValueFormatter = _chart.valueFormatter
|
||||
|
||||
let sliceangle = _chart.sliceAngle
|
||||
|
||||
// calculate the factor that is needed for transforming the value to pixels
|
||||
let factor = _chart.factor
|
||||
|
||||
let center = _chart.centerOffsets
|
||||
|
||||
let yoffset = CGFloat(5.0)
|
||||
|
||||
for (var i = 0, count = data.dataSetCount; i < count; i++)
|
||||
{
|
||||
let dataSet = data.getDataSetByIndex(i) as! RadarChartDataSet
|
||||
|
||||
if !dataSet.isDrawValuesEnabled || dataSet.entryCount == 0
|
||||
{
|
||||
continue
|
||||
}
|
||||
|
||||
var entries = dataSet.yVals
|
||||
|
||||
for (var j = 0; j < entries.count; j++)
|
||||
{
|
||||
let e = entries[j]
|
||||
|
||||
let p = ChartUtils.getPosition(center: center, dist: CGFloat(e.value) * factor, angle: sliceangle * CGFloat(j) + _chart.rotationAngle)
|
||||
|
||||
let valueFont = dataSet.valueFont
|
||||
let valueTextColor = dataSet.valueTextColor
|
||||
|
||||
var formatter = dataSet.valueFormatter
|
||||
if (formatter === nil)
|
||||
{
|
||||
formatter = defaultValueFormatter
|
||||
}
|
||||
|
||||
ChartUtils.drawText(context: context, text: formatter!.stringFromNumber(e.value)!, point: CGPoint(x: p.x, y: p.y - yoffset - valueFont.lineHeight), align: .Center, attributes: [NSFontAttributeName: valueFont, NSForegroundColorAttributeName: valueTextColor])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override func drawExtras(context context: CGContext?)
|
||||
{
|
||||
drawWeb(context: context)
|
||||
}
|
||||
|
||||
private var _webLineSegmentsBuffer = [CGPoint](count: 2, repeatedValue: CGPoint())
|
||||
|
||||
internal func drawWeb(context context: CGContext?)
|
||||
{
|
||||
let sliceangle = _chart.sliceAngle
|
||||
|
||||
CGContextSaveGState(context)
|
||||
|
||||
// calculate the factor that is needed for transforming the value to
|
||||
// pixels
|
||||
let factor = _chart.factor
|
||||
let rotationangle = _chart.rotationAngle
|
||||
|
||||
let center = _chart.centerOffsets
|
||||
|
||||
// draw the web lines that come from the center
|
||||
CGContextSetLineWidth(context, _chart.webLineWidth)
|
||||
CGContextSetStrokeColorWithColor(context, _chart.webColor.CGColor)
|
||||
CGContextSetAlpha(context, _chart.webAlpha)
|
||||
|
||||
let xIncrements = 1 + _chart.skipWebLineCount
|
||||
|
||||
for var i = 0, xValCount = _chart.data!.xValCount; i < xValCount; i += xIncrements
|
||||
{
|
||||
let p = ChartUtils.getPosition(center: center, dist: CGFloat(_chart.yRange) * factor, angle: sliceangle * CGFloat(i) + rotationangle)
|
||||
|
||||
_webLineSegmentsBuffer[0].x = center.x
|
||||
_webLineSegmentsBuffer[0].y = center.y
|
||||
_webLineSegmentsBuffer[1].x = p.x
|
||||
_webLineSegmentsBuffer[1].y = p.y
|
||||
|
||||
CGContextStrokeLineSegments(context, _webLineSegmentsBuffer, 2)
|
||||
}
|
||||
|
||||
// draw the inner-web
|
||||
CGContextSetLineWidth(context, _chart.innerWebLineWidth)
|
||||
CGContextSetStrokeColorWithColor(context, _chart.innerWebColor.CGColor)
|
||||
CGContextSetAlpha(context, _chart.webAlpha)
|
||||
|
||||
let labelCount = _chart.yAxis.entryCount
|
||||
|
||||
for (var j = 0; j < labelCount; j++)
|
||||
{
|
||||
for (var i = 0, xValCount = _chart.data!.xValCount; i < xValCount; i++)
|
||||
{
|
||||
let r = CGFloat(_chart.yAxis.entries[j] - _chart.chartYMin) * factor
|
||||
|
||||
let p1 = ChartUtils.getPosition(center: center, dist: r, angle: sliceangle * CGFloat(i) + rotationangle)
|
||||
let p2 = ChartUtils.getPosition(center: center, dist: r, angle: sliceangle * CGFloat(i + 1) + rotationangle)
|
||||
|
||||
_webLineSegmentsBuffer[0].x = p1.x
|
||||
_webLineSegmentsBuffer[0].y = p1.y
|
||||
_webLineSegmentsBuffer[1].x = p2.x
|
||||
_webLineSegmentsBuffer[1].y = p2.y
|
||||
|
||||
CGContextStrokeLineSegments(context, _webLineSegmentsBuffer, 2)
|
||||
}
|
||||
}
|
||||
|
||||
CGContextRestoreGState(context)
|
||||
}
|
||||
|
||||
private var _highlightPointBuffer = CGPoint()
|
||||
|
||||
public override func drawHighlighted(context context: CGContext?, indices: [ChartHighlight])
|
||||
{
|
||||
if (_chart.data === nil)
|
||||
{
|
||||
return
|
||||
}
|
||||
|
||||
let data = _chart.data as! RadarChartData
|
||||
|
||||
CGContextSaveGState(context)
|
||||
CGContextSetLineWidth(context, data.highlightLineWidth)
|
||||
if (data.highlightLineDashLengths != nil)
|
||||
{
|
||||
CGContextSetLineDash(context, data.highlightLineDashPhase, data.highlightLineDashLengths!, data.highlightLineDashLengths!.count)
|
||||
}
|
||||
else
|
||||
{
|
||||
CGContextSetLineDash(context, 0.0, nil, 0)
|
||||
}
|
||||
|
||||
let sliceangle = _chart.sliceAngle
|
||||
let factor = _chart.factor
|
||||
|
||||
let center = _chart.centerOffsets
|
||||
|
||||
for (var i = 0; i < indices.count; i++)
|
||||
{
|
||||
let set = _chart.data?.getDataSetByIndex(indices[i].dataSetIndex) as! RadarChartDataSet!
|
||||
|
||||
if (set === nil || !set.isHighlightEnabled)
|
||||
{
|
||||
continue
|
||||
}
|
||||
|
||||
CGContextSetStrokeColorWithColor(context, set.highlightColor.CGColor)
|
||||
|
||||
// get the index to highlight
|
||||
let xIndex = indices[i].xIndex
|
||||
|
||||
let e = set.entryForXIndex(xIndex)
|
||||
if (e === nil || e!.xIndex != xIndex)
|
||||
{
|
||||
continue
|
||||
}
|
||||
|
||||
let j = set.entryIndex(entry: e!, isEqual: true)
|
||||
let y = (e!.value - _chart.chartYMin)
|
||||
|
||||
if (y.isNaN)
|
||||
{
|
||||
continue
|
||||
}
|
||||
|
||||
_highlightPointBuffer = ChartUtils.getPosition(center: center, dist: CGFloat(y) * factor,
|
||||
angle: sliceangle * CGFloat(j) + _chart.rotationAngle)
|
||||
|
||||
// draw the lines
|
||||
drawHighlightLines(context: context, point: _highlightPointBuffer, set: set)
|
||||
}
|
||||
|
||||
CGContextRestoreGState(context)
|
||||
}
|
||||
}
|
||||
299
Carthage/Checkouts/Charts/Charts/Classes/Renderers/ScatterChartRenderer.swift
vendored
Normal file
299
Carthage/Checkouts/Charts/Charts/Classes/Renderers/ScatterChartRenderer.swift
vendored
Normal file
@@ -0,0 +1,299 @@
|
||||
//
|
||||
// ScatterChartRenderer.swift
|
||||
// Charts
|
||||
//
|
||||
// Created by Daniel Cohen Gindi on 4/3/15.
|
||||
//
|
||||
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
|
||||
// A port of MPAndroidChart for iOS
|
||||
// Licensed under Apache License 2.0
|
||||
//
|
||||
// https://github.com/danielgindi/ios-charts
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import CoreGraphics
|
||||
import UIKit
|
||||
|
||||
@objc
|
||||
public protocol ScatterChartRendererDelegate
|
||||
{
|
||||
func scatterChartRendererData(renderer: ScatterChartRenderer) -> ScatterChartData!
|
||||
func scatterChartRenderer(renderer: ScatterChartRenderer, transformerForAxis which: ChartYAxis.AxisDependency) -> ChartTransformer!
|
||||
func scatterChartDefaultRendererValueFormatter(renderer: ScatterChartRenderer) -> NSNumberFormatter!
|
||||
func scatterChartRendererChartYMax(renderer: ScatterChartRenderer) -> Double
|
||||
func scatterChartRendererChartYMin(renderer: ScatterChartRenderer) -> Double
|
||||
func scatterChartRendererChartXMax(renderer: ScatterChartRenderer) -> Double
|
||||
func scatterChartRendererChartXMin(renderer: ScatterChartRenderer) -> Double
|
||||
func scatterChartRendererMaxVisibleValueCount(renderer: ScatterChartRenderer) -> Int
|
||||
}
|
||||
|
||||
public class ScatterChartRenderer: LineScatterCandleRadarChartRenderer
|
||||
{
|
||||
public weak var delegate: ScatterChartRendererDelegate?
|
||||
|
||||
public init(delegate: ScatterChartRendererDelegate?, animator: ChartAnimator?, viewPortHandler: ChartViewPortHandler)
|
||||
{
|
||||
super.init(animator: animator, viewPortHandler: viewPortHandler)
|
||||
|
||||
self.delegate = delegate
|
||||
}
|
||||
|
||||
public override func drawData(context context: CGContext?)
|
||||
{
|
||||
let scatterData = delegate!.scatterChartRendererData(self)
|
||||
|
||||
if (scatterData === nil)
|
||||
{
|
||||
return
|
||||
}
|
||||
|
||||
for (var i = 0; i < scatterData.dataSetCount; i++)
|
||||
{
|
||||
let set = scatterData.getDataSetByIndex(i)
|
||||
|
||||
if (set !== nil && set!.isVisible)
|
||||
{
|
||||
drawDataSet(context: context, dataSet: set as! ScatterChartDataSet)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private var _lineSegments = [CGPoint](count: 2, repeatedValue: CGPoint())
|
||||
|
||||
internal func drawDataSet(context context: CGContext?, dataSet: ScatterChartDataSet)
|
||||
{
|
||||
let trans = delegate!.scatterChartRenderer(self, transformerForAxis: dataSet.axisDependency)
|
||||
|
||||
let phaseY = _animator.phaseY
|
||||
|
||||
var entries = dataSet.yVals
|
||||
|
||||
let shapeSize = dataSet.scatterShapeSize
|
||||
let shapeHalf = shapeSize / 2.0
|
||||
|
||||
var point = CGPoint()
|
||||
|
||||
let valueToPixelMatrix = trans.valueToPixelMatrix
|
||||
|
||||
let shape = dataSet.scatterShape
|
||||
|
||||
CGContextSaveGState(context)
|
||||
|
||||
for (var j = 0, count = Int(min(ceil(CGFloat(entries.count) * _animator.phaseX), CGFloat(entries.count))); j < count; j++)
|
||||
{
|
||||
let e = entries[j]
|
||||
point.x = CGFloat(e.xIndex)
|
||||
point.y = CGFloat(e.value) * phaseY
|
||||
point = CGPointApplyAffineTransform(point, valueToPixelMatrix);
|
||||
|
||||
if (!viewPortHandler.isInBoundsRight(point.x))
|
||||
{
|
||||
break
|
||||
}
|
||||
|
||||
if (!viewPortHandler.isInBoundsLeft(point.x) || !viewPortHandler.isInBoundsY(point.y))
|
||||
{
|
||||
continue
|
||||
}
|
||||
|
||||
if (shape == .Square)
|
||||
{
|
||||
CGContextSetFillColorWithColor(context, dataSet.colorAt(j).CGColor)
|
||||
var rect = CGRect()
|
||||
rect.origin.x = point.x - shapeHalf
|
||||
rect.origin.y = point.y - shapeHalf
|
||||
rect.size.width = shapeSize
|
||||
rect.size.height = shapeSize
|
||||
CGContextFillRect(context, rect)
|
||||
}
|
||||
else if (shape == .Circle)
|
||||
{
|
||||
CGContextSetFillColorWithColor(context, dataSet.colorAt(j).CGColor)
|
||||
var rect = CGRect()
|
||||
rect.origin.x = point.x - shapeHalf
|
||||
rect.origin.y = point.y - shapeHalf
|
||||
rect.size.width = shapeSize
|
||||
rect.size.height = shapeSize
|
||||
CGContextFillEllipseInRect(context, rect)
|
||||
}
|
||||
else if (shape == .Cross)
|
||||
{
|
||||
CGContextSetStrokeColorWithColor(context, dataSet.colorAt(j).CGColor)
|
||||
_lineSegments[0].x = point.x - shapeHalf
|
||||
_lineSegments[0].y = point.y
|
||||
_lineSegments[1].x = point.x + shapeHalf
|
||||
_lineSegments[1].y = point.y
|
||||
CGContextStrokeLineSegments(context, _lineSegments, 2)
|
||||
|
||||
_lineSegments[0].x = point.x
|
||||
_lineSegments[0].y = point.y - shapeHalf
|
||||
_lineSegments[1].x = point.x
|
||||
_lineSegments[1].y = point.y + shapeHalf
|
||||
CGContextStrokeLineSegments(context, _lineSegments, 2)
|
||||
}
|
||||
else if (shape == .Triangle)
|
||||
{
|
||||
CGContextSetFillColorWithColor(context, dataSet.colorAt(j).CGColor)
|
||||
|
||||
// create a triangle path
|
||||
CGContextBeginPath(context)
|
||||
CGContextMoveToPoint(context, point.x, point.y - shapeHalf)
|
||||
CGContextAddLineToPoint(context, point.x + shapeHalf, point.y + shapeHalf)
|
||||
CGContextAddLineToPoint(context, point.x - shapeHalf, point.y + shapeHalf)
|
||||
CGContextClosePath(context)
|
||||
|
||||
CGContextFillPath(context)
|
||||
}
|
||||
else if (shape == .Custom)
|
||||
{
|
||||
CGContextSetFillColorWithColor(context, dataSet.colorAt(j).CGColor)
|
||||
|
||||
let customShape = dataSet.customScatterShape
|
||||
|
||||
if (customShape === nil)
|
||||
{
|
||||
return
|
||||
}
|
||||
|
||||
// transform the provided custom path
|
||||
CGContextSaveGState(context)
|
||||
CGContextTranslateCTM(context, point.x, point.y)
|
||||
|
||||
CGContextBeginPath(context)
|
||||
CGContextAddPath(context, customShape)
|
||||
CGContextFillPath(context)
|
||||
|
||||
CGContextRestoreGState(context)
|
||||
}
|
||||
}
|
||||
|
||||
CGContextRestoreGState(context)
|
||||
}
|
||||
|
||||
public override func drawValues(context context: CGContext?)
|
||||
{
|
||||
let scatterData = delegate!.scatterChartRendererData(self)
|
||||
if (scatterData === nil)
|
||||
{
|
||||
return
|
||||
}
|
||||
|
||||
let defaultValueFormatter = delegate!.scatterChartDefaultRendererValueFormatter(self)
|
||||
|
||||
// if values are drawn
|
||||
if (scatterData.yValCount < Int(ceil(CGFloat(delegate!.scatterChartRendererMaxVisibleValueCount(self)) * viewPortHandler.scaleX)))
|
||||
{
|
||||
var dataSets = scatterData.dataSets as! [ScatterChartDataSet]
|
||||
|
||||
for (var i = 0; i < scatterData.dataSetCount; i++)
|
||||
{
|
||||
let dataSet = dataSets[i]
|
||||
|
||||
if !dataSet.isDrawValuesEnabled || dataSet.entryCount == 0
|
||||
{
|
||||
continue
|
||||
}
|
||||
|
||||
let valueFont = dataSet.valueFont
|
||||
let valueTextColor = dataSet.valueTextColor
|
||||
|
||||
var formatter = dataSet.valueFormatter
|
||||
if (formatter === nil)
|
||||
{
|
||||
formatter = defaultValueFormatter
|
||||
}
|
||||
|
||||
var entries = dataSet.yVals
|
||||
|
||||
var positions = delegate!.scatterChartRenderer(self, transformerForAxis: dataSet.axisDependency).generateTransformedValuesScatter(entries, phaseY: _animator.phaseY)
|
||||
|
||||
let shapeSize = dataSet.scatterShapeSize
|
||||
let lineHeight = valueFont.lineHeight
|
||||
|
||||
for (var j = 0, count = Int(ceil(CGFloat(positions.count) * _animator.phaseX)); j < count; j++)
|
||||
{
|
||||
if (!viewPortHandler.isInBoundsRight(positions[j].x))
|
||||
{
|
||||
break
|
||||
}
|
||||
|
||||
// make sure the lines don't do shitty things outside bounds
|
||||
if ((!viewPortHandler.isInBoundsLeft(positions[j].x)
|
||||
|| !viewPortHandler.isInBoundsY(positions[j].y)))
|
||||
{
|
||||
continue
|
||||
}
|
||||
|
||||
let val = entries[j].value
|
||||
|
||||
let text = formatter!.stringFromNumber(val)
|
||||
|
||||
ChartUtils.drawText(context: context, text: text!, point: CGPoint(x: positions[j].x, y: positions[j].y - shapeSize - lineHeight), align: .Center, attributes: [NSFontAttributeName: valueFont, NSForegroundColorAttributeName: valueTextColor])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override func drawExtras(context context: CGContext?)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private var _highlightPointBuffer = CGPoint()
|
||||
|
||||
public override func drawHighlighted(context context: CGContext?, indices: [ChartHighlight])
|
||||
{
|
||||
let scatterData = delegate!.scatterChartRendererData(self)
|
||||
let chartXMax = delegate!.scatterChartRendererChartXMax(self)
|
||||
CGContextSaveGState(context)
|
||||
|
||||
for (var i = 0; i < indices.count; i++)
|
||||
{
|
||||
let set = scatterData.getDataSetByIndex(indices[i].dataSetIndex) as! ScatterChartDataSet!
|
||||
|
||||
if (set === nil || !set.isHighlightEnabled)
|
||||
{
|
||||
continue
|
||||
}
|
||||
|
||||
CGContextSetStrokeColorWithColor(context, set.highlightColor.CGColor)
|
||||
CGContextSetLineWidth(context, set.highlightLineWidth)
|
||||
if (set.highlightLineDashLengths != nil)
|
||||
{
|
||||
CGContextSetLineDash(context, set.highlightLineDashPhase, set.highlightLineDashLengths!, set.highlightLineDashLengths!.count)
|
||||
}
|
||||
else
|
||||
{
|
||||
CGContextSetLineDash(context, 0.0, nil, 0)
|
||||
}
|
||||
|
||||
let xIndex = indices[i].xIndex; // get the x-position
|
||||
|
||||
if (CGFloat(xIndex) > CGFloat(chartXMax) * _animator.phaseX)
|
||||
{
|
||||
continue
|
||||
}
|
||||
|
||||
let yVal = set.yValForXIndex(xIndex)
|
||||
if (yVal.isNaN)
|
||||
{
|
||||
continue
|
||||
}
|
||||
|
||||
let y = CGFloat(yVal) * _animator.phaseY; // get the y-position
|
||||
|
||||
_highlightPointBuffer.x = CGFloat(xIndex)
|
||||
_highlightPointBuffer.y = y
|
||||
|
||||
let trans = delegate!.scatterChartRenderer(self, transformerForAxis: set.axisDependency)
|
||||
|
||||
trans.pointValueToPixel(&_highlightPointBuffer)
|
||||
|
||||
// draw the lines
|
||||
drawHighlightLines(context: context, point: _highlightPointBuffer, set: set)
|
||||
}
|
||||
|
||||
CGContextRestoreGState(context)
|
||||
}
|
||||
}
|
||||
74
Carthage/Checkouts/Charts/Charts/Classes/Utils/ChartColorTemplates.swift
vendored
Normal file
74
Carthage/Checkouts/Charts/Charts/Classes/Utils/ChartColorTemplates.swift
vendored
Normal file
@@ -0,0 +1,74 @@
|
||||
//
|
||||
// ChartColorTemplates.swift
|
||||
// Charts
|
||||
//
|
||||
// Created by Daniel Cohen Gindi on 23/2/15.
|
||||
|
||||
//
|
||||
// Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
|
||||
// A port of MPAndroidChart for iOS
|
||||
// Licensed under Apache License 2.0
|
||||
//
|
||||
// https://github.com/danielgindi/ios-charts
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import UIKit
|
||||
|
||||
public class ChartColorTemplates: NSObject
|
||||
{
|
||||
public class func liberty () -> [UIColor]
|
||||
{
|
||||
return [
|
||||
UIColor(red: 207/255.0, green: 248/255.0, blue: 246/255.0, alpha: 1.0),
|
||||
UIColor(red: 148/255.0, green: 212/255.0, blue: 212/255.0, alpha: 1.0),
|
||||
UIColor(red: 136/255.0, green: 180/255.0, blue: 187/255.0, alpha: 1.0),
|
||||
UIColor(red: 118/255.0, green: 174/255.0, blue: 175/255.0, alpha: 1.0),
|
||||
UIColor(red: 42/255.0, green: 109/255.0, blue: 130/255.0, alpha: 1.0)
|
||||
]
|
||||
}
|
||||
|
||||
public class func joyful () -> [UIColor]
|
||||
{
|
||||
return [
|
||||
UIColor(red: 217/255.0, green: 80/255.0, blue: 138/255.0, alpha: 1.0),
|
||||
UIColor(red: 254/255.0, green: 149/255.0, blue: 7/255.0, alpha: 1.0),
|
||||
UIColor(red: 254/255.0, green: 247/255.0, blue: 120/255.0, alpha: 1.0),
|
||||
UIColor(red: 106/255.0, green: 167/255.0, blue: 134/255.0, alpha: 1.0),
|
||||
UIColor(red: 53/255.0, green: 194/255.0, blue: 209/255.0, alpha: 1.0)
|
||||
]
|
||||
}
|
||||
|
||||
public class func pastel () -> [UIColor]
|
||||
{
|
||||
return [
|
||||
UIColor(red: 64/255.0, green: 89/255.0, blue: 128/255.0, alpha: 1.0),
|
||||
UIColor(red: 149/255.0, green: 165/255.0, blue: 124/255.0, alpha: 1.0),
|
||||
UIColor(red: 217/255.0, green: 184/255.0, blue: 162/255.0, alpha: 1.0),
|
||||
UIColor(red: 191/255.0, green: 134/255.0, blue: 134/255.0, alpha: 1.0),
|
||||
UIColor(red: 179/255.0, green: 48/255.0, blue: 80/255.0, alpha: 1.0)
|
||||
]
|
||||
}
|
||||
|
||||
public class func colorful () -> [UIColor]
|
||||
{
|
||||
return [
|
||||
UIColor(red: 193/255.0, green: 37/255.0, blue: 82/255.0, alpha: 1.0),
|
||||
UIColor(red: 255/255.0, green: 102/255.0, blue: 0/255.0, alpha: 1.0),
|
||||
UIColor(red: 245/255.0, green: 199/255.0, blue: 0/255.0, alpha: 1.0),
|
||||
UIColor(red: 106/255.0, green: 150/255.0, blue: 31/255.0, alpha: 1.0),
|
||||
UIColor(red: 179/255.0, green: 100/255.0, blue: 53/255.0, alpha: 1.0)
|
||||
]
|
||||
}
|
||||
|
||||
public class func vordiplom () -> [UIColor]
|
||||
{
|
||||
return [
|
||||
UIColor(red: 192/255.0, green: 255/255.0, blue: 140/255.0, alpha: 1.0),
|
||||
UIColor(red: 255/255.0, green: 247/255.0, blue: 140/255.0, alpha: 1.0),
|
||||
UIColor(red: 255/255.0, green: 208/255.0, blue: 140/255.0, alpha: 1.0),
|
||||
UIColor(red: 140/255.0, green: 234/255.0, blue: 255/255.0, alpha: 1.0),
|
||||
UIColor(red: 255/255.0, green: 140/255.0, blue: 157/255.0, alpha: 1.0)
|
||||
]
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user