├── ZFPlotChart ├── preview.png ├── AppDelegate.h ├── ViewController.h ├── main.m ├── Images.xcassets │ └── AppIcon.appiconset │ │ └── Contents.json ├── Base.lproj │ ├── Main.storyboard │ └── LaunchScreen.xib ├── Info.plist ├── ZFPlotChart.h ├── ViewController.m ├── AppDelegate.m ├── data.json └── ZFPlotChart.m ├── ZFPlotChart.xcodeproj ├── xcuserdata │ └── Francesco.xcuserdatad │ │ ├── xcdebugger │ │ └── Breakpoints_v2.xcbkptlist │ │ └── xcschemes │ │ ├── xcschememanagement.plist │ │ └── ZFPlotChart.xcscheme ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── ZFPlotChart.xccheckout └── project.pbxproj ├── README.md └── ZFPlotChartTests ├── Info.plist └── ZFPlotChartTests.m /ZFPlotChart/preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zerbfra/ZFPlotChart/HEAD/ZFPlotChart/preview.png -------------------------------------------------------------------------------- /ZFPlotChart.xcodeproj/xcuserdata/Francesco.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /ZFPlotChart.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ZFPlotChart/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // ZFPlotChart 4 | // 5 | // Created by Francesco Zerbinati on 21/06/15. 6 | // Copyright (c) 2015 Francesco Zerbinati. 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 | -------------------------------------------------------------------------------- /ZFPlotChart/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // ZFPlotChart 4 | // 5 | // Created by Francesco Zerbinati on 21/06/15. 6 | // Copyright (c) 2015 Francesco Zerbinati. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "ZFPlotChart.h" 11 | 12 | @interface ViewController : UIViewController 13 | 14 | @property (strong, nonatomic) IBOutlet ZFPlotChart *plotChart; 15 | 16 | 17 | @end 18 | 19 | -------------------------------------------------------------------------------- /ZFPlotChart/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // ZFPlotChart 4 | // 5 | // Created by Francesco Zerbinati on 21/06/15. 6 | // Copyright (c) 2015 Francesco Zerbinati. 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ZFPlotChart 2 | _Simple class to draw a line graph based on a JSON file, written in Objective-C_ 3 | 4 | This class is used in PriceRadar, the app I wrote to track prices on Amazon, available [here](https://itunes.apple.com/us/app/priceradar-seguiprezzo-per/id790926556?mt=8) 5 | 6 | Inside the project you will find a sample JSON used to make the example. 7 | 8 | As you can see it comes handy when drawing price/stock values during time. 9 | 10 | Feel free to use this class, let me know if you find some bugs! 11 | 12 | ## Preview Image 13 | 14 | ![ZFPlotChart](ZFPlotChart/preview.png) 15 | -------------------------------------------------------------------------------- /ZFPlotChart.xcodeproj/xcuserdata/Francesco.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | ZFPlotChart.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 13899B3B1B36CF4B0060AD92 16 | 17 | primary 18 | 19 | 20 | 13899B541B36CF4B0060AD92 21 | 22 | primary 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /ZFPlotChartTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | it.zerbinatifrancesco.$(PRODUCT_NAME:rfc1034identifier) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /ZFPlotChartTests/ZFPlotChartTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // ZFPlotChartTests.m 3 | // ZFPlotChartTests 4 | // 5 | // Created by Francesco Zerbinati on 21/06/15. 6 | // Copyright (c) 2015 Francesco Zerbinati. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | @interface ZFPlotChartTests : XCTestCase 13 | 14 | @end 15 | 16 | @implementation ZFPlotChartTests 17 | 18 | - (void)setUp { 19 | [super setUp]; 20 | // Put setup code here. This method is called before the invocation of each test method in the class. 21 | } 22 | 23 | - (void)tearDown { 24 | // Put teardown code here. This method is called after the invocation of each test method in the class. 25 | [super tearDown]; 26 | } 27 | 28 | - (void)testExample { 29 | // This is an example of a functional test case. 30 | XCTAssert(YES, @"Pass"); 31 | } 32 | 33 | - (void)testPerformanceExample { 34 | // This is an example of a performance test case. 35 | [self measureBlock:^{ 36 | // Put the code you want to measure the time of here. 37 | }]; 38 | } 39 | 40 | @end 41 | -------------------------------------------------------------------------------- /ZFPlotChart/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "ipad", 35 | "size" : "29x29", 36 | "scale" : "1x" 37 | }, 38 | { 39 | "idiom" : "ipad", 40 | "size" : "29x29", 41 | "scale" : "2x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "40x40", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "40x40", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "76x76", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "76x76", 61 | "scale" : "2x" 62 | } 63 | ], 64 | "info" : { 65 | "version" : 1, 66 | "author" : "xcode" 67 | } 68 | } -------------------------------------------------------------------------------- /ZFPlotChart/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /ZFPlotChart.xcodeproj/project.xcworkspace/xcshareddata/ZFPlotChart.xccheckout: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDESourceControlProjectFavoriteDictionaryKey 6 | 7 | IDESourceControlProjectIdentifier 8 | C2A84B5D-487D-4925-8D32-6112C53FB1A7 9 | IDESourceControlProjectName 10 | ZFPlotChart 11 | IDESourceControlProjectOriginsDictionary 12 | 13 | B333D55996A51EE13B7A99C43A031119C1C70BA4 14 | https://github.com/zerbfra/zfPlotChart.git 15 | 16 | IDESourceControlProjectPath 17 | ZFPlotChart.xcodeproj 18 | IDESourceControlProjectRelativeInstallPathDictionary 19 | 20 | B333D55996A51EE13B7A99C43A031119C1C70BA4 21 | ../.. 22 | 23 | IDESourceControlProjectURL 24 | https://github.com/zerbfra/zfPlotChart.git 25 | IDESourceControlProjectVersion 26 | 111 27 | IDESourceControlProjectWCCIdentifier 28 | B333D55996A51EE13B7A99C43A031119C1C70BA4 29 | IDESourceControlProjectWCConfigurations 30 | 31 | 32 | IDESourceControlRepositoryExtensionIdentifierKey 33 | public.vcs.git 34 | IDESourceControlWCCIdentifierKey 35 | B333D55996A51EE13B7A99C43A031119C1C70BA4 36 | IDESourceControlWCCName 37 | ZFPlotChart 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /ZFPlotChart/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | it.zerbinatifrancesco.$(PRODUCT_NAME:rfc1034identifier) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationLandscapeLeft 37 | UIInterfaceOrientationLandscapeRight 38 | 39 | UISupportedInterfaceOrientations~ipad 40 | 41 | UIInterfaceOrientationPortrait 42 | UIInterfaceOrientationPortraitUpsideDown 43 | UIInterfaceOrientationLandscapeLeft 44 | UIInterfaceOrientationLandscapeRight 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /ZFPlotChart/ZFPlotChart.h: -------------------------------------------------------------------------------- 1 | // 2 | // ZFPlotChart.h 3 | // 4 | // Created by Zerbinati Francesco 5 | // Copyright (c) 2014-2015 6 | // 7 | 8 | #import 9 | #import 10 | 11 | #define COLOR_WITH_RGB(r,g,b) [UIColor colorWithRed:r/255.0f green:g/255.0f blue:b/255.0f alpha:1.0f] // Macro for colors 12 | 13 | // Dimension costants 14 | #define topMargin 20.0f // top margin 15 | #define vMargin 40.0f // vertical margin 16 | #define hMargin 10.0f // horizontal margin 17 | #define leftSpace 10.0f // left space 18 | 19 | // Graph grid color 20 | #define linesColor [UIColor lightGrayColor] 21 | 22 | // Colors for lines and background 23 | #define orangeColor COLOR_WITH_RGB(255, 150, 10) 24 | #define whiteColor [UIColor whiteColor] 25 | 26 | // Fonts 27 | #define systemFont [UIFont systemFontOfSize:10] 28 | #define boldFont [UIFont boldSystemFontOfSize:10] 29 | 30 | // definitions (as JSON) 31 | #define fzPoint @"Point" 32 | #define fzValue @"value" 33 | #define fzDate @"time" 34 | #define fzDateFormat @"yyyyMMdd" 35 | 36 | @interface ZFPlotChart : UIView 37 | { 38 | NSMutableOrderedSet *dictDispPoint; 39 | float chartWidth, chartHeight; 40 | CGPoint prevPoint, curPoint; 41 | float min, max; 42 | BOOL isMovement; // Default NO 43 | CGPoint currentLoc; 44 | } 45 | 46 | @property (nonatomic, retain) NSMutableOrderedSet *dictDispPoint; 47 | 48 | @property (nonatomic, readwrite) float chartWidth, chartHeight; 49 | @property (nonatomic, readwrite) CGFloat leftMargin; 50 | 51 | @property (nonatomic, readwrite) CGPoint prevPoint, curPoint, currentLoc; 52 | @property (nonatomic, readwrite) float min, max; 53 | 54 | @property (nonatomic, readwrite) float yMax,yMin; 55 | 56 | @property (strong) UIActivityIndicatorView *loadingSpinner; 57 | 58 | - (void)createChartWith:(NSOrderedSet *)data; 59 | 60 | @end 61 | -------------------------------------------------------------------------------- /ZFPlotChart/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // ZFPlotChart 4 | // 5 | // Created by Francesco Zerbinati on 21/06/15. 6 | // Copyright (c) 2015 Francesco Zerbinati. All rights reserved. 7 | // 8 | 9 | #import "ViewController.h" 10 | 11 | @interface ViewController () 12 | 13 | @end 14 | 15 | @implementation ViewController 16 | 17 | - (void)viewDidLoad { 18 | [super viewDidLoad]; 19 | 20 | /********** Creating an area for the graph ***********/ 21 | 22 | CGRect screenRect = [[UIScreen mainScreen] bounds]; 23 | CGFloat screenWidth = screenRect.size.width; 24 | 25 | CGRect frame = CGRectMake(0, 100, screenWidth, 190); 26 | 27 | // initialization 28 | self.plotChart = [[ZFPlotChart alloc] initWithFrame:frame]; 29 | [self.view addSubview:self.plotChart]; 30 | 31 | 32 | // get the data from the json file 33 | NSString *filePath = [[NSBundle mainBundle] pathForResource:@"data" ofType:@"json"]; 34 | // string creation 35 | NSString *jsonString = [[NSString alloc] initWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:NULL]; 36 | // json parsing 37 | NSDictionary *json = [NSJSONSerialization JSONObjectWithData:[jsonString dataUsingEncoding:NSUTF8StringEncoding] options:kNilOptions error:nil]; 38 | 39 | if (!json) { 40 | NSLog(@"Error parsing JSON"); 41 | } else { 42 | NSLog(@"%@",json); 43 | } 44 | 45 | // values are contained inside "values" in the JSON file 46 | NSArray *values = [json valueForKeyPath:@"values"]; 47 | // create the nsorderedset from the array 48 | NSOrderedSet *result = [NSOrderedSet orderedSetWithArray:values]; 49 | 50 | self.plotChart.alpha = 0; 51 | // draw data 52 | [self.plotChart createChartWith:result]; 53 | [UIView animateWithDuration:0.5 animations:^{ 54 | self.plotChart.alpha = 1.0; 55 | }]; 56 | 57 | 58 | } 59 | 60 | - (void)didReceiveMemoryWarning { 61 | [super didReceiveMemoryWarning]; 62 | // Dispose of any resources that can be recreated. 63 | } 64 | 65 | @end 66 | -------------------------------------------------------------------------------- /ZFPlotChart/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // ZFPlotChart 4 | // 5 | // Created by Francesco Zerbinati on 21/06/15. 6 | // Copyright (c) 2015 Francesco Zerbinati. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | 11 | @interface AppDelegate () 12 | 13 | @end 14 | 15 | @implementation AppDelegate 16 | 17 | 18 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 19 | // Override point for customization after application launch. 20 | return YES; 21 | } 22 | 23 | - (void)applicationWillResignActive:(UIApplication *)application { 24 | // 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. 25 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 26 | } 27 | 28 | - (void)applicationDidEnterBackground:(UIApplication *)application { 29 | // 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. 30 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 31 | } 32 | 33 | - (void)applicationWillEnterForeground:(UIApplication *)application { 34 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 35 | } 36 | 37 | - (void)applicationDidBecomeActive:(UIApplication *)application { 38 | // 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. 39 | } 40 | 41 | - (void)applicationWillTerminate:(UIApplication *)application { 42 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 43 | } 44 | 45 | @end 46 | -------------------------------------------------------------------------------- /ZFPlotChart/Base.lproj/LaunchScreen.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 20 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /ZFPlotChart.xcodeproj/xcuserdata/Francesco.xcuserdatad/xcschemes/ZFPlotChart.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 38 | 39 | 44 | 45 | 47 | 53 | 54 | 55 | 56 | 57 | 63 | 64 | 65 | 66 | 75 | 77 | 83 | 84 | 85 | 86 | 87 | 88 | 94 | 96 | 102 | 103 | 104 | 105 | 107 | 108 | 111 | 112 | 113 | -------------------------------------------------------------------------------- /ZFPlotChart/data.json: -------------------------------------------------------------------------------- 1 | {"values": [ 2 | { 3 | "time": "20141204", 4 | "value": "12499" 5 | }, 6 | { 7 | "time": "20141205", 8 | "value": "12499" 9 | }, 10 | { 11 | "time": "20141206", 12 | "value": "12499" 13 | }, 14 | { 15 | "time": "20141207", 16 | "value": "12499" 17 | }, 18 | { 19 | "time": "20141208", 20 | "value": "12499" 21 | }, 22 | { 23 | "time": "20141209", 24 | "value": "12499" 25 | }, 26 | { 27 | "time": "20141210", 28 | "value": "12370" 29 | }, 30 | { 31 | "time": "20141211", 32 | "value": "12370" 33 | }, 34 | { 35 | "time": "20141212", 36 | "value": "12370" 37 | }, 38 | { 39 | "time": "20141213", 40 | "value": "12499" 41 | }, 42 | { 43 | "time": "20141214", 44 | "value": "12499" 45 | }, 46 | { 47 | "time": "20141215", 48 | "value": "12499" 49 | }, 50 | { 51 | "time": "20141216", 52 | "value": "12499" 53 | }, 54 | { 55 | "time": "20141217", 56 | "value": "12499" 57 | }, 58 | { 59 | "time": "20141218", 60 | "value": "12374" 61 | }, 62 | { 63 | "time": "20141219", 64 | "value": "12374" 65 | }, 66 | { 67 | "time": "20141220", 68 | "value": "12374" 69 | }, 70 | { 71 | "time": "20141221", 72 | "value": "12374" 73 | }, 74 | { 75 | "time": "20141222", 76 | "value": "12374" 77 | }, 78 | { 79 | "time": "20141223", 80 | "value": "12374" 81 | }, 82 | { 83 | "time": "20141224", 84 | "value": "12374" 85 | }, 86 | { 87 | "time": "20141228", 88 | "value": "12374" 89 | }, 90 | { 91 | "time": "20141229", 92 | "value": "12374" 93 | }, 94 | { 95 | "time": "20141230", 96 | "value": "12374" 97 | }, 98 | { 99 | "time": "20141231", 100 | "value": "12374" 101 | }, 102 | { 103 | "time": "20150101", 104 | "value": "12374" 105 | }, 106 | { 107 | "time": "20150102", 108 | "value": "12374" 109 | }, 110 | { 111 | "time": "20150103", 112 | "value": "12374" 113 | }, 114 | { 115 | "time": "20150104", 116 | "value": "12374" 117 | }, 118 | { 119 | "time": "20150105", 120 | "value": "12374" 121 | }, 122 | { 123 | "time": "20150106", 124 | "value": "12374" 125 | }, 126 | { 127 | "time": "20150107", 128 | "value": "12374" 129 | }, 130 | { 131 | "time": "20150108", 132 | "value": "12374" 133 | }, 134 | { 135 | "time": "20150109", 136 | "value": "12374" 137 | }, 138 | { 139 | "time": "20150110", 140 | "value": "12374" 141 | }, 142 | { 143 | "time": "20150111", 144 | "value": "12374" 145 | }, 146 | { 147 | "time": "20150112", 148 | "value": "12374" 149 | }, 150 | { 151 | "time": "20150113", 152 | "value": "12374" 153 | }, 154 | { 155 | "time": "20150114", 156 | "value": "12374" 157 | }, 158 | { 159 | "time": "20150115", 160 | "value": "12374" 161 | }, 162 | { 163 | "time": "20150116", 164 | "value": "12374" 165 | }, 166 | { 167 | "time": "20150117", 168 | "value": "12370" 169 | }, 170 | { 171 | "time": "20150118", 172 | "value": "12370" 173 | }, 174 | { 175 | "time": "20150119", 176 | "value": "12370" 177 | }, 178 | { 179 | "time": "20150120", 180 | "value": "12370" 181 | }, 182 | { 183 | "time": "20150121", 184 | "value": "12370" 185 | }, 186 | { 187 | "time": "20150122", 188 | "value": "12370" 189 | }, 190 | { 191 | "time": "20150202", 192 | "value": "12370" 193 | }, 194 | { 195 | "time": "20150203", 196 | "value": "12370" 197 | }, 198 | { 199 | "time": "20150204", 200 | "value": "12374" 201 | }, 202 | { 203 | "time": "20150205", 204 | "value": "12374" 205 | }, 206 | { 207 | "time": "20150206", 208 | "value": "12374" 209 | }, 210 | { 211 | "time": "20150207", 212 | "value": "12374" 213 | }, 214 | { 215 | "time": "20150208", 216 | "value": "12374" 217 | }, 218 | { 219 | "time": "20150209", 220 | "value": "12374" 221 | }, 222 | { 223 | "time": "20150210", 224 | "value": "12374" 225 | }, 226 | { 227 | "time": "20150211", 228 | "value": "12374" 229 | }, 230 | { 231 | "time": "20150212", 232 | "value": "12374" 233 | }, 234 | { 235 | "time": "20150213", 236 | "value": "12374" 237 | }, 238 | { 239 | "time": "20150214", 240 | "value": "12374" 241 | }, 242 | { 243 | "time": "20150215", 244 | "value": "12374" 245 | }, 246 | { 247 | "time": "20150216", 248 | "value": "11755" 249 | }, 250 | { 251 | "time": "20150217", 252 | "value": "12374" 253 | }, 254 | { 255 | "time": "20150218", 256 | "value": "12374" 257 | }, 258 | { 259 | "time": "20150219", 260 | "value": "12374" 261 | }, 262 | { 263 | "time": "20150220", 264 | "value": "12374" 265 | }, 266 | { 267 | "time": "20150221", 268 | "value": "12374" 269 | }, 270 | { 271 | "time": "20150222", 272 | "value": "12374" 273 | }, 274 | { 275 | "time": "20150223", 276 | "value": "12374" 277 | }, 278 | { 279 | "time": "20150224", 280 | "value": "12374" 281 | }, 282 | { 283 | "time": "20150225", 284 | "value": "12374" 285 | }, 286 | { 287 | "time": "20150226", 288 | "value": "12374" 289 | }, 290 | { 291 | "time": "20150227", 292 | "value": "12374" 293 | }, 294 | { 295 | "time": "20150228", 296 | "value": "12374" 297 | }, 298 | { 299 | "time": "20150301", 300 | "value": "12374" 301 | }, 302 | { 303 | "time": "20150302", 304 | "value": "12374" 305 | }, 306 | { 307 | "time": "20150303", 308 | "value": "12374" 309 | }, 310 | { 311 | "time": "20150304", 312 | "value": "12374" 313 | }, 314 | { 315 | "time": "20150305", 316 | "value": "12374" 317 | }, 318 | { 319 | "time": "20150306", 320 | "value": "12374" 321 | }, 322 | { 323 | "time": "20150307", 324 | "value": "12374" 325 | }, 326 | { 327 | "time": "20150308", 328 | "value": "12374" 329 | }, 330 | { 331 | "time": "20150309", 332 | "value": "12374" 333 | }, 334 | { 335 | "time": "20150310", 336 | "value": "12374" 337 | }, 338 | { 339 | "time": "20150311", 340 | "value": "12374" 341 | }, 342 | { 343 | "time": "20150312", 344 | "value": "12613" 345 | }, 346 | { 347 | "time": "20150313", 348 | "value": "12374" 349 | }, 350 | { 351 | "time": "20150314", 352 | "value": "12374" 353 | }, 354 | { 355 | "time": "20150315", 356 | "value": "12374" 357 | }, 358 | { 359 | "time": "20150316", 360 | "value": "12374" 361 | }, 362 | { 363 | "time": "20150317", 364 | "value": "12374" 365 | }, 366 | { 367 | "time": "20150318", 368 | "value": "13859" 369 | }, 370 | { 371 | "time": "20150319", 372 | "value": "12863" 373 | }, 374 | { 375 | "time": "20150320", 376 | "value": "11755" 377 | }, 378 | { 379 | "time": "20150321", 380 | "value": "11755" 381 | }, 382 | { 383 | "time": "20150322", 384 | "value": "11755" 385 | }, 386 | { 387 | "time": "20150323", 388 | "value": "11755" 389 | }, 390 | { 391 | "time": "20150324", 392 | "value": "11755" 393 | }, 394 | { 395 | "time": "20150325", 396 | "value": "11755" 397 | }, 398 | { 399 | "time": "20150326", 400 | "value": "11755" 401 | }, 402 | { 403 | "time": "20150327", 404 | "value": "13999" 405 | }, 406 | { 407 | "time": "20150328", 408 | "value": "13999" 409 | }, 410 | { 411 | "time": "20150329", 412 | "value": "13999" 413 | }, 414 | { 415 | "time": "20150330", 416 | "value": "12428" 417 | }, 418 | { 419 | "time": "20150331", 420 | "value": "13724" 421 | }, 422 | { 423 | "time": "20150401", 424 | "value": "12869" 425 | }, 426 | { 427 | "time": "20150402", 428 | "value": "12869" 429 | }, 430 | { 431 | "time": "20150403", 432 | "value": "12869" 433 | }, 434 | { 435 | "time": "20150404", 436 | "value": "12869" 437 | }, 438 | { 439 | "time": "20150405", 440 | "value": "12869" 441 | }, 442 | { 443 | "time": "20150406", 444 | "value": "12869" 445 | }, 446 | { 447 | "time": "20150407", 448 | "value": "12869" 449 | }, 450 | { 451 | "time": "20150408", 452 | "value": "12869" 453 | }, 454 | { 455 | "time": "20150409", 456 | "value": "12869" 457 | }, 458 | { 459 | "time": "20150410", 460 | "value": "12869" 461 | }, 462 | { 463 | "time": "20150411", 464 | "value": "12869" 465 | }, 466 | { 467 | "time": "20150412", 468 | "value": "12869" 469 | }, 470 | { 471 | "time": "20150413", 472 | "value": "13855" 473 | }, 474 | { 475 | "time": "20150414", 476 | "value": "12869" 477 | }, 478 | { 479 | "time": "20150415", 480 | "value": "12869" 481 | }, 482 | { 483 | "time": "20150416", 484 | "value": "12869" 485 | }, 486 | { 487 | "time": "20150417", 488 | "value": "12869" 489 | }, 490 | { 491 | "time": "20150418", 492 | "value": "12869" 493 | }, 494 | { 495 | "time": "20150419", 496 | "value": "12869" 497 | }, 498 | { 499 | "time": "20150420", 500 | "value": "12869" 501 | }, 502 | { 503 | "time": "20150421", 504 | "value": "13598" 505 | }, 506 | { 507 | "time": "20150422", 508 | "value": "12869" 509 | }, 510 | { 511 | "time": "20150423", 512 | "value": "13363" 513 | }, 514 | { 515 | "time": "20150424", 516 | "value": "11879" 517 | }, 518 | { 519 | "time": "20150425", 520 | "value": "11879" 521 | }, 522 | { 523 | "time": "20150426", 524 | "value": "11879" 525 | }, 526 | { 527 | "time": "20150427", 528 | "value": "12374" 529 | }, 530 | { 531 | "time": "20150428", 532 | "value": "12374" 533 | }, 534 | { 535 | "time": "20150429", 536 | "value": "12374" 537 | }, 538 | { 539 | "time": "20150430", 540 | "value": "12621" 541 | }, 542 | { 543 | "time": "20150501", 544 | "value": "12621" 545 | }, 546 | { 547 | "time": "20150502", 548 | "value": "12869" 549 | }, 550 | { 551 | "time": "20150503", 552 | "value": "12869" 553 | }, 554 | { 555 | "time": "20150504", 556 | "value": "12869" 557 | }, 558 | { 559 | "time": "20150505", 560 | "value": "12869" 561 | }, 562 | { 563 | "time": "20150506", 564 | "value": "12869" 565 | }, 566 | { 567 | "time": "20150507", 568 | "value": "12869" 569 | }, 570 | { 571 | "time": "20150508", 572 | "value": "12869" 573 | }, 574 | { 575 | "time": "20150509", 576 | "value": "12869" 577 | }, 578 | { 579 | "time": "20150510", 580 | "value": "12869" 581 | }, 582 | { 583 | "time": "20150511", 584 | "value": "12869" 585 | }, 586 | { 587 | "time": "20150512", 588 | "value": "12869" 589 | }, 590 | { 591 | "time": "20150513", 592 | "value": "12869" 593 | }, 594 | { 595 | "time": "20150514", 596 | "value": "12869" 597 | }, 598 | { 599 | "time": "20150515", 600 | "value": "12869" 601 | }, 602 | { 603 | "time": "20150516", 604 | "value": "12869" 605 | }, 606 | { 607 | "time": "20150517", 608 | "value": "12869" 609 | }, 610 | { 611 | "time": "20150518", 612 | "value": "12349" 613 | }, 614 | { 615 | "time": "20150519", 616 | "value": "12869" 617 | }, 618 | { 619 | "time": "20150531", 620 | "value": "12869" 621 | }, 622 | { 623 | "time": "20150601", 624 | "value": "12869" 625 | }, 626 | { 627 | "time": "20150602", 628 | "value": "12869" 629 | }, 630 | { 631 | "time": "20150603", 632 | "value": "12869" 633 | }, 634 | { 635 | "time": "20150604", 636 | "value": "12999" 637 | }, 638 | { 639 | "time": "20150605", 640 | "value": "13499" 641 | }, 642 | { 643 | "time": "20150606", 644 | "value": "13499" 645 | }, 646 | { 647 | "time": "20150607", 648 | "value": "13499" 649 | }, 650 | { 651 | "time": "20150608", 652 | "value": "13499" 653 | }, 654 | { 655 | "time": "20150609", 656 | "value": "13499" 657 | }, 658 | { 659 | "time": "20150610", 660 | "value": "13499" 661 | }, 662 | { 663 | "time": "20150611", 664 | "value": "13499" 665 | }, 666 | { 667 | "time": "20150612", 668 | "value": "13499" 669 | }, 670 | { 671 | "time": "20150613", 672 | "value": "13499" 673 | }, 674 | { 675 | "time": "20150614", 676 | "value": "13499" 677 | }, 678 | { 679 | "time": "20150615", 680 | "value": "13499" 681 | }, 682 | { 683 | "time": "20150616", 684 | "value": "13498" 685 | }, 686 | { 687 | "time": "20150617", 688 | "value": "12999" 689 | }, 690 | { 691 | "time": "20150618", 692 | "value": "12999" 693 | }, 694 | { 695 | "time": "20150619", 696 | "value": "12999" 697 | }, 698 | { 699 | "time": "20150620", 700 | "value": "12999" 701 | }, 702 | { 703 | "time": "20150621", 704 | "value": "12999" 705 | }, 706 | { 707 | "time": "20150622", 708 | "value": "12999" 709 | }, 710 | { 711 | "time": "20150623", 712 | "value": "12999" 713 | }, 714 | { 715 | "time": "20150624", 716 | "value": "12999" 717 | }, 718 | { 719 | "time": "20150625", 720 | "value": "12999" 721 | }, 722 | { 723 | "time": "20150626", 724 | "value": "12999" 725 | }, 726 | { 727 | "time": "20150627", 728 | "value": "12999" 729 | }, 730 | { 731 | "time": "20150628", 732 | "value": "12999" 733 | }, 734 | { 735 | "time": "20150629", 736 | "value": "12999" 737 | }, 738 | { 739 | "time": "20150630", 740 | "value": "12999" 741 | }, 742 | { 743 | "time": "20150701", 744 | "value": "12999" 745 | }, 746 | { 747 | "time": "20150702", 748 | "value": "12999" 749 | }, 750 | { 751 | "time": "20150703", 752 | "value": "12999" 753 | }, 754 | { 755 | "time": "20150704", 756 | "value": "12999" 757 | }, 758 | { 759 | "time": "20150705", 760 | "value": "12999" 761 | }, 762 | { 763 | "time": "20150706", 764 | "value": "12999" 765 | }, 766 | { 767 | "time": "20150707", 768 | "value": "12999" 769 | }, 770 | { 771 | "time": "20150708", 772 | "value": "12999" 773 | }, 774 | { 775 | "time": "20150709", 776 | "value": "12999" 777 | }, 778 | { 779 | "time": "20150710", 780 | "value": "12999" 781 | }, 782 | { 783 | "time": "20150711", 784 | "value": "12999" 785 | }, 786 | { 787 | "time": "20150712", 788 | "value": "12999" 789 | }, 790 | { 791 | "time": "20150713", 792 | "value": "12999" 793 | }, 794 | { 795 | "time": "20150714", 796 | "value": "12999" 797 | }, 798 | { 799 | "time": "20150715", 800 | "value": "12999" 801 | }, 802 | { 803 | "time": "20150716", 804 | "value": "13999" 805 | }, 806 | { 807 | "time": "20150717", 808 | "value": "12937" 809 | }, 810 | { 811 | "time": "20150718", 812 | "value": "12937" 813 | }, 814 | { 815 | "time": "20150719", 816 | "value": "12937" 817 | }, 818 | { 819 | "time": "20150720", 820 | "value": "13999" 821 | }, 822 | { 823 | "time": "20150721", 824 | "value": "13999" 825 | }, 826 | { 827 | "time": "20150722", 828 | "value": "13999" 829 | }, 830 | { 831 | "time": "20150723", 832 | "value": "13999" 833 | }, 834 | { 835 | "time": "20150724", 836 | "value": "13999" 837 | }, 838 | { 839 | "time": "20150804", 840 | "value": "13998" 841 | }, 842 | { 843 | "time": "20150805", 844 | "value": "13998" 845 | }, 846 | { 847 | "time": "20150806", 848 | "value": "13998" 849 | }, 850 | { 851 | "time": "20150807", 852 | "value": "13998" 853 | }, 854 | { 855 | "time": "20150808", 856 | "value": "13998" 857 | } 858 | ] 859 | } 860 | -------------------------------------------------------------------------------- /ZFPlotChart.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 135A8D301B77A1E000CE017E /* data.json in Resources */ = {isa = PBXBuildFile; fileRef = 135A8D2F1B77A1E000CE017E /* data.json */; }; 11 | 135A8D3A1B77AAF300CE017E /* preview.png in Resources */ = {isa = PBXBuildFile; fileRef = 135A8D391B77AAF300CE017E /* preview.png */; }; 12 | 13899B421B36CF4B0060AD92 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13899B411B36CF4B0060AD92 /* main.m */; }; 13 | 13899B451B36CF4B0060AD92 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 13899B441B36CF4B0060AD92 /* AppDelegate.m */; }; 14 | 13899B481B36CF4B0060AD92 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 13899B471B36CF4B0060AD92 /* ViewController.m */; }; 15 | 13899B4B1B36CF4B0060AD92 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 13899B491B36CF4B0060AD92 /* Main.storyboard */; }; 16 | 13899B4D1B36CF4B0060AD92 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13899B4C1B36CF4B0060AD92 /* Images.xcassets */; }; 17 | 13899B501B36CF4B0060AD92 /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 13899B4E1B36CF4B0060AD92 /* LaunchScreen.xib */; }; 18 | 13899B5C1B36CF4C0060AD92 /* ZFPlotChartTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 13899B5B1B36CF4C0060AD92 /* ZFPlotChartTests.m */; }; 19 | 13899B6A1B36CF820060AD92 /* ZFPlotChart.m in Sources */ = {isa = PBXBuildFile; fileRef = 13899B691B36CF820060AD92 /* ZFPlotChart.m */; }; 20 | /* End PBXBuildFile section */ 21 | 22 | /* Begin PBXContainerItemProxy section */ 23 | 13899B561B36CF4B0060AD92 /* PBXContainerItemProxy */ = { 24 | isa = PBXContainerItemProxy; 25 | containerPortal = 13899B341B36CF4B0060AD92 /* Project object */; 26 | proxyType = 1; 27 | remoteGlobalIDString = 13899B3B1B36CF4B0060AD92; 28 | remoteInfo = ZFPlotChart; 29 | }; 30 | /* End PBXContainerItemProxy section */ 31 | 32 | /* Begin PBXFileReference section */ 33 | 135A8D2F1B77A1E000CE017E /* data.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = data.json; sourceTree = ""; }; 34 | 135A8D391B77AAF300CE017E /* preview.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = preview.png; sourceTree = ""; }; 35 | 13899B3C1B36CF4B0060AD92 /* ZFPlotChart.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ZFPlotChart.app; sourceTree = BUILT_PRODUCTS_DIR; }; 36 | 13899B401B36CF4B0060AD92 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 37 | 13899B411B36CF4B0060AD92 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 38 | 13899B431B36CF4B0060AD92 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 39 | 13899B441B36CF4B0060AD92 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 40 | 13899B461B36CF4B0060AD92 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 41 | 13899B471B36CF4B0060AD92 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 42 | 13899B4A1B36CF4B0060AD92 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 43 | 13899B4C1B36CF4B0060AD92 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 44 | 13899B4F1B36CF4B0060AD92 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; }; 45 | 13899B551B36CF4B0060AD92 /* ZFPlotChartTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ZFPlotChartTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 46 | 13899B5A1B36CF4C0060AD92 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 47 | 13899B5B1B36CF4C0060AD92 /* ZFPlotChartTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ZFPlotChartTests.m; sourceTree = ""; }; 48 | 13899B681B36CF820060AD92 /* ZFPlotChart.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZFPlotChart.h; sourceTree = ""; }; 49 | 13899B691B36CF820060AD92 /* ZFPlotChart.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZFPlotChart.m; sourceTree = ""; }; 50 | /* End PBXFileReference section */ 51 | 52 | /* Begin PBXFrameworksBuildPhase section */ 53 | 13899B391B36CF4B0060AD92 /* Frameworks */ = { 54 | isa = PBXFrameworksBuildPhase; 55 | buildActionMask = 2147483647; 56 | files = ( 57 | ); 58 | runOnlyForDeploymentPostprocessing = 0; 59 | }; 60 | 13899B521B36CF4B0060AD92 /* Frameworks */ = { 61 | isa = PBXFrameworksBuildPhase; 62 | buildActionMask = 2147483647; 63 | files = ( 64 | ); 65 | runOnlyForDeploymentPostprocessing = 0; 66 | }; 67 | /* End PBXFrameworksBuildPhase section */ 68 | 69 | /* Begin PBXGroup section */ 70 | 13899B331B36CF4B0060AD92 = { 71 | isa = PBXGroup; 72 | children = ( 73 | 13899B3E1B36CF4B0060AD92 /* ZFPlotChart */, 74 | 13899B581B36CF4C0060AD92 /* ZFPlotChartTests */, 75 | 13899B3D1B36CF4B0060AD92 /* Products */, 76 | ); 77 | sourceTree = ""; 78 | }; 79 | 13899B3D1B36CF4B0060AD92 /* Products */ = { 80 | isa = PBXGroup; 81 | children = ( 82 | 13899B3C1B36CF4B0060AD92 /* ZFPlotChart.app */, 83 | 13899B551B36CF4B0060AD92 /* ZFPlotChartTests.xctest */, 84 | ); 85 | name = Products; 86 | sourceTree = ""; 87 | }; 88 | 13899B3E1B36CF4B0060AD92 /* ZFPlotChart */ = { 89 | isa = PBXGroup; 90 | children = ( 91 | 13899B431B36CF4B0060AD92 /* AppDelegate.h */, 92 | 13899B441B36CF4B0060AD92 /* AppDelegate.m */, 93 | 13899B461B36CF4B0060AD92 /* ViewController.h */, 94 | 13899B471B36CF4B0060AD92 /* ViewController.m */, 95 | 13899B681B36CF820060AD92 /* ZFPlotChart.h */, 96 | 13899B691B36CF820060AD92 /* ZFPlotChart.m */, 97 | 13899B491B36CF4B0060AD92 /* Main.storyboard */, 98 | 13899B4C1B36CF4B0060AD92 /* Images.xcassets */, 99 | 13899B4E1B36CF4B0060AD92 /* LaunchScreen.xib */, 100 | 13899B3F1B36CF4B0060AD92 /* Supporting Files */, 101 | ); 102 | path = ZFPlotChart; 103 | sourceTree = ""; 104 | }; 105 | 13899B3F1B36CF4B0060AD92 /* Supporting Files */ = { 106 | isa = PBXGroup; 107 | children = ( 108 | 135A8D391B77AAF300CE017E /* preview.png */, 109 | 135A8D2F1B77A1E000CE017E /* data.json */, 110 | 13899B401B36CF4B0060AD92 /* Info.plist */, 111 | 13899B411B36CF4B0060AD92 /* main.m */, 112 | ); 113 | name = "Supporting Files"; 114 | sourceTree = ""; 115 | }; 116 | 13899B581B36CF4C0060AD92 /* ZFPlotChartTests */ = { 117 | isa = PBXGroup; 118 | children = ( 119 | 13899B5B1B36CF4C0060AD92 /* ZFPlotChartTests.m */, 120 | 13899B591B36CF4C0060AD92 /* Supporting Files */, 121 | ); 122 | path = ZFPlotChartTests; 123 | sourceTree = ""; 124 | }; 125 | 13899B591B36CF4C0060AD92 /* Supporting Files */ = { 126 | isa = PBXGroup; 127 | children = ( 128 | 13899B5A1B36CF4C0060AD92 /* Info.plist */, 129 | ); 130 | name = "Supporting Files"; 131 | sourceTree = ""; 132 | }; 133 | /* End PBXGroup section */ 134 | 135 | /* Begin PBXNativeTarget section */ 136 | 13899B3B1B36CF4B0060AD92 /* ZFPlotChart */ = { 137 | isa = PBXNativeTarget; 138 | buildConfigurationList = 13899B5F1B36CF4C0060AD92 /* Build configuration list for PBXNativeTarget "ZFPlotChart" */; 139 | buildPhases = ( 140 | 13899B381B36CF4B0060AD92 /* Sources */, 141 | 13899B391B36CF4B0060AD92 /* Frameworks */, 142 | 13899B3A1B36CF4B0060AD92 /* Resources */, 143 | ); 144 | buildRules = ( 145 | ); 146 | dependencies = ( 147 | ); 148 | name = ZFPlotChart; 149 | productName = ZFPlotChart; 150 | productReference = 13899B3C1B36CF4B0060AD92 /* ZFPlotChart.app */; 151 | productType = "com.apple.product-type.application"; 152 | }; 153 | 13899B541B36CF4B0060AD92 /* ZFPlotChartTests */ = { 154 | isa = PBXNativeTarget; 155 | buildConfigurationList = 13899B621B36CF4C0060AD92 /* Build configuration list for PBXNativeTarget "ZFPlotChartTests" */; 156 | buildPhases = ( 157 | 13899B511B36CF4B0060AD92 /* Sources */, 158 | 13899B521B36CF4B0060AD92 /* Frameworks */, 159 | 13899B531B36CF4B0060AD92 /* Resources */, 160 | ); 161 | buildRules = ( 162 | ); 163 | dependencies = ( 164 | 13899B571B36CF4B0060AD92 /* PBXTargetDependency */, 165 | ); 166 | name = ZFPlotChartTests; 167 | productName = ZFPlotChartTests; 168 | productReference = 13899B551B36CF4B0060AD92 /* ZFPlotChartTests.xctest */; 169 | productType = "com.apple.product-type.bundle.unit-test"; 170 | }; 171 | /* End PBXNativeTarget section */ 172 | 173 | /* Begin PBXProject section */ 174 | 13899B341B36CF4B0060AD92 /* Project object */ = { 175 | isa = PBXProject; 176 | attributes = { 177 | LastUpgradeCheck = 0630; 178 | ORGANIZATIONNAME = "Francesco Zerbinati"; 179 | TargetAttributes = { 180 | 13899B3B1B36CF4B0060AD92 = { 181 | CreatedOnToolsVersion = 6.3.2; 182 | }; 183 | 13899B541B36CF4B0060AD92 = { 184 | CreatedOnToolsVersion = 6.3.2; 185 | TestTargetID = 13899B3B1B36CF4B0060AD92; 186 | }; 187 | }; 188 | }; 189 | buildConfigurationList = 13899B371B36CF4B0060AD92 /* Build configuration list for PBXProject "ZFPlotChart" */; 190 | compatibilityVersion = "Xcode 3.2"; 191 | developmentRegion = English; 192 | hasScannedForEncodings = 0; 193 | knownRegions = ( 194 | en, 195 | Base, 196 | ); 197 | mainGroup = 13899B331B36CF4B0060AD92; 198 | productRefGroup = 13899B3D1B36CF4B0060AD92 /* Products */; 199 | projectDirPath = ""; 200 | projectRoot = ""; 201 | targets = ( 202 | 13899B3B1B36CF4B0060AD92 /* ZFPlotChart */, 203 | 13899B541B36CF4B0060AD92 /* ZFPlotChartTests */, 204 | ); 205 | }; 206 | /* End PBXProject section */ 207 | 208 | /* Begin PBXResourcesBuildPhase section */ 209 | 13899B3A1B36CF4B0060AD92 /* Resources */ = { 210 | isa = PBXResourcesBuildPhase; 211 | buildActionMask = 2147483647; 212 | files = ( 213 | 13899B4B1B36CF4B0060AD92 /* Main.storyboard in Resources */, 214 | 13899B501B36CF4B0060AD92 /* LaunchScreen.xib in Resources */, 215 | 13899B4D1B36CF4B0060AD92 /* Images.xcassets in Resources */, 216 | 135A8D301B77A1E000CE017E /* data.json in Resources */, 217 | 135A8D3A1B77AAF300CE017E /* preview.png in Resources */, 218 | ); 219 | runOnlyForDeploymentPostprocessing = 0; 220 | }; 221 | 13899B531B36CF4B0060AD92 /* Resources */ = { 222 | isa = PBXResourcesBuildPhase; 223 | buildActionMask = 2147483647; 224 | files = ( 225 | ); 226 | runOnlyForDeploymentPostprocessing = 0; 227 | }; 228 | /* End PBXResourcesBuildPhase section */ 229 | 230 | /* Begin PBXSourcesBuildPhase section */ 231 | 13899B381B36CF4B0060AD92 /* Sources */ = { 232 | isa = PBXSourcesBuildPhase; 233 | buildActionMask = 2147483647; 234 | files = ( 235 | 13899B481B36CF4B0060AD92 /* ViewController.m in Sources */, 236 | 13899B6A1B36CF820060AD92 /* ZFPlotChart.m in Sources */, 237 | 13899B451B36CF4B0060AD92 /* AppDelegate.m in Sources */, 238 | 13899B421B36CF4B0060AD92 /* main.m in Sources */, 239 | ); 240 | runOnlyForDeploymentPostprocessing = 0; 241 | }; 242 | 13899B511B36CF4B0060AD92 /* Sources */ = { 243 | isa = PBXSourcesBuildPhase; 244 | buildActionMask = 2147483647; 245 | files = ( 246 | 13899B5C1B36CF4C0060AD92 /* ZFPlotChartTests.m in Sources */, 247 | ); 248 | runOnlyForDeploymentPostprocessing = 0; 249 | }; 250 | /* End PBXSourcesBuildPhase section */ 251 | 252 | /* Begin PBXTargetDependency section */ 253 | 13899B571B36CF4B0060AD92 /* PBXTargetDependency */ = { 254 | isa = PBXTargetDependency; 255 | target = 13899B3B1B36CF4B0060AD92 /* ZFPlotChart */; 256 | targetProxy = 13899B561B36CF4B0060AD92 /* PBXContainerItemProxy */; 257 | }; 258 | /* End PBXTargetDependency section */ 259 | 260 | /* Begin PBXVariantGroup section */ 261 | 13899B491B36CF4B0060AD92 /* Main.storyboard */ = { 262 | isa = PBXVariantGroup; 263 | children = ( 264 | 13899B4A1B36CF4B0060AD92 /* Base */, 265 | ); 266 | name = Main.storyboard; 267 | sourceTree = ""; 268 | }; 269 | 13899B4E1B36CF4B0060AD92 /* LaunchScreen.xib */ = { 270 | isa = PBXVariantGroup; 271 | children = ( 272 | 13899B4F1B36CF4B0060AD92 /* Base */, 273 | ); 274 | name = LaunchScreen.xib; 275 | sourceTree = ""; 276 | }; 277 | /* End PBXVariantGroup section */ 278 | 279 | /* Begin XCBuildConfiguration section */ 280 | 13899B5D1B36CF4C0060AD92 /* Debug */ = { 281 | isa = XCBuildConfiguration; 282 | buildSettings = { 283 | ALWAYS_SEARCH_USER_PATHS = NO; 284 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 285 | CLANG_CXX_LIBRARY = "libc++"; 286 | CLANG_ENABLE_MODULES = YES; 287 | CLANG_ENABLE_OBJC_ARC = YES; 288 | CLANG_WARN_BOOL_CONVERSION = YES; 289 | CLANG_WARN_CONSTANT_CONVERSION = YES; 290 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 291 | CLANG_WARN_EMPTY_BODY = YES; 292 | CLANG_WARN_ENUM_CONVERSION = YES; 293 | CLANG_WARN_INT_CONVERSION = YES; 294 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 295 | CLANG_WARN_UNREACHABLE_CODE = YES; 296 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 297 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 298 | COPY_PHASE_STRIP = NO; 299 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 300 | ENABLE_STRICT_OBJC_MSGSEND = YES; 301 | GCC_C_LANGUAGE_STANDARD = gnu99; 302 | GCC_DYNAMIC_NO_PIC = NO; 303 | GCC_NO_COMMON_BLOCKS = YES; 304 | GCC_OPTIMIZATION_LEVEL = 0; 305 | GCC_PREPROCESSOR_DEFINITIONS = ( 306 | "DEBUG=1", 307 | "$(inherited)", 308 | ); 309 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 310 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 311 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 312 | GCC_WARN_UNDECLARED_SELECTOR = YES; 313 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 314 | GCC_WARN_UNUSED_FUNCTION = YES; 315 | GCC_WARN_UNUSED_VARIABLE = YES; 316 | IPHONEOS_DEPLOYMENT_TARGET = 8.3; 317 | MTL_ENABLE_DEBUG_INFO = YES; 318 | ONLY_ACTIVE_ARCH = YES; 319 | SDKROOT = iphoneos; 320 | TARGETED_DEVICE_FAMILY = "1,2"; 321 | }; 322 | name = Debug; 323 | }; 324 | 13899B5E1B36CF4C0060AD92 /* Release */ = { 325 | isa = XCBuildConfiguration; 326 | buildSettings = { 327 | ALWAYS_SEARCH_USER_PATHS = NO; 328 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 329 | CLANG_CXX_LIBRARY = "libc++"; 330 | CLANG_ENABLE_MODULES = YES; 331 | CLANG_ENABLE_OBJC_ARC = YES; 332 | CLANG_WARN_BOOL_CONVERSION = YES; 333 | CLANG_WARN_CONSTANT_CONVERSION = YES; 334 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 335 | CLANG_WARN_EMPTY_BODY = YES; 336 | CLANG_WARN_ENUM_CONVERSION = YES; 337 | CLANG_WARN_INT_CONVERSION = YES; 338 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 339 | CLANG_WARN_UNREACHABLE_CODE = YES; 340 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 341 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 342 | COPY_PHASE_STRIP = NO; 343 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 344 | ENABLE_NS_ASSERTIONS = NO; 345 | ENABLE_STRICT_OBJC_MSGSEND = YES; 346 | GCC_C_LANGUAGE_STANDARD = gnu99; 347 | GCC_NO_COMMON_BLOCKS = YES; 348 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 349 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 350 | GCC_WARN_UNDECLARED_SELECTOR = YES; 351 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 352 | GCC_WARN_UNUSED_FUNCTION = YES; 353 | GCC_WARN_UNUSED_VARIABLE = YES; 354 | IPHONEOS_DEPLOYMENT_TARGET = 8.3; 355 | MTL_ENABLE_DEBUG_INFO = NO; 356 | SDKROOT = iphoneos; 357 | TARGETED_DEVICE_FAMILY = "1,2"; 358 | VALIDATE_PRODUCT = YES; 359 | }; 360 | name = Release; 361 | }; 362 | 13899B601B36CF4C0060AD92 /* Debug */ = { 363 | isa = XCBuildConfiguration; 364 | buildSettings = { 365 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 366 | INFOPLIST_FILE = ZFPlotChart/Info.plist; 367 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 368 | PRODUCT_NAME = "$(TARGET_NAME)"; 369 | }; 370 | name = Debug; 371 | }; 372 | 13899B611B36CF4C0060AD92 /* Release */ = { 373 | isa = XCBuildConfiguration; 374 | buildSettings = { 375 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 376 | INFOPLIST_FILE = ZFPlotChart/Info.plist; 377 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 378 | PRODUCT_NAME = "$(TARGET_NAME)"; 379 | }; 380 | name = Release; 381 | }; 382 | 13899B631B36CF4C0060AD92 /* Debug */ = { 383 | isa = XCBuildConfiguration; 384 | buildSettings = { 385 | BUNDLE_LOADER = "$(TEST_HOST)"; 386 | FRAMEWORK_SEARCH_PATHS = ( 387 | "$(SDKROOT)/Developer/Library/Frameworks", 388 | "$(inherited)", 389 | ); 390 | GCC_PREPROCESSOR_DEFINITIONS = ( 391 | "DEBUG=1", 392 | "$(inherited)", 393 | ); 394 | INFOPLIST_FILE = ZFPlotChartTests/Info.plist; 395 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 396 | PRODUCT_NAME = "$(TARGET_NAME)"; 397 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/ZFPlotChart.app/ZFPlotChart"; 398 | }; 399 | name = Debug; 400 | }; 401 | 13899B641B36CF4C0060AD92 /* Release */ = { 402 | isa = XCBuildConfiguration; 403 | buildSettings = { 404 | BUNDLE_LOADER = "$(TEST_HOST)"; 405 | FRAMEWORK_SEARCH_PATHS = ( 406 | "$(SDKROOT)/Developer/Library/Frameworks", 407 | "$(inherited)", 408 | ); 409 | INFOPLIST_FILE = ZFPlotChartTests/Info.plist; 410 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 411 | PRODUCT_NAME = "$(TARGET_NAME)"; 412 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/ZFPlotChart.app/ZFPlotChart"; 413 | }; 414 | name = Release; 415 | }; 416 | /* End XCBuildConfiguration section */ 417 | 418 | /* Begin XCConfigurationList section */ 419 | 13899B371B36CF4B0060AD92 /* Build configuration list for PBXProject "ZFPlotChart" */ = { 420 | isa = XCConfigurationList; 421 | buildConfigurations = ( 422 | 13899B5D1B36CF4C0060AD92 /* Debug */, 423 | 13899B5E1B36CF4C0060AD92 /* Release */, 424 | ); 425 | defaultConfigurationIsVisible = 0; 426 | defaultConfigurationName = Release; 427 | }; 428 | 13899B5F1B36CF4C0060AD92 /* Build configuration list for PBXNativeTarget "ZFPlotChart" */ = { 429 | isa = XCConfigurationList; 430 | buildConfigurations = ( 431 | 13899B601B36CF4C0060AD92 /* Debug */, 432 | 13899B611B36CF4C0060AD92 /* Release */, 433 | ); 434 | defaultConfigurationIsVisible = 0; 435 | defaultConfigurationName = Release; 436 | }; 437 | 13899B621B36CF4C0060AD92 /* Build configuration list for PBXNativeTarget "ZFPlotChartTests" */ = { 438 | isa = XCConfigurationList; 439 | buildConfigurations = ( 440 | 13899B631B36CF4C0060AD92 /* Debug */, 441 | 13899B641B36CF4C0060AD92 /* Release */, 442 | ); 443 | defaultConfigurationIsVisible = 0; 444 | defaultConfigurationName = Release; 445 | }; 446 | /* End XCConfigurationList section */ 447 | }; 448 | rootObject = 13899B341B36CF4B0060AD92 /* Project object */; 449 | } 450 | -------------------------------------------------------------------------------- /ZFPlotChart/ZFPlotChart.m: -------------------------------------------------------------------------------- 1 | // 2 | // ZFPlotChart.m 3 | // 4 | // Created by Zerbinati Francesco 5 | // Copyright (c) 2014-2015 6 | // 7 | 8 | #import "ZFPlotChart.h" 9 | 10 | @implementation ZFPlotChart 11 | 12 | @synthesize dictDispPoint; 13 | @synthesize chartWidth, chartHeight; 14 | 15 | @synthesize prevPoint, curPoint, currentLoc; 16 | @synthesize min, max; 17 | 18 | 19 | #pragma mark - Initialization/LifeCycle Method 20 | - (id)initWithFrame:(CGRect)frame 21 | { 22 | 23 | self = [super initWithFrame:frame]; 24 | if (self) { 25 | // Initialization code 26 | @try { 27 | 28 | [self setAutoresizingMask: UIViewAutoresizingFlexibleWidth]; 29 | [self setAutoresizesSubviews:YES]; 30 | 31 | self.backgroundColor = whiteColor; 32 | 33 | 34 | 35 | self.chartHeight = frame.size.height - vMargin; 36 | self.chartWidth = frame.size.width - hMargin; 37 | 38 | 39 | isMovement = NO; 40 | 41 | self.dictDispPoint = [[NSMutableOrderedSet alloc] initWithCapacity:0]; 42 | 43 | 44 | 45 | } 46 | @catch (NSException *exception) { 47 | NSLog(@"%@",[exception debugDescription]); 48 | } 49 | @finally { 50 | 51 | } 52 | } 53 | return self; 54 | } 55 | 56 | #pragma mark - Chart Creation Method 57 | - (void)createChartWith:(NSOrderedSet *)data 58 | { 59 | 60 | [self.dictDispPoint removeAllObjects]; 61 | 62 | NSMutableOrderedSet *orderSet = [[NSMutableOrderedSet alloc] initWithCapacity:0]; 63 | 64 | // Add data to the orderSet 65 | [data enumerateObjectsUsingBlock:^(id obj, NSUInteger ind, BOOL *stop){ 66 | [orderSet addObject:obj]; 67 | 68 | }]; 69 | 70 | // Find Min & Max of Chart 71 | self.max = [[[orderSet valueForKey:fzValue] valueForKeyPath:@"@max.floatValue"] floatValue]; 72 | self.min = [[[orderSet valueForKey:fzValue] valueForKeyPath:@"@min.floatValue"] floatValue]; 73 | 74 | 75 | // Enhance Upper & Lower Limit for Flexible Display, based on average of min and max 76 | self.max = ceilf((self.max+10 )/ 1000)*1000; 77 | self.min = floor((self.min-10)/1000)*1000; 78 | 79 | // Calculate left space given by the lenght of the string on the axis 80 | self.leftMargin = [self sizeOfString:[self formatNumberAsCurrency:self.max/100 withFractionDigits:0] withFont:systemFont].width + leftSpace; 81 | 82 | self.chartWidth-= self.leftMargin; 83 | float range = self.max-self.min; 84 | 85 | // Calculate deploying points for chart according to values 86 | float xGapBetweenTwoPoints = self.chartWidth/[orderSet count]; 87 | float x , y; 88 | 89 | 90 | x = self.leftMargin; 91 | y = topMargin; 92 | 93 | self.yMax = 0; 94 | 95 | // assing points to values 96 | for(NSDictionary *dictionary in orderSet) 97 | { 98 | float priceValue = [[dictionary valueForKey:fzValue] floatValue]; 99 | 100 | float diff = (self.max-priceValue); 101 | 102 | y = ((self.chartHeight)*diff)/range + topMargin; 103 | 104 | // calculate maximum y 105 | if(y > self.yMax) self.yMax = y; 106 | 107 | CGPoint point = CGPointMake(x,y); 108 | 109 | NSDictionary *dictPoint = [NSDictionary dictionaryWithObjectsAndKeys:[NSValue valueWithCGPoint:point], fzPoint, 110 | [dictionary valueForKey:fzValue], fzValue, 111 | [dictionary valueForKey:fzDate], fzDate, nil]; 112 | 113 | [self.dictDispPoint addObject:dictPoint]; 114 | 115 | x+= xGapBetweenTwoPoints; 116 | } 117 | 118 | [self setNeedsDisplay]; 119 | 120 | } 121 | 122 | #pragma mark - Drawing 123 | - (void)drawRect:(CGRect)rect 124 | { 125 | // Drawing code 126 | @try 127 | { 128 | if([self.dictDispPoint count] > 0) 129 | { 130 | // remove loading animation 131 | [self stopLoading]; 132 | 133 | float range = self.max-self.min; 134 | float intervalHlines = (self.chartHeight)/5.0f; 135 | float intervalValues = range/5.0f; 136 | 137 | // horizontal lines 138 | for(int i=5;i>0;i--) 139 | { 140 | [self setContextWidth:0.5f andColor:linesColor]; 141 | 142 | CGPoint start = CGPointMake(self.leftMargin, self.chartHeight+topMargin-i*intervalHlines); 143 | CGPoint end = CGPointMake(self.chartWidth+self.leftMargin, self.chartHeight+topMargin-i*intervalHlines); 144 | 145 | // draw the line 146 | [self drawLineFrom:start to:end]; 147 | 148 | // draw prices on the axis 149 | NSString *prezzoAsse = [self formatNumberAsCurrency:(self.min+i*intervalValues)/100 withFractionDigits:0]; 150 | CGPoint prezzoAssePoint = CGPointMake(self.leftMargin - [self sizeOfString:prezzoAsse withFont:systemFont].width - 5,(self.chartHeight+topMargin-i*intervalHlines-6)); 151 | 152 | [self drawString:prezzoAsse at:prezzoAssePoint withFont:systemFont andColor:linesColor]; 153 | 154 | [self endContext]; 155 | 156 | } 157 | 158 | /*** Draw points ***/ 159 | [self.dictDispPoint enumerateObjectsUsingBlock:^(id obj, NSUInteger ind, BOOL *stop){ 160 | if(ind > 0) 161 | { 162 | self.prevPoint = [[[self.dictDispPoint objectAtIndex:ind-1] valueForKey:fzPoint] CGPointValue]; 163 | self.curPoint = [[[self.dictDispPoint objectAtIndex:ind] valueForKey:fzPoint] CGPointValue]; 164 | } 165 | else 166 | { 167 | // first point 168 | self.prevPoint = [[[self.dictDispPoint objectAtIndex:ind] valueForKey:fzPoint] CGPointValue]; 169 | self.curPoint = self.prevPoint; 170 | } 171 | 172 | // line style 173 | [self setContextWidth:1.5f andColor:orangeColor]; 174 | 175 | // draw the curve 176 | [self drawCurveFrom:self.prevPoint to:self.curPoint]; 177 | 178 | [self endContext]; 179 | 180 | 181 | long linesRatio; 182 | 183 | if([self.dictDispPoint count] < 4) 184 | linesRatio = [self.dictDispPoint count]/([self.dictDispPoint count]-1); 185 | else linesRatio = [self.dictDispPoint count]/4 ; 186 | 187 | 188 | if(ind%linesRatio == 0) { 189 | 190 | [self setContextWidth:0.5f andColor:linesColor]; 191 | 192 | // Vertical Lines 193 | if(ind!=0) { 194 | CGPoint lower = CGPointMake(self.curPoint.x, topMargin+self.chartHeight); 195 | CGPoint higher = CGPointMake(self.curPoint.x, topMargin); 196 | [self drawLineFrom:lower to: higher]; 197 | 198 | } 199 | 200 | [self endContext]; 201 | 202 | // draw dates on the x axys 203 | NSString* date = [self dateFromString: [[self.dictDispPoint objectAtIndex:ind] valueForKey:fzDate]]; 204 | CGPoint datePoint = CGPointMake(self.curPoint.x-15, topMargin + self.chartHeight + 2); 205 | [self drawString:date at:datePoint withFont:systemFont andColor:linesColor]; 206 | 207 | [self endContext]; 208 | 209 | 210 | } 211 | 212 | }]; 213 | 214 | // gradient's path 215 | CGMutablePathRef path = CGPathCreateMutable(); 216 | 217 | CGPoint origin = CGPointMake(self.leftMargin, topMargin+self.chartHeight); 218 | if (self.dictDispPoint && self.dictDispPoint.count > 0) { 219 | 220 | //origin 221 | CGPathMoveToPoint(path, nil, origin.x, origin.y); 222 | CGPoint p; 223 | for (int i = 0; i < self.dictDispPoint.count; i++) { 224 | p = [[[self.dictDispPoint objectAtIndex:i] valueForKey:fzPoint] CGPointValue]; 225 | CGPathAddLineToPoint(path, nil, p.x, p.y); 226 | } 227 | } 228 | CGPathAddLineToPoint(path, nil, self.curPoint.x, topMargin+self.chartHeight); 229 | CGPathAddLineToPoint(path, nil, origin.x,origin.y); 230 | 231 | // gradient 232 | [self gradientizefromPoint:CGPointMake(0, self.yMax) toPoint:CGPointMake(0, topMargin+self.chartWidth) forPath:path]; 233 | 234 | CGPathRelease(path); 235 | 236 | 237 | // X and Y axys 238 | 239 | [self setContextWidth:1.0f andColor:linesColor]; 240 | 241 | // y 242 | [self drawLineFrom:CGPointMake(self.leftMargin, topMargin) to:CGPointMake(self.leftMargin, self.chartHeight+topMargin)]; 243 | // x 244 | [self drawLineFrom:CGPointMake(self.leftMargin, topMargin+self.chartHeight) to:CGPointMake(self.leftMargin+self.chartWidth, self.chartHeight+topMargin)]; 245 | 246 | // vertical closure 247 | CGPoint startLine = CGPointMake(self.leftMargin+self.chartWidth, topMargin); 248 | CGPoint endLine = CGPointMake(self.leftMargin+self.chartWidth, topMargin+self.chartHeight); 249 | [self drawLineFrom:startLine to:endLine]; 250 | 251 | // horizontal closure 252 | [self drawLineFrom:CGPointMake(self.leftMargin, topMargin) to:CGPointMake(self.chartWidth+self.leftMargin, topMargin)]; 253 | 254 | 255 | [self endContext]; 256 | 257 | 258 | CGContextRef context = UIGraphicsGetCurrentContext(); 259 | 260 | 261 | // popup when moving 262 | if(isMovement) 263 | { 264 | float xGapBetweenTwoPoints = self.chartWidth/[self.dictDispPoint count]; 265 | int pointSlot = currentLoc.x/xGapBetweenTwoPoints; 266 | 267 | if(pointSlot >= 0 && pointSlot < [self.dictDispPoint count]) 268 | { 269 | NSDictionary *dict = [self.dictDispPoint objectAtIndex:pointSlot]; 270 | 271 | // Calculate Point to draw Circle 272 | CGPoint point = CGPointMake([[dict valueForKey:fzPoint] CGPointValue].x,[[dict valueForKey:fzPoint] CGPointValue].y); 273 | 274 | 275 | [self setContextWidth:1.0f andColor:orangeColor]; 276 | 277 | // Line at current Point 278 | [self drawLineFrom:CGPointMake(point.x, topMargin-10) to:CGPointMake(point.x, self.chartHeight+topMargin)]; 279 | [self endContext]; 280 | 281 | // Circle at point 282 | [self setContextWidth:1.0f andColor:orangeColor]; 283 | [self drawCircleAt:point ofRadius:8]; 284 | 285 | [self endContext]; 286 | 287 | 288 | // draw the dynamic value 289 | 290 | float value = [[dict objectForKey:fzValue] floatValue]/100; 291 | NSString *price = [self formatNumberAsCurrency:value withFractionDigits:2]; 292 | 293 | CGSize priceSize = [self sizeOfString:price withFont:boldFont]; 294 | 295 | CGRect priceRect = {point.x-priceSize.width/2, 2, priceSize.width + 10, priceSize.height +3}; 296 | 297 | // if goes out on right 298 | if(point.x+-priceSize.width/2+priceSize.width+12 > self.chartWidth+self.leftMargin) 299 | priceRect.origin.x = self.chartWidth+self.leftMargin-priceSize.width-2; 300 | // if goes out on left 301 | if(priceRect.origin.x < self.leftMargin) 302 | priceRect.origin.x = self.leftMargin-(self.leftMargin/2); 303 | 304 | // rectangle for the label 305 | [self drawRoundedRect:context rect:priceRect radius:5 color:orangeColor]; 306 | // value string 307 | [self drawString:price at:CGPointMake(priceRect.origin.x+(priceRect.size.width-priceSize.width)/2,priceRect.origin.y+1.0f) withFont:boldFont andColor:whiteColor]; 308 | 309 | 310 | 311 | } 312 | } 313 | } 314 | else 315 | { 316 | // draw a loding spinner while loading the data 317 | [self drawLoading]; 318 | } 319 | } 320 | @catch (NSException *exception) { 321 | NSLog(@"%@",[exception debugDescription]); 322 | } 323 | @finally { 324 | 325 | } 326 | } 327 | 328 | 329 | 330 | 331 | #pragma mark - Graphic Utilities 332 | 333 | -(void)drawLoading { 334 | self.loadingSpinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray]; 335 | [self.loadingSpinner startAnimating]; 336 | 337 | CGRect screenRect = [[UIScreen mainScreen] bounds]; 338 | CGFloat screenWidth = screenRect.size.width; 339 | 340 | self.loadingSpinner.center = CGPointMake(screenWidth/2, self.frame.size.height/2); 341 | self.loadingSpinner.hidesWhenStopped = YES; 342 | [self addSubview:self.loadingSpinner]; 343 | } 344 | 345 | -(void)stopLoading { 346 | [self.loadingSpinner stopAnimating]; 347 | } 348 | 349 | -(void)gradientizefromPoint:(CGPoint) startPoint toPoint:(CGPoint) endPoint forPath:(CGMutablePathRef) path{ 350 | 351 | CGContextRef context = UIGraphicsGetCurrentContext(); 352 | 353 | CGFloat colors [] = { 354 | 245.0/255.0, 150.0/255.0, 10.0/255, 0.9, // orange 355 | 255.0/255.0,255.0/255.0,255.0/255.0, 0.0 // white clear 356 | }; 357 | 358 | 359 | 360 | CGColorSpaceRef baseSpace = CGColorSpaceCreateDeviceRGB(); // gray colors want gray color space 361 | CGGradientRef gradient = CGGradientCreateWithColorComponents(baseSpace, colors, NULL, 2); 362 | CGColorSpaceRelease(baseSpace), baseSpace = NULL; 363 | 364 | CGContextSaveGState(context); 365 | CGContextAddPath(context, path); 366 | CGContextClip(context); 367 | 368 | CGRect boundingBox = CGPathGetBoundingBox(path); 369 | CGPoint gradientStart = CGPointMake(0, CGRectGetMinY(boundingBox)); 370 | CGPoint gradientEnd = CGPointMake(0, CGRectGetMaxY(boundingBox)); 371 | 372 | CGContextDrawLinearGradient(context, gradient, gradientStart, gradientEnd, 0); 373 | CGGradientRelease(gradient), gradient = NULL; 374 | CGContextRestoreGState(context); 375 | 376 | 377 | 378 | 379 | } 380 | 381 | -(void)drawMessage:(NSString*)string { 382 | 383 | float stringWidth = [self sizeOfString:string withFont:boldFont].width; 384 | [self drawString:string at:CGPointMake(self.center.x-stringWidth/2, self.center.y) withFont:boldFont andColor:linesColor]; 385 | } 386 | 387 | 388 | // set the context with a specified widht and color 389 | -(void) setContextWidth:(float)width andColor:(UIColor*)color { 390 | 391 | CGContextRef context = UIGraphicsGetCurrentContext(); 392 | CGContextSetLineWidth(context, width); 393 | CGContextSetFillColorWithColor(context, color.CGColor); 394 | CGContextSetStrokeColorWithColor(context, color.CGColor); 395 | } 396 | // end context 397 | -(void)endContext { 398 | CGContextRef context = UIGraphicsGetCurrentContext(); 399 | CGContextStrokePath(context); 400 | } 401 | // line between two points 402 | -(void) drawLineFrom:(CGPoint) start to: (CGPoint)end { 403 | CGContextRef context = UIGraphicsGetCurrentContext(); 404 | CGContextMoveToPoint(context, start.x, start.y); 405 | CGContextAddLineToPoint(context,end.x,end.y); 406 | 407 | } 408 | // curve between two points 409 | -(void) drawCurveFrom:(CGPoint)start to:(CGPoint)end { 410 | CGContextRef context = UIGraphicsGetCurrentContext(); 411 | CGContextMoveToPoint(context, start.x, start.y); 412 | CGContextAddQuadCurveToPoint(context, start.x, start.y, end.x, end.y); 413 | CGContextSetLineCap(context, kCGLineCapRound); 414 | } 415 | // draws a string given a point, font and color 416 | -(void) drawString:(NSString*)string at:(CGPoint)point withFont:(UIFont*)font andColor:(UIColor*)color{ 417 | 418 | NSDictionary *attributes = @{NSFontAttributeName: font, NSForegroundColorAttributeName: color}; 419 | 420 | [string drawAtPoint:point withAttributes:attributes]; 421 | } 422 | // draw a circle given center and radius 423 | -(void) drawCircleAt:(CGPoint)point ofRadius:(int)radius { 424 | CGContextRef context = UIGraphicsGetCurrentContext(); 425 | CGRect myOval = {point.x-radius/2, point.y-radius/2, radius, radius}; 426 | CGContextAddEllipseInRect(context, myOval); 427 | CGContextFillPath(context); 428 | } 429 | // rounded corners rectangle 430 | - (void) drawRoundedRect:(CGContextRef)c rect:(CGRect)rect radius:(int)corner_radius color:(UIColor *)color 431 | { 432 | int x_left = rect.origin.x; 433 | int x_left_center = rect.origin.x + corner_radius; 434 | int x_right_center = rect.origin.x + rect.size.width - corner_radius; 435 | int x_right = rect.origin.x + rect.size.width; 436 | 437 | int y_top = rect.origin.y; 438 | int y_top_center = rect.origin.y + corner_radius; 439 | int y_bottom_center = rect.origin.y + rect.size.height - corner_radius; 440 | int y_bottom = rect.origin.y + rect.size.height; 441 | 442 | /* Begin! */ 443 | CGContextBeginPath(c); 444 | CGContextMoveToPoint(c, x_left, y_top_center); 445 | 446 | /* First corner */ 447 | CGContextAddArcToPoint(c, x_left, y_top, x_left_center, y_top, corner_radius); 448 | CGContextAddLineToPoint(c, x_right_center, y_top); 449 | 450 | /* Second corner */ 451 | CGContextAddArcToPoint(c, x_right, y_top, x_right, y_top_center, corner_radius); 452 | CGContextAddLineToPoint(c, x_right, y_bottom_center); 453 | 454 | /* Third corner */ 455 | CGContextAddArcToPoint(c, x_right, y_bottom, x_right_center, y_bottom, corner_radius); 456 | CGContextAddLineToPoint(c, x_left_center, y_bottom); 457 | 458 | /* Fourth corner */ 459 | CGContextAddArcToPoint(c, x_left, y_bottom, x_left, y_bottom_center, corner_radius); 460 | CGContextAddLineToPoint(c, x_left, y_top_center); 461 | 462 | /* Done */ 463 | CGContextClosePath(c); 464 | 465 | CGContextSetFillColorWithColor(c, color.CGColor); 466 | 467 | CGContextFillPath(c); 468 | } 469 | // size of a string given a specific font 470 | -(CGSize) sizeOfString:(NSString *)string withFont:(UIFont *)font { 471 | NSDictionary *attributes = @{ NSFontAttributeName: font}; 472 | return [string sizeWithAttributes:attributes]; 473 | } 474 | 475 | #pragma mark - String utilities 476 | 477 | // format a string as a date (italian convention) 478 | -(NSString*) dateFromString:(NSString*) string { 479 | 480 | NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; 481 | [dateFormatter setDateFormat:fzDateFormat]; 482 | NSDate *dateFromString = [dateFormatter dateFromString:string]; 483 | 484 | 485 | NSDateFormatter *formatter = [[NSDateFormatter alloc] init]; 486 | [formatter setDateStyle:NSDateFormatterShortStyle]; 487 | [formatter setTimeStyle:NSDateFormatterNoStyle]; 488 | [formatter setLocale:[NSLocale currentLocale]]; 489 | NSString *format = [formatter dateFormat]; 490 | format = [format stringByReplacingOccurrencesOfString:@"/y" withString:@""]; 491 | format = [format stringByReplacingOccurrencesOfString:@"y/" withString:@""]; 492 | format = [format stringByReplacingOccurrencesOfString:@"y" withString:@""]; 493 | 494 | [formatter setDateFormat:format]; 495 | 496 | NSString *printDate = [formatter stringFromDate:dateFromString]; 497 | 498 | return printDate; 499 | } 500 | 501 | 502 | #pragma mark - Handle Touch Events 503 | 504 | -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event 505 | { 506 | [[NSNotificationCenter defaultCenter] postNotificationName:@"disableScrolling" object:nil]; 507 | 508 | UITouch *touch = [touches anyObject]; 509 | currentLoc = [touch locationInView:self]; 510 | currentLoc.x -= self.leftMargin; 511 | isMovement = YES; 512 | 513 | [self setNeedsDisplay]; 514 | } 515 | 516 | -(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event 517 | { 518 | UITouch *touch = [touches anyObject]; 519 | currentLoc = [touch locationInView:self]; 520 | currentLoc.x -= self.leftMargin; 521 | [self setNeedsDisplay]; 522 | } 523 | 524 | -(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event 525 | { 526 | [[NSNotificationCenter defaultCenter] postNotificationName:@"enableScrolling" object:nil]; 527 | 528 | UITouch *touch = [touches anyObject]; 529 | currentLoc = [touch locationInView:self]; 530 | currentLoc.x -= self.leftMargin; 531 | 532 | isMovement = NO; 533 | [self setNeedsDisplay]; 534 | } 535 | 536 | 537 | -(NSString*)formatNumberAsCurrency:(float)number withFractionDigits: (int)digits { 538 | 539 | NSNumberFormatter *currencyFormatter = [[NSNumberFormatter alloc] init]; 540 | [currencyFormatter setCurrencyCode:@"EUR"]; 541 | [currencyFormatter setLocale: [[NSLocale alloc] initWithLocaleIdentifier:@"EUR"]]; 542 | [currencyFormatter setMaximumFractionDigits:digits]; 543 | [currencyFormatter setMinimumFractionDigits:digits]; 544 | //[currencyFormatter setAlwaysShowsDecimalSeparator:YES]; 545 | [currencyFormatter setNumberStyle:NSNumberFormatterCurrencyStyle]; 546 | NSString *numberAsString = [currencyFormatter stringFromNumber:[NSNumber numberWithFloat:number]]; 547 | 548 | return numberAsString; 549 | } 550 | 551 | 552 | @end --------------------------------------------------------------------------------