├── .DS_Store
├── img
├── pieImg_1.png
├── pieImg_2.png
├── pieImg_3.gif
├── lineImg_1.png
├── lineImg_2.png
├── lineImg_3.png
├── lineImg_4.png
├── lineImg_5.gif
├── columnImg_1.png
├── columnImg_2.png
├── columnImg_3.png
├── columnImg_4.png
└── columnImg_5.gif
├── GCChartDemo
├── .DS_Store
├── GCChartDemo
│ ├── .DS_Store
│ ├── Assets.xcassets
│ │ ├── Contents.json
│ │ └── AppIcon.appiconset
│ │ │ └── Contents.json
│ ├── ViewController.h
│ ├── AppDelegate.h
│ ├── LineChartViewController.h
│ ├── PieChartViewController.h
│ ├── ColumnChartViewController.h
│ ├── CircleRingChartViewController.h
│ ├── NegativeColumnChartViewController.h
│ ├── main.m
│ ├── Info.plist
│ ├── Base.lproj
│ │ ├── Main.storyboard
│ │ └── LaunchScreen.storyboard
│ ├── PieChartView
│ │ ├── CircleRingChartView.h
│ │ ├── PieChartView.h
│ │ ├── CircleRingChartView.m
│ │ └── PieChartView.m
│ ├── CircleRingChartViewController.m
│ ├── AppDelegate.m
│ ├── NegativeColumnChartViewController.m
│ ├── LineChartView
│ │ ├── LineChartView.h
│ │ └── LineChartView.m
│ ├── ColumnChartView
│ │ └── ColumnChartView.h
│ ├── ViewController.m
│ ├── ColumnChartViewController.m
│ ├── LineChartViewController.m
│ └── PieChartViewController.m
├── GCChartDemo.xcodeproj
│ ├── project.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ │ └── IDEWorkspaceChecks.plist
│ └── project.pbxproj
├── GCChartDemoTests
│ ├── Info.plist
│ └── GCChartDemoTests.m
└── GCChartDemoUITests
│ ├── Info.plist
│ └── GCChartDemoUITests.m
├── .gitignore
└── README.md
/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MichaelJackchuang/GCChart/HEAD/.DS_Store
--------------------------------------------------------------------------------
/img/pieImg_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MichaelJackchuang/GCChart/HEAD/img/pieImg_1.png
--------------------------------------------------------------------------------
/img/pieImg_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MichaelJackchuang/GCChart/HEAD/img/pieImg_2.png
--------------------------------------------------------------------------------
/img/pieImg_3.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MichaelJackchuang/GCChart/HEAD/img/pieImg_3.gif
--------------------------------------------------------------------------------
/img/lineImg_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MichaelJackchuang/GCChart/HEAD/img/lineImg_1.png
--------------------------------------------------------------------------------
/img/lineImg_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MichaelJackchuang/GCChart/HEAD/img/lineImg_2.png
--------------------------------------------------------------------------------
/img/lineImg_3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MichaelJackchuang/GCChart/HEAD/img/lineImg_3.png
--------------------------------------------------------------------------------
/img/lineImg_4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MichaelJackchuang/GCChart/HEAD/img/lineImg_4.png
--------------------------------------------------------------------------------
/img/lineImg_5.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MichaelJackchuang/GCChart/HEAD/img/lineImg_5.gif
--------------------------------------------------------------------------------
/GCChartDemo/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MichaelJackchuang/GCChart/HEAD/GCChartDemo/.DS_Store
--------------------------------------------------------------------------------
/img/columnImg_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MichaelJackchuang/GCChart/HEAD/img/columnImg_1.png
--------------------------------------------------------------------------------
/img/columnImg_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MichaelJackchuang/GCChart/HEAD/img/columnImg_2.png
--------------------------------------------------------------------------------
/img/columnImg_3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MichaelJackchuang/GCChart/HEAD/img/columnImg_3.png
--------------------------------------------------------------------------------
/img/columnImg_4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MichaelJackchuang/GCChart/HEAD/img/columnImg_4.png
--------------------------------------------------------------------------------
/img/columnImg_5.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MichaelJackchuang/GCChart/HEAD/img/columnImg_5.gif
--------------------------------------------------------------------------------
/GCChartDemo/GCChartDemo/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MichaelJackchuang/GCChart/HEAD/GCChartDemo/GCChartDemo/.DS_Store
--------------------------------------------------------------------------------
/GCChartDemo/GCChartDemo/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/GCChartDemo/GCChartDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/GCChartDemo/GCChartDemo/ViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.h
3 | // GCChartDemo
4 | //
5 | // Created by 古创 on 2019/5/13.
6 | // Copyright © 2019年 GC. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface ViewController : UIViewController
12 |
13 |
14 | @end
15 |
16 |
--------------------------------------------------------------------------------
/GCChartDemo/GCChartDemo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/GCChartDemo/GCChartDemo/AppDelegate.h:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.h
3 | // GCChartDemo
4 | //
5 | // Created by 古创 on 2019/5/13.
6 | // Copyright © 2019年 GC. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface AppDelegate : UIResponder
12 |
13 | @property (strong, nonatomic) UIWindow *window;
14 |
15 |
16 | @end
17 |
18 |
--------------------------------------------------------------------------------
/GCChartDemo/GCChartDemo/LineChartViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // LineChartViewController.h
3 | // LineChartTest
4 | //
5 | // Created by 古创 on 2019/5/13.
6 | // Copyright © 2019年 GC. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | NS_ASSUME_NONNULL_BEGIN
12 |
13 | @interface LineChartViewController : UIViewController
14 |
15 | @end
16 |
17 | NS_ASSUME_NONNULL_END
18 |
--------------------------------------------------------------------------------
/GCChartDemo/GCChartDemo/PieChartViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // PieChartViewController.h
3 | // PieChartTest
4 | //
5 | // Created by 古创 on 2019/5/8.
6 | // Copyright © 2019年 chuang. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | NS_ASSUME_NONNULL_BEGIN
12 |
13 | @interface PieChartViewController : UIViewController
14 |
15 | @end
16 |
17 | NS_ASSUME_NONNULL_END
18 |
--------------------------------------------------------------------------------
/GCChartDemo/GCChartDemo/ColumnChartViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // ColumnChartViewController.h
3 | // ColumnChartTest
4 | //
5 | // Created by 古创 on 2019/5/10.
6 | // Copyright © 2019年 chuang. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | NS_ASSUME_NONNULL_BEGIN
12 |
13 | @interface ColumnChartViewController : UIViewController
14 |
15 | @end
16 |
17 | NS_ASSUME_NONNULL_END
18 |
--------------------------------------------------------------------------------
/GCChartDemo/GCChartDemo/CircleRingChartViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // CircleRingChartViewController.h
3 | // GCChartDemo
4 | //
5 | // Created by 古创 on 2019/6/5.
6 | // Copyright © 2019年 GC. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | NS_ASSUME_NONNULL_BEGIN
12 |
13 | @interface CircleRingChartViewController : UIViewController
14 |
15 | @end
16 |
17 | NS_ASSUME_NONNULL_END
18 |
--------------------------------------------------------------------------------
/GCChartDemo/GCChartDemo/NegativeColumnChartViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // NegativeColumnChartViewController.h
3 | // GCChartDemo
4 | //
5 | // Created by 古创 on 2019/7/1.
6 | // Copyright © 2019年 GC. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | NS_ASSUME_NONNULL_BEGIN
12 |
13 | @interface NegativeColumnChartViewController : UIViewController
14 |
15 | @end
16 |
17 | NS_ASSUME_NONNULL_END
18 |
--------------------------------------------------------------------------------
/GCChartDemo/GCChartDemo/main.m:
--------------------------------------------------------------------------------
1 | //
2 | // main.m
3 | // GCChartDemo
4 | //
5 | // Created by 古创 on 2019/5/13.
6 | // Copyright © 2019年 GC. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "AppDelegate.h"
11 |
12 | int main(int argc, char * argv[]) {
13 | @autoreleasepool {
14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/GCChartDemo/GCChartDemoTests/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 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 |
22 |
23 |
--------------------------------------------------------------------------------
/GCChartDemo/GCChartDemoUITests/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 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 |
22 |
23 |
--------------------------------------------------------------------------------
/GCChartDemo/GCChartDemoTests/GCChartDemoTests.m:
--------------------------------------------------------------------------------
1 | //
2 | // GCChartDemoTests.m
3 | // GCChartDemoTests
4 | //
5 | // Created by 古创 on 2019/5/13.
6 | // Copyright © 2019年 GC. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface GCChartDemoTests : XCTestCase
12 |
13 | @end
14 |
15 | @implementation GCChartDemoTests
16 |
17 | - (void)setUp {
18 | // Put setup code here. This method is called before the invocation of each test method in the class.
19 | }
20 |
21 | - (void)tearDown {
22 | // Put teardown code here. This method is called after the invocation of each test method in the class.
23 | }
24 |
25 | - (void)testExample {
26 | // This is an example of a functional test case.
27 | // Use XCTAssert and related functions to verify your tests produce the correct results.
28 | }
29 |
30 | - (void)testPerformanceExample {
31 | // This is an example of a performance test case.
32 | [self measureBlock:^{
33 | // Put the code you want to measure the time of here.
34 | }];
35 | }
36 |
37 | @end
38 |
--------------------------------------------------------------------------------
/GCChartDemo/GCChartDemoUITests/GCChartDemoUITests.m:
--------------------------------------------------------------------------------
1 | //
2 | // GCChartDemoUITests.m
3 | // GCChartDemoUITests
4 | //
5 | // Created by 古创 on 2019/5/13.
6 | // Copyright © 2019年 GC. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface GCChartDemoUITests : XCTestCase
12 |
13 | @end
14 |
15 | @implementation GCChartDemoUITests
16 |
17 | - (void)setUp {
18 | // Put setup code here. This method is called before the invocation of each test method in the class.
19 |
20 | // In UI tests it is usually best to stop immediately when a failure occurs.
21 | self.continueAfterFailure = NO;
22 |
23 | // UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method.
24 | [[[XCUIApplication alloc] init] launch];
25 |
26 | // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this.
27 | }
28 |
29 | - (void)tearDown {
30 | // Put teardown code here. This method is called after the invocation of each test method in the class.
31 | }
32 |
33 | - (void)testExample {
34 | // Use recording to get started writing UI tests.
35 | // Use XCTAssert and related functions to verify your tests produce the correct results.
36 | }
37 |
38 | @end
39 |
--------------------------------------------------------------------------------
/GCChartDemo/GCChartDemo/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 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Xcode
2 | #
3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
4 |
5 | ## Build generated
6 | build/
7 | DerivedData/
8 |
9 | ## Various settings
10 | *.pbxuser
11 | !default.pbxuser
12 | *.mode1v3
13 | !default.mode1v3
14 | *.mode2v3
15 | !default.mode2v3
16 | *.perspectivev3
17 | !default.perspectivev3
18 | xcuserdata/
19 |
20 | ## Other
21 | *.moved-aside
22 | *.xccheckout
23 | *.xcscmblueprint
24 |
25 | ## Obj-C/Swift specific
26 | *.hmap
27 | *.ipa
28 | *.dSYM.zip
29 | *.dSYM
30 |
31 | # CocoaPods
32 | #
33 | # We recommend against adding the Pods directory to your .gitignore. However
34 | # you should judge for yourself, the pros and cons are mentioned at:
35 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
36 | #
37 | # Pods/
38 |
39 | # Carthage
40 | #
41 | # Add this line if you want to avoid checking in source code from Carthage dependencies.
42 | # Carthage/Checkouts
43 |
44 | Carthage/Build
45 |
46 | # fastlane
47 | #
48 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
49 | # screenshots whenever they are needed.
50 | # For more information about the recommended setup visit:
51 | # https://docs.fastlane.tools/best-practices/source-control/#source-control
52 |
53 | fastlane/report.xml
54 | fastlane/Preview.html
55 | fastlane/screenshots/**/*.png
56 | fastlane/test_output
57 |
58 | # Code Injection
59 | #
60 | # After new code Injection tools there's a generated folder /iOSInjectionProject
61 | # https://github.com/johnno1962/injectionforxcode
62 |
63 | iOSInjectionProject/
64 |
--------------------------------------------------------------------------------
/GCChartDemo/GCChartDemo/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 |
--------------------------------------------------------------------------------
/GCChartDemo/GCChartDemo/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 |
--------------------------------------------------------------------------------
/GCChartDemo/GCChartDemo/PieChartView/CircleRingChartView.h:
--------------------------------------------------------------------------------
1 | //
2 | // CircleRingChartView.h
3 | // GCChartDemo
4 | //
5 | // Created by 古创 on 2019/6/5.
6 | // Copyright © 2019年 GC. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | NS_ASSUME_NONNULL_BEGIN
12 |
13 | // 图例位置
14 | typedef NS_ENUM(NSInteger, LegendPosition) {
15 | LegendPositionNone = 0,// 无
16 | LegendPositionTop,// 上
17 | LegendPositionBottom,// 下
18 | };
19 |
20 | @interface CircleRingChartView : UIView
21 |
22 | /**
23 | 图例位置
24 | */
25 | @property (nonatomic,assign) LegendPosition legendPostion;
26 |
27 | /**
28 | 分组名称数组(图例名称)
29 | */
30 | @property (nonatomic,strong) NSArray *legendNameArray;
31 |
32 | /**
33 | 扇形颜色数组(传入十六进制颜色字符串)
34 | */
35 | @property (nonatomic,strong) NSArray *legendColorArray;
36 |
37 | /**
38 | 数据数组
39 | */
40 | @property (nonatomic,strong) NSArray *pieDataArray;
41 |
42 | /**
43 | 圆环半径
44 | */
45 | @property (nonatomic,assign) CGFloat radius;
46 |
47 | /**
48 | 圆环线宽
49 | */
50 | @property (nonatomic,assign) CGFloat lineWidth;
51 |
52 | /**
53 | 数据标签数组
54 | */
55 | @property (nonatomic,strong) NSArray *pieDataNameArray;
56 |
57 | /**
58 | 数据标注单位
59 | */
60 | @property (nonatomic,copy) NSString *pieDataUnit;
61 |
62 | /**
63 | 是否显示百分比
64 | */
65 | @property (nonatomic,assign) BOOL showPercentage;
66 |
67 | /**
68 | 是否允许点击
69 | */
70 | @property (nonatomic,assign) BOOL touchEnable;
71 |
72 | /**
73 | 中心标题
74 | */
75 | @property (nonatomic,copy) NSString *centerTitle;
76 |
77 | /**
78 | 初始化圆环
79 |
80 | @param frame frame
81 | @param legendPostion 图例位置
82 | @param nameArray 图例名称数组
83 | @param dataArray 数据数组
84 | @param radius 圆环半径
85 | @param lineWidth 圆环线宽
86 | */
87 | - (instancetype)initWithFrame:(CGRect)frame atPostiion:(LegendPosition)legendPostion withNameArray:(NSArray *)nameArray andDataArray:(NSArray *)dataArray andRadius:(CGFloat)radius andLineWidth:(CGFloat)lineWidth;
88 |
89 | /**
90 | 重设数据(更新数据后重新设置饼图)
91 | */
92 | - (void)resetData;
93 |
94 | @end
95 |
96 | NS_ASSUME_NONNULL_END
97 |
--------------------------------------------------------------------------------
/GCChartDemo/GCChartDemo/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "20x20",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "20x20",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "29x29",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "29x29",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "40x40",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "40x40",
31 | "scale" : "3x"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "size" : "60x60",
36 | "scale" : "2x"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "size" : "60x60",
41 | "scale" : "3x"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "size" : "20x20",
46 | "scale" : "1x"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "size" : "20x20",
51 | "scale" : "2x"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "size" : "29x29",
56 | "scale" : "1x"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "size" : "29x29",
61 | "scale" : "2x"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "size" : "40x40",
66 | "scale" : "1x"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "size" : "40x40",
71 | "scale" : "2x"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "size" : "76x76",
76 | "scale" : "1x"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "size" : "76x76",
81 | "scale" : "2x"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "size" : "83.5x83.5",
86 | "scale" : "2x"
87 | },
88 | {
89 | "idiom" : "ios-marketing",
90 | "size" : "1024x1024",
91 | "scale" : "1x"
92 | }
93 | ],
94 | "info" : {
95 | "version" : 1,
96 | "author" : "xcode"
97 | }
98 | }
--------------------------------------------------------------------------------
/GCChartDemo/GCChartDemo/CircleRingChartViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // CircleRingChartViewController.m
3 | // GCChartDemo
4 | //
5 | // Created by 古创 on 2019/6/5.
6 | // Copyright © 2019年 GC. All rights reserved.
7 | //
8 |
9 | #import "CircleRingChartViewController.h"
10 | #import "CircleRingChartView.h"
11 |
12 | @interface CircleRingChartViewController ()
13 |
14 | @property (nonatomic,strong) CircleRingChartView *circleRingChartView;
15 | @property (nonatomic,assign) BOOL isBtnClicked;
16 |
17 | @end
18 |
19 | @implementation CircleRingChartViewController
20 |
21 | - (void)viewDidLoad {
22 | [super viewDidLoad];
23 | self.view.backgroundColor = [UIColor redColor];
24 |
25 | self.circleRingChartView = [[CircleRingChartView alloc] initWithFrame:CGRectMake(0, 100, self.view.frame.size.width, 200) atPostiion:LegendPositionTop withNameArray:@[@"一工区",@"二工区",@"三工区"] andDataArray:@[@"100",@"100",@"100"] andRadius:60 andLineWidth:20];
26 | self.circleRingChartView.backgroundColor = [UIColor whiteColor];
27 | self.circleRingChartView.showPercentage = NO;
28 | self.circleRingChartView.touchEnable = YES;
29 | self.circleRingChartView.centerTitle = @"产值";
30 | [self.view addSubview:self.circleRingChartView];
31 | [self.circleRingChartView resetData];
32 |
33 | UIButton *btn1 = [[UIButton alloc] initWithFrame:CGRectMake(100, 300, 80, 21)];
34 | btn1.backgroundColor = [UIColor cyanColor];
35 | [btn1 setTitle:@"重设数据" forState:UIControlStateNormal];
36 | [btn1 setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
37 | btn1.titleLabel.font = [UIFont systemFontOfSize:16];
38 | [self.view addSubview:btn1];
39 | [btn1 addTarget:self action:@selector(btnAction1) forControlEvents:UIControlEventTouchUpInside];
40 |
41 | }
42 |
43 | - (void)btnAction1 {
44 | if (!self.isBtnClicked) {
45 | self.circleRingChartView.pieDataArray = @[@"100",@"200",@"300"];
46 | self.circleRingChartView.showPercentage = YES;
47 | } else {
48 | self.circleRingChartView.pieDataArray = @[@"100",@"100",@"100"];
49 | self.circleRingChartView.showPercentage = NO;
50 | }
51 | [self.circleRingChartView resetData];
52 | self.isBtnClicked = !self.isBtnClicked;
53 | }
54 |
55 |
56 |
57 | @end
58 |
--------------------------------------------------------------------------------
/GCChartDemo/GCChartDemo/PieChartView/PieChartView.h:
--------------------------------------------------------------------------------
1 | //
2 | // PieChartView.h
3 | // PieChartTest
4 | //
5 | // Created by 古创 on 2019/5/7.
6 | // Copyright © 2019年 chuang. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | NS_ASSUME_NONNULL_BEGIN
12 |
13 | // 图例位置
14 | typedef NS_ENUM(NSInteger, LegendPosition) {
15 | LegendPositionNone = 0,// 无
16 | LegendPositionTop,// 上
17 | LegendPositionBottom,// 下
18 | };
19 |
20 | @interface PieChartView : UIView
21 |
22 | /**
23 | 图例位置
24 | */
25 | @property (nonatomic,assign) LegendPosition legendPostion;
26 |
27 | /**
28 | 分组名称数组(图例名称)
29 | */
30 | @property (nonatomic,strong) NSArray *legendNameArray;
31 |
32 | /**
33 | 扇形颜色数组(传入十六进制颜色字符串)
34 | */
35 | @property (nonatomic,strong) NSArray *legendColorArray;
36 |
37 | /**
38 | 是否为双层饼图
39 | */
40 | @property (nonatomic,assign) BOOL isDoubleCircle;
41 |
42 | /**
43 | 数据数组,单层饼图的时候使用这个数组
44 | */
45 | @property (nonatomic,strong) NSArray *pieDataArray;
46 |
47 | /**
48 | 内层数据数组,双层饼图的时候使用这个数组
49 | */
50 | @property (nonatomic,strong) NSArray *pieInsideDataArray;
51 |
52 | /**
53 | 外层数据数组,双层饼图的时候使用这个数组
54 | */
55 | @property (nonatomic,strong) NSArray *pieOutsideDataArray;
56 |
57 | /**
58 | 单层圆环半径 或双层圆环外层半径
59 | */
60 | @property (nonatomic,assign) CGFloat radius;
61 |
62 | /**
63 | 数据标签数组
64 | */
65 | @property (nonatomic,strong) NSArray *pieDataNameArray;
66 |
67 | /**
68 | 数据标注单位
69 | */
70 | @property (nonatomic,copy) NSString *pieDataUnit;
71 |
72 | /**
73 | 是否显示百分比
74 | */
75 | @property (nonatomic,assign) BOOL showPercentage;
76 |
77 | /**
78 | 初始化单层饼图
79 |
80 | @param frame frame
81 | @param legendPostion 图例位置
82 | @param nameArray 图例名称数组
83 | @param dataArray 数据数组
84 | */
85 | - (instancetype)initWithFrame:(CGRect)frame atPostiion:(LegendPosition)legendPostion withNameArray:(NSArray *)nameArray andDataArray:(NSArray *)dataArray;
86 |
87 | /**
88 | 初始化内外圈两层饼图
89 |
90 | @param frame frame
91 | @param legendPostion 图例位置
92 | @param nameArray 图例名称数组
93 | @param insideArray 内圈数据数组
94 | @param outsideArray 外圈数据数组
95 | */
96 | - (instancetype)initWithFrame:(CGRect)frame atPostiion:(LegendPosition)legendPostion withNameArray:(NSArray *)nameArray andInsideDataArray:(NSArray *)insideArray andOutsideDataArray:(NSArray *)outsideArray;
97 |
98 | /**
99 | 重设数据(更新数据后重新设置饼图)
100 | */
101 | - (void)resetData;
102 |
103 | @end
104 |
105 | NS_ASSUME_NONNULL_END
106 |
--------------------------------------------------------------------------------
/GCChartDemo/GCChartDemo/AppDelegate.m:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.m
3 | // GCChartDemo
4 | //
5 | // Created by 古创 on 2019/5/13.
6 | // Copyright © 2019年 GC. All rights reserved.
7 | //
8 |
9 | #import "AppDelegate.h"
10 | #import "ViewController.h"
11 |
12 | @interface AppDelegate ()
13 |
14 | @end
15 |
16 | @implementation AppDelegate
17 |
18 |
19 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
20 | self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
21 | ViewController *vc = [[ViewController alloc] init];
22 | UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:vc];
23 | self.window.rootViewController = nav;
24 | [self.window makeKeyAndVisible];
25 | return YES;
26 | }
27 |
28 |
29 | - (void)applicationWillResignActive:(UIApplication *)application {
30 | // 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.
31 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
32 | }
33 |
34 |
35 | - (void)applicationDidEnterBackground:(UIApplication *)application {
36 | // 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.
37 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
38 | }
39 |
40 |
41 | - (void)applicationWillEnterForeground:(UIApplication *)application {
42 | // 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.
43 | }
44 |
45 |
46 | - (void)applicationDidBecomeActive:(UIApplication *)application {
47 | // 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.
48 | }
49 |
50 |
51 | - (void)applicationWillTerminate:(UIApplication *)application {
52 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
53 | }
54 |
55 |
56 | @end
57 |
--------------------------------------------------------------------------------
/GCChartDemo/GCChartDemo/NegativeColumnChartViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // NegativeColumnChartViewController.m
3 | // GCChartDemo
4 | //
5 | // Created by 古创 on 2019/7/1.
6 | // Copyright © 2019年 GC. All rights reserved.
7 | //
8 |
9 | #import "NegativeColumnChartViewController.h"
10 | #import "ColumnChartView.h"
11 |
12 | @interface NegativeColumnChartViewController ()
13 |
14 | @property (nonatomic,strong) ColumnChartView *columnChartView;
15 |
16 | @property (nonatomic,assign) BOOL isBtnClicked;
17 |
18 | @end
19 |
20 | @implementation NegativeColumnChartViewController
21 |
22 | - (void)viewDidLoad {
23 | [super viewDidLoad];
24 | self.view.backgroundColor = [UIColor redColor];
25 |
26 | self.columnChartView = [[ColumnChartView alloc] initNegativeYAxisWithFrame:CGRectMake(0, 100, self.view.frame.size.width, 400) andDataNameArray:@[@"一工区",@"二工区",@"三工区",@"项目部",@"一大队",@"二中队",@"三小队"] andDataArray:@[@"121",@"-137",@"-215",@"258",@"-65",@"78",@"47"] andColumnColor:@"#fbca58"];
27 | self.columnChartView.scrollEnabled = YES;
28 | self.columnChartView.backgroundColor = [UIColor whiteColor];
29 | self.columnChartView.didHaveNegativeYAxis = YES;// 带负y轴
30 | self.columnChartView.showDataHorizontalLine = YES;
31 | self.columnChartView.showDataLabel = YES;
32 | self.columnChartView.isColumnGradientColor = YES;
33 | self.columnChartView.columnGradientColorArray = @[@"#2c8efa",@"#42cbfe"];
34 | [self.view addSubview:self.columnChartView];
35 | [self.columnChartView resetData];
36 |
37 | UIButton *btn1 = [[UIButton alloc] initWithFrame:CGRectMake(100, 550, 80, 40)];
38 | btn1.backgroundColor = [UIColor cyanColor];
39 | [btn1 setTitle:@"重设数据" forState:UIControlStateNormal];
40 | [btn1 setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
41 | btn1.titleLabel.font = [UIFont systemFontOfSize:16];
42 | [self.view addSubview:btn1];
43 | [btn1 addTarget:self action:@selector(btnAction1) forControlEvents:UIControlEventTouchUpInside];
44 | }
45 |
46 | - (void)btnAction1 {
47 | if (!self.isBtnClicked) {
48 | self.columnChartView.columnGradientColorArray = @[@"#f6457d",@"#f88d5c"];
49 | self.columnChartView.dataArray = @[@"121",@"-337",@"115",@"58",@"365",@"-23",@"135"];
50 | } else {
51 | self.columnChartView.columnGradientColorArray = @[@"#2c8efa",@"#42cbfe"];
52 | self.columnChartView.dataArray = @[@"121",@"-137",@"-215",@"258",@"-65",@"78",@"47"];
53 | }
54 | [self.columnChartView resetData];
55 | self.isBtnClicked = !self.isBtnClicked;
56 | }
57 |
58 | @end
59 |
--------------------------------------------------------------------------------
/GCChartDemo/GCChartDemo/LineChartView/LineChartView.h:
--------------------------------------------------------------------------------
1 | //
2 | // LineChartView.h
3 | // LineChartTest
4 | //
5 | // Created by 古创 on 2019/5/13.
6 | // Copyright © 2019年 GC. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | NS_ASSUME_NONNULL_BEGIN
12 |
13 | // 图例位置
14 | typedef NS_ENUM(NSInteger, LegendPosition) {
15 | LegendPositionNone = 0,// 无
16 | LegendPositionTop,// 上
17 | LegendPositionBottom,// 下
18 | };
19 |
20 | @interface LineChartView : UIView
21 |
22 | /**
23 | 图例位置(单线折线图没有图例)
24 | */
25 | @property (nonatomic,assign) LegendPosition legendPostion;
26 |
27 | /**
28 | 图例名称数组
29 | */
30 | @property (nonatomic,strong) NSArray *legendNameArray;
31 |
32 | /**
33 | 图例颜色数组(传入十六进制颜色字符串)
34 | */
35 | @property (nonatomic,strong) NSArray *legendColorArray;
36 |
37 | /**
38 | 数据标签数组
39 | */
40 | @property (nonatomic,strong) NSArray *dataNameArray;
41 |
42 | /**
43 | 数据数组(暂时只有正整数)当不是单条折线时为二维数组,其中每个元素数组为一条折线的数据
44 | */
45 | @property (nonatomic,strong) NSArray *dataArray;
46 |
47 | /**
48 | y轴最大值,不设置这个值则自动查找数组中最大值
49 | */
50 | @property (nonatomic,copy) NSString *maxNum;
51 |
52 | /**
53 | y轴最小值,不设置这个值则自动查找数组中最小值
54 | */
55 | @property (nonatomic,copy) NSString *minNum;
56 |
57 | /**
58 | y轴刻度值,设置此数组则不自动计算y轴刻度值
59 | */
60 | @property (nonatomic,strong) NSArray *yAxisNums;
61 |
62 | /**
63 | x轴标题
64 | */
65 | @property (nonatomic,copy) NSString *xAxisTitle;
66 |
67 | /**
68 | y轴标题
69 | */
70 | @property (nonatomic,copy) NSString *yAxisTitle;
71 |
72 | /**
73 | 数据单位
74 | */
75 | @property (nonatomic,copy) NSString *dataUnit;
76 |
77 | /**
78 | 是否显示数据水平线
79 | */
80 | @property (nonatomic,assign) BOOL showDataHorizontalLine;
81 |
82 | /**
83 | 是否可以滚动 一般来说可以不用设置这个属性 当数据超过5组时可以滚动
84 | */
85 | @property (nonatomic,assign) BOOL scrollEnabled;
86 |
87 | /**
88 | 顶点是否显示具体数据
89 | */
90 | @property (nonatomic,assign) BOOL showDataLabel;
91 |
92 | /**
93 | 折线线宽(当设置线下面为颜色填充时此属性设置无效)
94 | */
95 | @property (nonatomic,assign) CGFloat lineWidth;
96 |
97 | /**
98 | 是否为平滑曲线
99 | */
100 | @property (nonatomic,assign) BOOL isSmooth;
101 |
102 | /**
103 | 是否为单条线
104 | */
105 | @property (nonatomic,assign) BOOL isSingleLine;
106 |
107 | /**
108 | 线条颜色
109 | */
110 | @property (nonatomic,copy) NSString *lineColor;
111 |
112 | /**
113 | 线条下部填充颜色
114 | */
115 | @property (nonatomic,copy) NSString *fillColor;
116 |
117 | /**
118 | 线条下部填充颜色透明度
119 | */
120 | @property (nonatomic,assign) CGFloat fillAlpha;
121 |
122 | /**
123 | 折线下部是否用颜色填充(仅单线条时此属性生效,且此属性设置为yes时线条颜色设置失效)
124 | */
125 | @property (nonatomic,assign) BOOL isFillWithColor;
126 |
127 | /**
128 | 初始化一个单线折线图
129 |
130 | @param frame frame
131 | @param dataNameArray 数据名称数组
132 | @param dataArray 数据数组
133 | @param colorString 线条颜色
134 | */
135 | - (instancetype)initWithFrame:(CGRect)frame andDataNameArray:(NSArray *)dataNameArray andDataArray:(NSArray *)dataArray andLineColor:(NSString *)colorString;
136 |
137 | /**
138 | 重设数据
139 | */
140 | - (void)resetData;
141 |
142 | @end
143 |
144 | NS_ASSUME_NONNULL_END
145 |
--------------------------------------------------------------------------------
/GCChartDemo/GCChartDemo/ColumnChartView/ColumnChartView.h:
--------------------------------------------------------------------------------
1 | //
2 | // ColumnChartView.h
3 | // ColumnChartTest
4 | //
5 | // Created by 古创 on 2019/5/10.
6 | // Copyright © 2019年 chuang. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | NS_ASSUME_NONNULL_BEGIN
12 |
13 | // 图例位置
14 | typedef NS_ENUM(NSInteger, LegendPosition) {
15 | LegendPositionNone = 0,// 无
16 | LegendPositionTop,// 上
17 | LegendPositionBottom,// 下
18 | };
19 |
20 | @interface ColumnChartView : UIView
21 |
22 | /**
23 | 图例位置
24 | */
25 | @property (nonatomic,assign) LegendPosition legendPostion;
26 |
27 | /**
28 | 分组名称数组(图例名称)
29 | */
30 | @property (nonatomic,strong) NSArray *legendNameArray;
31 |
32 | /**
33 | 数据标签数组
34 | */
35 | @property (nonatomic,strong) NSArray *dataNameArray;
36 |
37 | /**
38 | 数据数组(暂时只有正整数)(当不是单柱时这个数组是二维数组)
39 | */
40 | @property (nonatomic,strong) NSArray *dataArray;
41 |
42 | /**
43 | 柱体是否为渐变色
44 | */
45 | @property (nonatomic,assign) BOOL isColumnGradientColor;
46 |
47 | /**
48 | 图例颜色数组(传入十六进制颜色字符串),也可作为柱体颜色(柱体非渐变色时使用)
49 | */
50 | @property (nonatomic,strong) NSArray *legendColorArray;
51 |
52 | /**
53 | 柱体渐变色数组(当不是单柱时这个数组是二维数组)
54 | */
55 | @property (nonatomic,strong) NSArray *columnGradientColorArray;
56 |
57 | /**
58 | 单柱柱体颜色(非渐变色)
59 | */
60 | @property (nonatomic,copy) NSString *columnColor;
61 |
62 | /**
63 | x轴标题
64 | */
65 | @property (nonatomic,copy) NSString *xAxisTitle;
66 |
67 | /**
68 | y轴标题
69 | */
70 | @property (nonatomic,copy) NSString *yAxisTitle;
71 |
72 | /**
73 | 数据单位
74 | */
75 | @property (nonatomic,copy) NSString *dataUnit;
76 |
77 | /**
78 | 柱体宽度
79 | */
80 | @property (nonatomic,copy) NSString *columnWidth;
81 |
82 | /**
83 | 是否显示数据水平线
84 | */
85 | @property (nonatomic,assign) BOOL showDataHorizontalLine;
86 |
87 | /**
88 | 是否可以滚动
89 | */
90 | @property (nonatomic,assign) BOOL scrollEnabled;
91 |
92 | /**
93 | 是否为单柱(最多为4柱一组)
94 | */
95 | @property (nonatomic,assign) BOOL isSingleColumn;
96 |
97 | /**
98 | 是否有负y轴
99 | */
100 | @property (nonatomic,assign) BOOL didHaveNegativeYAxis;
101 |
102 | /**
103 | 每组柱体数量
104 | */
105 | @property (nonatomic,assign) int numberOfColumn;
106 |
107 | /**
108 | 柱顶是否显示具体数据
109 | */
110 | @property (nonatomic,assign) BOOL showDataLabel;
111 |
112 | /**
113 | 是否显示数据水平虚线
114 | */
115 | @property (nonatomic,assign) BOOL showHorizontalDashLine;
116 |
117 | /**
118 | 初始化一个单柱柱状图
119 |
120 | @param frame frame
121 | @param dataNameArray 数据名称数组
122 | @param dataArray 数据数组
123 | */
124 | - (instancetype)initWithFrame:(CGRect)frame andDataNameArray:(NSArray *)dataNameArray andDataArray:(NSArray *)dataArray andColumnColor:(NSString *)colorString;
125 |
126 | /**
127 | 初始化一个带负Y轴单柱柱状图
128 |
129 | @param frame frame
130 | @param dataNameArray 数据名称数组
131 | @param dataArray 数据数组
132 | */
133 | - (instancetype)initNegativeYAxisWithFrame:(CGRect)frame andDataNameArray:(NSArray *)dataNameArray andDataArray:(NSArray *)dataArray andColumnColor:(NSString *)colorString;
134 |
135 | /**
136 | 重设数据
137 | */
138 | - (void)resetData;
139 |
140 | @end
141 |
142 | NS_ASSUME_NONNULL_END
143 |
--------------------------------------------------------------------------------
/GCChartDemo/GCChartDemo/ViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.m
3 | // GCChartDemo
4 | //
5 | // Created by 古创 on 2019/5/13.
6 | // Copyright © 2019年 GC. All rights reserved.
7 | //
8 |
9 | #import "ViewController.h"
10 | #import "PieChartViewController.h"
11 | #import "ColumnChartViewController.h"
12 | #import "LineChartViewController.h"
13 | #import "CircleRingChartViewController.h"
14 | #import "NegativeColumnChartViewController.h"
15 |
16 | @interface ViewController ()
17 |
18 | @end
19 |
20 | @implementation ViewController
21 |
22 | - (void)viewDidLoad {
23 | [super viewDidLoad];
24 | self.view.backgroundColor = [UIColor whiteColor];
25 |
26 | UIButton *btn1 = [[UIButton alloc] initWithFrame:CGRectMake(70, 100, 50, 50)];
27 | btn1.backgroundColor = [UIColor redColor];
28 | [btn1 setTitle:@"扇形图" forState:UIControlStateNormal];
29 | [btn1 setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
30 | btn1.titleLabel.font = [UIFont systemFontOfSize:15];
31 | [self.view addSubview:btn1];
32 | [btn1 addTarget:self action:@selector(btnAction1) forControlEvents:UIControlEventTouchUpInside];
33 |
34 | UIButton *btn2 = [[UIButton alloc] initWithFrame:CGRectMake(170, 100, 50, 50)];
35 | btn2.backgroundColor = [UIColor redColor];
36 | [btn2 setTitle:@"柱状图" forState:UIControlStateNormal];
37 | [btn2 setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
38 | btn2.titleLabel.font = [UIFont systemFontOfSize:15];
39 | [self.view addSubview:btn2];
40 | [btn2 addTarget:self action:@selector(btnAction2) forControlEvents:UIControlEventTouchUpInside];
41 |
42 | UIButton *btn3 = [[UIButton alloc] initWithFrame:CGRectMake(270, 100, 50, 50)];
43 | btn3.backgroundColor = [UIColor redColor];
44 | [btn3 setTitle:@"折线图" forState:UIControlStateNormal];
45 | [btn3 setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
46 | btn3.titleLabel.font = [UIFont systemFontOfSize:15];
47 | [self.view addSubview:btn3];
48 | [btn3 addTarget:self action:@selector(btnAction3) forControlEvents:UIControlEventTouchUpInside];
49 |
50 | UIButton *btn4 = [[UIButton alloc] initWithFrame:CGRectMake(70, 200, 50, 50)];
51 | btn4.backgroundColor = [UIColor redColor];
52 | [btn4 setTitle:@"圆环图" forState:UIControlStateNormal];
53 | [btn4 setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
54 | btn4.titleLabel.font = [UIFont systemFontOfSize:15];
55 | [self.view addSubview:btn4];
56 | [btn4 addTarget:self action:@selector(btnAction4) forControlEvents:UIControlEventTouchUpInside];
57 |
58 | UIButton *btn5 = [[UIButton alloc] initWithFrame:CGRectMake(170, 200, 80, 50)];
59 | btn5.backgroundColor = [UIColor redColor];
60 | [btn5 setTitle:@"负轴柱状图" forState:UIControlStateNormal];
61 | [btn5 setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
62 | btn5.titleLabel.font = [UIFont systemFontOfSize:15];
63 | [self.view addSubview:btn5];
64 | [btn5 addTarget:self action:@selector(btnAction5) forControlEvents:UIControlEventTouchUpInside];
65 |
66 | }
67 |
68 | - (void)btnAction1 {
69 | PieChartViewController *pieChartVC = [[PieChartViewController alloc] init];
70 | [self.navigationController pushViewController:pieChartVC animated:YES];
71 | }
72 |
73 | - (void)btnAction2 {
74 | ColumnChartViewController *columnChartVC = [[ColumnChartViewController alloc] init];
75 | [self.navigationController pushViewController:columnChartVC animated:YES];
76 | }
77 |
78 | - (void)btnAction3 {
79 | LineChartViewController *columnChartVC = [[LineChartViewController alloc] init];
80 | [self.navigationController pushViewController:columnChartVC animated:YES];
81 | }
82 |
83 | - (void)btnAction4 {
84 | CircleRingChartViewController *columnChartVC = [[CircleRingChartViewController alloc] init];
85 | [self.navigationController pushViewController:columnChartVC animated:YES];
86 | }
87 |
88 | - (void)btnAction5 {
89 | NegativeColumnChartViewController *columnChartVC = [[NegativeColumnChartViewController alloc] init];
90 | [self.navigationController pushViewController:columnChartVC animated:YES];
91 | }
92 |
93 |
94 | @end
95 |
--------------------------------------------------------------------------------
/GCChartDemo/GCChartDemo/ColumnChartViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // ColumnChartViewController.m
3 | // ColumnChartTest
4 | //
5 | // Created by 古创 on 2019/5/10.
6 | // Copyright © 2019年 chuang. All rights reserved.
7 | //
8 |
9 | #import "ColumnChartViewController.h"
10 | #import "ColumnChartView.h"
11 |
12 | @interface ColumnChartViewController ()
13 |
14 | @property (nonatomic,strong) ColumnChartView *columnChartView;
15 | @property (nonatomic,strong) ColumnChartView *columnChartView2;
16 | @property (nonatomic,assign) BOOL isBtnClicked;
17 |
18 | @end
19 |
20 | @implementation ColumnChartViewController
21 |
22 | - (void)viewDidLoad {
23 | [super viewDidLoad];
24 | self.view.backgroundColor = [UIColor redColor];
25 |
26 | self.columnChartView = [[ColumnChartView alloc] initWithFrame:CGRectMake(0, 100, self.view.frame.size.width, 200) andDataNameArray:@[@"一工区",@"二工区",@"三工区",@"项目部",@"一大队",@"二中队",@"三小队"] andDataArray:@[@"121",@"137",@"215",@"258",@"65",@"78",@"47"] andColumnColor:@"#fbca58"];
27 | self.columnChartView.isSingleColumn = YES;
28 | self.columnChartView.scrollEnabled = YES;
29 | self.columnChartView.backgroundColor = [UIColor whiteColor];
30 | self.columnChartView.isColumnGradientColor = YES;
31 | self.columnChartView.columnGradientColorArray = @[@"#2c8efa",@"#42cbfe"];
32 | [self.view addSubview:self.columnChartView];
33 | self.columnChartView.showDataLabel = YES;
34 | self.columnChartView.showDataHorizontalLine = YES;
35 | [self.columnChartView resetData];
36 |
37 | UIButton *btn1 = [[UIButton alloc] initWithFrame:CGRectMake(100, 300, 80, 21)];
38 | btn1.backgroundColor = [UIColor cyanColor];
39 | [btn1 setTitle:@"重设数据" forState:UIControlStateNormal];
40 | [btn1 setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
41 | btn1.titleLabel.font = [UIFont systemFontOfSize:16];
42 | [self.view addSubview:btn1];
43 | [btn1 addTarget:self action:@selector(btnAction1) forControlEvents:UIControlEventTouchUpInside];
44 |
45 | self.columnChartView2 = [[ColumnChartView alloc] initWithFrame:CGRectMake(0, 321, self.view.frame.size.width, 200)];
46 | [self.view addSubview:self.columnChartView2];
47 | self.columnChartView2.backgroundColor = [UIColor whiteColor];
48 | self.columnChartView2.isSingleColumn = NO;
49 | self.columnChartView2.scrollEnabled = YES;
50 | self.columnChartView2.isColumnGradientColor = YES;
51 | // self.columnChartView2.columnColor = @"#fbca58";
52 | self.columnChartView2.legendPostion = LegendPositionTop;
53 | self.columnChartView2.legendNameArray = @[@"收入金额",@"支出金额"];
54 | // self.columnChartView2.legendColorArray = @[@"#f88d5c",@"#42cbfe"];
55 | self.columnChartView2.columnGradientColorArray = @[@[@"#2c8efa",@"#42cbfe"],@[@"#f6457d",@"#f88d5c"],@[@"#00cd00",@"#00ff00"],@[@"#ffd700",@"#ffff00"]];//@[@[@"#2c8efa",@"#42cbfe"],@[@"#f6457d",@"#f88d5c"]];
56 | self.columnChartView2.dataNameArray = @[@"一工区",@"二工区",@"三工区",@"项目部",@"一大队",@"二中队",@"三小队"];
57 | self.columnChartView2.numberOfColumn = 2;
58 | self.columnChartView2.dataArray = @[@[@"121",@"121"],@[@"137",@"337"],@[@"215",@"115"],@[@"258",@"58"],@[@"65",@"365"],@[@"78",@"23"],@[@"47",@"135"]];
59 | self.columnChartView2.showDataLabel = YES;
60 | self.columnChartView2.showDataHorizontalLine = YES;
61 | [self.columnChartView2 resetData];
62 | }
63 |
64 | - (void)btnAction1 {
65 | if (!self.isBtnClicked) {
66 | self.columnChartView.columnGradientColorArray = @[@"#f6457d",@"#f88d5c"];
67 | self.columnChartView.dataArray = @[@"121",@"337",@"115",@"58",@"365",@"23",@"135"];
68 | self.columnChartView2.dataArray = @[@[@"121",@"121",@"221"],@[@"137",@"337",@"21"],@[@"215",@"115",@"150"],@[@"258",@"58",@"180"],@[@"65",@"365",@"89"],@[@"78",@"23",@"399"],@[@"47",@"135",@"100"]];
69 | self.columnChartView2.legendNameArray = @[@"收入金额",@"支出金额",@"乱写金额"];
70 | } else {
71 | self.columnChartView.columnGradientColorArray = @[@"#2c8efa",@"#42cbfe"];
72 | self.columnChartView.dataArray = @[@"121",@"137",@"215",@"258",@"65",@"78",@"47"];
73 | self.columnChartView2.dataArray = @[@[@"121",@"121"],@[@"137",@"337"],@[@"215",@"115"],@[@"258",@"58"],@[@"65",@"365"],@[@"78",@"23"],@[@"47",@"135"]];
74 | self.columnChartView2.legendNameArray = @[@"收入金额",@"支出金额"];
75 | }
76 | [self.columnChartView resetData];
77 | [self.columnChartView2 resetData];
78 | self.isBtnClicked = !self.isBtnClicked;
79 | }
80 |
81 |
82 |
83 | @end
84 |
--------------------------------------------------------------------------------
/GCChartDemo/GCChartDemo/LineChartViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // LineChartViewController.m
3 | // LineChartTest
4 | //
5 | // Created by 古创 on 2019/5/13.
6 | // Copyright © 2019年 GC. All rights reserved.
7 | //
8 |
9 | #import "LineChartViewController.h"
10 | #import "LineChartView.h"
11 |
12 | @interface LineChartViewController ()
13 |
14 | @property (nonatomic,strong) LineChartView *lineChartView;
15 | @property (nonatomic,strong) LineChartView *lineChartView2;
16 | @property (nonatomic,assign) BOOL isBtnClicked;
17 |
18 | @end
19 |
20 | @implementation LineChartViewController
21 |
22 | - (void)viewDidLoad {
23 | [super viewDidLoad];
24 | self.view.backgroundColor = [UIColor redColor];
25 |
26 | self.lineChartView = [[LineChartView alloc] initWithFrame:CGRectMake(0, 100, self.view.frame.size.width, 200) andDataNameArray:@[@"一工区",@"二工区",@"三工区",@"项目部",@"一大队",@"二中队",@"三小队"] andDataArray:@[@"121",@"137",@"215",@"258",@"65",@"78",@"47"] andLineColor:@"#404040"];
27 | [self.view addSubview:self.lineChartView];
28 | self.lineChartView.backgroundColor = [UIColor whiteColor];
29 | self.lineChartView.showDataHorizontalLine = YES;
30 | self.lineChartView.lineWidth = 1;
31 | // self.lineChartView.lineColor = @"#dcdcdc";
32 | self.lineChartView.isSmooth = NO;
33 | self.lineChartView.isFillWithColor = NO;
34 | self.lineChartView.showDataLabel = YES;
35 | [self.lineChartView resetData];
36 |
37 | UIButton *btn1 = [[UIButton alloc] initWithFrame:CGRectMake(100, 300, 80, 21)];
38 | btn1.backgroundColor = [UIColor cyanColor];
39 | [btn1 setTitle:@"重设数据" forState:UIControlStateNormal];
40 | [btn1 setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
41 | btn1.titleLabel.font = [UIFont systemFontOfSize:16];
42 | [self.view addSubview:btn1];
43 | [btn1 addTarget:self action:@selector(btnAction1) forControlEvents:UIControlEventTouchUpInside];
44 |
45 | self.lineChartView2 = [[LineChartView alloc] initWithFrame:CGRectMake(0, 321, self.view.frame.size.width, 200)];
46 | [self.view addSubview:self.lineChartView2];
47 | self.lineChartView2.backgroundColor = [UIColor whiteColor];
48 | self.lineChartView2.showDataHorizontalLine = YES;
49 | self.lineChartView2.lineWidth = 1;
50 | self.lineChartView2.isSmooth = NO;
51 | self.lineChartView2.isSingleLine = NO;
52 | self.lineChartView2.dataArray = @[@[@"121",@"137",@"215",@"258",@"65",@"78]",@"47"],@[@"150",@"167",@"168",@"120",@"100",@"20",@"179"],@[@"50",@"67",@"68",@"20",@"10",@"10",@"79"]];
53 | self.lineChartView2.dataNameArray = @[@"一工区",@"二工区",@"三工区",@"项目部",@"一大队",@"二中队",@"三小队"];
54 | self.lineChartView2.legendPostion = LegendPositionTop;
55 | self.lineChartView2.legendNameArray = @[@"收入",@"支出",@"总收支"];
56 | // self.lineChartView2.legendColorArray = @[@"#36d7a9",@"#898989",@"#dcdcdc"];
57 | self.lineChartView2.isSmooth = NO;
58 | self.lineChartView2.showDataLabel = NO;
59 | [self.lineChartView2 resetData];
60 |
61 | }
62 |
63 | - (void)btnAction1 {
64 | if (!self.isBtnClicked) {
65 | self.lineChartView.isSmooth = YES;
66 | self.lineChartView.isFillWithColor = YES;
67 | self.lineChartView.fillColor = @"#f9856c";
68 | self.lineChartView.fillAlpha = 0.3;
69 | // self.lineChartView.dataArray = @[@"78",@"44",@"99",@"321",@"248",@"100",@"41"];
70 | self.lineChartView2.dataArray = @[@[@"121",@"137",@"215",@"258",@"65",@"78]",@"47"],@[@"150",@"167",@"168",@"120",@"100",@"20",@"179"]];
71 | self.lineChartView2.legendNameArray = @[@"收入",@"支出"];
72 | self.lineChartView2.legendPostion = LegendPositionBottom;
73 | self.lineChartView2.isSmooth = YES;
74 | self.lineChartView2.showDataLabel = YES;
75 | } else {
76 | self.lineChartView.isSmooth = NO;
77 | self.lineChartView.isFillWithColor = NO;
78 | // self.lineChartView.dataArray = @[@"121",@"137",@"215",@"258",@"65",@"78",@"47"];
79 | self.lineChartView2.dataArray = @[@[@"121",@"137",@"215",@"258",@"65",@"78]",@"47"],@[@"150",@"167",@"168",@"120",@"100",@"20",@"179"],@[@"50",@"67",@"68",@"20",@"10",@"10",@"79"]];
80 | self.lineChartView2.legendNameArray = @[@"收入",@"支出",@"总收支"];
81 | self.lineChartView2.legendPostion = LegendPositionTop;
82 | self.lineChartView2.isSmooth = NO;
83 | self.lineChartView2.showDataLabel = NO;
84 | }
85 |
86 | [self.lineChartView resetData];
87 | [self.lineChartView2 resetData];
88 | self.isBtnClicked = !self.isBtnClicked;
89 | }
90 |
91 | @end
92 |
--------------------------------------------------------------------------------
/GCChartDemo/GCChartDemo/PieChartViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // PieChartViewController.m
3 | // PieChartTest
4 | //
5 | // Created by 古创 on 2019/5/8.
6 | // Copyright © 2019年 chuang. All rights reserved.
7 | //
8 |
9 | #import "PieChartViewController.h"
10 | #import "PieChartView.h"
11 |
12 | @interface PieChartViewController ()
13 |
14 | @property (nonatomic,strong) PieChartView *pieChartView;
15 | @property (nonatomic,strong) PieChartView *pieChartView2;
16 | @property (nonatomic,strong) PieChartView *pieChartView3;
17 | @property (nonatomic,strong) PieChartView *pieChartView4;
18 | @property (nonatomic,assign) BOOL isBtnClicked;
19 |
20 | @end
21 |
22 | @implementation PieChartViewController
23 |
24 | - (void)viewDidLoad {
25 | [super viewDidLoad];
26 |
27 | self.view.backgroundColor = [UIColor redColor];
28 |
29 |
30 | self.pieChartView = [[PieChartView alloc] initWithFrame:CGRectMake(0, 100, self.view.frame.size.width, 200) atPostiion:LegendPositionTop withNameArray:@[@"一工区",@"二工区",@"三工区"] andDataArray:@[@"100",@"100",@"100"]];
31 | self.pieChartView.pieDataUnit = @"元";
32 | // self.pieChartView.showPercentage = YES;
33 | // self.pieChartView = [[PieChartView alloc] initWithFrame:CGRectMake(0, 100, self.view.frame.size.width, 200)];
34 | self.pieChartView.backgroundColor = [UIColor whiteColor];
35 | // self.pieChartView.legendPostion = LegendPositionTop;
36 | // NSArray *arr = @[@"一工区",@"二工区",@"三工区"];
37 | // self.pieChartView.legendNameArray = arr;
38 | [self.view addSubview:self.pieChartView];
39 | [self.pieChartView resetData];
40 |
41 | UIButton *btn1 = [[UIButton alloc] initWithFrame:CGRectMake(100, 300, 80, 21)];
42 | btn1.backgroundColor = [UIColor cyanColor];
43 | [btn1 setTitle:@"重设数据" forState:UIControlStateNormal];
44 | [btn1 setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
45 | btn1.titleLabel.font = [UIFont systemFontOfSize:16];
46 | [self.view addSubview:btn1];
47 | [btn1 addTarget:self action:@selector(btnAction1) forControlEvents:UIControlEventTouchUpInside];
48 |
49 | self.pieChartView2 = [[PieChartView alloc] initWithFrame:CGRectMake(0, 321, self.view.frame.size.width, 200) atPostiion:LegendPositionBottom withNameArray:@[@"一工区",@"二工区",@"三工区"] andInsideDataArray:@[@"100",@"100",@"100"] andOutsideDataArray:@[@"100",@"100",@"100"]];
50 | self.pieChartView2.backgroundColor = [UIColor whiteColor];
51 | [self.view addSubview:self.pieChartView2];
52 | self.pieChartView2.pieDataNameArray = @[@"一小队",@"二小队",@"三小队"];
53 | self.pieChartView2.pieDataUnit = @"元";
54 | self.pieChartView2.showPercentage = YES;
55 | [self.pieChartView2 resetData];
56 |
57 | self.pieChartView3 = [[PieChartView alloc] initWithFrame:CGRectMake(0, 525, self.view.frame.size.width / 2 - 5, 200)];
58 | self.pieChartView3.backgroundColor = [UIColor whiteColor];
59 | self.pieChartView3.isDoubleCircle = NO;
60 | self.pieChartView3.legendPostion = LegendPositionTop;
61 | self.pieChartView3.legendNameArray = @[@"一工区",@"二工区",@"三工区"];
62 | self.pieChartView3.pieDataArray = @[@"100",@"100",@"100"];
63 | self.pieChartView3.radius = 35;
64 | self.pieChartView3.pieDataUnit = @"元";
65 | [self.view addSubview:self.pieChartView3];
66 | [self.pieChartView3 resetData];
67 |
68 | self.pieChartView4 = [[PieChartView alloc] initWithFrame:CGRectMake(self.view.frame.size.width / 2 + 5, 525, self.view.frame.size.width / 2 - 5, 200)];
69 | self.pieChartView4.backgroundColor = [UIColor cyanColor];
70 | self.pieChartView4.isDoubleCircle = YES;
71 | self.pieChartView4.legendPostion = LegendPositionBottom;
72 | self.pieChartView4.legendNameArray = @[@"一工区",@"二工区",@"三工区"];
73 | self.pieChartView4.pieInsideDataArray = @[@"100",@"100",@"100"];
74 | self.pieChartView4.pieOutsideDataArray = @[@"100",@"100",@"100"];
75 | self.pieChartView4.radius = 80;
76 | [self.view addSubview:self.pieChartView4];
77 | [self.pieChartView4 resetData];
78 |
79 |
80 | }
81 |
82 | - (void)btnAction1 {
83 | if (!self.isBtnClicked) {
84 | self.pieChartView.legendNameArray = @[@"一工区",@"二工区",@"三工区",@"四工区",@"五工区"];
85 | self.pieChartView.pieDataArray = @[@"100",@"200",@"300",@"100",@"100"];
86 | self.pieChartView2.pieInsideDataArray = @[@"100",@"300",@"500"];
87 | self.pieChartView2.pieOutsideDataArray = @[@"100",@"300",@"500"];
88 | self.pieChartView3.pieDataArray = @[@"100",@"200",@"300"];
89 | self.pieChartView4.pieInsideDataArray = @[@"100",@"200",@"300"];
90 | self.pieChartView4.pieOutsideDataArray = @[@"100",@"200",@"300"];
91 | } else {
92 | self.pieChartView.legendNameArray = @[@"一工区",@"二工区",@"三工区"];
93 | self.pieChartView.pieDataArray = @[@"100",@"100",@"100"];
94 | self.pieChartView2.pieInsideDataArray = @[@"100",@"100",@"100"];
95 | self.pieChartView2.pieOutsideDataArray = @[@"100",@"100",@"100"];
96 | self.pieChartView3.pieDataArray = @[@"100",@"100",@"100"];
97 | self.pieChartView4.pieInsideDataArray = @[@"100",@"100",@"100"];
98 | self.pieChartView4.pieOutsideDataArray = @[@"100",@"100",@"100"];
99 | }
100 | [self.pieChartView resetData];
101 | [self.pieChartView2 resetData];
102 | [self.pieChartView3 resetData];
103 | [self.pieChartView4 resetData];
104 | self.isBtnClicked = !self.isBtnClicked;
105 | }
106 |
107 | /*
108 | #pragma mark - Navigation
109 |
110 | // In a storyboard-based application, you will often want to do a little preparation before navigation
111 | - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
112 | // Get the new view controller using [segue destinationViewController].
113 | // Pass the selected object to the new view controller.
114 | }
115 | */
116 |
117 | @end
118 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # iOS-UI之简易图表——饼图(扇形图)、柱状图、折(曲)线图
2 | 先来看看效果
3 | 1. 饼图(扇形图)
4 |  
5 | 
6 |
7 | 2. 柱状图
8 |  
9 |  
10 | 
11 |
12 | 3. 折线图
13 |  
14 |  
15 | 
16 |
17 | 样子粗糙,见笑了。
18 | Swift版本地址
19 |
20 | 现在来看看实现过程
21 | ## 一、饼图(扇形图)
22 | ### 1. 实现思路
23 | 实现思路其实很简单,首先算传入数据数组的数据总和,然后根据每个数据占比来乘以2π,得到每个数据的弧度,然后在循环中利用UIBezierPath的addArcWithCenter: radius: startAngle: endAngle: clockwise:方法设置路径,从圆顶点,即-π/2处开始,用CAShapeLayer画出子扇区,设置好颜色和半径就完成了。
24 | ### 2. 核心代码
25 | ```Objective-C
26 | CGFloat startAngle = -M_PI_2;
27 | for (int i = 0; i < self.pieDataArray.count; i++) {
28 | NSString *num = self.pieDataArray[i];
29 | UIBezierPath *path = [UIBezierPath bezierPath];
30 | [path addArcWithCenter:CGPointMake(pieView.bounds.size.width / 2, pieView.bounds.size.height / 2) radius:self.radius startAngle:startAngle endAngle:startAngle + [num floatValue] / total * M_PI * 2 clockwise:YES];
31 | [path addLineToPoint:CGPointMake(pieView.bounds.size.width / 2, pieView.bounds.size.height / 2)];// 圆心
32 | [[self colorWithHexString:self.colorArray[i]] setStroke];
33 | [[self colorWithHexString:self.colorArray[i]] setFill];
34 | [path stroke];
35 | [path fill];
36 |
37 | CAShapeLayer *layer = [CAShapeLayer layer];
38 | layer.path = path.CGPath;
39 | layer.strokeColor = [UIColor whiteColor].CGColor; // 描边颜色
40 | layer.fillColor = [self colorWithHexString:self.colorArray[i]].CGColor; // 背景填充色
41 | [pieView.layer addSublayer:layer];
42 |
43 | startAngle = startAngle + [num floatValue] / total * M_PI * 2 ;
44 | }
45 | ```
46 | 为了实现动画效果,需要在画出子扇区之前,设置一层遮罩,同样也可以用UIBezierPath和CAShapeLayer来实现,并将这层遮罩设置为圆
47 | ```Objective-C
48 | UIBezierPath *bgPath = [UIBezierPath bezierPathWithArcCenter:CGPointMake(pieView.bounds.size.width / 2, pieView.bounds.size.height / 2) radius:radius / 2 startAngle:-M_PI_2 endAngle:M_PI_2 * 3 clockwise:YES];
49 | CAShapeLayer *bgLayer = [CAShapeLayer layer];
50 | bgLayer.fillColor = [UIColor clearColor].CGColor;
51 | bgLayer.strokeColor = [UIColor lightGrayColor].CGColor;
52 | bgLayer.strokeStart = 0;
53 | bgLayer.strokeEnd = 1;
54 | bgLayer.zPosition = 1;
55 | bgLayer.lineWidth = radius;
56 | bgLayer.path = bgPath.CGPath;
57 | ```
58 | 并且务必在设置动画之前设置遮罩
59 | ```Objective-C
60 | pieView.layer.mask = bgLayer;
61 | ```
62 | 然后添加上动画
63 | ```Objective-C
64 | // 动画
65 | CABasicAnimation *strokeAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
66 | strokeAnimation.fromValue = @0;// 起始值
67 | strokeAnimation.toValue = @1;// 结束值
68 | strokeAnimation.duration = 1;// 动画持续时间
69 | strokeAnimation.repeatCount = 1;// 重复次数
70 | strokeAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
71 | strokeAnimation.removedOnCompletion = YES;
72 | [bgLayer addAnimation:strokeAnimation forKey:@"pieAnimation"];
73 | ```
74 | 这样一个单层饼图就完成了。
75 |
76 | 多层饼图的适用环境,内层饼图数据与外层饼图数据有包含关系,比如内层中的一工区包含外层的一小队、二小队等。
77 |
78 | 多层饼图的内层实现和单层饼图类似,外层实现是只利用UIBezierPath画一个圆弧轨迹,并设置线宽lineWidth和内层没有重合部分就行了。
79 |
80 | ## 二、柱状图
81 | ### 1. 实现思路
82 | 首先找到数据中的最大值,向上取整十或整百或整千并设置为Y轴最大值,然后在Y轴右侧放置一个scrollView(当数据超过5组时可以滚动),然后根据传入数据的分组标题,设置X轴和X轴分组标题,然后根据每个具体数据的值,算出柱顶点坐标,然后用UIBezierPath来设置柱路径,再画出柱子
83 | ### 2. 核心代码
84 | ```Objective-C
85 | NSString *num = self.dataArray[i];
86 | CGFloat columnHeight = (self.yAxisView.bounds.size.height - 20) * [num intValue] / maxNum;
87 | UIBezierPath *columnPath = [UIBezierPath bezierPath];
88 | [columnPath moveToPoint:CGPointMake(dataView.bounds.size.width / 2, dataView.bounds.size.height)];
89 | [columnPath addLineToPoint:CGPointMake(dataView.bounds.size.width / 2, dataView.bounds.size.height - columnHeight)];
90 | columnPath.lineWidth = [self.columnWidth intValue];
91 | [[self colorWithHexString:self.columnColor] setStroke];
92 | [[self colorWithHexString:self.columnColor] setFill];
93 | [columnPath stroke];
94 | [columnPath fill];
95 | /*
96 | 在这后面完成柱子的绘制(分渐变色和非渐变色讨论)
97 | */
98 | ```
99 | 当柱子不是渐变色时,用CAShapeLayer,代码如下:
100 | ```Objective-C
101 | CAShapeLayer *columnLayer = [CAShapeLayer layer];
102 | columnLayer.path = columnPath.CGPath;
103 | columnLayer.strokeColor = [self colorWithHexString:self.columnColor].CGColor;// 描边颜色
104 | columnLayer.fillColor = [self colorWithHexString:self.columnColor].CGColor;
105 | columnLayer.lineWidth = [self.columnWidth intValue];
106 | [dataView.layer addSublayer:columnLayer];
107 | ```
108 | 当柱子是渐变色时,用CAGradientLayer,代码如下:
109 | ```Objective-C
110 | CAGradientLayer *columnGradientLayer = [CAGradientLayer layer];
111 | columnGradientLayer.frame = CGRectMake(dataView.bounds.size.width / 2 - [self.columnWidth intValue] / 2, dataView.bounds.size.height - columnHeight, [self.columnWidth intValue], columnHeight);
112 | columnGradientLayer.colors = @[(__bridge id)[self colorWithHexString:self.columnGradientColorArray[0]].CGColor,
113 | (__bridge id)[self colorWithHexString:self.columnGradientColorArray[1]].CGColor];
114 | columnGradientLayer.locations = @[@(0.0),@(1.0)];// 颜色变化位置
115 | columnGradientLayer.startPoint = CGPointMake(0, 0);
116 | columnGradientLayer.endPoint = CGPointMake(0, 1);
117 | [dataView.layer addSublayer:columnGradientLayer];
118 | ```
119 | 同样的,如果需要实现柱子自下而上的动画,也需要设置一个背景来遮罩
120 | ```Objective-C
121 | UIBezierPath *bgPath = [UIBezierPath bezierPath];
122 | [bgPath moveToPoint:CGPointMake(dataView.bounds.size.width / 2, dataView.bounds.size.height)];
123 | [bgPath addLineToPoint:CGPointMake(dataView.bounds.size.width / 2, 0)];
124 | bgPath.lineWidth = groupWidth;
125 |
126 | CAShapeLayer *bgLayer = [CAShapeLayer layer];
127 | bgLayer.fillColor = [UIColor clearColor].CGColor;
128 | bgLayer.strokeColor = [UIColor lightGrayColor].CGColor;
129 | bgLayer.strokeStart = 0;
130 | bgLayer.strokeEnd = 1;
131 | bgLayer.zPosition = 1;
132 | bgLayer.lineWidth = groupWidth;
133 | bgLayer.path = bgPath.CGPath;
134 | dataView.layer.mask = bgLayer;
135 | ```
136 | 再加上动画
137 | ```Objective-C
138 | CABasicAnimation *strokeAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
139 | strokeAnimation.fromValue = @0;// 起始值
140 | strokeAnimation.toValue = @1;// 结束值
141 | strokeAnimation.duration = 1;// 动画持续时间
142 | strokeAnimation.repeatCount = 1;// 重复次数
143 | strokeAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
144 | strokeAnimation.removedOnCompletion = YES;
145 | [bgLayer addAnimation:strokeAnimation forKey:@"pieAnimation"];
146 | ```
147 | 一个单柱的柱状图就实现了,如果要实现多柱(最多4柱,因为多了不好看,嘻嘻~),也不复杂,大概实现思路和单柱一样,只有一点就是需要调整每组柱体的x坐标在每组的中点即可。
148 |
149 | ## 三、折线图
150 | ### 1. 实现思路
151 | 单纯的折线图实现思路起始很简单,就是在背景上利用循环,算出每个数据的点坐标,然后用UIBezierPath和CAShapeLayer来画出每个点之前的直线就行了。
152 |
153 | 然而,如果要把折线换成平滑的曲线,这就不好实现了,需要用到UIBezierPath的addCurveToPoint: controlPoint1: controlPoint2:方法了,除了需要传入数据点,还需要传入两个控制点,因为贝塞尔曲线是利用两个控制点来确定一段曲线路径的(大致内容参考自:,感谢大佬的分享),但是我依然不知道这两个控制点怎么来确定,毕竟这太高数了(参考自:),我又在网上搜了一下,有现成的(原谅我这个白嫖党)(再次感谢大佬),于是乎借(cmd+c)鉴(cmd+v)来用。在曲线找点开始之前,先另外创建一个可变数组(NSMutableArray)pointArray,先在这个数组第一个元素的位置保存上原点(0,0)的坐标,用来确定第一段曲线,然后将数据(此时已经转化成CGPointValue)挨个存入pointArray,最后再加上曲线末端向右偏移半个dataView的宽度的距离在x轴上的坐标,用来确定最后一段曲线。最后用CAShapelayer把曲线画出来。
154 | ### 2. 核心代码
155 | 单纯的折线时
156 | ```Objective-C
157 | UIBezierPath *dataPath = [UIBezierPath bezierPath];
158 | dataPath.lineWidth = self.lineWidth;
159 | [[self colorWithHexString:self.lineColor andAlpha:1.0] setStroke];
160 | [[self colorWithHexString:self.lineColor andAlpha:1.0] setFill];
161 | [dataPath stroke];
162 | [dataPath fill];
163 | for (int i = 0; i < self.dataArray.count; i++) {
164 | // 具体数据
165 | NSString *num = self.dataArray[i];
166 | CGFloat pointHeight = self.dataView.bounds.size.height - (self.dataView.bounds.size.height - 20) * [num intValue] / maxNum;
167 | [dataPath addLineToPoint:CGPointMake(groupWidth / 2 + groupWidth * i, pointHeight)];
168 | }
169 | CAShapeLayer *dataLayer = [CAShapeLayer layer];
170 | dataLayer.path = dataPath.CGPath;
171 | dataLayer.strokeColor = [self colorWithHexString:self.lineColor andAlpha:1.0].CGColor;
172 | dataLayer.fillColor = nil;
173 | dataLayer.lineWidth = self.lineWidth;
174 | [self.dataView.layer addSublayer:dataLayer];
175 | ```
176 | 平滑曲线时
177 | ```Objective-C
178 | UIBezierPath *dataPath = [UIBezierPath bezierPath];
179 | dataPath.lineWidth = self.lineWidth;
180 | [[self colorWithHexString:self.lineColor andAlpha:1.0] setStroke];
181 | [[self colorWithHexString:self.lineColor andAlpha:1.0] setFill];
182 | [dataPath stroke];
183 | [dataPath fill];
184 |
185 | [self.pointArray removeAllObjects];
186 | // 起始点
187 | [self.pointArray addObject:[NSValue valueWithCGPoint:CGPointMake(0, self.dataView.bounds.size.height)]];
188 | CGFloat groupWidth = self.scrollView.bounds.size.width / 5;
189 | for (int i = 0; i < self.dataArray.count; i++) {
190 | NSString *num = self.dataArray[i];
191 | CGFloat pointHeight = self.dataView.bounds.size.height - (self.dataView.bounds.size.height - 20) * [num intValue] / maxNum;
192 | [self.pointArray addObject:[NSValue valueWithCGPoint:CGPointMake(groupWidth / 2 + groupWidth * i, pointHeight)]];
193 | }
194 |
195 | // 添加结束点
196 | [self.pointArray addObject:[NSValue valueWithCGPoint:CGPointMake(self.dataView.bounds.size.width, self.dataView.bounds.size.height)]];
197 | for (int i = 0; i < self.dataArray.count - 1; i++) {
198 | CGPoint p1 = [self.pointArray[i] CGPointValue];
199 | CGPoint p2 = [self.pointArray[i+1] CGPointValue];
200 | CGPoint p3 = [self.pointArray[i+2] CGPointValue];
201 | CGPoint p4 = [self.pointArray[i+3] CGPointValue];
202 | if (i == 0) {
203 | if (self.isFillWithColor) {
204 | [dataPath moveToPoint:CGPointMake(groupWidth / 2, self.dataView.bounds.size.height)];
205 | [dataPath addLineToPoint:p2];
206 | } else {
207 | [dataPath moveToPoint:p2];
208 | [dataPath addLineToPoint:CGPointMake(groupWidth / 2, self.dataView.bounds.size.height)];
209 | }
210 | }
211 | [self getControlPointOfBezierPath:dataPath andPointx0:p1.x andy0:p1.y x1:p2.x andy1:p2.y x2:p3.x andy2:p3.y x3:p4.x andy3:p4.y];
212 | CAShapeLayer *dataLayer = [CAShapeLayer layer];
213 | dataLayer.path = dataPath.CGPath;
214 | dataLayer.strokeColor = [self colorWithHexString:self.lineColor andAlpha:1.0].CGColor;
215 | dataLayer.fillColor = nil;//[self colorWithHexString:self.lineColor].CGColor;
216 | dataLayer.lineWidth = self.lineWidth;
217 | [self.dataView.layer addSublayer:dataLayer];
218 | ```
219 | 其中,曲线控制点的计算方法getControlPointOfBezierPath: andPointx0:andy0: x1: andy1: x2: andy2: x3:andy3实现为
220 | ```Objective-C
221 | /**
222 | 传入四个点求两个控制点 (画2,3之间的曲线,需要传入1,2,3,4的坐标)
223 | 参考自:https://www.jianshu.com/p/c33081adce28
224 | 实在是看球不懂
225 | */
226 | - (void)getControlPointOfBezierPath:(UIBezierPath *)bezierPath
227 | andPointx0:(CGFloat)x0 andy0:(CGFloat)y0
228 | x1:(CGFloat)x1 andy1:(CGFloat)y1
229 | x2:(CGFloat)x2 andy2:(CGFloat)y2
230 | x3:(CGFloat)x3 andy3:(CGFloat)y3 {
231 | CGFloat smooth_value = 0.6;
232 | CGFloat ctrl1_x;
233 | CGFloat ctrl1_y;
234 | CGFloat ctrl2_x;
235 | CGFloat ctrl2_y;
236 | CGFloat xc1 = (x0 + x1) /2.0;
237 | CGFloat yc1 = (y0 + y1) /2.0;
238 | CGFloat xc2 = (x1 + x2) /2.0;
239 | CGFloat yc2 = (y1 + y2) /2.0;
240 | CGFloat xc3 = (x2 + x3) /2.0;
241 | CGFloat yc3 = (y2 + y3) /2.0;
242 | CGFloat len1 = sqrt((x1-x0) * (x1-x0) + (y1-y0) * (y1-y0));
243 | CGFloat len2 = sqrt((x2-x1) * (x2-x1) + (y2-y1) * (y2-y1));
244 | CGFloat len3 = sqrt((x3-x2) * (x3-x2) + (y3-y2) * (y3-y2));
245 | CGFloat k1 = len1 / (len1 + len2);
246 | CGFloat k2 = len2 / (len2 + len3);
247 | CGFloat xm1 = xc1 + (xc2 - xc1) * k1;
248 | CGFloat ym1 = yc1 + (yc2 - yc1) * k1;
249 | CGFloat xm2 = xc2 + (xc3 - xc2) * k2;
250 | CGFloat ym2 = yc2 + (yc3 - yc2) * k2;
251 | ctrl1_x = xm1 + (xc2 - xm1) * smooth_value + x1 - xm1;
252 | ctrl1_y = ym1 + (yc2 - ym1) * smooth_value + y1 - ym1;
253 | ctrl2_x = xm2 + (xc2 - xm2) * smooth_value + x2 - xm2;
254 | ctrl2_y = ym2 + (yc2 - ym2) * smooth_value + y2 - ym2;
255 |
256 | [bezierPath addCurveToPoint:CGPointMake(x2, y2) controlPoint1:CGPointMake(ctrl1_x, ctrl1_y) controlPoint2:CGPointMake(ctrl2_x, ctrl2_y)];
257 | }
258 | ```
259 | 当线条下面部分需要填充颜色时,需要在path里添加起始点在X轴上的投影的点坐标和结束点在X轴上的投影的点坐标,以保证路径是个闭合的图形,然后设置CAShapeLayer的fillColor(填充色)就可以了,完整判断填充色和平滑曲线的代码如下
260 | ```Objective-C
261 | UIBezierPath *dataPath = [UIBezierPath bezierPath];
262 | dataPath.lineWidth = self.lineWidth;
263 | [[self colorWithHexString:self.lineColor andAlpha:1.0] setStroke];
264 | [[self colorWithHexString:self.lineColor andAlpha:1.0] setFill];
265 | [dataPath stroke];
266 | [dataPath fill];
267 |
268 | [self.pointArray removeAllObjects];
269 | // 起始点
270 | [self.pointArray addObject:[NSValue valueWithCGPoint:CGPointMake(0, self.dataView.bounds.size.height)]];
271 |
272 | CGFloat groupWidth = self.scrollView.bounds.size.width / 5;
273 | for (int i = 0; i < self.dataArray.count; i++) {
274 | // 具体数据
275 | NSString *num = self.dataArray[i];
276 | CGFloat pointHeight = self.dataView.bounds.size.height - (self.dataView.bounds.size.height - 20) * [num intValue] / maxNum;
277 | if (self.isSmooth) {// 是否为平滑曲线
278 | [self.pointArray addObject:[NSValue valueWithCGPoint:CGPointMake(groupWidth / 2 + groupWidth * i, pointHeight)]];
279 | } else {
280 | if (i == 0) {
281 | if (self.isFillWithColor) {
282 | [dataPath moveToPoint:CGPointMake(groupWidth / 2, self.dataView.bounds.size.height)];
283 | [dataPath addLineToPoint:CGPointMake(groupWidth / 2, pointHeight)];
284 | } else {
285 | [dataPath moveToPoint:CGPointMake(groupWidth / 2, pointHeight)];
286 | }
287 | } else if (i == self.dataArray.count - 1) {
288 | [dataPath addLineToPoint:CGPointMake(groupWidth / 2 + groupWidth * i, pointHeight)];
289 | if (self.isFillWithColor) {
290 | [dataPath addLineToPoint:CGPointMake(groupWidth / 2 + groupWidth * i, self.dataView.bounds.size.height)];
291 | }
292 | } else {
293 | [dataPath addLineToPoint:CGPointMake(groupWidth / 2 + groupWidth * i, pointHeight)];
294 | }
295 | }
296 | }
297 |
298 | if (self.isSmooth) {
299 | // 添加结束点
300 | [self.pointArray addObject:[NSValue valueWithCGPoint:CGPointMake(self.dataView.bounds.size.width, self.dataView.bounds.size.height)]];
301 | for (int i = 0; i < self.dataArray.count - 1; i++) {
302 | CGPoint p1 = [self.pointArray[i] CGPointValue];
303 | CGPoint p2 = [self.pointArray[i+1] CGPointValue];
304 | CGPoint p3 = [self.pointArray[i+2] CGPointValue];
305 | CGPoint p4 = [self.pointArray[i+3] CGPointValue];
306 | if (i == 0) {
307 | if (self.isFillWithColor) {
308 | [dataPath moveToPoint:CGPointMake(groupWidth / 2, self.dataView.bounds.size.height)];
309 | [dataPath addLineToPoint:p2];
310 | } else {
311 | [dataPath moveToPoint:p2];
312 | [dataPath addLineToPoint:CGPointMake(groupWidth / 2, self.dataView.bounds.size.height)];
313 | }
314 | }
315 | [self getControlPointOfBezierPath:dataPath andPointx0:p1.x andy0:p1.y x1:p2.x andy1:p2.y x2:p3.x andy2:p3.y x3:p4.x andy3:p4.y];
316 | }
317 | if (self.isFillWithColor) {
318 | [dataPath addLineToPoint:CGPointMake(groupWidth / 2 + groupWidth * (self.dataArray.count - 1), self.dataView.bounds.size.height)];
319 | // [dataPath addLineToPoint:CGPointMake(groupWidth / 2, self.dataView.bounds.size.height)];
320 | }
321 | }
322 |
323 | CAShapeLayer *dataLayer = [CAShapeLayer layer];
324 | dataLayer.path = dataPath.CGPath;
325 | if (self.isFillWithColor) {
326 | dataLayer.strokeColor = nil;//[self colorWithHexString:self.lineColor].CGColor;
327 | dataLayer.fillColor = [self colorWithHexString:self.fillColor andAlpha:self.fillAlpha].CGColor;
328 | } else {
329 | dataLayer.strokeColor = [self colorWithHexString:self.lineColor andAlpha:1.0].CGColor;
330 | dataLayer.fillColor = nil;//[self colorWithHexString:self.lineColor].CGColor;
331 | }
332 | dataLayer.lineWidth = self.lineWidth;
333 | [self.dataView.layer addSublayer:dataLayer];
334 | ```
335 | 和之前两个图表相同,如果需要动画就要添加上背景遮罩
336 | ```Objective-C
337 | UIBezierPath *bgPath = [UIBezierPath bezierPath];
338 | [bgPath moveToPoint:CGPointMake(0, self.dataView.bounds.size.height / 2)];
339 | [bgPath addLineToPoint:CGPointMake(self.dataView.bounds.size.width, self.dataView.bounds.size.height / 2)];
340 | bgPath.lineWidth = self.dataView.bounds.size.height;
341 | CAShapeLayer *bgLayer = [CAShapeLayer layer];
342 | bgLayer.fillColor = [UIColor clearColor].CGColor;
343 | bgLayer.strokeColor = [UIColor lightGrayColor].CGColor;
344 | bgLayer.strokeStart = 0;
345 | bgLayer.strokeEnd = 1;
346 | bgLayer.zPosition = 1;
347 | bgLayer.lineWidth = self.dataView.bounds.size.height;
348 | bgLayer.path = bgPath.CGPath;
349 | self.dataView.layer.mask = bgLayer;
350 | ```
351 | 加上动画
352 | ```Objective-C
353 | CABasicAnimation *strokeAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
354 | strokeAnimation.fromValue = @0;// 起始值
355 | strokeAnimation.toValue = @1;// 结束值
356 | strokeAnimation.duration = 1;// 动画持续时间
357 | strokeAnimation.repeatCount = 1;// 重复次数
358 | strokeAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
359 | strokeAnimation.removedOnCompletion = YES;
360 | [bgLayer addAnimation:strokeAnimation forKey:@"pieAnimation"];
361 | ```
362 | 一个单条折线图就完成了,如果需要多条折线图,实现方式也和实现单条类似,只是需要解析的数据数组是个二维数组,里面每个元素都是一条线的数据,外层数组有多少个元素就有多少条线,用循环绘制就可以了。
363 |
364 | ## 四、结束语
365 | 时间仓促,有许多不完善的地方,还请海涵,有什么问题可以联系我
366 | CSDN博客地址:
367 |
368 | 另:Swift版本地址
369 |
370 |
--------------------------------------------------------------------------------
/GCChartDemo/GCChartDemo/PieChartView/CircleRingChartView.m:
--------------------------------------------------------------------------------
1 | //
2 | // CircleRingChartView.m
3 | // GCChartDemo
4 | //
5 | // Created by 古创 on 2019/6/5.
6 | // Copyright © 2019年 GC. All rights reserved.
7 | //
8 |
9 | #import "CircleRingChartView.h"
10 |
11 | @interface CircleRingChartView ()
12 |
13 | @property (nonatomic,strong) UIView *legendBgView;
14 | @property (nonatomic,strong) NSMutableArray *colorArray;
15 |
16 | @end
17 |
18 | @implementation CircleRingChartView
19 |
20 | - (instancetype)initWithFrame:(CGRect)frame atPostiion:(LegendPosition)legendPostion withNameArray:(NSArray *)nameArray andDataArray:(NSArray *)dataArray andRadius:(CGFloat)radius andLineWidth:(CGFloat)lineWidth;{
21 | self = [super initWithFrame:frame];
22 | if (self) {
23 | self.legendPostion = legendPostion;
24 | self.legendNameArray = nameArray;
25 | self.pieDataArray = dataArray;
26 | self.radius = radius;
27 | self.lineWidth = lineWidth;
28 | [self config];
29 | }
30 | return self;
31 | }
32 |
33 | - (instancetype)initWithFrame:(CGRect)frame
34 | {
35 | self = [super initWithFrame:frame];
36 | if (self) {
37 | [self config];
38 | }
39 | return self;
40 | }
41 |
42 | - (void)config {
43 | if (self.legendColorArray.count == 0 || self.legendColorArray.count < self.legendNameArray.count) {
44 | NSArray *arr = @[@"#308ff7",@"#fbca58",@"#f5447d",@"#a020f0",@"#00ffff",@"#00ff00"];
45 | self.colorArray = [NSMutableArray arrayWithArray:arr];
46 | } else {
47 | self.colorArray = [NSMutableArray arrayWithArray:self.legendColorArray];
48 | }
49 | if (self.radius == 0) {
50 | self.radius = 60;
51 | } else if (self.radius < 40) {
52 | self.radius = 40;
53 | } else if (self.radius * 2 > MIN(self.bounds.size.width, self.bounds.size.height) - 20 - 20 * 2) {// 极端情况 半径接近宽高较小值-20的时候 需要特殊处理 此时标注有可能超出范围而不显示或显示异常
54 | self.radius = (MIN(self.bounds.size.width, self.bounds.size.height) - 20 - 20 * 2) / 2;
55 | } else {
56 |
57 | }
58 | if (self.lineWidth == 0) {
59 | self.lineWidth = 10;
60 | } else if (self.lineWidth < 5) {
61 | self.lineWidth = 5;
62 | } else if (self.lineWidth >= self.radius / 2) {
63 | self.lineWidth = self.radius / 2;
64 | } else {
65 |
66 | }
67 |
68 | }
69 |
70 | - (void)resetLegend {
71 | // 先移除之前创建的
72 | for (UIView *view in self.legendBgView.subviews) {
73 | [view removeFromSuperview];
74 | }
75 | self.legendBgView = nil;
76 | [self.legendBgView removeFromSuperview];
77 | if (self.legendPostion == LegendPositionNone) {// 无图例的时候
78 | self.legendBgView = nil;
79 | } else {
80 | self.legendBgView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.bounds.size.width, 20)];
81 | [self addSubview:self.legendBgView];
82 | switch (self.legendPostion) {
83 | case LegendPositionTop:
84 | self.legendBgView.center = CGPointMake(self.bounds.size.width / 2, 10);
85 | break;
86 | case LegendPositionBottom:
87 | self.legendBgView.center = CGPointMake(self.bounds.size.width / 2, self.bounds.size.height - 10);
88 | break;
89 |
90 | default:
91 | break;
92 | }
93 | for (int i = 0; i < self.legendNameArray.count; i++) {
94 | UIView *colorPoint = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 10, 10)];
95 | colorPoint.center = CGPointMake(8 + (5 + 50 + 10) * i, 10);
96 | colorPoint.backgroundColor = [self colorWithHexString:self.colorArray[i]];
97 | colorPoint.layer.cornerRadius = 5;
98 | colorPoint.layer.masksToBounds = YES;
99 | [self.legendBgView addSubview:colorPoint];
100 |
101 | UILabel *legendTitle = [[UILabel alloc] initWithFrame:CGRectMake(CGRectGetMaxX(colorPoint.frame) + 2, 0, 50, 20)];
102 | legendTitle.text = self.legendNameArray[i];
103 | legendTitle.textColor = [UIColor blackColor];
104 | legendTitle.font = [UIFont systemFontOfSize:12];
105 | [self.legendBgView addSubview:legendTitle];
106 | }
107 | }
108 | }
109 |
110 | - (void)resetCircleRing {
111 | [self resetLegend];
112 |
113 | CGFloat pieCenterX = self.bounds.size.width / 2;
114 | CGFloat pieCenterY;
115 | if (self.legendPostion == LegendPositionTop) {
116 | pieCenterY = self.bounds.size.height / 2 + 10;
117 | } else if (self.legendPostion == LegendPositionBottom) {
118 | pieCenterY = self.bounds.size.height / 2 - 10;
119 | } else {
120 | pieCenterY = self.bounds.size.height / 2;
121 | }
122 | // 先移除之前创建的
123 | for (UIView *view in self.subviews) {
124 | if (view.tag == 101) {
125 | [view removeFromSuperview];
126 | }
127 | }
128 | UIView *pieView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.bounds.size.width, self.bounds.size.height - 20)];
129 | pieView.center = CGPointMake(pieCenterX, pieCenterY);
130 | pieView.tag = 101;
131 | pieView.backgroundColor = self.backgroundColor;//[UIColor whiteColor];
132 | [self addSubview:pieView];
133 |
134 | if (self.touchEnable) {
135 | UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapAction:)];
136 | [pieView addGestureRecognizer:tap];
137 | }
138 | float total = 0;
139 | for (NSString *str in self.pieDataArray) {
140 | total = total + [str floatValue];
141 | }
142 |
143 | UILabel *lblCenterTitle = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 60, 21)];
144 | lblCenterTitle.center = CGPointMake(pieView.bounds.size.width / 2, pieView.bounds.size.height / 2 - 20);
145 | lblCenterTitle.font = [UIFont systemFontOfSize:14];
146 | lblCenterTitle.textColor = [self colorWithHexString:@"#404040"];
147 | lblCenterTitle.text = self.centerTitle.length == 0 ? @"" : self.centerTitle;
148 | lblCenterTitle.textAlignment = NSTextAlignmentCenter;
149 | [pieView addSubview:lblCenterTitle];
150 |
151 | UILabel *lblCenterTotal = [[UILabel alloc] initWithFrame:CGRectMake(0, CGRectGetMaxY(lblCenterTitle.frame), 80, 21)];
152 | lblCenterTotal.center = CGPointMake(pieView.bounds.size.width / 2, lblCenterTotal.center.y);
153 | lblCenterTotal.font = [UIFont systemFontOfSize:16];
154 | lblCenterTotal.textColor = [UIColor blackColor];
155 | lblCenterTotal.text = [NSString stringWithFormat:@"%.f",total];
156 | lblCenterTotal.textAlignment = NSTextAlignmentCenter;
157 | [pieView addSubview:lblCenterTotal];
158 | lblCenterTotal.hidden = self.centerTitle.length == 0 ? YES : NO;
159 |
160 | CGFloat radius = MAX(pieView.bounds.size.width, pieView.bounds.size.height);//pieView.bounds.size.width > pieView.bounds.size.height ? pieView.bounds.size.height / 2 : pieView.bounds.size.width / 2;
161 |
162 | // 背景
163 | UIBezierPath *bgPath = [UIBezierPath bezierPathWithArcCenter:CGPointMake(pieView.bounds.size.width / 2, pieView.bounds.size.height / 2) radius:radius / 2 startAngle:-M_PI_2 endAngle:M_PI_2 * 3 clockwise:YES];
164 | CAShapeLayer *bgLayer = [CAShapeLayer layer];
165 | bgLayer.fillColor = [UIColor clearColor].CGColor;
166 | bgLayer.strokeColor = [UIColor lightGrayColor].CGColor;
167 | bgLayer.strokeStart = 0;
168 | bgLayer.strokeEnd = 1;
169 | bgLayer.zPosition = 1;
170 | bgLayer.lineWidth = radius;
171 | bgLayer.path = bgPath.CGPath;
172 |
173 |
174 | CGFloat startAngle = 1.5 * M_PI;
175 | for (int i = 0; i < self.pieDataArray.count; i++) {
176 | NSString *num = self.pieDataArray[i];
177 |
178 | UIBezierPath *path = [UIBezierPath bezierPath];
179 | [path addArcWithCenter:CGPointMake(pieView.bounds.size.width / 2, pieView.bounds.size.height / 2) radius:self.radius startAngle:startAngle endAngle:startAngle + [num floatValue] / total * M_PI * 2 clockwise:YES];
180 | // path.lineWidth = 10;// 线宽与半径相同
181 | // [path addLineToPoint:pieView.center];
182 | [[self colorWithHexString:self.colorArray[i]] setStroke];
183 | [[self colorWithHexString:self.colorArray[i]] setFill];
184 | [path stroke];
185 | [path fill];
186 |
187 | CAShapeLayer *layer = [CAShapeLayer layer];
188 | layer.path = path.CGPath;
189 | layer.lineWidth = self.lineWidth;//self.radius / 6;
190 | layer.strokeColor = [self colorWithHexString:self.colorArray[i]].CGColor; // 圆环颜色
191 | layer.fillColor = [UIColor clearColor].CGColor; // 背景填充色
192 | // layer.backgroundColor = [self colorWithHexString:self.colorArray[i]].CGColor;
193 | [pieView.layer addSublayer:layer];
194 |
195 | startAngle = startAngle + [num floatValue] / total * M_PI * 2 ;
196 |
197 | }
198 |
199 | // 标注
200 | CGFloat startAngle_p = 90;
201 | for (int i = 0; i < self.pieDataArray.count; i++) {
202 | NSString *num = self.pieDataArray[i];
203 | CGFloat angle = startAngle_p - [num floatValue] / 2 / total * 360;
204 | CGPoint pointInCenter = [self caculatePointAtCircleWithCenter:CGPointMake(pieView.bounds.size.width / 2, pieView.bounds.size.height / 2) andAngle:angle andRadius:self.radius + self.lineWidth / 2];
205 | CGPoint pointInCenter_2 = [self caculatePointAtCircleWithCenter:CGPointMake(pieView.bounds.size.width / 2, pieView.bounds.size.height / 2) andAngle:angle andRadius:self.radius + self.lineWidth / 2 + self.radius / 6];
206 | CGPoint pointAtLabel;
207 | if (cosf(angle * M_PI / 180) >= -0.01) { // 偏右侧
208 | pointAtLabel = CGPointMake(pointInCenter_2.x + self.radius / 3, pointInCenter_2.y);
209 | } else { // 偏左侧
210 | pointAtLabel = CGPointMake(pointInCenter_2.x - self.radius / 3, pointInCenter_2.y);
211 | }
212 |
213 | UIBezierPath *linePath = [UIBezierPath bezierPath];
214 | [linePath moveToPoint:pointInCenter];
215 | [linePath addLineToPoint:pointInCenter_2];
216 | [linePath addLineToPoint:pointAtLabel];
217 |
218 | CAShapeLayer *layer = [CAShapeLayer layer];
219 | layer.lineWidth = 0.5;
220 | layer.strokeColor = [self colorWithHexString:@"#dcdcdc"].CGColor;
221 | layer.fillColor = nil;
222 | layer.path = linePath.CGPath;
223 | [pieView.layer addSublayer:layer];
224 |
225 | UILabel *lblMark = [[UILabel alloc] init];
226 | if (cosf(angle * M_PI / 180) >= -0.01) { // 偏右侧
227 | lblMark.bounds = CGRectMake(0, 0, pieView.bounds.size.width - pointAtLabel.x - 2, 12);
228 | } else { // 偏左侧
229 | lblMark.bounds = CGRectMake(0, 0, pointAtLabel.x - 2, 12);
230 | }
231 | lblMark.textColor = [self colorWithHexString:@"#404040"];
232 | lblMark.font = [UIFont systemFontOfSize:10];
233 | lblMark.numberOfLines = 2;
234 | if (self.showPercentage) {
235 | NSString *num = self.pieDataArray[i];
236 | if (self.pieDataNameArray.count == 0 || self.pieDataNameArray.count != self.pieDataArray.count) {
237 | lblMark.text = [NSString stringWithFormat:@"%.2f%%",[num floatValue] / total * 100];
238 | } else {
239 | lblMark.text = [NSString stringWithFormat:@"%@:%.2f%%",self.pieDataNameArray[i],[num floatValue] / total * 100];
240 | }
241 | } else {
242 | if (!self.pieDataUnit) {
243 | self.pieDataUnit = @"";
244 | }
245 | if (self.pieDataNameArray.count == 0 || self.pieDataNameArray.count != self.pieDataArray.count) {
246 | lblMark.text = [NSString stringWithFormat:@"%@%@",self.pieDataArray[i],self.pieDataUnit];
247 | } else {
248 | lblMark.text = [NSString stringWithFormat:@"%@:%@%@",self.pieDataNameArray[i],self.pieDataArray[i],self.pieDataUnit];
249 | }
250 | }
251 | [lblMark sizeToFit];
252 | [pieView addSubview:lblMark];
253 | if (cosf(angle * M_PI / 180) >= -0.01) { // 偏右侧
254 | lblMark.center = CGPointMake(pointAtLabel.x + lblMark.bounds.size.width / 2 + 2, pointAtLabel.y);
255 | } else { // 偏左侧
256 | lblMark.center = CGPointMake(pointAtLabel.x - lblMark.bounds.size.width / 2 - 2, pointAtLabel.y);
257 | }
258 |
259 | startAngle_p = startAngle_p - [num floatValue] / total * 360 ;
260 | }
261 |
262 | pieView.layer.mask = bgLayer;
263 | // 动画
264 | CABasicAnimation *strokeAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
265 | strokeAnimation.fromValue = @0;// 起始值
266 | strokeAnimation.toValue = @1;// 结束值
267 | strokeAnimation.duration = 1;// 动画持续时间
268 | strokeAnimation.repeatCount = 1;// 重复次数
269 | strokeAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
270 | strokeAnimation.removedOnCompletion = YES;
271 | [bgLayer addAnimation:strokeAnimation forKey:@"pieAnimation"];
272 |
273 |
274 | }
275 |
276 | - (void)resetDataLabel {
277 | float total = 0;
278 | for (NSString *str in self.pieDataArray) {
279 | total = total + [str floatValue];
280 | }
281 | UIView *pieView;
282 | for (UIView *view in self.subviews) {
283 | if (view.tag == 101) {
284 | pieView = view;
285 | }
286 | }
287 | CGFloat startAngle_p = 90;
288 | for (int i = 0; i < self.pieDataArray.count; i++) {
289 | NSString *num = self.pieDataArray[i];
290 | CGFloat angle = startAngle_p - [num floatValue] / 2 / total * 360;
291 | CGPoint pointInCenter = [self caculatePointAtCircleWithCenter:CGPointMake(pieView.bounds.size.width / 2, pieView.center.y) andAngle:angle andRadius:self.radius];
292 | CGPoint pointInCenter_2 = [self caculatePointAtCircleWithCenter:CGPointMake(pieView.bounds.size.width / 2, pieView.center.y) andAngle:angle andRadius:self.radius + 5];
293 |
294 | UIBezierPath *linePath = [UIBezierPath bezierPath];
295 | [linePath moveToPoint:pointInCenter];
296 | [linePath addLineToPoint:pointInCenter_2];
297 |
298 | CAShapeLayer *layer = [CAShapeLayer layer];
299 | layer.lineWidth = 0.5;
300 | layer.strokeColor = [UIColor lightGrayColor].CGColor;
301 | layer.path = linePath.CGPath;
302 | [pieView.layer addSublayer:layer];
303 |
304 | startAngle_p = startAngle_p - [num floatValue] / total * 360 ;
305 | }
306 | }
307 |
308 | #pragma mark - resetData
309 | - (void)resetData {
310 | [self config];
311 |
312 | [self resetCircleRing];
313 | }
314 |
315 | #pragma mark - tapAction
316 | - (void)tapAction:(UITapGestureRecognizer *)tap {
317 | UIView *pieView = tap.view;
318 | CGPoint touchPoint = [tap locationInView:pieView];
319 | // NSLog(@"%f,%f",touchPoint.x,touchPoint.y);
320 | CGFloat distance = sqrt(pow(touchPoint.x - pieView.bounds.size.width / 2, 2) + pow(touchPoint.y - pieView.bounds.size.height / 2, 2));
321 | if (distance >= self.radius - self.lineWidth / 2 && distance <= self.radius + self.lineWidth / 2) {
322 | CGFloat angle = acos((pieView.bounds.size.height / 2 - touchPoint.y) / distance);
323 | if (touchPoint.x - pieView.bounds.size.width / 2 < 0) {
324 | angle = 2 * M_PI - angle;
325 | }
326 | // NSLog(@"%f",angle);
327 | float total = 0;
328 | for (NSString *str in self.pieDataArray) {
329 | total = total + [str floatValue];
330 | }
331 | CGFloat startAngle = 1.5 * M_PI;
332 | for (int i = 0; i < self.pieDataArray.count; i++) {
333 | // 因创建CAShapeLayer时,先添加的是圆环 所以在这里可以角标访问到对应的layer
334 | // CAShapeLayer *layer = pieView.layer.sublayers[i];
335 | NSString *num = self.pieDataArray[i];
336 | if (angle + 1.5 * M_PI >= startAngle && angle + 1.5 * M_PI < startAngle + [num floatValue] / total * M_PI * 2) {
337 | NSLog(@"%d",i);
338 |
339 | } else {
340 |
341 | }
342 |
343 | startAngle = startAngle + [num floatValue] / total * M_PI * 2;
344 | }
345 | }
346 | }
347 |
348 | #pragma mark - getter
349 | - (NSArray *)legendNameArray {
350 | if (!_legendNameArray) {
351 | _legendNameArray = [NSArray array];
352 | }
353 | return _legendNameArray;
354 | }
355 |
356 | - (NSArray *)legendColorArray {
357 | if (!_legendColorArray) {
358 | _legendColorArray = [NSArray array];
359 | }
360 | return _legendColorArray;
361 | }
362 |
363 | - (NSMutableArray *)colorArray {
364 | if (!_colorArray) {
365 | _colorArray = [NSMutableArray array];
366 | }
367 | return _colorArray;
368 | }
369 |
370 | - (NSArray *)pieDataArray {
371 | if (!_pieDataArray) {
372 | _pieDataArray = [NSArray array];
373 | }
374 | return _pieDataArray;
375 | }
376 |
377 | - (NSArray *)pieDataNameArray {
378 | if (!_pieDataNameArray) {
379 | _pieDataNameArray = [NSArray array];
380 | }
381 | return _pieDataNameArray;
382 | }
383 |
384 | #pragma mark - other
385 | - (UIColor *)colorWithHexString:(NSString *)color {
386 | //删除字符串中的空格
387 | NSString *cString = [[color stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] uppercaseString];
388 |
389 | // String should be 6 or 8 characters
390 | if ([cString length] < 6)
391 | {
392 | return [UIColor clearColor];
393 | }
394 |
395 | // strip 0X if it appears
396 | //如果是0x开头的,那么截取字符串,字符串从索引为2的位置开始,一直到末尾
397 | if ([cString hasPrefix:@"0X"])
398 | {
399 | cString = [cString substringFromIndex:2];
400 | }
401 |
402 | //如果是#开头的,那么截取字符串,字符串从索引为1的位置开始,一直到末尾
403 | if ([cString hasPrefix:@"#"])
404 | {
405 | cString = [cString substringFromIndex:1];
406 | }
407 | if ([cString length] != 6)
408 | {
409 | return [UIColor clearColor];
410 | }
411 |
412 | // Separate into r, g, b substrings
413 | NSRange range;
414 |
415 | range.location = 0;
416 |
417 | range.length = 2;
418 |
419 | //r
420 | NSString *rString = [cString substringWithRange:range];
421 |
422 | //g
423 | range.location = 2;
424 |
425 | NSString *gString = [cString substringWithRange:range];
426 |
427 | //b
428 | range.location = 4;
429 |
430 | NSString *bString = [cString substringWithRange:range];
431 |
432 | // Scan values
433 | unsigned int r, g, b;
434 |
435 | [[NSScanner scannerWithString:rString] scanHexInt:&r];
436 |
437 | [[NSScanner scannerWithString:gString] scanHexInt:&g];
438 |
439 | [[NSScanner scannerWithString:bString] scanHexInt:&b];
440 |
441 | return [UIColor colorWithRed:((float)r / 255.0f) green:((float)g / 255.0f) blue:((float)b / 255.0f) alpha:1.0];
442 | }
443 |
444 | - (CGPoint)caculatePointAtCircleWithCenter:(CGPoint)center andAngle:(CGFloat)angle andRadius:(CGFloat)radius {
445 | CGFloat x = radius * cosf(angle * M_PI / 180);
446 | CGFloat y = radius * sinf(angle * M_PI / 180);
447 | return CGPointMake(center.x + x, center.y - y);
448 | }
449 |
450 | @end
451 |
--------------------------------------------------------------------------------
/GCChartDemo/GCChartDemo/PieChartView/PieChartView.m:
--------------------------------------------------------------------------------
1 | //
2 | // PieChartView.m
3 | // PieChartTest
4 | //
5 | // Created by 古创 on 2019/5/7.
6 | // Copyright © 2019年 chuang. All rights reserved.
7 | //
8 |
9 | #import "PieChartView.h"
10 |
11 | @interface PieChartView ()
12 |
13 | @property (nonatomic,strong) UIView *legendBgView;
14 | @property (nonatomic,strong) NSMutableArray *colorArray;
15 |
16 | @end
17 |
18 | @implementation PieChartView
19 |
20 | - (instancetype)initWithFrame:(CGRect)frame atPostiion:(LegendPosition)legendPostion withNameArray:(NSArray *)nameArray andDataArray:(NSArray *)dataArray
21 | {
22 | self = [super initWithFrame:frame];
23 | if (self) {
24 | self.isDoubleCircle = NO;
25 | self.legendPostion = legendPostion;
26 | self.legendNameArray = nameArray;
27 | self.pieDataArray = dataArray;
28 | [self config];
29 | [self resetSingleCircle];
30 | }
31 | return self;
32 | }
33 |
34 | - (instancetype)initWithFrame:(CGRect)frame atPostiion:(LegendPosition)legendPostion withNameArray:(NSArray *)nameArray andInsideDataArray:(NSArray *)insideArray andOutsideDataArray:(NSArray *)outsideArray {
35 | self = [super initWithFrame:frame];
36 | if (self) {
37 | self.isDoubleCircle = YES;
38 | self.legendPostion = legendPostion;
39 | self.legendNameArray = nameArray;
40 | self.pieInsideDataArray = insideArray;
41 | self.pieOutsideDataArray = outsideArray;
42 | [self config];
43 | [self resetDoubleCircel];
44 | }
45 | return self;
46 | }
47 |
48 | - (instancetype)initWithFrame:(CGRect)frame
49 | {
50 | self = [super initWithFrame:frame];
51 | if (self) {
52 | [self config];
53 | }
54 | return self;
55 | }
56 |
57 | - (void)config {
58 | if (self.legendColorArray.count == 0 || self.legendColorArray.count < self.legendNameArray.count) {
59 | NSArray *arr = @[@"#308ff7",@"#fbca58",@"#f5447d",@"#a020f0",@"#00ffff",@"#00ff00"];
60 | self.colorArray = [NSMutableArray arrayWithArray:arr];
61 | } else {
62 | self.colorArray = [NSMutableArray arrayWithArray:self.legendColorArray];
63 | }
64 | if (self.radius == 0) {
65 | self.radius = 60;
66 | } else if (self.radius < 40) {
67 | self.radius = 40;
68 | } else if (self.radius * 2 > MIN(self.bounds.size.width, self.bounds.size.height) - 20 - 20 * 2) {// 极端情况 半径接近宽高较小值-20的时候 需要特殊处理 此时标注有可能超出范围而不显示或显示异常
69 | self.radius = (MIN(self.bounds.size.width, self.bounds.size.height) - 20 - 20 * 2) / 2;
70 | } else {
71 |
72 | }
73 | }
74 |
75 | // 图例
76 | - (void)resetLegend {
77 | // 先移除之前创建的
78 | for (UIView *view in self.legendBgView.subviews) {
79 | [view removeFromSuperview];
80 | }
81 | self.legendBgView = nil;
82 | [self.legendBgView removeFromSuperview];
83 | if (self.legendPostion == LegendPositionNone) {// 无图例的时候
84 | self.legendBgView = nil;
85 | } else {
86 | self.legendBgView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.bounds.size.width, 20)];
87 | [self addSubview:self.legendBgView];
88 | switch (self.legendPostion) {
89 | case LegendPositionTop:
90 | self.legendBgView.center = CGPointMake(self.bounds.size.width / 2, 10);
91 | break;
92 | case LegendPositionBottom:
93 | self.legendBgView.center = CGPointMake(self.bounds.size.width / 2, self.bounds.size.height - 10);
94 | break;
95 |
96 | default:
97 | break;
98 | }
99 | for (int i = 0; i < self.legendNameArray.count; i++) {
100 | UIView *colorPoint = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 10, 10)];
101 | colorPoint.center = CGPointMake(8 + (5 + 50 + 10) * i, 10);
102 | colorPoint.backgroundColor = [self colorWithHexString:self.colorArray[i]];
103 | colorPoint.layer.cornerRadius = 5;
104 | colorPoint.layer.masksToBounds = YES;
105 | [self.legendBgView addSubview:colorPoint];
106 |
107 | UILabel *legendTitle = [[UILabel alloc] initWithFrame:CGRectMake(CGRectGetMaxX(colorPoint.frame) + 2, 0, 50, 20)];
108 | legendTitle.text = self.legendNameArray[i];
109 | legendTitle.textColor = [UIColor blackColor];
110 | legendTitle.font = [UIFont systemFontOfSize:12];
111 | [self.legendBgView addSubview:legendTitle];
112 | }
113 | }
114 | }
115 |
116 | - (void)resetSingleCircle {
117 | [self resetLegend];
118 |
119 | CGFloat pieCenterX = self.bounds.size.width / 2;
120 | CGFloat pieCenterY;
121 | if (self.legendPostion == LegendPositionTop) {
122 | pieCenterY = self.bounds.size.height / 2 + 10;
123 | } else if (self.legendPostion == LegendPositionBottom) {
124 | pieCenterY = self.bounds.size.height / 2 - 10;
125 | } else {
126 | pieCenterY = self.bounds.size.height / 2;
127 | }
128 | // 先移除之前创建的
129 | for (UIView *view in self.subviews) {
130 | if (view.tag == 101) {
131 | [view removeFromSuperview];
132 | }
133 | }
134 | UIView *pieView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.bounds.size.width, self.bounds.size.height - 20)];
135 | pieView.center = CGPointMake(pieCenterX, pieCenterY);
136 | pieView.tag = 101;
137 | pieView.backgroundColor = self.backgroundColor;//[UIColor whiteColor];
138 | [self addSubview:pieView];
139 |
140 | CGFloat radius = MAX(pieView.bounds.size.width, pieView.bounds.size.height);//pieView.bounds.size.width > pieView.bounds.size.height ? pieView.bounds.size.height / 2 : pieView.bounds.size.width / 2;
141 |
142 | // 背景
143 | UIBezierPath *bgPath = [UIBezierPath bezierPathWithArcCenter:CGPointMake(pieView.bounds.size.width / 2, pieView.bounds.size.height / 2) radius:radius / 2 startAngle:-M_PI_2 endAngle:M_PI_2 * 3 clockwise:YES];
144 | CAShapeLayer *bgLayer = [CAShapeLayer layer];
145 | bgLayer.fillColor = [UIColor clearColor].CGColor;
146 | bgLayer.strokeColor = [UIColor lightGrayColor].CGColor;
147 | bgLayer.strokeStart = 0;
148 | bgLayer.strokeEnd = 1;
149 | bgLayer.zPosition = 1;
150 | bgLayer.lineWidth = radius;
151 | bgLayer.path = bgPath.CGPath;
152 |
153 | float total = 0;
154 | for (NSString *str in self.pieDataArray) {
155 | total = total + [str floatValue];
156 | }
157 |
158 | // 标注
159 | CGFloat startAngle_p = 90;
160 | for (int i = 0; i < self.pieDataArray.count; i++) {
161 | NSString *num = self.pieDataArray[i];
162 | CGFloat angle = startAngle_p - [num floatValue] / 2 / total * 360;
163 | CGPoint pointInCenter = [self caculatePointAtCircleWithCenter:CGPointMake(pieView.bounds.size.width / 2, pieView.bounds.size.height / 2) andAngle:angle andRadius:self.radius];
164 | CGPoint pointInCenter_2 = [self caculatePointAtCircleWithCenter:CGPointMake(pieView.bounds.size.width / 2, pieView.bounds.size.height / 2) andAngle:angle andRadius:self.radius + self.radius / 6];
165 | CGPoint pointAtLabel;
166 | if (cosf(angle * M_PI / 180) >= -0.01) { // 偏右侧
167 | pointAtLabel = CGPointMake(pointInCenter_2.x + self.radius / 3, pointInCenter_2.y);
168 | } else { // 偏左侧
169 | pointAtLabel = CGPointMake(pointInCenter_2.x - self.radius / 3, pointInCenter_2.y);
170 | }
171 |
172 | UIBezierPath *linePath = [UIBezierPath bezierPath];
173 | [linePath moveToPoint:pointInCenter];
174 | [linePath addLineToPoint:pointInCenter_2];
175 | [linePath addLineToPoint:pointAtLabel];
176 |
177 | CAShapeLayer *layer = [CAShapeLayer layer];
178 | layer.lineWidth = 0.5;
179 | layer.strokeColor = [self colorWithHexString:@"#dcdcdc"].CGColor;
180 | layer.fillColor = nil;
181 | layer.path = linePath.CGPath;
182 | [pieView.layer addSublayer:layer];
183 |
184 | UILabel *lblMark = [[UILabel alloc] init];
185 | if (cosf(angle * M_PI / 180) >= -0.01) { // 偏右侧
186 | lblMark.bounds = CGRectMake(0, 0, pieView.bounds.size.width - pointAtLabel.x - 2, 12);
187 | } else { // 偏左侧
188 | lblMark.bounds = CGRectMake(0, 0, pointAtLabel.x - 2, 12);
189 | }
190 | lblMark.textColor = [self colorWithHexString:@"#404040"];
191 | lblMark.font = [UIFont systemFontOfSize:10];
192 | lblMark.numberOfLines = 2;
193 | if (self.showPercentage) {
194 | NSString *num = self.pieDataArray[i];
195 | if (self.pieDataNameArray.count == 0 || self.pieDataNameArray.count != self.pieDataArray.count) {
196 | lblMark.text = [NSString stringWithFormat:@"%.2f%%",[num floatValue] / total * 100];
197 | } else {
198 | lblMark.text = [NSString stringWithFormat:@"%@:%.2f%%",self.pieDataNameArray[i],[num floatValue] / total * 100];
199 | }
200 | } else {
201 | if (!self.pieDataUnit) {
202 | self.pieDataUnit = @"";
203 | }
204 | if (self.pieDataNameArray.count == 0 || self.pieDataNameArray.count != self.pieOutsideDataArray.count) {
205 | lblMark.text = [NSString stringWithFormat:@"%@%@",self.pieDataArray[i],self.pieDataUnit];
206 | } else {
207 | lblMark.text = [NSString stringWithFormat:@"%@:%@%@",self.pieDataNameArray[i],self.pieDataArray[i],self.pieDataUnit];
208 | }
209 | }
210 | // if (!self.pieDataUnit) {
211 | // self.pieDataUnit = @"";
212 | // }
213 | // lblMark.text = [NSString stringWithFormat:@"%@:%@%@",self.legendNameArray[i],self.pieDataArray[i],self.pieDataUnit];
214 | [lblMark sizeToFit];
215 | [pieView addSubview:lblMark];
216 | if (cosf(angle * M_PI / 180) >= -0.01) { // 偏右侧
217 | lblMark.center = CGPointMake(pointAtLabel.x + lblMark.bounds.size.width / 2 + 2, pointAtLabel.y);
218 | } else { // 偏左侧
219 | lblMark.center = CGPointMake(pointAtLabel.x - lblMark.bounds.size.width / 2 - 2, pointAtLabel.y);
220 | }
221 |
222 | startAngle_p = startAngle_p - [num floatValue] / total * 360 ;
223 | }
224 |
225 | // 子扇区
226 | UIBezierPath *piePath = [UIBezierPath bezierPathWithArcCenter:CGPointMake(pieView.bounds.size.width / 2, pieView.bounds.size.height / 2) radius:radius startAngle:-M_PI_2 endAngle:M_PI_2 * 3 clockwise:YES];
227 | // CGFloat start = 0;
228 | // CGFloat end = 0;
229 | CGFloat startAngle = -M_PI_2;
230 | for (int i = 0; i < self.pieDataArray.count; i++) {
231 | NSString *num = self.pieDataArray[i];
232 |
233 | UIBezierPath *path = [UIBezierPath bezierPath];
234 | [path addArcWithCenter:CGPointMake(pieView.bounds.size.width / 2, pieView.bounds.size.height / 2) radius:self.radius startAngle:startAngle endAngle:startAngle + [num floatValue] / total * M_PI * 2 clockwise:YES];
235 | // path.lineWidth = 10;// 线宽与半径相同
236 | [path addLineToPoint:CGPointMake(pieView.bounds.size.width / 2, pieView.bounds.size.height / 2)];// 圆心
237 | [[self colorWithHexString:self.colorArray[i]] setStroke];
238 | [[self colorWithHexString:self.colorArray[i]] setFill];
239 | [path stroke];
240 | [path fill];
241 |
242 | CAShapeLayer *layer = [CAShapeLayer layer];
243 | layer.path = path.CGPath;
244 | // layer.lineWidth = 30;
245 | layer.strokeColor = [UIColor whiteColor].CGColor; // 描边颜色
246 | layer.fillColor = [self colorWithHexString:self.colorArray[i]].CGColor; // 背景填充色
247 | [pieView.layer addSublayer:layer];
248 |
249 | startAngle = startAngle + [num floatValue] / total * M_PI * 2 ;
250 | }
251 | pieView.layer.mask = bgLayer;
252 |
253 | // 动画
254 | CABasicAnimation *strokeAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
255 | strokeAnimation.fromValue = @0;// 起始值
256 | strokeAnimation.toValue = @1;// 结束值
257 | strokeAnimation.duration = 1;// 动画持续时间
258 | strokeAnimation.repeatCount = 1;// 重复次数
259 | strokeAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
260 | strokeAnimation.removedOnCompletion = YES;
261 | [bgLayer addAnimation:strokeAnimation forKey:@"pieAnimation"];
262 | }
263 |
264 | - (void)resetDoubleCircel {
265 | [self resetLegend];
266 |
267 | // 饼图
268 | CGFloat pieCenterX = self.bounds.size.width / 2;
269 | CGFloat pieCenterY;
270 | if (self.legendPostion == LegendPositionTop) {
271 | pieCenterY = self.bounds.size.height / 2 + 10;
272 | } else if (self.legendPostion == LegendPositionBottom) {
273 | pieCenterY = self.bounds.size.height / 2 - 10;
274 | } else {
275 | pieCenterY = self.bounds.size.height / 2;
276 | }
277 | // 先移除之前创建的
278 | for (UIView *view in self.subviews) {
279 | if (view.tag == 101) {
280 | [view removeFromSuperview];
281 | }
282 | }
283 | UIView *pieView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.bounds.size.width, self.bounds.size.height - 20)];
284 | pieView.center = CGPointMake(pieCenterX, pieCenterY);
285 | pieView.tag = 101;
286 | pieView.backgroundColor = self.backgroundColor;//[UIColor whiteColor];
287 | [self addSubview:pieView];
288 |
289 | CGFloat radius = MAX(pieView.bounds.size.width, pieView.bounds.size.height);//pieView.bounds.size.width > pieView.bounds.size.height ? pieView.bounds.size.height / 2 : pieView.bounds.size.width / 2;
290 |
291 | // 背景
292 | UIBezierPath *bgPath = [UIBezierPath bezierPathWithArcCenter:CGPointMake(pieView.bounds.size.width / 2, pieView.bounds.size.height / 2) radius:radius / 2 startAngle:-M_PI_2 endAngle:M_PI_2 * 3 clockwise:YES];
293 | CAShapeLayer *bgLayer = [CAShapeLayer layer];
294 | bgLayer.fillColor = [UIColor clearColor].CGColor;
295 | bgLayer.strokeColor = [UIColor lightGrayColor].CGColor;
296 | bgLayer.strokeStart = 0;
297 | bgLayer.strokeEnd = 1;
298 | bgLayer.zPosition = 1;
299 | bgLayer.lineWidth = radius;
300 | bgLayer.path = bgPath.CGPath;
301 |
302 | // 内圈
303 | int insideTotal = 0;
304 | for (NSString *str in self.pieInsideDataArray) {
305 | insideTotal = insideTotal + [str floatValue];
306 | }
307 | CGFloat startAngle = 1.5 * M_PI;
308 | for (int i = 0; i < self.pieInsideDataArray.count; i++) {
309 | NSString *num = self.pieInsideDataArray[i];
310 |
311 | UIBezierPath *path = [UIBezierPath bezierPath];
312 | [path addArcWithCenter:CGPointMake(pieView.bounds.size.width / 2, pieView.bounds.size.height / 2) radius:self.radius / 2 startAngle:startAngle endAngle:startAngle + [num floatValue] / insideTotal * M_PI * 2 clockwise:YES];
313 | // path.lineWidth = 10;// 线宽与半径相同
314 | if (!self.isDoubleCircle) {
315 | [path addLineToPoint:CGPointMake(pieView.bounds.size.width / 2, pieView.bounds.size.height / 2)];// 圆心
316 | }
317 | [[self colorWithHexString:self.colorArray[i]] setStroke];
318 | [[self colorWithHexString:self.colorArray[i]] setFill];
319 | [path stroke];
320 | [path fill];
321 |
322 | CAShapeLayer *layer = [CAShapeLayer layer];
323 | layer.path = path.CGPath;
324 | layer.lineWidth = self.radius / 2;
325 | layer.strokeColor = [self colorWithHexString:self.colorArray[i]].CGColor; // 描边颜色
326 | layer.fillColor = [UIColor clearColor].CGColor; // 背景填充色
327 | [pieView.layer addSublayer:layer];
328 |
329 | startAngle = startAngle + [num floatValue] / insideTotal * M_PI * 2 ;
330 |
331 | // 动画
332 | // CABasicAnimation *strokeAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
333 | // strokeAnimation.fromValue = @0;// 起始值
334 | // strokeAnimation.toValue = @1;// 结束值
335 | // strokeAnimation.duration = 0.5;// 动画持续时间
336 | // strokeAnimation.repeatCount = 1;// 重复次数
337 | // [layer addAnimation:strokeAnimation forKey:@"pieAnimation"];
338 | }
339 |
340 | int outsideTotal = 0;
341 | for (NSString *str in self.pieOutsideDataArray) {
342 | outsideTotal = outsideTotal + [str floatValue];
343 | }
344 |
345 | // 外圈
346 | startAngle = 1.5 * M_PI;
347 | for (int i = 0; i < self.pieOutsideDataArray.count; i++) {
348 | NSString *num = self.pieOutsideDataArray[i];
349 |
350 | UIBezierPath *path = [UIBezierPath bezierPath];
351 | [path addArcWithCenter:CGPointMake(pieView.bounds.size.width / 2, pieView.bounds.size.height / 2) radius:self.radius startAngle:startAngle endAngle:startAngle + [num floatValue] / outsideTotal * M_PI * 2 clockwise:YES];
352 | // path.lineWidth = 10;// 线宽与半径相同
353 | // [path addLineToPoint:pieView.center];
354 | [[self colorWithHexString:self.colorArray[i]] setStroke];
355 | [[self colorWithHexString:self.colorArray[i]] setFill];
356 | [path stroke];
357 | [path fill];
358 |
359 | CAShapeLayer *layer = [CAShapeLayer layer];
360 | layer.path = path.CGPath;
361 | layer.lineWidth = self.radius / 6;
362 | layer.strokeColor = [self colorWithHexString:self.colorArray[i]].CGColor; // 圆环颜色
363 | layer.fillColor = [UIColor clearColor].CGColor; // 背景填充色
364 | // layer.backgroundColor = [self colorWithHexString:self.colorArray[i]].CGColor;
365 | [pieView.layer addSublayer:layer];
366 |
367 | startAngle = startAngle + [num floatValue] / outsideTotal * M_PI * 2 ;
368 |
369 | }
370 |
371 | // 外圈标注
372 | CGFloat startAngle_p = 90;
373 | for (int i = 0; i < self.pieOutsideDataArray.count; i++) {
374 | NSString *num = self.pieOutsideDataArray[i];
375 | CGFloat angle = startAngle_p - [num floatValue] / 2 / outsideTotal * 360;
376 | CGPoint pointInCenter = [self caculatePointAtCircleWithCenter:CGPointMake(pieView.bounds.size.width / 2, pieView.bounds.size.height / 2) andAngle:angle andRadius:self.radius+ self.radius / 12];
377 | CGPoint pointInCenter_2 = [self caculatePointAtCircleWithCenter:CGPointMake(pieView.bounds.size.width / 2, pieView.bounds.size.height / 2) andAngle:angle andRadius:self.radius + self.radius / 12 + self.radius / 6];
378 | CGPoint pointAtLabel;
379 | if (cosf(angle * M_PI / 180) >= -0.01) { // 偏右侧
380 | pointAtLabel = CGPointMake(pointInCenter_2.x + self.radius / 3, pointInCenter_2.y);
381 | } else { // 偏左侧
382 | pointAtLabel = CGPointMake(pointInCenter_2.x - self.radius / 3, pointInCenter_2.y);
383 | }
384 |
385 | UIBezierPath *linePath = [UIBezierPath bezierPath];
386 | [linePath moveToPoint:pointInCenter];
387 | [linePath addLineToPoint:pointInCenter_2];
388 | [linePath addLineToPoint:pointAtLabel];
389 |
390 | CAShapeLayer *layer = [CAShapeLayer layer];
391 | layer.lineWidth = 0.5;
392 | layer.strokeColor = [self colorWithHexString:@"#dcdcdc"].CGColor;
393 | layer.fillColor = nil;
394 | layer.path = linePath.CGPath;
395 | [pieView.layer addSublayer:layer];
396 |
397 | UILabel *lblMark = [[UILabel alloc] init];
398 | if (cosf(angle * M_PI / 180) >= -0.01) { // 偏右侧
399 | lblMark.bounds = CGRectMake(0, 0, pieView.bounds.size.width - pointAtLabel.x - 2, 12);
400 | } else { // 偏左侧
401 | lblMark.bounds = CGRectMake(0, 0, pointAtLabel.x - 2, 12);
402 | }
403 | lblMark.textColor = [self colorWithHexString:@"#404040"];
404 | lblMark.font = [UIFont systemFontOfSize:10];
405 | lblMark.numberOfLines = 2;
406 | if (self.showPercentage) {
407 | NSString *num = self.pieOutsideDataArray[i];
408 | if (self.pieDataNameArray.count == 0 || self.pieDataNameArray.count != self.pieOutsideDataArray.count) {
409 | lblMark.text = [NSString stringWithFormat:@"%.2f%%",[num floatValue] / outsideTotal * 100];
410 | } else {
411 | lblMark.text = [NSString stringWithFormat:@"%@:%.2f%%",self.pieDataNameArray[i],[num floatValue] / outsideTotal * 100];
412 | }
413 | } else {
414 | if (!self.pieDataUnit) {
415 | self.pieDataUnit = @"";
416 | }
417 | if (self.pieDataNameArray.count == 0 || self.pieDataNameArray.count != self.pieOutsideDataArray.count) {
418 | lblMark.text = [NSString stringWithFormat:@"%@%@",self.pieOutsideDataArray[i],self.pieDataUnit];
419 | } else {
420 | lblMark.text = [NSString stringWithFormat:@"%@:%@%@",self.pieDataNameArray[i],self.pieOutsideDataArray[i],self.pieDataUnit];
421 | }
422 | }
423 |
424 | [lblMark sizeToFit];
425 | [pieView addSubview:lblMark];
426 | if (cosf(angle * M_PI / 180) >= -0.01) { // 偏右侧
427 | lblMark.center = CGPointMake(pointAtLabel.x + lblMark.bounds.size.width / 2 + 2, pointAtLabel.y);
428 | } else { // 偏左侧
429 | lblMark.center = CGPointMake(pointAtLabel.x - lblMark.bounds.size.width / 2 - 2, pointAtLabel.y);
430 | }
431 |
432 | startAngle_p = startAngle_p - [num floatValue] / outsideTotal * 360 ;
433 | }
434 |
435 | pieView.layer.mask = bgLayer;
436 | // 动画
437 | CABasicAnimation *strokeAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
438 | strokeAnimation.fromValue = @0;// 起始值
439 | strokeAnimation.toValue = @1;// 结束值
440 | strokeAnimation.duration = 1;// 动画持续时间
441 | strokeAnimation.repeatCount = 1;// 重复次数
442 | strokeAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
443 | strokeAnimation.removedOnCompletion = YES;
444 | [bgLayer addAnimation:strokeAnimation forKey:@"pieAnimation"];
445 |
446 | }
447 |
448 | - (void)resetDataLabel {
449 | if (self.isDoubleCircle) {// 双层
450 |
451 | } else {// 单层
452 | float total = 0;
453 | for (NSString *str in self.pieDataArray) {
454 | total = total + [str floatValue];
455 | }
456 | UIView *pieView;
457 | for (UIView *view in self.subviews) {
458 | if (view.tag == 101) {
459 | pieView = view;
460 | }
461 | }
462 | CGFloat startAngle_p = 90;
463 | for (int i = 0; i < self.pieDataArray.count; i++) {
464 | NSString *num = self.pieDataArray[i];
465 | CGFloat angle = startAngle_p - [num floatValue] / 2 / total * 360;
466 | CGPoint pointInCenter = [self caculatePointAtCircleWithCenter:CGPointMake(pieView.bounds.size.width / 2, pieView.center.y) andAngle:angle andRadius:self.radius];
467 | CGPoint pointInCenter_2 = [self caculatePointAtCircleWithCenter:CGPointMake(pieView.bounds.size.width / 2, pieView.center.y) andAngle:angle andRadius:self.radius + 5];
468 |
469 | UIBezierPath *linePath = [UIBezierPath bezierPath];
470 | [linePath moveToPoint:pointInCenter];
471 | [linePath addLineToPoint:pointInCenter_2];
472 |
473 | CAShapeLayer *layer = [CAShapeLayer layer];
474 | layer.lineWidth = 0.5;
475 | layer.strokeColor = [UIColor lightGrayColor].CGColor;
476 | layer.path = linePath.CGPath;
477 | [pieView.layer addSublayer:layer];
478 |
479 | startAngle_p = startAngle_p - [num floatValue] / total * 360 ;
480 | }
481 | }
482 | }
483 |
484 | #pragma mark - resetData
485 | - (void)resetData {
486 | [self config];
487 | if (self.isDoubleCircle) {
488 | [self resetDoubleCircel];
489 | } else {
490 | [self resetSingleCircle];
491 | }
492 | }
493 |
494 |
495 | #pragma mark - getter
496 | - (NSArray *)legendNameArray {
497 | if (!_legendNameArray) {
498 | _legendNameArray = [NSArray array];
499 | }
500 | return _legendNameArray;
501 | }
502 |
503 | - (NSArray *)legendColorArray {
504 | if (!_legendColorArray) {
505 | _legendColorArray = [NSArray array];
506 | }
507 | return _legendColorArray;
508 | }
509 |
510 | - (NSMutableArray *)colorArray {
511 | if (!_colorArray) {
512 | _colorArray = [NSMutableArray array];
513 | }
514 | return _colorArray;
515 | }
516 |
517 | - (NSArray *)pieDataArray {
518 | if (!_pieDataArray) {
519 | _pieDataArray = [NSArray array];
520 | }
521 | return _pieDataArray;
522 | }
523 |
524 | - (NSArray *)pieInsideDataArray {
525 | if (!_pieInsideDataArray) {
526 | _pieInsideDataArray = [NSArray array];
527 | }
528 | return _pieInsideDataArray;
529 | }
530 |
531 | - (NSArray *)pieOutsideDataArray {
532 | if (!_pieOutsideDataArray) {
533 | _pieOutsideDataArray = [NSArray array];
534 | }
535 | return _pieOutsideDataArray;
536 | }
537 |
538 | - (NSArray *)pieDataNameArray {
539 | if (!_pieDataNameArray) {
540 | _pieDataNameArray = [NSArray array];
541 | }
542 | return _pieDataNameArray;
543 | }
544 |
545 | #pragma mark - other
546 | - (UIColor *)colorWithHexString:(NSString *)color {
547 | //删除字符串中的空格
548 | NSString *cString = [[color stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] uppercaseString];
549 |
550 | // String should be 6 or 8 characters
551 | if ([cString length] < 6)
552 | {
553 | return [UIColor clearColor];
554 | }
555 |
556 | // strip 0X if it appears
557 | //如果是0x开头的,那么截取字符串,字符串从索引为2的位置开始,一直到末尾
558 | if ([cString hasPrefix:@"0X"])
559 | {
560 | cString = [cString substringFromIndex:2];
561 | }
562 |
563 | //如果是#开头的,那么截取字符串,字符串从索引为1的位置开始,一直到末尾
564 | if ([cString hasPrefix:@"#"])
565 | {
566 | cString = [cString substringFromIndex:1];
567 | }
568 | if ([cString length] != 6)
569 | {
570 | return [UIColor clearColor];
571 | }
572 |
573 | // Separate into r, g, b substrings
574 | NSRange range;
575 |
576 | range.location = 0;
577 |
578 | range.length = 2;
579 |
580 | //r
581 | NSString *rString = [cString substringWithRange:range];
582 |
583 | //g
584 | range.location = 2;
585 |
586 | NSString *gString = [cString substringWithRange:range];
587 |
588 | //b
589 | range.location = 4;
590 |
591 | NSString *bString = [cString substringWithRange:range];
592 |
593 | // Scan values
594 | unsigned int r, g, b;
595 |
596 | [[NSScanner scannerWithString:rString] scanHexInt:&r];
597 |
598 | [[NSScanner scannerWithString:gString] scanHexInt:&g];
599 |
600 | [[NSScanner scannerWithString:bString] scanHexInt:&b];
601 |
602 | return [UIColor colorWithRed:((float)r / 255.0f) green:((float)g / 255.0f) blue:((float)b / 255.0f) alpha:1.0];
603 | }
604 |
605 | - (CGPoint)caculatePointAtCircleWithCenter:(CGPoint)center andAngle:(CGFloat)angle andRadius:(CGFloat)radius {
606 | CGFloat x = radius * cosf(angle * M_PI / 180);
607 | CGFloat y = radius * sinf(angle * M_PI / 180);
608 | return CGPointMake(center.x + x, center.y - y);
609 | }
610 |
611 | @end
612 |
--------------------------------------------------------------------------------
/GCChartDemo/GCChartDemo.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 50;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 3D42BDCF22896D1E00D72864 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 3D42BDCE22896D1E00D72864 /* AppDelegate.m */; };
11 | 3D42BDD222896D1E00D72864 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3D42BDD122896D1E00D72864 /* ViewController.m */; };
12 | 3D42BDD522896D1E00D72864 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 3D42BDD322896D1E00D72864 /* Main.storyboard */; };
13 | 3D42BDD722896D2100D72864 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 3D42BDD622896D2100D72864 /* Assets.xcassets */; };
14 | 3D42BDDA22896D2100D72864 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 3D42BDD822896D2100D72864 /* LaunchScreen.storyboard */; };
15 | 3D42BDDD22896D2100D72864 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 3D42BDDC22896D2100D72864 /* main.m */; };
16 | 3D42BDE722896D2100D72864 /* GCChartDemoTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 3D42BDE622896D2100D72864 /* GCChartDemoTests.m */; };
17 | 3D42BDF222896D2100D72864 /* GCChartDemoUITests.m in Sources */ = {isa = PBXBuildFile; fileRef = 3D42BDF122896D2100D72864 /* GCChartDemoUITests.m */; };
18 | 3D42BE0522896D6200D72864 /* ColumnChartView.m in Sources */ = {isa = PBXBuildFile; fileRef = 3D42BE0122896D6200D72864 /* ColumnChartView.m */; };
19 | 3D42BE0622896D6200D72864 /* PieChartView.m in Sources */ = {isa = PBXBuildFile; fileRef = 3D42BE0422896D6200D72864 /* PieChartView.m */; };
20 | 3D42BE0922896D9E00D72864 /* ColumnChartViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3D42BE0822896D9E00D72864 /* ColumnChartViewController.m */; };
21 | 3D42BE0C22896DB400D72864 /* PieChartViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3D42BE0B22896DB400D72864 /* PieChartViewController.m */; };
22 | 3D4701B722A756250056F888 /* CircleRingChartView.m in Sources */ = {isa = PBXBuildFile; fileRef = 3D4701B622A756250056F888 /* CircleRingChartView.m */; };
23 | 3D4701BA22A75AD70056F888 /* CircleRingChartViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3D4701B922A75AD70056F888 /* CircleRingChartViewController.m */; };
24 | 3D4C77DA22C9E39B00474E2C /* NegativeColumnChartViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3D4C77D922C9E39B00474E2C /* NegativeColumnChartViewController.m */; };
25 | 3D51336D228BA81E0066E3AA /* LineChartView.m in Sources */ = {isa = PBXBuildFile; fileRef = 3D51336C228BA81E0066E3AA /* LineChartView.m */; };
26 | 3D513370228BA8440066E3AA /* LineChartViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3D51336E228BA8430066E3AA /* LineChartViewController.m */; };
27 | /* End PBXBuildFile section */
28 |
29 | /* Begin PBXContainerItemProxy section */
30 | 3D42BDE322896D2100D72864 /* PBXContainerItemProxy */ = {
31 | isa = PBXContainerItemProxy;
32 | containerPortal = 3D42BDC222896D1E00D72864 /* Project object */;
33 | proxyType = 1;
34 | remoteGlobalIDString = 3D42BDC922896D1E00D72864;
35 | remoteInfo = GCChartDemo;
36 | };
37 | 3D42BDEE22896D2100D72864 /* PBXContainerItemProxy */ = {
38 | isa = PBXContainerItemProxy;
39 | containerPortal = 3D42BDC222896D1E00D72864 /* Project object */;
40 | proxyType = 1;
41 | remoteGlobalIDString = 3D42BDC922896D1E00D72864;
42 | remoteInfo = GCChartDemo;
43 | };
44 | /* End PBXContainerItemProxy section */
45 |
46 | /* Begin PBXFileReference section */
47 | 3D42BDCA22896D1E00D72864 /* GCChartDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = GCChartDemo.app; sourceTree = BUILT_PRODUCTS_DIR; };
48 | 3D42BDCD22896D1E00D72864 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; };
49 | 3D42BDCE22896D1E00D72864 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; };
50 | 3D42BDD022896D1E00D72864 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; };
51 | 3D42BDD122896D1E00D72864 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; };
52 | 3D42BDD422896D1E00D72864 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
53 | 3D42BDD622896D2100D72864 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
54 | 3D42BDD922896D2100D72864 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
55 | 3D42BDDB22896D2100D72864 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
56 | 3D42BDDC22896D2100D72864 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; };
57 | 3D42BDE222896D2100D72864 /* GCChartDemoTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = GCChartDemoTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
58 | 3D42BDE622896D2100D72864 /* GCChartDemoTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GCChartDemoTests.m; sourceTree = ""; };
59 | 3D42BDE822896D2100D72864 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
60 | 3D42BDED22896D2100D72864 /* GCChartDemoUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = GCChartDemoUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
61 | 3D42BDF122896D2100D72864 /* GCChartDemoUITests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GCChartDemoUITests.m; sourceTree = ""; };
62 | 3D42BDF322896D2100D72864 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
63 | 3D42BE0022896D6200D72864 /* ColumnChartView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ColumnChartView.h; sourceTree = ""; };
64 | 3D42BE0122896D6200D72864 /* ColumnChartView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ColumnChartView.m; sourceTree = ""; };
65 | 3D42BE0322896D6200D72864 /* PieChartView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PieChartView.h; sourceTree = ""; };
66 | 3D42BE0422896D6200D72864 /* PieChartView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PieChartView.m; sourceTree = ""; };
67 | 3D42BE0722896D9E00D72864 /* ColumnChartViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ColumnChartViewController.h; sourceTree = ""; };
68 | 3D42BE0822896D9E00D72864 /* ColumnChartViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ColumnChartViewController.m; sourceTree = ""; };
69 | 3D42BE0A22896DB400D72864 /* PieChartViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PieChartViewController.h; sourceTree = ""; };
70 | 3D42BE0B22896DB400D72864 /* PieChartViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PieChartViewController.m; sourceTree = ""; };
71 | 3D4701B522A756250056F888 /* CircleRingChartView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CircleRingChartView.h; sourceTree = ""; };
72 | 3D4701B622A756250056F888 /* CircleRingChartView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CircleRingChartView.m; sourceTree = ""; };
73 | 3D4701B822A75AD70056F888 /* CircleRingChartViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CircleRingChartViewController.h; sourceTree = ""; };
74 | 3D4701B922A75AD70056F888 /* CircleRingChartViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CircleRingChartViewController.m; sourceTree = ""; };
75 | 3D4C77D822C9E39B00474E2C /* NegativeColumnChartViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = NegativeColumnChartViewController.h; sourceTree = ""; };
76 | 3D4C77D922C9E39B00474E2C /* NegativeColumnChartViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = NegativeColumnChartViewController.m; sourceTree = ""; };
77 | 3D51336B228BA81E0066E3AA /* LineChartView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LineChartView.h; sourceTree = ""; };
78 | 3D51336C228BA81E0066E3AA /* LineChartView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LineChartView.m; sourceTree = ""; };
79 | 3D51336E228BA8430066E3AA /* LineChartViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LineChartViewController.m; sourceTree = ""; };
80 | 3D51336F228BA8440066E3AA /* LineChartViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LineChartViewController.h; sourceTree = ""; };
81 | /* End PBXFileReference section */
82 |
83 | /* Begin PBXFrameworksBuildPhase section */
84 | 3D42BDC722896D1E00D72864 /* Frameworks */ = {
85 | isa = PBXFrameworksBuildPhase;
86 | buildActionMask = 2147483647;
87 | files = (
88 | );
89 | runOnlyForDeploymentPostprocessing = 0;
90 | };
91 | 3D42BDDF22896D2100D72864 /* Frameworks */ = {
92 | isa = PBXFrameworksBuildPhase;
93 | buildActionMask = 2147483647;
94 | files = (
95 | );
96 | runOnlyForDeploymentPostprocessing = 0;
97 | };
98 | 3D42BDEA22896D2100D72864 /* Frameworks */ = {
99 | isa = PBXFrameworksBuildPhase;
100 | buildActionMask = 2147483647;
101 | files = (
102 | );
103 | runOnlyForDeploymentPostprocessing = 0;
104 | };
105 | /* End PBXFrameworksBuildPhase section */
106 |
107 | /* Begin PBXGroup section */
108 | 3D42BDC122896D1E00D72864 = {
109 | isa = PBXGroup;
110 | children = (
111 | 3D42BDCC22896D1E00D72864 /* GCChartDemo */,
112 | 3D42BDE522896D2100D72864 /* GCChartDemoTests */,
113 | 3D42BDF022896D2100D72864 /* GCChartDemoUITests */,
114 | 3D42BDCB22896D1E00D72864 /* Products */,
115 | );
116 | sourceTree = "";
117 | };
118 | 3D42BDCB22896D1E00D72864 /* Products */ = {
119 | isa = PBXGroup;
120 | children = (
121 | 3D42BDCA22896D1E00D72864 /* GCChartDemo.app */,
122 | 3D42BDE222896D2100D72864 /* GCChartDemoTests.xctest */,
123 | 3D42BDED22896D2100D72864 /* GCChartDemoUITests.xctest */,
124 | );
125 | name = Products;
126 | sourceTree = "";
127 | };
128 | 3D42BDCC22896D1E00D72864 /* GCChartDemo */ = {
129 | isa = PBXGroup;
130 | children = (
131 | 3D42BDFF22896D6200D72864 /* ColumnChartView */,
132 | 3D42BE0222896D6200D72864 /* PieChartView */,
133 | 3D51336A228BA81E0066E3AA /* LineChartView */,
134 | 3D42BDCD22896D1E00D72864 /* AppDelegate.h */,
135 | 3D42BDCE22896D1E00D72864 /* AppDelegate.m */,
136 | 3D42BDD022896D1E00D72864 /* ViewController.h */,
137 | 3D42BDD122896D1E00D72864 /* ViewController.m */,
138 | 3D42BE0722896D9E00D72864 /* ColumnChartViewController.h */,
139 | 3D42BE0822896D9E00D72864 /* ColumnChartViewController.m */,
140 | 3D42BE0A22896DB400D72864 /* PieChartViewController.h */,
141 | 3D42BE0B22896DB400D72864 /* PieChartViewController.m */,
142 | 3D51336F228BA8440066E3AA /* LineChartViewController.h */,
143 | 3D51336E228BA8430066E3AA /* LineChartViewController.m */,
144 | 3D4701B822A75AD70056F888 /* CircleRingChartViewController.h */,
145 | 3D4701B922A75AD70056F888 /* CircleRingChartViewController.m */,
146 | 3D4C77D822C9E39B00474E2C /* NegativeColumnChartViewController.h */,
147 | 3D4C77D922C9E39B00474E2C /* NegativeColumnChartViewController.m */,
148 | 3D42BDD322896D1E00D72864 /* Main.storyboard */,
149 | 3D42BDD622896D2100D72864 /* Assets.xcassets */,
150 | 3D42BDD822896D2100D72864 /* LaunchScreen.storyboard */,
151 | 3D42BDDB22896D2100D72864 /* Info.plist */,
152 | 3D42BDDC22896D2100D72864 /* main.m */,
153 | );
154 | path = GCChartDemo;
155 | sourceTree = "";
156 | };
157 | 3D42BDE522896D2100D72864 /* GCChartDemoTests */ = {
158 | isa = PBXGroup;
159 | children = (
160 | 3D42BDE622896D2100D72864 /* GCChartDemoTests.m */,
161 | 3D42BDE822896D2100D72864 /* Info.plist */,
162 | );
163 | path = GCChartDemoTests;
164 | sourceTree = "";
165 | };
166 | 3D42BDF022896D2100D72864 /* GCChartDemoUITests */ = {
167 | isa = PBXGroup;
168 | children = (
169 | 3D42BDF122896D2100D72864 /* GCChartDemoUITests.m */,
170 | 3D42BDF322896D2100D72864 /* Info.plist */,
171 | );
172 | path = GCChartDemoUITests;
173 | sourceTree = "";
174 | };
175 | 3D42BDFF22896D6200D72864 /* ColumnChartView */ = {
176 | isa = PBXGroup;
177 | children = (
178 | 3D42BE0022896D6200D72864 /* ColumnChartView.h */,
179 | 3D42BE0122896D6200D72864 /* ColumnChartView.m */,
180 | );
181 | path = ColumnChartView;
182 | sourceTree = "";
183 | };
184 | 3D42BE0222896D6200D72864 /* PieChartView */ = {
185 | isa = PBXGroup;
186 | children = (
187 | 3D42BE0322896D6200D72864 /* PieChartView.h */,
188 | 3D42BE0422896D6200D72864 /* PieChartView.m */,
189 | 3D4701B522A756250056F888 /* CircleRingChartView.h */,
190 | 3D4701B622A756250056F888 /* CircleRingChartView.m */,
191 | );
192 | path = PieChartView;
193 | sourceTree = "";
194 | };
195 | 3D51336A228BA81E0066E3AA /* LineChartView */ = {
196 | isa = PBXGroup;
197 | children = (
198 | 3D51336B228BA81E0066E3AA /* LineChartView.h */,
199 | 3D51336C228BA81E0066E3AA /* LineChartView.m */,
200 | );
201 | path = LineChartView;
202 | sourceTree = "";
203 | };
204 | /* End PBXGroup section */
205 |
206 | /* Begin PBXNativeTarget section */
207 | 3D42BDC922896D1E00D72864 /* GCChartDemo */ = {
208 | isa = PBXNativeTarget;
209 | buildConfigurationList = 3D42BDF622896D2100D72864 /* Build configuration list for PBXNativeTarget "GCChartDemo" */;
210 | buildPhases = (
211 | 3D42BDC622896D1E00D72864 /* Sources */,
212 | 3D42BDC722896D1E00D72864 /* Frameworks */,
213 | 3D42BDC822896D1E00D72864 /* Resources */,
214 | );
215 | buildRules = (
216 | );
217 | dependencies = (
218 | );
219 | name = GCChartDemo;
220 | productName = GCChartDemo;
221 | productReference = 3D42BDCA22896D1E00D72864 /* GCChartDemo.app */;
222 | productType = "com.apple.product-type.application";
223 | };
224 | 3D42BDE122896D2100D72864 /* GCChartDemoTests */ = {
225 | isa = PBXNativeTarget;
226 | buildConfigurationList = 3D42BDF922896D2100D72864 /* Build configuration list for PBXNativeTarget "GCChartDemoTests" */;
227 | buildPhases = (
228 | 3D42BDDE22896D2100D72864 /* Sources */,
229 | 3D42BDDF22896D2100D72864 /* Frameworks */,
230 | 3D42BDE022896D2100D72864 /* Resources */,
231 | );
232 | buildRules = (
233 | );
234 | dependencies = (
235 | 3D42BDE422896D2100D72864 /* PBXTargetDependency */,
236 | );
237 | name = GCChartDemoTests;
238 | productName = GCChartDemoTests;
239 | productReference = 3D42BDE222896D2100D72864 /* GCChartDemoTests.xctest */;
240 | productType = "com.apple.product-type.bundle.unit-test";
241 | };
242 | 3D42BDEC22896D2100D72864 /* GCChartDemoUITests */ = {
243 | isa = PBXNativeTarget;
244 | buildConfigurationList = 3D42BDFC22896D2100D72864 /* Build configuration list for PBXNativeTarget "GCChartDemoUITests" */;
245 | buildPhases = (
246 | 3D42BDE922896D2100D72864 /* Sources */,
247 | 3D42BDEA22896D2100D72864 /* Frameworks */,
248 | 3D42BDEB22896D2100D72864 /* Resources */,
249 | );
250 | buildRules = (
251 | );
252 | dependencies = (
253 | 3D42BDEF22896D2100D72864 /* PBXTargetDependency */,
254 | );
255 | name = GCChartDemoUITests;
256 | productName = GCChartDemoUITests;
257 | productReference = 3D42BDED22896D2100D72864 /* GCChartDemoUITests.xctest */;
258 | productType = "com.apple.product-type.bundle.ui-testing";
259 | };
260 | /* End PBXNativeTarget section */
261 |
262 | /* Begin PBXProject section */
263 | 3D42BDC222896D1E00D72864 /* Project object */ = {
264 | isa = PBXProject;
265 | attributes = {
266 | LastUpgradeCheck = 1010;
267 | ORGANIZATIONNAME = GC;
268 | TargetAttributes = {
269 | 3D42BDC922896D1E00D72864 = {
270 | CreatedOnToolsVersion = 10.1;
271 | };
272 | 3D42BDE122896D2100D72864 = {
273 | CreatedOnToolsVersion = 10.1;
274 | TestTargetID = 3D42BDC922896D1E00D72864;
275 | };
276 | 3D42BDEC22896D2100D72864 = {
277 | CreatedOnToolsVersion = 10.1;
278 | TestTargetID = 3D42BDC922896D1E00D72864;
279 | };
280 | };
281 | };
282 | buildConfigurationList = 3D42BDC522896D1E00D72864 /* Build configuration list for PBXProject "GCChartDemo" */;
283 | compatibilityVersion = "Xcode 9.3";
284 | developmentRegion = en;
285 | hasScannedForEncodings = 0;
286 | knownRegions = (
287 | en,
288 | Base,
289 | );
290 | mainGroup = 3D42BDC122896D1E00D72864;
291 | productRefGroup = 3D42BDCB22896D1E00D72864 /* Products */;
292 | projectDirPath = "";
293 | projectRoot = "";
294 | targets = (
295 | 3D42BDC922896D1E00D72864 /* GCChartDemo */,
296 | 3D42BDE122896D2100D72864 /* GCChartDemoTests */,
297 | 3D42BDEC22896D2100D72864 /* GCChartDemoUITests */,
298 | );
299 | };
300 | /* End PBXProject section */
301 |
302 | /* Begin PBXResourcesBuildPhase section */
303 | 3D42BDC822896D1E00D72864 /* Resources */ = {
304 | isa = PBXResourcesBuildPhase;
305 | buildActionMask = 2147483647;
306 | files = (
307 | 3D42BDDA22896D2100D72864 /* LaunchScreen.storyboard in Resources */,
308 | 3D42BDD722896D2100D72864 /* Assets.xcassets in Resources */,
309 | 3D42BDD522896D1E00D72864 /* Main.storyboard in Resources */,
310 | );
311 | runOnlyForDeploymentPostprocessing = 0;
312 | };
313 | 3D42BDE022896D2100D72864 /* Resources */ = {
314 | isa = PBXResourcesBuildPhase;
315 | buildActionMask = 2147483647;
316 | files = (
317 | );
318 | runOnlyForDeploymentPostprocessing = 0;
319 | };
320 | 3D42BDEB22896D2100D72864 /* Resources */ = {
321 | isa = PBXResourcesBuildPhase;
322 | buildActionMask = 2147483647;
323 | files = (
324 | );
325 | runOnlyForDeploymentPostprocessing = 0;
326 | };
327 | /* End PBXResourcesBuildPhase section */
328 |
329 | /* Begin PBXSourcesBuildPhase section */
330 | 3D42BDC622896D1E00D72864 /* Sources */ = {
331 | isa = PBXSourcesBuildPhase;
332 | buildActionMask = 2147483647;
333 | files = (
334 | 3D42BDD222896D1E00D72864 /* ViewController.m in Sources */,
335 | 3D42BDDD22896D2100D72864 /* main.m in Sources */,
336 | 3D513370228BA8440066E3AA /* LineChartViewController.m in Sources */,
337 | 3D4701BA22A75AD70056F888 /* CircleRingChartViewController.m in Sources */,
338 | 3D42BDCF22896D1E00D72864 /* AppDelegate.m in Sources */,
339 | 3D42BE0922896D9E00D72864 /* ColumnChartViewController.m in Sources */,
340 | 3D42BE0522896D6200D72864 /* ColumnChartView.m in Sources */,
341 | 3D42BE0622896D6200D72864 /* PieChartView.m in Sources */,
342 | 3D4C77DA22C9E39B00474E2C /* NegativeColumnChartViewController.m in Sources */,
343 | 3D42BE0C22896DB400D72864 /* PieChartViewController.m in Sources */,
344 | 3D51336D228BA81E0066E3AA /* LineChartView.m in Sources */,
345 | 3D4701B722A756250056F888 /* CircleRingChartView.m in Sources */,
346 | );
347 | runOnlyForDeploymentPostprocessing = 0;
348 | };
349 | 3D42BDDE22896D2100D72864 /* Sources */ = {
350 | isa = PBXSourcesBuildPhase;
351 | buildActionMask = 2147483647;
352 | files = (
353 | 3D42BDE722896D2100D72864 /* GCChartDemoTests.m in Sources */,
354 | );
355 | runOnlyForDeploymentPostprocessing = 0;
356 | };
357 | 3D42BDE922896D2100D72864 /* Sources */ = {
358 | isa = PBXSourcesBuildPhase;
359 | buildActionMask = 2147483647;
360 | files = (
361 | 3D42BDF222896D2100D72864 /* GCChartDemoUITests.m in Sources */,
362 | );
363 | runOnlyForDeploymentPostprocessing = 0;
364 | };
365 | /* End PBXSourcesBuildPhase section */
366 |
367 | /* Begin PBXTargetDependency section */
368 | 3D42BDE422896D2100D72864 /* PBXTargetDependency */ = {
369 | isa = PBXTargetDependency;
370 | target = 3D42BDC922896D1E00D72864 /* GCChartDemo */;
371 | targetProxy = 3D42BDE322896D2100D72864 /* PBXContainerItemProxy */;
372 | };
373 | 3D42BDEF22896D2100D72864 /* PBXTargetDependency */ = {
374 | isa = PBXTargetDependency;
375 | target = 3D42BDC922896D1E00D72864 /* GCChartDemo */;
376 | targetProxy = 3D42BDEE22896D2100D72864 /* PBXContainerItemProxy */;
377 | };
378 | /* End PBXTargetDependency section */
379 |
380 | /* Begin PBXVariantGroup section */
381 | 3D42BDD322896D1E00D72864 /* Main.storyboard */ = {
382 | isa = PBXVariantGroup;
383 | children = (
384 | 3D42BDD422896D1E00D72864 /* Base */,
385 | );
386 | name = Main.storyboard;
387 | sourceTree = "";
388 | };
389 | 3D42BDD822896D2100D72864 /* LaunchScreen.storyboard */ = {
390 | isa = PBXVariantGroup;
391 | children = (
392 | 3D42BDD922896D2100D72864 /* Base */,
393 | );
394 | name = LaunchScreen.storyboard;
395 | sourceTree = "";
396 | };
397 | /* End PBXVariantGroup section */
398 |
399 | /* Begin XCBuildConfiguration section */
400 | 3D42BDF422896D2100D72864 /* Debug */ = {
401 | isa = XCBuildConfiguration;
402 | buildSettings = {
403 | ALWAYS_SEARCH_USER_PATHS = NO;
404 | CLANG_ANALYZER_NONNULL = YES;
405 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
406 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
407 | CLANG_CXX_LIBRARY = "libc++";
408 | CLANG_ENABLE_MODULES = YES;
409 | CLANG_ENABLE_OBJC_ARC = YES;
410 | CLANG_ENABLE_OBJC_WEAK = YES;
411 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
412 | CLANG_WARN_BOOL_CONVERSION = YES;
413 | CLANG_WARN_COMMA = YES;
414 | CLANG_WARN_CONSTANT_CONVERSION = YES;
415 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
416 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
417 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
418 | CLANG_WARN_EMPTY_BODY = YES;
419 | CLANG_WARN_ENUM_CONVERSION = YES;
420 | CLANG_WARN_INFINITE_RECURSION = YES;
421 | CLANG_WARN_INT_CONVERSION = YES;
422 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
423 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
424 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
425 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
426 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
427 | CLANG_WARN_STRICT_PROTOTYPES = YES;
428 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
429 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
430 | CLANG_WARN_UNREACHABLE_CODE = YES;
431 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
432 | CODE_SIGN_IDENTITY = "iPhone Developer";
433 | COPY_PHASE_STRIP = NO;
434 | DEBUG_INFORMATION_FORMAT = dwarf;
435 | ENABLE_STRICT_OBJC_MSGSEND = YES;
436 | ENABLE_TESTABILITY = YES;
437 | GCC_C_LANGUAGE_STANDARD = gnu11;
438 | GCC_DYNAMIC_NO_PIC = NO;
439 | GCC_NO_COMMON_BLOCKS = YES;
440 | GCC_OPTIMIZATION_LEVEL = 0;
441 | GCC_PREPROCESSOR_DEFINITIONS = (
442 | "DEBUG=1",
443 | "$(inherited)",
444 | );
445 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
446 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
447 | GCC_WARN_UNDECLARED_SELECTOR = YES;
448 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
449 | GCC_WARN_UNUSED_FUNCTION = YES;
450 | GCC_WARN_UNUSED_VARIABLE = YES;
451 | IPHONEOS_DEPLOYMENT_TARGET = 12.1;
452 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
453 | MTL_FAST_MATH = YES;
454 | ONLY_ACTIVE_ARCH = YES;
455 | SDKROOT = iphoneos;
456 | };
457 | name = Debug;
458 | };
459 | 3D42BDF522896D2100D72864 /* Release */ = {
460 | isa = XCBuildConfiguration;
461 | buildSettings = {
462 | ALWAYS_SEARCH_USER_PATHS = NO;
463 | CLANG_ANALYZER_NONNULL = YES;
464 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
465 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
466 | CLANG_CXX_LIBRARY = "libc++";
467 | CLANG_ENABLE_MODULES = YES;
468 | CLANG_ENABLE_OBJC_ARC = YES;
469 | CLANG_ENABLE_OBJC_WEAK = YES;
470 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
471 | CLANG_WARN_BOOL_CONVERSION = YES;
472 | CLANG_WARN_COMMA = YES;
473 | CLANG_WARN_CONSTANT_CONVERSION = YES;
474 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
475 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
476 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
477 | CLANG_WARN_EMPTY_BODY = YES;
478 | CLANG_WARN_ENUM_CONVERSION = YES;
479 | CLANG_WARN_INFINITE_RECURSION = YES;
480 | CLANG_WARN_INT_CONVERSION = YES;
481 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
482 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
483 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
484 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
485 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
486 | CLANG_WARN_STRICT_PROTOTYPES = YES;
487 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
488 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
489 | CLANG_WARN_UNREACHABLE_CODE = YES;
490 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
491 | CODE_SIGN_IDENTITY = "iPhone Developer";
492 | COPY_PHASE_STRIP = NO;
493 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
494 | ENABLE_NS_ASSERTIONS = NO;
495 | ENABLE_STRICT_OBJC_MSGSEND = YES;
496 | GCC_C_LANGUAGE_STANDARD = gnu11;
497 | GCC_NO_COMMON_BLOCKS = YES;
498 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
499 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
500 | GCC_WARN_UNDECLARED_SELECTOR = YES;
501 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
502 | GCC_WARN_UNUSED_FUNCTION = YES;
503 | GCC_WARN_UNUSED_VARIABLE = YES;
504 | IPHONEOS_DEPLOYMENT_TARGET = 12.1;
505 | MTL_ENABLE_DEBUG_INFO = NO;
506 | MTL_FAST_MATH = YES;
507 | SDKROOT = iphoneos;
508 | VALIDATE_PRODUCT = YES;
509 | };
510 | name = Release;
511 | };
512 | 3D42BDF722896D2100D72864 /* Debug */ = {
513 | isa = XCBuildConfiguration;
514 | buildSettings = {
515 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
516 | CODE_SIGN_STYLE = Automatic;
517 | DEVELOPMENT_TEAM = C5N2R2LJ84;
518 | INFOPLIST_FILE = GCChartDemo/Info.plist;
519 | LD_RUNPATH_SEARCH_PATHS = (
520 | "$(inherited)",
521 | "@executable_path/Frameworks",
522 | );
523 | PRODUCT_BUNDLE_IDENTIFIER = gu.GCChartDemo;
524 | PRODUCT_NAME = "$(TARGET_NAME)";
525 | TARGETED_DEVICE_FAMILY = "1,2";
526 | };
527 | name = Debug;
528 | };
529 | 3D42BDF822896D2100D72864 /* Release */ = {
530 | isa = XCBuildConfiguration;
531 | buildSettings = {
532 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
533 | CODE_SIGN_STYLE = Automatic;
534 | DEVELOPMENT_TEAM = C5N2R2LJ84;
535 | INFOPLIST_FILE = GCChartDemo/Info.plist;
536 | LD_RUNPATH_SEARCH_PATHS = (
537 | "$(inherited)",
538 | "@executable_path/Frameworks",
539 | );
540 | PRODUCT_BUNDLE_IDENTIFIER = gu.GCChartDemo;
541 | PRODUCT_NAME = "$(TARGET_NAME)";
542 | TARGETED_DEVICE_FAMILY = "1,2";
543 | };
544 | name = Release;
545 | };
546 | 3D42BDFA22896D2100D72864 /* Debug */ = {
547 | isa = XCBuildConfiguration;
548 | buildSettings = {
549 | BUNDLE_LOADER = "$(TEST_HOST)";
550 | CODE_SIGN_STYLE = Automatic;
551 | INFOPLIST_FILE = GCChartDemoTests/Info.plist;
552 | LD_RUNPATH_SEARCH_PATHS = (
553 | "$(inherited)",
554 | "@executable_path/Frameworks",
555 | "@loader_path/Frameworks",
556 | );
557 | PRODUCT_BUNDLE_IDENTIFIER = gu.GCChartDemoTests;
558 | PRODUCT_NAME = "$(TARGET_NAME)";
559 | TARGETED_DEVICE_FAMILY = "1,2";
560 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/GCChartDemo.app/GCChartDemo";
561 | };
562 | name = Debug;
563 | };
564 | 3D42BDFB22896D2100D72864 /* Release */ = {
565 | isa = XCBuildConfiguration;
566 | buildSettings = {
567 | BUNDLE_LOADER = "$(TEST_HOST)";
568 | CODE_SIGN_STYLE = Automatic;
569 | INFOPLIST_FILE = GCChartDemoTests/Info.plist;
570 | LD_RUNPATH_SEARCH_PATHS = (
571 | "$(inherited)",
572 | "@executable_path/Frameworks",
573 | "@loader_path/Frameworks",
574 | );
575 | PRODUCT_BUNDLE_IDENTIFIER = gu.GCChartDemoTests;
576 | PRODUCT_NAME = "$(TARGET_NAME)";
577 | TARGETED_DEVICE_FAMILY = "1,2";
578 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/GCChartDemo.app/GCChartDemo";
579 | };
580 | name = Release;
581 | };
582 | 3D42BDFD22896D2100D72864 /* Debug */ = {
583 | isa = XCBuildConfiguration;
584 | buildSettings = {
585 | CODE_SIGN_STYLE = Automatic;
586 | INFOPLIST_FILE = GCChartDemoUITests/Info.plist;
587 | LD_RUNPATH_SEARCH_PATHS = (
588 | "$(inherited)",
589 | "@executable_path/Frameworks",
590 | "@loader_path/Frameworks",
591 | );
592 | PRODUCT_BUNDLE_IDENTIFIER = gu.GCChartDemoUITests;
593 | PRODUCT_NAME = "$(TARGET_NAME)";
594 | TARGETED_DEVICE_FAMILY = "1,2";
595 | TEST_TARGET_NAME = GCChartDemo;
596 | };
597 | name = Debug;
598 | };
599 | 3D42BDFE22896D2100D72864 /* Release */ = {
600 | isa = XCBuildConfiguration;
601 | buildSettings = {
602 | CODE_SIGN_STYLE = Automatic;
603 | INFOPLIST_FILE = GCChartDemoUITests/Info.plist;
604 | LD_RUNPATH_SEARCH_PATHS = (
605 | "$(inherited)",
606 | "@executable_path/Frameworks",
607 | "@loader_path/Frameworks",
608 | );
609 | PRODUCT_BUNDLE_IDENTIFIER = gu.GCChartDemoUITests;
610 | PRODUCT_NAME = "$(TARGET_NAME)";
611 | TARGETED_DEVICE_FAMILY = "1,2";
612 | TEST_TARGET_NAME = GCChartDemo;
613 | };
614 | name = Release;
615 | };
616 | /* End XCBuildConfiguration section */
617 |
618 | /* Begin XCConfigurationList section */
619 | 3D42BDC522896D1E00D72864 /* Build configuration list for PBXProject "GCChartDemo" */ = {
620 | isa = XCConfigurationList;
621 | buildConfigurations = (
622 | 3D42BDF422896D2100D72864 /* Debug */,
623 | 3D42BDF522896D2100D72864 /* Release */,
624 | );
625 | defaultConfigurationIsVisible = 0;
626 | defaultConfigurationName = Release;
627 | };
628 | 3D42BDF622896D2100D72864 /* Build configuration list for PBXNativeTarget "GCChartDemo" */ = {
629 | isa = XCConfigurationList;
630 | buildConfigurations = (
631 | 3D42BDF722896D2100D72864 /* Debug */,
632 | 3D42BDF822896D2100D72864 /* Release */,
633 | );
634 | defaultConfigurationIsVisible = 0;
635 | defaultConfigurationName = Release;
636 | };
637 | 3D42BDF922896D2100D72864 /* Build configuration list for PBXNativeTarget "GCChartDemoTests" */ = {
638 | isa = XCConfigurationList;
639 | buildConfigurations = (
640 | 3D42BDFA22896D2100D72864 /* Debug */,
641 | 3D42BDFB22896D2100D72864 /* Release */,
642 | );
643 | defaultConfigurationIsVisible = 0;
644 | defaultConfigurationName = Release;
645 | };
646 | 3D42BDFC22896D2100D72864 /* Build configuration list for PBXNativeTarget "GCChartDemoUITests" */ = {
647 | isa = XCConfigurationList;
648 | buildConfigurations = (
649 | 3D42BDFD22896D2100D72864 /* Debug */,
650 | 3D42BDFE22896D2100D72864 /* Release */,
651 | );
652 | defaultConfigurationIsVisible = 0;
653 | defaultConfigurationName = Release;
654 | };
655 | /* End XCConfigurationList section */
656 | };
657 | rootObject = 3D42BDC222896D1E00D72864 /* Project object */;
658 | }
659 |
--------------------------------------------------------------------------------
/GCChartDemo/GCChartDemo/LineChartView/LineChartView.m:
--------------------------------------------------------------------------------
1 | //
2 | // LineChartView.m
3 | // LineChartTest
4 | //
5 | // Created by 古创 on 2019/5/13.
6 | // Copyright © 2019年 GC. All rights reserved.
7 | //
8 |
9 | #import "LineChartView.h"
10 |
11 | @interface LineChartView ()
12 |
13 | @property (nonatomic,strong) UIScrollView *scrollView;
14 | @property (nonatomic,strong) UIView *yAxisView;
15 | @property (nonatomic,strong) UIView *xAxisView;
16 | @property (nonatomic,strong) UIView *dataView;
17 | @property (nonatomic,strong) UIView *legendBgView;
18 | @property (nonatomic,strong) NSMutableArray *pointArray;
19 | @property (nonatomic,strong) NSMutableArray *colorArray;
20 |
21 | @end
22 |
23 | @implementation LineChartView
24 |
25 | #pragma mark - init
26 |
27 |
28 | - (instancetype)init
29 | {
30 | self = [super init];
31 | if (self) {
32 | [self config];
33 | }
34 | return self;
35 | }
36 |
37 | - (instancetype)initWithFrame:(CGRect)frame
38 | {
39 | self = [super initWithFrame:frame];
40 | if (self) {
41 | [self config];
42 | }
43 | return self;
44 | }
45 |
46 | - (instancetype)initWithFrame:(CGRect)frame andDataNameArray:(NSArray *)dataNameArray andDataArray:(NSArray *)dataArray andLineColor:(NSString *)colorString {
47 | self = [super initWithFrame:frame];
48 | if (self) {
49 | self.isSingleLine = YES;
50 | self.dataNameArray = dataNameArray;
51 | self.dataArray = dataArray;
52 | self.lineColor = colorString;
53 | [self config];
54 | }
55 | return self;
56 | }
57 |
58 | // 配置一些默认属性
59 | - (void)config {
60 | self.lineWidth = 2;
61 | if (self.lineColor.length == 0) {
62 | self.lineColor = @"#404040";
63 | }
64 | if (self.fillAlpha == 0) {
65 | self.fillAlpha = 1.0;
66 | }
67 |
68 | if (self.legendColorArray.count == 0) {
69 | NSArray *arr = @[@"#308ff7",@"#fbca58",@"#f5447d",@"#a020f0",@"#00ffff",@"#00ff00"];
70 | self.colorArray = [NSMutableArray arrayWithArray:arr];
71 | }
72 |
73 | // scrollView
74 | self.scrollView = [[UIScrollView alloc] init];
75 | self.scrollView.backgroundColor = [UIColor whiteColor];
76 | self.scrollView.showsVerticalScrollIndicator = NO;
77 | self.scrollView.showsHorizontalScrollIndicator = NO;
78 | [self addSubview:self.scrollView];
79 |
80 | // y轴
81 | self.yAxisView = [[UIView alloc] init];
82 | self.yAxisView.backgroundColor = [UIColor whiteColor];
83 | [self addSubview:self.yAxisView];
84 |
85 | // x轴
86 | self.xAxisView = [[UIView alloc] init];
87 | self.xAxisView.backgroundColor = [UIColor whiteColor];
88 | [self.scrollView addSubview:self.xAxisView];
89 |
90 | // 数据view
91 | // self.dataView = [[UIView alloc] init];
92 | // self.dataView.backgroundColor = [UIColor whiteColor];
93 | // [self.scrollView addSubview:self.dataView];
94 | }
95 |
96 | #pragma mark - setUI & resetUI
97 | // 单条折线
98 | - (void)resetSingleLine {
99 | self.yAxisView.frame = CGRectMake(0, 20, 30, self.bounds.size.height - 20);
100 | self.scrollView.frame = CGRectMake(30, 0, self.bounds.size.width - 40, self.bounds.size.height);
101 |
102 | for (UIView *view in self.yAxisView.subviews) {
103 | [view removeFromSuperview];
104 | }
105 | UIView *lineView = [[UIView alloc] initWithFrame:CGRectMake(29, 0, 1, self.yAxisView.bounds.size.height - 20)];
106 | lineView.backgroundColor = [self colorWithHexString:@"#898989" andAlpha:1.0];
107 | [self.yAxisView addSubview:lineView];
108 |
109 | int maxValue = 0;
110 | float maxNum = 0;
111 | NSString *str = @"";
112 | if (self.yAxisNums.count == 0) {
113 | maxValue = [[self.dataArray valueForKeyPath:@"@max.intValue"] intValue];// 寻找数组中的最大值
114 |
115 |
116 | if (!self.maxNum || self.maxNum.length == 0) {
117 | maxNum = [self approximateRoundNumberWithString:[NSString stringWithFormat:@"%d",maxValue]];// 取近似最大值
118 | } else {
119 | maxNum = [self.maxNum intValue];
120 | }
121 |
122 | str = [[NSString stringWithFormat:@"%ld",(long)maxNum] substringToIndex:1];
123 | int level = (int)maxNum / [str intValue]; // 数量级 整十或整百或整千等
124 | for (int i = 0; i < [str intValue]; i++) {
125 | CGFloat lblY = self.yAxisView.bounds.size.height - 28 - i * (lineView.bounds.size.height / [str intValue]);
126 | UILabel *lblYAxisNum = [[UILabel alloc] initWithFrame:CGRectMake(0, lblY, 29, 16)];
127 | lblYAxisNum.font = [UIFont systemFontOfSize:8];
128 | lblYAxisNum.textColor = [self colorWithHexString:@"#898989" andAlpha:1.0];
129 | lblYAxisNum.textAlignment = NSTextAlignmentCenter;
130 | lblYAxisNum.text = [NSString stringWithFormat:@"%d",i * level];
131 | [self.yAxisView addSubview:lblYAxisNum];
132 | }
133 | if (self.dataArray.count != 0 || self.maxNum.length != 0) {
134 | UILabel *lblMax = [[UILabel alloc] initWithFrame:CGRectMake(0, -8, 29, 16)];
135 | lblMax.font = [UIFont systemFontOfSize:8];
136 | lblMax.textColor = [self colorWithHexString:@"#898989" andAlpha:1.0];
137 | lblMax.textAlignment = NSTextAlignmentCenter;
138 | lblMax.text = [NSString stringWithFormat:@"%ld",(long)maxNum];
139 | [self.yAxisView addSubview:lblMax];
140 | }
141 | } else {
142 | maxNum = [self.yAxisNums.lastObject intValue];
143 | for (int i = 0; i < self.yAxisNums.count; i++) {
144 | CGFloat lblY = self.yAxisView.bounds.size.height - 28 - i * (lineView.bounds.size.height / (self.yAxisNums.count - 1));
145 | UILabel *lblYAxisNum = [[UILabel alloc] initWithFrame:CGRectMake(0, lblY, 29, 16)];
146 | lblYAxisNum.font = [UIFont systemFontOfSize:8];
147 | lblYAxisNum.textColor = [self colorWithHexString:@"#898989" andAlpha:1.0];
148 | lblYAxisNum.textAlignment = NSTextAlignmentCenter;
149 | lblYAxisNum.text = self.yAxisNums[i];
150 | [self.yAxisView addSubview:lblYAxisNum];
151 | }
152 | }
153 |
154 | if (self.dataArray.count <= 5) {
155 | self.scrollView.contentSize = CGSizeMake(self.scrollView.bounds.size.width, self.scrollView.bounds.size.width);
156 | self.xAxisView.frame = CGRectMake(0, self.scrollView.bounds.size.height - 20, self.scrollView.bounds.size.width, 20);
157 | } else {
158 | CGFloat groupWidth = self.scrollView.bounds.size.width / 5;
159 | self.scrollView.contentSize = CGSizeMake(groupWidth * self.dataArray.count, self.scrollView.bounds.size.height);
160 | self.xAxisView.frame = CGRectMake(0, self.scrollView.bounds.size.height - 20, groupWidth * self.dataArray.count, 20);
161 | }
162 |
163 | for (UIView *view in self.xAxisView.subviews) {
164 | [view removeFromSuperview];
165 | }
166 | UIView *xLineView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.xAxisView.bounds.size.width, 1)];
167 | xLineView.backgroundColor = [self colorWithHexString:@"#898989" andAlpha:1.0];
168 | [self.xAxisView addSubview:xLineView];
169 |
170 | for (UIView *view in self.scrollView.subviews) {
171 | if (view != self.xAxisView) {
172 | [view removeFromSuperview];
173 | }
174 | }
175 |
176 | // 水平虚线
177 | if (self.showDataHorizontalLine) {
178 | for (int i = 0; i < [str intValue]; i++) {
179 | UIView *dashlineView = [[UIView alloc] initWithFrame:CGRectMake(0, self.scrollView.bounds.size.height - 20 - (i + 1) * ((self.yAxisView.bounds.size.height - 20) / [str intValue]), self.scrollView.contentSize.width, 1)];
180 | [self.scrollView addSubview:dashlineView];
181 | CAShapeLayer *lineLayer = [CAShapeLayer layer];
182 | [lineLayer setBounds:dashlineView.bounds];
183 | [lineLayer setPosition:CGPointMake(CGRectGetWidth(dashlineView.frame) / 2, CGRectGetHeight(dashlineView.frame) / 2)];
184 | lineLayer.lineWidth = 0.5;
185 | [lineLayer setLineDashPattern:@[@2,@1]];
186 | lineLayer.strokeColor = [self colorWithHexString:@"#dcdcdc" andAlpha:1.0].CGColor;
187 | // 设置路径
188 | CGMutablePathRef path = CGPathCreateMutable();
189 | CGPathMoveToPoint(path, NULL, 0, dashlineView.bounds.size.height / 2);
190 | CGPathAddLineToPoint(path, NULL, dashlineView.bounds.size.width, dashlineView.bounds.size.height / 2);
191 | [lineLayer setPath:path];
192 | CGPathRelease(path);
193 | [dashlineView.layer addSublayer:lineLayer];
194 | }
195 | }
196 |
197 | [self.dataView removeFromSuperview];
198 | self.dataView = nil;
199 | self.dataView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.scrollView.contentSize.width, self.scrollView.bounds.size.height - 20)];
200 | [self.scrollView addSubview:self.dataView];
201 |
202 | UIBezierPath *bgPath = [UIBezierPath bezierPath];
203 | [bgPath moveToPoint:CGPointMake(0, self.dataView.bounds.size.height / 2)];
204 | [bgPath addLineToPoint:CGPointMake(self.dataView.bounds.size.width, self.dataView.bounds.size.height / 2)];
205 | bgPath.lineWidth = self.dataView.bounds.size.height;
206 | CAShapeLayer *bgLayer = [CAShapeLayer layer];
207 | bgLayer.fillColor = [UIColor clearColor].CGColor;
208 | bgLayer.strokeColor = [UIColor lightGrayColor].CGColor;
209 | bgLayer.strokeStart = 0;
210 | bgLayer.strokeEnd = 1;
211 | bgLayer.zPosition = 1;
212 | bgLayer.lineWidth = self.dataView.bounds.size.height;
213 | bgLayer.path = bgPath.CGPath;
214 | self.dataView.layer.mask = bgLayer;
215 |
216 | UIBezierPath *dataPath = [UIBezierPath bezierPath];
217 | dataPath.lineWidth = self.lineWidth;
218 | [[self colorWithHexString:self.lineColor andAlpha:1.0] setStroke];
219 | [[self colorWithHexString:self.lineColor andAlpha:1.0] setFill];
220 | [dataPath stroke];
221 | [dataPath fill];
222 |
223 | [self.pointArray removeAllObjects];
224 | // 起始点
225 | [self.pointArray addObject:[NSValue valueWithCGPoint:CGPointMake(0, self.dataView.bounds.size.height)]];
226 |
227 | CGFloat groupWidth = self.scrollView.bounds.size.width / 5;
228 | for (int i = 0; i < self.dataArray.count; i++) {
229 | UIView *groupCenterLineView = [[UIView alloc] initWithFrame:CGRectMake(groupWidth * i + groupWidth / 2 - 0.5, 1, 1, 5)];
230 | groupCenterLineView.backgroundColor = [self colorWithHexString:@"#898989" andAlpha:1.0];
231 | [self.xAxisView addSubview:groupCenterLineView];
232 |
233 | // 分组标题
234 | UILabel *lblGroupTitle = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, groupWidth, 14)];
235 | lblGroupTitle.center = CGPointMake(groupWidth * i + groupWidth / 2, 13);
236 | lblGroupTitle.font = [UIFont systemFontOfSize:8];
237 | lblGroupTitle.textColor = [self colorWithHexString:@"#898989" andAlpha:1.0];
238 | lblGroupTitle.textAlignment = NSTextAlignmentCenter;
239 | lblGroupTitle.text = self.dataNameArray[i];
240 | [self.xAxisView addSubview:lblGroupTitle];
241 |
242 | //
243 | UIView *groupDataView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, groupWidth, self.scrollView.bounds.size.height - 20)];
244 | groupDataView.center = CGPointMake(groupWidth * i + groupWidth / 2, groupDataView.center.y);
245 | [self.scrollView addSubview:groupDataView];
246 |
247 | // 具体数据
248 | NSString *num = self.dataArray[i];
249 | CGFloat pointHeight = self.dataView.bounds.size.height - (self.dataView.bounds.size.height - 20) * [num intValue] / maxNum;
250 | if (self.isSmooth) {// 是否为平滑曲线
251 | [self.pointArray addObject:[NSValue valueWithCGPoint:CGPointMake(groupWidth / 2 + groupWidth * i, pointHeight)]];
252 | } else {
253 | if (i == 0) {
254 | if (self.isFillWithColor) {
255 | [dataPath moveToPoint:CGPointMake(groupWidth / 2, self.dataView.bounds.size.height)];
256 | [dataPath addLineToPoint:CGPointMake(groupWidth / 2, pointHeight)];
257 | } else {
258 | [dataPath moveToPoint:CGPointMake(groupWidth / 2, pointHeight)];
259 | }
260 | } else if (i == self.dataArray.count - 1) {
261 | [dataPath addLineToPoint:CGPointMake(groupWidth / 2 + groupWidth * i, pointHeight)];
262 | if (self.isFillWithColor) {
263 | [dataPath addLineToPoint:CGPointMake(groupWidth / 2 + groupWidth * i, self.dataView.bounds.size.height)];
264 | }
265 | } else {
266 | [dataPath addLineToPoint:CGPointMake(groupWidth / 2 + groupWidth * i, pointHeight)];
267 | }
268 | }
269 | }
270 |
271 | if (self.isSmooth) {
272 | // 添加结束点
273 | [self.pointArray addObject:[NSValue valueWithCGPoint:CGPointMake(self.dataView.bounds.size.width, self.dataView.bounds.size.height)]];
274 | for (int i = 0; i < self.dataArray.count - 1; i++) {
275 | CGPoint p1 = [self.pointArray[i] CGPointValue];
276 | CGPoint p2 = [self.pointArray[i+1] CGPointValue];
277 | CGPoint p3 = [self.pointArray[i+2] CGPointValue];
278 | CGPoint p4 = [self.pointArray[i+3] CGPointValue];
279 | if (i == 0) {
280 | if (self.isFillWithColor) {
281 | [dataPath moveToPoint:CGPointMake(groupWidth / 2, self.dataView.bounds.size.height)];
282 | [dataPath addLineToPoint:p2];
283 | } else {
284 | [dataPath moveToPoint:p2];
285 | [dataPath addLineToPoint:CGPointMake(groupWidth / 2, self.dataView.bounds.size.height)];
286 | }
287 | }
288 | [self getControlPointOfBezierPath:dataPath andPointx0:p1.x andy0:p1.y x1:p2.x andy1:p2.y x2:p3.x andy2:p3.y x3:p4.x andy3:p4.y];
289 | }
290 | if (self.isFillWithColor) {
291 | [dataPath addLineToPoint:CGPointMake(groupWidth / 2 + groupWidth * (self.dataArray.count - 1), self.dataView.bounds.size.height)];
292 | // [dataPath addLineToPoint:CGPointMake(groupWidth / 2, self.dataView.bounds.size.height)];
293 | }
294 | }
295 |
296 | CAShapeLayer *dataLayer = [CAShapeLayer layer];
297 | dataLayer.path = dataPath.CGPath;
298 | if (self.isFillWithColor) {
299 | dataLayer.strokeColor = nil;//[self colorWithHexString:self.lineColor].CGColor;
300 | dataLayer.fillColor = [self colorWithHexString:self.fillColor andAlpha:self.fillAlpha].CGColor;
301 | } else {
302 | dataLayer.strokeColor = [self colorWithHexString:self.lineColor andAlpha:1.0].CGColor;
303 | dataLayer.fillColor = nil;//[self colorWithHexString:self.lineColor].CGColor;
304 | }
305 | dataLayer.lineWidth = self.lineWidth;
306 | [self.dataView.layer addSublayer:dataLayer];
307 |
308 | // 显示数据具体值
309 | if (self.showDataLabel) {
310 | for (int i = 0; i < self.dataArray.count; i++) {
311 | NSString *num = self.dataArray[i];
312 | CGFloat pointHeight = self.dataView.bounds.size.height - (self.dataView.bounds.size.height - 20) * [num intValue] / maxNum;
313 | UILabel *dataLable = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, groupWidth, 16)];
314 | dataLable.center = CGPointMake(groupWidth / 2 + groupWidth * i, pointHeight - 8);
315 | dataLable.font = [UIFont systemFontOfSize:8];
316 | dataLable.textColor = [self colorWithHexString:@"#404040" andAlpha:1.0];
317 | dataLable.textAlignment = NSTextAlignmentCenter;
318 | dataLable.text = self.dataArray[i];
319 | [self.dataView addSubview:dataLable];
320 | }
321 | }
322 |
323 | // 动画
324 | CABasicAnimation *strokeAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
325 | strokeAnimation.fromValue = @0;// 起始值
326 | strokeAnimation.toValue = @1;// 结束值
327 | strokeAnimation.duration = 1;// 动画持续时间
328 | strokeAnimation.repeatCount = 1;// 重复次数
329 | strokeAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
330 | strokeAnimation.removedOnCompletion = YES;
331 | [bgLayer addAnimation:strokeAnimation forKey:@"pieAnimation"];
332 | }
333 |
334 | // 多条折线
335 | - (void)resetMultiLine {
336 | if (self.legendColorArray.count == 0 || self.legendColorArray.count < self.dataArray.count) {
337 | NSArray *arr = @[@"#308ff7",@"#fbca58",@"#f5447d",@"#a020f0",@"#00ffff",@"#00ff00"];
338 | self.colorArray = [NSMutableArray arrayWithArray:arr];
339 | } else {
340 | self.colorArray = [NSMutableArray arrayWithArray:self.legendColorArray];
341 | }
342 |
343 | // 先移除之前创建的
344 | for (UIView *view in self.legendBgView.subviews) {
345 | [view removeFromSuperview];
346 | }
347 | [self.legendBgView removeFromSuperview];
348 | self.legendBgView = nil;
349 | if (self.legendPostion == LegendPositionNone) {// 无图例的时候
350 | self.legendBgView = nil;
351 | } else {
352 | self.legendBgView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.bounds.size.width, 20)];
353 | [self addSubview:self.legendBgView];
354 | switch (self.legendPostion) {
355 | case LegendPositionTop:
356 | self.legendBgView.center = CGPointMake(self.bounds.size.width / 2, 10);
357 | break;
358 | case LegendPositionBottom:
359 | self.legendBgView.center = CGPointMake(self.bounds.size.width / 2, self.bounds.size.height - 10);
360 | break;
361 |
362 | default:
363 | break;
364 | }
365 | for (int i = 0; i < self.legendNameArray.count; i++) {
366 | UIView *colorLine = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 20, 2)];
367 | colorLine.center = CGPointMake(20 + (10 + 50 + 20) * i, 10);
368 | // colorLine.layer.cornerRadius = 5;
369 | // colorLine.layer.masksToBounds = YES;
370 | [self.legendBgView addSubview:colorLine];
371 | colorLine.backgroundColor = [self colorWithHexString:self.colorArray[i] andAlpha:1.0];
372 |
373 | UILabel *legendTitle = [[UILabel alloc] initWithFrame:CGRectMake(CGRectGetMaxX(colorLine.frame) + 2, 0, 50, 20)];
374 | legendTitle.text = self.legendNameArray[i];
375 | legendTitle.textColor = [UIColor blackColor];
376 | legendTitle.font = [UIFont systemFontOfSize:12];
377 | [self.legendBgView addSubview:legendTitle];
378 | }
379 | }
380 | switch (self.legendPostion) {
381 | case LegendPositionNone:
382 | self.yAxisView.frame = CGRectMake(0, 20, 30, self.bounds.size.height - 20);
383 | self.scrollView.frame = CGRectMake(30, 0, self.bounds.size.width - 40, self.bounds.size.height);
384 | break;
385 | case LegendPositionTop:
386 | self.yAxisView.frame = CGRectMake(0, 40, 30, self.bounds.size.height - 40);
387 | self.scrollView.frame = CGRectMake(30, 20, self.bounds.size.width - 40, self.bounds.size.height - 20);
388 | break;
389 | case LegendPositionBottom:
390 | self.yAxisView.frame = CGRectMake(0, 20, 30, self.bounds.size.height - 40);
391 | self.scrollView.frame = CGRectMake(30, 0, self.bounds.size.width - 40, self.bounds.size.height - 20);
392 | break;
393 |
394 | default:
395 | self.yAxisView.frame = CGRectMake(0, 0, 30, self.bounds.size.height);
396 | self.scrollView.frame = CGRectMake(30, 0, self.bounds.size.width - 40, self.bounds.size.height);
397 | break;
398 | }
399 |
400 | for (UIView *view in self.yAxisView.subviews) {
401 | [view removeFromSuperview];
402 | }
403 | UIView *lineView = [[UIView alloc] initWithFrame:CGRectMake(29, 0, 1, self.yAxisView.bounds.size.height - 20)];
404 | lineView.backgroundColor = [self colorWithHexString:@"#898989" andAlpha:1.0];
405 | [self.yAxisView addSubview:lineView];
406 |
407 | NSMutableArray *array = [NSMutableArray array];
408 | for (NSArray *arr in self.dataArray) {
409 | int max = [[arr valueForKeyPath:@"@max.intValue"] intValue];// 寻找数组中的最大值
410 | [array addObject:[NSNumber numberWithInt:max]];
411 | }
412 | int maxValue = [[array valueForKeyPath:@"@max.intValue"] intValue];// 寻找数组中的最大值
413 | NSInteger maxNum = [self approximateRoundNumberWithString:[NSString stringWithFormat:@"%d",maxValue]];// 取近似最大值
414 | NSString *str = [[NSString stringWithFormat:@"%ld",(long)maxNum] substringToIndex:1];
415 | int level = (int)maxNum / [str intValue]; // 数量级 整十或整百或整千等
416 | for (int i = 0; i < [str intValue]; i++) {
417 | CGFloat lblY = self.yAxisView.bounds.size.height - 28 - i * (lineView.bounds.size.height / [str intValue]);
418 | UILabel *lblYAxisNum = [[UILabel alloc] initWithFrame:CGRectMake(0, lblY, 29, 16)];
419 | lblYAxisNum.font = [UIFont systemFontOfSize:8];
420 | lblYAxisNum.textColor = [self colorWithHexString:@"#898989" andAlpha:1.0];
421 | lblYAxisNum.textAlignment = NSTextAlignmentCenter;
422 | lblYAxisNum.text = [NSString stringWithFormat:@"%d",i * level];
423 | [self.yAxisView addSubview:lblYAxisNum];
424 | }
425 | UILabel *lblMax = [[UILabel alloc] initWithFrame:CGRectMake(0, -8, 29, 16)];
426 | lblMax.font = [UIFont systemFontOfSize:8];
427 | lblMax.textColor = [self colorWithHexString:@"#898989" andAlpha:1.0];
428 | lblMax.textAlignment = NSTextAlignmentCenter;
429 | lblMax.text = [NSString stringWithFormat:@"%ld",(long)maxNum];
430 | [self.yAxisView addSubview:lblMax];
431 |
432 | if (self.dataNameArray.count <= 5) {
433 | self.scrollView.contentSize = CGSizeMake(self.scrollView.bounds.size.width, self.scrollView.bounds.size.width);
434 | self.xAxisView.frame = CGRectMake(0, self.scrollView.bounds.size.height - 20, self.scrollView.bounds.size.width, 20);
435 | self.dataView.frame = CGRectMake(0, 0, self.scrollView.bounds.size.width, self.scrollView.bounds.size.height - 20);
436 | } else {
437 | CGFloat groupWidth = self.scrollView.bounds.size.width / 5;
438 | self.scrollView.contentSize = CGSizeMake(groupWidth * self.dataNameArray.count, self.scrollView.bounds.size.height);
439 | self.xAxisView.frame = CGRectMake(0, self.scrollView.bounds.size.height - 20, groupWidth * self.dataNameArray.count, 20);
440 | self.dataView.frame = CGRectMake(0, 0, groupWidth * self.dataNameArray.count, self.scrollView.bounds.size.height - 20);
441 | }
442 |
443 | for (UIView *view in self.xAxisView.subviews) {
444 | [view removeFromSuperview];
445 | }
446 | UIView *xLineView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.xAxisView.bounds.size.width, 1)];
447 | xLineView.backgroundColor = [self colorWithHexString:@"#898989" andAlpha:1.0];
448 | [self.xAxisView addSubview:xLineView];
449 |
450 | for (UIView *view in self.scrollView.subviews) {
451 | if (view != self.xAxisView) {
452 | [view removeFromSuperview];
453 | }
454 | }
455 |
456 | // 水平虚线
457 | if (self.showDataHorizontalLine) {
458 | for (int i = 0; i < [str intValue]; i++) {
459 | UIView *dashlineView = [[UIView alloc] initWithFrame:CGRectMake(0, self.scrollView.bounds.size.height - 20 - (i + 1) * ((self.yAxisView.bounds.size.height - 20) / [str intValue]), self.scrollView.contentSize.width, 1)];
460 | [self.scrollView addSubview:dashlineView];
461 | CAShapeLayer *lineLayer = [CAShapeLayer layer];
462 | [lineLayer setBounds:dashlineView.bounds];
463 | [lineLayer setPosition:CGPointMake(CGRectGetWidth(dashlineView.frame) / 2, CGRectGetHeight(dashlineView.frame) / 2)];
464 | lineLayer.lineWidth = 0.5;
465 | [lineLayer setLineDashPattern:@[@2,@1]];
466 | lineLayer.strokeColor = [self colorWithHexString:@"#dcdcdc" andAlpha:1.0].CGColor;
467 | // 设置路径
468 | CGMutablePathRef path = CGPathCreateMutable();
469 | CGPathMoveToPoint(path, NULL, 0, dashlineView.bounds.size.height / 2);
470 | CGPathAddLineToPoint(path, NULL, dashlineView.bounds.size.width, dashlineView.bounds.size.height / 2);
471 | [lineLayer setPath:path];
472 | CGPathRelease(path);
473 | [dashlineView.layer addSublayer:lineLayer];
474 | }
475 | }
476 |
477 | [self.dataView removeFromSuperview];
478 | self.dataView = nil;
479 | self.dataView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.scrollView.contentSize.width, self.scrollView.bounds.size.height - 20)];
480 | [self.scrollView addSubview:self.dataView];
481 |
482 | UIBezierPath *bgPath = [UIBezierPath bezierPath];
483 | [bgPath moveToPoint:CGPointMake(0, self.dataView.bounds.size.height / 2)];
484 | [bgPath addLineToPoint:CGPointMake(self.dataView.bounds.size.width, self.dataView.bounds.size.height / 2)];
485 | bgPath.lineWidth = self.dataView.bounds.size.height;
486 | CAShapeLayer *bgLayer = [CAShapeLayer layer];
487 | bgLayer.fillColor = [UIColor clearColor].CGColor;
488 | bgLayer.strokeColor = [UIColor lightGrayColor].CGColor;
489 | bgLayer.strokeStart = 0;
490 | bgLayer.strokeEnd = 1;
491 | bgLayer.zPosition = 1;
492 | bgLayer.lineWidth = self.dataView.bounds.size.height;
493 | bgLayer.path = bgPath.CGPath;
494 | self.dataView.layer.mask = bgLayer;
495 |
496 | CGFloat groupWidth = self.scrollView.bounds.size.width / 5;
497 | for (int i = 0; i < self.dataNameArray.count; i++) {
498 | UIView *groupCenterLineView = [[UIView alloc] initWithFrame:CGRectMake(groupWidth * i + groupWidth / 2 - 0.5, 1, 1, 5)];
499 | groupCenterLineView.backgroundColor = [self colorWithHexString:@"#898989" andAlpha:1.0];
500 | [self.xAxisView addSubview:groupCenterLineView];
501 |
502 | // 分组标题
503 | UILabel *lblGroupTitle = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, groupWidth, 14)];
504 | lblGroupTitle.center = CGPointMake(groupWidth * i + groupWidth / 2, 13);
505 | lblGroupTitle.font = [UIFont systemFontOfSize:8];
506 | lblGroupTitle.textColor = [self colorWithHexString:@"#898989" andAlpha:1.0];
507 | lblGroupTitle.textAlignment = NSTextAlignmentCenter;
508 | lblGroupTitle.text = self.dataNameArray[i];
509 | [self.xAxisView addSubview:lblGroupTitle];
510 |
511 | //
512 | UIView *groupDataView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, groupWidth, self.scrollView.bounds.size.height - 20)];
513 | groupDataView.center = CGPointMake(groupWidth * i + groupWidth / 2, groupDataView.center.y);
514 | [self.scrollView addSubview:groupDataView];
515 | }
516 |
517 |
518 | for (int i = 0; i < self.dataArray.count; i++) {
519 | UIBezierPath *dataPath = [UIBezierPath bezierPath];
520 | dataPath.lineWidth = self.lineWidth;
521 | [[self colorWithHexString:self.lineColor andAlpha:1.0] setStroke];
522 | [[self colorWithHexString:self.lineColor andAlpha:1.0] setFill];
523 | [dataPath stroke];
524 | [dataPath fill];
525 | NSArray *array = self.dataArray[i];
526 | [self.pointArray removeAllObjects];
527 | // 起始点
528 | [self.pointArray addObject:[NSValue valueWithCGPoint:CGPointMake(0, self.dataView.bounds.size.height)]];
529 | for (int j = 0; j < array.count; j++) {
530 | // 具体数据
531 | NSString *num = array[j];
532 | CGFloat pointHeight = self.dataView.bounds.size.height - (self.dataView.bounds.size.height - 20) * [num intValue] / maxNum;
533 | if (self.isSmooth) {// 是否为平滑曲线
534 | [self.pointArray addObject:[NSValue valueWithCGPoint:CGPointMake(groupWidth / 2 + groupWidth * j, pointHeight)]];
535 | } else {
536 | if (j == 0) {
537 | [dataPath moveToPoint:CGPointMake(groupWidth / 2, pointHeight)];
538 | } else {
539 | [dataPath addLineToPoint:CGPointMake(groupWidth / 2 + groupWidth * j, pointHeight)];
540 | }
541 | }
542 | }
543 | if (self.isSmooth) {
544 | // 添加结束点
545 | [self.pointArray addObject:[NSValue valueWithCGPoint:CGPointMake(self.dataView.bounds.size.width, self.dataView.bounds.size.height)]];
546 | for (int i = 0; i < array.count - 1; i++) {
547 | CGPoint p1 = [self.pointArray[i] CGPointValue];
548 | CGPoint p2 = [self.pointArray[i+1] CGPointValue];
549 | CGPoint p3 = [self.pointArray[i+2] CGPointValue];
550 | CGPoint p4 = [self.pointArray[i+3] CGPointValue];
551 | if (i == 0) {
552 | [dataPath moveToPoint:p2];
553 | }
554 | [self getControlPointOfBezierPath:dataPath andPointx0:p1.x andy0:p1.y x1:p2.x andy1:p2.y x2:p3.x andy2:p3.y x3:p4.x andy3:p4.y];
555 | }
556 | }
557 |
558 | CAShapeLayer *dataLayer = [CAShapeLayer layer];
559 | dataLayer.path = dataPath.CGPath;
560 | dataLayer.strokeColor = [self colorWithHexString:self.colorArray[i] andAlpha:1.0].CGColor;
561 | dataLayer.fillColor = nil;//[self colorWithHexString:self.lineColor andAlpha:1.0].CGColor;
562 | dataLayer.lineWidth = self.lineWidth;
563 | [self.dataView.layer addSublayer:dataLayer];
564 |
565 | // 显示数据具体值
566 | if (self.showDataLabel) {
567 | for (int k = 0; k < array.count; k++) {
568 | NSString *num = array[k];
569 | CGFloat pointHeight = self.dataView.bounds.size.height - (self.dataView.bounds.size.height - 20) * [num intValue] / maxNum;
570 | UILabel *dataLable = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, groupWidth, 16)];
571 | dataLable.center = CGPointMake(groupWidth / 2 + groupWidth * k, pointHeight - 8);
572 | dataLable.font = [UIFont systemFontOfSize:8];
573 | dataLable.textColor = [self colorWithHexString:@"#404040" andAlpha:1.0];
574 | dataLable.textAlignment = NSTextAlignmentCenter;
575 | dataLable.text = array[k];
576 | [self.dataView addSubview:dataLable];
577 | }
578 | }
579 | }
580 |
581 | // 动画
582 | CABasicAnimation *strokeAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
583 | strokeAnimation.fromValue = @0;// 起始值
584 | strokeAnimation.toValue = @1;// 结束值
585 | strokeAnimation.duration = 1;// 动画持续时间
586 | strokeAnimation.repeatCount = 1;// 重复次数
587 | strokeAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
588 | strokeAnimation.removedOnCompletion = YES;
589 | [bgLayer addAnimation:strokeAnimation forKey:@"pieAnimation"];
590 | }
591 |
592 | #pragma mark - resetData
593 | - (void)resetData {
594 | if (self.isSingleLine) {
595 | [self resetSingleLine];
596 | } else {
597 | [self resetMultiLine];
598 | }
599 | }
600 |
601 | #pragma mark - getter
602 | - (NSArray *)dataNameArray {
603 | if (!_dataNameArray) {
604 | _dataNameArray = [NSArray array];
605 | }
606 | return _dataNameArray;
607 | }
608 |
609 | - (NSArray *)dataArray {
610 | if (!_dataArray) {
611 | _dataArray = [NSArray array];
612 | }
613 | return _dataArray;
614 | }
615 |
616 | - (NSArray *)legendNameArray {
617 | if (!_legendNameArray) {
618 | _legendNameArray = [NSArray array];
619 | }
620 | return _legendNameArray;
621 | }
622 |
623 | - (NSMutableArray *)pointArray {
624 | if (!_pointArray) {
625 | _pointArray = [NSMutableArray array];
626 | }
627 | return _pointArray;
628 | }
629 |
630 | - (NSMutableArray *)colorArray {
631 | if (!_colorArray) {
632 | _colorArray = [NSMutableArray array];
633 | }
634 | return _colorArray;
635 | }
636 |
637 | - (NSArray *)legendColorArray {
638 | if (!_legendColorArray) {
639 | _legendColorArray = [NSArray array];
640 | }
641 | return _legendColorArray;
642 | }
643 |
644 | #pragma mark - other
645 | // 向上取整十、整百、整千等值
646 | - (int)approximateRoundNumberWithString:(NSString *)numString {
647 | NSInteger length = numString.length;
648 | NSString *numberGrade = @"1";// 数字量级
649 | for (int i = 0; i < length - 1; i++) {
650 | numberGrade = [numberGrade stringByAppendingString:@"0"];
651 | }
652 | return ceil((double)[numString intValue] / [numberGrade intValue]) * [numberGrade intValue];
653 | }
654 |
655 | - (UIColor *)colorWithHexString:(NSString *)color andAlpha:(CGFloat)alpha{
656 | //删除字符串中的空格
657 | NSString *cString = [[color stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] uppercaseString];
658 |
659 | // String should be 6 or 8 characters
660 | if ([cString length] < 6)
661 | {
662 | return [UIColor clearColor];
663 | }
664 |
665 | // strip 0X if it appears
666 | //如果是0x开头的,那么截取字符串,字符串从索引为2的位置开始,一直到末尾
667 | if ([cString hasPrefix:@"0X"])
668 | {
669 | cString = [cString substringFromIndex:2];
670 | }
671 |
672 | //如果是#开头的,那么截取字符串,字符串从索引为1的位置开始,一直到末尾
673 | if ([cString hasPrefix:@"#"])
674 | {
675 | cString = [cString substringFromIndex:1];
676 | }
677 | if ([cString length] != 6)
678 | {
679 | return [UIColor clearColor];
680 | }
681 |
682 | // Separate into r, g, b substrings
683 | NSRange range;
684 |
685 | range.location = 0;
686 |
687 | range.length = 2;
688 |
689 | //r
690 | NSString *rString = [cString substringWithRange:range];
691 |
692 | //g
693 | range.location = 2;
694 |
695 | NSString *gString = [cString substringWithRange:range];
696 |
697 | //b
698 | range.location = 4;
699 |
700 | NSString *bString = [cString substringWithRange:range];
701 |
702 | // Scan values
703 | unsigned int r, g, b;
704 |
705 | [[NSScanner scannerWithString:rString] scanHexInt:&r];
706 |
707 | [[NSScanner scannerWithString:gString] scanHexInt:&g];
708 |
709 | [[NSScanner scannerWithString:bString] scanHexInt:&b];
710 |
711 | return [UIColor colorWithRed:((float)r / 255.0f) green:((float)g / 255.0f) blue:((float)b / 255.0f) alpha:alpha];
712 | }
713 |
714 |
715 | /**
716 | 传入四个点求两个控制点 (画2,3之间的曲线,需要传入1,2,3,4的坐标)
717 | 参考自:https://www.jianshu.com/p/c33081adce28
718 | 实在是看球不懂
719 | */
720 | - (void)getControlPointOfBezierPath:(UIBezierPath *)bezierPath
721 | andPointx0:(CGFloat)x0 andy0:(CGFloat)y0
722 | x1:(CGFloat)x1 andy1:(CGFloat)y1
723 | x2:(CGFloat)x2 andy2:(CGFloat)y2
724 | x3:(CGFloat)x3 andy3:(CGFloat)y3 {
725 | CGFloat smooth_value = 0.6;
726 | CGFloat ctrl1_x;
727 | CGFloat ctrl1_y;
728 | CGFloat ctrl2_x;
729 | CGFloat ctrl2_y;
730 | CGFloat xc1 = (x0 + x1) /2.0;
731 | CGFloat yc1 = (y0 + y1) /2.0;
732 | CGFloat xc2 = (x1 + x2) /2.0;
733 | CGFloat yc2 = (y1 + y2) /2.0;
734 | CGFloat xc3 = (x2 + x3) /2.0;
735 | CGFloat yc3 = (y2 + y3) /2.0;
736 | CGFloat len1 = sqrt((x1-x0) * (x1-x0) + (y1-y0) * (y1-y0));
737 | CGFloat len2 = sqrt((x2-x1) * (x2-x1) + (y2-y1) * (y2-y1));
738 | CGFloat len3 = sqrt((x3-x2) * (x3-x2) + (y3-y2) * (y3-y2));
739 | CGFloat k1 = len1 / (len1 + len2);
740 | CGFloat k2 = len2 / (len2 + len3);
741 | CGFloat xm1 = xc1 + (xc2 - xc1) * k1;
742 | CGFloat ym1 = yc1 + (yc2 - yc1) * k1;
743 | CGFloat xm2 = xc2 + (xc3 - xc2) * k2;
744 | CGFloat ym2 = yc2 + (yc3 - yc2) * k2;
745 | ctrl1_x = xm1 + (xc2 - xm1) * smooth_value + x1 - xm1;
746 | ctrl1_y = ym1 + (yc2 - ym1) * smooth_value + y1 - ym1;
747 | ctrl2_x = xm2 + (xc2 - xm2) * smooth_value + x2 - xm2;
748 | ctrl2_y = ym2 + (yc2 - ym2) * smooth_value + y2 - ym2;
749 |
750 | [bezierPath addCurveToPoint:CGPointMake(x2, y2) controlPoint1:CGPointMake(ctrl1_x, ctrl1_y) controlPoint2:CGPointMake(ctrl2_x, ctrl2_y)];
751 | }
752 |
753 |
754 | @end
755 |
--------------------------------------------------------------------------------