├── .github ├── CONTRIBUTING.md ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md └── PULL_REQUEST_TEMPLATE.md ├── .gitignore ├── .travis.yml ├── BEMSimpleLineGraph.podspec.json ├── CHANGELOG.md ├── Classes ├── BEMAverageLine.h ├── BEMAverageLine.m ├── BEMCircle.h ├── BEMCircle.m ├── BEMLine.h ├── BEMLine.m ├── BEMPermanentPopupView.h ├── BEMPermanentPopupView.m ├── BEMSimpleLineGraphView.h └── BEMSimpleLineGraphView.m ├── LICENSE ├── README.md └── Sample Project ├── SimpleLineChart.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ ├── xcshareddata │ │ ├── SimpleLineChart.xccheckout │ │ └── SimpleLineChart.xcscmblueprint │ └── xcuserdata │ │ ├── Spencers.xcuserdatad │ │ └── UserInterfaceState.xcuserstate │ │ └── bobo.xcuserdatad │ │ ├── UserInterfaceState.xcuserstate │ │ └── WorkspaceSettings.xcsettings ├── xcshareddata │ ├── xcbaselines │ │ └── C3FD8175186DFD9A00FD8ED3.xcbaseline │ │ │ ├── 2C820550-74B3-4FE2-BBBC-50D038B845C0.plist │ │ │ └── Info.plist │ └── xcschemes │ │ ├── SimpleLineChart.xcscheme │ │ └── SimpleLineChartTests.xcscheme └── xcuserdata │ ├── Spencers.xcuserdatad │ ├── xcdebugger │ │ └── Breakpoints_v2.xcbkptlist │ └── xcschemes │ │ └── xcschememanagement.plist │ └── bobo.xcuserdatad │ ├── xcdebugger │ └── Breakpoints_v2.xcbkptlist │ └── xcschemes │ └── xcschememanagement.plist ├── SimpleLineChart ├── AppDelegate.h ├── AppDelegate.m ├── Base.lproj │ ├── Launch Screen.storyboard │ └── Main.storyboard ├── Images.xcassets │ ├── AppIcon.appiconset │ │ ├── AppIcon29x29@2x.png │ │ ├── AppIcon40x40@2x.png │ │ ├── AppIcon60x60@2x.png │ │ └── Contents.json │ └── LaunchImage.launchimage │ │ └── Contents.json ├── SimpleLineChart-Info.plist ├── SimpleLineChart-Prefix.pch ├── StatsViewController.h ├── StatsViewController.m ├── ViewController.h ├── ViewController.m ├── en.lproj │ └── InfoPlist.strings └── main.m └── SimpleLineChartTests ├── CustomizationTests.m ├── SimpleLineChartTests-Info.plist ├── SimpleLineChartTests.m ├── contantsTests.h └── en.lproj └── InfoPlist.strings /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## Contributing 2 | This document lays out exactly how you can contribute to BEMSimpleLineGraph. All contributions are welcome and appreciated. Thanks for contributing! 3 | 4 | ### Questions 5 | The best way to ask questions is through [StackOverflow](http://www.stackoverflow.com) using the [BEMSimpleLineGraph tag](http://stackoverflow.com/questions/tagged/bemsimplelinegraph). StackOverflow questions are highly discoverable, viewed by an active and massive community of programmers, and incredibly reapplicable. If another developer using BEMSimpleLineGraph runs into the same question, it is to their advantage to find it on StackOverflow rather than via GitHub issues. 6 | 7 | We would like to keep GitHub issues strictly for bugs, feature requests, enhancements, etc. You can [ask your question right here](http://stackoverflow.com/questions/ask). Make sure to add the correct tags. 8 | 9 | ### Issues (Bugs, Enhancements, Features) 10 | The best way to report **issues** (e.g. bugs, glitches, problems, etc.) and **feature requests** (e.g. improvements, new features, API changes, etc.) with BEMSimpleLineGraph is by submitting an issue. 11 | 12 | Submitting an issue on GitHub help us easily organize, track, manage, and respond to those issues. 13 | 14 | 1. Open the BEMSimpleLineGraph project page on GitHub. 15 | 2. Look through the [issues](https://github.com/Boris-Em/BEMSimpleLineGraph/issues) (opened or closed) for BEMSimpleLineGraph to see if your issue has already been fixed, answered, or is being fixed. 16 | 3. Try filtering issues by "milestones" (i.e. updates / releases) using the milestone selector on the left side of the page. 17 | 4. Create a [new issue](https://github.com/Boris-Em/BEMSimpleLineGraph/issues/new) using the button on the right side of the screen. Here are a few basic guidelines for writing an issue that make things easier on everyone: 18 | 1. One issue per issue. If you have more than one issue, bug to report, feature to request, or question to ask - open a separate issue for each. Don't make a list of issues inside of a single issue. It makes it easier to track and manage things when they're separated out. 19 | 2. Spell correctly; use proper punctuation and grammar. This may seem obvious, however, whn u spell not rite hard 2 reed. This helps minimize questions like: "Could you please clarify that?". 20 | 3. Use code blocks (hint: don't take a screenshot of your code). Not sure how to write markdown syntax for code? Take a look at [this wonderful guide](https://help.github.com/articles/markdown-basics#code-formatting) from the great people at GitHub. 21 | 22 | ### Changes (Bug Fixes, Improvements, New Features) 23 | The best way to contribute changes (e.g. a great idea, a new feature, bug fixes, etc.) to the project is through forks and pull requests. 24 | 25 | 1. Fork this repository and clone that fork onto your computer. 26 | 2. Make changes to the forked repo, fix any errors, debug. 27 | 3. Commit and then push all the changes up to your forked GitHub repo. 28 | 4. Choose a branch on the main repository to merge your changes into. If you're unsure, check below for which branch to merge with. 29 | - **Master Branch**: Your changes are non-breaking project updates, README changes, documentation updates, bug fixes, and minor improvements. Generally, any non-breaking major changes should be submitted to this branch. 30 | - **Feature Branch**: Your forked changes are either major project updates / changes, or breaking changes. Because of semantic versioning and API vavailability, any changes to public API availability or behavior should be submitted to this branch. 31 | 5. Submit a pull request from your forked GitHub repo into the main repo. Make sure to detail what changes you made in the pull request. 32 | 33 | #### Code Guidelines 34 | Before submitting any code changes, read over the code / syntax guidelines to make sure everything you write matches the appropriate coding style. The [Objective-C Coding Guidelines](https://github.com/github/objective-c-conventions) are available on GitHub. 35 | 36 | #### Versioning Guidelines 37 | It is crucial that all contributions to this project adhere to [semantic versioning](http://semver.org). Ther version format should always follow the X.Y.Z format. Breaking changes to the public API increment the X value. Internal changes, API deprecation, bug fixes, etc. warrant an increment to the Y value. Bug fixes, patches, documentation updates, etc. are cause for an increment to the Z value. 38 | 39 | Removing old APIs should use the following process: 40 | 1. Deprecate the API, update documentation, and provide internal support and warnings for the deprecated API (so as to alert developers and to smoothly transition to new APIs without cause errors or bugs). 41 | 2. Release a new minor version including the deprecated API 42 | 3. When the next major version is released, remove the API entirely. Reflect the changes in the documentation. 43 | 44 | #### Documentation Guidelines 45 | Document the changes you make. Only fundamental documentation is written in the `Readme.md` (e.g. setup, installation, data source, and delegation). Full documentation is written on the [wiki](https://github.com/Boris-Em/BEMSimpleLineGraph/wiki). There's a lot of work left to do on the [wiki](https://github.com/Boris-Em/BEMSimpleLineGraph/wiki), and any help **writing documentation for the wiki is greatly appreciated**. 46 | 47 | API documentation is available in both the wiki and in Xcode (by option-clicking, using the Quick Help menu, or by going through the header files. See below for how to write documentation comments in the code. 48 | 49 | Write appropriate documentation in the code (using comments). Always write the documentation comments in the header, above the related method, property, etc. Write regular comments with your code in the implementation too. Here's an example of a documentation comment: 50 | 51 | /// One line documentation comments can use the triple forward slash 52 | @property (strong) NSObject *object; 53 | 54 | /** Multi-line documentation comments can use the forward slash with a double asterisk at the beginning and a single asterisk at the end. 55 | @description Use different keys inside of a multi-line documentation comment to specify various aspects of a method. There are many available keys that Xcode recognizes: @description, @param, @return, @deprecated, @warning, etc. The documentation system also recognizes standard markdown formatting within comments. When building the documentation, this information will be appropriately formatted in Xcode and the Document Browser. 56 | 57 | @see Use this key to add a see-also section. 58 | 59 | @todo Still have more to add later, something left to do in the implementation? Use this key. 60 | 61 | @param parameterName Parameter Description. The @param key should be used for each parameter in a method. Make sure to describe exactly what the parameter does and if it can be nil or not. 62 | @return Return value. Use the @return key to specify a return value of a method. */ 63 | - (BOOL)alwaysWriteDocumentCommentsAboveMethods:(NSObject *)paramName; 64 | 65 | ## What to Contribute 66 | Contribute anything, we're open to ideas! Although if you're looking for a little more structure, you can go through the [open issues on GitHub](https://github.com/Boris-Em/BEMSimpleLineGraph/issues?state=open) or look at the known issues in the [Releases documentation](https://github.com/Boris-Em/BEMSimpleLineGraph/releases). Additionally, a lot of documentation needs to be written on the [wiki](https://github.com/Boris-Em/BEMSimpleLineGraph/wiki) (and contributions there are greatly appreciated). 67 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Additional context** 27 | Add any other context about the problem here. 28 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: new feature 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ### Summary 2 | *Replace this line with a short description of the content in your pull request.* 3 | 4 | ### Fixes Issues 5 | This pull request fixes the following issues: 6 | - # 7 | 8 | ### Changes 9 | The following changes are included in this pull request: 10 | - *Replace this with a description of a change* 11 | 12 | ### Notes 13 | - [ ] This pull request makes breaking changes, and if so, involves the following: 14 | - [ ] Public API availability 15 | - [ ] Internal functionality or behavior 16 | - [ ] I have run and ensured that this pull request passes all XCTests 17 | 18 | *Include any additional notes on your pull request* 19 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .DS_Store? 3 | ._* 4 | .Spotlight-V100 5 | .Trashes 6 | Icon? 7 | ehthumbs.db 8 | Thumbs.db 9 | xcuserdata/ 10 | *.xcuserstate 11 | 12 | *.xcuserstate 13 | 14 | *.xcuserstate 15 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: objective-c 2 | osx_image: xcode7 3 | # xcode_project: Sample Project/SimpleLineChart.xcodeproj 4 | # xcode_scheme: SimpleLineChartTests 5 | # xcode_sdk: iphonesimulator 6 | script: 7 | - xcodebuild clean build test -project "Sample Project/SimpleLineChart.xcodeproj" -scheme SimpleLineChartTests -sdk iphonesimulator ONLY_ACTIVE_ARCH=NO 8 | -------------------------------------------------------------------------------- /BEMSimpleLineGraph.podspec.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "BEMSimpleLineGraph", 3 | "version": "4.1.1", 4 | "summary": "Elegant Line Graphs for iOS (charting library)", 5 | "description": "BEMSimpleLineGraph lets you create highly customizable line graphs / charts for iOS.", 6 | "homepage": "https://github.com/Boris-Em/BEMSimpleLineGraph", 7 | "screenshots": [ 8 | "http://s27.postimg.org/txboc1peb/BEMSimple_Line_Graph_Main.png", 9 | "http://s21.postimg.org/3lkbvgp53/GIF_Touch_Report.gif" 10 | ], 11 | "license": { 12 | "type": "MIT", 13 | "file": "LICENSE" 14 | }, 15 | "authors": { 16 | "Boris Emorine": "boris.emorine@gmail.com" 17 | }, 18 | "platforms": { 19 | "ios": "6.1" 20 | }, 21 | "requires_arc": true, 22 | "source": { 23 | "git": "https://github.com/Boris-Em/BEMSimpleLineGraph.git", 24 | "tag": "v4.1.1" 25 | }, 26 | "source_files": [ 27 | "Classes", 28 | "Classes/**/*.{h,m}" 29 | ] 30 | } 31 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | ## [v4.1](https://github.com/Boris-Em/BEMSimpleLineGraph/releases/tag/v4.1) 4 | 5 | [Full Changelog](https://github.com/Boris-Em/BEMSimpleLineGraph/compare/v4.0...v4.1) 6 | 7 | **Improvements** 8 | * Bezier Algorithm Improvements. This modifies the algorithm used to determine the graph's line. The old 9 | algorithm, although generating prettier graphs, displayed inaccurate information; line arcs would go above and below min/max values, and a graph that had two data points of the same value in a row would show invalid arcs between the two data points (always upward) giving the user an inaccurate representation of the data. Thanks to @tres for this wonderful improvement (9311f8d). 10 | * Allow gesture recognizer to function simultaneously with other gesture recognizers. (8c25436). 11 | 12 | **New Features** 13 | * New reference line width property (`referenceLineWidth`) allows you to control the width of the reference lines independently from the graph line. (0bb60c9) 14 | 15 | **Bug Fixes** 16 | * Fixes #135, an issue where bezier curve lines were not confined to the graph's boundaries (despite the fill gradients and colors being confined). (17fe25f) 17 | * Fixes an issue where permanent pop up labels are duplicated when `layoutSubview` is called (i.e. during interface orientation changes). (929df84) 18 | * Fixes a crash that may have occurred when attempting to perform calculations on a graph with no data, or before data is loaded. (e2a5167) 19 | * Fixes a static analyzer warning about uninitialized struct. (af70a96) 20 | 21 | **GitHub Repo Updates** 22 | * Readme Updates 23 | * Fixes quotation mark for Swift bridging header example (978b504) 24 | 25 | **Public to Private API Transition** 26 | * Removed previously public properties on `BEMLine` and made them private. These properties are not marked as deprecated because they should not have been public in the first-place, and any public use of them would have unintentional consequences. The following properties are no longer available publicly: 27 | * `@property (assign, nonatomic) CGPoint P0` 28 | * `@property (assign, nonatomic) CGPoint P1` 29 | * `@property (assign, nonatomic) CGPoint P2` 30 | * `@property (assign, nonatomic) CGPoint P3` 31 | 32 | ## [v4.0](https://github.com/Boris-Em/BEMSimpleLineGraph/releases/tag/v4.0) 33 | 34 | [Full Changelog](https://github.com/Boris-Em/BEMSimpleLineGraph/compare/v3.3...v4.0) 35 | 36 | **Breaking Changes** 37 | * Changed the purpose of `lineGraphDidFinishLoading:`. 38 | * Added a new `lineGraphDidFinishDrawing:` delegate method to differentiate between when the graph finishes drawing & animating and when it finishes loading its data. 39 | * Those who previously used `lineGraphDidFinishLoading:` to take graph snapshots should now use `lineGraphDidFinishDrawing:` instead. 40 | * The new `lineGraphDidFinishDrawing:` can be used to create snapshots for the  WATCH 41 | * Deprecated the `distanceToClosestPoint` method. This method will become unavailable in a future update. There will be no replacement for this method and we suggest phasing it out. 42 | * Removed compile-time module check (`@import` vs. `#import`). Modules are now be used by default. (a43ba9380f5b2a8dc8fcb268b3eb611e1dcfb471) 43 | * Added warnings to deprecated methods which will be removed in the next major release: 44 | * `numberOfPointsInGraph` 45 | * `didTouchGraphWithClosestIndex:` 46 | * `didReleaseGraphWithClosestIndex:` 47 | * `numberOfGapsBetweenLabels` 48 | 49 | **Semi-Breaking Changes** 50 | * Improved the implementation of the X-Axis. The X-Axis background is now drawn by BEMSimpleLineGraph (as the Y-Axis is) instead of by BEMLine. This will help ensure stability and provide a more reliable system moving forward. It also fixes issues with gradient overlap into the X-Axis area. 51 | 52 | **Xcode 6 Improvements** 53 | * BEMSimpleLineGraph now takes advantage of Xcode 6's new IBDesignable and IBInspectable features. Preview select graph properties in Interface Builder. 54 | * Starting in Xcode 6.3 and Swift 1.2, BEMSimpleLineGraph is compatible with the new NULLABILITY standards. All methods and properties are, by default, non-nullable unless otherwise marked. (a43ba9380f5b2a8dc8fcb268b3eb611e1dcfb471) 55 | 56 | **Key Feature** 57 | * Average Lines (a939039a1e9a7d728cb71356b1e01902282b9132). Added an Average Line feature. Draw an average line with a specific y-value. Use the new `averageLine` property on BEMSimpleLineGraphView to setup and customize the line. Might be considered a fix for issue #42. The implementation of the average line feature is likely the direction BEMSimpleLineGraph is headed as it expands. 58 | 59 | **New Features** - Shoutout to @RobDay and his team at @dowjones for PR #132 60 | * New Properties 61 | * Optionally display only dots and no line on your graph (resolves #51) using the new `displayDotsOnly` property. 62 | * Added new `positionYAxisRight`property. A boolean flag that moves the Y-Axis to the right of the graph. 63 | * Added a new `lineDashPatternForReference[X|Y]AxisLines` property. Specify a dash pattern for the reference lines drawn on the graph. This creates the reference lines with a dotted or hashed pattern. 64 | * Added a new `enable[Left|Right|Top|Bottom]ReferenceAxisFrameLine` property. By setting these properties, you can control what reference frame lines are drawn on the graph. 65 | * New `displayDotsWhileAnimating` property. A boolean specifying whether or not to show the dots while animating the reference lines. 66 | * New `noDataLabelColor`. Specify the color for the no data label 67 | * New `noDataLabelFont`. Specify the font for the no data label 68 | * Created a new `formatStringForValues` property. A format string to apply to values in the Y-Axis. This lets you have fine-grain control over the decimal precision of these values (eg. ".02f") 69 | * New `yAxis[Prefix|Suffix]OnLineGraph` property. Specify popup prefix and suffix to show in the built-in popup view 70 | * Null Graph Values 71 | * The graph now has the ability to plot null graph values. `BEMSimpleLineGraph.h` now specifies a special value, `BEMNullGraphValue`, that corresponds to a null data point. In your response to `valueForPointAtIndex`, return this special value whenever your data point is null. BEMSimpleLineGraph will now skip over this value when drawing the line. If you set `interpolateNullValues`, the graph will connect non-null values while preserving spacing for the null value. 72 | * Customizing Popup Views 73 | * Added a `popUpSuffixForlineGraph:` delegate method. A suffix to append to the stock pop up label view's value. 74 | * Added a `popUpPrefixForlineGraph:` delegate method. A prefix to prepend to the stock pop up label view's value. 75 | * If you want to use a custom popup view instead of the built-in popup view, you can respond to the optional method `popUpViewForLineGraph:`. You respond to this method with a UIView that will be used in place of the default popup. 76 | * When you use the custom popup view, the data in the view needs to be changed whenever the user drags his or her finger. To handle this modification, BEMSimpleLineGraph will send the message `lineGraph:modifyPopupView:ForIndex:`. This lets you modify your view for a given datapoint. 77 | * Axis Customizations 78 | * Added a new delegate method, `incrementPositionsForXAxisOnLineGraph` that lets you set the specific indices where X-Axis labels should be drawn. 79 | * Added a new delegate method, `baseIndexForXAxisOnLineGraph`, that lets you specify the index of the first X-Axis label to draw. 80 | * `incrementIndexForXAxisOnLineGraph`. An increment to apply to the response. 81 | * `baseIndexForXAxisOnLineGraph`. X-Axis labels will be drawn on this increment across the X-Axis. 82 | * `baseValueForYAxisOnLineGraph`. The starting Y-Axis value to plot draw on the Y-Axis. This lets you set a specifically formatted value so that your access label can be more user friendly (21.50 instead of 21.47) 83 | * `incrementValueForYAxisOnLineGraph`- An increment value to add to the response of `baseValueForYAxisOnLineGraph` that specifies what Y-Axis values to draw. This lets you return a user friendly increment, eg. .25. 84 | * Snapshot Methods 85 | * Use the new graphSnapshotImageRenderedWhileInBackground: method to capture a graph snapshot while your app is in the background. Fixes #193. (512f716a36c94663080abb80224404e17940d133) 86 | * Animation & Drawing 87 | * New “expansion” animation has been added to the list of available animations. Try out the new animation with the `BEMLineAnimationExpand` type. 88 | 89 | **Bug Fixes** 90 | * Fixes #134, an issue where popup suffixes would not display when `alwaysDisplayPopUpLabels` was set to YES. The sample app now demonstrates the use of popup suffixes. (183a67504b3851e4f79f49b86a54e3e69935ac9f) 91 | * Fixes #138, an issue where popup prefixes would not display when `alwaysDisplayPopUpLabels` was set to YES. The sample app now demonstrates the use of popup prefixes. (c83d66c32e9b0ee31b95e996a919f896afdd7e38) 92 | * Fixes #70, a bug where reference axis frame drawing was conditional on reference axis lines being enabled. Now these properties are not dependent on one another. (f1f2ac453bcecd6f84fd5bcba5346068285e6467) 93 | * Fixes #196, vertical reference lines are now properly aligned with x-axis labels. (64b4fb1756eeb42c564b946a34b66edac21bf020) 94 | * Fixes #67, the far-right and far-left x-axis labels now re-orient themselves to avoid being clipped.(64b4fb1756eeb42c564b946a34b66edac21bf020) 95 | * Fixed an issue where the reference lines would have an alpha value of 0 if the line also had an alpha value of zero. Reference lines now set to an alpha of 0.1 when the line alpha is 0.0. As before, you can disable 96 | reference lines using the boolean properties to make them appear or disappear. (1acc2e206a0bbb4020ee3e8004ab900c71295a8a) 97 | 98 | **GitHub Repo Updates** 99 | * Graph Properties View Controller 100 | * View all available public BEMSimpleLineGraph properties directly from the sample project 101 | * Ability to use and toggle these properties directly from the Storyboard is coming soon 102 | * Readme Updates 103 | * New *Apps Using This Project* Section 104 | * Added details on IBDesignables 105 | * Added contributions note 106 | * Improved markdown formatting 107 | * Added *StackOverflow* support details 108 | * Updated project requirements 109 | 110 | ## [v3.3](https://github.com/Boris-Em/BEMSimpleLineGraph/tree/v3.3) (2015-01-31) 111 | 112 | [Full Changelog](https://github.com/Boris-Em/BEMSimpleLineGraph/compare/v3.2...v3.3) 113 | 114 | **Implemented enhancements:** 115 | 116 | - huge performance improvement suggestion [\#107](https://github.com/Boris-Em/BEMSimpleLineGraph/issues/107) 117 | 118 | **Fixed bugs:** 119 | 120 | - popupReport will not show up if animation has been set off [\#106](https://github.com/Boris-Em/BEMSimpleLineGraph/issues/106) 121 | 122 | - autoScaleYAxis Not working with Bezier curves [\#99](https://github.com/Boris-Em/BEMSimpleLineGraph/issues/99) 123 | 124 | - Popup Labels Displaying as Double with iOS8 [\#74](https://github.com/Boris-Em/BEMSimpleLineGraph/issues/74) 125 | 126 | - BezierCurve do not always work [\#73](https://github.com/Boris-Em/BEMSimpleLineGraph/issues/73) 127 | 128 | **Closed issues:** 129 | 130 | - Gradient fill [\#57](https://github.com/Boris-Em/BEMSimpleLineGraph/issues/57) 131 | 132 | **Merged pull requests:** 133 | 134 | - Ensure permanent pop-up labels are not duplicated [\#122](https://github.com/Boris-Em/BEMSimpleLineGraph/pull/122) ([kattrali](https://github.com/kattrali)) 135 | 136 | - fix bug about colorTouchInputLine [\#118](https://github.com/Boris-Em/BEMSimpleLineGraph/pull/118) ([Vernsu](https://github.com/Vernsu)) 137 | 138 | - Update README.md [\#115](https://github.com/Boris-Em/BEMSimpleLineGraph/pull/115) ([jeffreyjackson](https://github.com/jeffreyjackson)) 139 | 140 | - Bug/107 [\#111](https://github.com/Boris-Em/BEMSimpleLineGraph/pull/111) ([Boris-Em](https://github.com/Boris-Em)) 141 | 142 | - Fixed touch report when no animation [\#110](https://github.com/Boris-Em/BEMSimpleLineGraph/pull/110) ([Boris-Em](https://github.com/Boris-Em)) 143 | 144 | - Multiple lines support \(Re-pull-request\) [\#103](https://github.com/Boris-Em/BEMSimpleLineGraph/pull/103) ([adonishi](https://github.com/adonishi)) 145 | 146 | - Multiple lines support [\#102](https://github.com/Boris-Em/BEMSimpleLineGraph/pull/102) ([adonishi](https://github.com/adonishi)) 147 | 148 | - Allow drawing a horizontal or vertical gradient as the graph line [\#101](https://github.com/Boris-Em/BEMSimpleLineGraph/pull/101) ([kattrali](https://github.com/kattrali)) 149 | 150 | - Add a Gitter chat badge to README.md [\#100](https://github.com/Boris-Em/BEMSimpleLineGraph/pull/100) ([gitter-badger](https://github.com/gitter-badger)) 151 | 152 | - Add ability to fill the top and/or bottom of a graph with a gradient [\#98](https://github.com/Boris-Em/BEMSimpleLineGraph/pull/98) ([kattrali](https://github.com/kattrali)) 153 | 154 | - Pr/90 [\#97](https://github.com/Boris-Em/BEMSimpleLineGraph/pull/97) ([Boris-Em](https://github.com/Boris-Em)) 155 | 156 | - Add automatically generated changelog file [\#94](https://github.com/Boris-Em/BEMSimpleLineGraph/pull/94) ([skywinder](https://github.com/skywinder)) 157 | 158 | - able to customize text on no data label [\#93](https://github.com/Boris-Em/BEMSimpleLineGraph/pull/93) ([sbhhbs](https://github.com/sbhhbs)) 159 | 160 | - Code improvements [\#90](https://github.com/Boris-Em/BEMSimpleLineGraph/pull/90) ([skywinder](https://github.com/skywinder)) 161 | 162 | - Fix path in bridging header section in Readme [\#89](https://github.com/Boris-Em/BEMSimpleLineGraph/pull/89) ([DavidQL](https://github.com/DavidQL)) 163 | 164 | - Reference line color & draw order [\#88](https://github.com/Boris-Em/BEMSimpleLineGraph/pull/88) ([gavinbunney](https://github.com/gavinbunney)) 165 | 166 | ## [v3.2](https://github.com/Boris-Em/BEMSimpleLineGraph/tree/v3.2) (2014-11-02) 167 | 168 | [Full Changelog](https://github.com/Boris-Em/BEMSimpleLineGraph/compare/v3.1...v3.2) 169 | 170 | **Implemented enhancements:** 171 | 172 | - Dots still animating when animationGraphStyle set to BEMLineAnimationNone [\#80](https://github.com/Boris-Em/BEMSimpleLineGraph/issues/80) 173 | 174 | - enableReferenceAxisLines should be two: enableReferenceY-AxisLines and enableReferenceX-AxisLines [\#69](https://github.com/Boris-Em/BEMSimpleLineGraph/issues/69) 175 | 176 | - Y-axis label issues [\#62](https://github.com/Boris-Em/BEMSimpleLineGraph/issues/62) 177 | 178 | - Touch interaction on touch-down, not just start-pan? [\#59](https://github.com/Boris-Em/BEMSimpleLineGraph/issues/59) 179 | 180 | **Fixed bugs:** 181 | 182 | - Dots still animating when animationGraphStyle set to BEMLineAnimationNone [\#80](https://github.com/Boris-Em/BEMSimpleLineGraph/issues/80) 183 | 184 | - BackgroundPopUplabel never show if enableYAxisLabel is set NO [\#71](https://github.com/Boris-Em/BEMSimpleLineGraph/issues/71) 185 | 186 | **Merged pull requests:** 187 | 188 | - Split enableReferenceAxisLines into two properties [\#87](https://github.com/Boris-Em/BEMSimpleLineGraph/pull/87) ([gavinbunney](https://github.com/gavinbunney)) 189 | 190 | - fix issue \#80 [\#86](https://github.com/Boris-Em/BEMSimpleLineGraph/pull/86) ([skywinder](https://github.com/skywinder)) 191 | 192 | - Fix wrong presentation of years in code exmple + auto-update graph by clicking on segment controll [\#85](https://github.com/Boris-Em/BEMSimpleLineGraph/pull/85) ([skywinder](https://github.com/skywinder)) 193 | 194 | - update travis script to avoid "exited with 134" [\#84](https://github.com/Boris-Em/BEMSimpleLineGraph/pull/84) ([skywinder](https://github.com/skywinder)) 195 | 196 | - Fix representation of negative values in Y axis [\#83](https://github.com/Boris-Em/BEMSimpleLineGraph/pull/83) ([skywinder](https://github.com/skywinder)) 197 | 198 | - Fix several UI bug when displaying data with negative numbers [\#79](https://github.com/Boris-Em/BEMSimpleLineGraph/pull/79) ([ben181231](https://github.com/ben181231)) 199 | 200 | - Fixed issue \#73 and labels Y axis height [\#78](https://github.com/Boris-Em/BEMSimpleLineGraph/pull/78) ([Boris-Em](https://github.com/Boris-Em)) 201 | 202 | - Add segment to select Bezier or straght line [\#76](https://github.com/Boris-Em/BEMSimpleLineGraph/pull/76) ([skywinder](https://github.com/skywinder)) 203 | 204 | ## [v3.1](https://github.com/Boris-Em/BEMSimpleLineGraph/tree/v3.1) (2014-08-28) 205 | 206 | [Full Changelog](https://github.com/Boris-Em/BEMSimpleLineGraph/compare/v3.0...v3.1) 207 | 208 | **Fixed bugs:** 209 | 210 | - alwaysDisplayDots=YES is not having effect when animationGraphEntranceTime=0.0 [\#61](https://github.com/Boris-Em/BEMSimpleLineGraph/issues/61) 211 | 212 | ## [v3.0](https://github.com/Boris-Em/BEMSimpleLineGraph/tree/v3.0) (2014-08-19) 213 | 214 | [Full Changelog](https://github.com/Boris-Em/BEMSimpleLineGraph/compare/v2.3...v3.0) 215 | 216 | **Fixed bugs:** 217 | 218 | - Crash with one point or less on Feature branch [\#56](https://github.com/Boris-Em/BEMSimpleLineGraph/issues/56) 219 | 220 | - X-Axis label displays under the graph view [\#47](https://github.com/Boris-Em/BEMSimpleLineGraph/issues/47) 221 | 222 | **Merged pull requests:** 223 | 224 | - Podname should be quoted [\#55](https://github.com/Boris-Em/BEMSimpleLineGraph/pull/55) ([zrcoder](https://github.com/zrcoder)) 225 | 226 | - Add Y-Axis Reference Line \(\#40\) [\#43](https://github.com/Boris-Em/BEMSimpleLineGraph/pull/43) ([japanconman](https://github.com/japanconman)) 227 | 228 | - Added Obj-C Tags and Added access to Labels [\#39](https://github.com/Boris-Em/BEMSimpleLineGraph/pull/39) ([joeblau](https://github.com/joeblau)) 229 | 230 | - Add Y-Axis feature [\#33](https://github.com/Boris-Em/BEMSimpleLineGraph/pull/33) ([japanconman](https://github.com/japanconman)) 231 | 232 | ## [v2.3](https://github.com/Boris-Em/BEMSimpleLineGraph/tree/v2.3) (2014-06-02) 233 | 234 | [Full Changelog](https://github.com/Boris-Em/BEMSimpleLineGraph/compare/v2.2...v2.3) 235 | 236 | **Fixed bugs:** 237 | 238 | - index beyond bounds when touch graph [\#31](https://github.com/Boris-Em/BEMSimpleLineGraph/issues/31) 239 | 240 | - On Device [\#29](https://github.com/Boris-Em/BEMSimpleLineGraph/issues/29) 241 | 242 | **Merged pull requests:** 243 | 244 | - Feature branch catch up on Master branch [\#32](https://github.com/Boris-Em/BEMSimpleLineGraph/pull/32) ([Boris-Em](https://github.com/Boris-Em)) 245 | 246 | ## [v2.2](https://github.com/Boris-Em/BEMSimpleLineGraph/tree/v2.2) (2014-05-19) 247 | 248 | [Full Changelog](https://github.com/Boris-Em/BEMSimpleLineGraph/compare/v2.1...v2.2) 249 | 250 | **Fixed bugs:** 251 | 252 | - Graph Displaying Opposite Direction [\#20](https://github.com/Boris-Em/BEMSimpleLineGraph/issues/20) 253 | 254 | - Outside the Graph [\#18](https://github.com/Boris-Em/BEMSimpleLineGraph/issues/18) 255 | 256 | **Merged pull requests:** 257 | 258 | - Feature branch catch up on Master branch [\#25](https://github.com/Boris-Em/BEMSimpleLineGraph/pull/25) ([Boris-Em](https://github.com/Boris-Em)) 259 | 260 | - Added support for scrolling with a GraphView placed in UIScrollView [\#12](https://github.com/Boris-Em/BEMSimpleLineGraph/pull/12) ([nmattisson](https://github.com/nmattisson)) 261 | 262 | ## [v2.1](https://github.com/Boris-Em/BEMSimpleLineGraph/tree/v2.1) (2014-04-20) 263 | 264 | [Full Changelog](https://github.com/Boris-Em/BEMSimpleLineGraph/compare/v2.0.1...v2.1) 265 | 266 | **Fixed bugs:** 267 | 268 | - Demo projects not working. [\#14](https://github.com/Boris-Em/BEMSimpleLineGraph/issues/14) 269 | 270 | ## [v2.0.1](https://github.com/Boris-Em/BEMSimpleLineGraph/tree/v2.0.1) (2014-03-03) 271 | 272 | [Full Changelog](https://github.com/Boris-Em/BEMSimpleLineGraph/compare/v2.0...v2.0.1) 273 | 274 | ## [v2.0](https://github.com/Boris-Em/BEMSimpleLineGraph/tree/v2.0) (2014-03-02) 275 | 276 | [Full Changelog](https://github.com/Boris-Em/BEMSimpleLineGraph/compare/v1.3...v2.0) 277 | 278 | **Implemented enhancements:** 279 | 280 | - Several Graphs in the same View Controller [\#11](https://github.com/Boris-Em/BEMSimpleLineGraph/issues/11) 281 | 282 | **Fixed bugs:** 283 | 284 | - Bug: The chart can not draw a single dot and it crashes. [\#6](https://github.com/Boris-Em/BEMSimpleLineGraph/issues/6) 285 | 286 | - CALayerInvalidGeometry exception for duplicate & zeroed data points [\#3](https://github.com/Boris-Em/BEMSimpleLineGraph/issues/3) 287 | 288 | **Merged pull requests:** 289 | 290 | - 2.0 Update [\#13](https://github.com/Boris-Em/BEMSimpleLineGraph/pull/13) ([Sam-Spencer](https://github.com/Sam-Spencer)) 291 | 292 | - Fixed issue \#3 and \#6 [\#9](https://github.com/Boris-Em/BEMSimpleLineGraph/pull/9) ([Boris-Em](https://github.com/Boris-Em)) 293 | 294 | - Fixes crash, cleaned up for 64 bit [\#4](https://github.com/Boris-Em/BEMSimpleLineGraph/pull/4) ([darkFunction](https://github.com/darkFunction)) 295 | 296 | ## [v1.3](https://github.com/Boris-Em/BEMSimpleLineGraph/tree/v1.3) (2014-02-08) 297 | 298 | [Full Changelog](https://github.com/Boris-Em/BEMSimpleLineGraph/compare/v1.2.2...v1.3) 299 | 300 | **Merged pull requests:** 301 | 302 | - Feature 1.3, 1.x Update [\#2](https://github.com/Boris-Em/BEMSimpleLineGraph/pull/2) ([Sam-Spencer](https://github.com/Sam-Spencer)) 303 | 304 | ## [v1.2.2](https://github.com/Boris-Em/BEMSimpleLineGraph/tree/v1.2.2) (2014-01-14) 305 | 306 | [Full Changelog](https://github.com/Boris-Em/BEMSimpleLineGraph/compare/v1.2.1...v1.2.2) 307 | 308 | ## [v1.2.1](https://github.com/Boris-Em/BEMSimpleLineGraph/tree/v1.2.1) (2014-01-08) 309 | 310 | [Full Changelog](https://github.com/Boris-Em/BEMSimpleLineGraph/compare/v1.2...v1.2.1) 311 | 312 | ## [v1.2](https://github.com/Boris-Em/BEMSimpleLineGraph/tree/v1.2) (2014-01-04) 313 | 314 | **Merged pull requests:** 315 | 316 | - Interface Initialization & Reload Data [\#1](https://github.com/Boris-Em/BEMSimpleLineGraph/pull/1) ([Sam-Spencer](https://github.com/Sam-Spencer)) 317 | 318 | 319 | 320 | \* *This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)* 321 | -------------------------------------------------------------------------------- /Classes/BEMAverageLine.h: -------------------------------------------------------------------------------- 1 | // 2 | // BEMAverageLine.h 3 | // SimpleLineChart 4 | // 5 | // Created by Sam Spencer on 4/7/15. 6 | // Copyright (c) 2015 Boris Emorine. All rights reserved. 7 | // 8 | 9 | @import Foundation; 10 | @import UIKit; 11 | 12 | 13 | /// A line displayed horizontally across the graph at the average y-value 14 | @interface BEMAverageLine : NSObject 15 | 16 | 17 | /// When set to YES, an average line will be displayed on the line graph 18 | @property (nonatomic) BOOL enableAverageLine; 19 | 20 | 21 | /// The color of the average line 22 | @property (strong, nonatomic) UIColor *color; 23 | 24 | 25 | /// The Y-Value of the average line. This could be an average, a median, a mode, sum, etc. 26 | @property (nonatomic) CGFloat yValue; 27 | 28 | 29 | /// The alpha of the average line 30 | @property (nonatomic) CGFloat alpha; 31 | 32 | 33 | /// The width of the average line 34 | @property (nonatomic) CGFloat width; 35 | 36 | 37 | /// Dash pattern for the average line 38 | @property (strong, nonatomic) NSArray *dashPattern; 39 | 40 | 41 | @end 42 | -------------------------------------------------------------------------------- /Classes/BEMAverageLine.m: -------------------------------------------------------------------------------- 1 | // 2 | // BEMAverageLine.m 3 | // SimpleLineChart 4 | // 5 | // Created by Sam Spencer on 4/7/15. 6 | // Copyright (c) 2015 Boris Emorine. All rights reserved. 7 | // 8 | 9 | #import "BEMAverageLine.h" 10 | 11 | @implementation BEMAverageLine 12 | 13 | - (instancetype)init { 14 | self = [super init]; 15 | if (self) { 16 | _enableAverageLine = NO; 17 | _color = [UIColor whiteColor]; 18 | _alpha = 1.0; 19 | _width = 3.0; 20 | _yValue = 0.0; 21 | } 22 | 23 | return self; 24 | } 25 | 26 | @end 27 | -------------------------------------------------------------------------------- /Classes/BEMCircle.h: -------------------------------------------------------------------------------- 1 | // 2 | // BEMCircle.h 3 | // SimpleLineGraph 4 | // 5 | // Created by Bobo on 12/27/13. Updated by Sam Spencer on 1/11/14. 6 | // Copyright (c) 2013 Boris Emorine. All rights reserved. 7 | // Copyright (c) 2014 Sam Spencer. 8 | // 9 | 10 | @import Foundation; 11 | @import UIKit; 12 | @import CoreGraphics; 13 | 14 | 15 | /// Class to draw the circle for the points. 16 | @interface BEMCircle : UIView 17 | 18 | /// Set to YES if the data point circles should be constantly displayed. NO if they should only appear when relevant. 19 | @property (assign, nonatomic) BOOL shouldDisplayConstantly; 20 | 21 | /// The point color 22 | @property (strong, nonatomic) UIColor *Pointcolor; 23 | 24 | /// The value of the point 25 | @property (nonatomic) CGFloat absoluteValue; 26 | 27 | @end -------------------------------------------------------------------------------- /Classes/BEMCircle.m: -------------------------------------------------------------------------------- 1 | // 2 | // BEMCircle.m 3 | // SimpleLineGraph 4 | // 5 | // Created by Bobo on 12/27/13. Updated by Sam Spencer on 1/11/14. 6 | // Copyright (c) 2013 Boris Emorine. All rights reserved. 7 | // Copyright (c) 2014 Sam Spencer. 8 | // 9 | 10 | #import "BEMCircle.h" 11 | 12 | @implementation BEMCircle 13 | 14 | - (instancetype)initWithFrame:(CGRect)frame { 15 | self = [super initWithFrame:frame]; 16 | if (self) { 17 | // Initialization code 18 | self.backgroundColor = [UIColor clearColor]; 19 | } 20 | return self; 21 | } 22 | 23 | - (void)drawRect:(CGRect)rect { 24 | CGContextRef ctx = UIGraphicsGetCurrentContext(); 25 | CGContextAddEllipseInRect(ctx, rect); 26 | [self.Pointcolor set]; 27 | CGContextFillPath(ctx); 28 | } 29 | 30 | @end -------------------------------------------------------------------------------- /Classes/BEMLine.h: -------------------------------------------------------------------------------- 1 | // 2 | // BEMLine.h 3 | // SimpleLineGraph 4 | // 5 | // Created by Bobo on 12/27/13. Updated by Sam Spencer on 1/11/14. 6 | // Copyright (c) 2013 Boris Emorine. All rights reserved. 7 | // Copyright (c) 2014 Sam Spencer. 8 | // 9 | 10 | @import Foundation; 11 | @import UIKit; 12 | @import CoreGraphics; 13 | 14 | #import "BEMAverageLine.h" 15 | 16 | 17 | /// The type of animation used to display the graph 18 | typedef NS_ENUM(NSInteger, BEMLineAnimation) { 19 | /// The draw animation draws the lines from left to right and bottom to top. 20 | BEMLineAnimationDraw, 21 | /// The fade animation fades in the lines from 0% opaque to 100% opaque (based on the \p lineAlpha property). 22 | BEMLineAnimationFade, 23 | /// The expand animation expands the lines from a small point to their full width (based on the \p lineWidth property). 24 | BEMLineAnimationExpand, 25 | /// No animation is used to display the graph 26 | BEMLineAnimationNone 27 | }; 28 | 29 | /// The drawing direction of the gradient used to draw the graph line (if any) 30 | typedef NS_ENUM(NSUInteger, BEMLineGradientDirection) { 31 | /// The gradient is drawn from left to right 32 | BEMLineGradientDirectionHorizontal = 0, 33 | /// The gradient is drawn from top to bottom 34 | BEMLineGradientDirectionVertical = 1 35 | }; 36 | 37 | 38 | /// Class to draw the line of the graph 39 | @interface BEMLine : UIView 40 | 41 | 42 | 43 | //----- POINTS -----// 44 | 45 | /// All of the Y-axis values for the points 46 | @property (strong, nonatomic) NSArray *arrayOfPoints; 47 | 48 | /// All of the X-Axis coordinates used to draw vertical lines through 49 | @property (strong, nonatomic) NSArray *arrayOfVerticalRefrenceLinePoints; 50 | 51 | /// The value used to offset the fringe vertical reference lines when the x-axis labels are on the edge 52 | @property (assign, nonatomic) CGFloat verticalReferenceHorizontalFringeNegation; 53 | 54 | /// All of the Y-Axis coordinates used to draw horizontal lines through 55 | @property (strong, nonatomic) NSArray *arrayOfHorizontalRefrenceLinePoints; 56 | 57 | /// All of the point values 58 | @property (strong, nonatomic) NSArray *arrayOfValues; 59 | 60 | /** Draw thin, translucent, reference lines using the provided X-Axis and Y-Axis coordinates. 61 | @see Use \p arrayOfVerticalRefrenceLinePoints to specify vertical reference lines' positions. Use \p arrayOfHorizontalRefrenceLinePoints to specify horizontal reference lines' positions. */ 62 | @property (assign, nonatomic) BOOL enableRefrenceLines; 63 | 64 | /** Draw a thin, translucent, frame on the edge of the graph to separate it from the labels on the X-Axis and the Y-Axis. */ 65 | @property (assign, nonatomic) BOOL enableRefrenceFrame; 66 | 67 | /** If reference frames are enabled, this will enable/disable specific borders. Default: YES */ 68 | @property (assign, nonatomic) BOOL enableLeftReferenceFrameLine; 69 | 70 | /** If reference frames are enabled, this will enable/disable specific borders. Default: YES */ 71 | @property (assign, nonatomic) BOOL enableBottomReferenceFrameLine; 72 | 73 | /** If reference frames are enabled, this will enable/disable specific borders. Default: NO */ 74 | @property (assign, nonatomic) BOOL enableRightReferenceFrameLine; 75 | 76 | /** If reference frames are enabled, this will enable/disable specific borders. Default: NO */ 77 | @property (assign, nonatomic) BOOL enableTopReferenceFrameLine; 78 | 79 | /** Dash pattern for the references line on the X axis */ 80 | @property (nonatomic, strong) NSArray *lineDashPatternForReferenceXAxisLines; 81 | 82 | /** Dash pattern for the references line on the Y axis */ 83 | @property (nonatomic, strong) NSArray *lineDashPatternForReferenceYAxisLines; 84 | 85 | /** If a null value is present, interpolation would draw a best fit line through the null point bound by its surrounding points. Default: YES */ 86 | @property (assign, nonatomic) BOOL interpolateNullValues; 87 | 88 | /** Draws everything but the main line on the graph; correlates to the \p displayDotsOnly property. Default: NO */ 89 | @property (assign, nonatomic) BOOL disableMainLine; 90 | 91 | 92 | 93 | //----- COLORS -----// 94 | 95 | /// The line color. A single, solid color which is applied to the entire line. If the \p gradient property is non-nil this property will be ignored. 96 | @property (strong, nonatomic) UIColor *color; 97 | 98 | /// The color of the area above the line, inside of its superview 99 | @property (strong, nonatomic) UIColor *topColor; 100 | 101 | /// A color gradient applied to the area above the line, inside of its superview. If set, it will be drawn on top of the fill from the \p topColor property. 102 | @property (assign, nonatomic) CGGradientRef topGradient; 103 | 104 | /// The color of the area below the line, inside of its superview 105 | @property (strong, nonatomic) UIColor *bottomColor; 106 | 107 | /// A color gradient applied to the area below the line, inside of its superview. If set, it will be drawn on top of the fill from the \p bottomColor property. 108 | @property (assign, nonatomic) CGGradientRef bottomGradient; 109 | 110 | /// A color gradient to be applied to the line. If this property is set, it will mask (override) the \p color property. 111 | @property (assign, nonatomic) CGGradientRef lineGradient; 112 | 113 | /// The drawing direction of the line gradient color 114 | @property (nonatomic) BEMLineGradientDirection lineGradientDirection; 115 | 116 | /// The reference line color. Defaults to `color`. 117 | @property (strong, nonatomic) UIColor *refrenceLineColor; 118 | 119 | 120 | 121 | //----- ALPHA -----// 122 | 123 | /// The line alpha 124 | @property (assign, nonatomic) float lineAlpha; 125 | 126 | /// The alpha value of the area above the line, inside of its superview 127 | @property (assign, nonatomic) float topAlpha; 128 | 129 | /// The alpha value of the area below the line, inside of its superview 130 | @property (assign, nonatomic) float bottomAlpha; 131 | 132 | 133 | 134 | //----- SIZE -----// 135 | 136 | /// The width of the line 137 | @property (assign, nonatomic) float lineWidth; 138 | 139 | /// The width of a reference line 140 | @property (nonatomic) float referenceLineWidth; 141 | 142 | 143 | 144 | //----- BEZIER CURVE -----// 145 | 146 | /// The line is drawn with smooth curves rather than straight lines when set to YES. 147 | @property (assign, nonatomic) BOOL bezierCurveIsEnabled; 148 | 149 | 150 | 151 | //----- ANIMATION -----// 152 | 153 | /// The entrance animation period in seconds. 154 | @property (assign, nonatomic) CGFloat animationTime; 155 | 156 | /// The type of entrance animation. 157 | @property (assign, nonatomic) BEMLineAnimation animationType; 158 | 159 | 160 | 161 | //----- AVERAGE -----// 162 | 163 | /// The average line 164 | @property (strong, nonatomic) BEMAverageLine *averageLine; 165 | 166 | /// The average line's y-value translated into the coordinate system 167 | @property (assign, nonatomic) CGFloat averageLineYCoordinate; 168 | 169 | 170 | 171 | @end 172 | -------------------------------------------------------------------------------- /Classes/BEMLine.m: -------------------------------------------------------------------------------- 1 | // 2 | // BEMLine.m 3 | // SimpleLineGraph 4 | // 5 | // Created by Bobo on 12/27/13. Updated by Sam Spencer on 1/11/14. 6 | // Copyright (c) 2013 Boris Emorine. All rights reserved. 7 | // Copyright (c) 2014 Sam Spencer. 8 | // 9 | 10 | #import "BEMLine.h" 11 | #import "BEMSimpleLineGraphView.h" 12 | 13 | #if CGFLOAT_IS_DOUBLE 14 | #define CGFloatValue doubleValue 15 | #else 16 | #define CGFloatValue floatValue 17 | #endif 18 | 19 | 20 | @interface BEMLine() 21 | 22 | @property (nonatomic, strong) NSMutableArray *points; 23 | 24 | @end 25 | 26 | @implementation BEMLine 27 | 28 | - (instancetype)initWithFrame:(CGRect)frame { 29 | self = [super initWithFrame:frame]; 30 | if (self) { 31 | // Initialization code 32 | self.backgroundColor = [UIColor clearColor]; 33 | _enableLeftReferenceFrameLine = YES; 34 | _enableBottomReferenceFrameLine = YES; 35 | _interpolateNullValues = YES; 36 | } 37 | return self; 38 | } 39 | 40 | - (void)drawRect:(CGRect)rect { 41 | //----------------------------// 42 | //---- Draw Refrence Lines ---// 43 | //----------------------------// 44 | UIBezierPath *verticalReferenceLinesPath = [UIBezierPath bezierPath]; 45 | UIBezierPath *horizontalReferenceLinesPath = [UIBezierPath bezierPath]; 46 | UIBezierPath *referenceFramePath = [UIBezierPath bezierPath]; 47 | 48 | verticalReferenceLinesPath.lineCapStyle = kCGLineCapButt; 49 | verticalReferenceLinesPath.lineWidth = 0.7; 50 | 51 | horizontalReferenceLinesPath.lineCapStyle = kCGLineCapButt; 52 | horizontalReferenceLinesPath.lineWidth = 0.7; 53 | 54 | referenceFramePath.lineCapStyle = kCGLineCapButt; 55 | referenceFramePath.lineWidth = 0.7; 56 | 57 | if (self.enableRefrenceFrame == YES) { 58 | if (self.enableBottomReferenceFrameLine) { 59 | // Bottom Line 60 | [referenceFramePath moveToPoint:CGPointMake(0, self.frame.size.height)]; 61 | [referenceFramePath addLineToPoint:CGPointMake(self.frame.size.width, self.frame.size.height)]; 62 | } 63 | 64 | if (self.enableLeftReferenceFrameLine) { 65 | // Left Line 66 | [referenceFramePath moveToPoint:CGPointMake(0+self.referenceLineWidth/4, self.frame.size.height)]; 67 | [referenceFramePath addLineToPoint:CGPointMake(0+self.referenceLineWidth/4, 0)]; 68 | } 69 | 70 | if (self.enableTopReferenceFrameLine) { 71 | // Top Line 72 | [referenceFramePath moveToPoint:CGPointMake(0+self.referenceLineWidth/4, 0)]; 73 | [referenceFramePath addLineToPoint:CGPointMake(self.frame.size.width, 0)]; 74 | } 75 | 76 | if (self.enableRightReferenceFrameLine) { 77 | // Right Line 78 | [referenceFramePath moveToPoint:CGPointMake(self.frame.size.width - self.referenceLineWidth/4, self.frame.size.height)]; 79 | [referenceFramePath addLineToPoint:CGPointMake(self.frame.size.width - self.referenceLineWidth/4, 0)]; 80 | } 81 | } 82 | 83 | if (self.enableRefrenceLines == YES) { 84 | if (self.arrayOfVerticalRefrenceLinePoints.count > 0) { 85 | for (NSNumber *xNumber in self.arrayOfVerticalRefrenceLinePoints) { 86 | CGFloat xValue; 87 | if (self.verticalReferenceHorizontalFringeNegation != 0.0) { 88 | if ([self.arrayOfVerticalRefrenceLinePoints indexOfObject:xNumber] == 0) { // far left reference line 89 | xValue = [xNumber floatValue] + self.verticalReferenceHorizontalFringeNegation; 90 | } else if ([self.arrayOfVerticalRefrenceLinePoints indexOfObject:xNumber] == [self.arrayOfVerticalRefrenceLinePoints count]-1) { // far right reference line 91 | xValue = [xNumber floatValue] - self.verticalReferenceHorizontalFringeNegation; 92 | } else xValue = [xNumber floatValue]; 93 | } else xValue = [xNumber floatValue]; 94 | 95 | CGPoint initialPoint = CGPointMake(xValue, self.frame.size.height); 96 | CGPoint finalPoint = CGPointMake(xValue, 0); 97 | 98 | [verticalReferenceLinesPath moveToPoint:initialPoint]; 99 | [verticalReferenceLinesPath addLineToPoint:finalPoint]; 100 | } 101 | } 102 | 103 | if (self.arrayOfHorizontalRefrenceLinePoints.count > 0) { 104 | for (NSNumber *yNumber in self.arrayOfHorizontalRefrenceLinePoints) { 105 | CGPoint initialPoint = CGPointMake(0, [yNumber floatValue]); 106 | CGPoint finalPoint = CGPointMake(self.frame.size.width, [yNumber floatValue]); 107 | 108 | [horizontalReferenceLinesPath moveToPoint:initialPoint]; 109 | [horizontalReferenceLinesPath addLineToPoint:finalPoint]; 110 | } 111 | } 112 | } 113 | 114 | 115 | //----------------------------// 116 | //----- Draw Average Line ----// 117 | //----------------------------// 118 | UIBezierPath *averageLinePath = [UIBezierPath bezierPath]; 119 | if (self.averageLine.enableAverageLine == YES) { 120 | averageLinePath.lineCapStyle = kCGLineCapButt; 121 | averageLinePath.lineWidth = self.averageLine.width; 122 | 123 | CGPoint initialPoint = CGPointMake(0, self.averageLineYCoordinate); 124 | CGPoint finalPoint = CGPointMake(self.frame.size.width, self.averageLineYCoordinate); 125 | 126 | [averageLinePath moveToPoint:initialPoint]; 127 | [averageLinePath addLineToPoint:finalPoint]; 128 | } 129 | 130 | 131 | //----------------------------// 132 | //------ Draw Graph Line -----// 133 | //----------------------------// 134 | // LINE 135 | UIBezierPath *line = [UIBezierPath bezierPath]; 136 | UIBezierPath *fillTop; 137 | UIBezierPath *fillBottom; 138 | 139 | CGFloat xIndexScale = self.frame.size.width/([self.arrayOfPoints count] - 1); 140 | 141 | self.points = [NSMutableArray arrayWithCapacity:self.arrayOfPoints.count]; 142 | for (int i = 0; i < self.arrayOfPoints.count; i++) { 143 | CGPoint value = CGPointMake(xIndexScale * i, [self.arrayOfPoints[i] CGFloatValue]); 144 | if (value.y != BEMNullGraphValue || !self.interpolateNullValues) { 145 | [self.points addObject:[NSValue valueWithCGPoint:value]]; 146 | } 147 | } 148 | 149 | BOOL bezierStatus = self.bezierCurveIsEnabled; 150 | if (self.arrayOfPoints.count <= 2 && self.bezierCurveIsEnabled == YES) bezierStatus = NO; 151 | 152 | if (!self.disableMainLine && bezierStatus) { 153 | line = [BEMLine quadCurvedPathWithPoints:self.points]; 154 | fillBottom = [BEMLine quadCurvedPathWithPoints:self.bottomPointsArray]; 155 | fillTop = [BEMLine quadCurvedPathWithPoints:self.topPointsArray]; 156 | } else if (!self.disableMainLine && !bezierStatus) { 157 | line = [BEMLine linesToPoints:self.points]; 158 | fillBottom = [BEMLine linesToPoints:self.bottomPointsArray]; 159 | fillTop = [BEMLine linesToPoints:self.topPointsArray]; 160 | } else { 161 | fillBottom = [BEMLine linesToPoints:self.bottomPointsArray]; 162 | fillTop = [BEMLine linesToPoints:self.topPointsArray]; 163 | } 164 | 165 | //----------------------------// 166 | //----- Draw Fill Colors -----// 167 | //----------------------------// 168 | [self.topColor set]; 169 | [fillTop fillWithBlendMode:kCGBlendModeNormal alpha:self.topAlpha]; 170 | 171 | [self.bottomColor set]; 172 | [fillBottom fillWithBlendMode:kCGBlendModeNormal alpha:self.bottomAlpha]; 173 | 174 | CGContextRef ctx = UIGraphicsGetCurrentContext(); 175 | if (self.topGradient != nil) { 176 | CGContextSaveGState(ctx); 177 | CGContextAddPath(ctx, [fillTop CGPath]); 178 | CGContextClip(ctx); 179 | CGContextDrawLinearGradient(ctx, self.topGradient, CGPointZero, CGPointMake(0, CGRectGetMaxY(fillTop.bounds)), 0); 180 | CGContextRestoreGState(ctx); 181 | } 182 | 183 | if (self.bottomGradient != nil) { 184 | CGContextSaveGState(ctx); 185 | CGContextAddPath(ctx, [fillBottom CGPath]); 186 | CGContextClip(ctx); 187 | CGContextDrawLinearGradient(ctx, self.bottomGradient, CGPointZero, CGPointMake(0, CGRectGetMaxY(fillBottom.bounds)), 0); 188 | CGContextRestoreGState(ctx); 189 | } 190 | 191 | 192 | //----------------------------// 193 | //------ Animate Drawing -----// 194 | //----------------------------// 195 | if (self.enableRefrenceLines == YES) { 196 | CAShapeLayer *verticalReferenceLinesPathLayer = [CAShapeLayer layer]; 197 | verticalReferenceLinesPathLayer.frame = self.bounds; 198 | verticalReferenceLinesPathLayer.path = verticalReferenceLinesPath.CGPath; 199 | verticalReferenceLinesPathLayer.opacity = self.lineAlpha == 0 ? 0.1 : self.lineAlpha/2; 200 | verticalReferenceLinesPathLayer.fillColor = nil; 201 | verticalReferenceLinesPathLayer.lineWidth = self.referenceLineWidth/2; 202 | 203 | if (self.lineDashPatternForReferenceYAxisLines) { 204 | verticalReferenceLinesPathLayer.lineDashPattern = self.lineDashPatternForReferenceYAxisLines; 205 | } 206 | 207 | if (self.refrenceLineColor) { 208 | verticalReferenceLinesPathLayer.strokeColor = self.refrenceLineColor.CGColor; 209 | } else { 210 | verticalReferenceLinesPathLayer.strokeColor = self.color.CGColor; 211 | } 212 | 213 | if (self.animationTime > 0) 214 | [self animateForLayer:verticalReferenceLinesPathLayer withAnimationType:self.animationType isAnimatingReferenceLine:YES]; 215 | [self.layer addSublayer:verticalReferenceLinesPathLayer]; 216 | 217 | 218 | CAShapeLayer *horizontalReferenceLinesPathLayer = [CAShapeLayer layer]; 219 | horizontalReferenceLinesPathLayer.frame = self.bounds; 220 | horizontalReferenceLinesPathLayer.path = horizontalReferenceLinesPath.CGPath; 221 | horizontalReferenceLinesPathLayer.opacity = self.lineAlpha == 0 ? 0.1 : self.lineAlpha/2; 222 | horizontalReferenceLinesPathLayer.fillColor = nil; 223 | horizontalReferenceLinesPathLayer.lineWidth = self.referenceLineWidth/2; 224 | if(self.lineDashPatternForReferenceXAxisLines) { 225 | horizontalReferenceLinesPathLayer.lineDashPattern = self.lineDashPatternForReferenceXAxisLines; 226 | } 227 | 228 | if (self.refrenceLineColor) { 229 | horizontalReferenceLinesPathLayer.strokeColor = self.refrenceLineColor.CGColor; 230 | } else { 231 | horizontalReferenceLinesPathLayer.strokeColor = self.color.CGColor; 232 | } 233 | 234 | if (self.animationTime > 0) 235 | [self animateForLayer:horizontalReferenceLinesPathLayer withAnimationType:self.animationType isAnimatingReferenceLine:YES]; 236 | [self.layer addSublayer:horizontalReferenceLinesPathLayer]; 237 | } 238 | 239 | CAShapeLayer *referenceLinesPathLayer = [CAShapeLayer layer]; 240 | referenceLinesPathLayer.frame = self.bounds; 241 | referenceLinesPathLayer.path = referenceFramePath.CGPath; 242 | referenceLinesPathLayer.opacity = self.lineAlpha == 0 ? 0.1 : self.lineAlpha/2; 243 | referenceLinesPathLayer.fillColor = nil; 244 | referenceLinesPathLayer.lineWidth = self.referenceLineWidth/2; 245 | 246 | if (self.refrenceLineColor) referenceLinesPathLayer.strokeColor = self.refrenceLineColor.CGColor; 247 | else referenceLinesPathLayer.strokeColor = self.color.CGColor; 248 | 249 | if (self.animationTime > 0) 250 | [self animateForLayer:referenceLinesPathLayer withAnimationType:self.animationType isAnimatingReferenceLine:YES]; 251 | [self.layer addSublayer:referenceLinesPathLayer]; 252 | 253 | if (self.disableMainLine == NO) { 254 | CAShapeLayer *pathLayer = [CAShapeLayer layer]; 255 | pathLayer.frame = self.bounds; 256 | pathLayer.path = line.CGPath; 257 | pathLayer.strokeColor = self.color.CGColor; 258 | pathLayer.fillColor = nil; 259 | pathLayer.opacity = self.lineAlpha; 260 | pathLayer.lineWidth = self.lineWidth; 261 | pathLayer.lineJoin = kCALineJoinBevel; 262 | pathLayer.lineCap = kCALineCapRound; 263 | if (self.animationTime > 0) [self animateForLayer:pathLayer withAnimationType:self.animationType isAnimatingReferenceLine:NO]; 264 | if (self.lineGradient) [self.layer addSublayer:[self backgroundGradientLayerForLayer:pathLayer]]; 265 | else [self.layer addSublayer:pathLayer]; 266 | } 267 | 268 | if (self.averageLine.enableAverageLine == YES) { 269 | CAShapeLayer *averageLinePathLayer = [CAShapeLayer layer]; 270 | averageLinePathLayer.frame = self.bounds; 271 | averageLinePathLayer.path = averageLinePath.CGPath; 272 | averageLinePathLayer.opacity = self.averageLine.alpha; 273 | averageLinePathLayer.fillColor = nil; 274 | averageLinePathLayer.lineWidth = self.averageLine.width; 275 | 276 | if (self.averageLine.dashPattern) averageLinePathLayer.lineDashPattern = self.averageLine.dashPattern; 277 | 278 | if (self.averageLine.color) averageLinePathLayer.strokeColor = self.averageLine.color.CGColor; 279 | else averageLinePathLayer.strokeColor = self.color.CGColor; 280 | 281 | if (self.animationTime > 0) 282 | [self animateForLayer:averageLinePathLayer withAnimationType:self.animationType isAnimatingReferenceLine:NO]; 283 | [self.layer addSublayer:averageLinePathLayer]; 284 | } 285 | } 286 | 287 | - (NSArray *)topPointsArray { 288 | CGPoint topPointZero = CGPointMake(0,0); 289 | CGPoint topPointFull = CGPointMake(self.frame.size.width, 0); 290 | NSMutableArray *topPoints = [NSMutableArray arrayWithArray:self.points]; 291 | [topPoints insertObject:[NSValue valueWithCGPoint:topPointZero] atIndex:0]; 292 | [topPoints addObject:[NSValue valueWithCGPoint:topPointFull]]; 293 | return topPoints; 294 | } 295 | 296 | - (NSArray *)bottomPointsArray { 297 | CGPoint bottomPointZero = CGPointMake(0, self.frame.size.height); 298 | CGPoint bottomPointFull = CGPointMake(self.frame.size.width, self.frame.size.height); 299 | NSMutableArray *bottomPoints = [NSMutableArray arrayWithArray:self.points]; 300 | [bottomPoints insertObject:[NSValue valueWithCGPoint:bottomPointZero] atIndex:0]; 301 | [bottomPoints addObject:[NSValue valueWithCGPoint:bottomPointFull]]; 302 | return bottomPoints; 303 | } 304 | 305 | + (UIBezierPath *)linesToPoints:(NSArray *)points { 306 | UIBezierPath *path = [UIBezierPath bezierPath]; 307 | NSValue *value = points[0]; 308 | CGPoint p1 = [value CGPointValue]; 309 | [path moveToPoint:p1]; 310 | 311 | for (NSUInteger i = 1; i < points.count; i++) { 312 | value = points[i]; 313 | CGPoint p2 = [value CGPointValue]; 314 | [path addLineToPoint:p2]; 315 | } 316 | return path; 317 | } 318 | 319 | + (UIBezierPath *)quadCurvedPathWithPoints:(NSArray *)points { 320 | UIBezierPath *path = [UIBezierPath bezierPath]; 321 | 322 | NSValue *value = points[0]; 323 | CGPoint p1 = [value CGPointValue]; 324 | [path moveToPoint:p1]; 325 | 326 | if (points.count == 2) { 327 | value = points[1]; 328 | CGPoint p2 = [value CGPointValue]; 329 | [path addLineToPoint:p2]; 330 | return path; 331 | } 332 | 333 | for (NSUInteger i = 1; i < points.count; i++) { 334 | value = points[i]; 335 | CGPoint p2 = [value CGPointValue]; 336 | 337 | CGPoint midPoint = midPointForPoints(p1, p2); 338 | [path addQuadCurveToPoint:midPoint controlPoint:controlPointForPoints(midPoint, p1)]; 339 | [path addQuadCurveToPoint:p2 controlPoint:controlPointForPoints(midPoint, p2)]; 340 | 341 | p1 = p2; 342 | } 343 | return path; 344 | } 345 | 346 | static CGPoint midPointForPoints(CGPoint p1, CGPoint p2) { 347 | return CGPointMake((p1.x + p2.x) / 2, (p1.y + p2.y) / 2); 348 | } 349 | 350 | static CGPoint controlPointForPoints(CGPoint p1, CGPoint p2) { 351 | CGPoint controlPoint = midPointForPoints(p1, p2); 352 | CGFloat diffY = fabs(p2.y - controlPoint.y); 353 | 354 | if (p1.y < p2.y) 355 | controlPoint.y += diffY; 356 | else if (p1.y > p2.y) 357 | controlPoint.y -= diffY; 358 | 359 | return controlPoint; 360 | } 361 | 362 | - (void)animateForLayer:(CAShapeLayer *)shapeLayer withAnimationType:(BEMLineAnimation)animationType isAnimatingReferenceLine:(BOOL)shouldHalfOpacity { 363 | if (animationType == BEMLineAnimationNone) return; 364 | else if (animationType == BEMLineAnimationFade) { 365 | CABasicAnimation *pathAnimation = [CABasicAnimation animationWithKeyPath:@"opacity"]; 366 | pathAnimation.duration = self.animationTime; 367 | pathAnimation.fromValue = [NSNumber numberWithFloat:0.0f]; 368 | if (shouldHalfOpacity == YES) pathAnimation.toValue = [NSNumber numberWithFloat:self.lineAlpha == 0 ? 0.1 : self.lineAlpha/2]; 369 | else pathAnimation.toValue = [NSNumber numberWithFloat:self.lineAlpha]; 370 | [shapeLayer addAnimation:pathAnimation forKey:@"opacity"]; 371 | 372 | return; 373 | } else if (animationType == BEMLineAnimationExpand) { 374 | CABasicAnimation *pathAnimation = [CABasicAnimation animationWithKeyPath:@"lineWidth"]; 375 | pathAnimation.duration = self.animationTime; 376 | pathAnimation.fromValue = [NSNumber numberWithFloat:0.0f]; 377 | pathAnimation.toValue = [NSNumber numberWithFloat:shapeLayer.lineWidth]; 378 | [shapeLayer addAnimation:pathAnimation forKey:@"lineWidth"]; 379 | 380 | return; 381 | } else { 382 | CABasicAnimation *pathAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"]; 383 | pathAnimation.duration = self.animationTime; 384 | pathAnimation.fromValue = [NSNumber numberWithFloat:0.0f]; 385 | pathAnimation.toValue = [NSNumber numberWithFloat:1.0f]; 386 | [shapeLayer addAnimation:pathAnimation forKey:@"strokeEnd"]; 387 | 388 | return; 389 | } 390 | } 391 | 392 | - (CALayer *)backgroundGradientLayerForLayer:(CAShapeLayer *)shapeLayer { 393 | UIGraphicsBeginImageContext(self.bounds.size); 394 | CGContextRef imageCtx = UIGraphicsGetCurrentContext(); 395 | CGPoint start, end; 396 | if (self.lineGradientDirection == BEMLineGradientDirectionHorizontal) { 397 | start = CGPointMake(0, CGRectGetMidY(shapeLayer.bounds)); 398 | end = CGPointMake(CGRectGetMaxX(shapeLayer.bounds), CGRectGetMidY(shapeLayer.bounds)); 399 | } else { 400 | start = CGPointMake(CGRectGetMidX(shapeLayer.bounds), 0); 401 | end = CGPointMake(CGRectGetMidX(shapeLayer.bounds), CGRectGetMaxY(shapeLayer.bounds)); 402 | } 403 | 404 | CGContextDrawLinearGradient(imageCtx, self.lineGradient, start, end, 0); 405 | UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); 406 | UIGraphicsEndImageContext(); 407 | CALayer *gradientLayer = [CALayer layer]; 408 | gradientLayer.frame = self.bounds; 409 | gradientLayer.contents = (id)image.CGImage; 410 | gradientLayer.mask = shapeLayer; 411 | return gradientLayer; 412 | } 413 | 414 | @end 415 | -------------------------------------------------------------------------------- /Classes/BEMPermanentPopupView.h: -------------------------------------------------------------------------------- 1 | // 2 | // BEMPermanentPopupView.h 3 | // SimpleLineGraph 4 | // 5 | // Created by Delisa Mason on 1/29/15. 6 | // Copyright (c) 2015 Boris Emorine. All rights reserved. 7 | // 8 | 9 | @import UIKit; 10 | 11 | 12 | @interface BEMPermanentPopupView : UIView 13 | 14 | @end 15 | 16 | @interface BEMPermanentPopupLabel : UILabel 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /Classes/BEMPermanentPopupView.m: -------------------------------------------------------------------------------- 1 | // 2 | // BEMPermanentPopupView.m 3 | // SimpleLineGraph 4 | // 5 | // Created by Delisa Mason on 1/29/15. 6 | // Copyright (c) 2015 Boris Emorine. All rights reserved. 7 | // 8 | 9 | #import "BEMPermanentPopupView.h" 10 | 11 | @implementation BEMPermanentPopupView 12 | 13 | @end 14 | 15 | @implementation BEMPermanentPopupLabel 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /Classes/BEMSimpleLineGraphView.h: -------------------------------------------------------------------------------- 1 | // 2 | // BEMSimpleLineGraphView.h 3 | // SimpleLineGraph 4 | // 5 | // Created by Bobo on 12/27/13. Updated by Sam Spencer on 1/11/14. 6 | // Copyright (c) 2013 Boris Emorine. All rights reserved. 7 | // Copyright (c) 2014 Sam Spencer. 8 | // 9 | 10 | @import Foundation; 11 | @import UIKit; 12 | @import CoreGraphics; 13 | 14 | #import "BEMCircle.h" 15 | #import "BEMLine.h" 16 | #import "BEMPermanentPopupView.h" 17 | #import "BEMAverageLine.h" 18 | 19 | @protocol BEMSimpleLineGraphDelegate; 20 | @protocol BEMSimpleLineGraphDataSource; 21 | @protocol BEMSimpleLineGraphPopoverProtocol; 22 | 23 | 24 | extern const CGFloat BEMNullGraphValue; 25 | 26 | // Tell the compiler to assume that no method should have a NULL value 27 | NS_ASSUME_NONNULL_BEGIN 28 | 29 | /// Simple line graph / chart UIView subclass for iOS apps. Creates beautiful line graphs (without huge memory impacts) using QuartzCore. 30 | IB_DESIGNABLE @interface BEMSimpleLineGraphView : UIView 31 | 32 | 33 | 34 | //------------------------------------------------------------------------------------// 35 | //----- DELEGATE ---------------------------------------------------------------------// 36 | //------------------------------------------------------------------------------------// 37 | 38 | 39 | /** The object that acts as the delegate of the receiving line graph. 40 | 41 | @abstract The BEMSimpleLineGraphView delegate object plays a key role in changing the appearance of the graph and receiving graph events. Use the delegate to provide appearance changes, receive touch events, and receive graph events. The delegate can be set from the interface or from code. 42 | @discussion The delegate must adopt the \p BEMSimpleLineGraphDelegate protocol. The delegate is not retained.*/ 43 | @property (nonatomic, weak, nullable) IBOutlet id delegate; 44 | 45 | 46 | 47 | //------------------------------------------------------------------------------------// 48 | //----- DATA SOURCE ------------------------------------------------------------------// 49 | //------------------------------------------------------------------------------------// 50 | 51 | 52 | /** The object that acts as the data source of the receiving line graph. 53 | 54 | @abstract The BEMSimpleLineGraphView data source object is essential to the line graph. Use the data source to provide the graph with data (data points and x-axis labels). The delegate can be set from the interface or from code. 55 | @discussion The data source must adopt the \p BEMSimpleLineGraphDataSource protocol. The data source is not retained.*/ 56 | @property (nonatomic, weak) IBOutlet id dataSource; 57 | 58 | 59 | 60 | //------------------------------------------------------------------------------------// 61 | //----- METHODS ----------------------------------------------------------------------// 62 | //------------------------------------------------------------------------------------// 63 | 64 | 65 | /// Reload the graph, all delegate methods are called again and the graph is reloaded. Similar to calling reloadData on a UITableView. 66 | - (void)reloadGraph; 67 | 68 | 69 | /** Calculates the distance between the touch input and the closest point on the graph. 70 | @return The distance between the touch input and the closest point on the graph. */ 71 | - (CGFloat)distanceToClosestPoint __deprecated; 72 | 73 | 74 | /** Takes a snapshot of the graph while the app is in the foreground. 75 | @return The snapshot of the graph as a UIImage object. */ 76 | - (UIImage *)graphSnapshotImage NS_AVAILABLE_IOS(7_0); 77 | 78 | 79 | /** Takes a snapshot of the graph. 80 | @param appIsInBackground If your app is currently in the background state, pass YES to \p appIsInBackground. Otherwise, when your app is in the foreground you should take advantage of more efficient APIs by passing NO to \p appIsInBackground. 81 | @return The snapshot of the graph as a UIImage object. */ 82 | - (UIImage *)graphSnapshotImageRenderedWhileInBackground:(BOOL)appIsInBackground NS_AVAILABLE_IOS(7_0); 83 | 84 | 85 | /** Calculates the average (mean) of all points on the line graph. 86 | @return The average (mean) number of the points on the graph. Originally a float. */ 87 | - (NSNumber *)calculatePointValueAverage; 88 | 89 | 90 | /** Calculates the sum of all points on the line graph. 91 | @return The sum of the points on the graph. Originally a float. */ 92 | - (NSNumber *)calculatePointValueSum; 93 | 94 | 95 | /** Calculates the median of all points on the line graph. 96 | @return The median number of the points on the graph. Originally a float. */ 97 | - (NSNumber *)calculatePointValueMedian; 98 | 99 | 100 | /** Calculates the mode of all points on the line graph. 101 | @return The mode number of the points on the graph. Originally a float. */ 102 | - (NSNumber *)calculatePointValueMode; 103 | 104 | 105 | /** Calculates the standard deviation of all points on the line graph. 106 | @return The standard deviation of the points on the graph. Originally a float. */ 107 | - (NSNumber *)calculateLineGraphStandardDeviation; 108 | 109 | 110 | /** Calculates the minimum value of all points on the line graph. 111 | @return The minimum number of the points on the graph. Originally a float. */ 112 | - (NSNumber *)calculateMinimumPointValue; 113 | 114 | 115 | /** Calculates the maximum value of all points on the line graph. 116 | @return The maximum value of the points on the graph. Originally a float. */ 117 | - (NSNumber *)calculateMaximumPointValue; 118 | 119 | 120 | /** All the displayed values of the X-Axis. 121 | @return An array of NSStrings, one for each displayed X-Axis label. The array is sorted from the left side of the graph to the right side. */ 122 | - (nullable NSArray *)graphValuesForXAxis; 123 | 124 | 125 | /** All the data points on the graph. 126 | @return An array of NSNumbers, one for each data point. The array is sorted from the left side of the graph to the right side. */ 127 | - (nullable NSArray *)graphValuesForDataPoints; 128 | 129 | 130 | /** All the labels of the X-Axis. 131 | @return An array of UILabels, one for each displayed X-Axis label. The array is sorted from the left side of the graph to the right side. */ 132 | - (nullable NSArray *)graphLabelsForXAxis; 133 | 134 | 135 | 136 | //------------------------------------------------------------------------------------// 137 | //----- PROPERTIES -------------------------------------------------------------------// 138 | //------------------------------------------------------------------------------------// 139 | 140 | 141 | /// The graph's label font used on various axis. This property may be privately overwritten, do not expect full functionality from this property. 142 | @property (strong, nonatomic, nullable) UIFont *labelFont; 143 | 144 | 145 | /// Time of the animation when the graph appears in seconds. Default value is 1.5. 146 | @property (nonatomic) CGFloat animationGraphEntranceTime; 147 | 148 | 149 | /** Animation style used when the graph appears. Default value is BEMLineAnimationDraw. 150 | @see Refer to \p BEMLineAnimation for a complete list of animation styles. */ 151 | @property (nonatomic) BEMLineAnimation animationGraphStyle; 152 | 153 | 154 | /// If set to YES, the graph will report the value of the closest point from the user current touch location. The 2 methods for touch event bellow should therefore be implemented. Default value is NO. 155 | @property (nonatomic) BOOL enableTouchReport; 156 | 157 | 158 | /** The number of fingers required to report touches to the graph's delegate. The default value is 1. 159 | @discussion Setting this value to greater than 1 might be beneficial in interfaces that allow the graph to scroll and still want to use touch reporting. */ 160 | @property (nonatomic) NSInteger touchReportFingersRequired; 161 | 162 | 163 | /// If set to YES, a label will pop up on the graph when the user touches it. It will be displayed on top of the closest point from the user current touch location. Default value is NO. 164 | @property (nonatomic) BOOL enablePopUpReport; 165 | 166 | 167 | /// The way the graph is drawn, with or without bezier curved lines. Default value is NO. 168 | @property (nonatomic) IBInspectable BOOL enableBezierCurve; 169 | 170 | 171 | /** Show Y-Axis label on the side. Default value is NO. 172 | @todo Could enhance further by specifying the position of Y-Axis, i.e. Left or Right of the view. Also auto detection on label overlapping. */ 173 | @property (nonatomic) IBInspectable BOOL enableYAxisLabel; 174 | 175 | 176 | /** Show X-Axis label at the bottom of the graph. Default value is YES. 177 | @see \p labelOnXAxisForIndex */ 178 | @property (nonatomic) IBInspectable BOOL enableXAxisLabel; 179 | 180 | 181 | /** When set to YES, the points on the Y-axis will be set to all fit in the graph view. When set to NO, the points on the Y-axis will be set with their absolute value (which means that certain points might not be visible because they are outside of the view). Default value is YES. */ 182 | @property (nonatomic) BOOL autoScaleYAxis; 183 | 184 | 185 | /// The horizontal line across the graph at the average value. 186 | @property (strong, nonatomic) BEMAverageLine *averageLine; 187 | 188 | 189 | /// Draws a translucent vertical lines along the graph for each X-Axis when set to YES. Default value is NO. 190 | @property (nonatomic) BOOL enableReferenceXAxisLines; 191 | 192 | 193 | /// Draws a translucent horizontal lines along the graph for each Y-Axis label, when set to YES. Default value is NO. 194 | @property (nonatomic) BOOL enableReferenceYAxisLines; 195 | 196 | 197 | /** Draws a translucent frame between the graph and any enabled axis, when set to YES. Default value is NO. 198 | @see enableReferenceXAxisLines or enableReferenceYAxisLines must be set to YES for this property to have any effect. */ 199 | @property (nonatomic) BOOL enableReferenceAxisFrame; 200 | 201 | 202 | /** If reference frames are enabled, this will enable/disable specific borders. Default: YES */ 203 | @property (nonatomic) BOOL enableLeftReferenceAxisFrameLine; 204 | 205 | 206 | /** If reference frames are enabled, this will enable/disable specific borders. Default: YES */ 207 | @property (nonatomic) BOOL enableBottomReferenceAxisFrameLine; 208 | 209 | 210 | /** If reference frames are enabled, this will enable/disable specific borders. Default: NO */ 211 | @property (nonatomic) BOOL enableRightReferenceAxisFrameLine; 212 | 213 | 214 | /** If reference frames are enabled, this will enable/disable specific borders. Default: NO */ 215 | @property (nonatomic) BOOL enableTopReferenceAxisFrameLine; 216 | 217 | 218 | /// If set to YES, the dots representing the points on the graph will always be visible. Default value is NO. 219 | @property (nonatomic) BOOL alwaysDisplayDots; 220 | 221 | /// If set to YES, the dots will be drawn during the animation. If NO, dots won't show up for the animation if alwaysDisplayDots if false. Default value is YES 222 | @property (nonatomic) BOOL displayDotsWhileAnimating; 223 | 224 | 225 | /// If set to YES, pop up labels with the Y-value of the point will always be visible. Default value is NO. 226 | @property (nonatomic) BOOL alwaysDisplayPopUpLabels; 227 | 228 | 229 | /// Color of the bottom part of the graph (between the line and the X-axis). 230 | @property (strong, nonatomic) IBInspectable UIColor *colorBottom; 231 | 232 | 233 | /// Alpha of the bottom part of the graph (between the line and the X-axis). 234 | @property (nonatomic) IBInspectable CGFloat alphaBottom; 235 | 236 | 237 | /// Fill gradient of the bottom part of the graph (between the line and the X-axis). When set, it will draw a gradient over top of the fill provided by the \p colorBottom and \p alphaBottom properties. 238 | @property (assign, nonatomic) CGGradientRef gradientBottom; 239 | 240 | 241 | /// Color of the top part of the graph (between the line and the top of the view the graph is drawn in). 242 | @property (strong, nonatomic) IBInspectable UIColor *colorTop; 243 | 244 | 245 | /// Alpha of the top part of the graph (between the line and the top of the view the graph is drawn in). 246 | @property (nonatomic) IBInspectable CGFloat alphaTop; 247 | 248 | 249 | /// Fill gradient of the top part of the graph (between the line and the top of the view the graph is drawn in). When set, it will draw a gradient over top of the fill provided by the \p colorTop and \p alphaTop properties. 250 | @property (assign, nonatomic) CGGradientRef gradientTop; 251 | 252 | 253 | /// Color of the line of the graph. 254 | @property (strong, nonatomic) IBInspectable UIColor *colorLine; 255 | 256 | 257 | /// Fill gradient of the line of the graph, which will be scaled to the length of the graph. Overrides the line color provided by \p colorLine 258 | @property (assign, nonatomic) CGGradientRef gradientLine; 259 | 260 | 261 | /// The drawing direction of the line gradient color, which defaults to horizontal 262 | @property (nonatomic) BEMLineGradientDirection gradientLineDirection; 263 | 264 | 265 | /// Alpha of the line of the graph. 266 | @property (nonatomic) IBInspectable CGFloat alphaLine; 267 | 268 | 269 | /// Width of the line of the graph. Default value is 1.0. 270 | @property (nonatomic) IBInspectable CGFloat widthLine; 271 | 272 | 273 | /// Width of the reference lines of the graph. Default is the value of widthLine/2. 274 | @property (nonatomic) IBInspectable CGFloat widthReferenceLines; 275 | 276 | 277 | /// Color of the reference lines of the graph. Default is same color as `colorLine`. 278 | @property (strong, nonatomic) UIColor *colorReferenceLines; 279 | 280 | 281 | /// The size of the circles that represent each point. Default is 10.0. 282 | @property (nonatomic) IBInspectable CGFloat sizePoint; 283 | 284 | 285 | /// The color of the circles that represent each point. Default is white at 70% alpha. 286 | @property (strong, nonatomic) IBInspectable UIColor *colorPoint; 287 | 288 | 289 | /// The color of the line that appears when the user touches the graph. 290 | @property (strong, nonatomic) UIColor *colorTouchInputLine; 291 | 292 | 293 | /// The alpha of the line that appears when the user touches the graph. 294 | @property (nonatomic) CGFloat alphaTouchInputLine; 295 | 296 | 297 | /// The width of the line that appears when the user touches the graph. 298 | @property (nonatomic) CGFloat widthTouchInputLine; 299 | 300 | 301 | /// Color of the label's text displayed on the X-Axis. Defaut value is blackColor. 302 | @property (strong, nonatomic) IBInspectable UIColor *colorXaxisLabel; 303 | 304 | 305 | /// Color of the background of the X-Axis 306 | @property (strong, nonatomic, nullable) UIColor *colorBackgroundXaxis; 307 | 308 | 309 | /// Alpha of the background of the X-Axis 310 | @property (nonatomic) CGFloat alphaBackgroundXaxis; 311 | 312 | 313 | /// Color of the background of the Y-Axis 314 | @property (strong, nonatomic, nullable) UIColor *colorBackgroundYaxis; 315 | 316 | 317 | /// Alpha of the background of the Y-Axis 318 | @property (nonatomic) CGFloat alphaBackgroundYaxis; 319 | 320 | 321 | /// Color of the label's text displayed on the Y-Axis. Defaut value is blackColor. 322 | @property (strong, nonatomic) IBInspectable UIColor *colorYaxisLabel; 323 | 324 | 325 | /// Color of the pop up label's background displayed when the user touches the graph. 326 | @property (strong, nonatomic) UIColor *colorBackgroundPopUplabel; 327 | 328 | 329 | /// Position of the y-Axis in relation to the chart (Default: NO) 330 | @property (nonatomic) BOOL positionYAxisRight; 331 | 332 | 333 | /// A line dash patter to be applied to X axis reference lines. This allows you to draw a dotted or hashed line 334 | @property (nonatomic, strong) NSArray *lineDashPatternForReferenceXAxisLines; 335 | 336 | 337 | /// A line dash patter to be applied to Y axis reference lines. This allows you to draw a dotted or hashed line 338 | @property (nonatomic, strong) NSArray *lineDashPatternForReferenceYAxisLines; 339 | 340 | 341 | /// Color to be used for the no data label on the chart 342 | @property (nonatomic, strong) UIColor *noDataLabelColor; 343 | 344 | 345 | /// Font to be used for the no data label on the chart 346 | @property (nonatomic, strong) UIFont *noDataLabelFont; 347 | 348 | 349 | /// Float format string to be used when formatting popover and y axis values 350 | @property (nonatomic, strong) NSString *formatStringForValues; 351 | 352 | 353 | /** If a null value is present, interpolation would draw a best fit line through the null point bound by its surrounding points. Default: YES*/ 354 | @property (nonatomic) BOOL interpolateNullValues; 355 | 356 | 357 | /// When set to YES, dots will be displayed at full opacity and no line will be drawn through the dots. Default value is NO. 358 | @property (nonatomic) BOOL displayDotsOnly; 359 | 360 | 361 | @end 362 | 363 | 364 | 365 | @interface BEMSimpleLineGraphPopoverView : UIView 366 | 367 | 368 | @end 369 | 370 | 371 | 372 | /// Line Graph Data Source. Used to populate the graph with data, similar to how a UITableView works. 373 | @protocol BEMSimpleLineGraphDataSource 374 | 375 | 376 | @required 377 | 378 | 379 | //----- DATA POINTS -----// 380 | 381 | 382 | /** The number of points along the X-axis of the graph. 383 | @param graph The graph object requesting the total number of points. 384 | @return The total number of points in the line graph. */ 385 | - (NSInteger)numberOfPointsInLineGraph:(BEMSimpleLineGraphView *)graph; 386 | 387 | 388 | /** The vertical position for a point at the given index. It corresponds to the Y-axis value of the Graph. 389 | @param graph The graph object requesting the point value. 390 | @param index The index from left to right of a given point (X-axis). The first value for the index is 0. 391 | @return The Y-axis value at a given index. */ 392 | - (CGFloat)lineGraph:(BEMSimpleLineGraphView *)graph valueForPointAtIndex:(NSInteger)index; 393 | 394 | 395 | @optional 396 | 397 | 398 | //------- X AXIS -------// 399 | 400 | /** The string to display on the label on the X-axis at a given index. 401 | @discussion The number of strings to be returned should be equal to the number of points in the graph (returned in \p numberOfPointsInLineGraph). Otherwise, an exception may be thrown. 402 | @param graph The graph object which is requesting the label on the specified X-Axis position. 403 | @param index The index from left to right of a given label on the X-axis. Is the same index as the one for the points. The first value for the index is 0. */ 404 | - (nullable NSString *)lineGraph:(nonnull BEMSimpleLineGraphView *)graph labelOnXAxisForIndex:(NSInteger)index; 405 | 406 | 407 | @end 408 | 409 | 410 | 411 | /// Line Graph Delegate. Used to change the graph's appearance and recieve events, similar to how a UITableView works. 412 | @protocol BEMSimpleLineGraphDelegate 413 | 414 | 415 | @optional 416 | 417 | 418 | 419 | //----- GRAPH EVENTS -----// 420 | 421 | 422 | /** Sent to the delegate each time the line graph is loaded or reloaded. 423 | @seealso lineGraphDidFinishLoading: 424 | @param graph The graph object that is about to be loaded or reloaded. */ 425 | - (void)lineGraphDidBeginLoading:(BEMSimpleLineGraphView *)graph; 426 | 427 | 428 | /** Sent to the delegate each time the line graph finishes loading or reloading. 429 | @discussion The respective graph object's data has been loaded at this time. However, the graph may not be fully rendered. Use this method to update any content with the new graph object's data. 430 | 431 | @seealso lineGraphDidBeginLoading: lineGraphDidFinishDrawing: 432 | @param graph The graph object that finished loading or reloading. */ 433 | - (void)lineGraphDidFinishLoading:(BEMSimpleLineGraphView *)graph; 434 | 435 | 436 | /** Sent to the delegate each time the line graph finishes animating and drawing. 437 | @discussion The respective graph object has been completely drawn and animated at this point. It is safe to use \p graphSnapshotImage after recieving this method call on the delegate. 438 | 439 | This method may be called in addition to the \p lineGraphDidFinishLoading: method, after drawing has completed. \p animationGraphEntranceTime is taken into account when calling this method. 440 | 441 | @seealso lineGraphDidFinishLoading: 442 | @param graph The graph object that finished drawing. */ 443 | - (void)lineGraphDidFinishDrawing:(BEMSimpleLineGraphView *)graph; 444 | 445 | 446 | //----- CUSTOMIZATION -----// 447 | 448 | 449 | /** The optional suffix to append to the popup report. 450 | @param graph The graph object requesting the total number of points. 451 | @return The suffix to append to the popup report. */ 452 | - (NSString *)popUpSuffixForlineGraph:(BEMSimpleLineGraphView *)graph; 453 | 454 | 455 | /** The optional prefix to append to the popup report. 456 | @param graph The graph object requesting the total number of points. 457 | @return The prefix to prepend to the popup report. */ 458 | - (NSString *)popUpPrefixForlineGraph:(BEMSimpleLineGraphView *)graph; 459 | 460 | 461 | /** Optional method to always display some of the pop up labels on the graph. 462 | @see alwaysDisplayPopUpLabels must be set to YES for this method to have any effect. 463 | @param graph The graph object requesting the total number of points. 464 | @param index The index from left to right of the points on the graph. The first value for the index is 0. 465 | @return Return YES if you want the popup label to be displayed for this index. */ 466 | - (BOOL)lineGraph:(BEMSimpleLineGraphView *)graph alwaysDisplayPopUpAtIndex:(CGFloat)index; 467 | 468 | 469 | /** Optional method to set the maximum value of the Y-Axis. If not implemented, the maximum value will be the biggest point of the graph. 470 | @param graph The graph object requesting the maximum value. 471 | @return The maximum value of the Y-Axis. */ 472 | - (CGFloat)maxValueForLineGraph:(BEMSimpleLineGraphView *)graph; 473 | 474 | 475 | /** Optional method to set the minimum value of the Y-Axis. If not implemented, the minimum value will be the smallest point of the graph. 476 | @param graph The graph object requesting the minimum value. 477 | @return The minimum value of the Y-Axis. */ 478 | - (CGFloat)minValueForLineGraph:(BEMSimpleLineGraphView *)graph; 479 | 480 | 481 | /** Optional method to control whether a label indicating NO DATA will be shown while number of data is zero 482 | @param graph The graph object for the NO DATA label 483 | @return The boolean value indicating the availability of the NO DATA label. */ 484 | - (BOOL)noDataLabelEnableForLineGraph:(BEMSimpleLineGraphView *)graph; 485 | 486 | 487 | /** Optional method to control the text to be displayed on NO DATA label 488 | @param graph The graph object for the NO DATA label 489 | @return The text to show on the NO DATA label. */ 490 | - (NSString *)noDataLabelTextForLineGraph:(BEMSimpleLineGraphView *)graph; 491 | 492 | 493 | /** Optional method to set the static padding distance between the graph line and the whole graph 494 | @param graph The graph object requesting the padding value. 495 | @return The padding value of the graph. */ 496 | - (CGFloat)staticPaddingForLineGraph:(BEMSimpleLineGraphView *)graph; 497 | 498 | 499 | /** Optional method to return a custom popup view to be used on the chart 500 | @param graph The graph object requesting the padding value. 501 | @return The custom popup view to use */ 502 | - (UIView *)popUpViewForLineGraph:(BEMSimpleLineGraphView *)graph; 503 | 504 | 505 | /** Optional method that gets called if you are using a custom popup view. This method allows you to modify your popup view for different graph indices 506 | @param graph The graph object requesting the padding value. 507 | @param popupView The popup view owned by the graph that needs to be modified 508 | @param index The index of the element associated with the popup view 509 | @return The custom popup view to use */ 510 | - (void)lineGraph:(BEMSimpleLineGraphView *)graph modifyPopupView:(UIView *)popupView forIndex:(NSUInteger)index; 511 | 512 | 513 | //----- TOUCH EVENTS -----// 514 | 515 | 516 | /** Sent to the delegate when the user starts touching the graph. The property 'enableTouchReport' must be set to YES. 517 | @param graph The graph object which was touched by the user. 518 | @param index The closest index (X-axis) from the location the user is currently touching. */ 519 | - (void)lineGraph:(BEMSimpleLineGraphView *)graph didTouchGraphWithClosestIndex:(NSInteger)index; 520 | 521 | 522 | /** Sent to the delegate when the user stops touching the graph. 523 | @param graph The graph object which was touched by the user. 524 | @param index The closest index (X-axis) from the location the user last touched. */ 525 | - (void)lineGraph:(BEMSimpleLineGraphView *)graph didReleaseTouchFromGraphWithClosestIndex:(CGFloat)index; 526 | 527 | 528 | //----- X AXIS -----// 529 | 530 | 531 | /** The number of free space between labels on the X-axis to avoid overlapping. 532 | @discussion For example returning '1' would mean that half of the labels on the X-axis are not displayed: the first is not displayed, the second is, the third is not etc. Returning '0' would mean that all of the labels will be displayed. Finally, returning a value equal to the number of labels will only display the first and last label. 533 | @param graph The graph object which is requesting the number of gaps between the labels. 534 | @return The number of labels to "jump" between each displayed label on the X-axis. */ 535 | - (NSInteger)numberOfGapsBetweenLabelsOnLineGraph:(BEMSimpleLineGraphView *)graph; 536 | 537 | 538 | /** The starting index to plot X-Axis values. MUST ALSO IMPLEMENT incrementIndexForXAxisOnLineGraph FOR THIS TO TAKE EFFECT 539 | @discussion This allows you to specify a custom starting index for drawing x axis labels 540 | @param graph The graph object which is requesting the number of gaps between the labels. 541 | @return The graph data index to begin drawing labels */ 542 | - (NSInteger)baseIndexForXAxisOnLineGraph:(BEMSimpleLineGraphView *)graph; 543 | 544 | 545 | /** The increment to apply when drawing X-Axis labels. This increment is applied to the base x axis index. MUST ALSO IMPLEMENT baseIndexForXAxisOnLineGraph FOR THIS TO TAKE EFFECT 546 | @discussion This allows you to set a custom interval in drawing x axis labels. When this is set in conjuction with baseIndexForXAxisOnLineGraph, `numberOfGapsBetweenLabelsOnLineGraph` is ignored 547 | @param graph The graph object which is requesting the number of gaps between the labels. 548 | @return The increment between X-Axis labels */ 549 | - (NSInteger)incrementIndexForXAxisOnLineGraph:(BEMSimpleLineGraphView *)graph; 550 | 551 | 552 | /** An array of graph indices where X-Axis labels should be drawn 553 | @discussion This allows high customization over where X-Axis labels can be placed. They can be placed in non-consistent intervals. Additionally, 554 | it allows you to draw the X-Axis labels based on traits of your data (eg. when the date corresponding to the data becomes a new day). 555 | When this is set, `numberOfGapsBetweenLabelsOnLineGraph` is ignored 556 | @param graph The graph object which is requesting the number of gaps between the labels. 557 | @return Array of graph indices to place X-Axis labels */ 558 | - (NSArray *)incrementPositionsForXAxisOnLineGraph:(BEMSimpleLineGraphView *)graph; 559 | 560 | 561 | 562 | //----- Y AXIS -----// 563 | 564 | 565 | /** The total number of Y-axis labels on the line graph. 566 | @discussion Calculates the total height of the graph and evenly spaces the labels based on the graph height. Default value is 3. 567 | @param graph The graph object which is requesting the number of labels. 568 | @return The number of labels displayed on the Y-axis. */ 569 | - (NSInteger)numberOfYAxisLabelsOnLineGraph:(BEMSimpleLineGraphView *)graph; 570 | 571 | 572 | /** The optional prefix to append to the y axis. 573 | @param graph The graph object requesting the total number of points. 574 | @return The prefix to prepend to append to the y axis. */ 575 | - (NSString *)yAxisPrefixOnLineGraph:(BEMSimpleLineGraphView *)graph; 576 | 577 | 578 | /** The optional suffix to append to the y axis. 579 | @param graph The graph object requesting the total number of points. 580 | @return The suffix to prepend to append to the y axis. */ 581 | - (NSString *)yAxisSuffixOnLineGraph:(BEMSimpleLineGraphView *)graph; 582 | 583 | 584 | /** Starting value to begin drawing Y-Axis labels MUST ALSO IMPLEMENT incrementValueForYAxisOnLineGraph FOR THIS TO TAKE EFFECT 585 | @discussion This allows you to finally hone the granularity of the data label. Instead of drawing values like 11.24, 586 | you can lock these values to draw 11.20 to make it more user friendly. When this is set, `numberOfYAxisLabelsOnLineGraph` is ignored. 587 | @param graph The graph object which is requesting the number of gaps between the labels. 588 | @return The base value to draw the first Y-Axis label */ 589 | - (CGFloat)baseValueForYAxisOnLineGraph:(BEMSimpleLineGraphView *)graph; 590 | 591 | 592 | /** Increment value to apply to the base Y-Axis label. MUST ALSO IMPLEMENT baseValueForYAxisOnLineGraph FOR THIS TO TAKE EFFECT 593 | @discussion This value tells the graph the interval to be applied to the base Y-Axis value. This allows you to increment the Y-Axis via user-friendly values rather than values 594 | like 37.17. This let's you enforce that your Y-Axis have values rounded to whatever granularity best fits your data. 595 | @param graph The graph object which is requesting the number of gaps between the labels. 596 | @return The increment value to add to the value returned from `baseValueForYAxisOnLineGraph` for future Y-Axis labels */ 597 | - (CGFloat)incrementValueForYAxisOnLineGraph:(BEMSimpleLineGraphView *)graph; 598 | 599 | 600 | 601 | 602 | //----- DEPRECATED -----// 603 | 604 | 605 | /** \b DEPRECATED. Use \p numberOfPointsInLineGraph: instead. The number of points along the X-axis of the graph. 606 | @warning This method will be removed in the next version with breaking changes. 607 | @deprecated Deprecated in 1.3. Use \p numberOfPointsInLineGraph: instead. 608 | @return Number of points. */ 609 | - (int)numberOfPointsInGraph __deprecated; 610 | 611 | 612 | /** \b DEPRECATED. Use \p lineGraph:valueForPointAtIndex: instead. 613 | @warning This method will be removed in the next version with breaking changes. 614 | @deprecated Deprecated in 1.3. Use \p lineGraph:valueForPointAtIndex: instead. 615 | @param index The index from left to right of a given point (X-axis). The first value for the index is 0. 616 | @return The Y-axis value at a given index. */ 617 | - (float)valueForIndex:(NSInteger)index __deprecated; 618 | 619 | 620 | /** \b DEPRECATED. Use \p lineGraph:didTouchGraphWithClosestIndex: instead. Gets called when the user starts touching the graph. The property 'enableTouchReport' must be set to YES. 621 | @warning This method will be removed in the next version with breaking changes. 622 | @deprecated Deprecated in 1.3. Use \p lineGraph:didTouchGraphWithClosestIndex: instead. 623 | @param index The closest index (X-axis) from the location the user is currently touching. */ 624 | - (void)didTouchGraphWithClosestIndex:(int)index __deprecated; 625 | 626 | 627 | /** \b DEPRECATED. Use \p lineGraph:didReleaseTouchFromGraphWithClosestIndex: instead. Gets called when the user stops touching the graph. 628 | @warning This method will be removed in the next version with breaking changes. 629 | @deprecated Deprecated in 1.3. Use \p lineGraph:didReleaseTouchFromGraphWithClosestIndex: instead. 630 | @param index The closest index (X-axis) from the location the user last touched. */ 631 | - (void)didReleaseGraphWithClosestIndex:(float)index __deprecated; 632 | 633 | 634 | /** \b DEPRECATED. Use \p numberOfGapsBetweenLabelsOnLineGraph: instead. The number of free space between labels on the X-axis to avoid overlapping. 635 | @warning This method will be removed in the next version with breaking changes. 636 | @deprecated Deprecated in 1.3. Use \p numberOfGapsBetweenLabelsOnLineGraph: instead. 637 | @discussion For example returning '1' would mean that half of the labels on the X-axis are not displayed: the first is not displayed, the second is, the third is not etc. Returning '0' would mean that all of the labels will be displayed. Finally, returning a value equal to the number of labels will only display the first and last label. 638 | @return The number of labels to "jump" between each displayed label on the X-axis. */ 639 | - (int)numberOfGapsBetweenLabels __deprecated; 640 | 641 | 642 | /** \b DEPRECATED. Use \p lineGraph:labelOnXAxisForIndex: instead. The string to display on the label on the X-axis at a given index. Please note that the number of strings to be returned should be equal to the number of points in the Graph. 643 | @warning This method will be removed in the next version with breaking changes. 644 | @deprecated Deprecated in 1.3. Use \p lineGraph:labelOnXAxisForIndex: instead. 645 | @param index The index from left to right of a given label on the X-axis. Is the same index as the one for the points. The first value for the index is 0. */ 646 | - (NSString *)labelOnXAxisForIndex:(NSInteger)index __deprecated; 647 | 648 | 649 | /** \b DEPRECATED. No longer available on \p BEMSimpleLineGraphDelegate. Implement this method on \p BEMSimpleLineGraphDataSource instead. The number of points along the X-axis of the graph. 650 | @deprecated Deprecated in 2.3. Implement with \p BEMSimpleLineGraphDataSource instead. 651 | @param graph The graph object requesting the total number of points. 652 | @return The total number of points in the line graph. */ 653 | - (NSInteger)numberOfPointsInLineGraph:(BEMSimpleLineGraphView *)graph __unavailable __deprecated; 654 | 655 | 656 | /** \b DEPRECATED. No longer available on \p BEMSimpleLineGraphDelegate. Implement this method on \p BEMSimpleLineGraphDataSource instead. The vertical position for a point at the given index. It corresponds to the Y-axis value of the Graph. 657 | @deprecated Deprecated in 2.3. Implement with \p BEMSimpleLineGraphDataSource instead. 658 | 659 | @param graph The graph object requesting the point value. 660 | @param index The index from left to right of a given point (X-axis). The first value for the index is 0. 661 | @return The Y-axis value at a given index. */ 662 | - (CGFloat)lineGraph:(BEMSimpleLineGraphView *)graph valueForPointAtIndex:(NSInteger)index __unavailable __deprecated; 663 | 664 | 665 | /** \b DEPRECATED. No longer available on \p BEMSimpleLineGraphDelegate. Implement this method on \p BEMSimpleLineGraphDataSource instead. The string to display on the label on the X-axis at a given index. Please note that the number of strings to be returned should be equal to the number of points in the Graph. 666 | @deprecated Deprecated in 2.3. Implement with \p BEMSimpleLineGraphDataSource instead. 667 | 668 | @param graph The graph object which is requesting the label on the specified X-Axis position. 669 | @param index The index from left to right of a given label on the X-axis. Is the same index as the one for the points. The first value for the index is 0. */ 670 | - (NSString *)lineGraph:(BEMSimpleLineGraphView *)graph labelOnXAxisForIndex:(NSInteger)index __unavailable __deprecated; 671 | 672 | 673 | NS_ASSUME_NONNULL_END 674 | 675 | @end 676 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2019 Boris Emorine & Sam Spencer. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # BEMSimpleLineGraph 2 | [![Build Status](https://travis-ci.org/Boris-Em/BEMSimpleLineGraph.svg?branch=master)](https://travis-ci.org/Boris-Em/BEMSimpleLineGraph) 3 | [![Version](https://img.shields.io/cocoapods/v/BEMSimpleLineGraph.svg?style=flat)](http://cocoadocs.org/docsets/BEMSimpleLineGraph) 4 | [![License](https://img.shields.io/cocoapods/l/BEMSimpleLineGraph.svg?style=flat)](http://cocoadocs.org/docsets/BEMSimpleLineGraph) 5 | [![Platform](https://img.shields.io/cocoapods/p/BEMSimpleLineGraph.svg?style=flat)](http://cocoadocs.org/docsets/BEMSimpleLineGraph) 6 |

