├── .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 | 
4 | 
5 | [](http://cocoapods.org/pods/AMChart)
6 | [](https://github.com/Carthage/Carthage)
7 | [](https://github.com/apple/swift-package-manager)
8 |
9 | ## Demo
10 |
11 | 
12 |
13 | ## Usage
14 | ### AMBarChartView
15 | 
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 | 
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 | 
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 | 
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 | 
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..