├── .gitignore ├── .swiftpm └── xcode │ └── package.xcworkspace │ └── contents.xcworkspacedata ├── AMChart.podspec ├── AMChart.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist └── xcshareddata │ └── xcschemes │ └── AMChart.xcscheme ├── AMChart ├── AMChart.h └── Info.plist ├── LICENSE ├── Package.swift ├── README.md ├── SampleAMChart ├── SampleAMChart.xcodeproj │ ├── project.pbxproj │ └── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist └── SampleAMChart │ ├── Assets.xcassets │ └── AppIcon.appiconset │ │ └── Contents.json │ ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard │ ├── Classes │ ├── AppDelegate.swift │ └── ViewController.swift │ └── Info.plist └── Source ├── AMBarChartView.swift ├── AMChartData.swift ├── AMChartView.swift ├── AMLineChartView.swift ├── AMPieChartView.swift ├── AMRadarChartView.swift └── AMScatterChartView.swift /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode (from gitignore.io) 2 | build/ 3 | *.pbxuser 4 | !default.pbxuser 5 | *.mode1v3 6 | !default.mode1v3 7 | *.mode2v3 8 | !default.mode2v3 9 | *.perspectivev3 10 | !default.perspectivev3 11 | xcuserdata 12 | *.xccheckout 13 | *.moved-aside 14 | DerivedData 15 | *.hmap 16 | *.ipa 17 | *.xcuserstate 18 | 19 | # CocoaPod 20 | Pods/* 21 | Podfile.lock 22 | 23 | # Carthage 24 | Carthage/Build 25 | 26 | # others 27 | *.swp 28 | !.gitkeep 29 | .DS_Store 30 | UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /AMChart.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = "AMChart" 3 | s.version = "2.3.3" 4 | s.summary = "It can display chart." 5 | s.license = { :type => 'MIT', :file => 'LICENSE' } 6 | s.homepage = "https://github.com/adventam10/AMChart" 7 | s.author = { "am10" => "adventam10@gmail.com" } 8 | s.source = { :git => "https://github.com/adventam10/AMChart.git", :tag => "#{s.version}" } 9 | s.platform = :ios, "9.0" 10 | s.requires_arc = true 11 | s.source_files = 'Source/*.{swift}' 12 | s.swift_version = "5.0" 13 | end 14 | 15 | -------------------------------------------------------------------------------- /AMChart.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 48; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 0E3ADB75235C1BCE008F5FCD /* AMChartView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E3ADB73235C1BCD008F5FCD /* AMChartView.swift */; }; 11 | 0E3ADB76235C1BCE008F5FCD /* AMChartData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E3ADB74235C1BCE008F5FCD /* AMChartData.swift */; }; 12 | 0E407B10235483F30096FA4A /* AMLineChartView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E407B0B235483F30096FA4A /* AMLineChartView.swift */; }; 13 | 0E407B11235483F30096FA4A /* AMPieChartView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E407B0C235483F30096FA4A /* AMPieChartView.swift */; }; 14 | 0E407B12235483F30096FA4A /* AMScatterChartView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E407B0D235483F30096FA4A /* AMScatterChartView.swift */; }; 15 | 0E407B13235483F30096FA4A /* AMBarChartView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E407B0E235483F30096FA4A /* AMBarChartView.swift */; }; 16 | 0E407B14235483F30096FA4A /* AMRadarChartView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E407B0F235483F30096FA4A /* AMRadarChartView.swift */; }; 17 | 0E4753A6201F7412002EA382 /* AMChart.h in Headers */ = {isa = PBXBuildFile; fileRef = 0E4753A4201F7412002EA382 /* AMChart.h */; settings = {ATTRIBUTES = (Public, ); }; }; 18 | /* End PBXBuildFile section */ 19 | 20 | /* Begin PBXFileReference section */ 21 | 0E3ADB73235C1BCD008F5FCD /* AMChartView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AMChartView.swift; sourceTree = ""; }; 22 | 0E3ADB74235C1BCE008F5FCD /* AMChartData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AMChartData.swift; sourceTree = ""; }; 23 | 0E407B0B235483F30096FA4A /* AMLineChartView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AMLineChartView.swift; sourceTree = ""; }; 24 | 0E407B0C235483F30096FA4A /* AMPieChartView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AMPieChartView.swift; sourceTree = ""; }; 25 | 0E407B0D235483F30096FA4A /* AMScatterChartView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AMScatterChartView.swift; sourceTree = ""; }; 26 | 0E407B0E235483F30096FA4A /* AMBarChartView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AMBarChartView.swift; sourceTree = ""; }; 27 | 0E407B0F235483F30096FA4A /* AMRadarChartView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AMRadarChartView.swift; sourceTree = ""; }; 28 | 0E4753A1201F7412002EA382 /* AMChart.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = AMChart.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 29 | 0E4753A4201F7412002EA382 /* AMChart.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AMChart.h; sourceTree = ""; }; 30 | 0E4753A5201F7412002EA382 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 31 | /* End PBXFileReference section */ 32 | 33 | /* Begin PBXFrameworksBuildPhase section */ 34 | 0E47539D201F7412002EA382 /* Frameworks */ = { 35 | isa = PBXFrameworksBuildPhase; 36 | buildActionMask = 2147483647; 37 | files = ( 38 | ); 39 | runOnlyForDeploymentPostprocessing = 0; 40 | }; 41 | /* End PBXFrameworksBuildPhase section */ 42 | 43 | /* Begin PBXGroup section */ 44 | 0E407B0A235483F30096FA4A /* Source */ = { 45 | isa = PBXGroup; 46 | children = ( 47 | 0E3ADB74235C1BCE008F5FCD /* AMChartData.swift */, 48 | 0E3ADB73235C1BCD008F5FCD /* AMChartView.swift */, 49 | 0E407B0B235483F30096FA4A /* AMLineChartView.swift */, 50 | 0E407B0C235483F30096FA4A /* AMPieChartView.swift */, 51 | 0E407B0D235483F30096FA4A /* AMScatterChartView.swift */, 52 | 0E407B0E235483F30096FA4A /* AMBarChartView.swift */, 53 | 0E407B0F235483F30096FA4A /* AMRadarChartView.swift */, 54 | ); 55 | path = Source; 56 | sourceTree = ""; 57 | }; 58 | 0E475397201F7412002EA382 = { 59 | isa = PBXGroup; 60 | children = ( 61 | 0E407B0A235483F30096FA4A /* Source */, 62 | 0E4753A3201F7412002EA382 /* AMChart */, 63 | 0E4753A2201F7412002EA382 /* Products */, 64 | ); 65 | sourceTree = ""; 66 | }; 67 | 0E4753A2201F7412002EA382 /* Products */ = { 68 | isa = PBXGroup; 69 | children = ( 70 | 0E4753A1201F7412002EA382 /* AMChart.framework */, 71 | ); 72 | name = Products; 73 | sourceTree = ""; 74 | }; 75 | 0E4753A3201F7412002EA382 /* AMChart */ = { 76 | isa = PBXGroup; 77 | children = ( 78 | 0E4753A4201F7412002EA382 /* AMChart.h */, 79 | 0E4753A5201F7412002EA382 /* Info.plist */, 80 | ); 81 | path = AMChart; 82 | sourceTree = ""; 83 | }; 84 | /* End PBXGroup section */ 85 | 86 | /* Begin PBXHeadersBuildPhase section */ 87 | 0E47539E201F7412002EA382 /* Headers */ = { 88 | isa = PBXHeadersBuildPhase; 89 | buildActionMask = 2147483647; 90 | files = ( 91 | 0E4753A6201F7412002EA382 /* AMChart.h in Headers */, 92 | ); 93 | runOnlyForDeploymentPostprocessing = 0; 94 | }; 95 | /* End PBXHeadersBuildPhase section */ 96 | 97 | /* Begin PBXNativeTarget section */ 98 | 0E4753A0201F7412002EA382 /* AMChart */ = { 99 | isa = PBXNativeTarget; 100 | buildConfigurationList = 0E4753A9201F7412002EA382 /* Build configuration list for PBXNativeTarget "AMChart" */; 101 | buildPhases = ( 102 | 0E47539C201F7412002EA382 /* Sources */, 103 | 0E47539D201F7412002EA382 /* Frameworks */, 104 | 0E47539E201F7412002EA382 /* Headers */, 105 | 0E47539F201F7412002EA382 /* Resources */, 106 | ); 107 | buildRules = ( 108 | ); 109 | dependencies = ( 110 | ); 111 | name = AMChart; 112 | productName = AMChart; 113 | productReference = 0E4753A1201F7412002EA382 /* AMChart.framework */; 114 | productType = "com.apple.product-type.framework"; 115 | }; 116 | /* End PBXNativeTarget section */ 117 | 118 | /* Begin PBXProject section */ 119 | 0E475398201F7412002EA382 /* Project object */ = { 120 | isa = PBXProject; 121 | attributes = { 122 | LastUpgradeCheck = 1020; 123 | ORGANIZATIONNAME = am10; 124 | TargetAttributes = { 125 | 0E4753A0201F7412002EA382 = { 126 | CreatedOnToolsVersion = 9.2; 127 | LastSwiftMigration = 1020; 128 | ProvisioningStyle = Automatic; 129 | }; 130 | }; 131 | }; 132 | buildConfigurationList = 0E47539B201F7412002EA382 /* Build configuration list for PBXProject "AMChart" */; 133 | compatibilityVersion = "Xcode 8.0"; 134 | developmentRegion = en; 135 | hasScannedForEncodings = 0; 136 | knownRegions = ( 137 | en, 138 | ); 139 | mainGroup = 0E475397201F7412002EA382; 140 | productRefGroup = 0E4753A2201F7412002EA382 /* Products */; 141 | projectDirPath = ""; 142 | projectRoot = ""; 143 | targets = ( 144 | 0E4753A0201F7412002EA382 /* AMChart */, 145 | ); 146 | }; 147 | /* End PBXProject section */ 148 | 149 | /* Begin PBXResourcesBuildPhase section */ 150 | 0E47539F201F7412002EA382 /* Resources */ = { 151 | isa = PBXResourcesBuildPhase; 152 | buildActionMask = 2147483647; 153 | files = ( 154 | ); 155 | runOnlyForDeploymentPostprocessing = 0; 156 | }; 157 | /* End PBXResourcesBuildPhase section */ 158 | 159 | /* Begin PBXSourcesBuildPhase section */ 160 | 0E47539C201F7412002EA382 /* Sources */ = { 161 | isa = PBXSourcesBuildPhase; 162 | buildActionMask = 2147483647; 163 | files = ( 164 | 0E407B14235483F30096FA4A /* AMRadarChartView.swift in Sources */, 165 | 0E3ADB75235C1BCE008F5FCD /* AMChartView.swift in Sources */, 166 | 0E407B12235483F30096FA4A /* AMScatterChartView.swift in Sources */, 167 | 0E407B11235483F30096FA4A /* AMPieChartView.swift in Sources */, 168 | 0E407B10235483F30096FA4A /* AMLineChartView.swift in Sources */, 169 | 0E407B13235483F30096FA4A /* AMBarChartView.swift in Sources */, 170 | 0E3ADB76235C1BCE008F5FCD /* AMChartData.swift in Sources */, 171 | ); 172 | runOnlyForDeploymentPostprocessing = 0; 173 | }; 174 | /* End PBXSourcesBuildPhase section */ 175 | 176 | /* Begin XCBuildConfiguration section */ 177 | 0E4753A7201F7412002EA382 /* Debug */ = { 178 | isa = XCBuildConfiguration; 179 | buildSettings = { 180 | ALWAYS_SEARCH_USER_PATHS = NO; 181 | CLANG_ANALYZER_NONNULL = YES; 182 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 183 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 184 | CLANG_CXX_LIBRARY = "libc++"; 185 | CLANG_ENABLE_MODULES = YES; 186 | CLANG_ENABLE_OBJC_ARC = YES; 187 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 188 | CLANG_WARN_BOOL_CONVERSION = YES; 189 | CLANG_WARN_COMMA = YES; 190 | CLANG_WARN_CONSTANT_CONVERSION = YES; 191 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 192 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 193 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 194 | CLANG_WARN_EMPTY_BODY = YES; 195 | CLANG_WARN_ENUM_CONVERSION = YES; 196 | CLANG_WARN_INFINITE_RECURSION = YES; 197 | CLANG_WARN_INT_CONVERSION = YES; 198 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 199 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 200 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 201 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 202 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 203 | CLANG_WARN_STRICT_PROTOTYPES = YES; 204 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 205 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 206 | CLANG_WARN_UNREACHABLE_CODE = YES; 207 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 208 | CODE_SIGN_IDENTITY = "iPhone Developer"; 209 | COPY_PHASE_STRIP = NO; 210 | CURRENT_PROJECT_VERSION = 1; 211 | DEBUG_INFORMATION_FORMAT = dwarf; 212 | ENABLE_STRICT_OBJC_MSGSEND = YES; 213 | ENABLE_TESTABILITY = YES; 214 | GCC_C_LANGUAGE_STANDARD = gnu11; 215 | GCC_DYNAMIC_NO_PIC = NO; 216 | GCC_NO_COMMON_BLOCKS = YES; 217 | GCC_OPTIMIZATION_LEVEL = 0; 218 | GCC_PREPROCESSOR_DEFINITIONS = ( 219 | "DEBUG=1", 220 | "$(inherited)", 221 | ); 222 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 223 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 224 | GCC_WARN_UNDECLARED_SELECTOR = YES; 225 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 226 | GCC_WARN_UNUSED_FUNCTION = YES; 227 | GCC_WARN_UNUSED_VARIABLE = YES; 228 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 229 | MTL_ENABLE_DEBUG_INFO = YES; 230 | ONLY_ACTIVE_ARCH = YES; 231 | SDKROOT = iphoneos; 232 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 233 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 234 | VERSIONING_SYSTEM = "apple-generic"; 235 | VERSION_INFO_PREFIX = ""; 236 | }; 237 | name = Debug; 238 | }; 239 | 0E4753A8201F7412002EA382 /* Release */ = { 240 | isa = XCBuildConfiguration; 241 | buildSettings = { 242 | ALWAYS_SEARCH_USER_PATHS = NO; 243 | CLANG_ANALYZER_NONNULL = YES; 244 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 245 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 246 | CLANG_CXX_LIBRARY = "libc++"; 247 | CLANG_ENABLE_MODULES = YES; 248 | CLANG_ENABLE_OBJC_ARC = YES; 249 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 250 | CLANG_WARN_BOOL_CONVERSION = YES; 251 | CLANG_WARN_COMMA = YES; 252 | CLANG_WARN_CONSTANT_CONVERSION = YES; 253 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 254 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 255 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 256 | CLANG_WARN_EMPTY_BODY = YES; 257 | CLANG_WARN_ENUM_CONVERSION = YES; 258 | CLANG_WARN_INFINITE_RECURSION = YES; 259 | CLANG_WARN_INT_CONVERSION = YES; 260 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 261 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 262 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 263 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 264 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 265 | CLANG_WARN_STRICT_PROTOTYPES = YES; 266 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 267 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 268 | CLANG_WARN_UNREACHABLE_CODE = YES; 269 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 270 | CODE_SIGN_IDENTITY = "iPhone Developer"; 271 | COPY_PHASE_STRIP = NO; 272 | CURRENT_PROJECT_VERSION = 1; 273 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 274 | ENABLE_NS_ASSERTIONS = NO; 275 | ENABLE_STRICT_OBJC_MSGSEND = YES; 276 | GCC_C_LANGUAGE_STANDARD = gnu11; 277 | GCC_NO_COMMON_BLOCKS = YES; 278 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 279 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 280 | GCC_WARN_UNDECLARED_SELECTOR = YES; 281 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 282 | GCC_WARN_UNUSED_FUNCTION = YES; 283 | GCC_WARN_UNUSED_VARIABLE = YES; 284 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 285 | MTL_ENABLE_DEBUG_INFO = NO; 286 | SDKROOT = iphoneos; 287 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 288 | VALIDATE_PRODUCT = YES; 289 | VERSIONING_SYSTEM = "apple-generic"; 290 | VERSION_INFO_PREFIX = ""; 291 | }; 292 | name = Release; 293 | }; 294 | 0E4753AA201F7412002EA382 /* Debug */ = { 295 | isa = XCBuildConfiguration; 296 | buildSettings = { 297 | CODE_SIGN_IDENTITY = ""; 298 | CODE_SIGN_STYLE = Automatic; 299 | DEFINES_MODULE = YES; 300 | DEVELOPMENT_TEAM = ""; 301 | DYLIB_COMPATIBILITY_VERSION = 1; 302 | DYLIB_CURRENT_VERSION = 1; 303 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 304 | INFOPLIST_FILE = AMChart/Info.plist; 305 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 306 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 307 | PRODUCT_BUNDLE_IDENTIFIER = am10.AMChart; 308 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; 309 | SKIP_INSTALL = YES; 310 | SWIFT_VERSION = 5.0; 311 | TARGETED_DEVICE_FAMILY = "1,2"; 312 | }; 313 | name = Debug; 314 | }; 315 | 0E4753AB201F7412002EA382 /* Release */ = { 316 | isa = XCBuildConfiguration; 317 | buildSettings = { 318 | CODE_SIGN_IDENTITY = ""; 319 | CODE_SIGN_STYLE = Automatic; 320 | DEFINES_MODULE = YES; 321 | DEVELOPMENT_TEAM = ""; 322 | DYLIB_COMPATIBILITY_VERSION = 1; 323 | DYLIB_CURRENT_VERSION = 1; 324 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 325 | INFOPLIST_FILE = AMChart/Info.plist; 326 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 327 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 328 | PRODUCT_BUNDLE_IDENTIFIER = am10.AMChart; 329 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; 330 | SKIP_INSTALL = YES; 331 | SWIFT_VERSION = 5.0; 332 | TARGETED_DEVICE_FAMILY = "1,2"; 333 | }; 334 | name = Release; 335 | }; 336 | /* End XCBuildConfiguration section */ 337 | 338 | /* Begin XCConfigurationList section */ 339 | 0E47539B201F7412002EA382 /* Build configuration list for PBXProject "AMChart" */ = { 340 | isa = XCConfigurationList; 341 | buildConfigurations = ( 342 | 0E4753A7201F7412002EA382 /* Debug */, 343 | 0E4753A8201F7412002EA382 /* Release */, 344 | ); 345 | defaultConfigurationIsVisible = 0; 346 | defaultConfigurationName = Release; 347 | }; 348 | 0E4753A9201F7412002EA382 /* Build configuration list for PBXNativeTarget "AMChart" */ = { 349 | isa = XCConfigurationList; 350 | buildConfigurations = ( 351 | 0E4753AA201F7412002EA382 /* Debug */, 352 | 0E4753AB201F7412002EA382 /* Release */, 353 | ); 354 | defaultConfigurationIsVisible = 0; 355 | defaultConfigurationName = Release; 356 | }; 357 | /* End XCConfigurationList section */ 358 | }; 359 | rootObject = 0E475398201F7412002EA382 /* Project object */; 360 | } 361 | -------------------------------------------------------------------------------- /AMChart.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /AMChart.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /AMChart.xcodeproj/xcshareddata/xcschemes/AMChart.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 34 | 35 | 45 | 46 | 52 | 53 | 54 | 55 | 56 | 57 | 63 | 64 | 70 | 71 | 72 | 73 | 75 | 76 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /AMChart/AMChart.h: -------------------------------------------------------------------------------- 1 | // 2 | // AMChart.h 3 | // AMChart 4 | // 5 | // Created by am10 on 2018/01/30. 6 | // Copyright © 2018年 am10. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for AMChart. 12 | FOUNDATION_EXPORT double AMChartVersionNumber; 13 | 14 | //! Project version string for AMChart. 15 | FOUNDATION_EXPORT const unsigned char AMChartVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import 18 | 19 | 20 | -------------------------------------------------------------------------------- /AMChart/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | $(CURRENT_PROJECT_VERSION) 21 | NSPrincipalClass 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 adventam10 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:5.1 2 | // The swift-tools-version declares the minimum version of Swift required to build this package. 3 | // 4 | // AMBarChartView.swift 5 | // AMChart, https://github.com/adventam10/AMChart 6 | // 7 | // Created by am10 on 2018/01/02. 8 | // Copyright © 2018年 am10. All rights reserved. 9 | // 10 | 11 | import PackageDescription 12 | 13 | let package = Package(name: "AMChart", 14 | platforms: [.iOS(.v9)], 15 | products: [.library(name: "AMChart", 16 | targets: ["AMChart"])], 17 | targets: [.target(name: "AMChart", 18 | path: "Source")], 19 | swiftLanguageVersions: [.v5]) 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AMChart 2 | 3 | ![Pod Platform](https://img.shields.io/cocoapods/p/AMChart.svg?style=flat) 4 | ![Pod License](https://img.shields.io/cocoapods/l/AMChart.svg?style=flat) 5 | [![Pod Version](https://img.shields.io/cocoapods/v/AMChart.svg?style=flat)](http://cocoapods.org/pods/AMChart) 6 | [![Carthage Compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) 7 | [![Swift Package Manager compatible](https://img.shields.io/badge/Swift%20Package%20Manager-compatible-brightgreen.svg)](https://github.com/apple/swift-package-manager) 8 | 9 | ## Demo 10 | 11 | ![charts](https://user-images.githubusercontent.com/34936885/67146899-d0171500-f2ca-11e9-8266-31e1984e66e4.gif) 12 | 13 | ## Usage 14 | ### AMBarChartView 15 | ![bar](https://user-images.githubusercontent.com/34936885/67146915-f63cb500-f2ca-11e9-9073-5eb8f3314360.png) 16 | 17 | ```swift 18 | let barChartView = AMBarChartView(frame: view.bounds) 19 | 20 | // customize here 21 | 22 | barChartView.dataSource = self 23 | view.addSubview(barChartView) 24 | ``` 25 | 26 | Conform to the protocol in the class implementation. 27 | 28 | ```swift 29 | func numberOfSections(in barChartView: AMBarChartView) -> Int 30 | func barChartView(_ barChartView: AMBarChartView, numberOfRowsInSection section: Int) -> Int 31 | func barChartView(_ barChartView: AMBarChartView, valueForRowAtIndexPath indexPath: IndexPath) -> CGFloat 32 | func barChartView(_ barChartView: AMBarChartView, colorForRowAtIndexPath indexPath: IndexPath) -> UIColor 33 | func barChartView(_ barChartView: AMBarChartView, titleForXlabelInSection section: Int) -> String 34 | ``` 35 | 36 | #### Customization 37 | `AMBarChartView` can be customized via the following properties. 38 | 39 | ```swift 40 | @IBInspectable public var yAxisMaxValue: CGFloat = 1000 41 | @IBInspectable public var numberOfYAxisLabel: Int = 6 42 | @IBInspectable public var axisColor: UIColor = .black 43 | @IBInspectable public var axisWidth: CGFloat = 1.0 44 | @IBInspectable public var barSpace: CGFloat = 8 45 | @IBInspectable public var yAxisTitleFont: UIFont = .systemFont(ofSize: 15) 46 | @IBInspectable public var xAxisTitleFont: UIFont = .systemFont(ofSize: 15) 47 | @IBInspectable public var yLabelsFont: UIFont = .systemFont(ofSize: 15) 48 | @IBInspectable public var xLabelsFont: UIFont = .systemFont(ofSize: 15) 49 | @IBInspectable public var yAxisTitleColor: UIColor = .black 50 | @IBInspectable public var xAxisTitleColor: UIColor = .black 51 | @IBInspectable public var yLabelsTextColor: UIColor = .black 52 | @IBInspectable public var xLabelsTextColor: UIColor = .black 53 | @IBInspectable public var isHorizontalLine: Bool = false 54 | @IBInspectable public var yAxisTitle: String = "" 55 | @IBInspectable public var xAxisTitle: String = "" 56 | public var yAxisDecimalFormat: AMDecimalFormat = .none 57 | public var animationDuration: CFTimeInterval = 0.6 58 | ``` 59 | 60 | ### AMLineChartView 61 | ![line](https://user-images.githubusercontent.com/34936885/67146924-14a2b080-f2cb-11e9-9720-4290ac1b9832.png) 62 | 63 | ```swift 64 | let lineChartView = AMLineChartView(frame: view.bounds) 65 | 66 | // customize here 67 | 68 | lineChartView.dataSource = self 69 | view.addSubview(lineChartView) 70 | ``` 71 | 72 | Conform to the protocol in the class implementation. 73 | 74 | ```swift 75 | func numberOfSections(in lineChartView: AMLineChartView) -> Int 76 | func numberOfRows(in lineChartView: AMLineChartView) -> Int 77 | func lineChartView(_ lineChartView: AMLineChartView, valueForRowAtIndexPath indexPath: IndexPath) -> CGFloat 78 | func lineChartView(_ lineChartView: AMLineChartView, colorForSection section: Int) -> UIColor 79 | func lineChartView(_ lineChartView: AMLineChartView, titleForXlabelInRow row: Int) -> String 80 | func lineChartView(_ lineChartView: AMLineChartView, pointTypeForSection section: Int) -> AMPointType 81 | ``` 82 | 83 | #### Customization 84 | `AMLineChartView` can be customized via the following properties. 85 | 86 | ```swift 87 | @IBInspectable public var yAxisMaxValue: CGFloat = 1000 88 | @IBInspectable public var yAxisMinValue: CGFloat = 0 89 | @IBInspectable public var numberOfYAxisLabel: Int = 6 90 | @IBInspectable public var axisColor: UIColor = .black 91 | @IBInspectable public var axisWidth: CGFloat = 1.0 92 | @IBInspectable public var yAxisTitleFont: UIFont = .systemFont(ofSize: 15) 93 | @IBInspectable public var xAxisTitleFont: UIFont = .systemFont(ofSize: 15) 94 | @IBInspectable public var yLabelsFont: UIFont = .systemFont(ofSize: 15) 95 | @IBInspectable public var xLabelsFont: UIFont = .systemFont(ofSize: 15) 96 | @IBInspectable public var yAxisTitleColor: UIColor = .black 97 | @IBInspectable public var xAxisTitleColor: UIColor = .black 98 | @IBInspectable public var yLabelsTextColor: UIColor = .black 99 | @IBInspectable public var xLabelsTextColor: UIColor = .black 100 | @IBInspectable public var isHorizontalLine: Bool = false 101 | @IBInspectable public var yAxisTitle: String = "" 102 | @IBInspectable public var xAxisTitle: String = "" 103 | public var yAxisDecimalFormat: AMDecimalFormat = .none 104 | public var animationDuration: CFTimeInterval = 0.6 105 | ``` 106 | 107 | ### AMPieChartView 108 | ![pie](https://user-images.githubusercontent.com/34936885/67146931-23896300-f2cb-11e9-8dbf-84743a54f314.png) 109 | 110 | ```swift 111 | let pieChartView = AMPieChartView(frame: view.bounds) 112 | 113 | // customize here 114 | 115 | pieChartView.delegate = self 116 | pieChartView.dataSource = self 117 | view.addSubview(pieChartView) 118 | ``` 119 | 120 | Conform to the protocol in the class implementation. 121 | 122 | ```swift 123 | /// DataSource 124 | func numberOfSections(in pieChartView: AMPieChartView) -> Int 125 | func pieChartView(_ pieChartView: AMPieChartView, valueForSection section: Int) -> CGFloat 126 | func pieChartView(_ pieChartView: AMPieChartView, colorForSection section: Int) -> UIColor 127 | 128 | /// Delegate 129 | func pieChartView(_ pieChartView: AMPieChartView, didSelectSection section: Int) { 130 | // use selected section here 131 | } 132 | 133 | func pieChartView(_ pieChartView: AMPieChartView, didDeSelectSection section: Int) { 134 | // use deselected section here 135 | } 136 | ``` 137 | 138 | #### Customization 139 | `AMPieChartView` can be customized via the following properties. 140 | 141 | ```swift 142 | @IBInspectable public var isDounut: Bool = false 143 | @IBInspectable public var centerLabelFont: UIFont = .systemFont(ofSize: 15) 144 | @IBInspectable public var centerLabelTextColor: UIColor = .black 145 | @IBInspectable public var centerLabelText: String = "" 146 | public var animationDuration: CFTimeInterval = 0.4 147 | public var selectedAnimationDuration: CFTimeInterval = 0.3 148 | public var centerLabelAttributedText: NSAttributedString? = nil 149 | ``` 150 | 151 | ### AMRadarChartView 152 | ![radar](https://user-images.githubusercontent.com/34936885/67146968-78c57480-f2cb-11e9-896f-4de1b13f0b82.png) 153 | 154 | ```swift 155 | let radarChartView = AMRadarChartView(frame: view.bounds) 156 | 157 | // customize here 158 | 159 | radarChartView.dataSource = self 160 | view.addSubview(radarChartView) 161 | ``` 162 | 163 | Conform to the protocol in the class implementation. 164 | 165 | ```swift 166 | /// Required 167 | func numberOfSections(in radarChartView: AMRadarChartView) -> Int 168 | func numberOfRows(in radarChartView: AMRadarChartView) -> Int 169 | func radarChartView(_ radarChartView: AMRadarChartView, valueForRowAtIndexPath indexPath: IndexPath) -> CGFloat 170 | func radarChartView(_ radarChartView: AMRadarChartView, fillColorForSection section: Int) -> UIColor 171 | func radarChartView(_ radarChartView: AMRadarChartView, strokeColorForSection section: Int) -> UIColor 172 | 173 | /// Optional 174 | func radarChartView(_ radarChartView: AMRadarChartView, titleForVertexInRow row: Int) -> String 175 | func radarChartView(_ radarChartView: AMRadarChartView, fontForVertexInRow row: Int) -> UIFont // default is System 15.0 176 | func radarChartView(_ radarChartView: AMRadarChartView, textColorForVertexInRow row: Int) -> UIColor // default is black 177 | ``` 178 | 179 | #### Customization 180 | `AMRadarChartView` can be customized via the following properties. 181 | 182 | ```swift 183 | @IBInspectable public var axisMaxValue: CGFloat = 5.0 184 | @IBInspectable public var axisMinValue: CGFloat = 0.0 185 | @IBInspectable public var numberOfAxisLabels: Int = 6 186 | @IBInspectable public var axisColor: UIColor = .black 187 | @IBInspectable public var axisWidth: CGFloat = 1.0 188 | @IBInspectable public var axisLabelsFont: UIFont = .systemFont(ofSize: 15) 189 | @IBInspectable public var axisLabelsTextColor: UIColor = .black 190 | @IBInspectable public var isDottedLine: Bool = false 191 | public var axisDecimalFormat: AMDecimalFormat = .none 192 | public var animationDuration: CFTimeInterval = 0.6 193 | ``` 194 | 195 | ### AMScatterChartView 196 | ![scatter](https://user-images.githubusercontent.com/34936885/67146918-fccb2c80-f2ca-11e9-8348-ee00d5febf12.png) 197 | 198 | ```swift 199 | let scatterChartView = AMScatterChartView(frame: view.bounds) 200 | 201 | // customize here 202 | 203 | scatterChartView.dataSource = self 204 | view.addSubview(scatterChartView) 205 | ``` 206 | 207 | Conform to the protocol in the class implementation. 208 | 209 | ```swift 210 | func numberOfSections(in scatterChartView: AMScatterChartView) -> Int 211 | func scatterChartView(_ scatterChartView: AMScatterChartView, numberOfRowsInSection section: Int) -> Int 212 | func scatterChartView(_ scatterChartView: AMScatterChartView, valueForRowAtIndexPath indexPath: IndexPath) -> AMScatterValue 213 | func scatterChartView(_ scatterChartView: AMScatterChartView, colorForSection section: Int) -> UIColor 214 | func scatterChartView(_ scatterChartView: AMScatterChartView, pointTypeForSection section: Int) -> AMPointType 215 | ``` 216 | 217 | #### Customization 218 | `AMScatterChartView` can be customized via the following properties. 219 | 220 | ```swift 221 | @IBInspectable public var yAxisMaxValue: CGFloat = 1000 222 | @IBInspectable public var yAxisMinValue: CGFloat = 0 223 | @IBInspectable public var numberOfYAxisLabel: Int = 6 224 | @IBInspectable public var xAxisMaxValue: CGFloat = 1000 225 | @IBInspectable public var xAxisMinValue: CGFloat = 0 226 | @IBInspectable public var numberOfXAxisLabel: Int = 6 227 | @IBInspectable public var axisColor: UIColor = .black 228 | @IBInspectable public var axisWidth: CGFloat = 1.0 229 | @IBInspectable public var yAxisTitleFont: UIFont = .systemFont(ofSize: 15) 230 | @IBInspectable public var xAxisTitleFont: UIFont = .systemFont(ofSize: 15) 231 | @IBInspectable public var yLabelsFont: UIFont = .systemFont(ofSize: 15) 232 | @IBInspectable public var xLabelsFont: UIFont = .systemFont(ofSize: 15) 233 | @IBInspectable public var yAxisTitleColor: UIColor = .black 234 | @IBInspectable public var xAxisTitleColor: UIColor = .black 235 | @IBInspectable public var yLabelsTextColor: UIColor = .black 236 | @IBInspectable public var xLabelsTextColor: UIColor = .black 237 | @IBInspectable public var isHorizontalLine: Bool = false 238 | @IBInspectable public var yAxisTitle: String = "" 239 | @IBInspectable public var xAxisTitle: String = "" 240 | public var yAxisDecimalFormat: AMDecimalFormat = .none 241 | public var xAxisDecimalFormat: AMDecimalFormat = .none 242 | public var animationDuration: CFTimeInterval = 0.6 243 | ``` 244 | 245 | ## Installation 246 | 247 | ### CocoaPods 248 | 249 | Add this to your Podfile. 250 | 251 | ```ogdl 252 | pod 'AMChart' 253 | ``` 254 | 255 | ### Carthage 256 | 257 | Add this to your Cartfile. 258 | 259 | ```ogdl 260 | github "adventam10/AMChart" 261 | ``` 262 | 263 | ## License 264 | 265 | MIT 266 | 267 | -------------------------------------------------------------------------------- /SampleAMChart/SampleAMChart.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 48; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 0E407B05235483D20096FA4A /* AMLineChartView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E407B00235483D20096FA4A /* AMLineChartView.swift */; }; 11 | 0E407B06235483D20096FA4A /* AMPieChartView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E407B01235483D20096FA4A /* AMPieChartView.swift */; }; 12 | 0E407B07235483D20096FA4A /* AMScatterChartView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E407B02235483D20096FA4A /* AMScatterChartView.swift */; }; 13 | 0E407B08235483D20096FA4A /* AMBarChartView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E407B03235483D20096FA4A /* AMBarChartView.swift */; }; 14 | 0E407B09235483D20096FA4A /* AMRadarChartView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E407B04235483D20096FA4A /* AMRadarChartView.swift */; }; 15 | 0E47538A201F73EC002EA382 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E475388201F73EC002EA382 /* AppDelegate.swift */; }; 16 | 0E47538B201F73EC002EA382 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E475389201F73EC002EA382 /* ViewController.swift */; }; 17 | 0E9A094020038FA800DD65DB /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0E9A093E20038FA800DD65DB /* Main.storyboard */; }; 18 | 0E9A094220038FA800DD65DB /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0E9A094120038FA800DD65DB /* Assets.xcassets */; }; 19 | 0E9A094520038FA800DD65DB /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0E9A094320038FA800DD65DB /* LaunchScreen.storyboard */; }; 20 | 0E9F7CC0235767A200F3ED4C /* AMChartData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E9F7CBF235767A200F3ED4C /* AMChartData.swift */; }; 21 | 0E9F7CC223576A5A00F3ED4C /* AMChartView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E9F7CC123576A5A00F3ED4C /* AMChartView.swift */; }; 22 | /* End PBXBuildFile section */ 23 | 24 | /* Begin PBXFileReference section */ 25 | 0E407B00235483D20096FA4A /* AMLineChartView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AMLineChartView.swift; sourceTree = ""; }; 26 | 0E407B01235483D20096FA4A /* AMPieChartView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AMPieChartView.swift; sourceTree = ""; }; 27 | 0E407B02235483D20096FA4A /* AMScatterChartView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AMScatterChartView.swift; sourceTree = ""; }; 28 | 0E407B03235483D20096FA4A /* AMBarChartView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AMBarChartView.swift; sourceTree = ""; }; 29 | 0E407B04235483D20096FA4A /* AMRadarChartView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AMRadarChartView.swift; sourceTree = ""; }; 30 | 0E475388201F73EC002EA382 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 31 | 0E475389201F73EC002EA382 /* ViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 32 | 0E9A093720038FA800DD65DB /* SampleAMChart.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SampleAMChart.app; sourceTree = BUILT_PRODUCTS_DIR; }; 33 | 0E9A093F20038FA800DD65DB /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 34 | 0E9A094120038FA800DD65DB /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 35 | 0E9A094420038FA800DD65DB /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 36 | 0E9A094620038FA900DD65DB /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 37 | 0E9F7CBF235767A200F3ED4C /* AMChartData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AMChartData.swift; sourceTree = ""; }; 38 | 0E9F7CC123576A5A00F3ED4C /* AMChartView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AMChartView.swift; sourceTree = ""; }; 39 | /* End PBXFileReference section */ 40 | 41 | /* Begin PBXFrameworksBuildPhase section */ 42 | 0E9A093420038FA800DD65DB /* Frameworks */ = { 43 | isa = PBXFrameworksBuildPhase; 44 | buildActionMask = 2147483647; 45 | files = ( 46 | ); 47 | runOnlyForDeploymentPostprocessing = 0; 48 | }; 49 | /* End PBXFrameworksBuildPhase section */ 50 | 51 | /* Begin PBXGroup section */ 52 | 0E407AFF235483D20096FA4A /* Source */ = { 53 | isa = PBXGroup; 54 | children = ( 55 | 0E9F7CBF235767A200F3ED4C /* AMChartData.swift */, 56 | 0E9F7CC123576A5A00F3ED4C /* AMChartView.swift */, 57 | 0E407B00235483D20096FA4A /* AMLineChartView.swift */, 58 | 0E407B01235483D20096FA4A /* AMPieChartView.swift */, 59 | 0E407B02235483D20096FA4A /* AMScatterChartView.swift */, 60 | 0E407B03235483D20096FA4A /* AMBarChartView.swift */, 61 | 0E407B04235483D20096FA4A /* AMRadarChartView.swift */, 62 | ); 63 | name = Source; 64 | path = ../../../Source; 65 | sourceTree = ""; 66 | }; 67 | 0E475387201F73EC002EA382 /* Classes */ = { 68 | isa = PBXGroup; 69 | children = ( 70 | 0E407AFF235483D20096FA4A /* Source */, 71 | 0E475388201F73EC002EA382 /* AppDelegate.swift */, 72 | 0E475389201F73EC002EA382 /* ViewController.swift */, 73 | ); 74 | path = Classes; 75 | sourceTree = ""; 76 | }; 77 | 0E9A092E20038FA800DD65DB = { 78 | isa = PBXGroup; 79 | children = ( 80 | 0E9A093920038FA800DD65DB /* SampleAMChart */, 81 | 0E9A093820038FA800DD65DB /* Products */, 82 | ); 83 | sourceTree = ""; 84 | }; 85 | 0E9A093820038FA800DD65DB /* Products */ = { 86 | isa = PBXGroup; 87 | children = ( 88 | 0E9A093720038FA800DD65DB /* SampleAMChart.app */, 89 | ); 90 | name = Products; 91 | sourceTree = ""; 92 | }; 93 | 0E9A093920038FA800DD65DB /* SampleAMChart */ = { 94 | isa = PBXGroup; 95 | children = ( 96 | 0E475387201F73EC002EA382 /* Classes */, 97 | 0E9A093E20038FA800DD65DB /* Main.storyboard */, 98 | 0E9A094120038FA800DD65DB /* Assets.xcassets */, 99 | 0E9A094320038FA800DD65DB /* LaunchScreen.storyboard */, 100 | 0E9A094620038FA900DD65DB /* Info.plist */, 101 | ); 102 | path = SampleAMChart; 103 | sourceTree = ""; 104 | }; 105 | /* End PBXGroup section */ 106 | 107 | /* Begin PBXNativeTarget section */ 108 | 0E9A093620038FA800DD65DB /* SampleAMChart */ = { 109 | isa = PBXNativeTarget; 110 | buildConfigurationList = 0E9A094920038FA900DD65DB /* Build configuration list for PBXNativeTarget "SampleAMChart" */; 111 | buildPhases = ( 112 | 0E9A093320038FA800DD65DB /* Sources */, 113 | 0E9A093420038FA800DD65DB /* Frameworks */, 114 | 0E9A093520038FA800DD65DB /* Resources */, 115 | ); 116 | buildRules = ( 117 | ); 118 | dependencies = ( 119 | ); 120 | name = SampleAMChart; 121 | productName = SampleAMChart; 122 | productReference = 0E9A093720038FA800DD65DB /* SampleAMChart.app */; 123 | productType = "com.apple.product-type.application"; 124 | }; 125 | /* End PBXNativeTarget section */ 126 | 127 | /* Begin PBXProject section */ 128 | 0E9A092F20038FA800DD65DB /* Project object */ = { 129 | isa = PBXProject; 130 | attributes = { 131 | LastSwiftUpdateCheck = 0920; 132 | LastUpgradeCheck = 1020; 133 | ORGANIZATIONNAME = am10; 134 | TargetAttributes = { 135 | 0E9A093620038FA800DD65DB = { 136 | CreatedOnToolsVersion = 9.2; 137 | LastSwiftMigration = 1020; 138 | ProvisioningStyle = Automatic; 139 | }; 140 | }; 141 | }; 142 | buildConfigurationList = 0E9A093220038FA800DD65DB /* Build configuration list for PBXProject "SampleAMChart" */; 143 | compatibilityVersion = "Xcode 8.0"; 144 | developmentRegion = en; 145 | hasScannedForEncodings = 0; 146 | knownRegions = ( 147 | en, 148 | Base, 149 | ); 150 | mainGroup = 0E9A092E20038FA800DD65DB; 151 | productRefGroup = 0E9A093820038FA800DD65DB /* Products */; 152 | projectDirPath = ""; 153 | projectRoot = ""; 154 | targets = ( 155 | 0E9A093620038FA800DD65DB /* SampleAMChart */, 156 | ); 157 | }; 158 | /* End PBXProject section */ 159 | 160 | /* Begin PBXResourcesBuildPhase section */ 161 | 0E9A093520038FA800DD65DB /* Resources */ = { 162 | isa = PBXResourcesBuildPhase; 163 | buildActionMask = 2147483647; 164 | files = ( 165 | 0E9A094520038FA800DD65DB /* LaunchScreen.storyboard in Resources */, 166 | 0E9A094220038FA800DD65DB /* Assets.xcassets in Resources */, 167 | 0E9A094020038FA800DD65DB /* Main.storyboard in Resources */, 168 | ); 169 | runOnlyForDeploymentPostprocessing = 0; 170 | }; 171 | /* End PBXResourcesBuildPhase section */ 172 | 173 | /* Begin PBXSourcesBuildPhase section */ 174 | 0E9A093320038FA800DD65DB /* Sources */ = { 175 | isa = PBXSourcesBuildPhase; 176 | buildActionMask = 2147483647; 177 | files = ( 178 | 0E407B06235483D20096FA4A /* AMPieChartView.swift in Sources */, 179 | 0E407B08235483D20096FA4A /* AMBarChartView.swift in Sources */, 180 | 0E407B07235483D20096FA4A /* AMScatterChartView.swift in Sources */, 181 | 0E47538B201F73EC002EA382 /* ViewController.swift in Sources */, 182 | 0E407B05235483D20096FA4A /* AMLineChartView.swift in Sources */, 183 | 0E47538A201F73EC002EA382 /* AppDelegate.swift in Sources */, 184 | 0E9F7CC0235767A200F3ED4C /* AMChartData.swift in Sources */, 185 | 0E9F7CC223576A5A00F3ED4C /* AMChartView.swift in Sources */, 186 | 0E407B09235483D20096FA4A /* AMRadarChartView.swift in Sources */, 187 | ); 188 | runOnlyForDeploymentPostprocessing = 0; 189 | }; 190 | /* End PBXSourcesBuildPhase section */ 191 | 192 | /* Begin PBXVariantGroup section */ 193 | 0E9A093E20038FA800DD65DB /* Main.storyboard */ = { 194 | isa = PBXVariantGroup; 195 | children = ( 196 | 0E9A093F20038FA800DD65DB /* Base */, 197 | ); 198 | name = Main.storyboard; 199 | sourceTree = ""; 200 | }; 201 | 0E9A094320038FA800DD65DB /* LaunchScreen.storyboard */ = { 202 | isa = PBXVariantGroup; 203 | children = ( 204 | 0E9A094420038FA800DD65DB /* Base */, 205 | ); 206 | name = LaunchScreen.storyboard; 207 | sourceTree = ""; 208 | }; 209 | /* End PBXVariantGroup section */ 210 | 211 | /* Begin XCBuildConfiguration section */ 212 | 0E9A094720038FA900DD65DB /* Debug */ = { 213 | isa = XCBuildConfiguration; 214 | buildSettings = { 215 | ALWAYS_SEARCH_USER_PATHS = NO; 216 | CLANG_ANALYZER_NONNULL = YES; 217 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 218 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 219 | CLANG_CXX_LIBRARY = "libc++"; 220 | CLANG_ENABLE_MODULES = YES; 221 | CLANG_ENABLE_OBJC_ARC = YES; 222 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 223 | CLANG_WARN_BOOL_CONVERSION = YES; 224 | CLANG_WARN_COMMA = YES; 225 | CLANG_WARN_CONSTANT_CONVERSION = YES; 226 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 227 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 228 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 229 | CLANG_WARN_EMPTY_BODY = YES; 230 | CLANG_WARN_ENUM_CONVERSION = YES; 231 | CLANG_WARN_INFINITE_RECURSION = YES; 232 | CLANG_WARN_INT_CONVERSION = YES; 233 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 234 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 235 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 236 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 237 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 238 | CLANG_WARN_STRICT_PROTOTYPES = YES; 239 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 240 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 241 | CLANG_WARN_UNREACHABLE_CODE = YES; 242 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 243 | CODE_SIGN_IDENTITY = "iPhone Developer"; 244 | COPY_PHASE_STRIP = NO; 245 | DEBUG_INFORMATION_FORMAT = dwarf; 246 | ENABLE_STRICT_OBJC_MSGSEND = YES; 247 | ENABLE_TESTABILITY = YES; 248 | GCC_C_LANGUAGE_STANDARD = gnu11; 249 | GCC_DYNAMIC_NO_PIC = NO; 250 | GCC_NO_COMMON_BLOCKS = YES; 251 | GCC_OPTIMIZATION_LEVEL = 0; 252 | GCC_PREPROCESSOR_DEFINITIONS = ( 253 | "DEBUG=1", 254 | "$(inherited)", 255 | ); 256 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 257 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 258 | GCC_WARN_UNDECLARED_SELECTOR = YES; 259 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 260 | GCC_WARN_UNUSED_FUNCTION = YES; 261 | GCC_WARN_UNUSED_VARIABLE = YES; 262 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 263 | MTL_ENABLE_DEBUG_INFO = YES; 264 | ONLY_ACTIVE_ARCH = YES; 265 | SDKROOT = iphoneos; 266 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 267 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 268 | }; 269 | name = Debug; 270 | }; 271 | 0E9A094820038FA900DD65DB /* Release */ = { 272 | isa = XCBuildConfiguration; 273 | buildSettings = { 274 | ALWAYS_SEARCH_USER_PATHS = NO; 275 | CLANG_ANALYZER_NONNULL = YES; 276 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 277 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 278 | CLANG_CXX_LIBRARY = "libc++"; 279 | CLANG_ENABLE_MODULES = YES; 280 | CLANG_ENABLE_OBJC_ARC = YES; 281 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 282 | CLANG_WARN_BOOL_CONVERSION = YES; 283 | CLANG_WARN_COMMA = YES; 284 | CLANG_WARN_CONSTANT_CONVERSION = YES; 285 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 286 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 287 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 288 | CLANG_WARN_EMPTY_BODY = YES; 289 | CLANG_WARN_ENUM_CONVERSION = YES; 290 | CLANG_WARN_INFINITE_RECURSION = YES; 291 | CLANG_WARN_INT_CONVERSION = YES; 292 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 293 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 294 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 295 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 296 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 297 | CLANG_WARN_STRICT_PROTOTYPES = YES; 298 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 299 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 300 | CLANG_WARN_UNREACHABLE_CODE = YES; 301 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 302 | CODE_SIGN_IDENTITY = "iPhone Developer"; 303 | COPY_PHASE_STRIP = NO; 304 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 305 | ENABLE_NS_ASSERTIONS = NO; 306 | ENABLE_STRICT_OBJC_MSGSEND = YES; 307 | GCC_C_LANGUAGE_STANDARD = gnu11; 308 | GCC_NO_COMMON_BLOCKS = YES; 309 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 310 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 311 | GCC_WARN_UNDECLARED_SELECTOR = YES; 312 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 313 | GCC_WARN_UNUSED_FUNCTION = YES; 314 | GCC_WARN_UNUSED_VARIABLE = YES; 315 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 316 | MTL_ENABLE_DEBUG_INFO = NO; 317 | SDKROOT = iphoneos; 318 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 319 | VALIDATE_PRODUCT = YES; 320 | }; 321 | name = Release; 322 | }; 323 | 0E9A094A20038FA900DD65DB /* Debug */ = { 324 | isa = XCBuildConfiguration; 325 | buildSettings = { 326 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 327 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 328 | CODE_SIGN_STYLE = Automatic; 329 | DEVELOPMENT_TEAM = ""; 330 | INFOPLIST_FILE = SampleAMChart/Info.plist; 331 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 332 | PRODUCT_BUNDLE_IDENTIFIER = am10.SampleAMChart; 333 | PRODUCT_NAME = "$(TARGET_NAME)"; 334 | PROVISIONING_PROFILE_SPECIFIER = ""; 335 | SWIFT_VERSION = 5.0; 336 | TARGETED_DEVICE_FAMILY = "1,2"; 337 | }; 338 | name = Debug; 339 | }; 340 | 0E9A094B20038FA900DD65DB /* Release */ = { 341 | isa = XCBuildConfiguration; 342 | buildSettings = { 343 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 344 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 345 | CODE_SIGN_STYLE = Automatic; 346 | DEVELOPMENT_TEAM = ""; 347 | INFOPLIST_FILE = SampleAMChart/Info.plist; 348 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 349 | PRODUCT_BUNDLE_IDENTIFIER = am10.SampleAMChart; 350 | PRODUCT_NAME = "$(TARGET_NAME)"; 351 | PROVISIONING_PROFILE_SPECIFIER = ""; 352 | SWIFT_VERSION = 5.0; 353 | TARGETED_DEVICE_FAMILY = "1,2"; 354 | }; 355 | name = Release; 356 | }; 357 | /* End XCBuildConfiguration section */ 358 | 359 | /* Begin XCConfigurationList section */ 360 | 0E9A093220038FA800DD65DB /* Build configuration list for PBXProject "SampleAMChart" */ = { 361 | isa = XCConfigurationList; 362 | buildConfigurations = ( 363 | 0E9A094720038FA900DD65DB /* Debug */, 364 | 0E9A094820038FA900DD65DB /* Release */, 365 | ); 366 | defaultConfigurationIsVisible = 0; 367 | defaultConfigurationName = Release; 368 | }; 369 | 0E9A094920038FA900DD65DB /* Build configuration list for PBXNativeTarget "SampleAMChart" */ = { 370 | isa = XCConfigurationList; 371 | buildConfigurations = ( 372 | 0E9A094A20038FA900DD65DB /* Debug */, 373 | 0E9A094B20038FA900DD65DB /* Release */, 374 | ); 375 | defaultConfigurationIsVisible = 0; 376 | defaultConfigurationName = Release; 377 | }; 378 | /* End XCConfigurationList section */ 379 | }; 380 | rootObject = 0E9A092F20038FA800DD65DB /* Project object */; 381 | } 382 | -------------------------------------------------------------------------------- /SampleAMChart/SampleAMChart.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /SampleAMChart/SampleAMChart.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /SampleAMChart/SampleAMChart/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 | "info" : { 90 | "version" : 1, 91 | "author" : "xcode" 92 | } 93 | } -------------------------------------------------------------------------------- /SampleAMChart/SampleAMChart/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 | -------------------------------------------------------------------------------- /SampleAMChart/SampleAMChart/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 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 48 | 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 | -------------------------------------------------------------------------------- /SampleAMChart/SampleAMChart/Classes/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // SampleAMChart 4 | // 5 | // Created by am10 on 2018/01/08. 6 | // Copyright © 2018年 am10. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | var window: UIWindow? 15 | 16 | 17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 18 | // Override point for customization after application launch. 19 | return true 20 | } 21 | 22 | func applicationWillResignActive(_ application: UIApplication) { 23 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 24 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 25 | } 26 | 27 | func applicationDidEnterBackground(_ application: UIApplication) { 28 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 29 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 30 | } 31 | 32 | func applicationWillEnterForeground(_ application: UIApplication) { 33 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 34 | } 35 | 36 | func applicationDidBecomeActive(_ application: UIApplication) { 37 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 38 | } 39 | 40 | func applicationWillTerminate(_ application: UIApplication) { 41 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 42 | } 43 | 44 | 45 | } 46 | 47 | -------------------------------------------------------------------------------- /SampleAMChart/SampleAMChart/Classes/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // SampleAMChart 4 | // 5 | // Created by am10 on 2018/01/08. 6 | // Copyright © 2018年 am10. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class ViewController: UIViewController { 12 | 13 | @IBOutlet private weak var radarChartView: AMRadarChartView! 14 | @IBOutlet private weak var barChartView: AMBarChartView! 15 | @IBOutlet private weak var pieChartView: AMPieChartView! 16 | @IBOutlet private weak var scatterChartView: AMScatterChartView! 17 | @IBOutlet private weak var lineChartView: AMLineChartView! 18 | 19 | private var radarDataList = [[CGFloat]]() 20 | private var barDataList = [[CGFloat]]() 21 | private var pieDataList = [CGFloat]() 22 | private var scatterDataList = [[AMScatterValue]]() 23 | private var lineDataList = [[CGFloat]]() 24 | private var radarRowNum = 0 25 | private let radarAxisNum = 6 26 | private var barColors = [UIColor]() 27 | private var lineRowNum = 0 28 | private let titles = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"] 29 | 30 | override func viewDidLoad() { 31 | super.viewDidLoad() 32 | // Do any additional setup after loading the view, typically from a nib. 33 | 34 | radarChartView.dataSource = self 35 | barChartView.dataSource = self 36 | pieChartView.dataSource = self 37 | scatterChartView.dataSource = self 38 | lineChartView.dataSource = self 39 | scatterChartView.xAxisMinValue = 0 40 | scatterChartView.xAxisMaxValue = 100 41 | scatterChartView.yAxisMinValue = 0 42 | scatterChartView.yAxisMaxValue = 1000 43 | lineChartView.yAxisMinValue = 0 44 | lineChartView.yAxisMaxValue = 1000 45 | barChartView.yAxisMaxValue = 1000 46 | prepareDataList() 47 | } 48 | 49 | @IBAction private func tappedReloadButton(_ sender: Any) { 50 | prepareDataList() 51 | radarChartView.reloadData() 52 | lineChartView.reloadData() 53 | pieChartView.reloadData() 54 | barChartView.reloadData() 55 | scatterChartView.reloadData() 56 | } 57 | 58 | @IBAction private func tappedRedrawButton(_ sender: Any) { 59 | radarChartView.redrawChart() 60 | lineChartView.redrawChart() 61 | pieChartView.redrawChart() 62 | barChartView.reloadData() 63 | scatterChartView.reloadData() 64 | } 65 | 66 | private func randomColor(alpha: CGFloat) -> UIColor { 67 | let r = CGFloat.random(in: 0...255) / 255.0 68 | let g = CGFloat.random(in: 0...255) / 255.0 69 | let b = CGFloat.random(in: 0...255) / 255.0 70 | return UIColor(red: r, green: g, blue: b, alpha: alpha) 71 | } 72 | 73 | private func randomPointType() -> AMPointType { 74 | let pointTypes: [AMPointType] = [.type1, .type2, .type3, .type4, .type5, .type6, .type7, .type8, .type9] 75 | return pointTypes[Int.random(in: 0...8)] 76 | } 77 | 78 | private func prepareDataList() { 79 | radarRowNum = Int.random(in: 3...titles.count) 80 | let radarSectionNum = Int.random(in: 1...10) 81 | radarDataList.removeAll() 82 | for _ in 0.. Int { 137 | return radarDataList.count 138 | } 139 | 140 | func numberOfRows(in radarChartView: AMRadarChartView) -> Int { 141 | return radarRowNum 142 | } 143 | 144 | func radarChartView(_ radarChartView: AMRadarChartView, valueForRowAtIndexPath indexPath: IndexPath) -> CGFloat { 145 | return radarDataList[indexPath.section][indexPath.row] 146 | } 147 | 148 | func radarChartView(_ radarChartView: AMRadarChartView, fillColorForSection section: Int) -> UIColor { 149 | return randomColor(alpha: 0.5) 150 | } 151 | 152 | func radarChartView(_ radarChartView: AMRadarChartView, strokeColorForSection section: Int) -> UIColor { 153 | return randomColor(alpha: 0.5) 154 | } 155 | 156 | func radarChartView(_ radarChartView: AMRadarChartView, titleForVertexInRow row: Int) -> String { 157 | return titles[row] 158 | } 159 | } 160 | 161 | extension ViewController: AMScatterChartViewDataSource { 162 | func numberOfSections(in scatterChartView: AMScatterChartView) -> Int { 163 | return scatterDataList.count 164 | } 165 | 166 | func scatterChartView(_ scatterChartView: AMScatterChartView, numberOfRowsInSection section: Int) -> Int { 167 | return scatterDataList[section].count 168 | } 169 | 170 | func scatterChartView(_ scatterChartView: AMScatterChartView, valueForRowAtIndexPath indexPath: IndexPath) -> AMScatterValue { 171 | return scatterDataList[indexPath.section][indexPath.row] 172 | } 173 | 174 | func scatterChartView(_ scatterChartView: AMScatterChartView, colorForSection section: Int) -> UIColor { 175 | return randomColor(alpha: 1.0) 176 | } 177 | 178 | func scatterChartView(_ scatterChartView: AMScatterChartView, pointTypeForSection section: Int) -> AMPointType { 179 | return randomPointType() 180 | } 181 | } 182 | 183 | extension ViewController: AMPieChartViewDataSource { 184 | func numberOfSections(in pieChartView: AMPieChartView) -> Int { 185 | return pieDataList.count 186 | } 187 | 188 | func pieChartView(_ pieChartView: AMPieChartView, valueForSection section: Int) -> CGFloat { 189 | return pieDataList[section] 190 | } 191 | 192 | func pieChartView(_ pieChartView: AMPieChartView, colorForSection section: Int) -> UIColor { 193 | return randomColor(alpha: 1.0) 194 | } 195 | } 196 | 197 | extension ViewController: AMLineChartViewDataSource { 198 | func numberOfSections(in lineChartView: AMLineChartView) -> Int { 199 | return lineDataList.count 200 | } 201 | 202 | func numberOfRows(in lineChartView: AMLineChartView) -> Int { 203 | return lineDataList.first!.count 204 | } 205 | 206 | func lineChartView(_ lineChartView: AMLineChartView, valueForRowAtIndexPath indexPath: IndexPath) -> CGFloat { 207 | return lineDataList[indexPath.section][indexPath.row] 208 | } 209 | 210 | func lineChartView(_ lineChartView: AMLineChartView, colorForSection section: Int) -> UIColor { 211 | return randomColor(alpha: 1.0) 212 | } 213 | 214 | func lineChartView(_ lineChartView: AMLineChartView, titleForXlabelInRow row: Int) -> String { 215 | return titles[row] 216 | } 217 | 218 | func lineChartView(_ lineChartView: AMLineChartView, pointTypeForSection section: Int) -> AMPointType { 219 | return randomPointType() 220 | } 221 | } 222 | 223 | extension ViewController: AMBarChartViewDataSource { 224 | func numberOfSections(in barChartView: AMBarChartView) -> Int { 225 | return barDataList.count 226 | } 227 | 228 | func barChartView(_ barChartView: AMBarChartView, numberOfRowsInSection section: Int) -> Int { 229 | return barDataList[section].count 230 | } 231 | 232 | func barChartView(_ barChartView: AMBarChartView, valueForRowAtIndexPath indexPath: IndexPath) -> CGFloat { 233 | return barDataList[indexPath.section][indexPath.row] 234 | } 235 | 236 | func barChartView(_ barChartView: AMBarChartView, colorForRowAtIndexPath indexPath: IndexPath) -> UIColor { 237 | return barColors[indexPath.row] 238 | } 239 | 240 | func barChartView(_ barChartView: AMBarChartView, titleForXlabelInSection section: Int) -> String { 241 | return titles[section] 242 | } 243 | } 244 | -------------------------------------------------------------------------------- /SampleAMChart/SampleAMChart/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | 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 | -------------------------------------------------------------------------------- /Source/AMBarChartView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AMBarChartView.swift 3 | // AMChart, https://github.com/adventam10/AMChart 4 | // 5 | // Created by am10 on 2018/01/02. 6 | // Copyright © 2018年 am10. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | public protocol AMBarChartViewDataSource: AnyObject { 12 | func numberOfSections(in barChartView: AMBarChartView) -> Int 13 | func barChartView(_ barChartView: AMBarChartView, numberOfRowsInSection section: Int) -> Int 14 | func barChartView(_ barChartView: AMBarChartView, valueForRowAtIndexPath indexPath: IndexPath) -> CGFloat 15 | func barChartView(_ barChartView: AMBarChartView, colorForRowAtIndexPath indexPath: IndexPath) -> UIColor 16 | func barChartView(_ barChartView: AMBarChartView, titleForXlabelInSection section: Int) -> String 17 | } 18 | 19 | public class AMBarChartView: AMChartView { 20 | 21 | @IBInspectable public var yAxisMaxValue: CGFloat = 1000 22 | @IBInspectable public var numberOfYAxisLabel: Int = 6 23 | @IBInspectable public var axisColor: UIColor = .black 24 | @IBInspectable public var axisWidth: CGFloat = 1.0 25 | @IBInspectable public var barSpace: CGFloat = 8 26 | @IBInspectable public var yAxisTitleFont: UIFont = .systemFont(ofSize: 15) 27 | @IBInspectable public var xAxisTitleFont: UIFont = .systemFont(ofSize: 15) 28 | @IBInspectable public var yLabelsFont: UIFont = .systemFont(ofSize: 15) 29 | @IBInspectable public var xLabelsFont: UIFont = .systemFont(ofSize: 15) 30 | @IBInspectable public var yAxisTitleColor: UIColor = .black 31 | @IBInspectable public var xAxisTitleColor: UIColor = .black 32 | @IBInspectable public var yLabelsTextColor: UIColor = .black 33 | @IBInspectable public var xLabelsTextColor: UIColor = .black 34 | @IBInspectable public var isHorizontalLine: Bool = false 35 | @IBInspectable public var yAxisTitle: String = "" 36 | @IBInspectable public var xAxisTitle: String = "" 37 | 38 | weak public var dataSource: AMBarChartViewDataSource? 39 | public var yAxisDecimalFormat: AMDecimalFormat = .none 40 | public var animationDuration: CFTimeInterval = 0.6 41 | 42 | private let yAxisMinValue: CGFloat = 0 43 | private let margin: CGFloat = 8 44 | private let xAxisView = UIView() 45 | private let yAxisView = UIView() 46 | private var xLabels = [UILabel]() 47 | private var yLabels = [UILabel]() 48 | private var barLayers = [CALayer]() 49 | private let xAxisTitleLabel: UILabel = { 50 | let label = UILabel() 51 | label.numberOfLines = 0 52 | return label 53 | }() 54 | private let yAxisTitleLabel: UILabel = { 55 | let label = UILabel() 56 | label.numberOfLines = 0 57 | return label 58 | }() 59 | private var horizontalLineLayers = [CALayer]() 60 | private var graphLineLayers = [CAShapeLayer]() 61 | private var graphLineLayer = CALayer() 62 | private var yAxisPositionX: CGFloat { 63 | let sorted = yLabels.sorted { $0.frame.width > $1.frame.width } 64 | guard let maxWidthLabel = sorted.first else { 65 | return margin 66 | } 67 | return maxWidthLabel.frame.size.width + margin 68 | } 69 | private var xAxisPositionY: CGFloat { 70 | let sorted = xLabels.sorted { $0.frame.height > $1.frame.height } 71 | let margin = xAxisTitleLabel.frame.size.height > 0 ? self.margin * 2 : self.margin 72 | guard let maxHeightLabel = sorted.first else { 73 | return frame.size.height - margin - xAxisTitleLabel.frame.size.height - axisWidth 74 | } 75 | return frame.size.height - maxHeightLabel.frame.size.height - margin - xAxisTitleLabel.frame.size.height - axisWidth 76 | } 77 | 78 | override public func initView() { 79 | addSubview(yAxisView) 80 | addSubview(yAxisTitleLabel) 81 | addSubview(xAxisView) 82 | addSubview(xAxisTitleLabel) 83 | graphLineLayer.masksToBounds = true 84 | layer.addSublayer(graphLineLayer) 85 | } 86 | 87 | // MARK:- Draw 88 | private func makeXAxisLabels(sections: Int) -> [UILabel] { 89 | var labels = [UILabel]() 90 | for _ in 0.. [UILabel] { 102 | let valueCount = (yAxisMaxValue - yAxisMinValue) / CGFloat(numberOfYAxisLabel - 1) 103 | var value = yAxisMinValue 104 | var labels = [UILabel]() 105 | for _ in 0.. $1.frame.height }.first!.frame.size.height 138 | let y = yAxisTitleLabel.frame.size.height + margin + yLabelHeight/2 139 | yAxisView.frame = CGRect(x: yAxisPositionX, y: y, width: axisWidth, height: xAxisPositionY - y) 140 | xAxisView.frame = CGRect(x: yAxisPositionX, y: xAxisPositionY, width: frame.width - yAxisPositionX, height: axisWidth) 141 | yAxisView.backgroundColor = axisColor 142 | xAxisView.backgroundColor = axisColor 143 | graphLineLayer.frame = CGRect(x: yAxisView.frame.minX + axisWidth, y: yAxisView.frame.minY, 144 | width: xAxisView.frame.width - axisWidth, height: yAxisView.frame.height) 145 | } 146 | 147 | private func prepareYLabels() { 148 | let space = (yAxisView.frame.height / CGFloat(numberOfYAxisLabel - 1)) 149 | var y = xAxisView.frame.origin.y 150 | yLabels.forEach { 151 | let width = $0.frame.size.width 152 | let height = $0.frame.size.height 153 | $0.frame = CGRect(x: yAxisView.frame.origin.x - width - margin, y: y - height/2, width: width, height: height) 154 | y -= space 155 | addSubview($0) 156 | } 157 | } 158 | 159 | private func prepareXlabels() { 160 | let width = (xAxisView.frame.size.width - axisWidth) / CGFloat(xLabels.count) 161 | for (index, label) in xLabels.enumerated() { 162 | let x = xAxisView.frame.origin.x + axisWidth + width * CGFloat(index) 163 | label.text = dataSource?.barChartView(self, titleForXlabelInSection: index) 164 | label.frame = CGRect(x: x, y: xAxisView.frame.origin.y + axisWidth + margin, width: width, height: label.frame.size.height) 165 | label.textAlignment = .center 166 | addSubview(label) 167 | } 168 | } 169 | 170 | private func prepareGraphLineLayers(positionY: CGFloat) { 171 | let lineLayer = CALayer() 172 | lineLayer.frame = CGRect(x: xAxisView.frame.minX, y: positionY, 173 | width: xAxisView.frame.width, height: 1) 174 | lineLayer.backgroundColor = UIColor.black.cgColor 175 | layer.addSublayer(lineLayer) 176 | horizontalLineLayers.append(lineLayer) 177 | } 178 | 179 | private func prepareBarLayers(section: Int) { 180 | let xLabel = xLabels[section] 181 | let barLayer = CALayer() 182 | let width = (xAxisView.frame.width - axisWidth - barSpace*CGFloat(xLabels.count + 1)) / CGFloat(xLabels.count) 183 | barLayer.frame = CGRect(x: xLabel.center.x - width/2, y: yAxisView.frame.minY, 184 | width: width, height: yAxisView.frame.height - axisWidth) 185 | barLayers.append(barLayer) 186 | layer.addSublayer(barLayer) 187 | } 188 | 189 | private func prepareBarGraph(section: Int, colors: [UIColor], values: [CGFloat]) { 190 | let sum = values.reduce(0, +) 191 | let barLayer = barLayers[section] 192 | barLayer.masksToBounds = true 193 | var frame = barLayer.frame 194 | frame.size.height = ((sum - yAxisMinValue) / (yAxisMaxValue - yAxisMinValue)) * barLayer.frame.height 195 | if frame.size.height.isNaN { 196 | frame.size.height = 0 197 | } 198 | frame.origin.y = xAxisView.frame.minY - frame.height 199 | barLayer.frame = frame 200 | var y = barLayer.frame.height + (barLayer.frame.height * yAxisMinValue) / (sum - yAxisMinValue) 201 | if y.isNaN { 202 | y = 0 203 | } 204 | 205 | for (index, color) in colors.enumerated() { 206 | let value = values[index] 207 | var height = (value/(sum - yAxisMinValue)) * barLayer.frame.height 208 | if height.isNaN { 209 | height = 0 210 | } 211 | let valueLayer = CAShapeLayer() 212 | valueLayer.frame = barLayer.bounds 213 | valueLayer.fillColor = color.cgColor 214 | let path = UIBezierPath() 215 | path.move(to: CGPoint(x: 0, y: y - height)) 216 | path.addLine(to: CGPoint(x: 0, y: y)) 217 | path.addLine(to: CGPoint(x: barLayer.frame.width, y: y)) 218 | path.addLine(to: CGPoint(x: barLayer.frame.width, y: y - height)) 219 | path.addLine(to: CGPoint(x: 0, y: y - height)) 220 | valueLayer.path = path.cgPath 221 | barLayer.addSublayer(valueLayer) 222 | y -= height 223 | } 224 | } 225 | 226 | private func showAnimation() { 227 | for barLayer in barLayers { 228 | let startPath = UIBezierPath() 229 | startPath.move(to: CGPoint(x: 0, y: barLayer.frame.height)) 230 | startPath.addLine(to: CGPoint(x: 0, y: barLayer.frame.height)) 231 | startPath.addLine(to: CGPoint(x: barLayer.frame.width, y: barLayer.frame.height)) 232 | startPath.addLine(to: CGPoint(x: barLayer.frame.width, y: barLayer.frame.height)) 233 | startPath.addLine(to: CGPoint(x: 0, y: barLayer.frame.height)) 234 | for layer in barLayer.sublayers! { 235 | let valueLayer = layer as! CAShapeLayer 236 | let animationPath = UIBezierPath(cgPath: valueLayer.path!) 237 | let animation = CABasicAnimation(keyPath: "path") 238 | animation.duration = animationDuration 239 | animation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeOut) 240 | animation.fromValue = startPath.cgPath 241 | animation.toValue = animationPath.cgPath 242 | valueLayer.path = animationPath.cgPath 243 | valueLayer.add(animation, forKey: nil) 244 | } 245 | } 246 | } 247 | 248 | // MARK:- Reload 249 | override public func reloadData() { 250 | clearView() 251 | guard let dataSource = dataSource else { 252 | return 253 | } 254 | let sections = dataSource.numberOfSections(in: self) 255 | precondition(numberOfYAxisLabel > 1, "numberOfYAxisLabel is less than 2") 256 | precondition(sections > 0, "sections is less than 1") 257 | precondition(yAxisMaxValue >= 0, "yAxisMaxValue is less than 0") 258 | yLabels = makeYAxisLabels() 259 | xLabels = makeXAxisLabels(sections: sections) 260 | prepareXAxisTitleLabel() 261 | prepareYAxisTitleLabel() 262 | settingAxisViewFrame() 263 | prepareYLabels() 264 | prepareXlabels() 265 | if isHorizontalLine { 266 | yLabels.forEach { 267 | prepareGraphLineLayers(positionY: $0.center.y) 268 | } 269 | } 270 | for section in 0..= 0, "value is less than 0 \(indexPath)") 279 | values.append(value) 280 | colors.append(dataSource.barChartView(self, colorForRowAtIndexPath: indexPath)) 281 | } 282 | prepareBarGraph(section: section, colors: colors, values: values) 283 | } 284 | showAnimation() 285 | } 286 | 287 | private func clearView() { 288 | xLabels.forEach { $0.removeFromSuperview() } 289 | xLabels.removeAll() 290 | 291 | yLabels.forEach { $0.removeFromSuperview() } 292 | yLabels.removeAll() 293 | 294 | horizontalLineLayers.forEach { $0.removeFromSuperlayer() } 295 | horizontalLineLayers.removeAll() 296 | 297 | barLayers.forEach { $0.removeFromSuperlayer() } 298 | barLayers.removeAll() 299 | 300 | graphLineLayers.forEach { $0.removeFromSuperlayer() } 301 | graphLineLayers.removeAll() 302 | } 303 | } 304 | -------------------------------------------------------------------------------- /Source/AMChartData.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AMChartData.swift 3 | // SampleAMChart 4 | // 5 | // Created by am10 on 2019/10/16. 6 | // Copyright © 2019 am10. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | public enum AMDecimalFormat { 12 | case none 13 | case first 14 | case second 15 | 16 | public func formattedValue(_ value: CGFloat) -> String { 17 | switch self { 18 | case .none: 19 | return String(format: "%.0f", value) 20 | case .first: 21 | return String(format: "%.1f", value) 22 | case .second: 23 | return String(format: "%.2f", value) 24 | } 25 | } 26 | } 27 | 28 | public enum AMPointType { 29 | /// circle(not filled) 30 | case type1 31 | /// circle(filled) 32 | case type2 33 | /// square(not filled) 34 | case type3 35 | /// square(filled) 36 | case type4 37 | /// triangle(not filled) 38 | case type5 39 | /// triangle(filled) 40 | case type6 41 | /// diamond(not filled) 42 | case type7 43 | /// diamond(filled) 44 | case type8 45 | /// x mark 46 | case type9 47 | 48 | var isFilled: Bool { 49 | switch self { 50 | case .type2, .type4, .type6, .type8: 51 | return true 52 | default: 53 | return false 54 | } 55 | } 56 | } 57 | 58 | public struct AMScatterValue { 59 | 60 | public var xValue: CGFloat = 0 61 | public var yValue: CGFloat = 0 62 | 63 | public init(x: CGFloat, y: CGFloat) { 64 | xValue = x 65 | yValue = y 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /Source/AMChartView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AMChartView.swift 3 | // SampleAMChart 4 | // 5 | // Created by makoto on 2019/10/17. 6 | // Copyright © 2019 am10. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | public class AMChartView: UIView { 12 | 13 | override public var bounds: CGRect { 14 | didSet { 15 | reloadData() 16 | } 17 | } 18 | 19 | // MARK:- Initialize 20 | required public init?(coder aDecoder: NSCoder) { 21 | super.init(coder:aDecoder) 22 | initView() 23 | } 24 | 25 | override public init(frame: CGRect) { 26 | super.init(frame: frame) 27 | backgroundColor = .clear 28 | initView() 29 | } 30 | 31 | convenience init() { 32 | self.init(frame: .zero) 33 | } 34 | 35 | public func initView() { 36 | } 37 | 38 | override public func draw(_ rect: CGRect) { 39 | reloadData() 40 | } 41 | 42 | // MARK:- Reload 43 | public func reloadData() { 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Source/AMLineChartView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AMLineChartView.swift 3 | // AMChart, https://github.com/adventam10/AMChart 4 | // 5 | // Created by am10 on 2018/01/02. 6 | // Copyright © 2018年 am10. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | public protocol AMLineChartViewDataSource: AnyObject { 12 | func numberOfSections(in lineChartView: AMLineChartView) -> Int 13 | func numberOfRows(in lineChartView: AMLineChartView) -> Int 14 | func lineChartView(_ lineChartView: AMLineChartView, valueForRowAtIndexPath indexPath: IndexPath) -> CGFloat 15 | func lineChartView(_ lineChartView: AMLineChartView, colorForSection section: Int) -> UIColor 16 | func lineChartView(_ lineChartView: AMLineChartView, titleForXlabelInRow row: Int) -> String 17 | func lineChartView(_ lineChartView: AMLineChartView, pointTypeForSection section: Int) -> AMPointType 18 | } 19 | 20 | public class AMLineChartView: AMChartView { 21 | 22 | @IBInspectable public var yAxisMaxValue: CGFloat = 1000 23 | @IBInspectable public var yAxisMinValue: CGFloat = 0 24 | @IBInspectable public var numberOfYAxisLabel: Int = 6 25 | @IBInspectable public var axisColor: UIColor = .black 26 | @IBInspectable public var axisWidth: CGFloat = 1.0 27 | @IBInspectable public var yAxisTitleFont: UIFont = .systemFont(ofSize: 15) 28 | @IBInspectable public var xAxisTitleFont: UIFont = .systemFont(ofSize: 15) 29 | @IBInspectable public var yLabelsFont: UIFont = .systemFont(ofSize: 15) 30 | @IBInspectable public var xLabelsFont: UIFont = .systemFont(ofSize: 15) 31 | @IBInspectable public var yAxisTitleColor: UIColor = .black 32 | @IBInspectable public var xAxisTitleColor: UIColor = .black 33 | @IBInspectable public var yLabelsTextColor: UIColor = .black 34 | @IBInspectable public var xLabelsTextColor: UIColor = .black 35 | @IBInspectable public var isHorizontalLine: Bool = false 36 | @IBInspectable public var yAxisTitle: String = "" 37 | @IBInspectable public var xAxisTitle: String = "" 38 | 39 | weak public var dataSource: AMLineChartViewDataSource? 40 | public var yAxisDecimalFormat: AMDecimalFormat = .none 41 | public var animationDuration: CFTimeInterval = 0.6 42 | 43 | private let margin: CGFloat = 8 44 | private let pointRadius: CGFloat = 5 45 | private let xAxisView = UIView() 46 | private let yAxisView = UIView() 47 | private let xAxisTitleLabel: UILabel = { 48 | let label = UILabel() 49 | label.adjustsFontSizeToFitWidth = true 50 | label.numberOfLines = 0 51 | return label 52 | }() 53 | private let yAxisTitleLabel: UILabel = { 54 | let label = UILabel() 55 | label.adjustsFontSizeToFitWidth = true 56 | label.numberOfLines = 0 57 | return label 58 | }() 59 | 60 | private var xLabels = [UILabel]() 61 | private var yLabels = [UILabel]() 62 | private var graphLayers = [CAShapeLayer]() 63 | private var horizontalLineLayers = [CALayer]() 64 | private var animationPaths = [UIBezierPath]() 65 | private var yAxisPositionX: CGFloat { 66 | let sorted = yLabels.sorted { $0.frame.width > $1.frame.width } 67 | guard let maxWidthLabel = sorted.first else { 68 | return margin 69 | } 70 | return maxWidthLabel.frame.size.width + margin 71 | } 72 | private var xAxisPositionY: CGFloat { 73 | let sorted = xLabels.sorted { $0.frame.height > $1.frame.height } 74 | let margin = xAxisTitleLabel.frame.size.height > 0 ? self.margin * 2 : self.margin 75 | guard let maxHeightLabel = sorted.first else { 76 | return frame.size.height - margin - xAxisTitleLabel.frame.size.height - axisWidth 77 | } 78 | return frame.size.height - maxHeightLabel.frame.size.height - margin - xAxisTitleLabel.frame.size.height - axisWidth 79 | } 80 | 81 | override public func initView() { 82 | addSubview(yAxisView) 83 | addSubview(yAxisTitleLabel) 84 | addSubview(xAxisView) 85 | addSubview(xAxisTitleLabel) 86 | } 87 | 88 | // MARK:- Draw 89 | private func makeXAxisLabels(rows: Int) -> [UILabel] { 90 | var labels = [UILabel]() 91 | for _ in 0.. [UILabel] { 103 | let valueCount = (yAxisMaxValue - yAxisMinValue) / CGFloat(numberOfYAxisLabel - 1) 104 | var value = yAxisMinValue 105 | var labels = [UILabel]() 106 | for _ in 0.. $1.frame.height }.first!.frame.size.height 139 | let y = yAxisTitleLabel.frame.size.height + margin + yLabelHeight/2 140 | yAxisView.frame = CGRect(x: yAxisPositionX, y: y, width: axisWidth, height: xAxisPositionY - y) 141 | xAxisView.frame = CGRect(x: yAxisPositionX, y: xAxisPositionY, width: frame.width - yAxisPositionX, height: axisWidth) 142 | yAxisView.backgroundColor = axisColor 143 | xAxisView.backgroundColor = axisColor 144 | } 145 | 146 | private func prepareYLabels() { 147 | let space = (yAxisView.frame.height / CGFloat(numberOfYAxisLabel - 1)) 148 | var y = xAxisView.frame.origin.y 149 | yLabels.forEach { 150 | let width = $0.frame.size.width 151 | let height = $0.frame.size.height 152 | $0.frame = CGRect(x: yAxisView.frame.origin.x - width - margin, y: y - height/2, width: width, height: height) 153 | y -= space 154 | addSubview($0) 155 | } 156 | } 157 | 158 | private func prepareXlabels() { 159 | let width = (xAxisView.frame.size.width - axisWidth) / CGFloat(xLabels.count) 160 | for (index, label) in xLabels.enumerated() { 161 | let x = xAxisView.frame.origin.x + axisWidth + width * CGFloat(index) 162 | label.text = dataSource?.lineChartView(self, titleForXlabelInRow: index) 163 | label.frame = CGRect(x: x, y: xAxisView.frame.origin.y + axisWidth + margin, width: width, height: label.frame.size.height) 164 | label.textAlignment = .center 165 | addSubview(label) 166 | } 167 | } 168 | 169 | private func prepareGraphLineLayers(positionY: CGFloat) { 170 | let lineLayer = CALayer() 171 | lineLayer.frame = CGRect(x: xAxisView.frame.origin.x, y: positionY, 172 | width: xAxisView.frame.width, height: 1) 173 | lineLayer.backgroundColor = UIColor.black.cgColor 174 | layer.addSublayer(lineLayer) 175 | horizontalLineLayers.append(lineLayer) 176 | } 177 | 178 | private func prepareGraphLayers(sections: Int) { 179 | while graphLayers.count < sections { 180 | let graphLayer = CAShapeLayer() 181 | layer.addSublayer(graphLayer) 182 | graphLayers.append(graphLayer) 183 | } 184 | 185 | while graphLayers.count > sections { 186 | let graphLayer = graphLayers.last 187 | graphLayer?.removeFromSuperlayer() 188 | graphLayers.removeLast() 189 | } 190 | 191 | graphLayers.forEach { 192 | $0.frame = CGRect(x: yAxisView.frame.origin.x + axisWidth, y: yAxisView.frame.origin.y, 193 | width: xAxisView.frame.width - axisWidth, height: yAxisView.frame.height) 194 | } 195 | } 196 | 197 | private func setGraphLayerColor(_ graphLayer: CAShapeLayer, color: UIColor, pointType: AMPointType) { 198 | graphLayer.strokeColor = color.cgColor 199 | if pointType.isFilled { 200 | graphLayer.fillColor = color.cgColor 201 | } else { 202 | graphLayer.fillColor = UIColor.clear.cgColor 203 | } 204 | } 205 | 206 | private func makeAnimationPath(_ graphLayer: CAShapeLayer, values: [CGFloat], pointType: AMPointType) -> UIBezierPath { 207 | let path = UIBezierPath() 208 | for (index, xLabel) in xLabels.enumerated() { 209 | let value = values[index] 210 | let x = xLabel.frame.origin.x + xLabel.frame.width/2 - (yAxisView.frame.origin.x + axisWidth) 211 | var y = graphLayer.frame.height - (((value - yAxisMinValue)/(yAxisMaxValue - yAxisMinValue)) * graphLayer.frame.height) 212 | if y.isNaN { 213 | y = 0 214 | } 215 | 216 | let pointPath = makePointPath(x: x, y: y, pointType: pointType) 217 | if index == 0 { 218 | path.append(pointPath) 219 | path.move(to: CGPoint(x: x, y: y)) 220 | } else { 221 | path.addLine(to: CGPoint(x: x, y: y)) 222 | path.append(pointPath) 223 | path.move(to: CGPoint(x: x, y: y)) 224 | } 225 | } 226 | return path 227 | } 228 | 229 | private func makePointPath(x: CGFloat, y: CGFloat, pointType: AMPointType) -> UIBezierPath { 230 | switch pointType { 231 | case .type1, .type2: 232 | return makeCirclePointPath(x: x, y: y) 233 | case .type3, .type4: 234 | return makeSquarePointPath(x: x, y: y) 235 | case .type5, .type6: 236 | return makeTrianglePointPath(x: x, y: y) 237 | case .type7, .type8: 238 | return makeDiamondPointPath(x: x, y: y) 239 | case .type9: 240 | return makeXPointPath(x: x, y: y) 241 | } 242 | } 243 | 244 | private func makeCirclePointPath(x: CGFloat, y: CGFloat) -> UIBezierPath { 245 | return .init(ovalIn: CGRect(x: x - pointRadius, y: y - pointRadius, 246 | width: pointRadius * 2, height: pointRadius * 2)) 247 | } 248 | 249 | private func makeSquarePointPath(x: CGFloat, y: CGFloat) -> UIBezierPath { 250 | return .init(rect: CGRect(x: x - pointRadius, y: y - pointRadius, 251 | width: pointRadius * 2, height: pointRadius * 2)) 252 | } 253 | 254 | private func makeTrianglePointPath(x: CGFloat, y: CGFloat) -> UIBezierPath { 255 | let path = UIBezierPath() 256 | path.move(to: CGPoint(x: x, y: y - pointRadius)) 257 | path.addLine(to: CGPoint(x: x + pointRadius, y: y + pointRadius)) 258 | path.addLine(to: CGPoint(x: x - pointRadius, y: y + pointRadius)) 259 | path.addLine(to: CGPoint(x: x, y: y - pointRadius)) 260 | return path 261 | } 262 | 263 | private func makeDiamondPointPath(x: CGFloat, y: CGFloat) -> UIBezierPath { 264 | let path = UIBezierPath() 265 | path.move(to: CGPoint(x: x, y: y - pointRadius)) 266 | path.addLine(to: CGPoint(x: x + pointRadius, y: y)) 267 | path.addLine(to: CGPoint(x: x , y: y + pointRadius)) 268 | path.addLine(to: CGPoint(x: x - pointRadius, y: y)) 269 | path.addLine(to: CGPoint(x: x, y: y - pointRadius)) 270 | return path 271 | } 272 | 273 | private func makeXPointPath(x: CGFloat, y: CGFloat) -> UIBezierPath { 274 | let path = UIBezierPath() 275 | path.move(to: CGPoint(x: x - pointRadius, y: y - pointRadius)) 276 | path.addLine(to: CGPoint(x: x + pointRadius, y: y + pointRadius)) 277 | path.move(to: CGPoint(x: x + pointRadius, y: y - pointRadius)) 278 | path.addLine(to: CGPoint(x: x - pointRadius, y: y + pointRadius)) 279 | return path 280 | } 281 | 282 | private func showAnimation() { 283 | for (index, graphLayer) in graphLayers.enumerated() { 284 | let animationPath = animationPaths[index] 285 | if graphLayer.path == nil { 286 | let animation = CABasicAnimation(keyPath: "strokeEnd") 287 | animation.duration = animationDuration 288 | animation.fromValue = 0 289 | animation.toValue = 1 290 | graphLayer.path = animationPath.cgPath 291 | graphLayer.add(animation, forKey: nil) 292 | } else { 293 | let animation = CABasicAnimation(keyPath: "path") 294 | animation.duration = animationDuration 295 | animation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeOut) 296 | animation.fromValue = UIBezierPath(cgPath: graphLayer.path!).cgPath 297 | animation.toValue = animationPath.cgPath 298 | graphLayer.path = animationPath.cgPath 299 | graphLayer.add(animation, forKey: nil) 300 | } 301 | } 302 | animationPaths.removeAll() 303 | } 304 | 305 | // MARK:- Reload 306 | override public func reloadData() { 307 | clearView() 308 | guard let dataSource = dataSource else { 309 | return 310 | } 311 | let sections = dataSource.numberOfSections(in: self) 312 | let rows = dataSource.numberOfRows(in: self) 313 | precondition(numberOfYAxisLabel > 1, "numberOfYAxisLabel is less than 2") 314 | precondition(rows > 0, "rows is less than 1") 315 | precondition(yAxisMinValue < yAxisMaxValue, "yAxisMaxValue is less than or eqaul to yAxisMinValue") 316 | yLabels = makeYAxisLabels() 317 | xLabels = makeXAxisLabels(rows: rows) 318 | prepareXAxisTitleLabel() 319 | prepareYAxisTitleLabel() 320 | settingAxisViewFrame() 321 | prepareYLabels() 322 | prepareXlabels() 323 | if isHorizontalLine { 324 | yLabels.forEach { 325 | prepareGraphLineLayers(positionY: $0.center.y) 326 | } 327 | } 328 | prepareGraphLayers(sections: sections) 329 | for section in 0.. Int 13 | func pieChartView(_ pieChartView: AMPieChartView, valueForSection section: Int) -> CGFloat 14 | func pieChartView(_ pieChartView: AMPieChartView, colorForSection section: Int) -> UIColor 15 | } 16 | 17 | public protocol AMPieChartViewDelegate: AnyObject { 18 | func pieChartView(_ pieChartView: AMPieChartView, didSelectSection section: Int) 19 | func pieChartView(_ pieChartView: AMPieChartView, didDeSelectSection section: Int) 20 | } 21 | 22 | private let animationSpace: CGFloat = 10 23 | private let deSelectIndex: Int = -1 24 | 25 | public class AMPieChartView: AMChartView { 26 | 27 | class FanLayer: CAShapeLayer { 28 | var index: Int = 0 29 | @objc var startAngle: Float = 0 30 | @objc var endAngle: Float = 0 31 | var value: CGFloat = 0 32 | var rate: CGFloat = 0 33 | var isDounut = false 34 | private var centerPoint: CGPoint { 35 | return CGPoint(x: bounds.midX, y: bounds.midY) 36 | } 37 | private var radius: CGFloat { 38 | return (frame.width - animationSpace * 2) / 2 39 | } 40 | private var dounutRadius: CGFloat { 41 | return radius / 2 42 | } 43 | override class func needsDisplay(forKey key: String) -> Bool { 44 | if key == #keyPath(endAngle) || key == #keyPath(startAngle) { 45 | return true 46 | } 47 | return super.needsDisplay(forKey: key) 48 | } 49 | 50 | override init() { 51 | super.init() 52 | } 53 | 54 | override init(layer: Any) { 55 | if let layer = layer as? FanLayer { 56 | startAngle = layer.startAngle 57 | endAngle = layer.endAngle 58 | isDounut = layer.isDounut 59 | } 60 | 61 | super.init(layer: layer) 62 | } 63 | 64 | required init(coder aDecoder: NSCoder) { 65 | fatalError("init(coder:) has not been implemented") 66 | } 67 | 68 | override func draw(in ctx: CGContext) { 69 | ctx.beginPath() 70 | if isDounut { 71 | ctx.move(to: .init(x: centerPoint.x + dounutRadius * CGFloat(cosf(startAngle)), 72 | y: centerPoint.y + dounutRadius * CGFloat(sinf(startAngle)))) 73 | } else { 74 | ctx.move(to: CGPoint(x: centerPoint.x, y: centerPoint.y)) 75 | } 76 | ctx.addLine(to: .init(x: centerPoint.x + radius * CGFloat(cosf(startAngle)), 77 | y: centerPoint.y + radius * CGFloat(sinf(startAngle)))) 78 | ctx.addArc(center: centerPoint, radius: radius, startAngle: CGFloat(startAngle), 79 | endAngle: CGFloat(endAngle), clockwise: false) 80 | if isDounut { 81 | ctx.addLine(to: .init(x: centerPoint.x + dounutRadius * CGFloat(cosf(endAngle)), 82 | y: centerPoint.y + dounutRadius * CGFloat(sinf(endAngle)))) 83 | ctx.addArc(center: centerPoint, radius: dounutRadius, startAngle: CGFloat(endAngle), 84 | endAngle: CGFloat(startAngle) + CGFloat(Double.pi * 2), clockwise: true) 85 | } 86 | ctx.closePath() 87 | ctx.setFillColor(fillColor!) 88 | ctx.drawPath(using: .fill) 89 | } 90 | } 91 | 92 | @IBInspectable public var isDounut: Bool = false 93 | @IBInspectable public var centerLabelFont: UIFont = .systemFont(ofSize: 15) 94 | @IBInspectable public var centerLabelTextColor: UIColor = .black 95 | @IBInspectable public var centerLabelText: String = "" { 96 | didSet { 97 | centerLabel.text = centerLabelText 98 | } 99 | } 100 | 101 | weak public var dataSource: AMPieChartViewDataSource? 102 | weak public var delegate: AMPieChartViewDelegate? 103 | public var animationDuration: CFTimeInterval = 0.4 104 | public var selectedAnimationDuration: CFTimeInterval = 0.3 105 | public var centerLabelAttributedText: NSAttributedString? = nil { 106 | didSet { 107 | centerLabel.attributedText = centerLabelAttributedText 108 | } 109 | } 110 | 111 | private let chartView = UIView() 112 | private let animationChartView = UIView() 113 | private var selectedIndex: Int = deSelectIndex 114 | private let centerLabel: UILabel = { 115 | let label = UILabel() 116 | label.textAlignment = .center 117 | label.adjustsFontSizeToFitWidth = true 118 | label.numberOfLines = 0 119 | return label 120 | }() 121 | private var fanLayers = [FanLayer]() 122 | private var animationFanLayers = [FanLayer]() 123 | private var animationStartAngles = [Float]() 124 | private var animationEndAngles = [Float]() 125 | private var radius: CGFloat { 126 | return (chartView.frame.width - animationSpace * 2)/2 127 | } 128 | private var dounutRadius: CGFloat { 129 | return radius / 2 130 | } 131 | 132 | override public func initView() { 133 | addSubview(animationChartView) 134 | addSubview(chartView) 135 | let tap = UITapGestureRecognizer(target: self, 136 | action: #selector(self.tapAction(gesture:))) 137 | chartView.addGestureRecognizer(tap) 138 | addSubview(centerLabel) 139 | } 140 | 141 | // MARK:- Draw 142 | private func settingChartViewFrame() { 143 | let length = frame.width < frame.height ? frame.width : frame.height 144 | chartView.frame = CGRect(x: bounds.midX - length/2, y: bounds.midY - length/2, 145 | width: length, height: length) 146 | animationChartView.frame = chartView.frame 147 | chartView.isHidden = true 148 | animationChartView.isHidden = false 149 | 150 | centerLabel.frame = CGRect(x: 0, y: 0, width: dounutRadius*2, height: dounutRadius*2) 151 | centerLabel.font = centerLabelFont 152 | centerLabel.textColor = centerLabelTextColor 153 | centerLabel.layer.cornerRadius = dounutRadius 154 | centerLabel.layer.masksToBounds = true 155 | centerLabel.center = chartView.center 156 | } 157 | 158 | private func prepareFanLayers(sections: Int) { 159 | while fanLayers.count < sections { 160 | let fanLayer = FanLayer() 161 | let animfanLayer = FanLayer() 162 | animationChartView.layer.addSublayer(animfanLayer) 163 | chartView.layer.addSublayer(fanLayer) 164 | fanLayers.append(fanLayer) 165 | animationFanLayers.append(animfanLayer) 166 | } 167 | 168 | while fanLayers.count > sections { 169 | fanLayers.last?.removeFromSuperlayer() 170 | animationFanLayers.last?.removeFromSuperlayer() 171 | fanLayers.removeLast() 172 | animationFanLayers.removeLast() 173 | } 174 | 175 | for (index, fanLayer) in fanLayers.enumerated() { 176 | fanLayer.frame = chartView.bounds 177 | fanLayer.index = index 178 | animationFanLayers[index].index = index 179 | animationFanLayers[index].frame = chartView.bounds 180 | } 181 | } 182 | 183 | private func setFanLayers(colors: [UIColor], values: [CGFloat]) { 184 | let sum = values.reduce(0, +) 185 | var angle = Float(Double.pi/2 + Double.pi) 186 | for (index, fanLayer) in fanLayers.enumerated() { 187 | let rate = values[index] / sum 188 | fanLayer.fillColor = colors[index].cgColor 189 | fanLayer.value = values[index] 190 | fanLayer.rate = rate 191 | fanLayer.startAngle = angle 192 | fanLayer.endAngle = angle + Float(Double.pi*2) * Float(rate) 193 | fanLayer.isDounut = isDounut 194 | 195 | let animFanLayer = animationFanLayers[index] 196 | animFanLayer.fillColor = colors[index].cgColor 197 | animFanLayer.value = values[index] 198 | animFanLayer.rate = rate 199 | animFanLayer.isDounut = isDounut 200 | 201 | animationStartAngles.append(angle) 202 | animationEndAngles.append(angle + Float(Double.pi*2) * Float(rate)) 203 | angle += Float(Double.pi*2) * Float(rate) 204 | } 205 | } 206 | 207 | private func makeFanLayerPath(center: CGPoint, startAngle: Float, endAngle: Float) -> UIBezierPath { 208 | let piePath = UIBezierPath() 209 | if isDounut { 210 | piePath.move(to: CGPoint(x: center.x + dounutRadius * CGFloat(cosf(startAngle)), 211 | y: center.y + dounutRadius * CGFloat(sinf(startAngle)))) 212 | } else { 213 | piePath.move(to: center) 214 | } 215 | piePath.addLine(to: CGPoint(x: center.x + radius * CGFloat(cosf(startAngle)), 216 | y: center.y + radius * CGFloat(sinf(startAngle)))) 217 | piePath.addArc(withCenter: center, radius: radius, startAngle: CGFloat(startAngle), 218 | endAngle: CGFloat(endAngle), clockwise: true) 219 | if isDounut { 220 | piePath.addLine(to: CGPoint(x: center.x + dounutRadius * CGFloat(cosf(endAngle)), 221 | y: center.y + dounutRadius * CGFloat(sinf(endAngle)))) 222 | if startAngle + Float(Double.pi*2) == endAngle { 223 | piePath.addArc(withCenter: center, radius: dounutRadius, startAngle: CGFloat(startAngle), 224 | endAngle: CGFloat(endAngle), clockwise: false) 225 | } else { 226 | piePath.addArc(withCenter: center, radius: dounutRadius, startAngle: CGFloat(endAngle), 227 | endAngle: CGFloat(startAngle) + CGFloat(Double.pi*2), clockwise: false) 228 | } 229 | } 230 | piePath.close() 231 | return piePath 232 | } 233 | 234 | private func showAnimation() { 235 | for (index ,animfanLayer) in animationFanLayers.enumerated() { 236 | CATransaction.begin() 237 | CATransaction.setCompletionBlock { [unowned self] in 238 | if animfanLayer.animation(forKey: "angleAnimation") != nil{ 239 | animfanLayer.removeAnimation(forKey: "angleAnimation") 240 | self.animationComplete(index: index) 241 | } 242 | } 243 | 244 | let fanLayer = fanLayers[index] 245 | let animation1 = CABasicAnimation(keyPath: "startAngle") 246 | if fanLayer.path == nil { 247 | animation1.fromValue = Float(Double.pi/2 + Double.pi) 248 | } else { 249 | animation1.fromValue = animfanLayer.startAngle 250 | } 251 | animation1.toValue = animationStartAngles[index] 252 | 253 | let animation2 = CABasicAnimation(keyPath: "endAngle") 254 | if fanLayer.path == nil { 255 | animation2.fromValue = Float(Double.pi/2 + Double.pi) 256 | } else { 257 | animation2.fromValue = animfanLayer.endAngle 258 | } 259 | animation2.toValue = animationEndAngles[index] 260 | 261 | let group = CAAnimationGroup() 262 | group.duration = animationDuration 263 | group.repeatCount = 1 264 | group.isRemovedOnCompletion = false 265 | group.animations = [animation1, animation2] 266 | 267 | animfanLayer.startAngle = animationStartAngles[index] 268 | animfanLayer.endAngle = animationEndAngles[index] 269 | animfanLayer.add(group, forKey: "angleAnimation") 270 | CATransaction.commit() 271 | } 272 | animationStartAngles.removeAll() 273 | animationEndAngles.removeAll() 274 | } 275 | 276 | private func animationComplete(index: Int) { 277 | if index < fanLayers.count { 278 | let fanLayer = fanLayers[index] 279 | let path = makeFanLayerPath(center: .init(x: fanLayer.bounds.midX, y: fanLayer.bounds.midY), 280 | startAngle: fanLayer.startAngle, endAngle: fanLayer.endAngle) 281 | fanLayer.path = path.cgPath 282 | animationChartView.isHidden = true 283 | chartView.isHidden = false 284 | } 285 | } 286 | 287 | // MARK:- Select / Deselect 288 | private func makeAnimation(fromPath: UIBezierPath, toPath: UIBezierPath, duration: CFTimeInterval) -> CABasicAnimation { 289 | let animation = CABasicAnimation(keyPath: "path") 290 | animation.duration = duration 291 | animation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeOut) 292 | animation.fromValue = fromPath.cgPath 293 | animation.toValue = toPath.cgPath 294 | return animation 295 | } 296 | 297 | private func setDidSelectAnimation(fanLayer: FanLayer) { 298 | let centerPoint = CGPoint(x: fanLayer.bounds.midX, y: fanLayer.bounds.midY) 299 | let angle = (fanLayer.startAngle + fanLayer.endAngle) / 2 300 | let smallCenterPoint = CGPoint(x: centerPoint.x + animationSpace * CGFloat(cosf(angle)), 301 | y: centerPoint.y + animationSpace * CGFloat(sinf(angle))) 302 | let animationPath = makeFanLayerPath(center: smallCenterPoint, startAngle: fanLayer.startAngle, endAngle: fanLayer.endAngle) 303 | let startPath = UIBezierPath(cgPath: fanLayer.path!) 304 | let animation = makeAnimation(fromPath: startPath, toPath: animationPath, duration: selectedAnimationDuration) 305 | fanLayer.path = animationPath.cgPath 306 | fanLayer.add(animation, forKey:nil) 307 | } 308 | 309 | private func setDidDeselectAnimation(fanLayer: FanLayer) { 310 | let animationPath = makeFanLayerPath(center: .init(x: fanLayer.bounds.midX, y: fanLayer.bounds.midY), 311 | startAngle: fanLayer.startAngle, endAngle: fanLayer.endAngle) 312 | let startPath = UIBezierPath(cgPath: fanLayer.path!) 313 | let animation = makeAnimation(fromPath: startPath, toPath: animationPath, duration: selectedAnimationDuration) 314 | fanLayer.path = animationPath.cgPath 315 | fanLayer.add(animation, forKey:nil) 316 | } 317 | 318 | @objc func tapAction(gesture: UITapGestureRecognizer) { 319 | let point = gesture.location(in: chartView) 320 | fanLayers.forEach { 321 | if UIBezierPath(cgPath: $0.path!).contains(point) { 322 | if selectedIndex == deSelectIndex { 323 | setDidSelectAnimation(fanLayer: $0) 324 | selectedIndex = $0.index 325 | } else if selectedIndex == $0.index { 326 | setDidDeselectAnimation(fanLayer: $0) 327 | delegate?.pieChartView(self, didDeSelectSection: $0.index) 328 | selectedIndex = deSelectIndex 329 | } else { 330 | setDidSelectAnimation(fanLayer: $0) 331 | setDidDeselectAnimation(fanLayer: fanLayers[selectedIndex]) 332 | delegate?.pieChartView(self, didDeSelectSection: fanLayers[selectedIndex].index) 333 | selectedIndex = $0.index 334 | } 335 | delegate?.pieChartView(self, didSelectSection: selectedIndex) 336 | } 337 | } 338 | } 339 | 340 | // MARK:- Reload 341 | override public func reloadData() { 342 | selectedIndex = deSelectIndex 343 | settingChartViewFrame() 344 | guard let dataSource = dataSource else { 345 | return 346 | } 347 | 348 | let sections = dataSource.numberOfSections(in: self) 349 | prepareFanLayers(sections: sections) 350 | var values = [CGFloat]() 351 | var colors = [UIColor]() 352 | for section in 0.. Int 14 | func numberOfRows(in radarChartView: AMRadarChartView) -> Int 15 | func radarChartView(_ radarChartView: AMRadarChartView, valueForRowAtIndexPath indexPath: IndexPath) -> CGFloat 16 | func radarChartView(_ radarChartView: AMRadarChartView, fillColorForSection section: Int) -> UIColor 17 | func radarChartView(_ radarChartView: AMRadarChartView, strokeColorForSection section: Int) -> UIColor 18 | // MARK:- Optional 19 | func radarChartView(_ radarChartView: AMRadarChartView, titleForVertexInRow row: Int) -> String 20 | func radarChartView(_ radarChartView: AMRadarChartView, fontForVertexInRow row: Int) -> UIFont 21 | func radarChartView(_ radarChartView: AMRadarChartView, textColorForVertexInRow row: Int) -> UIColor 22 | } 23 | 24 | public extension AMRadarChartViewDataSource { 25 | func radarChartView(_ radarChartView: AMRadarChartView, titleForVertexInRow row: Int) -> String { 26 | return "" 27 | } 28 | 29 | func radarChartView(_ radarChartView: AMRadarChartView, fontForVertexInRow row: Int) -> UIFont { 30 | return .systemFont(ofSize: 15) 31 | } 32 | 33 | func radarChartView(_ radarChartView: AMRadarChartView, textColorForVertexInRow row: Int) -> UIColor { 34 | return .black 35 | } 36 | } 37 | 38 | public class AMRadarChartView: AMChartView { 39 | 40 | @IBInspectable public var axisMaxValue: CGFloat = 5.0 41 | @IBInspectable public var axisMinValue: CGFloat = 0.0 42 | @IBInspectable public var numberOfAxisLabels: Int = 6 43 | @IBInspectable public var axisColor: UIColor = .black 44 | @IBInspectable public var axisWidth: CGFloat = 1.0 45 | @IBInspectable public var axisLabelsFont: UIFont = .systemFont(ofSize: 15) 46 | @IBInspectable public var axisLabelsTextColor: UIColor = .black 47 | @IBInspectable public var isDottedLine: Bool = false 48 | 49 | weak public var dataSource: AMRadarChartViewDataSource? 50 | public var axisDecimalFormat: AMDecimalFormat = .none 51 | public var animationDuration: CFTimeInterval = 0.6 52 | 53 | private let borderLineWidth: CGFloat = 3.5 54 | private let chartView = UIView() 55 | private let axisView = UIView() 56 | private let graphView = UIView() 57 | 58 | private var radarChartLayer: CAShapeLayer? 59 | private var graphLayers = [CAShapeLayer]() 60 | private var angleList = [Float]() 61 | private var animationPaths = [UIBezierPath]() 62 | private var radius: CGFloat { 63 | if let radarChartLayer = radarChartLayer { 64 | return radarChartLayer.frame.size.width / 2 65 | } 66 | let height = chartView.frame.height - (maxVertexLabelLength*2) 67 | let width = chartView.frame.width - (maxVertexLabelLength*2) 68 | let length = height < width ? height : width 69 | return length / 2 70 | } 71 | private var chartCenter: CGPoint { 72 | return chartView.center 73 | } 74 | private var maxVertexLabelLength: CGFloat = 0 75 | override public func initView() { 76 | addSubview(chartView) 77 | chartView.addSubview(axisView) 78 | chartView.addSubview(graphView) 79 | } 80 | 81 | // MARK:- Prepare View 82 | private func settingChartViewFrame() { 83 | let length = (frame.height < frame.width) ? frame.height : frame.width 84 | chartView.frame = CGRect(x: frame.width/2 - length/2, y: frame.height/2 - length/2, 85 | width: length, height: length) 86 | axisView.frame = chartView.bounds 87 | graphView.frame = chartView.bounds 88 | } 89 | 90 | private func prepareRowLabels() { 91 | var labels = [UILabel]() 92 | for (index, _) in angleList.enumerated() { 93 | let label = makeLabel() 94 | label.font = dataSource?.radarChartView(self, fontForVertexInRow: index) 95 | label.textColor = dataSource?.radarChartView(self, textColorForVertexInRow: index) 96 | label.text = dataSource?.radarChartView(self, titleForVertexInRow: index) 97 | label.sizeToFit() 98 | chartView.addSubview(label) 99 | labels.append(label) 100 | } 101 | let margin: CGFloat = 2 102 | let maxWidth = labels.sorted { $0.frame.width > $1.frame.width }.first!.frame.width 103 | let maxHeight = labels.sorted { $0.frame.height > $1.frame.height }.first!.frame.height 104 | maxVertexLabelLength = maxWidth < maxHeight ? maxHeight + margin : maxWidth + margin 105 | let smallRadius = radius + maxVertexLabelLength/2 106 | let center = CGPoint(x: chartView.frame.size.width/2, y: chartView.frame.size.height/2) 107 | for (index, angle) in angleList.enumerated() { 108 | let label = labels[index] 109 | label.center = CGPoint(x: center.x + smallRadius * CGFloat(cosf(angle)), 110 | y: center.y + smallRadius * CGFloat(sinf(angle))) 111 | } 112 | } 113 | 114 | private func prepareAxisLabels() { 115 | let valueCount = CGFloat(axisMaxValue - axisMinValue) / CGFloat(numberOfAxisLabels - 1) 116 | var value = axisMaxValue 117 | var labels = [UILabel]() 118 | for _ in 0.. $1.frame.width }.first!.frame.width 132 | let center = CGPoint(x: chartView.frame.size.width/2, y: chartView.frame.size.height/2) 133 | labels.forEach { 134 | $0.center = CGPoint(x: center.x - maxWidth/2 - margin + drawRadius * CGFloat(cosf(angle)), 135 | y: center.y + margin + drawRadius * CGFloat(sinf(angle))) 136 | drawRadius -= radius / CGFloat(numberOfAxisLabels - 1) 137 | } 138 | } 139 | 140 | private func makeLabel() -> UILabel { 141 | let label = UILabel(frame: .zero) 142 | label.numberOfLines = 0 143 | return label 144 | } 145 | 146 | // MARK:- ChartLayers 147 | private func makeRadarChartLayer() -> CAShapeLayer { 148 | let radarChartLayer = CAShapeLayer() 149 | radarChartLayer.lineWidth = axisWidth 150 | radarChartLayer.frame = CGRect(x: chartView.frame.width/2 - radius, 151 | y: chartView.frame.height/2 - radius, 152 | width: radius*2, height: radius*2) 153 | radarChartLayer.strokeColor = axisColor.cgColor 154 | radarChartLayer.fillColor = UIColor.clear.cgColor 155 | radarChartLayer.path = makeRadarChartPath().cgPath 156 | radarChartLayer.cornerRadius = radius 157 | return radarChartLayer 158 | } 159 | 160 | private func makeRadarChartPath() -> UIBezierPath { 161 | let centerPoint = CGPoint(x: radius, y: radius) 162 | func point(radius: CGFloat, angle: Float) -> CGPoint { 163 | return .init(x: centerPoint.x + radius * CGFloat(cosf(angle)), y: centerPoint.y + radius * CGFloat(sinf(angle))) 164 | } 165 | let path = UIBezierPath() 166 | path.move(to: centerPoint) 167 | angleList.forEach { 168 | path.addLine(to: point(radius: radius, angle: $0)) 169 | path.move(to: centerPoint) 170 | } 171 | 172 | var drawRadius = radius 173 | for _ in 0.. [Float] { 186 | var angle = Float(Double.pi/2 + Double.pi) 187 | var angleList = [Float]() 188 | for _ in 0.. sections { 203 | let graphLayer = graphLayers.last 204 | graphLayer?.removeFromSuperlayer() 205 | graphLayers.removeLast() 206 | } 207 | 208 | guard let radarChartLayer = radarChartLayer else { 209 | return 210 | } 211 | 212 | for graphLayer in graphLayers { 213 | graphLayer.frame = radarChartLayer.frame 214 | graphLayer.lineWidth = borderLineWidth 215 | graphLayer.lineJoin = .round 216 | graphLayer.lineCap = .round 217 | graphLayer.lineDashPattern = isDottedLine ? [5, 6] : nil 218 | } 219 | } 220 | 221 | private func setGraphLayer(_ graphLayer: CAShapeLayer, path: UIBezierPath, 222 | fillColor: UIColor, strokeColor: UIColor) { 223 | graphLayer.fillColor = fillColor.cgColor 224 | graphLayer.strokeColor = strokeColor.cgColor 225 | graphLayer.cornerRadius = radius 226 | if graphLayer.path == nil { 227 | graphLayer.path = path.cgPath 228 | } 229 | } 230 | 231 | private func makeGraphPath(rows: Int, values: [CGFloat]) -> (start: UIBezierPath, animation: UIBezierPath) { 232 | let centerPoint = CGPoint(x: radius, y: radius) 233 | let animationPath = UIBezierPath() 234 | let startPath = UIBezierPath() 235 | var startPoint = CGPoint.zero 236 | for row in 0.. 1, "numberOfAxisLabel is less than 2") 279 | precondition(sections > 0, "numberOfSections is less than 1") 280 | precondition(rows > 2, "numberOfRows is less than 3") 281 | precondition(axisMinValue < axisMaxValue, "axisMaxValue is less than or eqaul to axisMinValue") 282 | angleList = makeAngleList(rows: rows) 283 | prepareRowLabels() 284 | prepareAxisLabels() 285 | radarChartLayer = makeRadarChartLayer() 286 | axisView.layer.addSublayer(radarChartLayer!) 287 | prepareGraphLayers(sections: sections) 288 | for section in 0.. Int 13 | func scatterChartView(_ scatterChartView: AMScatterChartView, numberOfRowsInSection section: Int) -> Int 14 | func scatterChartView(_ scatterChartView: AMScatterChartView, valueForRowAtIndexPath indexPath: IndexPath) -> AMScatterValue 15 | func scatterChartView(_ scatterChartView: AMScatterChartView, colorForSection section: Int) -> UIColor 16 | func scatterChartView(_ scatterChartView: AMScatterChartView, pointTypeForSection section: Int) -> AMPointType 17 | } 18 | 19 | public class AMScatterChartView: AMChartView { 20 | 21 | @IBInspectable public var yAxisMaxValue: CGFloat = 1000 22 | @IBInspectable public var yAxisMinValue: CGFloat = 0 23 | @IBInspectable public var numberOfYAxisLabel: Int = 6 24 | @IBInspectable public var xAxisMaxValue: CGFloat = 1000 25 | @IBInspectable public var xAxisMinValue: CGFloat = 0 26 | @IBInspectable public var numberOfXAxisLabel: Int = 6 27 | @IBInspectable public var axisColor: UIColor = .black 28 | @IBInspectable public var axisWidth: CGFloat = 1.0 29 | @IBInspectable public var yAxisTitleFont: UIFont = .systemFont(ofSize: 15) 30 | @IBInspectable public var xAxisTitleFont: UIFont = .systemFont(ofSize: 15) 31 | @IBInspectable public var yLabelsFont: UIFont = .systemFont(ofSize: 15) 32 | @IBInspectable public var xLabelsFont: UIFont = .systemFont(ofSize: 15) 33 | @IBInspectable public var yAxisTitleColor: UIColor = .black 34 | @IBInspectable public var xAxisTitleColor: UIColor = .black 35 | @IBInspectable public var yLabelsTextColor: UIColor = .black 36 | @IBInspectable public var xLabelsTextColor: UIColor = .black 37 | @IBInspectable public var isHorizontalLine: Bool = false 38 | @IBInspectable public var yAxisTitle: String = "" 39 | @IBInspectable public var xAxisTitle: String = "" 40 | 41 | weak public var dataSource: AMScatterChartViewDataSource? 42 | public var yAxisDecimalFormat: AMDecimalFormat = .none 43 | public var xAxisDecimalFormat: AMDecimalFormat = .none 44 | public var animationDuration: CFTimeInterval = 0.6 45 | 46 | private let xAxisView = UIView() 47 | private let yAxisView = UIView() 48 | private let xAxisTitleLabel: UILabel = { 49 | let label = UILabel() 50 | label.adjustsFontSizeToFitWidth = true 51 | label.numberOfLines = 0 52 | return label 53 | }() 54 | private let yAxisTitleLabel: UILabel = { 55 | let label = UILabel() 56 | label.adjustsFontSizeToFitWidth = true 57 | label.numberOfLines = 0 58 | return label 59 | }() 60 | private let margin: CGFloat = 8 61 | private let pointRadius: CGFloat = 5 62 | 63 | private var xLabels = [UILabel]() 64 | private var yLabels = [UILabel]() 65 | private var graphLayers = [CAShapeLayer]() 66 | private var horizontalLineLayers = [CALayer]() 67 | private var graphLayer = CALayer() 68 | private var yAxisPositionX: CGFloat { 69 | let sorted = yLabels.sorted { $0.frame.width > $1.frame.width } 70 | guard let maxWidthLabel = sorted.first else { 71 | return margin 72 | } 73 | return maxWidthLabel.frame.size.width + margin 74 | } 75 | private var xAxisPositionY: CGFloat { 76 | let sorted = xLabels.sorted { $0.frame.height > $1.frame.height } 77 | let margin = xAxisTitleLabel.frame.size.height > 0 ? self.margin * 2 : self.margin 78 | guard let maxHeightLabel = sorted.first else { 79 | return frame.size.height - margin - xAxisTitleLabel.frame.size.height - axisWidth 80 | } 81 | return frame.size.height - maxHeightLabel.frame.size.height - margin - xAxisTitleLabel.frame.size.height - axisWidth 82 | } 83 | private var xAxisWidth: CGFloat { 84 | let labelWidth = xLabels.last?.frame.size.width ?? 0 85 | return frame.size.width - yAxisPositionX - labelWidth/2 86 | } 87 | 88 | override public func initView() { 89 | addSubview(yAxisView) 90 | addSubview(yAxisTitleLabel) 91 | addSubview(xAxisView) 92 | addSubview(xAxisTitleLabel) 93 | layer.addSublayer(graphLayer) 94 | } 95 | 96 | // MARK:- Draw 97 | private func makeXAxisLabels() -> [UILabel] { 98 | let valueCount = (xAxisMaxValue - xAxisMinValue) / CGFloat(numberOfXAxisLabel - 1) 99 | var value = xAxisMinValue 100 | var labels = [UILabel]() 101 | for _ in 0.. [UILabel] { 114 | let valueCount = (yAxisMaxValue - yAxisMinValue) / CGFloat(numberOfYAxisLabel - 1) 115 | var value = yAxisMinValue 116 | var labels = [UILabel]() 117 | for _ in 0.. $1.frame.height }.first!.frame.size.height 150 | let y = yAxisTitleLabel.frame.size.height + margin + yLabelHeight/2 151 | yAxisView.frame = CGRect(x: yAxisPositionX, y: y, width: axisWidth, height: xAxisPositionY - y) 152 | xAxisView.frame = CGRect(x: yAxisView.frame.minX, y: xAxisPositionY, width: xAxisWidth, height: axisWidth) 153 | yAxisView.backgroundColor = axisColor 154 | xAxisView.backgroundColor = axisColor 155 | 156 | graphLayer.frame = CGRect(x: yAxisView.frame.maxX, 157 | y: yAxisView.frame.minY, 158 | width: xAxisView.frame.width - axisWidth, 159 | height: yAxisView.frame.height) 160 | } 161 | 162 | private func prepareYLabels() { 163 | let space = (yAxisView.frame.height / CGFloat(numberOfYAxisLabel - 1)) 164 | var y = xAxisView.frame.origin.y 165 | yLabels.forEach { 166 | let width = $0.frame.size.width 167 | let height = $0.frame.size.height 168 | $0.frame = CGRect(x: yAxisView.frame.origin.x - width - margin, y: y - height/2, width: width, height: height) 169 | y -= space 170 | addSubview($0) 171 | } 172 | } 173 | 174 | private func prepareXLabels() { 175 | let space = (xAxisWidth / CGFloat(numberOfXAxisLabel - 1)) 176 | var x = xAxisView.frame.origin.x 177 | xLabels.forEach { 178 | let width = $0.frame.size.width 179 | let height = $0.frame.size.height 180 | $0.frame = CGRect(x: x - width/2, y: xAxisView.frame.origin.y + axisWidth + margin, width: width, height: height) 181 | x += space 182 | addSubview($0) 183 | } 184 | } 185 | 186 | private func prepareGraphLineLayers(positionY: CGFloat) { 187 | let lineLayer = CALayer() 188 | lineLayer.frame = CGRect(x: xAxisView.frame.minX, y: positionY, 189 | width: xAxisView.frame.width, height: 1) 190 | lineLayer.backgroundColor = UIColor.black.cgColor 191 | layer.addSublayer(lineLayer) 192 | horizontalLineLayers.append(lineLayer) 193 | } 194 | 195 | private func prepareGraphLayers(sections: Int) { 196 | while graphLayers.count < sections { 197 | let layer = CAShapeLayer() 198 | graphLayer.addSublayer(layer) 199 | graphLayers.append(layer) 200 | } 201 | 202 | while graphLayers.count > sections { 203 | let layer = graphLayers.last 204 | layer?.removeFromSuperlayer() 205 | graphLayers.removeLast() 206 | } 207 | 208 | graphLayers.forEach { $0.frame = graphLayer.bounds } 209 | } 210 | 211 | private func setGraphLayerColor(_ graphLayer: CAShapeLayer, color: UIColor, pointType: AMPointType) { 212 | graphLayer.strokeColor = color.cgColor 213 | if pointType.isFilled { 214 | graphLayer.fillColor = color.cgColor 215 | } else { 216 | graphLayer.fillColor = UIColor.clear.cgColor 217 | } 218 | } 219 | 220 | private func makeAnimationPath(_ graphLayer: CAShapeLayer, values: [AMScatterValue], pointType: AMPointType) -> UIBezierPath { 221 | let path = UIBezierPath() 222 | for value in values { 223 | var x = (value.xValue / (xAxisMaxValue - xAxisMinValue)) * graphLayer.frame.width - graphLayer.frame.width * (xAxisMinValue / (xAxisMaxValue - xAxisMinValue)) 224 | var y = (graphLayer.frame.height + graphLayer.frame.height * (yAxisMinValue / (yAxisMaxValue - yAxisMinValue))) - ((value.yValue / (yAxisMaxValue - yAxisMinValue)) * graphLayer.frame.height) 225 | if y.isNaN { 226 | y = 0 227 | } 228 | if x.isNaN { 229 | x = 0 230 | } 231 | let point = CGPoint(x: x, y: y) 232 | path.append(makePointPath(center: point, pointType: pointType)) 233 | path.move(to: point) 234 | } 235 | return path 236 | } 237 | 238 | private func makePointPath(center: CGPoint, pointType: AMPointType) -> UIBezierPath { 239 | switch pointType { 240 | case .type1, .type2: 241 | return makeCirclePointPath(center: center) 242 | case .type3, .type4: 243 | return makeSquarePointPath(center: center) 244 | case .type5, .type6: 245 | return makeTrianglePointPath(center: center) 246 | case .type7, .type8: 247 | return makeDiamondPointPath(center: center) 248 | case .type9: 249 | return makeXPointPath(center: center) 250 | } 251 | } 252 | 253 | private func makeCirclePointPath(center: CGPoint) -> UIBezierPath { 254 | return .init(ovalIn: CGRect(x: center.x - pointRadius, y: center.y - pointRadius, 255 | width: pointRadius * 2, height: pointRadius * 2)) 256 | } 257 | 258 | private func makeSquarePointPath(center: CGPoint) -> UIBezierPath { 259 | return .init(rect: CGRect(x: center.x - pointRadius, y: center.y - pointRadius, 260 | width: pointRadius * 2, height: pointRadius * 2)) 261 | } 262 | 263 | private func makeTrianglePointPath(center: CGPoint) -> UIBezierPath { 264 | let path = UIBezierPath() 265 | path.move(to: CGPoint(x: center.x, y: center.y - pointRadius)) 266 | path.addLine(to: CGPoint(x: center.x + pointRadius, y: center.y + pointRadius)) 267 | path.addLine(to: CGPoint(x: center.x - pointRadius, y: center.y + pointRadius)) 268 | path.close() 269 | return path 270 | } 271 | 272 | private func makeDiamondPointPath(center: CGPoint) -> UIBezierPath { 273 | let path = UIBezierPath() 274 | path.move(to: CGPoint(x: center.x, y: center.y - pointRadius)) 275 | path.addLine(to: CGPoint(x: center.x + pointRadius, y: center.y)) 276 | path.addLine(to: CGPoint(x: center.x , y: center.y + pointRadius)) 277 | path.addLine(to: CGPoint(x: center.x - pointRadius, y: center.y)) 278 | path.close() 279 | return path 280 | } 281 | 282 | private func makeXPointPath(center: CGPoint) -> UIBezierPath { 283 | let path = UIBezierPath() 284 | path.move(to: CGPoint(x: center.x - pointRadius, y: center.y - pointRadius)) 285 | path.addLine(to: CGPoint(x: center.x + pointRadius, y: center.y + pointRadius)) 286 | path.move(to: CGPoint(x: center.x + pointRadius, y: center.y - pointRadius)) 287 | path.addLine(to: CGPoint(x: center.x - pointRadius, y: center.y + pointRadius)) 288 | return path 289 | } 290 | 291 | private func showAnimation() { 292 | for graphLayer in graphLayers { 293 | let animation = CABasicAnimation(keyPath: "strokeEnd") 294 | animation.duration = animationDuration 295 | animation.fromValue = 0 296 | animation.toValue = 1 297 | graphLayer.add(animation, forKey: nil) 298 | } 299 | } 300 | 301 | // MARK:- Reload 302 | override public func reloadData() { 303 | clearView() 304 | guard let dataSource = dataSource else { 305 | return 306 | } 307 | let sections = dataSource.numberOfSections(in: self) 308 | precondition(numberOfYAxisLabel > 1, "numberOfYAxisLabel is less than 2") 309 | precondition(numberOfXAxisLabel > 1, "numberOfXAxisLabel is less than 2") 310 | precondition(xAxisMinValue < xAxisMaxValue, "xAxisMaxValue is less than or eqaul to xAxisMinValue") 311 | precondition(yAxisMinValue < yAxisMaxValue, "yAxisMaxValue is less than or eqaul to yAxisMinValue") 312 | yLabels = makeYAxisLabels() 313 | xLabels = makeXAxisLabels() 314 | prepareXAxisTitleLabel() 315 | prepareYAxisTitleLabel() 316 | settingAxisViewFrame() 317 | prepareYLabels() 318 | prepareXLabels() 319 | if isHorizontalLine { 320 | yLabels.forEach { 321 | prepareGraphLineLayers(positionY: $0.center.y) 322 | } 323 | } 324 | prepareGraphLayers(sections:sections) 325 | for section in 0..