7 | 8 |

9 |

10 | 11 |

12 | BEMSimpleLineGraph makes it easy to create and customize line graphs for iOS. 13 |

14 | 15 | **BEMSimpleLineGraph** is a charting library that makes it easy to create beautiful line graphs for iOS. It is easy to set-up and to use in any iOS Project. It's focused on highly customizable and interactive line graphs. Plus, it is lightweight and can be integrated in minutes (maybe even seconds). 16 | 17 | **BEMSimpleLineGraph's** implementation, data source, and delegate are all modeled off of UITableView and UICollectionView. If you're familiar with using a UITableView, UITableViewController, or UICollectionView, using BEMSimpleLineGraph should be a breeze! 18 | 19 | The full documentation of the project is available on its [wiki](https://github.com/Boris-Em/BEMSimpleLineGraph/wiki). 20 | 21 | ## Table of Contents 22 | 23 | * [**Project Details**](#project-details) 24 | * [Requirements](#requirements) 25 | * [License](#license) 26 | * [Support](#support) 27 | * [Sample App](#sample-app) 28 | * [Apps Using This Project](#apps-using-this-project) 29 | * [**Getting Started**](#getting-started) 30 | * [Installation](#installation) 31 | * [Setup](#setup) 32 | * [**Documentation**](#documentation) 33 | * [Full documentation (wiki)](https://github.com/Boris-Em/BEMSimpleLineGraph/wiki) 34 | * [Required Delegate / Data Source Methods](#required-delegate--data-source-methods) 35 | * [Reloading the Data Source](#reloading-the-data-source) 36 | * [Bezier Curves](#bezier-curves) 37 | * [Interactive Graph](#interactive-graph) 38 | * [Properties](#properties) 39 | 40 | ## Project Details 41 | Learn more about the **BEMSimpleLineGraph** project requirements, licensing, and contributions. 42 | 43 | ### Requirements 44 | *See the full article on the wiki [here](https://github.com/Boris-Em/BEMSimpleLineGraph/wiki/Requirements).* 45 | 46 | - Requires iOS 7 or later. The sample project is optimized for iOS 8. 47 | - Requires Automatic Reference Counting (ARC). 48 | - Optimized for ARM64 Architecture 49 | 50 | Requires Xcode 6 for use in any iOS Project. Requires a minimum of iOS 7.0 as the deployment target. 51 | 52 | | Current Build Target | Earliest Supported Build Target | Earliest Compatible Build Target | 53 | |:--------------------: |:-------------------------------: |:--------------------------------: | 54 | | iOS 8.0 | iOS 7.0 | iOS 6.1 | 55 | | Xcode 6.3 | Xcode 6.1.1 | Xcode 6.0 | 56 | | LLVM 6.1 | LLVM 6.1 | LLVM 5.0 | 57 | 58 | > REQUIREMENTS NOTE 59 | *Supported* means that the library has been tested with this version. *Compatible* means that the library should work on this OS version (i.e. it doesn't rely on any unavailable SDK features) but is no longer being tested for compatibility and may require tweaking or bug fixes to run correctly. 60 | 61 | ### License 62 | See the [License](https://github.com/Boris-Em/BEMSimpleLineGraph/blob/master/LICENSE). You are free to make changes and use this in either personal or commercial projects. Attribution is not required, but it is appreciated. A little Thanks! (or something to that affect) would be much appreciated. If you use BEMSimpleLineGraph in your app, let us know. 63 | 64 | ### Support 65 | [![Gitter chat](https://badges.gitter.im/Boris-Em/BEMSimpleLineGraph.png)](https://gitter.im/Boris-Em/BEMSimpleLineGraph) 66 | Join us on [Gitter](https://gitter.im/Boris-Em/BEMSimpleLineGraph) if you need any help or want to talk about the project. 67 | 68 | Ask questions and get answers from a massive community or programmers on StackOverflow when you use the [BEMSimpleLineGraph tag](http://stackoverflow.com/questions/tagged/bemsimplelinegraph). 69 | 70 | ### Sample App 71 | The iOS Sample App included with this project demonstrates how to correctly setup and use BEMSimpleLineGraph. You can refer to the sample app for an understanding of how to use and setup BEMSimpleLineGraph. 72 | 73 | ### Apps Using This Project 74 | Dozens of production apps available on the iOS App Store use **BEMSimpleLineGraph**. You can view a full list of the [known App Store apps using this project on the wiki](https://github.com/Boris-Em/BEMSimpleLineGraph/wiki/Apps-Using-This-Project), read their descriptions, get links, pricing, featured status, and screenshots of graph usage. 75 | 76 | Add your **BEMSimpleLineGraph** app to the wiki page for a chance to get showcased in the Readme and / or the wiki. We can't wait to see what you create with **BEMSimpleLineGraph**. 77 | 78 | ## Getting Started 79 | *See the full article on the wiki [here](https://github.com/Boris-Em/BEMSimpleLineGraph/wiki/Getting-Started).* 80 | 81 | **BEMSimpleLineGraph** can be added to any project (big or small) in a matter of minutes (maybe even seconds if you're super speedy). CocoaPods is fully supported, and so are all the latest technologies (eg. ARC, Storyboards, Interface Builder Attributes, Modules, and more). 82 | 83 | ### Installation 84 | The easiest way to install BEMSimpleLineGraph is to use CocoaPods. To do so, simply add the following line to your `Podfile`: 85 |
pod 'BEMSimpleLineGraph'
86 | 87 | The other way to install **BEMSimpleLineGraph**, is to drag and drop the *Classes* folder into your Xcode project. When you do so, check the "*Copy items into destination group's folder*" box. 88 | 89 | #### Swift Projects 90 | To use **BEMSimpleLineGraph** in a Swift project add the following to your bridging header: 91 | 92 | #import "BEMSimpleLineGraphView.h" 93 | 94 | ### Setup 95 | Setting up **BEMSimpleLineGraph** in your project is simple. If you're familiar with UITableView, then **BEMSimpleLineGraph **should be a breeze. Follow the steps below to get everything up and running. 96 | 97 | 1. Import `"BEMSimpleLineGraphView.h"` to the header of your view controller: 98 | 99 | #import "BEMSimpleLineGraphView.h" 100 | 101 | 2. Implement the `BEMSimpleLineGraphDelegate` and `BEMSimpleLineGraphDataSource` in the same view controller: 102 | 103 | @interface YourViewController : UIViewController 104 | 105 | 3. BEMSimpleLineGraphView can be initialized in one of two ways. You can either add it directly to your interface (storyboard file) OR through code. Both ways provide the same initialization, just different ways to do the same thing. Use the method that makes sense for your app or project. 106 | 107 | **Interface Initialization** 108 | 1 - Add a UIView to your UIViewController 109 | 2 - Change the class type of the UIView to `BEMSimpleLineGraphView` 110 | 3 - Link the view to your code using an `IBOutlet`. You can set the property to `weak` and `nonatomic`. 111 | 4 - Select the `BEMSimpleLineGraphView` in your interface. Connect the **dataSource** property and then the **delegate** property to your ViewController. 112 | 5 - Select the `BEMSimpleLineGraphView` and open the Attributes Inspector. Most of the line graph's customizable properties can easily be set from the Attributes Inspector. The Sample App demonstrates this capability. Note that graph data will not be loaded in Interface Builder. 113 | 114 | **Code Initialization** 115 | Just add the following code to your implementation (usually the `viewDidLoad` method). 116 | 117 | BEMSimpleLineGraphView *myGraph = [[BEMSimpleLineGraphView alloc] initWithFrame:CGRectMake(0, 0, 320, 200)]; 118 | myGraph.dataSource = self; 119 | myGraph.delegate = self; 120 | [self.view addSubview:myGraph]; 121 | 122 | 4. Implement the two required data source methods: `numberOfPointsInLineGraph:` and `lineGraph:valueForPointAtIndex:`. See documentation below for more information 123 | 124 | ## Documentation 125 | The essential parts of **BEMSimpleLineGraph** are documented below. For full documentation, see the [wiki](https://github.com/Boris-Em/BEMSimpleLineGraph/wiki). Documentation is available directly within Xcode (just Option-Click any method for Quick Help). 126 | 127 | ### Required Delegate / Data Source Methods 128 | 129 | **Number of Points in Graph** 130 | Returns the number of points in the line graph. The line graph gets the value returned by this method from its data source and caches it. 131 | 132 | - (NSInteger)numberOfPointsInLineGraph:(BEMSimpleLineGraphView *)graph { 133 | return X; // Number of points in the graph. 134 | } 135 | 136 | **Value for Point at Index** 137 | Informs the position of each point on the Y-Axis at a given index. This method is called for every point specified in the `numberOfPointsInLineGraph:` method. The parameter `index` is the position from left to right of the point on the X-Axis: 138 | 139 | - (CGFloat)lineGraph:(BEMSimpleLineGraphView *)graph valueForPointAtIndex:(NSInteger)index { 140 | return …; // The value of the point on the Y-Axis for the index. 141 | } 142 | 143 | ### Reloading the Data Source 144 | Similar to a UITableView's `reloadData` method, BEMSimpleLineGraph has a `reloadGraph` method. Call this method to reload all the data that is used to construct the graph, including points, axis, index arrays, colors, alphas, and so on. Calling this method will cause the line graph to call `layoutSubviews` on itself. The line graph will also call all of its data source and delegate methods again (to get the updated data). 145 | 146 | - (void)anyMethodInYourOwnController { 147 | // Change graph properties 148 | // Update data source / arrays 149 | 150 | // Reload the graph 151 | [self.myGraph reloadGraph]; 152 | } 153 | 154 | ### Interactive Graph 155 | **BEMSimpleLineGraph** can react to the user touching the graph by two different ways: **Popup Reporting** and **Touch Reporting**. 156 | 157 |

