├── .gitignore ├── LICENSE ├── PNChartSwift.xcodeproj ├── project.pbxproj └── project.xcworkspace │ └── contents.xcworkspacedata ├── PNChartSwift ├── AppDelegate.swift ├── Assets.xcassets │ └── AppIcon.appiconset │ │ └── Contents.json ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard ├── ChartTableViewCell.swift ├── DetailViewController.swift ├── Info.plist ├── MainViewController.swift └── Source │ ├── PNBar.swift │ ├── PNBarChart.swift │ ├── PNChartLabel.swift │ ├── PNChartSwift.podspec │ ├── PNColor.swift │ ├── PNGenericChart.swift │ ├── PNLineChart.swift │ ├── PNLineChartData.swift │ ├── PNLineChartDataItem.swift │ ├── PNPieChart.swift │ ├── PNPieChartDataItem.swift │ └── PNValue.swift ├── PNChartSwiftTests ├── Info.plist └── PNChartSwiftTests.swift ├── PNChartSwiftUITests ├── Info.plist └── PNChartSwiftUITests.swift └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | # CocoaPods 2 | # 3 | # We recommend against adding the Pods directory to your .gitignore. However 4 | # you should judge for yourself, the pros and cons are mentioned at: 5 | # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control? 6 | # 7 | Build/ 8 | Pods/ 9 | 10 | # OS X Finder 11 | .DS_Store 12 | 13 | # Xcode per-user config 14 | *.mode1 15 | *.mode1v3 16 | *.mode2v3 17 | *.perspective 18 | *.perspectivev3 19 | *.pbxuser 20 | xcuserdata 21 | *.xccheckout 22 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /PNChartSwift.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 54; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 3A30C4FA1F424CC0002F7905 /* PNChartLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A30C4F81F424CC0002F7905 /* PNChartLabel.swift */; }; 11 | 3A30C4FB1F424CC0002F7905 /* PNGenericChart.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A30C4F91F424CC0002F7905 /* PNGenericChart.swift */; }; 12 | 3A30C4FE1F424D00002F7905 /* PNColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A30C4F21F424C7E002F7905 /* PNColor.swift */; }; 13 | 3A30C4FF1F424D03002F7905 /* PNValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A30C4F11F424C7E002F7905 /* PNValue.swift */; }; 14 | 3A30C5001F424D08002F7905 /* PNPieChart.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A30C4F31F424C91002F7905 /* PNPieChart.swift */; }; 15 | 3A30C5011F424D08002F7905 /* PNPieChartDataItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A30C4F41F424C91002F7905 /* PNPieChartDataItem.swift */; }; 16 | 3A30C5021F424D13002F7905 /* PNLineChart.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A30C4F71F424CA2002F7905 /* PNLineChart.swift */; }; 17 | 3A30C5031F424D13002F7905 /* PNLineChartData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A30C4F51F424CA2002F7905 /* PNLineChartData.swift */; }; 18 | 3A30C5041F424D13002F7905 /* PNLineChartDataItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A30C4F61F424CA2002F7905 /* PNLineChartDataItem.swift */; }; 19 | 3A30C5051F424D18002F7905 /* PNBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A30C4FC1F424CE7002F7905 /* PNBar.swift */; }; 20 | 3A30C5061F424D18002F7905 /* PNBarChart.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A30C4FD1F424CE7002F7905 /* PNBarChart.swift */; }; 21 | 3A30C5081F4253CC002F7905 /* MainViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A30C5071F4253CC002F7905 /* MainViewController.swift */; }; 22 | 3A30C50A1F4255EE002F7905 /* ChartTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A30C5091F4255EE002F7905 /* ChartTableViewCell.swift */; }; 23 | 3A30C50C1F425768002F7905 /* DetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A30C50B1F425768002F7905 /* DetailViewController.swift */; }; 24 | 3A9AD07C1E17043200A1732F /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A9AD07B1E17043200A1732F /* AppDelegate.swift */; }; 25 | 3A9AD0811E17043200A1732F /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 3A9AD07F1E17043200A1732F /* Main.storyboard */; }; 26 | 3A9AD0831E17043200A1732F /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 3A9AD0821E17043200A1732F /* Assets.xcassets */; }; 27 | 3A9AD0861E17043200A1732F /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 3A9AD0841E17043200A1732F /* LaunchScreen.storyboard */; }; 28 | 3A9AD0911E17043200A1732F /* PNChartSwiftTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A9AD0901E17043200A1732F /* PNChartSwiftTests.swift */; }; 29 | 3A9AD09C1E17043200A1732F /* PNChartSwiftUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A9AD09B1E17043200A1732F /* PNChartSwiftUITests.swift */; }; 30 | /* End PBXBuildFile section */ 31 | 32 | /* Begin PBXContainerItemProxy section */ 33 | 3A9AD08D1E17043200A1732F /* PBXContainerItemProxy */ = { 34 | isa = PBXContainerItemProxy; 35 | containerPortal = 3A9AD0701E17043200A1732F /* Project object */; 36 | proxyType = 1; 37 | remoteGlobalIDString = 3A9AD0771E17043200A1732F; 38 | remoteInfo = PNChartSwift; 39 | }; 40 | 3A9AD0981E17043200A1732F /* PBXContainerItemProxy */ = { 41 | isa = PBXContainerItemProxy; 42 | containerPortal = 3A9AD0701E17043200A1732F /* Project object */; 43 | proxyType = 1; 44 | remoteGlobalIDString = 3A9AD0771E17043200A1732F; 45 | remoteInfo = PNChartSwift; 46 | }; 47 | /* End PBXContainerItemProxy section */ 48 | 49 | /* Begin PBXFileReference section */ 50 | 3A30C4F11F424C7E002F7905 /* PNValue.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = PNValue.swift; path = PNChartSwift/Source/PNValue.swift; sourceTree = ""; }; 51 | 3A30C4F21F424C7E002F7905 /* PNColor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = PNColor.swift; path = PNChartSwift/Source/PNColor.swift; sourceTree = ""; }; 52 | 3A30C4F31F424C91002F7905 /* PNPieChart.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = PNPieChart.swift; path = PNChartSwift/Source/PNPieChart.swift; sourceTree = ""; }; 53 | 3A30C4F41F424C91002F7905 /* PNPieChartDataItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = PNPieChartDataItem.swift; path = PNChartSwift/Source/PNPieChartDataItem.swift; sourceTree = ""; }; 54 | 3A30C4F51F424CA2002F7905 /* PNLineChartData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = PNLineChartData.swift; path = PNChartSwift/Source/PNLineChartData.swift; sourceTree = ""; }; 55 | 3A30C4F61F424CA2002F7905 /* PNLineChartDataItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = PNLineChartDataItem.swift; path = PNChartSwift/Source/PNLineChartDataItem.swift; sourceTree = ""; }; 56 | 3A30C4F71F424CA2002F7905 /* PNLineChart.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = PNLineChart.swift; path = PNChartSwift/Source/PNLineChart.swift; sourceTree = ""; }; 57 | 3A30C4F81F424CC0002F7905 /* PNChartLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = PNChartLabel.swift; path = PNChartSwift/Source/PNChartLabel.swift; sourceTree = ""; }; 58 | 3A30C4F91F424CC0002F7905 /* PNGenericChart.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = PNGenericChart.swift; path = PNChartSwift/Source/PNGenericChart.swift; sourceTree = ""; }; 59 | 3A30C4FC1F424CE7002F7905 /* PNBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = PNBar.swift; path = PNChartSwift/Source/PNBar.swift; sourceTree = ""; }; 60 | 3A30C4FD1F424CE7002F7905 /* PNBarChart.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = PNBarChart.swift; path = PNChartSwift/Source/PNBarChart.swift; sourceTree = ""; }; 61 | 3A30C5071F4253CC002F7905 /* MainViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainViewController.swift; sourceTree = ""; }; 62 | 3A30C5091F4255EE002F7905 /* ChartTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChartTableViewCell.swift; sourceTree = ""; }; 63 | 3A30C50B1F425768002F7905 /* DetailViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DetailViewController.swift; sourceTree = ""; }; 64 | 3A9AD0781E17043200A1732F /* PNChartSwift.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = PNChartSwift.app; sourceTree = BUILT_PRODUCTS_DIR; }; 65 | 3A9AD07B1E17043200A1732F /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 66 | 3A9AD0801E17043200A1732F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 67 | 3A9AD0821E17043200A1732F /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 68 | 3A9AD0851E17043200A1732F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 69 | 3A9AD0871E17043200A1732F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 70 | 3A9AD08C1E17043200A1732F /* PNChartSwiftTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = PNChartSwiftTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 71 | 3A9AD0901E17043200A1732F /* PNChartSwiftTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PNChartSwiftTests.swift; sourceTree = ""; }; 72 | 3A9AD0921E17043200A1732F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 73 | 3A9AD0971E17043200A1732F /* PNChartSwiftUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = PNChartSwiftUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 74 | 3A9AD09B1E17043200A1732F /* PNChartSwiftUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PNChartSwiftUITests.swift; sourceTree = ""; }; 75 | 3A9AD09D1E17043200A1732F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 76 | /* End PBXFileReference section */ 77 | 78 | /* Begin PBXFrameworksBuildPhase section */ 79 | 3A9AD0751E17043200A1732F /* Frameworks */ = { 80 | isa = PBXFrameworksBuildPhase; 81 | buildActionMask = 2147483647; 82 | files = ( 83 | ); 84 | runOnlyForDeploymentPostprocessing = 0; 85 | }; 86 | 3A9AD0891E17043200A1732F /* Frameworks */ = { 87 | isa = PBXFrameworksBuildPhase; 88 | buildActionMask = 2147483647; 89 | files = ( 90 | ); 91 | runOnlyForDeploymentPostprocessing = 0; 92 | }; 93 | 3A9AD0941E17043200A1732F /* Frameworks */ = { 94 | isa = PBXFrameworksBuildPhase; 95 | buildActionMask = 2147483647; 96 | files = ( 97 | ); 98 | runOnlyForDeploymentPostprocessing = 0; 99 | }; 100 | /* End PBXFrameworksBuildPhase section */ 101 | 102 | /* Begin PBXGroup section */ 103 | 3A30C4EC1F421CE9002F7905 /* Bar */ = { 104 | isa = PBXGroup; 105 | children = ( 106 | 3A30C4FC1F424CE7002F7905 /* PNBar.swift */, 107 | 3A30C4FD1F424CE7002F7905 /* PNBarChart.swift */, 108 | ); 109 | name = Bar; 110 | sourceTree = ""; 111 | }; 112 | 3A30C4ED1F422130002F7905 /* Helper */ = { 113 | isa = PBXGroup; 114 | children = ( 115 | 3A30C4F21F424C7E002F7905 /* PNColor.swift */, 116 | 3A30C4F11F424C7E002F7905 /* PNValue.swift */, 117 | ); 118 | name = Helper; 119 | sourceTree = ""; 120 | }; 121 | 3A30C4EE1F422171002F7905 /* Chart */ = { 122 | isa = PBXGroup; 123 | children = ( 124 | 3A30C4F81F424CC0002F7905 /* PNChartLabel.swift */, 125 | 3A30C4F91F424CC0002F7905 /* PNGenericChart.swift */, 126 | ); 127 | name = Chart; 128 | sourceTree = ""; 129 | }; 130 | 3A30C4EF1F422183002F7905 /* Line */ = { 131 | isa = PBXGroup; 132 | children = ( 133 | 3A30C4F71F424CA2002F7905 /* PNLineChart.swift */, 134 | 3A30C4F51F424CA2002F7905 /* PNLineChartData.swift */, 135 | 3A30C4F61F424CA2002F7905 /* PNLineChartDataItem.swift */, 136 | ); 137 | name = Line; 138 | sourceTree = ""; 139 | }; 140 | 3A30C4F01F42219F002F7905 /* Pie */ = { 141 | isa = PBXGroup; 142 | children = ( 143 | 3A30C4F31F424C91002F7905 /* PNPieChart.swift */, 144 | 3A30C4F41F424C91002F7905 /* PNPieChartDataItem.swift */, 145 | ); 146 | name = Pie; 147 | sourceTree = ""; 148 | }; 149 | 3A9AD06F1E17043200A1732F = { 150 | isa = PBXGroup; 151 | children = ( 152 | 3A9AD0AA1E17045F00A1732F /* Source */, 153 | 3A9AD07A1E17043200A1732F /* PNChartSwift */, 154 | 3A9AD08F1E17043200A1732F /* PNChartSwiftTests */, 155 | 3A9AD09A1E17043200A1732F /* PNChartSwiftUITests */, 156 | 3A9AD0791E17043200A1732F /* Products */, 157 | ); 158 | sourceTree = ""; 159 | }; 160 | 3A9AD0791E17043200A1732F /* Products */ = { 161 | isa = PBXGroup; 162 | children = ( 163 | 3A9AD0781E17043200A1732F /* PNChartSwift.app */, 164 | 3A9AD08C1E17043200A1732F /* PNChartSwiftTests.xctest */, 165 | 3A9AD0971E17043200A1732F /* PNChartSwiftUITests.xctest */, 166 | ); 167 | name = Products; 168 | sourceTree = ""; 169 | }; 170 | 3A9AD07A1E17043200A1732F /* PNChartSwift */ = { 171 | isa = PBXGroup; 172 | children = ( 173 | 3A9AD07B1E17043200A1732F /* AppDelegate.swift */, 174 | 3A30C5071F4253CC002F7905 /* MainViewController.swift */, 175 | 3A30C50B1F425768002F7905 /* DetailViewController.swift */, 176 | 3A30C5091F4255EE002F7905 /* ChartTableViewCell.swift */, 177 | 3A9AD07F1E17043200A1732F /* Main.storyboard */, 178 | 3A9AD0821E17043200A1732F /* Assets.xcassets */, 179 | 3A9AD0841E17043200A1732F /* LaunchScreen.storyboard */, 180 | 3A9AD0871E17043200A1732F /* Info.plist */, 181 | ); 182 | path = PNChartSwift; 183 | sourceTree = ""; 184 | }; 185 | 3A9AD08F1E17043200A1732F /* PNChartSwiftTests */ = { 186 | isa = PBXGroup; 187 | children = ( 188 | 3A9AD0901E17043200A1732F /* PNChartSwiftTests.swift */, 189 | 3A9AD0921E17043200A1732F /* Info.plist */, 190 | ); 191 | path = PNChartSwiftTests; 192 | sourceTree = ""; 193 | }; 194 | 3A9AD09A1E17043200A1732F /* PNChartSwiftUITests */ = { 195 | isa = PBXGroup; 196 | children = ( 197 | 3A9AD09B1E17043200A1732F /* PNChartSwiftUITests.swift */, 198 | 3A9AD09D1E17043200A1732F /* Info.plist */, 199 | ); 200 | path = PNChartSwiftUITests; 201 | sourceTree = ""; 202 | }; 203 | 3A9AD0AA1E17045F00A1732F /* Source */ = { 204 | isa = PBXGroup; 205 | children = ( 206 | 3A30C4ED1F422130002F7905 /* Helper */, 207 | 3A30C4F01F42219F002F7905 /* Pie */, 208 | 3A30C4EF1F422183002F7905 /* Line */, 209 | 3A30C4EE1F422171002F7905 /* Chart */, 210 | 3A30C4EC1F421CE9002F7905 /* Bar */, 211 | ); 212 | name = Source; 213 | sourceTree = ""; 214 | }; 215 | /* End PBXGroup section */ 216 | 217 | /* Begin PBXNativeTarget section */ 218 | 3A9AD0771E17043200A1732F /* PNChartSwift */ = { 219 | isa = PBXNativeTarget; 220 | buildConfigurationList = 3A9AD0A01E17043200A1732F /* Build configuration list for PBXNativeTarget "PNChartSwift" */; 221 | buildPhases = ( 222 | 3A9AD0741E17043200A1732F /* Sources */, 223 | 3A9AD0751E17043200A1732F /* Frameworks */, 224 | 3A9AD0761E17043200A1732F /* Resources */, 225 | ); 226 | buildRules = ( 227 | ); 228 | dependencies = ( 229 | ); 230 | name = PNChartSwift; 231 | productName = PNChartSwift; 232 | productReference = 3A9AD0781E17043200A1732F /* PNChartSwift.app */; 233 | productType = "com.apple.product-type.application"; 234 | }; 235 | 3A9AD08B1E17043200A1732F /* PNChartSwiftTests */ = { 236 | isa = PBXNativeTarget; 237 | buildConfigurationList = 3A9AD0A31E17043200A1732F /* Build configuration list for PBXNativeTarget "PNChartSwiftTests" */; 238 | buildPhases = ( 239 | 3A9AD0881E17043200A1732F /* Sources */, 240 | 3A9AD0891E17043200A1732F /* Frameworks */, 241 | 3A9AD08A1E17043200A1732F /* Resources */, 242 | ); 243 | buildRules = ( 244 | ); 245 | dependencies = ( 246 | 3A9AD08E1E17043200A1732F /* PBXTargetDependency */, 247 | ); 248 | name = PNChartSwiftTests; 249 | productName = PNChartSwiftTests; 250 | productReference = 3A9AD08C1E17043200A1732F /* PNChartSwiftTests.xctest */; 251 | productType = "com.apple.product-type.bundle.unit-test"; 252 | }; 253 | 3A9AD0961E17043200A1732F /* PNChartSwiftUITests */ = { 254 | isa = PBXNativeTarget; 255 | buildConfigurationList = 3A9AD0A61E17043200A1732F /* Build configuration list for PBXNativeTarget "PNChartSwiftUITests" */; 256 | buildPhases = ( 257 | 3A9AD0931E17043200A1732F /* Sources */, 258 | 3A9AD0941E17043200A1732F /* Frameworks */, 259 | 3A9AD0951E17043200A1732F /* Resources */, 260 | ); 261 | buildRules = ( 262 | ); 263 | dependencies = ( 264 | 3A9AD0991E17043200A1732F /* PBXTargetDependency */, 265 | ); 266 | name = PNChartSwiftUITests; 267 | productName = PNChartSwiftUITests; 268 | productReference = 3A9AD0971E17043200A1732F /* PNChartSwiftUITests.xctest */; 269 | productType = "com.apple.product-type.bundle.ui-testing"; 270 | }; 271 | /* End PBXNativeTarget section */ 272 | 273 | /* Begin PBXProject section */ 274 | 3A9AD0701E17043200A1732F /* Project object */ = { 275 | isa = PBXProject; 276 | attributes = { 277 | BuildIndependentTargetsInParallel = YES; 278 | LastSwiftUpdateCheck = 0820; 279 | LastUpgradeCheck = 1510; 280 | TargetAttributes = { 281 | 3A9AD0771E17043200A1732F = { 282 | CreatedOnToolsVersion = 8.2.1; 283 | LastSwiftMigration = 1510; 284 | ProvisioningStyle = Manual; 285 | }; 286 | 3A9AD08B1E17043200A1732F = { 287 | CreatedOnToolsVersion = 8.2.1; 288 | LastSwiftMigration = 1510; 289 | ProvisioningStyle = Manual; 290 | TestTargetID = 3A9AD0771E17043200A1732F; 291 | }; 292 | 3A9AD0961E17043200A1732F = { 293 | CreatedOnToolsVersion = 8.2.1; 294 | LastSwiftMigration = 1510; 295 | ProvisioningStyle = Manual; 296 | TestTargetID = 3A9AD0771E17043200A1732F; 297 | }; 298 | }; 299 | }; 300 | buildConfigurationList = 3A9AD0731E17043200A1732F /* Build configuration list for PBXProject "PNChartSwift" */; 301 | compatibilityVersion = "Xcode 3.2"; 302 | developmentRegion = en; 303 | hasScannedForEncodings = 0; 304 | knownRegions = ( 305 | en, 306 | Base, 307 | ); 308 | mainGroup = 3A9AD06F1E17043200A1732F; 309 | productRefGroup = 3A9AD0791E17043200A1732F /* Products */; 310 | projectDirPath = ""; 311 | projectRoot = ""; 312 | targets = ( 313 | 3A9AD0771E17043200A1732F /* PNChartSwift */, 314 | 3A9AD08B1E17043200A1732F /* PNChartSwiftTests */, 315 | 3A9AD0961E17043200A1732F /* PNChartSwiftUITests */, 316 | ); 317 | }; 318 | /* End PBXProject section */ 319 | 320 | /* Begin PBXResourcesBuildPhase section */ 321 | 3A9AD0761E17043200A1732F /* Resources */ = { 322 | isa = PBXResourcesBuildPhase; 323 | buildActionMask = 2147483647; 324 | files = ( 325 | 3A9AD0861E17043200A1732F /* LaunchScreen.storyboard in Resources */, 326 | 3A9AD0831E17043200A1732F /* Assets.xcassets in Resources */, 327 | 3A9AD0811E17043200A1732F /* Main.storyboard in Resources */, 328 | ); 329 | runOnlyForDeploymentPostprocessing = 0; 330 | }; 331 | 3A9AD08A1E17043200A1732F /* Resources */ = { 332 | isa = PBXResourcesBuildPhase; 333 | buildActionMask = 2147483647; 334 | files = ( 335 | ); 336 | runOnlyForDeploymentPostprocessing = 0; 337 | }; 338 | 3A9AD0951E17043200A1732F /* Resources */ = { 339 | isa = PBXResourcesBuildPhase; 340 | buildActionMask = 2147483647; 341 | files = ( 342 | ); 343 | runOnlyForDeploymentPostprocessing = 0; 344 | }; 345 | /* End PBXResourcesBuildPhase section */ 346 | 347 | /* Begin PBXSourcesBuildPhase section */ 348 | 3A9AD0741E17043200A1732F /* Sources */ = { 349 | isa = PBXSourcesBuildPhase; 350 | buildActionMask = 2147483647; 351 | files = ( 352 | 3A30C5021F424D13002F7905 /* PNLineChart.swift in Sources */, 353 | 3A30C4FA1F424CC0002F7905 /* PNChartLabel.swift in Sources */, 354 | 3A30C5001F424D08002F7905 /* PNPieChart.swift in Sources */, 355 | 3A30C5011F424D08002F7905 /* PNPieChartDataItem.swift in Sources */, 356 | 3A30C5031F424D13002F7905 /* PNLineChartData.swift in Sources */, 357 | 3A30C4FF1F424D03002F7905 /* PNValue.swift in Sources */, 358 | 3A30C50C1F425768002F7905 /* DetailViewController.swift in Sources */, 359 | 3A30C5081F4253CC002F7905 /* MainViewController.swift in Sources */, 360 | 3A30C4FB1F424CC0002F7905 /* PNGenericChart.swift in Sources */, 361 | 3A30C50A1F4255EE002F7905 /* ChartTableViewCell.swift in Sources */, 362 | 3A30C4FE1F424D00002F7905 /* PNColor.swift in Sources */, 363 | 3A30C5051F424D18002F7905 /* PNBar.swift in Sources */, 364 | 3A9AD07C1E17043200A1732F /* AppDelegate.swift in Sources */, 365 | 3A30C5041F424D13002F7905 /* PNLineChartDataItem.swift in Sources */, 366 | 3A30C5061F424D18002F7905 /* PNBarChart.swift in Sources */, 367 | ); 368 | runOnlyForDeploymentPostprocessing = 0; 369 | }; 370 | 3A9AD0881E17043200A1732F /* Sources */ = { 371 | isa = PBXSourcesBuildPhase; 372 | buildActionMask = 2147483647; 373 | files = ( 374 | 3A9AD0911E17043200A1732F /* PNChartSwiftTests.swift in Sources */, 375 | ); 376 | runOnlyForDeploymentPostprocessing = 0; 377 | }; 378 | 3A9AD0931E17043200A1732F /* Sources */ = { 379 | isa = PBXSourcesBuildPhase; 380 | buildActionMask = 2147483647; 381 | files = ( 382 | 3A9AD09C1E17043200A1732F /* PNChartSwiftUITests.swift in Sources */, 383 | ); 384 | runOnlyForDeploymentPostprocessing = 0; 385 | }; 386 | /* End PBXSourcesBuildPhase section */ 387 | 388 | /* Begin PBXTargetDependency section */ 389 | 3A9AD08E1E17043200A1732F /* PBXTargetDependency */ = { 390 | isa = PBXTargetDependency; 391 | target = 3A9AD0771E17043200A1732F /* PNChartSwift */; 392 | targetProxy = 3A9AD08D1E17043200A1732F /* PBXContainerItemProxy */; 393 | }; 394 | 3A9AD0991E17043200A1732F /* PBXTargetDependency */ = { 395 | isa = PBXTargetDependency; 396 | target = 3A9AD0771E17043200A1732F /* PNChartSwift */; 397 | targetProxy = 3A9AD0981E17043200A1732F /* PBXContainerItemProxy */; 398 | }; 399 | /* End PBXTargetDependency section */ 400 | 401 | /* Begin PBXVariantGroup section */ 402 | 3A9AD07F1E17043200A1732F /* Main.storyboard */ = { 403 | isa = PBXVariantGroup; 404 | children = ( 405 | 3A9AD0801E17043200A1732F /* Base */, 406 | ); 407 | name = Main.storyboard; 408 | sourceTree = ""; 409 | }; 410 | 3A9AD0841E17043200A1732F /* LaunchScreen.storyboard */ = { 411 | isa = PBXVariantGroup; 412 | children = ( 413 | 3A9AD0851E17043200A1732F /* Base */, 414 | ); 415 | name = LaunchScreen.storyboard; 416 | sourceTree = ""; 417 | }; 418 | /* End PBXVariantGroup section */ 419 | 420 | /* Begin XCBuildConfiguration section */ 421 | 3A9AD09E1E17043200A1732F /* Debug */ = { 422 | isa = XCBuildConfiguration; 423 | buildSettings = { 424 | ALWAYS_SEARCH_USER_PATHS = NO; 425 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 426 | CLANG_ANALYZER_NONNULL = YES; 427 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 428 | CLANG_CXX_LIBRARY = "libc++"; 429 | CLANG_ENABLE_MODULES = YES; 430 | CLANG_ENABLE_OBJC_ARC = YES; 431 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 432 | CLANG_WARN_BOOL_CONVERSION = YES; 433 | CLANG_WARN_COMMA = YES; 434 | CLANG_WARN_CONSTANT_CONVERSION = YES; 435 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 436 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 437 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 438 | CLANG_WARN_EMPTY_BODY = YES; 439 | CLANG_WARN_ENUM_CONVERSION = YES; 440 | CLANG_WARN_INFINITE_RECURSION = YES; 441 | CLANG_WARN_INT_CONVERSION = YES; 442 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 443 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 444 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 445 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 446 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 447 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 448 | CLANG_WARN_STRICT_PROTOTYPES = YES; 449 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 450 | CLANG_WARN_UNREACHABLE_CODE = YES; 451 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 452 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 453 | COPY_PHASE_STRIP = NO; 454 | DEBUG_INFORMATION_FORMAT = dwarf; 455 | ENABLE_STRICT_OBJC_MSGSEND = YES; 456 | ENABLE_TESTABILITY = YES; 457 | ENABLE_USER_SCRIPT_SANDBOXING = YES; 458 | GCC_C_LANGUAGE_STANDARD = gnu99; 459 | GCC_DYNAMIC_NO_PIC = NO; 460 | GCC_NO_COMMON_BLOCKS = YES; 461 | GCC_OPTIMIZATION_LEVEL = 0; 462 | GCC_PREPROCESSOR_DEFINITIONS = ( 463 | "DEBUG=1", 464 | "$(inherited)", 465 | ); 466 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 467 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 468 | GCC_WARN_UNDECLARED_SELECTOR = YES; 469 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 470 | GCC_WARN_UNUSED_FUNCTION = YES; 471 | GCC_WARN_UNUSED_VARIABLE = YES; 472 | IPHONEOS_DEPLOYMENT_TARGET = 12.0; 473 | MTL_ENABLE_DEBUG_INFO = YES; 474 | ONLY_ACTIVE_ARCH = YES; 475 | SDKROOT = iphoneos; 476 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 477 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 478 | TARGETED_DEVICE_FAMILY = "1,2"; 479 | }; 480 | name = Debug; 481 | }; 482 | 3A9AD09F1E17043200A1732F /* Release */ = { 483 | isa = XCBuildConfiguration; 484 | buildSettings = { 485 | ALWAYS_SEARCH_USER_PATHS = NO; 486 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 487 | CLANG_ANALYZER_NONNULL = YES; 488 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 489 | CLANG_CXX_LIBRARY = "libc++"; 490 | CLANG_ENABLE_MODULES = YES; 491 | CLANG_ENABLE_OBJC_ARC = YES; 492 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 493 | CLANG_WARN_BOOL_CONVERSION = YES; 494 | CLANG_WARN_COMMA = YES; 495 | CLANG_WARN_CONSTANT_CONVERSION = YES; 496 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 497 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 498 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 499 | CLANG_WARN_EMPTY_BODY = YES; 500 | CLANG_WARN_ENUM_CONVERSION = YES; 501 | CLANG_WARN_INFINITE_RECURSION = YES; 502 | CLANG_WARN_INT_CONVERSION = YES; 503 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 504 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 505 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 506 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 507 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 508 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 509 | CLANG_WARN_STRICT_PROTOTYPES = YES; 510 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 511 | CLANG_WARN_UNREACHABLE_CODE = YES; 512 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 513 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 514 | COPY_PHASE_STRIP = NO; 515 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 516 | ENABLE_NS_ASSERTIONS = NO; 517 | ENABLE_STRICT_OBJC_MSGSEND = YES; 518 | ENABLE_USER_SCRIPT_SANDBOXING = YES; 519 | GCC_C_LANGUAGE_STANDARD = gnu99; 520 | GCC_NO_COMMON_BLOCKS = YES; 521 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 522 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 523 | GCC_WARN_UNDECLARED_SELECTOR = YES; 524 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 525 | GCC_WARN_UNUSED_FUNCTION = YES; 526 | GCC_WARN_UNUSED_VARIABLE = YES; 527 | IPHONEOS_DEPLOYMENT_TARGET = 12.0; 528 | MTL_ENABLE_DEBUG_INFO = NO; 529 | SDKROOT = iphoneos; 530 | SWIFT_COMPILATION_MODE = wholemodule; 531 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 532 | TARGETED_DEVICE_FAMILY = "1,2"; 533 | VALIDATE_PRODUCT = YES; 534 | }; 535 | name = Release; 536 | }; 537 | 3A9AD0A11E17043200A1732F /* Debug */ = { 538 | isa = XCBuildConfiguration; 539 | buildSettings = { 540 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 541 | CODE_SIGN_STYLE = Manual; 542 | DEVELOPMENT_TEAM = ""; 543 | INFOPLIST_FILE = PNChartSwift/Info.plist; 544 | IPHONEOS_DEPLOYMENT_TARGET = 12.0; 545 | LD_RUNPATH_SEARCH_PATHS = ( 546 | "$(inherited)", 547 | "@executable_path/Frameworks", 548 | ); 549 | PRODUCT_BUNDLE_IDENTIFIER = Demo.PNChartSwift; 550 | PRODUCT_NAME = "$(TARGET_NAME)"; 551 | PROVISIONING_PROFILE_SPECIFIER = ""; 552 | SWIFT_SWIFT3_OBJC_INFERENCE = Off; 553 | SWIFT_VERSION = 5.0; 554 | }; 555 | name = Debug; 556 | }; 557 | 3A9AD0A21E17043200A1732F /* Release */ = { 558 | isa = XCBuildConfiguration; 559 | buildSettings = { 560 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 561 | CODE_SIGN_STYLE = Manual; 562 | DEVELOPMENT_TEAM = ""; 563 | INFOPLIST_FILE = PNChartSwift/Info.plist; 564 | IPHONEOS_DEPLOYMENT_TARGET = 12.0; 565 | LD_RUNPATH_SEARCH_PATHS = ( 566 | "$(inherited)", 567 | "@executable_path/Frameworks", 568 | ); 569 | PRODUCT_BUNDLE_IDENTIFIER = Demo.PNChartSwift; 570 | PRODUCT_NAME = "$(TARGET_NAME)"; 571 | PROVISIONING_PROFILE_SPECIFIER = ""; 572 | SWIFT_SWIFT3_OBJC_INFERENCE = Off; 573 | SWIFT_VERSION = 5.0; 574 | }; 575 | name = Release; 576 | }; 577 | 3A9AD0A41E17043200A1732F /* Debug */ = { 578 | isa = XCBuildConfiguration; 579 | buildSettings = { 580 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 581 | BUNDLE_LOADER = "$(TEST_HOST)"; 582 | CODE_SIGN_STYLE = Manual; 583 | DEVELOPMENT_TEAM = ""; 584 | INFOPLIST_FILE = PNChartSwiftTests/Info.plist; 585 | LD_RUNPATH_SEARCH_PATHS = ( 586 | "$(inherited)", 587 | "@executable_path/Frameworks", 588 | "@loader_path/Frameworks", 589 | ); 590 | PRODUCT_BUNDLE_IDENTIFIER = Demo.PNChartSwiftTests; 591 | PRODUCT_NAME = "$(TARGET_NAME)"; 592 | PROVISIONING_PROFILE_SPECIFIER = ""; 593 | SWIFT_SWIFT3_OBJC_INFERENCE = On; 594 | SWIFT_VERSION = 5.0; 595 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/PNChartSwift.app/PNChartSwift"; 596 | }; 597 | name = Debug; 598 | }; 599 | 3A9AD0A51E17043200A1732F /* Release */ = { 600 | isa = XCBuildConfiguration; 601 | buildSettings = { 602 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 603 | BUNDLE_LOADER = "$(TEST_HOST)"; 604 | CODE_SIGN_STYLE = Manual; 605 | DEVELOPMENT_TEAM = ""; 606 | INFOPLIST_FILE = PNChartSwiftTests/Info.plist; 607 | LD_RUNPATH_SEARCH_PATHS = ( 608 | "$(inherited)", 609 | "@executable_path/Frameworks", 610 | "@loader_path/Frameworks", 611 | ); 612 | PRODUCT_BUNDLE_IDENTIFIER = Demo.PNChartSwiftTests; 613 | PRODUCT_NAME = "$(TARGET_NAME)"; 614 | PROVISIONING_PROFILE_SPECIFIER = ""; 615 | SWIFT_SWIFT3_OBJC_INFERENCE = On; 616 | SWIFT_VERSION = 5.0; 617 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/PNChartSwift.app/PNChartSwift"; 618 | }; 619 | name = Release; 620 | }; 621 | 3A9AD0A71E17043200A1732F /* Debug */ = { 622 | isa = XCBuildConfiguration; 623 | buildSettings = { 624 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 625 | CODE_SIGN_STYLE = Manual; 626 | DEVELOPMENT_TEAM = ""; 627 | INFOPLIST_FILE = PNChartSwiftUITests/Info.plist; 628 | LD_RUNPATH_SEARCH_PATHS = ( 629 | "$(inherited)", 630 | "@executable_path/Frameworks", 631 | "@loader_path/Frameworks", 632 | ); 633 | PRODUCT_BUNDLE_IDENTIFIER = Demo.PNChartSwiftUITests; 634 | PRODUCT_NAME = "$(TARGET_NAME)"; 635 | PROVISIONING_PROFILE_SPECIFIER = ""; 636 | SWIFT_SWIFT3_OBJC_INFERENCE = On; 637 | SWIFT_VERSION = 5.0; 638 | TEST_TARGET_NAME = PNChartSwift; 639 | }; 640 | name = Debug; 641 | }; 642 | 3A9AD0A81E17043200A1732F /* Release */ = { 643 | isa = XCBuildConfiguration; 644 | buildSettings = { 645 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 646 | CODE_SIGN_STYLE = Manual; 647 | DEVELOPMENT_TEAM = ""; 648 | INFOPLIST_FILE = PNChartSwiftUITests/Info.plist; 649 | LD_RUNPATH_SEARCH_PATHS = ( 650 | "$(inherited)", 651 | "@executable_path/Frameworks", 652 | "@loader_path/Frameworks", 653 | ); 654 | PRODUCT_BUNDLE_IDENTIFIER = Demo.PNChartSwiftUITests; 655 | PRODUCT_NAME = "$(TARGET_NAME)"; 656 | PROVISIONING_PROFILE_SPECIFIER = ""; 657 | SWIFT_SWIFT3_OBJC_INFERENCE = On; 658 | SWIFT_VERSION = 5.0; 659 | TEST_TARGET_NAME = PNChartSwift; 660 | }; 661 | name = Release; 662 | }; 663 | /* End XCBuildConfiguration section */ 664 | 665 | /* Begin XCConfigurationList section */ 666 | 3A9AD0731E17043200A1732F /* Build configuration list for PBXProject "PNChartSwift" */ = { 667 | isa = XCConfigurationList; 668 | buildConfigurations = ( 669 | 3A9AD09E1E17043200A1732F /* Debug */, 670 | 3A9AD09F1E17043200A1732F /* Release */, 671 | ); 672 | defaultConfigurationIsVisible = 0; 673 | defaultConfigurationName = Release; 674 | }; 675 | 3A9AD0A01E17043200A1732F /* Build configuration list for PBXNativeTarget "PNChartSwift" */ = { 676 | isa = XCConfigurationList; 677 | buildConfigurations = ( 678 | 3A9AD0A11E17043200A1732F /* Debug */, 679 | 3A9AD0A21E17043200A1732F /* Release */, 680 | ); 681 | defaultConfigurationIsVisible = 0; 682 | defaultConfigurationName = Release; 683 | }; 684 | 3A9AD0A31E17043200A1732F /* Build configuration list for PBXNativeTarget "PNChartSwiftTests" */ = { 685 | isa = XCConfigurationList; 686 | buildConfigurations = ( 687 | 3A9AD0A41E17043200A1732F /* Debug */, 688 | 3A9AD0A51E17043200A1732F /* Release */, 689 | ); 690 | defaultConfigurationIsVisible = 0; 691 | defaultConfigurationName = Release; 692 | }; 693 | 3A9AD0A61E17043200A1732F /* Build configuration list for PBXNativeTarget "PNChartSwiftUITests" */ = { 694 | isa = XCConfigurationList; 695 | buildConfigurations = ( 696 | 3A9AD0A71E17043200A1732F /* Debug */, 697 | 3A9AD0A81E17043200A1732F /* Release */, 698 | ); 699 | defaultConfigurationIsVisible = 0; 700 | defaultConfigurationName = Release; 701 | }; 702 | /* End XCConfigurationList section */ 703 | }; 704 | rootObject = 3A9AD0701E17043200A1732F /* Project object */; 705 | } 706 | -------------------------------------------------------------------------------- /PNChartSwift.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /PNChartSwift/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // PNChartSwift 4 | // 5 | // Created by YiChen Zhou on 12/30/16. 6 | // 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | var window: UIWindow? 15 | 16 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 17 | // Override point for customization after application launch. 18 | return true 19 | } 20 | } 21 | 22 | -------------------------------------------------------------------------------- /PNChartSwift/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "20x20", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "20x20", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "29x29", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "29x29", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "size" : "40x40", 66 | "scale" : "1x" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "size" : "40x40", 71 | "scale" : "2x" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "size" : "76x76", 76 | "scale" : "1x" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "size" : "76x76", 81 | "scale" : "2x" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "size" : "83.5x83.5", 86 | "scale" : "2x" 87 | }, 88 | { 89 | "idiom" : "ios-marketing", 90 | "size" : "1024x1024", 91 | "scale" : "1x" 92 | } 93 | ], 94 | "info" : { 95 | "version" : 1, 96 | "author" : "xcode" 97 | } 98 | } -------------------------------------------------------------------------------- /PNChartSwift/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /PNChartSwift/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | -------------------------------------------------------------------------------- /PNChartSwift/ChartTableViewCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ChartTableViewCell.swift 3 | // PNChartSwift 4 | // 5 | // Created by YiChen Zhou on 8/14/17. 6 | // 7 | 8 | import UIKit 9 | 10 | class ChartTableViewCell: UITableViewCell { 11 | @IBOutlet weak var cellLabel: UILabel! 12 | override func awakeFromNib() { 13 | super.awakeFromNib() 14 | // Initialization code 15 | } 16 | 17 | override func setSelected(_ selected: Bool, animated: Bool) { 18 | super.setSelected(selected, animated: animated) 19 | 20 | // Configure the view for the selected state 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /PNChartSwift/DetailViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DetailViewController.swift 3 | // PNChartSwift 4 | // 5 | // Created by YiChen Zhou on 8/14/17. 6 | // 7 | 8 | import UIKit 9 | 10 | class DetailViewController: UIViewController { 11 | var chartName: String? 12 | override func viewDidLoad() { 13 | super.viewDidLoad() 14 | 15 | guard let _chartName = self.chartName else { 16 | print("Invalid Chart Name") 17 | return 18 | } 19 | 20 | self.title = _chartName 21 | 22 | switch _chartName { 23 | case "Pie Chart": 24 | let pieChart = self.setPieChart() 25 | self.view.addSubview(pieChart) 26 | case "Bar Chart": 27 | let barChart = self.setBarChart() 28 | self.view.addSubview(barChart) 29 | case "Line Chart": 30 | let lineChart = self.setLineChart() 31 | self.view.addSubview(lineChart) 32 | default: 33 | break 34 | } 35 | } 36 | 37 | // override func viewWillAppear(_ animated: Bool) { 38 | // for view in self.view.subviews { 39 | // view.removeFromSuperview() 40 | // } 41 | // } 42 | 43 | private func setPieChart() -> PNPieChart { 44 | let item1 = PNPieChartDataItem(dateValue: 20, dateColor: PNLightGreen, description: "Build") 45 | let item2 = PNPieChartDataItem(dateValue: 20, dateColor: PNFreshGreen, description: "I/O") 46 | let item3 = PNPieChartDataItem(dateValue: 45, dateColor: PNDeepGreen, description: "WWDC") 47 | let frame = CGRect(x: 40, y: 155, width: 240, height: 240) 48 | let items: [PNPieChartDataItem] = [item1, item2, item3] 49 | let pieChart = PNPieChart(frame: frame, items: items) 50 | pieChart.descriptionTextColor = UIColor.white 51 | pieChart.descriptionTextFont = UIFont(name: "Avenir-Medium", size: 14)! 52 | pieChart.center = self.view.center 53 | return pieChart 54 | } 55 | 56 | private func setBarChart() -> PNBarChart { 57 | let barChart = PNBarChart(frame: CGRect(x: 0, y: 135, width: 320, height: 200)) 58 | barChart.backgroundColor = UIColor.clear 59 | barChart.animationType = .Waterfall 60 | barChart.labelMarginTop = 5.0 61 | barChart.xLabels = ["Sep 1", "Sep 2", "Sep 3", "Sep 4", "Sep 5", "Sep 6", "Sep 7"] 62 | barChart.yValues = [1, 23, 12, 18, 30, 12, 21] 63 | barChart.strokeChart() 64 | barChart.center = self.view.center 65 | return barChart 66 | } 67 | 68 | private func setLineChart() -> PNLineChart { 69 | let lineChart = PNLineChart(frame: CGRect(x: 0, y: 135, width: 320, height: 250)) 70 | lineChart.yLabelFormat = "%1.1f" 71 | lineChart.showLabel = true 72 | lineChart.backgroundColor = UIColor.clear 73 | lineChart.xLabels = ["Sep 1", "Sep 2", "Sep 3", "Sep 4", "Sep 5", "Sep 6", "Sep 7"] 74 | lineChart.showCoordinateAxis = true 75 | lineChart.center = self.view.center 76 | 77 | let dataArr = [60.1, 160.1, 126.4, 232.2, 186.2, 127.2, 176.2] 78 | let data = PNLineChartData() 79 | data.color = PNGreen 80 | data.itemCount = dataArr.count 81 | data.inflexPointStyle = .None 82 | data.getData = ({ 83 | (index: Int) -> PNLineChartDataItem in 84 | let yValue = CGFloat(dataArr[index]) 85 | let item = PNLineChartDataItem(y: yValue) 86 | return item 87 | }) 88 | 89 | lineChart.chartData = [data] 90 | lineChart.strokeChart() 91 | return lineChart 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /PNChartSwift/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UILaunchStoryboardName 24 | LaunchScreen 25 | UIMainStoryboardFile 26 | Main 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /PNChartSwift/MainViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MainViewController.swift 3 | // PNChartSwift 4 | // 5 | // Created by YiChen Zhou on 8/14/17. 6 | // 7 | 8 | import UIKit 9 | 10 | class MainViewController: UIViewController { 11 | @IBOutlet weak var tableView: UITableView! 12 | override func viewDidLoad() { 13 | super.viewDidLoad() 14 | if #available(iOS 13.0, *) { 15 | self.view.backgroundColor = .systemBackground 16 | } 17 | self.title = "PNChart" 18 | } 19 | } 20 | 21 | extension MainViewController: UITableViewDelegate { 22 | override func prepare(for segue: UIStoryboardSegue, sender: Any?) { 23 | guard segue.identifier == "chartSegue" else { 24 | print("Unknown segue") 25 | return 26 | } 27 | guard let indexPath = tableView.indexPathForSelectedRow else { 28 | print("Failed to get selected indexPath") 29 | return 30 | } 31 | let destinationVC = segue.destination as! DetailViewController 32 | switch indexPath.row { 33 | case 0: 34 | destinationVC.chartName = "Pie Chart" 35 | case 1: 36 | destinationVC.chartName = "Bar Chart" 37 | case 2: 38 | destinationVC.chartName = "Line Chart" 39 | default: 40 | break 41 | } 42 | } 43 | } 44 | 45 | extension MainViewController: UITableViewDataSource { 46 | func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 47 | return 3 48 | } 49 | 50 | func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 51 | let cell = tableView.dequeueReusableCell(withIdentifier: "chartCell", for: indexPath) as! ChartTableViewCell 52 | switch indexPath.row { 53 | case 0: 54 | cell.cellLabel.text = "Pie Chart" 55 | case 1: 56 | cell.cellLabel.text = "Bar Chart" 57 | case 2: 58 | cell.cellLabel.text = "Line Chart" 59 | default: 60 | break 61 | } 62 | return cell 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /PNChartSwift/Source/PNBar.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PNBar.swift 3 | // PNChartSwift 4 | // 5 | // Created by YiChen Zhou on 12/29/16. 6 | // Copyright © 2016 YiChen Zhou. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class PNBar: UIView { 12 | 13 | // Time brfore bar starts to animate 14 | var startAnimationTime: Double = 0 15 | var chartLine: CAShapeLayer = { 16 | return CAShapeLayer() 17 | 18 | }() 19 | 20 | var barColor = PNFreshGreen 21 | var barRadius: CGFloat = 0 { 22 | didSet { 23 | layer.cornerRadius = self.barRadius 24 | } 25 | } 26 | 27 | var grade: CGFloat = 0 { 28 | didSet { 29 | UIGraphicsBeginImageContext(self.frame.size) 30 | let path = CABasicAnimation(keyPath: "strokeEnd") 31 | path.duration = 1 32 | path.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut) 33 | path.fromValue = 0 34 | path.toValue = 1 35 | self.chartLine.add(path, forKey: "strokeEndAnimation") 36 | self.chartLine.strokeEnd = 1 37 | self.delay(delay: self.startAnimationTime, closure: { 38 | () -> () in 39 | self.chartLine.add(path, forKey: "strokeEndAnimation") 40 | let progressLine = UIBezierPath() 41 | progressLine.move(to: CGPoint(x: self.frame.size.width / 2.0, y: self.frame.size.height)) 42 | progressLine.addLine(to: CGPoint(x: self.frame.size.width / 2.0, y: (1 - self.grade) * self.frame.size.height)) 43 | progressLine.lineCapStyle = .square 44 | self.chartLine.path = progressLine.cgPath 45 | self.chartLine.strokeColor = self.barColor.cgColor 46 | }) 47 | UIGraphicsEndImageContext() 48 | } 49 | } 50 | 51 | override init(frame: CGRect) { 52 | super.init(frame: frame) 53 | self.chartLine = CAShapeLayer() 54 | self.chartLine.lineCap = CAShapeLayerLineCap.butt 55 | self.chartLine.fillColor = UIColor.white.cgColor 56 | self.chartLine.lineWidth = self.frame.size.width 57 | self.chartLine.strokeEnd = 0 58 | self.clipsToBounds = true 59 | self.backgroundColor = PNLightGrey 60 | self.layer.addSublayer(self.chartLine) 61 | self.barRadius = 10 62 | } 63 | 64 | required init?(coder aDecoder: NSCoder) { 65 | fatalError("init(coder:) has not been implemented") 66 | } 67 | 68 | override func draw(_ rect: CGRect) { 69 | // Draw BackGround 70 | let context = UIGraphicsGetCurrentContext()! 71 | context.setFillColor((self.backgroundColor?.cgColor)!) 72 | context.addRect(rect) 73 | } 74 | 75 | func delay(delay: Double, closure: @escaping () -> ()) { 76 | DispatchQueue.main.asyncAfter(deadline: .now() + delay) { 77 | () -> () in 78 | closure() 79 | } 80 | } 81 | 82 | func rollBack() { 83 | UIView.animate(withDuration: 0.3, delay: 0.0, options: .curveEaseInOut, animations: ({ 84 | self.chartLine.strokeColor = UIColor.clear.cgColor 85 | }), completion: nil) 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /PNChartSwift/Source/PNBarChart.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PNBarChart.swift 3 | // PNChartSwift 4 | // 5 | // Created by YiChen Zhou on 12/29/16. 6 | // Copyright © 2016 YiChen Zhou. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class PNBarChart: UIView { 12 | var bars = NSMutableArray() 13 | var xLabelWidth: CGFloat! 14 | var yValueMax: CGFloat! 15 | var strokeColor = PNGreen 16 | var strokeColors: Array! 17 | var xLabelHeight: CGFloat = 11 18 | var yLabelHeight: CGFloat = 20 19 | var labels: NSMutableArray = [] 20 | var xLabels = [String]() { 21 | didSet { 22 | if self.showLabel { 23 | self.xLabelWidth = (self.frame.size.width - self.chartMargin * 2.0 - yChartLabelWidth) / CGFloat(self.xLabels.count) 24 | } 25 | } 26 | } 27 | 28 | var yLabels = [String]() 29 | var yValues = [CGFloat]() { 30 | didSet { 31 | if self.yMaxValue != nil { 32 | self.yValueMax = self.yMaxValue 33 | } else { 34 | self.getYValueMax(yLabels: self.yValues) 35 | } 36 | self.xLabelWidth = (self.frame.size.width - self.chartMargin * 2 - yChartLabelWidth) / CGFloat(self.yValues.count) 37 | } 38 | } 39 | var yChartLabelWidth: CGFloat = 18 40 | var chartMargin: CGFloat = 15 41 | var showLabel = true 42 | var showChartBorder = false 43 | var chartBottomLine = CAShapeLayer() 44 | var chartLeftLine = CAShapeLayer() 45 | var barRadius: CGFloat = 0 46 | var barWidth: CGFloat! 47 | var labelMarginTop: CGFloat = 0 48 | var barBackgroundColor = PNLightGrey 49 | var labelTextColor = UIColor.darkGray 50 | var labelTextFont = UIFont(name: "Avenir-Medium", size: 11.0) 51 | var xLabelSkip = 1 52 | var yLabelSum = 4 53 | // Max value of the chart 54 | var yMaxValue: CGFloat! 55 | // Min value of the chart 56 | var yMinValue: CGFloat! 57 | var animationType: AnimationType = .Default 58 | // Initialize Methods 59 | override init(frame: CGRect) { 60 | super.init(frame: frame) 61 | self.backgroundColor = PNLightGrey 62 | self.clipsToBounds = true 63 | } 64 | 65 | required init?(coder aDecoder: NSCoder) { 66 | fatalError("init(coder:) has not been implemented") 67 | } 68 | 69 | func strokeChart() { 70 | self.viewCleanUpForCollection(arr: self.labels) 71 | 72 | if self.showLabel { 73 | // Add X Labels 74 | var labelAddCount = 0 75 | for index in 0.. 0 { 116 | barXPosition = CGFloat(index) * self.xLabelWidth + self.yChartLabelWidth + self.chartMargin + (self.xLabelWidth / 2) - (self.barWidth / 2) 117 | } else { 118 | barXPosition = CGFloat(index) * self.xLabelWidth + self.yChartLabelWidth + self.chartMargin + self.xLabelWidth * 0.25 119 | if self.showLabel { 120 | self.barWidth = self.xLabelWidth * 0.5 121 | } else { 122 | self.barWidth = self.xLabelWidth * 0.6 123 | } 124 | } 125 | 126 | let bar = PNBar(frame: CGRect(x: barXPosition, y: self.frame.size.height - chartCarvanHeight - self.xLabelHeight - self.chartMargin, width: self.barWidth, height: chartCarvanHeight)) 127 | bar.barRadius = self.barRadius 128 | bar.backgroundColor = self.barBackgroundColor 129 | if self.strokeColor != UIColor.black { 130 | bar.barColor = self.strokeColor 131 | } else { 132 | bar.barColor = self.barColorAtIndex(index: index) 133 | } 134 | 135 | if self.animationType == .Waterfall { 136 | bar.startAnimationTime = Double(index) * 0.1 137 | } 138 | 139 | // Height of Bar 140 | bar.grade = grade 141 | // For Click Index 142 | bar.tag = index 143 | self.bars.add(bar) 144 | self.addSubview(bar) 145 | index += 1 146 | } 147 | 148 | // Add Chart Border Lines 149 | if self.showChartBorder { 150 | self.chartBottomLine = CAShapeLayer() 151 | self.chartBottomLine.lineCap = CAShapeLayerLineCap.butt 152 | self.chartBottomLine.fillColor = UIColor.white.cgColor 153 | self.chartBottomLine.lineWidth = 1 154 | self.chartBottomLine.strokeEnd = 0 155 | let progressLine = UIBezierPath() 156 | progressLine.move(to: CGPoint(x: self.chartMargin, y: self.frame.size.height - self.xLabelHeight - self.chartMargin)) 157 | progressLine.addLine(to: CGPoint(x: self.frame.size.width - self.chartMargin, y: self.frame.size.height - self.xLabelHeight - self.chartMargin)) 158 | progressLine.lineWidth = 1 159 | progressLine.lineCapStyle = .square 160 | self.chartBottomLine.path = progressLine.cgPath 161 | let path = CABasicAnimation(keyPath: "strokeEnd") 162 | path.duration = 0.5 163 | path.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut) 164 | path.fromValue = 0 165 | path.toValue = 1 166 | self.chartBottomLine.add(path, forKey: "strokeEndAnimation") 167 | self.chartBottomLine.strokeEnd = 1 168 | self.layer.addSublayer(self.chartBottomLine) 169 | // Add Left Chart Line 170 | self.chartLeftLine = CAShapeLayer() 171 | self.chartLeftLine.lineCap = CAShapeLayerLineCap.butt 172 | self.chartLeftLine.fillColor = UIColor.white.cgColor 173 | self.chartLeftLine.lineWidth = 1 174 | self.chartLeftLine.strokeEnd = 0 175 | let progressLeftLine = UIBezierPath() 176 | progressLeftLine.move(to: CGPoint(x: self.chartMargin + self.yChartLabelWidth, y: self.frame.size.height - self.xLabelHeight - self.chartMargin)) 177 | progressLeftLine.addLine(to: CGPoint(x: self.chartMargin + self.yChartLabelWidth, y: self.chartMargin)) 178 | progressLeftLine.lineWidth = 1 179 | progressLeftLine.lineCapStyle = .square 180 | self.chartLeftLine.path = progressLeftLine.cgPath 181 | self.chartLeftLine.strokeColor = PNLightGrey.cgColor 182 | let pathLeft = CABasicAnimation(keyPath: "strokeEnd") 183 | pathLeft.duration = 0.5 184 | pathLeft.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut) 185 | pathLeft.fromValue = 0 186 | pathLeft.toValue = 1 187 | self.chartLeftLine.add(pathLeft, forKey: "strokeEndAnimation") 188 | self.chartLeftLine.strokeEnd = 1 189 | self.layer.addSublayer(self.chartLeftLine) 190 | } 191 | } 192 | 193 | } 194 | 195 | extension PNBarChart { 196 | enum AnimationType { 197 | case Default 198 | case Waterfall 199 | } 200 | 201 | func getYValueMax(yLabels: [CGFloat]) { 202 | let max = yLabels.max() 203 | if max == 0 { 204 | self.yValueMax = self.yMinValue 205 | } else { 206 | self.yValueMax = max 207 | } 208 | } 209 | 210 | func viewCleanUpForCollection(arr: NSMutableArray) { 211 | if arr.count > 0 { 212 | for object in arr { 213 | let view = object as! UIView 214 | view.removeFromSuperview() 215 | } 216 | arr.removeAllObjects() 217 | } 218 | } 219 | 220 | func barColorAtIndex(index: Int) -> UIColor { 221 | if self.strokeColors.count == self.yValues.count { 222 | return self.strokeColors[index] as! UIColor 223 | } else { 224 | return self.strokeColor 225 | } 226 | } 227 | 228 | override func touchesBegan(_ touches: Set, with event: UIEvent?) { 229 | self.touchPoint(touches, with: event) 230 | super.touchesBegan(touches, with: event) 231 | } 232 | 233 | func touchPoint(_ touches: Set, with event: UIEvent?) { 234 | let touch = touches.first 235 | let touchPoint = touch?.location(in: self) 236 | let subview = hitTest(touchPoint!, with: nil) 237 | 238 | if let barView = subview as? PNBar { 239 | self.userClickedOnBarChartIndex(barIndex: barView.tag) 240 | } 241 | } 242 | 243 | func userClickedOnBarChartIndex(barIndex: Int) { 244 | print("Click on bar \(barIndex)") 245 | } 246 | } 247 | -------------------------------------------------------------------------------- /PNChartSwift/Source/PNChartLabel.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PNChartLabel.swift 3 | // PNChartSwift 4 | // 5 | // Created by YiChen Zhou on 11/11/16. 6 | // Copyright © 2016 YiChen Zhou. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class PNChartLabel: UILabel { 12 | override init(frame: CGRect) { 13 | super.init(frame: frame) 14 | self.font = UIFont.boldSystemFont(ofSize: 10.0) 15 | self.textColor = PNGrey 16 | self.backgroundColor = UIColor.clear 17 | self.textAlignment = NSTextAlignment.center 18 | self.isUserInteractionEnabled = true 19 | } 20 | 21 | required init?(coder aDecoder: NSCoder) { 22 | fatalError("init(coder: NSCode) has not been implemented.") 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /PNChartSwift/Source/PNChartSwift.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = 'PNChartSwift' 3 | s.version = '0.0.2' 4 | s.license = 'MIT' 5 | s.summary = 'A simple and beautiful chart lib written in Swift for iOS' 6 | s.homepage = 'https://github.com/kevinzhow/PNChart-Swift' 7 | s.author = { "kevinzhow" => "kevinchou.c@gmail.com" } 8 | s.source = { :git => 'https://github.com/kevinzhow/PNChart-Swift.git' } 9 | 10 | s.ios.deployment_target = '8.0' 11 | 12 | s.source_files = 'PNChartSwift/**/*.swift' 13 | 14 | s.requires_arc = true 15 | end 16 | -------------------------------------------------------------------------------- /PNChartSwift/Source/PNColor.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PNColor.swift 3 | // PNChartSwift 4 | // 5 | // Created by YiChen Zhou on 12/30/16. 6 | // Copyright © 2016 YiChen Zhou. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | public let PNGreen = UIColor(red: 77.0/255.0, green: 186.0/255.0, blue: 122.0/255.0, alpha: 1.0) 12 | public let PNLightGreen = UIColor(red: 77.0/255.0, green: 216.0/255.0, blue: 122.0/255.0, alpha: 1.0) 13 | public let PNFreshGreen = UIColor(red: 77.0 / 255.0 , green: 196.0 / 255.0, blue: 122.0 / 255.0, alpha: 1.0) 14 | public let PNDeepGreen = UIColor(red: 77.0/255.0, green: 176.0/255.0, blue: 122.0/255.0, alpha: 1.0) 15 | 16 | public let PNGrey = UIColor(red: 186.0/255.0 , green: 186.0/255.0, blue: 186.0/255.0, alpha: 1.0) 17 | public let PNLightGrey = UIColor(red: 246.0 / 255.0 , green: 246.0 / 255.0, blue: 246.0 / 255.0, alpha: 1.0) 18 | public let PNDeepGrey = UIColor(red: 99.0/255.0, green: 99.0/255.0, blue: 99.0/255.0, alpha: 1.0) 19 | 20 | public let PNLightBlue = UIColor(red: 94.0/255.0, green: 147.0/255.0, blue: 246.0/255.0, alpha: 1.0) 21 | public let PNBule = UIColor(red: 82.0/255.0, green: 116.0/255.0, blue: 188.0/255.0, alpha: 1.0) 22 | public let PNDarkBlue = UIColor(red: 121.0/255.0, green: 134.0/255.0, blue: 142.0/255.0, alpha: 1.0) 23 | public let PNTwitterBlue = UIColor(red: 0.0/255.0, green: 171.0/255.0, blue: 243.0/255.0, alpha: 1.0) 24 | 25 | public let PNRed = UIColor(red: 245.0/255.0, green: 94.0/255.0, blue: 78.0/255.0, alpha: 1.0) 26 | -------------------------------------------------------------------------------- /PNChartSwift/Source/PNGenericChart.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PNGenericChart.swift 3 | // PNChartSwift 4 | // 5 | // Created by YiChen Zhou on 12/27/16. 6 | // Copyright © 2016 YiChen Zhou. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class PNGenericChart: UIView { 12 | var hasLegend: Bool! 13 | var legendPosition: PNLegendPosition! 14 | var legendStyle: PNLegendItemStyle! 15 | var legendFont: UIFont! 16 | var legendFontColor: UIColor! 17 | var labelRowsInSerialMode: Int! 18 | var displayAnimation: Bool = false 19 | 20 | func setupDefaultValues() { 21 | hasLegend = true 22 | legendPosition = .Bottom 23 | legendStyle = .Stacked 24 | labelRowsInSerialMode = 1 25 | displayAnimation = true 26 | } 27 | 28 | func getLegendWIthMaxWidth(maxWidth: Float) -> UIView! { 29 | //self.doesNotRecognizeSelector(_cmd) 30 | return nil 31 | } 32 | 33 | func setLabelRowsInSerialMode(num: Int) { 34 | if legendStyle == .Serial { 35 | labelRowsInSerialMode = num 36 | } else { 37 | labelRowsInSerialMode = 1 38 | } 39 | } 40 | } 41 | 42 | extension PNGenericChart { 43 | enum PNLegendPosition: Int { 44 | case Top = 0 45 | case Bottom = 1 46 | case Left = 2 47 | case Right = 3 48 | } 49 | 50 | enum PNLegendItemStyle: Int { 51 | case Stacked = 0 52 | case Serial = 1 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /PNChartSwift/Source/PNLineChart.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PNLineChart.swift 3 | // PNChartSwift 4 | // 5 | // Created by YiChen Zhou on 11/10/16. 6 | // Copyright © 2016 YiChen Zhou. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import QuartzCore 11 | 12 | class PNLineChart: UIView{ 13 | public var xLabels: NSArray = []{ 14 | didSet { 15 | if self.showLabel { 16 | self.xLabelWidth = self.chartCavanWidth/CGFloat(self.xLabels.count) 17 | for index in 0.., with event: UIEvent?) { 187 | self.touchPoint(touches: touches as NSSet, withEvent: event!) 188 | self.touchKeyPoint(touches: touches as NSSet, withEvent: event!) 189 | } 190 | 191 | override func touchesMoved(_ touches: Set, with event: UIEvent?) { 192 | self.touchPoint(touches: touches as NSSet, withEvent: event!) 193 | self.touchKeyPoint(touches: touches as NSSet, withEvent: event!) 194 | } 195 | 196 | func touchPoint(touches: NSSet, withEvent event: UIEvent) { 197 | let touch: UITouch = touches.anyObject() as! UITouch 198 | let touchPoint = touch.location(in: self) 199 | 200 | for linePoints in self.pathPoints { 201 | let linePointsArray = linePoints as! [PNValue] 202 | for index in 0..<(linePointsArray.count - 1) { 203 | let p1: CGPoint = (linePointsArray[index]).point 204 | let p2: CGPoint = (linePointsArray[index + 1]).point 205 | // The closest distance from point to value 206 | var distance: CGFloat = abs(((p2.x - p1.x) * (touchPoint.y - p1.y)) - ((p1.x - touchPoint.x) * (p1.y - p2.y))) 207 | distance = distance / hypot(p2.x - p1.x, p1.y - p2.y) 208 | if distance <= 5 { 209 | for path in self.chartPaths { 210 | if (path as AnyObject).contains(p1) { 211 | self.userClickedOnLinePoint(point: touchPoint, lineIndex: self.chartPaths.index(of: path)) 212 | } 213 | } 214 | } 215 | } 216 | } 217 | } 218 | 219 | func touchKeyPoint(touches: NSSet, withEvent event: UIEvent) { 220 | let touch: UITouch = touches.anyObject() as! UITouch 221 | let touchPoint = touch.location(in: self) 222 | 223 | for linePoints in pathPoints { 224 | let linePointsArray = pathPoints as! [PNValue] 225 | 226 | for index in 0..<(linePointsArray.count - 1) { 227 | let p1: CGPoint = (linePointsArray[index]).point 228 | let p2: CGPoint = (linePointsArray[index + 1]).point 229 | 230 | let distanceToP1: CGFloat = abs(CGFloat(hypot(touchPoint.x - p1.x , touchPoint.y - p1.y ))) 231 | let distanceToP2: CGFloat = hypot( touchPoint.x - p2.x, touchPoint.y - p2.y) 232 | 233 | let distance: CGFloat = fmin(distanceToP1, distanceToP2) 234 | if distance <= 10 { 235 | self.userClickedOnLineKeyPoint(point: touchPoint, lineIndex: self.pathPoints.index(of: linePoints), keyPointIndex: (distance == distanceToP2 ? index + 1 : index)) 236 | } 237 | } 238 | } 239 | } 240 | 241 | // This method will be called and stroke the line in animation 242 | func strokeChart() { 243 | let chartPaths = NSMutableArray() 244 | let pointPaths = NSMutableArray() 245 | 246 | for lineIndex in 0.. CGFloat { 457 | let size = CGSize(width: width, height: CGFloat.greatestFiniteMagnitude) 458 | let rect = text.boundingRect(with: size, options: .usesLineFragmentOrigin, attributes: [NSAttributedString.Key.font: font], context: nil) 459 | return rect.size.height 460 | } 461 | 462 | func drawTextInContext(ctx: CGContext, text: NSString, rect: CGRect, font: UIFont) { 463 | let priceParagraphStyle: NSMutableParagraphStyle = NSParagraphStyle.default as! NSMutableParagraphStyle 464 | priceParagraphStyle.lineBreakMode = .byTruncatingTail 465 | priceParagraphStyle.alignment = .left 466 | text.draw(in: rect, withAttributes: [NSAttributedString.Key.paragraphStyle: priceParagraphStyle]) 467 | } 468 | 469 | func userClickedOnLineKeyPoint(point: CGPoint, lineIndex: Int, keyPointIndex: Int) { 470 | print("Click Key on line \(point.x), \(point.y) line index is \(lineIndex) and point index is \(keyPointIndex)") 471 | } 472 | 473 | func userClickedOnLinePoint(point: CGPoint, lineIndex: Int) { 474 | print("Click Key on line \(point.x), \(point.y) line index is \(lineIndex)") 475 | } 476 | } 477 | -------------------------------------------------------------------------------- /PNChartSwift/Source/PNLineChartData.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PNLineChartData.swift 3 | // PNChartSwift 4 | // 5 | // Created by YiChen Zhou on 11/10/16. 6 | // Copyright © 2016 YiChen Zhou. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | public class PNLineChartData { 12 | public var getData = { 13 | (index: Int) -> PNLineChartDataItem in 14 | return PNLineChartDataItem() 15 | } 16 | 17 | public var inflexPointStyle = PNLineChartPointStyle.None 18 | public var color: UIColor = UIColor.gray 19 | public var itemCount: Int = 0 20 | public var lineWidth: CGFloat = 2.0 21 | public var inflexionPointWidth: CGFloat = 6.0 22 | 23 | public init() { } 24 | } 25 | 26 | extension PNLineChartData { 27 | public enum PNLineChartPointStyle: Int { 28 | case None = 0 29 | case Cycle 30 | case Triangle 31 | case Square 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /PNChartSwift/Source/PNLineChartDataItem.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PNLineChartDataItem.swift 3 | // PNChartSwift 4 | // 5 | // Created by YiChen Zhou on 11/10/16. 6 | // Copyright © 2016 YiChen Zhou. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | public class PNLineChartDataItem { 12 | var y: CGFloat = 0.0 13 | 14 | public init() { } 15 | 16 | public init(y: CGFloat) { 17 | self.y = y 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /PNChartSwift/Source/PNPieChart.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PNPieChart.swift 3 | // PNChartSwift 4 | // 5 | // Created by YiChen Zhou on 12/27/16. 6 | // Copyright © 2016 YiChen Zhou. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class PNPieChart: PNGenericChart { 12 | lazy var items: [PNPieChartDataItem] = { 13 | return [PNPieChartDataItem]() 14 | }() 15 | 16 | var endPercentages = [CGFloat]() 17 | var contentView = UIView() 18 | var pieLayer: CAShapeLayer = { 19 | return CAShapeLayer() 20 | }() 21 | 22 | var descriptionLabels = NSMutableArray() 23 | var sectorHighlight: CAShapeLayer = { 24 | return CAShapeLayer() 25 | }() 26 | 27 | var selectedItems = NSMutableDictionary() 28 | var descriptionTextFont: UIFont = { 29 | return UIFont(name: "Avenir-Medium", size: 14)! 30 | }() 31 | var descriptionTextColor: UIColor = { 32 | return UIColor.white 33 | }() 34 | var descriptionTextShadowColor: UIColor = { 35 | return UIColor.darkGray 36 | }() 37 | var descriptionTextShadowOffset: CGSize = { 38 | return CGSize(width: 0, height: 1) 39 | }() 40 | var duration: TimeInterval = 1.0 41 | 42 | var hideValues: Bool = true 43 | var showOnlyValues: Bool = true 44 | var showAbsoluteValues: Bool = true 45 | var showTextShadow: Bool = true 46 | 47 | // Hide percentage labels less than cutoff value 48 | var labelPercentageCutoff: CGFloat = 0 49 | 50 | // Default as true 51 | var shouldHighlightSectorOnTouch: Bool = true 52 | 53 | // Current outer radius. Override recompute() to change this. 54 | lazy var outerCircleRadius: CGFloat = { 55 | return self.bounds.size.width / 2 56 | }() 57 | 58 | // Current inner radius. Override recompute() to change this. 59 | lazy var innerCircleRadius: CGFloat = { 60 | return self.bounds.size.width / 6 61 | }() 62 | 63 | // Multiple selection 64 | var enableMultipleSelection: Bool = true 65 | 66 | init(frame: CGRect, items: [PNPieChartDataItem]) { 67 | super.init(frame: frame) 68 | self.items = items 69 | self.baseInit() 70 | } 71 | 72 | required init?(coder aDecoder: NSCoder) { 73 | fatalError("init(coder:) has not been implemented") 74 | } 75 | 76 | override func awakeFromNib() { 77 | super.awakeFromNib() 78 | self.baseInit() 79 | } 80 | override func layoutSubviews() { 81 | super.layoutSubviews() 82 | self.strokeChart() 83 | } 84 | 85 | func baseInit() { 86 | self.shouldHighlightSectorOnTouch = true 87 | self.enableMultipleSelection = true 88 | self.labelPercentageCutoff = 0 89 | self.hideValues = false 90 | self.showOnlyValues = false 91 | self.showAbsoluteValues = false 92 | self.showTextShadow = false 93 | super.setupDefaultValues() 94 | self.loadDefault() 95 | } 96 | 97 | func loadDefault() { 98 | var currentTotal: CGFloat = 0; 99 | var total: CGFloat = 0 100 | for index in 0.. CGFloat { 155 | if index == 0 { 156 | return 0 157 | } else { 158 | return self.endPercentages[index - 1] 159 | } 160 | } 161 | 162 | func endPercentageForItemAtIndex(index: Int) -> CGFloat { 163 | return self.endPercentages[index] 164 | } 165 | 166 | func ratioForItemAtIndex(index: Int) -> CGFloat { 167 | return self.endPercentageForItemAtIndex(index: index) - self.startPercentageForItemAtIndex(index: index) 168 | } 169 | 170 | func newCircileLayerWithRadius(radius: CGFloat, borderWidth: CGFloat, fillColor: UIColor, borderColor: UIColor, startPercentage: CGFloat, endPercentage: CGFloat) -> CAShapeLayer { 171 | let circle = CAShapeLayer(layer: self.layer) 172 | 173 | let center = CGPoint(x: self.bounds.midX, y: self.bounds.midY) 174 | let path = UIBezierPath(arcCenter: center, radius: radius, startAngle: -(CGFloat)(Double.pi/2), endAngle: CGFloat(Double.pi/2) * 3, clockwise: true) 175 | circle.fillColor = fillColor.cgColor 176 | circle.strokeColor = borderColor.cgColor 177 | circle.strokeStart = startPercentage 178 | circle.strokeEnd = endPercentage 179 | circle.lineWidth = borderWidth 180 | circle.path = path.cgPath 181 | return circle 182 | } 183 | 184 | func maskChart() { 185 | let radius = self.innerCircleRadius + (self.outerCircleRadius - self.innerCircleRadius) / 2 186 | let borderWidth = self.outerCircleRadius - self.innerCircleRadius 187 | let maskLayer = self.newCircileLayerWithRadius(radius: radius, borderWidth: borderWidth, fillColor: UIColor.clear, borderColor: UIColor.black, startPercentage: 0, endPercentage: 1) 188 | self.pieLayer.mask = maskLayer 189 | } 190 | 191 | func descriptionLabelForItemAtIndex(index: Int) -> UILabel? { 192 | let currentDateItem = self.items[index] 193 | let distance = self.innerCircleRadius + (self.outerCircleRadius - self.innerCircleRadius) / 2 194 | let centerPercentage = (self.startPercentageForItemAtIndex(index: index) + self.endPercentageForItemAtIndex(index: index)) / 2 195 | let rad = Double(centerPercentage) * 2 * Double.pi 196 | let descriptionLabel = UILabel(frame: CGRect(x: 0, y: 0, width: 100, height: 80)) 197 | let titleText = currentDateItem.text 198 | var titleValue: String { 199 | if self.showAbsoluteValues { 200 | return String(format: "%.0f", currentDateItem.value!) 201 | } else { 202 | return String(format: "%.0f%%", self.ratioForItemAtIndex(index: index) * 100) 203 | } 204 | } 205 | 206 | if self.hideValues { 207 | descriptionLabel.text = titleText 208 | } else if (titleText == nil || self.showOnlyValues) { 209 | descriptionLabel.text = titleValue 210 | } else { 211 | descriptionLabel.text = titleValue + String(format: "\n%@", titleText!) 212 | } 213 | 214 | // If value is less than cutoff, show no label 215 | if self.ratioForItemAtIndex(index: index) < self.labelPercentageCutoff { 216 | descriptionLabel.text = nil 217 | } 218 | 219 | let center = CGPoint(x: self.outerCircleRadius + distance * CGFloat(sin(rad)), y: self.outerCircleRadius - distance * CGFloat(cos(rad))) 220 | descriptionLabel.font = self.descriptionTextFont 221 | let labelSize = descriptionLabel.text?.size(withAttributes: [NSAttributedString.Key.font: descriptionLabel.font as Any]) 222 | descriptionLabel.frame = CGRect(x: descriptionLabel.frame.origin.x, y: descriptionLabel.frame.origin.y, width: descriptionLabel.frame.size.width, height: (labelSize?.height)!) 223 | descriptionLabel.numberOfLines = 0 224 | descriptionLabel.textColor = self.descriptionTextColor 225 | descriptionLabel.textAlignment = .center 226 | 227 | if self.showTextShadow { 228 | descriptionLabel.shadowColor = self.descriptionTextShadowColor 229 | descriptionLabel.shadowOffset = self.descriptionTextShadowOffset 230 | } 231 | 232 | descriptionLabel.center = center 233 | descriptionLabel.alpha = 1 234 | descriptionLabel.backgroundColor = UIColor.clear 235 | return descriptionLabel 236 | } 237 | 238 | func addAnimationIfNeeded() { 239 | if self.displayAnimation { 240 | let animation = CABasicAnimation(keyPath: "strokeEnd") 241 | animation.duration = duration 242 | animation.fromValue = 0 243 | animation.toValue = 1 244 | animation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut) 245 | animation.isRemovedOnCompletion = true 246 | self.pieLayer.mask?.add(animation, forKey: "circleAnimation") 247 | } 248 | } 249 | 250 | func findPercentageOfAngleInCircle(center: CGPoint, fromPoint reference: CGPoint) -> CGFloat { 251 | let disY = Float(reference.y - center.y) 252 | let disX = Float(reference.x - center.x) 253 | let angleOfLine = atanf((disY) / (disX)) 254 | let percentage = (angleOfLine + Float(Double.pi/2)) / Float(2 * Double.pi) 255 | 256 | if disX > 0 { 257 | return CGFloat(percentage) 258 | } else { 259 | return CGFloat(percentage + 0.5) 260 | } 261 | } 262 | 263 | func didTouchAt(touchLocation: CGPoint) { 264 | let circleCenter = CGPoint(x: self.contentView.bounds.size.width / 2.0, y: self.contentView.bounds.size.height / 2.0) 265 | let distanceY = Float(touchLocation.y - circleCenter.y) 266 | let distanceX = Float(touchLocation.x - circleCenter.x) 267 | let distanceFromCenter = CGFloat(sqrtf(powf(distanceY, 2) + powf(distanceX, 2))) 268 | 269 | if distanceFromCenter < self.innerCircleRadius { 270 | self.sectorHighlight.removeFromSuperlayer() 271 | return 272 | } 273 | 274 | let percentage = self.findPercentageOfAngleInCircle(center: circleCenter, fromPoint: touchLocation) 275 | var index = 0 276 | while percentage > self.endPercentageForItemAtIndex(index: index) { 277 | index = index + 1 278 | } 279 | 280 | if self.shouldHighlightSectorOnTouch { 281 | if self.enableMultipleSelection { 282 | self.sectorHighlight.removeFromSuperlayer() 283 | let currentItem = self.items[index] 284 | let newColor = currentItem.color!.withAlphaComponent(0.5) 285 | let startPercentage = self.startPercentageForItemAtIndex(index: index) 286 | let endPercentage = self.endPercentageForItemAtIndex(index: index) 287 | 288 | self.sectorHighlight = self.newCircileLayerWithRadius(radius: outerCircleRadius + 5, borderWidth: 10, fillColor: UIColor.clear, borderColor: newColor, startPercentage: startPercentage, endPercentage: endPercentage) 289 | if self.enableMultipleSelection { 290 | let dicIndex = String(index) 291 | let indexShape = self.selectedItems.value(forKey: dicIndex) as? CAShapeLayer 292 | 293 | if indexShape != nil { 294 | indexShape?.removeFromSuperlayer() 295 | self.selectedItems.removeObject(forKey: dicIndex) 296 | } else { 297 | self.selectedItems.setObject(self.sectorHighlight, forKey: dicIndex as NSCopying) 298 | self.contentView.layer.addSublayer(self.sectorHighlight) 299 | } 300 | } else { 301 | self.contentView.layer.addSublayer(self.sectorHighlight) 302 | } 303 | } 304 | } 305 | } 306 | 307 | override func touchesBegan(_ touches: Set, with event: UIEvent?) { 308 | for touch in touches { 309 | let touchLocation = touch.location(in: self.contentView) 310 | self.didTouchAt(touchLocation: touchLocation) 311 | } 312 | } 313 | } 314 | 315 | -------------------------------------------------------------------------------- /PNChartSwift/Source/PNPieChartDataItem.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PNPieChartDataItem.swift 3 | // PNChartSwift 4 | // 5 | // Created by YiChen Zhou on 12/27/16. 6 | // Copyright © 2016 YiChen Zhou. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class PNPieChartDataItem: NSObject { 12 | var color: UIColor? 13 | var text: String? 14 | var value: CGFloat? 15 | 16 | init(dateColor color: UIColor, description text: String) { 17 | self.color = color 18 | self.text = text 19 | } 20 | 21 | init(dateValue value: CGFloat, dateColor color: UIColor, description text: String) { 22 | self.value = value 23 | self.color = color 24 | self.text = text 25 | } 26 | 27 | func setValue(newValue: CGFloat) { 28 | guard newValue > 0 else { 29 | print("Value should >= 0") 30 | return 31 | } 32 | self.value = (self.value != newValue) ? newValue : value 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /PNChartSwift/Source/PNValue.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PNValue.swift 3 | // PNChartSwift 4 | // 5 | // Created by YiChen Zhou on 11/11/16. 6 | // Copyright © 2016 YiChen Zhou. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class PNValue{ 12 | var point: CGPoint = CGPoint() 13 | init(point: CGPoint) 14 | { 15 | self.point = point 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /PNChartSwiftTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /PNChartSwiftTests/PNChartSwiftTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PNChartSwiftTests.swift 3 | // PNChartSwiftTests 4 | // 5 | // Created by YiChen Zhou on 12/30/16. 6 | // 7 | // 8 | 9 | import XCTest 10 | @testable import PNChartSwift 11 | 12 | class PNChartSwiftTests: XCTestCase { 13 | 14 | override func setUp() { 15 | super.setUp() 16 | // Put setup code here. This method is called before the invocation of each test method in the class. 17 | } 18 | 19 | override func tearDown() { 20 | // Put teardown code here. This method is called after the invocation of each test method in the class. 21 | super.tearDown() 22 | } 23 | 24 | func testExample() { 25 | // This is an example of a functional test case. 26 | // Use XCTAssert and related functions to verify your tests produce the correct results. 27 | } 28 | 29 | func testPerformanceExample() { 30 | // This is an example of a performance test case. 31 | self.measure { 32 | // Put the code you want to measure the time of here. 33 | } 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /PNChartSwiftUITests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /PNChartSwiftUITests/PNChartSwiftUITests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PNChartSwiftUITests.swift 3 | // PNChartSwiftUITests 4 | // 5 | // Created by YiChen Zhou on 12/30/16. 6 | // 7 | // 8 | 9 | import XCTest 10 | 11 | class PNChartSwiftUITests: XCTestCase { 12 | 13 | override func setUp() { 14 | super.setUp() 15 | 16 | // Put setup code here. This method is called before the invocation of each test method in the class. 17 | 18 | // In UI tests it is usually best to stop immediately when a failure occurs. 19 | continueAfterFailure = false 20 | // UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method. 21 | XCUIApplication().launch() 22 | 23 | // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this. 24 | } 25 | 26 | override func tearDown() { 27 | // Put teardown code here. This method is called after the invocation of each test method in the class. 28 | super.tearDown() 29 | } 30 | 31 | func testExample() { 32 | // Use recording to get started writing UI tests. 33 | // Use XCTAssert and related functions to verify your tests produce the correct results. 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | PNChart-Swift 2 | ============= 3 | 4 | PNChart(https://github.com/kevinzhow/PNChart) Swift Implementation 5 | 6 | # Installation 7 | This isn't on CocoaPods yet, so to install, add this to your Podfile 8 | ``` 9 | pod 'PNChartSwift',:git => 'https://github.com/kevinzhow/PNChart-Swift.git' 10 | ``` 11 | --------------------------------------------------------------------------------