158 |

On this example, both Popup Reporting and Touch Reporting are activated.

159 | 160 | ### Bezier Curves 161 | 162 | 163 | **BEMSimpleLineGraph** can be drawn with curved lines instead of directly connecting the dots with straight lines. 164 | To do so, set the property `enableBezierCurve` to YES. 165 | 166 | self.myGraph.enableBezierCurve = YES; 167 | 168 | ### Properties 169 | **BEMSimpleLineGraphs** can be customized by using various properties. A multitude of properties let you control the animation, colors, and alpha of the graph. Many of these properties can be set from Interface Build and the Attributes Inspector, others must be set in code. 170 | 171 | ## Contributing 172 | To contribute to **BEMSimpleLineGraph** please see the `CONTRIBUTING.md` file, which lays out exactly how you can contribute to this project. 173 | -------------------------------------------------------------------------------- /Sample Project/SimpleLineChart.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 8AB8D62F1A7ABDF600FC4AEC /* BEMPermanentPopupView.m in Sources */ = {isa = PBXBuildFile; fileRef = 8AB8D62E1A7ABDF600FC4AEC /* BEMPermanentPopupView.m */; }; 11 | 99B15643187B412400B24591 /* StatsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 99B15642187B412400B24591 /* StatsViewController.m */; }; 12 | 99B3FA3A1877898B00539A7B /* LICENSE in Resources */ = {isa = PBXBuildFile; fileRef = 99B3FA381877898B00539A7B /* LICENSE */; }; 13 | 99B3FA3B1877898B00539A7B /* README.md in Resources */ = {isa = PBXBuildFile; fileRef = 99B3FA391877898B00539A7B /* README.md */; }; 14 | A63990B51AD4923900B14D88 /* BEMAverageLine.m in Sources */ = {isa = PBXBuildFile; fileRef = A63990B41AD4923900B14D88 /* BEMAverageLine.m */; }; 15 | A64594521BAB257B00D6B8FD /* Launch Screen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = A64594501BAB257B00D6B8FD /* Launch Screen.storyboard */; }; 16 | C3B90A5F187D15F7003E407D /* BEMCircle.m in Sources */ = {isa = PBXBuildFile; fileRef = C3B90A59187D15F7003E407D /* BEMCircle.m */; }; 17 | C3B90A60187D15F7003E407D /* BEMLine.m in Sources */ = {isa = PBXBuildFile; fileRef = C3B90A5B187D15F7003E407D /* BEMLine.m */; }; 18 | C3B90A61187D15F7003E407D /* BEMSimpleLineGraphView.m in Sources */ = {isa = PBXBuildFile; fileRef = C3B90A5D187D15F7003E407D /* BEMSimpleLineGraphView.m */; }; 19 | C3BCA7E71B8ECCA6007E6090 /* CustomizationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = C3BCA7E61B8ECCA6007E6090 /* CustomizationTests.m */; }; 20 | C3DC80671903845D0080FF06 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = C3FD816A186DFD9A00FD8ED3 /* Main.storyboard */; }; 21 | C3FD8159186DFD9A00FD8ED3 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C3FD8158186DFD9A00FD8ED3 /* Foundation.framework */; }; 22 | C3FD815B186DFD9A00FD8ED3 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C3FD815A186DFD9A00FD8ED3 /* CoreGraphics.framework */; }; 23 | C3FD815D186DFD9A00FD8ED3 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C3FD815C186DFD9A00FD8ED3 /* UIKit.framework */; }; 24 | C3FD8163186DFD9A00FD8ED3 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = C3FD8161186DFD9A00FD8ED3 /* InfoPlist.strings */; }; 25 | C3FD8165186DFD9A00FD8ED3 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = C3FD8164186DFD9A00FD8ED3 /* main.m */; }; 26 | C3FD8169186DFD9A00FD8ED3 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = C3FD8168186DFD9A00FD8ED3 /* AppDelegate.m */; }; 27 | C3FD816F186DFD9A00FD8ED3 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = C3FD816E186DFD9A00FD8ED3 /* ViewController.m */; }; 28 | C3FD8171186DFD9A00FD8ED3 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C3FD8170186DFD9A00FD8ED3 /* Images.xcassets */; }; 29 | C3FD8178186DFD9A00FD8ED3 /* XCTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C3FD8177186DFD9A00FD8ED3 /* XCTest.framework */; }; 30 | C3FD8179186DFD9A00FD8ED3 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C3FD8158186DFD9A00FD8ED3 /* Foundation.framework */; }; 31 | C3FD817A186DFD9A00FD8ED3 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C3FD815C186DFD9A00FD8ED3 /* UIKit.framework */; }; 32 | C3FD8182186DFD9A00FD8ED3 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = C3FD8180186DFD9A00FD8ED3 /* InfoPlist.strings */; }; 33 | C3FD8184186DFD9A00FD8ED3 /* SimpleLineChartTests.m in Sources */ = {isa = PBXBuildFile; fileRef = C3FD8183186DFD9A00FD8ED3 /* SimpleLineChartTests.m */; }; 34 | /* End PBXBuildFile section */ 35 | 36 | /* Begin PBXContainerItemProxy section */ 37 | C3FD817B186DFD9A00FD8ED3 /* PBXContainerItemProxy */ = { 38 | isa = PBXContainerItemProxy; 39 | containerPortal = C3FD814D186DFD9A00FD8ED3 /* Project object */; 40 | proxyType = 1; 41 | remoteGlobalIDString = C3FD8154186DFD9A00FD8ED3; 42 | remoteInfo = SimpleLineChart; 43 | }; 44 | /* End PBXContainerItemProxy section */ 45 | 46 | /* Begin PBXFileReference section */ 47 | 8AB8D62D1A7ABDF600FC4AEC /* BEMPermanentPopupView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BEMPermanentPopupView.h; sourceTree = ""; }; 48 | 8AB8D62E1A7ABDF600FC4AEC /* BEMPermanentPopupView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BEMPermanentPopupView.m; sourceTree = ""; }; 49 | 99B15641187B412400B24591 /* StatsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StatsViewController.h; sourceTree = ""; }; 50 | 99B15642187B412400B24591 /* StatsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = StatsViewController.m; sourceTree = ""; }; 51 | 99B3FA381877898B00539A7B /* LICENSE */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = LICENSE; path = ../LICENSE; sourceTree = ""; }; 52 | 99B3FA391877898B00539A7B /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = README.md; path = ../README.md; sourceTree = ""; }; 53 | A63990B31AD4923900B14D88 /* BEMAverageLine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BEMAverageLine.h; sourceTree = ""; }; 54 | A63990B41AD4923900B14D88 /* BEMAverageLine.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BEMAverageLine.m; sourceTree = ""; }; 55 | A64594511BAB257B00D6B8FD /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = "Base.lproj/Launch Screen.storyboard"; sourceTree = ""; }; 56 | C3B90A58187D15F7003E407D /* BEMCircle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BEMCircle.h; sourceTree = ""; }; 57 | C3B90A59187D15F7003E407D /* BEMCircle.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BEMCircle.m; sourceTree = ""; }; 58 | C3B90A5A187D15F7003E407D /* BEMLine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BEMLine.h; sourceTree = ""; }; 59 | C3B90A5B187D15F7003E407D /* BEMLine.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BEMLine.m; sourceTree = ""; }; 60 | C3B90A5C187D15F7003E407D /* BEMSimpleLineGraphView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BEMSimpleLineGraphView.h; sourceTree = ""; }; 61 | C3B90A5D187D15F7003E407D /* BEMSimpleLineGraphView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BEMSimpleLineGraphView.m; sourceTree = ""; }; 62 | C3BCA7E61B8ECCA6007E6090 /* CustomizationTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CustomizationTests.m; sourceTree = ""; }; 63 | C3BCA7E81B8ECE4E007E6090 /* contantsTests.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = contantsTests.h; sourceTree = ""; }; 64 | C3FD8155186DFD9A00FD8ED3 /* SimpleLineChart.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SimpleLineChart.app; sourceTree = BUILT_PRODUCTS_DIR; }; 65 | C3FD8158186DFD9A00FD8ED3 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 66 | C3FD815A186DFD9A00FD8ED3 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; 67 | C3FD815C186DFD9A00FD8ED3 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 68 | C3FD8160186DFD9A00FD8ED3 /* SimpleLineChart-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "SimpleLineChart-Info.plist"; sourceTree = ""; }; 69 | C3FD8162186DFD9A00FD8ED3 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 70 | C3FD8164186DFD9A00FD8ED3 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 71 | C3FD8166186DFD9A00FD8ED3 /* SimpleLineChart-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "SimpleLineChart-Prefix.pch"; sourceTree = ""; }; 72 | C3FD8167186DFD9A00FD8ED3 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 73 | C3FD8168186DFD9A00FD8ED3 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 74 | C3FD816B186DFD9A00FD8ED3 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 75 | C3FD816D186DFD9A00FD8ED3 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 76 | C3FD816E186DFD9A00FD8ED3 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 77 | C3FD8170186DFD9A00FD8ED3 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 78 | C3FD8176186DFD9A00FD8ED3 /* SimpleLineChartTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SimpleLineChartTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 79 | C3FD8177186DFD9A00FD8ED3 /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; }; 80 | C3FD817F186DFD9A00FD8ED3 /* SimpleLineChartTests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "SimpleLineChartTests-Info.plist"; sourceTree = ""; }; 81 | C3FD8181186DFD9A00FD8ED3 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 82 | C3FD8183186DFD9A00FD8ED3 /* SimpleLineChartTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SimpleLineChartTests.m; sourceTree = ""; }; 83 | /* End PBXFileReference section */ 84 | 85 | /* Begin PBXFrameworksBuildPhase section */ 86 | C3FD8152186DFD9A00FD8ED3 /* Frameworks */ = { 87 | isa = PBXFrameworksBuildPhase; 88 | buildActionMask = 2147483647; 89 | files = ( 90 | C3FD815B186DFD9A00FD8ED3 /* CoreGraphics.framework in Frameworks */, 91 | C3FD815D186DFD9A00FD8ED3 /* UIKit.framework in Frameworks */, 92 | C3FD8159186DFD9A00FD8ED3 /* Foundation.framework in Frameworks */, 93 | ); 94 | runOnlyForDeploymentPostprocessing = 0; 95 | }; 96 | C3FD8173186DFD9A00FD8ED3 /* Frameworks */ = { 97 | isa = PBXFrameworksBuildPhase; 98 | buildActionMask = 2147483647; 99 | files = ( 100 | C3FD8178186DFD9A00FD8ED3 /* XCTest.framework in Frameworks */, 101 | C3FD817A186DFD9A00FD8ED3 /* UIKit.framework in Frameworks */, 102 | C3FD8179186DFD9A00FD8ED3 /* Foundation.framework in Frameworks */, 103 | ); 104 | runOnlyForDeploymentPostprocessing = 0; 105 | }; 106 | /* End PBXFrameworksBuildPhase section */ 107 | 108 | /* Begin PBXGroup section */ 109 | C3B90A55187D15F7003E407D /* Classes */ = { 110 | isa = PBXGroup; 111 | children = ( 112 | C3B90A5C187D15F7003E407D /* BEMSimpleLineGraphView.h */, 113 | C3B90A5D187D15F7003E407D /* BEMSimpleLineGraphView.m */, 114 | C3B90A58187D15F7003E407D /* BEMCircle.h */, 115 | C3B90A59187D15F7003E407D /* BEMCircle.m */, 116 | C3B90A5A187D15F7003E407D /* BEMLine.h */, 117 | C3B90A5B187D15F7003E407D /* BEMLine.m */, 118 | A63990B31AD4923900B14D88 /* BEMAverageLine.h */, 119 | A63990B41AD4923900B14D88 /* BEMAverageLine.m */, 120 | 8AB8D62D1A7ABDF600FC4AEC /* BEMPermanentPopupView.h */, 121 | 8AB8D62E1A7ABDF600FC4AEC /* BEMPermanentPopupView.m */, 122 | ); 123 | name = Classes; 124 | path = ../Classes; 125 | sourceTree = ""; 126 | }; 127 | C3FD814C186DFD9A00FD8ED3 = { 128 | isa = PBXGroup; 129 | children = ( 130 | 99B3FA381877898B00539A7B /* LICENSE */, 131 | 99B3FA391877898B00539A7B /* README.md */, 132 | C3B90A55187D15F7003E407D /* Classes */, 133 | C3FD815E186DFD9A00FD8ED3 /* SimpleLineChart */, 134 | C3FD817D186DFD9A00FD8ED3 /* SimpleLineChartTests */, 135 | C3FD8157186DFD9A00FD8ED3 /* Frameworks */, 136 | C3FD8156186DFD9A00FD8ED3 /* Products */, 137 | ); 138 | sourceTree = ""; 139 | }; 140 | C3FD8156186DFD9A00FD8ED3 /* Products */ = { 141 | isa = PBXGroup; 142 | children = ( 143 | C3FD8155186DFD9A00FD8ED3 /* SimpleLineChart.app */, 144 | C3FD8176186DFD9A00FD8ED3 /* SimpleLineChartTests.xctest */, 145 | ); 146 | name = Products; 147 | sourceTree = ""; 148 | }; 149 | C3FD8157186DFD9A00FD8ED3 /* Frameworks */ = { 150 | isa = PBXGroup; 151 | children = ( 152 | C3FD8158186DFD9A00FD8ED3 /* Foundation.framework */, 153 | C3FD815A186DFD9A00FD8ED3 /* CoreGraphics.framework */, 154 | C3FD815C186DFD9A00FD8ED3 /* UIKit.framework */, 155 | C3FD8177186DFD9A00FD8ED3 /* XCTest.framework */, 156 | ); 157 | name = Frameworks; 158 | sourceTree = ""; 159 | }; 160 | C3FD815E186DFD9A00FD8ED3 /* SimpleLineChart */ = { 161 | isa = PBXGroup; 162 | children = ( 163 | C3FD8167186DFD9A00FD8ED3 /* AppDelegate.h */, 164 | C3FD8168186DFD9A00FD8ED3 /* AppDelegate.m */, 165 | C3FD816A186DFD9A00FD8ED3 /* Main.storyboard */, 166 | C3FD816D186DFD9A00FD8ED3 /* ViewController.h */, 167 | C3FD816E186DFD9A00FD8ED3 /* ViewController.m */, 168 | 99B15641187B412400B24591 /* StatsViewController.h */, 169 | 99B15642187B412400B24591 /* StatsViewController.m */, 170 | C3FD8170186DFD9A00FD8ED3 /* Images.xcassets */, 171 | C3FD815F186DFD9A00FD8ED3 /* Supporting Files */, 172 | ); 173 | path = SimpleLineChart; 174 | sourceTree = ""; 175 | }; 176 | C3FD815F186DFD9A00FD8ED3 /* Supporting Files */ = { 177 | isa = PBXGroup; 178 | children = ( 179 | A64594501BAB257B00D6B8FD /* Launch Screen.storyboard */, 180 | C3FD8160186DFD9A00FD8ED3 /* SimpleLineChart-Info.plist */, 181 | C3FD8161186DFD9A00FD8ED3 /* InfoPlist.strings */, 182 | C3FD8164186DFD9A00FD8ED3 /* main.m */, 183 | C3FD8166186DFD9A00FD8ED3 /* SimpleLineChart-Prefix.pch */, 184 | ); 185 | name = "Supporting Files"; 186 | sourceTree = ""; 187 | }; 188 | C3FD817D186DFD9A00FD8ED3 /* SimpleLineChartTests */ = { 189 | isa = PBXGroup; 190 | children = ( 191 | C3BCA7E61B8ECCA6007E6090 /* CustomizationTests.m */, 192 | C3FD8183186DFD9A00FD8ED3 /* SimpleLineChartTests.m */, 193 | C3BCA7E81B8ECE4E007E6090 /* contantsTests.h */, 194 | C3FD817E186DFD9A00FD8ED3 /* Supporting Files */, 195 | ); 196 | path = SimpleLineChartTests; 197 | sourceTree = ""; 198 | }; 199 | C3FD817E186DFD9A00FD8ED3 /* Supporting Files */ = { 200 | isa = PBXGroup; 201 | children = ( 202 | C3FD817F186DFD9A00FD8ED3 /* SimpleLineChartTests-Info.plist */, 203 | C3FD8180186DFD9A00FD8ED3 /* InfoPlist.strings */, 204 | ); 205 | name = "Supporting Files"; 206 | sourceTree = ""; 207 | }; 208 | /* End PBXGroup section */ 209 | 210 | /* Begin PBXNativeTarget section */ 211 | C3FD8154186DFD9A00FD8ED3 /* SimpleLineChart */ = { 212 | isa = PBXNativeTarget; 213 | buildConfigurationList = C3FD8187186DFD9A00FD8ED3 /* Build configuration list for PBXNativeTarget "SimpleLineChart" */; 214 | buildPhases = ( 215 | C3FD8151186DFD9A00FD8ED3 /* Sources */, 216 | C3FD8152186DFD9A00FD8ED3 /* Frameworks */, 217 | C3FD8153186DFD9A00FD8ED3 /* Resources */, 218 | ); 219 | buildRules = ( 220 | ); 221 | dependencies = ( 222 | ); 223 | name = SimpleLineChart; 224 | productName = SimpleLineChart; 225 | productReference = C3FD8155186DFD9A00FD8ED3 /* SimpleLineChart.app */; 226 | productType = "com.apple.product-type.application"; 227 | }; 228 | C3FD8175186DFD9A00FD8ED3 /* SimpleLineChartTests */ = { 229 | isa = PBXNativeTarget; 230 | buildConfigurationList = C3FD818A186DFD9A00FD8ED3 /* Build configuration list for PBXNativeTarget "SimpleLineChartTests" */; 231 | buildPhases = ( 232 | C3FD8172186DFD9A00FD8ED3 /* Sources */, 233 | C3FD8173186DFD9A00FD8ED3 /* Frameworks */, 234 | C3FD8174186DFD9A00FD8ED3 /* Resources */, 235 | ); 236 | buildRules = ( 237 | ); 238 | dependencies = ( 239 | C3FD817C186DFD9A00FD8ED3 /* PBXTargetDependency */, 240 | ); 241 | name = SimpleLineChartTests; 242 | productName = SimpleLineChartTests; 243 | productReference = C3FD8176186DFD9A00FD8ED3 /* SimpleLineChartTests.xctest */; 244 | productType = "com.apple.product-type.bundle.unit-test"; 245 | }; 246 | /* End PBXNativeTarget section */ 247 | 248 | /* Begin PBXProject section */ 249 | C3FD814D186DFD9A00FD8ED3 /* Project object */ = { 250 | isa = PBXProject; 251 | attributes = { 252 | LastUpgradeCheck = 0800; 253 | ORGANIZATIONNAME = "Boris Emorine"; 254 | TargetAttributes = { 255 | C3FD8175186DFD9A00FD8ED3 = { 256 | TestTargetID = C3FD8154186DFD9A00FD8ED3; 257 | }; 258 | }; 259 | }; 260 | buildConfigurationList = C3FD8150186DFD9A00FD8ED3 /* Build configuration list for PBXProject "SimpleLineChart" */; 261 | compatibilityVersion = "Xcode 3.2"; 262 | developmentRegion = English; 263 | hasScannedForEncodings = 0; 264 | knownRegions = ( 265 | en, 266 | Base, 267 | ); 268 | mainGroup = C3FD814C186DFD9A00FD8ED3; 269 | productRefGroup = C3FD8156186DFD9A00FD8ED3 /* Products */; 270 | projectDirPath = ""; 271 | projectRoot = ""; 272 | targets = ( 273 | C3FD8154186DFD9A00FD8ED3 /* SimpleLineChart */, 274 | C3FD8175186DFD9A00FD8ED3 /* SimpleLineChartTests */, 275 | ); 276 | }; 277 | /* End PBXProject section */ 278 | 279 | /* Begin PBXResourcesBuildPhase section */ 280 | C3FD8153186DFD9A00FD8ED3 /* Resources */ = { 281 | isa = PBXResourcesBuildPhase; 282 | buildActionMask = 2147483647; 283 | files = ( 284 | A64594521BAB257B00D6B8FD /* Launch Screen.storyboard in Resources */, 285 | 99B3FA3A1877898B00539A7B /* LICENSE in Resources */, 286 | C3DC80671903845D0080FF06 /* Main.storyboard in Resources */, 287 | C3FD8171186DFD9A00FD8ED3 /* Images.xcassets in Resources */, 288 | 99B3FA3B1877898B00539A7B /* README.md in Resources */, 289 | C3FD8163186DFD9A00FD8ED3 /* InfoPlist.strings in Resources */, 290 | ); 291 | runOnlyForDeploymentPostprocessing = 0; 292 | }; 293 | C3FD8174186DFD9A00FD8ED3 /* Resources */ = { 294 | isa = PBXResourcesBuildPhase; 295 | buildActionMask = 2147483647; 296 | files = ( 297 | C3FD8182186DFD9A00FD8ED3 /* InfoPlist.strings in Resources */, 298 | ); 299 | runOnlyForDeploymentPostprocessing = 0; 300 | }; 301 | /* End PBXResourcesBuildPhase section */ 302 | 303 | /* Begin PBXSourcesBuildPhase section */ 304 | C3FD8151186DFD9A00FD8ED3 /* Sources */ = { 305 | isa = PBXSourcesBuildPhase; 306 | buildActionMask = 2147483647; 307 | files = ( 308 | C3B90A61187D15F7003E407D /* BEMSimpleLineGraphView.m in Sources */, 309 | C3B90A5F187D15F7003E407D /* BEMCircle.m in Sources */, 310 | C3FD816F186DFD9A00FD8ED3 /* ViewController.m in Sources */, 311 | C3B90A60187D15F7003E407D /* BEMLine.m in Sources */, 312 | 8AB8D62F1A7ABDF600FC4AEC /* BEMPermanentPopupView.m in Sources */, 313 | C3FD8169186DFD9A00FD8ED3 /* AppDelegate.m in Sources */, 314 | 99B15643187B412400B24591 /* StatsViewController.m in Sources */, 315 | A63990B51AD4923900B14D88 /* BEMAverageLine.m in Sources */, 316 | C3FD8165186DFD9A00FD8ED3 /* main.m in Sources */, 317 | ); 318 | runOnlyForDeploymentPostprocessing = 0; 319 | }; 320 | C3FD8172186DFD9A00FD8ED3 /* Sources */ = { 321 | isa = PBXSourcesBuildPhase; 322 | buildActionMask = 2147483647; 323 | files = ( 324 | C3FD8184186DFD9A00FD8ED3 /* SimpleLineChartTests.m in Sources */, 325 | C3BCA7E71B8ECCA6007E6090 /* CustomizationTests.m in Sources */, 326 | ); 327 | runOnlyForDeploymentPostprocessing = 0; 328 | }; 329 | /* End PBXSourcesBuildPhase section */ 330 | 331 | /* Begin PBXTargetDependency section */ 332 | C3FD817C186DFD9A00FD8ED3 /* PBXTargetDependency */ = { 333 | isa = PBXTargetDependency; 334 | target = C3FD8154186DFD9A00FD8ED3 /* SimpleLineChart */; 335 | targetProxy = C3FD817B186DFD9A00FD8ED3 /* PBXContainerItemProxy */; 336 | }; 337 | /* End PBXTargetDependency section */ 338 | 339 | /* Begin PBXVariantGroup section */ 340 | A64594501BAB257B00D6B8FD /* Launch Screen.storyboard */ = { 341 | isa = PBXVariantGroup; 342 | children = ( 343 | A64594511BAB257B00D6B8FD /* Base */, 344 | ); 345 | name = "Launch Screen.storyboard"; 346 | sourceTree = ""; 347 | }; 348 | C3FD8161186DFD9A00FD8ED3 /* InfoPlist.strings */ = { 349 | isa = PBXVariantGroup; 350 | children = ( 351 | C3FD8162186DFD9A00FD8ED3 /* en */, 352 | ); 353 | name = InfoPlist.strings; 354 | sourceTree = ""; 355 | }; 356 | C3FD816A186DFD9A00FD8ED3 /* Main.storyboard */ = { 357 | isa = PBXVariantGroup; 358 | children = ( 359 | C3FD816B186DFD9A00FD8ED3 /* Base */, 360 | ); 361 | name = Main.storyboard; 362 | sourceTree = ""; 363 | }; 364 | C3FD8180186DFD9A00FD8ED3 /* InfoPlist.strings */ = { 365 | isa = PBXVariantGroup; 366 | children = ( 367 | C3FD8181186DFD9A00FD8ED3 /* en */, 368 | ); 369 | name = InfoPlist.strings; 370 | sourceTree = ""; 371 | }; 372 | /* End PBXVariantGroup section */ 373 | 374 | /* Begin XCBuildConfiguration section */ 375 | C3FD8185186DFD9A00FD8ED3 /* Debug */ = { 376 | isa = XCBuildConfiguration; 377 | buildSettings = { 378 | ALWAYS_SEARCH_USER_PATHS = NO; 379 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 380 | CLANG_CXX_LIBRARY = "libc++"; 381 | CLANG_ENABLE_MODULES = YES; 382 | CLANG_ENABLE_OBJC_ARC = YES; 383 | CLANG_WARN_BOOL_CONVERSION = YES; 384 | CLANG_WARN_CONSTANT_CONVERSION = YES; 385 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 386 | CLANG_WARN_EMPTY_BODY = YES; 387 | CLANG_WARN_ENUM_CONVERSION = YES; 388 | CLANG_WARN_INFINITE_RECURSION = YES; 389 | CLANG_WARN_INT_CONVERSION = YES; 390 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 391 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 392 | CLANG_WARN_UNREACHABLE_CODE = YES; 393 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 394 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 395 | COPY_PHASE_STRIP = NO; 396 | ENABLE_STRICT_OBJC_MSGSEND = YES; 397 | ENABLE_TESTABILITY = YES; 398 | GCC_C_LANGUAGE_STANDARD = gnu99; 399 | GCC_DYNAMIC_NO_PIC = NO; 400 | GCC_NO_COMMON_BLOCKS = YES; 401 | GCC_OPTIMIZATION_LEVEL = 0; 402 | GCC_PREPROCESSOR_DEFINITIONS = ( 403 | "DEBUG=1", 404 | "$(inherited)", 405 | ); 406 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 407 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 408 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 409 | GCC_WARN_UNDECLARED_SELECTOR = YES; 410 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 411 | GCC_WARN_UNUSED_FUNCTION = YES; 412 | GCC_WARN_UNUSED_VARIABLE = YES; 413 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 414 | ONLY_ACTIVE_ARCH = YES; 415 | SDKROOT = iphoneos; 416 | }; 417 | name = Debug; 418 | }; 419 | C3FD8186186DFD9A00FD8ED3 /* Release */ = { 420 | isa = XCBuildConfiguration; 421 | buildSettings = { 422 | ALWAYS_SEARCH_USER_PATHS = NO; 423 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 424 | CLANG_CXX_LIBRARY = "libc++"; 425 | CLANG_ENABLE_MODULES = YES; 426 | CLANG_ENABLE_OBJC_ARC = YES; 427 | CLANG_WARN_BOOL_CONVERSION = YES; 428 | CLANG_WARN_CONSTANT_CONVERSION = YES; 429 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 430 | CLANG_WARN_EMPTY_BODY = YES; 431 | CLANG_WARN_ENUM_CONVERSION = YES; 432 | CLANG_WARN_INFINITE_RECURSION = YES; 433 | CLANG_WARN_INT_CONVERSION = YES; 434 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 435 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 436 | CLANG_WARN_UNREACHABLE_CODE = YES; 437 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 438 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 439 | COPY_PHASE_STRIP = YES; 440 | ENABLE_NS_ASSERTIONS = NO; 441 | ENABLE_STRICT_OBJC_MSGSEND = YES; 442 | GCC_C_LANGUAGE_STANDARD = gnu99; 443 | GCC_NO_COMMON_BLOCKS = YES; 444 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 445 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 446 | GCC_WARN_UNDECLARED_SELECTOR = YES; 447 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 448 | GCC_WARN_UNUSED_FUNCTION = YES; 449 | GCC_WARN_UNUSED_VARIABLE = YES; 450 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 451 | SDKROOT = iphoneos; 452 | VALIDATE_PRODUCT = YES; 453 | }; 454 | name = Release; 455 | }; 456 | C3FD8188186DFD9A00FD8ED3 /* Debug */ = { 457 | isa = XCBuildConfiguration; 458 | buildSettings = { 459 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 460 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; 461 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 462 | GCC_PREFIX_HEADER = "SimpleLineChart/SimpleLineChart-Prefix.pch"; 463 | INFOPLIST_FILE = "SimpleLineChart/SimpleLineChart-Info.plist"; 464 | PRODUCT_BUNDLE_IDENTIFIER = "BorisEmorine.${PRODUCT_NAME:rfc1034identifier}"; 465 | PRODUCT_NAME = "$(TARGET_NAME)"; 466 | WRAPPER_EXTENSION = app; 467 | }; 468 | name = Debug; 469 | }; 470 | C3FD8189186DFD9A00FD8ED3 /* Release */ = { 471 | isa = XCBuildConfiguration; 472 | buildSettings = { 473 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 474 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; 475 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 476 | GCC_PREFIX_HEADER = "SimpleLineChart/SimpleLineChart-Prefix.pch"; 477 | INFOPLIST_FILE = "SimpleLineChart/SimpleLineChart-Info.plist"; 478 | PRODUCT_BUNDLE_IDENTIFIER = "BorisEmorine.${PRODUCT_NAME:rfc1034identifier}"; 479 | PRODUCT_NAME = "$(TARGET_NAME)"; 480 | WRAPPER_EXTENSION = app; 481 | }; 482 | name = Release; 483 | }; 484 | C3FD818B186DFD9A00FD8ED3 /* Debug */ = { 485 | isa = XCBuildConfiguration; 486 | buildSettings = { 487 | BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/SimpleLineChart.app/SimpleLineChart"; 488 | FRAMEWORK_SEARCH_PATHS = ""; 489 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 490 | GCC_PREFIX_HEADER = "SimpleLineChart/SimpleLineChart-Prefix.pch"; 491 | GCC_PREPROCESSOR_DEFINITIONS = ( 492 | "DEBUG=1", 493 | "$(inherited)", 494 | ); 495 | INFOPLIST_FILE = "SimpleLineChartTests/SimpleLineChartTests-Info.plist"; 496 | PRODUCT_BUNDLE_IDENTIFIER = "BorisEmorine.${PRODUCT_NAME:rfc1034identifier}"; 497 | PRODUCT_NAME = "$(TARGET_NAME)"; 498 | TEST_HOST = "$(BUNDLE_LOADER)"; 499 | WRAPPER_EXTENSION = xctest; 500 | }; 501 | name = Debug; 502 | }; 503 | C3FD818C186DFD9A00FD8ED3 /* Release */ = { 504 | isa = XCBuildConfiguration; 505 | buildSettings = { 506 | BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/SimpleLineChart.app/SimpleLineChart"; 507 | FRAMEWORK_SEARCH_PATHS = ""; 508 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 509 | GCC_PREFIX_HEADER = "SimpleLineChart/SimpleLineChart-Prefix.pch"; 510 | INFOPLIST_FILE = "SimpleLineChartTests/SimpleLineChartTests-Info.plist"; 511 | PRODUCT_BUNDLE_IDENTIFIER = "BorisEmorine.${PRODUCT_NAME:rfc1034identifier}"; 512 | PRODUCT_NAME = "$(TARGET_NAME)"; 513 | TEST_HOST = "$(BUNDLE_LOADER)"; 514 | WRAPPER_EXTENSION = xctest; 515 | }; 516 | name = Release; 517 | }; 518 | /* End XCBuildConfiguration section */ 519 | 520 | /* Begin XCConfigurationList section */ 521 | C3FD8150186DFD9A00FD8ED3 /* Build configuration list for PBXProject "SimpleLineChart" */ = { 522 | isa = XCConfigurationList; 523 | buildConfigurations = ( 524 | C3FD8185186DFD9A00FD8ED3 /* Debug */, 525 | C3FD8186186DFD9A00FD8ED3 /* Release */, 526 | ); 527 | defaultConfigurationIsVisible = 0; 528 | defaultConfigurationName = Release; 529 | }; 530 | C3FD8187186DFD9A00FD8ED3 /* Build configuration list for PBXNativeTarget "SimpleLineChart" */ = { 531 | isa = XCConfigurationList; 532 | buildConfigurations = ( 533 | C3FD8188186DFD9A00FD8ED3 /* Debug */, 534 | C3FD8189186DFD9A00FD8ED3 /* Release */, 535 | ); 536 | defaultConfigurationIsVisible = 0; 537 | defaultConfigurationName = Release; 538 | }; 539 | C3FD818A186DFD9A00FD8ED3 /* Build configuration list for PBXNativeTarget "SimpleLineChartTests" */ = { 540 | isa = XCConfigurationList; 541 | buildConfigurations = ( 542 | C3FD818B186DFD9A00FD8ED3 /* Debug */, 543 | C3FD818C186DFD9A00FD8ED3 /* Release */, 544 | ); 545 | defaultConfigurationIsVisible = 0; 546 | defaultConfigurationName = Release; 547 | }; 548 | /* End XCConfigurationList section */ 549 | }; 550 | rootObject = C3FD814D186DFD9A00FD8ED3 /* Project object */; 551 | } 552 | -------------------------------------------------------------------------------- /Sample Project/SimpleLineChart.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Sample Project/SimpleLineChart.xcodeproj/project.xcworkspace/xcshareddata/SimpleLineChart.xccheckout: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDESourceControlProjectFavoriteDictionaryKey 6 | 7 | IDESourceControlProjectIdentifier 8 | F1F15B84-6620-4046-8D91-529CC20CD7C2 9 | IDESourceControlProjectName 10 | SimpleLineChart 11 | IDESourceControlProjectOriginsDictionary 12 | 13 | 1CA8AD815677B6FB0DD135F65EC4576AE68426CF 14 | https://github.com/Boris-Em/BEMSimpleLineGraph.git 15 | 3A216D26EB93D9EB79DE1E013DBEF75CF4509620 16 | https://github.dowjones.net/DJMobile/ios-thesituation.git 17 | 18 | IDESourceControlProjectPath 19 | Sample Project/SimpleLineChart.xcodeproj 20 | IDESourceControlProjectRelativeInstallPathDictionary 21 | 22 | 1CA8AD815677B6FB0DD135F65EC4576AE68426CF 23 | ../../.. 24 | 3A216D26EB93D9EB79DE1E013DBEF75CF4509620 25 | ../../../.. 26 | 27 | IDESourceControlProjectURL 28 | https://github.com/Boris-Em/BEMSimpleLineGraph.git 29 | IDESourceControlProjectVersion 30 | 111 31 | IDESourceControlProjectWCCIdentifier 32 | 1CA8AD815677B6FB0DD135F65EC4576AE68426CF 33 | IDESourceControlProjectWCConfigurations 34 | 35 | 36 | IDESourceControlRepositoryExtensionIdentifierKey 37 | public.vcs.git 38 | IDESourceControlWCCIdentifierKey 39 | 3A216D26EB93D9EB79DE1E013DBEF75CF4509620 40 | IDESourceControlWCCName 41 | 42 | 43 | 44 | IDESourceControlRepositoryExtensionIdentifierKey 45 | public.vcs.git 46 | IDESourceControlWCCIdentifierKey 47 | 1CA8AD815677B6FB0DD135F65EC4576AE68426CF 48 | IDESourceControlWCCName 49 | BEMSimpleLineGraph 50 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /Sample Project/SimpleLineChart.xcodeproj/project.xcworkspace/xcshareddata/SimpleLineChart.xcscmblueprint: -------------------------------------------------------------------------------- 1 | { 2 | "DVTSourceControlWorkspaceBlueprintPrimaryRemoteRepositoryKey" : "1CA8AD815677B6FB0DD135F65EC4576AE68426CF", 3 | "DVTSourceControlWorkspaceBlueprintWorkingCopyRepositoryLocationsKey" : { 4 | 5 | }, 6 | "DVTSourceControlWorkspaceBlueprintWorkingCopyStatesKey" : { 7 | "1CA8AD815677B6FB0DD135F65EC4576AE68426CF" : 0, 8 | "3A216D26EB93D9EB79DE1E013DBEF75CF4509620" : 0 9 | }, 10 | "DVTSourceControlWorkspaceBlueprintIdentifierKey" : "F1F15B84-6620-4046-8D91-529CC20CD7C2", 11 | "DVTSourceControlWorkspaceBlueprintWorkingCopyPathsKey" : { 12 | "1CA8AD815677B6FB0DD135F65EC4576AE68426CF" : "BEMSimpleLineGraph\/", 13 | "3A216D26EB93D9EB79DE1E013DBEF75CF4509620" : "" 14 | }, 15 | "DVTSourceControlWorkspaceBlueprintNameKey" : "SimpleLineChart", 16 | "DVTSourceControlWorkspaceBlueprintVersion" : 204, 17 | "DVTSourceControlWorkspaceBlueprintRelativePathToProjectKey" : "Sample Project\/SimpleLineChart.xcodeproj", 18 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoriesKey" : [ 19 | { 20 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/Boris-Em\/BEMSimpleLineGraph.git", 21 | "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git", 22 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "1CA8AD815677B6FB0DD135F65EC4576AE68426CF" 23 | }, 24 | { 25 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.dowjones.net\/DJMobile\/ios-thesituation.git", 26 | "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git", 27 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "3A216D26EB93D9EB79DE1E013DBEF75CF4509620" 28 | } 29 | ] 30 | } -------------------------------------------------------------------------------- /Sample Project/SimpleLineChart.xcodeproj/project.xcworkspace/xcuserdata/Spencers.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Boris-Em/BEMSimpleLineGraph/39ff8048cd5764f26d78b7b24816bf279a49ab98/Sample Project/SimpleLineChart.xcodeproj/project.xcworkspace/xcuserdata/Spencers.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /Sample Project/SimpleLineChart.xcodeproj/project.xcworkspace/xcuserdata/bobo.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Boris-Em/BEMSimpleLineGraph/39ff8048cd5764f26d78b7b24816bf279a49ab98/Sample Project/SimpleLineChart.xcodeproj/project.xcworkspace/xcuserdata/bobo.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /Sample Project/SimpleLineChart.xcodeproj/project.xcworkspace/xcuserdata/bobo.xcuserdatad/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | HasAskedToTakeAutomaticSnapshotBeforeSignificantChanges 6 | 7 | SnapshotAutomaticallyBeforeSignificantChanges 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Sample Project/SimpleLineChart.xcodeproj/xcshareddata/xcbaselines/C3FD8175186DFD9A00FD8ED3.xcbaseline/2C820550-74B3-4FE2-BBBC-50D038B845C0.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | classNames 6 | 7 | SimpleLineGraphTests 8 | 9 | testReloadDataPerformance 10 | 11 | com.apple.XCTPerformanceMetric_WallClockTime 12 | 13 | baselineAverage 14 | 0.017 15 | baselineIntegrationDisplayName 16 | Local Baseline 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /Sample Project/SimpleLineChart.xcodeproj/xcshareddata/xcbaselines/C3FD8175186DFD9A00FD8ED3.xcbaseline/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | runDestinationsByUUID 6 | 7 | 2C820550-74B3-4FE2-BBBC-50D038B845C0 8 | 9 | localComputer 10 | 11 | busSpeedInMHz 12 | 100 13 | cpuCount 14 | 1 15 | cpuKind 16 | Intel Core i5 17 | cpuSpeedInMHz 18 | 2800 19 | logicalCPUCoresPerPackage 20 | 4 21 | modelCode 22 | MacBookPro11,1 23 | physicalCPUCoresPerPackage 24 | 2 25 | platformIdentifier 26 | com.apple.platform.macosx 27 | 28 | targetArchitecture 29 | x86_64 30 | targetDevice 31 | 32 | modelCode 33 | iPhone8,1 34 | platformIdentifier 35 | com.apple.platform.iphonesimulator 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /Sample Project/SimpleLineChart.xcodeproj/xcshareddata/xcschemes/SimpleLineChart.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 49 | 50 | 51 | 52 | 53 | 54 | 64 | 66 | 72 | 73 | 74 | 75 | 79 | 80 | 81 | 82 | 83 | 84 | 90 | 92 | 98 | 99 | 100 | 101 | 103 | 104 | 107 | 108 | 109 | -------------------------------------------------------------------------------- /Sample Project/SimpleLineChart.xcodeproj/xcshareddata/xcschemes/SimpleLineChartTests.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 49 | 50 | 51 | 52 | 53 | 54 | 64 | 65 | 71 | 72 | 73 | 74 | 75 | 76 | 82 | 83 | 89 | 90 | 91 | 92 | 94 | 95 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /Sample Project/SimpleLineChart.xcodeproj/xcuserdata/Spencers.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /Sample Project/SimpleLineChart.xcodeproj/xcuserdata/Spencers.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | SimpleLineChart.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 1 11 | 12 | SimpleLineChartTests.xcscheme_^#shared#^_ 13 | 14 | orderHint 15 | 3 16 | 17 | 18 | SuppressBuildableAutocreation 19 | 20 | C3FD8154186DFD9A00FD8ED3 21 | 22 | primary 23 | 24 | 25 | C3FD8175186DFD9A00FD8ED3 26 | 27 | primary 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /Sample Project/SimpleLineChart.xcodeproj/xcuserdata/bobo.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /Sample Project/SimpleLineChart.xcodeproj/xcuserdata/bobo.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | SimpleLineChart.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | C3FD8154186DFD9A00FD8ED3 16 | 17 | primary 18 | 19 | 20 | C3FD8175186DFD9A00FD8ED3 21 | 22 | primary 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /Sample Project/SimpleLineChart/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // SimpleLineGraph 4 | // 5 | // Created by Bobo on 12/27/13. 6 | // Copyright (c) 2013 Boris Emorine. All rights reserved. 7 | // 8 | 9 | @interface AppDelegate : UIResponder 10 | 11 | @property (strong, nonatomic) UIWindow *window; 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /Sample Project/SimpleLineChart/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // SimpleLineGraph 4 | // 5 | // Created by Bobo on 12/27/13. 6 | // Copyright (c) 2013 Boris Emorine. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | 11 | @implementation AppDelegate 12 | 13 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 14 | // Override point for customization after application launch. 15 | return YES; 16 | } 17 | 18 | - (void)applicationWillResignActive:(UIApplication *)application { 19 | // 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. 20 | // 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. 21 | } 22 | 23 | - (void)applicationDidEnterBackground:(UIApplication *)application { 24 | // 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. 25 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 26 | } 27 | 28 | - (void)applicationWillEnterForeground:(UIApplication *)application { 29 | // 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. 30 | } 31 | 32 | - (void)applicationDidBecomeActive:(UIApplication *)application { 33 | // 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. 34 | } 35 | 36 | - (void)applicationWillTerminate:(UIApplication *)application { 37 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 38 | } 39 | 40 | @end 41 | -------------------------------------------------------------------------------- /Sample Project/SimpleLineChart/Base.lproj/Launch Screen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /Sample Project/SimpleLineChart/Images.xcassets/AppIcon.appiconset/AppIcon29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Boris-Em/BEMSimpleLineGraph/39ff8048cd5764f26d78b7b24816bf279a49ab98/Sample Project/SimpleLineChart/Images.xcassets/AppIcon.appiconset/AppIcon29x29@2x.png -------------------------------------------------------------------------------- /Sample Project/SimpleLineChart/Images.xcassets/AppIcon.appiconset/AppIcon40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Boris-Em/BEMSimpleLineGraph/39ff8048cd5764f26d78b7b24816bf279a49ab98/Sample Project/SimpleLineChart/Images.xcassets/AppIcon.appiconset/AppIcon40x40@2x.png -------------------------------------------------------------------------------- /Sample Project/SimpleLineChart/Images.xcassets/AppIcon.appiconset/AppIcon60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Boris-Em/BEMSimpleLineGraph/39ff8048cd5764f26d78b7b24816bf279a49ab98/Sample Project/SimpleLineChart/Images.xcassets/AppIcon.appiconset/AppIcon60x60@2x.png -------------------------------------------------------------------------------- /Sample Project/SimpleLineChart/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "29x29", 5 | "idiom" : "iphone", 6 | "filename" : "AppIcon29x29@2x.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "40x40", 11 | "idiom" : "iphone", 12 | "filename" : "AppIcon40x40@2x.png", 13 | "scale" : "2x" 14 | }, 15 | { 16 | "size" : "60x60", 17 | "idiom" : "iphone", 18 | "filename" : "AppIcon60x60@2x.png", 19 | "scale" : "2x" 20 | } 21 | ], 22 | "info" : { 23 | "version" : 1, 24 | "author" : "xcode" 25 | } 26 | } -------------------------------------------------------------------------------- /Sample Project/SimpleLineChart/Images.xcassets/LaunchImage.launchimage/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "orientation" : "portrait", 5 | "idiom" : "iphone", 6 | "extent" : "full-screen", 7 | "minimum-system-version" : "7.0", 8 | "scale" : "2x" 9 | }, 10 | { 11 | "orientation" : "portrait", 12 | "idiom" : "iphone", 13 | "subtype" : "retina4", 14 | "extent" : "full-screen", 15 | "minimum-system-version" : "7.0", 16 | "scale" : "2x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } -------------------------------------------------------------------------------- /Sample Project/SimpleLineChart/SimpleLineChart-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | LineChart 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1.0 25 | LSRequiresIPhoneOS 26 | 27 | UILaunchStoryboardName 28 | Launch Screen 29 | UIMainStoryboardFile 30 | Main 31 | UIRequiredDeviceCapabilities 32 | 33 | armv7 34 | 35 | UISupportedInterfaceOrientations 36 | 37 | UIInterfaceOrientationPortrait 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /Sample Project/SimpleLineChart/SimpleLineChart-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header 3 | // 4 | // The contents of this file are implicitly included at the beginning of every source file. 5 | // 6 | 7 | #import 8 | 9 | #ifndef __IPHONE_5_0 10 | #warning "This project uses features only available in iOS SDK 5.0 and later." 11 | #endif 12 | 13 | #ifdef __OBJC__ 14 | @import UIKit; 15 | @import Foundation; 16 | #endif 17 | -------------------------------------------------------------------------------- /Sample Project/SimpleLineChart/StatsViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // StatsViewController.h 3 | // SimpleLineChart 4 | // 5 | // Created by iRare Media on 1/6/14. 6 | // Copyright (c) 2014 Boris Emorine. All rights reserved. 7 | // Copyright (c) 2014 Sam Spencer. 8 | // 9 | 10 | @interface StatsViewController : UITableViewController 11 | 12 | @property (weak, nonatomic) IBOutlet UILabel *standardDeviationLabel; 13 | @property (weak, nonatomic) IBOutlet UILabel *averageLabel; 14 | @property (weak, nonatomic) IBOutlet UILabel *medianLabel; 15 | @property (weak, nonatomic) IBOutlet UILabel *modeLabel; 16 | @property (weak, nonatomic) IBOutlet UILabel *minimumLabel; 17 | @property (weak, nonatomic) IBOutlet UILabel *maximumLabel; 18 | @property (weak, nonatomic) IBOutlet UIImageView *snapshotImageView; 19 | 20 | @property (strong, nonatomic) NSString *standardDeviation; 21 | @property (strong, nonatomic) NSString *average; 22 | @property (strong, nonatomic) NSString *median; 23 | @property (strong, nonatomic) NSString *mode; 24 | @property (strong, nonatomic) NSString *minimum; 25 | @property (strong, nonatomic) NSString *maximum; 26 | @property (strong, nonatomic) UIImage *snapshotImage; 27 | 28 | @end 29 | -------------------------------------------------------------------------------- /Sample Project/SimpleLineChart/StatsViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // StatsViewController.m 3 | // SimpleLineChart 4 | // 5 | // Created by iRare Media on 1/6/14. 6 | // Copyright (c) 2014 Boris Emorine. All rights reserved. 7 | // Copyright (c) 2014 Sam Spencer. 8 | // 9 | 10 | #import "StatsViewController.h" 11 | 12 | @interface StatsViewController () 13 | 14 | @end 15 | 16 | @implementation StatsViewController 17 | @synthesize standardDeviation, average, median, mode, maximum, minimum, snapshotImage; 18 | @synthesize standardDeviationLabel, averageLabel, medianLabel, modeLabel, maximumLabel, minimumLabel, snapshotImageView; 19 | 20 | - (void)viewDidLoad { 21 | [super viewDidLoad]; 22 | // Do any additional setup after loading the view. 23 | } 24 | 25 | - (void)viewWillAppear:(BOOL)animated { 26 | [super viewWillAppear:animated]; 27 | standardDeviationLabel.text = standardDeviation; 28 | averageLabel.text = average; 29 | medianLabel.text = median; 30 | modeLabel.text = mode; 31 | maximumLabel.text = maximum; 32 | minimumLabel.text = minimum; 33 | snapshotImageView.image = snapshotImage; 34 | } 35 | 36 | - (void)didReceiveMemoryWarning { 37 | [super didReceiveMemoryWarning]; 38 | // Dispose of any resources that can be recreated. 39 | } 40 | 41 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 42 | if (section == 0) return 6; 43 | else return 1; 44 | } 45 | 46 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 47 | static NSString *CellIdentifier = @"Cell"; 48 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; 49 | if (cell == nil) cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier]; 50 | 51 | if (indexPath.row == 0 && indexPath.section == 0) { 52 | cell.textLabel.text = standardDeviation; 53 | cell.detailTextLabel.text = @"Standard Deviation"; 54 | return cell; 55 | } else if (indexPath.row == 1) { 56 | cell.textLabel.text = average; 57 | cell.detailTextLabel.text = @"Average"; 58 | return cell; 59 | } else if (indexPath.row == 2) { 60 | cell.textLabel.text = median; 61 | cell.detailTextLabel.text = @"Median"; 62 | return cell; 63 | } else if (indexPath.row == 3) { 64 | cell.textLabel.text = mode; 65 | cell.detailTextLabel.text = @"Mode"; 66 | return cell; 67 | } else if (indexPath.row == 4) { 68 | cell.textLabel.text = maximum; 69 | cell.detailTextLabel.text = @"Maximum Value"; 70 | return cell; 71 | } else if (indexPath.row == 5) { 72 | cell.textLabel.text = minimum; 73 | cell.detailTextLabel.text = @"Minimum Value"; 74 | return cell; 75 | } else if (indexPath.row == 0 && indexPath.section == 1) { 76 | cell.textLabel.text = @"Rendered Snapshot"; 77 | cell.imageView.image = snapshotImage; 78 | return cell; 79 | } else { 80 | NSLog(@"Unknown"); 81 | return cell; 82 | } 83 | } 84 | 85 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { 86 | [self.tableView deselectRowAtIndexPath:indexPath animated:YES]; 87 | } 88 | 89 | @end 90 | -------------------------------------------------------------------------------- /Sample Project/SimpleLineChart/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // SimpleLineGraph 4 | // 5 | // Created by Bobo on 12/27/13. Updated by Sam Spencer on 1/11/14. 6 | // Copyright (c) 2013 Boris Emorine. All rights reserved. 7 | // Copyright (c) 2014 Sam Spencer. 8 | // 9 | 10 | #import "BEMSimpleLineGraphView.h" 11 | #import "StatsViewController.h" 12 | 13 | @interface ViewController : UIViewController 14 | 15 | @property (weak, nonatomic) IBOutlet BEMSimpleLineGraphView *myGraph; 16 | 17 | @property (strong, nonatomic) NSMutableArray *arrayOfValues; 18 | @property (strong, nonatomic) NSMutableArray *arrayOfDates; 19 | 20 | @property (strong, nonatomic) IBOutlet UILabel *labelValues; 21 | @property (strong, nonatomic) IBOutlet UILabel *labelDates; 22 | 23 | @property (weak, nonatomic) IBOutlet UISegmentedControl *graphColorChoice; 24 | @property (strong, nonatomic) IBOutlet UISegmentedControl *curveChoice; 25 | @property (weak, nonatomic) IBOutlet UIStepper *graphObjectIncrement; 26 | 27 | - (IBAction)refresh:(id)sender; 28 | - (IBAction)addOrRemovePointFromGraph:(id)sender; 29 | 30 | - (IBAction)displayStatistics:(id)sender; 31 | 32 | @end -------------------------------------------------------------------------------- /Sample Project/SimpleLineChart/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // SimpleLineGraph 4 | // 5 | // Created by Bobo on 12/27/13. Updated by Sam Spencer on 1/11/14. 6 | // Copyright (c) 2013 Boris Emorine. All rights reserved. 7 | // Copyright (c) 2014 Sam Spencer. 8 | // 9 | 10 | #import "ViewController.h" 11 | 12 | 13 | @interface ViewController () { 14 | int previousStepperValue; 15 | int totalNumber; 16 | } @end 17 | 18 | @implementation ViewController 19 | 20 | #pragma mark - View Lifecycle 21 | 22 | - (void)viewDidLoad { 23 | [super viewDidLoad]; 24 | // Do any additional setup after loading the view, typically from a nib. 25 | 26 | [self hydrateDatasets]; 27 | 28 | /* This is commented out because the graph is created in the interface with this sample app. However, the code remains as an example for creating the graph using code. 29 | BEMSimpleLineGraphView *myGraph = [[BEMSimpleLineGraphView alloc] initWithFrame:CGRectMake(0, 60, 320, 250)]; 30 | myGraph.delegate = self; 31 | myGraph.dataSource = self; 32 | [self.view addSubview:myGraph]; */ 33 | 34 | // Create a gradient to apply to the bottom portion of the graph 35 | CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB(); 36 | size_t num_locations = 2; 37 | CGFloat locations[2] = { 0.0, 1.0 }; 38 | CGFloat components[8] = { 39 | 1.0, 1.0, 1.0, 1.0, 40 | 1.0, 1.0, 1.0, 0.0 41 | }; 42 | 43 | // Apply the gradient to the bottom portion of the graph 44 | self.myGraph.gradientBottom = CGGradientCreateWithColorComponents(colorspace, components, locations, num_locations); 45 | 46 | // Enable and disable various graph properties and axis displays 47 | self.myGraph.enableTouchReport = YES; 48 | self.myGraph.enablePopUpReport = YES; 49 | self.myGraph.enableYAxisLabel = YES; 50 | self.myGraph.autoScaleYAxis = YES; 51 | self.myGraph.alwaysDisplayDots = NO; 52 | self.myGraph.enableReferenceXAxisLines = YES; 53 | self.myGraph.enableReferenceYAxisLines = YES; 54 | self.myGraph.enableReferenceAxisFrame = YES; 55 | 56 | // Draw an average line 57 | self.myGraph.averageLine.enableAverageLine = YES; 58 | self.myGraph.averageLine.alpha = 0.6; 59 | self.myGraph.averageLine.color = [UIColor darkGrayColor]; 60 | self.myGraph.averageLine.width = 2.5; 61 | self.myGraph.averageLine.dashPattern = @[@(2),@(2)]; 62 | 63 | // Set the graph's animation style to draw, fade, or none 64 | self.myGraph.animationGraphStyle = BEMLineAnimationDraw; 65 | 66 | // Dash the y reference lines 67 | self.myGraph.lineDashPatternForReferenceYAxisLines = @[@(2),@(2)]; 68 | 69 | // Show the y axis values with this format string 70 | self.myGraph.formatStringForValues = @"%.1f"; 71 | 72 | // Setup initial curve selection segment 73 | self.curveChoice.selectedSegmentIndex = self.myGraph.enableBezierCurve; 74 | 75 | // The labels to report the values of the graph when the user touches it 76 | self.labelValues.text = [NSString stringWithFormat:@"%i", [[self.myGraph calculatePointValueSum] intValue]]; 77 | self.labelDates.text = @"between now and later"; 78 | } 79 | 80 | - (void)didReceiveMemoryWarning { 81 | [super didReceiveMemoryWarning]; 82 | // Dispose of any resources that can be recreated. 83 | } 84 | 85 | - (void)hydrateDatasets { 86 | // Reset the arrays of values (Y-Axis points) and dates (X-Axis points / labels) 87 | if (!self.arrayOfValues) self.arrayOfValues = [[NSMutableArray alloc] init]; 88 | if (!self.arrayOfDates) self.arrayOfDates = [[NSMutableArray alloc] init]; 89 | [self.arrayOfValues removeAllObjects]; 90 | [self.arrayOfDates removeAllObjects]; 91 | 92 | previousStepperValue = self.graphObjectIncrement.value; 93 | totalNumber = 0; 94 | NSDate *baseDate = [NSDate date]; 95 | BOOL showNullValue = true; 96 | 97 | // Add objects to the array based on the stepper value 98 | for (int i = 0; i < 9; i++) { 99 | [self.arrayOfValues addObject:@([self getRandomFloat])]; // Random values for the graph 100 | if (i == 0) { 101 | [self.arrayOfDates addObject:baseDate]; // Dates for the X-Axis of the graph 102 | } else if (showNullValue && i == 4) { 103 | [self.arrayOfDates addObject:[self dateForGraphAfterDate:self.arrayOfDates[i-1]]]; // Dates for the X-Axis of the graph 104 | self.arrayOfValues[i] = @(BEMNullGraphValue); 105 | } else { 106 | [self.arrayOfDates addObject:[self dateForGraphAfterDate:self.arrayOfDates[i-1]]]; // Dates for the X-Axis of the graph 107 | } 108 | 109 | totalNumber = totalNumber + [[self.arrayOfValues objectAtIndex:i] intValue]; // All of the values added together 110 | } 111 | } 112 | 113 | - (NSDate *)dateForGraphAfterDate:(NSDate *)date { 114 | NSTimeInterval secondsInTwentyFourHours = 24 * 60 * 60; 115 | NSDate *newDate = [date dateByAddingTimeInterval:secondsInTwentyFourHours]; 116 | return newDate; 117 | } 118 | 119 | - (NSString *)labelForDateAtIndex:(NSInteger)index { 120 | NSDate *date = self.arrayOfDates[index]; 121 | NSDateFormatter *df = [[NSDateFormatter alloc] init]; 122 | df.dateFormat = @"MM/dd"; 123 | NSString *label = [df stringFromDate:date]; 124 | return label; 125 | } 126 | 127 | #pragma mark - Graph Actions 128 | 129 | // Refresh the line graph using the specified properties 130 | - (IBAction)refresh:(id)sender { 131 | [self hydrateDatasets]; 132 | 133 | UIColor *color = [UIColor colorWithRed:31.0/255.0 green:187.0/255.0 blue:166.0/255.0 alpha:1.0]; // set the default color 134 | if (self.graphColorChoice.selectedSegmentIndex == 0) color = [UIColor colorWithRed:31.0/255.0 green:187.0/255.0 blue:166.0/255.0 alpha:1.0]; 135 | else if (self.graphColorChoice.selectedSegmentIndex == 1) color = [UIColor colorWithRed:255.0/255.0 green:187.0/255.0 blue:31.0/255.0 alpha:1.0]; 136 | else if (self.graphColorChoice.selectedSegmentIndex == 2) color = [UIColor colorWithRed:0.0 green:140.0/255.0 blue:255.0/255.0 alpha:1.0]; 137 | 138 | self.myGraph.enableBezierCurve = (BOOL) self.curveChoice.selectedSegmentIndex; 139 | self.myGraph.colorTop = color; 140 | self.myGraph.colorBottom = color; 141 | self.myGraph.backgroundColor = color; 142 | self.view.tintColor = color; 143 | self.labelValues.textColor = color; 144 | self.navigationController.navigationBar.tintColor = color; 145 | 146 | self.myGraph.animationGraphStyle = BEMLineAnimationFade; 147 | [self.myGraph reloadGraph]; 148 | } 149 | 150 | - (float)getRandomFloat { 151 | float i1 = (float)(arc4random() % 1000000) / 100 ; 152 | return i1; 153 | } 154 | 155 | - (IBAction)addOrRemovePointFromGraph:(id)sender { 156 | if (self.graphObjectIncrement.value > previousStepperValue) { 157 | // Add point 158 | [self.arrayOfValues addObject:@([self getRandomFloat])]; 159 | NSDate *newDate = [self dateForGraphAfterDate:(NSDate *)[self.arrayOfDates lastObject]]; 160 | [self.arrayOfDates addObject:newDate]; 161 | [self.myGraph reloadGraph]; 162 | } else if (self.graphObjectIncrement.value < previousStepperValue) { 163 | // Remove point 164 | [self.arrayOfValues removeObjectAtIndex:0]; 165 | [self.arrayOfDates removeObjectAtIndex:0]; 166 | [self.myGraph reloadGraph]; 167 | } 168 | 169 | previousStepperValue = self.graphObjectIncrement.value; 170 | } 171 | 172 | - (IBAction)displayStatistics:(id)sender { 173 | [self performSegueWithIdentifier:@"showStats" sender:self]; 174 | } 175 | 176 | - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { 177 | [super prepareForSegue:segue sender:sender]; 178 | 179 | if ([segue.identifier isEqualToString:@"showStats"]) { 180 | StatsViewController *controller = segue.destinationViewController; 181 | controller.standardDeviation = [NSString stringWithFormat:@"%.2f", [[self.myGraph calculateLineGraphStandardDeviation] floatValue]]; 182 | controller.average = [NSString stringWithFormat:@"%.2f", [[self.myGraph calculatePointValueAverage] floatValue]]; 183 | controller.median = [NSString stringWithFormat:@"%.2f", [[self.myGraph calculatePointValueMedian] floatValue]]; 184 | controller.mode = [NSString stringWithFormat:@"%.2f", [[self.myGraph calculatePointValueMode] floatValue]]; 185 | controller.minimum = [NSString stringWithFormat:@"%.2f", [[self.myGraph calculateMinimumPointValue] floatValue]]; 186 | controller.maximum = [NSString stringWithFormat:@"%.2f", [[self.myGraph calculateMaximumPointValue] floatValue]]; 187 | controller.snapshotImage = [self.myGraph graphSnapshotImage]; 188 | } 189 | } 190 | 191 | 192 | #pragma mark - SimpleLineGraph Data Source 193 | 194 | - (NSInteger)numberOfPointsInLineGraph:(BEMSimpleLineGraphView *)graph { 195 | return (int)[self.arrayOfValues count]; 196 | } 197 | 198 | - (CGFloat)lineGraph:(BEMSimpleLineGraphView *)graph valueForPointAtIndex:(NSInteger)index { 199 | return [[self.arrayOfValues objectAtIndex:index] doubleValue]; 200 | } 201 | 202 | #pragma mark - SimpleLineGraph Delegate 203 | 204 | - (NSInteger)numberOfGapsBetweenLabelsOnLineGraph:(BEMSimpleLineGraphView *)graph { 205 | return 2; 206 | } 207 | 208 | - (NSString *)lineGraph:(BEMSimpleLineGraphView *)graph labelOnXAxisForIndex:(NSInteger)index { 209 | 210 | NSString *label = [self labelForDateAtIndex:index]; 211 | return [label stringByReplacingOccurrencesOfString:@" " withString:@"\n"]; 212 | } 213 | 214 | - (void)lineGraph:(BEMSimpleLineGraphView *)graph didTouchGraphWithClosestIndex:(NSInteger)index { 215 | self.labelValues.text = [NSString stringWithFormat:@"%@", [self.arrayOfValues objectAtIndex:index]]; 216 | self.labelDates.text = [NSString stringWithFormat:@"in %@", [self labelForDateAtIndex:index]]; 217 | } 218 | 219 | - (void)lineGraph:(BEMSimpleLineGraphView *)graph didReleaseTouchFromGraphWithClosestIndex:(CGFloat)index { 220 | [UIView animateWithDuration:0.2 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{ 221 | self.labelValues.alpha = 0.0; 222 | self.labelDates.alpha = 0.0; 223 | } completion:^(BOOL finished) { 224 | self.labelValues.text = [NSString stringWithFormat:@"%i", [[self.myGraph calculatePointValueSum] intValue]]; 225 | self.labelDates.text = [NSString stringWithFormat:@"between %@ and %@", [self labelForDateAtIndex:0], [self labelForDateAtIndex:self.arrayOfDates.count - 1]]; 226 | 227 | [UIView animateWithDuration:0.5 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{ 228 | self.labelValues.alpha = 1.0; 229 | self.labelDates.alpha = 1.0; 230 | } completion:nil]; 231 | }]; 232 | } 233 | 234 | - (void)lineGraphDidFinishLoading:(BEMSimpleLineGraphView *)graph { 235 | self.labelValues.text = [NSString stringWithFormat:@"%i", [[self.myGraph calculatePointValueSum] intValue]]; 236 | self.labelDates.text = [NSString stringWithFormat:@"between %@ and %@", [self labelForDateAtIndex:0], [self labelForDateAtIndex:self.arrayOfDates.count - 1]]; 237 | } 238 | 239 | /* - (void)lineGraphDidFinishDrawing:(BEMSimpleLineGraphView *)graph { 240 | // Use this method for tasks after the graph has finished drawing 241 | } */ 242 | 243 | - (NSString *)popUpSuffixForlineGraph:(BEMSimpleLineGraphView *)graph { 244 | return @" people"; 245 | } 246 | 247 | //- (NSString *)popUpPrefixForlineGraph:(BEMSimpleLineGraphView *)graph { 248 | // return @"$ "; 249 | //} 250 | 251 | #pragma mark - Optional Datasource Customizations 252 | /* 253 | This section holds a bunch of graph customizations that can be made. They are commented out because they aren't required. If you choose to uncomment some, they will override some of the other delegate and datasource methods above. 254 | 255 | */ 256 | 257 | //- (NSInteger)baseIndexForXAxisOnLineGraph:(BEMSimpleLineGraphView *)graph { 258 | // return 0; 259 | //} 260 | // 261 | //- (NSInteger)incrementIndexForXAxisOnLineGraph:(BEMSimpleLineGraphView *)graph { 262 | // return 2; 263 | //} 264 | 265 | //- (NSArray *)incrementPositionsForXAxisOnLineGraph:(BEMSimpleLineGraphView *)graph { 266 | // NSMutableArray *positions = [NSMutableArray array]; 267 | // NSCalendar *calendar = [NSCalendar currentCalendar]; 268 | // NSInteger previousDay = -1; 269 | // for(int i = 0; i < self.arrayOfDates.count; i++) { 270 | // NSDate *date = self.arrayOfDates[i]; 271 | // NSDateComponents * components = [calendar components:NSCalendarUnitDay fromDate:date]; 272 | // NSInteger day = components.day; 273 | // if(day != previousDay) { 274 | // [positions addObject:@(i)]; 275 | // previousDay = day; 276 | // } 277 | // } 278 | // return positions; 279 | // 280 | //} 281 | // 282 | //- (CGFloat)baseValueForYAxisOnLineGraph:(BEMSimpleLineGraphView *)graph { 283 | // NSNumber *minValue = [graph calculateMinimumPointValue]; 284 | // //Let's round our value down to the nearest 100 285 | // double min = minValue.doubleValue; 286 | // double roundPrecision = 100; 287 | // double offset = roundPrecision / 2; 288 | // double roundedVal = round((min - offset) / roundPrecision) * roundPrecision; 289 | // return roundedVal; 290 | //} 291 | // 292 | //- (CGFloat)incrementValueForYAxisOnLineGraph:(BEMSimpleLineGraphView *)graph { 293 | // NSNumber *minValue = [graph calculateMinimumPointValue]; 294 | // NSNumber *maxValue = [graph calculateMaximumPointValue]; 295 | // double range = maxValue.doubleValue - minValue.doubleValue; 296 | // float increment = 1.0; 297 | // if (range < 10) { 298 | // increment = 2; 299 | // } else if (range < 100) { 300 | // increment = 10; 301 | // } else if (range < 500) { 302 | // increment = 50; 303 | // } else if (range < 1000) { 304 | // increment = 100; 305 | // } else if (range < 5000) { 306 | // increment = 500; 307 | // } else { 308 | // increment = 1000; 309 | // } 310 | // return increment; 311 | //} 312 | 313 | @end 314 | -------------------------------------------------------------------------------- /Sample Project/SimpleLineChart/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /Sample Project/SimpleLineChart/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // SimpleLineGraph 4 | // 5 | // Created by Bobo on 12/27/13. 6 | // Copyright (c) 2013 Boris Emorine. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "AppDelegate.h" 12 | 13 | int main(int argc, char * argv[]) 14 | { 15 | @autoreleasepool { 16 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Sample Project/SimpleLineChartTests/CustomizationTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // CustomizationTests.m 3 | // SimpleLineChart 4 | // 5 | // Created by Bobo on 8/26/15. 6 | // Copyright (c) 2015 Boris Emorine. All rights reserved. 7 | // 8 | 9 | @import XCTest; 10 | #import "BEMSimpleLineGraphView.h" 11 | #import "contantsTests.h" 12 | 13 | /// Same tags as in BEMSimpleLineGraphView.m 14 | typedef NS_ENUM(NSInteger, BEMInternalTags) 15 | { 16 | DotFirstTag100 = 100, 17 | DotLastTag1000 = 1000, 18 | LabelYAxisTag2000 = 2000, 19 | BackgroundYAxisTag2100 = 2100, 20 | BackgroundXAxisTag2200 = 2200, 21 | PermanentPopUpViewTag3100 = 3100, 22 | }; 23 | 24 | @interface CustomizationTests : XCTestCase 25 | 26 | @property (strong, nonatomic) BEMSimpleLineGraphView *lineGraph; 27 | 28 | @end 29 | 30 | @implementation CustomizationTests 31 | 32 | - (void)setUp { 33 | [super setUp]; 34 | 35 | self.lineGraph = [[BEMSimpleLineGraphView alloc] initWithFrame:CGRectMake(0, 0, 200, 200)]; 36 | self.lineGraph.delegate = self; 37 | self.lineGraph.dataSource = self; 38 | } 39 | 40 | #pragma mark BEMSimpleLineGraph Data Source 41 | 42 | - (NSInteger)numberOfPointsInLineGraph:(BEMSimpleLineGraphView * __nonnull)graph { 43 | return numberOfPoints; 44 | } 45 | 46 | - (CGFloat)lineGraph:(BEMSimpleLineGraphView * __nonnull)graph valueForPointAtIndex:(NSInteger)index { 47 | return pointValue; 48 | } 49 | 50 | - (NSString *)lineGraph:(nonnull BEMSimpleLineGraphView *)graph labelOnXAxisForIndex:(NSInteger)index { 51 | return xAxisLabelString; 52 | } 53 | 54 | - (NSString *)popUpPrefixForlineGraph:(BEMSimpleLineGraphView * __nonnull)graph { 55 | return popUpPrefix; 56 | } 57 | 58 | - (NSString *)popUpSuffixForlineGraph:(BEMSimpleLineGraphView * __nonnull)graph { 59 | return popUpSuffix; 60 | } 61 | 62 | #pragma mark Tests 63 | 64 | - (void)testDotCustomization { 65 | CGFloat sizePoint = 20.0; 66 | 67 | self.lineGraph.alwaysDisplayDots = YES; 68 | self.lineGraph.animationGraphEntranceTime = 0.0; 69 | self.lineGraph.sizePoint = sizePoint; 70 | self.lineGraph.colorPoint = [UIColor greenColor]; 71 | [self.lineGraph reloadGraph]; 72 | 73 | NSMutableArray *dots = [NSMutableArray new]; 74 | for (UIView *dot in self.lineGraph.subviews) { 75 | if ([dot isKindOfClass:[BEMCircle class]] && dot.tag >= DotFirstTag100 && dot.tag <= DotLastTag1000) { 76 | [dots addObject:dot]; 77 | } 78 | } 79 | 80 | XCTAssert(dots.count == numberOfPoints, @"There should be as many BEMCircle views in the graph's subviews as the data source method 'numberOfPointsInLineGraph:' returns"); 81 | 82 | for (BEMCircle *dot in dots) { 83 | XCTAssert(dot.bounds.size.width == sizePoint, @"Dots size point has been customized to 20.0"); 84 | XCTAssert(dot.bounds.size.height == sizePoint, @"Dots size point has been customized to 20.0"); 85 | XCTAssert([dot.Pointcolor isEqual:[UIColor greenColor]], @"Dots color has been set to green"); 86 | XCTAssert(dot.absoluteValue == pointValue, @"Dots are expected to have a value equal to the value returned by the data source method 'valueForPointAtIndex:'"); 87 | XCTAssert(dot.alpha >= 0.98 && dot.alpha <= 1.0, @"Dots are expected to always be displayed (alpha of 0.7)"); 88 | XCTAssert([dot.backgroundColor isEqual:[UIColor clearColor]], @"Dots are expected to have a clearColor background color by default"); 89 | } 90 | } 91 | 92 | - (void)testXAxisCustomization { 93 | UIFont *font = [UIFont systemFontOfSize:25.0]; 94 | self.lineGraph.labelFont = font; 95 | self.lineGraph.colorXaxisLabel = [UIColor greenColor]; 96 | [self.lineGraph reloadGraph]; 97 | 98 | NSArray *labels = [self.lineGraph graphLabelsForXAxis]; 99 | XCTAssert(labels.count == numberOfPoints, @"The number of X-Axis labels should be the same as the number of points on the graph"); 100 | 101 | for (UILabel *XAxisLabel in labels) { 102 | XCTAssert([XAxisLabel isMemberOfClass:[UILabel class]], @"The array returned by 'graphLabelsForXAxis' should only return UILabels"); 103 | XCTAssert([XAxisLabel.text isEqualToString:xAxisLabelString], @"The X-Axis label's strings should be the same as the one returned by the data source method 'labelOnXAxisForIndex:'"); 104 | XCTAssert([XAxisLabel.backgroundColor isEqual:[UIColor clearColor]], @"X-Axis labels are expected to have a clear beackground color by default"); 105 | XCTAssert(XAxisLabel.textAlignment == NSTextAlignmentCenter, @"X-Axis labels are expected to have their text centered by default"); 106 | XCTAssert(XAxisLabel.tag == DotLastTag1000, @"X-Axis labels are expected to have a certain tag by default"); 107 | XCTAssert(XAxisLabel.font == font, @"X-Axis label's font is expected to be the customized one"); 108 | XCTAssert(XAxisLabel.textColor = [UIColor greenColor], @"X-Axis label's text color is expected to tbe the customized one"); 109 | } 110 | } 111 | 112 | - (void)testPopUps { 113 | self.lineGraph.alwaysDisplayPopUpLabels = YES; 114 | self.lineGraph.colorBackgroundPopUplabel = [UIColor greenColor]; 115 | UIFont *font = [UIFont systemFontOfSize:25.0]; 116 | self.lineGraph.labelFont = font; 117 | [self.lineGraph reloadGraph]; 118 | 119 | NSMutableArray *popUps = [NSMutableArray new]; 120 | for (BEMPermanentPopupView *popUp in self.lineGraph.subviews) { 121 | if ([popUp isKindOfClass:[BEMPermanentPopupView class]] && popUp.tag == PermanentPopUpViewTag3100) { 122 | [popUps addObject:popUp]; 123 | } 124 | } 125 | 126 | XCTAssert(popUps.count == numberOfPoints, @"We should have a popup above each and every dot"); 127 | for (BEMPermanentPopupView *popUp in popUps) { 128 | XCTAssert(popUp.backgroundColor == [UIColor greenColor], @"The popups backgorunf color should be the one set by the property"); 129 | XCTAssert(popUp.alpha >= 0.69 && popUp.alpha <= 0.71, @"The popups should always be displayed and have an alpha of 0.7"); 130 | } 131 | 132 | NSMutableArray *popUpsLabels = [NSMutableArray new]; 133 | for (UILabel *label in self.lineGraph.subviews) { 134 | if ([label isKindOfClass:[BEMPermanentPopupLabel class]]) { 135 | [popUpsLabels addObject:label]; 136 | } 137 | } 138 | 139 | XCTAssert(popUpsLabels.count == numberOfPoints, @"We should have a popup above each and every dot"); 140 | NSString *expectedLabelText = [NSString stringWithFormat:@"%@%.f%@", popUpPrefix,pointValue,popUpSuffix]; 141 | for (BEMPermanentPopupLabel *label in popUpsLabels) { 142 | XCTAssert([label.text isEqualToString:expectedLabelText], @"The popup labels should display the value of the dot and the suffix and prefix returned by the delegate"); 143 | XCTAssert(label.font == font, @"The popup label's font is expected to be the customized one"); 144 | XCTAssert(label.backgroundColor == [UIColor clearColor], @"The popup label's backgorund color should always be clear color"); 145 | } 146 | } 147 | 148 | - (void)tearDown { 149 | self.lineGraph = nil; 150 | [super tearDown]; 151 | } 152 | 153 | @end 154 | -------------------------------------------------------------------------------- /Sample Project/SimpleLineChartTests/SimpleLineChartTests-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundlePackageType 14 | BNDL 15 | CFBundleShortVersionString 16 | 1.0 17 | CFBundleSignature 18 | ???? 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /Sample Project/SimpleLineChartTests/SimpleLineChartTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // SimpleLineGraphTests.m 3 | // SimpleLineGraphTests 4 | // 5 | // Created by Bobo on 12/27/13. 6 | // Copyright (c) 2013 Boris Emorine. All rights reserved. 7 | // 8 | 9 | @import XCTest; 10 | #import "BEMSimpleLineGraphView.h" 11 | #import "contantsTests.h" 12 | 13 | /// Same tags as in BEMSimpleLineGraphView.m 14 | typedef NS_ENUM(NSInteger, BEMInternalTags) 15 | { 16 | DotFirstTag100 = 100, 17 | DotLastTag1000 = 1000, 18 | LabelYAxisTag2000 = 2000, 19 | BackgroundYAxisTag2100 = 2100, 20 | BackgroundXAxisTag2200 = 2200, 21 | PermanentPopUpViewTag3100 = 3100, 22 | }; 23 | 24 | /// General, simple tests for BEMSimpleLineGraph. Mostly testing default values. 25 | @interface SimpleLineGraphTests : XCTestCase 26 | 27 | @property (strong, nonatomic) BEMSimpleLineGraphView *lineGraph; 28 | 29 | @end 30 | 31 | 32 | @implementation SimpleLineGraphTests 33 | 34 | - (void)setUp { 35 | [super setUp]; 36 | 37 | self.lineGraph = [[BEMSimpleLineGraphView alloc] initWithFrame:CGRectMake(0, 0, 200, 200)]; 38 | self.lineGraph.delegate = self; 39 | self.lineGraph.dataSource = self; 40 | } 41 | 42 | #pragma mark BEMSimpleLineGraph Data Source 43 | 44 | - (NSInteger)numberOfPointsInLineGraph:(BEMSimpleLineGraphView * __nonnull)graph { 45 | return numberOfPoints; 46 | } 47 | 48 | - (CGFloat)lineGraph:(BEMSimpleLineGraphView * __nonnull)graph valueForPointAtIndex:(NSInteger)index { 49 | return pointValue; 50 | } 51 | 52 | - (NSString *)lineGraph:(nonnull BEMSimpleLineGraphView *)graph labelOnXAxisForIndex:(NSInteger)index { 53 | return xAxisLabelString; 54 | } 55 | 56 | #pragma mark Test Methods 57 | 58 | - (void)testInit { 59 | XCTAssertNotNil(self.lineGraph, @"An allocated and initialized BEMSimpleLineGraph should not be nil."); 60 | } 61 | 62 | - (void)testInitWithFrame { 63 | XCTAssertNotNil(self.lineGraph, @"An allocated and initialized BEMSimpleLineGraph should not be nil."); 64 | } 65 | 66 | - (void)testReloadDataPerformance { 67 | [self measureBlock:^{ 68 | [self.lineGraph reloadGraph]; 69 | }]; 70 | } 71 | 72 | - (void)testGraphValuesForXAxis { 73 | [self.lineGraph reloadGraph]; 74 | 75 | NSArray *xAxisStrings = [self.lineGraph graphValuesForXAxis]; 76 | XCTAssert(xAxisStrings.count == numberOfPoints, @"The number of strings on the X-Axis should be equal to the number returned by the data source method 'numberOfPointsInLineGraph:'"); 77 | 78 | for (NSString *xAxisString in xAxisStrings) { 79 | XCTAssert([xAxisString isKindOfClass:[NSString class]], @"The array returned by 'graphValuesForXAxis' should only return NSStrings"); 80 | XCTAssert([xAxisString isEqualToString:xAxisLabelString], @"The X-Axis strings should be the same as the one returned by the data source method 'labelOnXAxisForIndex:'"); 81 | } 82 | } 83 | 84 | - (void)testGraphValuesForDataPoints { 85 | [self.lineGraph reloadGraph]; 86 | 87 | NSArray *values = [self.lineGraph graphValuesForDataPoints]; 88 | XCTAssert(values.count == numberOfPoints, @"The number of data points should be equal to the number returned by the data source method 'numberOfPointsInLineGraph:'"); 89 | 90 | NSMutableArray *mockedValues = [NSMutableArray new]; 91 | for (NSInteger i = 0; i < numberOfPoints; i++) { 92 | [mockedValues addObject:[NSNumber numberWithFloat:pointValue]]; 93 | } 94 | XCTAssert([values isEqualToArray:mockedValues], @"The array returned by 'graphValuesForDataPoints' should be similar than the one returned by the data source method 'valueForPointAtIndex:'labelOnXAxisForIndex:"); 95 | } 96 | 97 | - (void)testDrawnPoints { 98 | self.lineGraph.animationGraphEntranceTime = 0.0; 99 | [self.lineGraph reloadGraph]; 100 | 101 | NSMutableArray *dots = [NSMutableArray new]; 102 | for (UIView *dot in self.lineGraph.subviews) { 103 | if ([dot isKindOfClass:[BEMCircle class]] && dot.tag >= DotFirstTag100 && dot.tag <= DotLastTag1000) { 104 | [dots addObject:dot]; 105 | } 106 | } 107 | XCTAssert(dots.count == numberOfPoints, @"There should be as many BEMCircle views in the graph's subviews as the data source method 'numberOfPointsInLineGraph:' returns"); 108 | 109 | for (BEMCircle *dot in dots) { 110 | XCTAssert(dot.bounds.size.width == 10.0, @"Dots are expected to have a default width of 10.0"); 111 | XCTAssert(dot.bounds.size.height == 10.0, @"Dots are expected to have a default height of 10.0"); 112 | XCTAssert([dot.Pointcolor isEqual:[UIColor colorWithWhite:1.0 alpha:0.7]], @"Dots are expected to be white by default"); 113 | XCTAssert(dot.absoluteValue == pointValue, @"Dots are expected to have a value equal to the value returned by the data source method 'valueForPointAtIndex:'"); 114 | XCTAssert(dot.alpha == 0.0, @"Dots are expected to not be displayed by default (alpha of 0)"); 115 | XCTAssert([dot.backgroundColor isEqual:[UIColor clearColor]], @"Dots are expected to have a clearColor background color by default"); 116 | } 117 | } 118 | 119 | - (void)testGraphLabelsForXAxis { 120 | self.lineGraph.enableXAxisLabel = NO; 121 | [self.lineGraph reloadGraph]; 122 | 123 | XCTAssert([self.lineGraph graphLabelsForXAxis].count == 0); 124 | 125 | self.lineGraph.enableXAxisLabel = YES; 126 | [self.lineGraph reloadGraph]; 127 | 128 | NSArray *labels = [self.lineGraph graphLabelsForXAxis]; 129 | XCTAssert(labels.count == numberOfPoints, @"The number of X-Axis labels should be the same as the number of points on the graph"); 130 | 131 | for (UILabel *XAxisLabel in labels) { 132 | XCTAssert([XAxisLabel isMemberOfClass:[UILabel class]], @"The array returned by 'graphLabelsForXAxis' should only return UILabels"); 133 | XCTAssert([XAxisLabel.text isEqualToString:xAxisLabelString], @"The X-Axis label's strings should be the same as the one returned by the data source method 'labelOnXAxisForIndex:'"); 134 | XCTAssert([XAxisLabel.backgroundColor isEqual:[UIColor clearColor]], @"X-Axis labels are expected to have a clear beackground color by default"); 135 | XCTAssert([XAxisLabel.textColor isEqual:[UIColor blackColor]], @"X-Axis labels are expected to have a black text color by default"); 136 | XCTAssert(XAxisLabel.textAlignment == NSTextAlignmentCenter, @"X-Axis labels are expected to have their text centered by default"); 137 | XCTAssert(XAxisLabel.tag == DotLastTag1000, @"X-Axis labels are expected to have a certain tag by default"); 138 | } 139 | } 140 | 141 | - (void)testYAxisLabels { 142 | self.lineGraph.enableYAxisLabel = NO; 143 | [self.lineGraph reloadGraph]; 144 | 145 | for (UILabel *label in self.lineGraph.subviews) { 146 | XCTAssert(label.tag != LabelYAxisTag2000, @"No Y-Axis labels are expected if enableYAxisLabel is set to NO"); 147 | } 148 | 149 | self.lineGraph.enableYAxisLabel = YES; 150 | [self.lineGraph reloadGraph]; 151 | 152 | NSString *value = [NSString stringWithFormat:@"%.f", pointValue]; 153 | 154 | NSMutableArray *yAxisLabels = [NSMutableArray new]; 155 | for (UILabel *label in self.lineGraph.subviews) { 156 | if ([label isKindOfClass:[UILabel class]] && label.tag == LabelYAxisTag2000) { 157 | [yAxisLabels addObject:label]; 158 | XCTAssert([label.text isEqualToString:value], @"The value on the Y-Axis label is expected to be the value given by the data source method 'valueForPointAtIndex:'"); 159 | XCTAssert([label.textColor isEqual:[UIColor blackColor]], @"The Y-Axis label is expected to have a text color of black by default"); 160 | XCTAssert([label.backgroundColor isEqual:[UIColor clearColor]], @"The Y-Axis label is expected to have a backgrounf color of clear by default"); 161 | } 162 | } 163 | 164 | XCTAssert(yAxisLabels.count == 1, @"With all the dots having the same value, we only expect one Y axis label"); 165 | } 166 | 167 | - (void)tearDown { 168 | self.lineGraph = nil; 169 | [super tearDown]; 170 | } 171 | 172 | @end 173 | -------------------------------------------------------------------------------- /Sample Project/SimpleLineChartTests/contantsTests.h: -------------------------------------------------------------------------------- 1 | // 2 | // contantsTests.h 3 | // SimpleLineChart 4 | // 5 | // Created by Bobo on 8/26/15. 6 | // Copyright (c) 2015 Boris Emorine. All rights reserved. 7 | // 8 | 9 | #ifndef SimpleLineChart_contantsTests_h 10 | #define SimpleLineChart_contantsTests_h 11 | 12 | static NSInteger numberOfPoints = 100; 13 | static CGFloat pointValue = 3.0; 14 | static NSString * xAxisLabelString = @"X-Axis-Label"; 15 | static NSString * popUpPrefix = @"Prefix"; 16 | static NSString * popUpSuffix = @"Suffix"; 17 | 18 | #endif 19 | -------------------------------------------------------------------------------- /Sample Project/SimpleLineChartTests/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | --------------------------------------------------------------------------------