├── .gitignore ├── GraphView.swift ├── LICENCE.md ├── README.md ├── Sample Code ├── GraphView iOS │ ├── GraphView iOS.xcodeproj │ │ ├── project.pbxproj │ │ └── project.xcworkspace │ │ │ └── contents.xcworkspacedata │ └── GraphView iOS │ │ ├── AppDelegate.swift │ │ ├── Assets.xcassets │ │ └── AppIcon.appiconset │ │ │ └── Contents.json │ │ ├── Base.lproj │ │ ├── LaunchScreen.storyboard │ │ └── Main.storyboard │ │ ├── Info.plist │ │ └── ViewController.swift ├── OS X (deprecated) │ ├── .DS_Store │ └── OS X Example │ │ ├── .DS_Store │ │ ├── MOONGraphView │ │ ├── Info.plist │ │ ├── MOONGraphView.h │ │ └── MOONGraphView.swift │ │ ├── OS X Example.xcodeproj │ │ ├── project.pbxproj │ │ └── project.xcworkspace │ │ │ └── contents.xcworkspacedata │ │ └── OS X Example │ │ ├── AppDelegate.swift │ │ ├── Assets.xcassets │ │ └── AppIcon.appiconset │ │ │ └── Contents.json │ │ ├── Base.lproj │ │ └── Main.storyboard │ │ ├── Info.plist │ │ └── ViewController.swift └── iOS (deprecated) │ ├── .DS_Store │ └── iOS Example │ ├── .DS_Store │ ├── iOS Example.xcodeproj │ ├── project.pbxproj │ └── project.xcworkspace │ │ └── contents.xcworkspacedata │ └── iOS Example │ ├── .DS_Store │ ├── AppDelegate.swift │ ├── Assets.xcassets │ └── AppIcon.appiconset │ │ └── Contents.json │ ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard │ ├── Info.plist │ ├── MOONGraphView.swift │ └── ViewController.swift └── graph_shader.metal /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## Build generated 6 | build/ 7 | DerivedData/ 8 | 9 | ## Various settings 10 | *.pbxuser 11 | !default.pbxuser 12 | *.mode1v3 13 | !default.mode1v3 14 | *.mode2v3 15 | !default.mode2v3 16 | *.perspectivev3 17 | !default.perspectivev3 18 | xcuserdata/ 19 | 20 | ## Other 21 | *.moved-aside 22 | *.xcuserstate 23 | 24 | ## Obj-C/Swift specific 25 | *.hmap 26 | *.ipa 27 | 28 | ## Playgrounds 29 | timeline.xctimeline 30 | playground.xcworkspace 31 | 32 | # Swift Package Manager 33 | # 34 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 35 | # Packages/ 36 | .build/ 37 | 38 | # CocoaPods 39 | # 40 | # We recommend against adding the Pods directory to your .gitignore. However 41 | # you should judge for yourself, the pros and cons are mentioned at: 42 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 43 | # 44 | # Pods/ 45 | 46 | # Carthage 47 | # 48 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 49 | # Carthage/Checkouts 50 | 51 | Carthage/Build 52 | 53 | # fastlane 54 | # 55 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 56 | # screenshots whenever they are needed. 57 | # For more information about the recommended setup visit: 58 | # https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md 59 | 60 | fastlane/report.xml 61 | fastlane/Preview.html 62 | fastlane/screenshots 63 | fastlane/test_output 64 | .DS_Store 65 | -------------------------------------------------------------------------------- /LICENCE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Vegard Solheim Theriault 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Graph View 2 | 3 | ## Description 4 | GraphView is a very simple graph library for both iOS and OS X that lets you very easily plot a graph from real-time data. We use it internally at MOON Wearables to plot real-time data from different sensors. Below you can see a screenshot and some GIFs of the graph view plotting sample data generated by compound sine waves. There's example code for both OS X and iOS in their respective folders. 5 | 6 | ![Image](http://imgur.com/P8pfcP8.png) 7 | 8 | ![Image](http://imgur.com/aBwsPs5.gif) 9 | 10 | ## API 11 | ### Overview 12 | The entire library is just one class called `GraphView`. It has a range of properties that can be used to customize the graph, and a few methods to add and remove data. The graph automatically scales based on the values you've passed into it. Although you can force it to not scale by setting `isAutoscaling = false` and `visibleRange = 3...5`, or whatever range you want. On iOS, you can also pinch and pan on the graph to move around. If you don't want this behavior (like if you're using it in a table view) you can set `gesturesEnabled = false`. 13 | 14 | ### Properties 15 | 16 | 17 | 18 | ##### var backgroundTint = BackgroundTintColor.blue 19 | This will set the background gradient of the graph. It's an enum with eight colors to pick from: `.gray`, `.red`, `.green`, `.blue`, `.turquoise`, `.yellow`, `.purple`, and `.clear`. The default is `.blue`. 20 | 21 | ##### var sampleColor = SampleColor.color(plain: .white) 22 | The color of the samples plotted in the graph. This can either be a `.plain` color, or a `.gradient` one. The default value is plain white. 23 | 24 | ##### var roundedCorners = false 25 | Use this to make the corners rounded or square. The default is true, meaning rounded corners. 26 | 27 | ##### var title: String = "" 28 | Used to set the title of the graph in one of the upper corners. The default value for this is `""`, meaning that it will not be displayed. 29 | 30 | ##### var subtitle: String = "" 31 | Used to set a subtitle that will go right underneath the title. The default value for this is `""`, and will thus not be displayed. 32 | 33 | ##### var valueUnit: String = "" 34 | The unit of the samples added to the graph. This appears as a suffix for the value labels on the right hand side. 35 | 36 | ##### var valueUnitDecimals = 0 37 | The number of desired decimals displayed for the values. The default is 0. 38 | 39 | ##### var capacity = 1000 40 | The number of samples that fit in the graph view. When more samples than this are added, the oldest samples will slide off the left edge. This value can't be lower than 2. The default value is 1000. 41 | 42 | ##### var graphType = GraphType.scatter 43 | How the graph should be plotted. You can choose between `.line` and `.scatter`. The `.line` option currently only works when using the replace(with: ...) method to set the data. 44 | 45 | ##### var sampleSize = SampleSize.small 46 | The size of the samples. This is only applicable when `graphType` is set to `.scatter`. 47 | 48 | ##### var gesturesEnabled = true 49 | This property is only available on iOS. It specifies if the user should be able to change the capacity (by pinching horizontally), the minimum and maximum value (by pinching vertically), and moving up and down the y-axis (by swiping). When the user has started interacting, an "Auto-Scale" button will appear. This button is removed again when the user taps it. 50 | 51 | ##### var visibleRange: ClosedRange = 0...1 52 | Gets or sets the range of values that can be visible within the graph view. If `isAutoscaling` is set to true, this will change by itself. If you want to set this variable yourself, you should probably set `isAutoscaling` to false. 53 | 54 | ##### var isAutoscaling = true 55 | Whether or not the graph should be autoscaling. This will be false if the user is currently using gestures 56 | 57 | ##### var horizontalLines: [Float] = [] 58 | Horizontal lines will be drawn with the y-axis values corresponding to the values in this array. 59 | 60 | 61 | 62 | 63 | ### Methods 64 | ##### func add(sample: Float) 65 | This method is where you add your data to the graph. When the number of samples in the graph exceeds `capacity`, the values will disappear off to the left. If you want to set the `graphType` to `.line`, you have to call `replace(with: ...)` instead of this to make the graph look correct. 66 | 67 | ##### func replace(with: [Float]) 68 | This replaces all the samples in the graph at the same time. It also sets the `capacity` to the correct value. This is a lot faster than looping through your data and continuously calling `add(sample: ...)` if you want to show a whole dataset at once. If you want to set the `graphType` to `.line`, you have to call this method instead of `add(sample: ...)` to make the graph look correct. 69 | 70 | ##### func clear() 71 | Removes all the samples you've added to the graph. All the other properties like `roundedCorners` and `capacity` etc are kept the same. Useful if you want to reuse the same graph view. 72 | 73 | ## Todo 74 | - Change the size of the labels when the view gets too small. 75 | - I'm pretty sure there's a different way of doing this that will make it faster. Will probably end up drawing into a bunch of tall, skinny CALayers, and then moving them sideways. 76 | - Have an auto-scale feature. Might do this by having an Optional scale tuple with a min and max value. If this is nil, use auto-scale. If it's set use a fixed scale. 77 | - Add IBDesignable 78 | - Add scatter plot 79 | 80 | ## Contact 81 | - [@vegather on Twitter](http://www.twitter.com/vegather) 82 | -------------------------------------------------------------------------------- /Sample Code/GraphView iOS/GraphView iOS.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 48; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 1A3CC8EA1F54CEB700248D67 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A3CC8E91F54CEB700248D67 /* AppDelegate.swift */; }; 11 | 1A3CC8EC1F54CEB700248D67 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A3CC8EB1F54CEB700248D67 /* ViewController.swift */; }; 12 | 1A3CC8EF1F54CEB700248D67 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 1A3CC8ED1F54CEB700248D67 /* Main.storyboard */; }; 13 | 1A3CC8F11F54CEB700248D67 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 1A3CC8F01F54CEB700248D67 /* Assets.xcassets */; }; 14 | 1A3CC8F41F54CEB700248D67 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 1A3CC8F21F54CEB700248D67 /* LaunchScreen.storyboard */; }; 15 | 1A3CC8FD1F54CF1E00248D67 /* graph_shader.metal in Sources */ = {isa = PBXBuildFile; fileRef = 1A3CC8FB1F54CF1E00248D67 /* graph_shader.metal */; }; 16 | 1A3CC8FE1F54CF1E00248D67 /* GraphView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A3CC8FC1F54CF1E00248D67 /* GraphView.swift */; }; 17 | /* End PBXBuildFile section */ 18 | 19 | /* Begin PBXFileReference section */ 20 | 1A3CC8E61F54CEB700248D67 /* GraphView iOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "GraphView iOS.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 21 | 1A3CC8E91F54CEB700248D67 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 22 | 1A3CC8EB1F54CEB700248D67 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 23 | 1A3CC8EE1F54CEB700248D67 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 24 | 1A3CC8F01F54CEB700248D67 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 25 | 1A3CC8F31F54CEB700248D67 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 26 | 1A3CC8F51F54CEB700248D67 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 27 | 1A3CC8FB1F54CF1E00248D67 /* graph_shader.metal */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.metal; name = graph_shader.metal; path = ../../../graph_shader.metal; sourceTree = ""; }; 28 | 1A3CC8FC1F54CF1E00248D67 /* GraphView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = GraphView.swift; path = ../../../GraphView.swift; sourceTree = ""; }; 29 | /* End PBXFileReference section */ 30 | 31 | /* Begin PBXFrameworksBuildPhase section */ 32 | 1A3CC8E31F54CEB700248D67 /* Frameworks */ = { 33 | isa = PBXFrameworksBuildPhase; 34 | buildActionMask = 2147483647; 35 | files = ( 36 | ); 37 | runOnlyForDeploymentPostprocessing = 0; 38 | }; 39 | /* End PBXFrameworksBuildPhase section */ 40 | 41 | /* Begin PBXGroup section */ 42 | 1A3CC8DD1F54CEB700248D67 = { 43 | isa = PBXGroup; 44 | children = ( 45 | 1A3CC8E81F54CEB700248D67 /* GraphView iOS */, 46 | 1A3CC8E71F54CEB700248D67 /* Products */, 47 | ); 48 | sourceTree = ""; 49 | }; 50 | 1A3CC8E71F54CEB700248D67 /* Products */ = { 51 | isa = PBXGroup; 52 | children = ( 53 | 1A3CC8E61F54CEB700248D67 /* GraphView iOS.app */, 54 | ); 55 | name = Products; 56 | sourceTree = ""; 57 | }; 58 | 1A3CC8E81F54CEB700248D67 /* GraphView iOS */ = { 59 | isa = PBXGroup; 60 | children = ( 61 | 1A3CC8E91F54CEB700248D67 /* AppDelegate.swift */, 62 | 1A3CC8EB1F54CEB700248D67 /* ViewController.swift */, 63 | 1A3CC8FB1F54CF1E00248D67 /* graph_shader.metal */, 64 | 1A3CC8FC1F54CF1E00248D67 /* GraphView.swift */, 65 | 1A3CC8ED1F54CEB700248D67 /* Main.storyboard */, 66 | 1A3CC8F01F54CEB700248D67 /* Assets.xcassets */, 67 | 1A3CC8F21F54CEB700248D67 /* LaunchScreen.storyboard */, 68 | 1A3CC8F51F54CEB700248D67 /* Info.plist */, 69 | ); 70 | path = "GraphView iOS"; 71 | sourceTree = ""; 72 | }; 73 | /* End PBXGroup section */ 74 | 75 | /* Begin PBXNativeTarget section */ 76 | 1A3CC8E51F54CEB700248D67 /* GraphView iOS */ = { 77 | isa = PBXNativeTarget; 78 | buildConfigurationList = 1A3CC8F81F54CEB700248D67 /* Build configuration list for PBXNativeTarget "GraphView iOS" */; 79 | buildPhases = ( 80 | 1A3CC8E21F54CEB700248D67 /* Sources */, 81 | 1A3CC8E31F54CEB700248D67 /* Frameworks */, 82 | 1A3CC8E41F54CEB700248D67 /* Resources */, 83 | ); 84 | buildRules = ( 85 | ); 86 | dependencies = ( 87 | ); 88 | name = "GraphView iOS"; 89 | productName = "GraphView iOS"; 90 | productReference = 1A3CC8E61F54CEB700248D67 /* GraphView iOS.app */; 91 | productType = "com.apple.product-type.application"; 92 | }; 93 | /* End PBXNativeTarget section */ 94 | 95 | /* Begin PBXProject section */ 96 | 1A3CC8DE1F54CEB700248D67 /* Project object */ = { 97 | isa = PBXProject; 98 | attributes = { 99 | LastSwiftUpdateCheck = 0900; 100 | LastUpgradeCheck = 0900; 101 | ORGANIZATIONNAME = "Vegard Solheim Theriault"; 102 | TargetAttributes = { 103 | 1A3CC8E51F54CEB700248D67 = { 104 | CreatedOnToolsVersion = 9.0; 105 | ProvisioningStyle = Automatic; 106 | }; 107 | }; 108 | }; 109 | buildConfigurationList = 1A3CC8E11F54CEB700248D67 /* Build configuration list for PBXProject "GraphView iOS" */; 110 | compatibilityVersion = "Xcode 8.0"; 111 | developmentRegion = en; 112 | hasScannedForEncodings = 0; 113 | knownRegions = ( 114 | en, 115 | Base, 116 | ); 117 | mainGroup = 1A3CC8DD1F54CEB700248D67; 118 | productRefGroup = 1A3CC8E71F54CEB700248D67 /* Products */; 119 | projectDirPath = ""; 120 | projectRoot = ""; 121 | targets = ( 122 | 1A3CC8E51F54CEB700248D67 /* GraphView iOS */, 123 | ); 124 | }; 125 | /* End PBXProject section */ 126 | 127 | /* Begin PBXResourcesBuildPhase section */ 128 | 1A3CC8E41F54CEB700248D67 /* Resources */ = { 129 | isa = PBXResourcesBuildPhase; 130 | buildActionMask = 2147483647; 131 | files = ( 132 | 1A3CC8F41F54CEB700248D67 /* LaunchScreen.storyboard in Resources */, 133 | 1A3CC8F11F54CEB700248D67 /* Assets.xcassets in Resources */, 134 | 1A3CC8EF1F54CEB700248D67 /* Main.storyboard in Resources */, 135 | ); 136 | runOnlyForDeploymentPostprocessing = 0; 137 | }; 138 | /* End PBXResourcesBuildPhase section */ 139 | 140 | /* Begin PBXSourcesBuildPhase section */ 141 | 1A3CC8E21F54CEB700248D67 /* Sources */ = { 142 | isa = PBXSourcesBuildPhase; 143 | buildActionMask = 2147483647; 144 | files = ( 145 | 1A3CC8EC1F54CEB700248D67 /* ViewController.swift in Sources */, 146 | 1A3CC8FD1F54CF1E00248D67 /* graph_shader.metal in Sources */, 147 | 1A3CC8EA1F54CEB700248D67 /* AppDelegate.swift in Sources */, 148 | 1A3CC8FE1F54CF1E00248D67 /* GraphView.swift in Sources */, 149 | ); 150 | runOnlyForDeploymentPostprocessing = 0; 151 | }; 152 | /* End PBXSourcesBuildPhase section */ 153 | 154 | /* Begin PBXVariantGroup section */ 155 | 1A3CC8ED1F54CEB700248D67 /* Main.storyboard */ = { 156 | isa = PBXVariantGroup; 157 | children = ( 158 | 1A3CC8EE1F54CEB700248D67 /* Base */, 159 | ); 160 | name = Main.storyboard; 161 | sourceTree = ""; 162 | }; 163 | 1A3CC8F21F54CEB700248D67 /* LaunchScreen.storyboard */ = { 164 | isa = PBXVariantGroup; 165 | children = ( 166 | 1A3CC8F31F54CEB700248D67 /* Base */, 167 | ); 168 | name = LaunchScreen.storyboard; 169 | sourceTree = ""; 170 | }; 171 | /* End PBXVariantGroup section */ 172 | 173 | /* Begin XCBuildConfiguration section */ 174 | 1A3CC8F61F54CEB700248D67 /* Debug */ = { 175 | isa = XCBuildConfiguration; 176 | buildSettings = { 177 | ALWAYS_SEARCH_USER_PATHS = NO; 178 | CLANG_ANALYZER_NONNULL = YES; 179 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 180 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 181 | CLANG_CXX_LIBRARY = "libc++"; 182 | CLANG_ENABLE_MODULES = YES; 183 | CLANG_ENABLE_OBJC_ARC = YES; 184 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 185 | CLANG_WARN_BOOL_CONVERSION = YES; 186 | CLANG_WARN_COMMA = YES; 187 | CLANG_WARN_CONSTANT_CONVERSION = YES; 188 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 189 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 190 | CLANG_WARN_EMPTY_BODY = YES; 191 | CLANG_WARN_ENUM_CONVERSION = YES; 192 | CLANG_WARN_INFINITE_RECURSION = YES; 193 | CLANG_WARN_INT_CONVERSION = YES; 194 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 195 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 196 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 197 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 198 | CLANG_WARN_STRICT_PROTOTYPES = YES; 199 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 200 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 201 | CLANG_WARN_UNREACHABLE_CODE = YES; 202 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 203 | CODE_SIGN_IDENTITY = "iPhone Developer"; 204 | COPY_PHASE_STRIP = NO; 205 | DEBUG_INFORMATION_FORMAT = dwarf; 206 | ENABLE_STRICT_OBJC_MSGSEND = YES; 207 | ENABLE_TESTABILITY = YES; 208 | GCC_C_LANGUAGE_STANDARD = gnu11; 209 | GCC_DYNAMIC_NO_PIC = NO; 210 | GCC_NO_COMMON_BLOCKS = YES; 211 | GCC_OPTIMIZATION_LEVEL = 0; 212 | GCC_PREPROCESSOR_DEFINITIONS = ( 213 | "DEBUG=1", 214 | "$(inherited)", 215 | ); 216 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 217 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 218 | GCC_WARN_UNDECLARED_SELECTOR = YES; 219 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 220 | GCC_WARN_UNUSED_FUNCTION = YES; 221 | GCC_WARN_UNUSED_VARIABLE = YES; 222 | IPHONEOS_DEPLOYMENT_TARGET = 11.0; 223 | MTL_ENABLE_DEBUG_INFO = YES; 224 | ONLY_ACTIVE_ARCH = YES; 225 | SDKROOT = iphoneos; 226 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 227 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 228 | }; 229 | name = Debug; 230 | }; 231 | 1A3CC8F71F54CEB700248D67 /* Release */ = { 232 | isa = XCBuildConfiguration; 233 | buildSettings = { 234 | ALWAYS_SEARCH_USER_PATHS = NO; 235 | CLANG_ANALYZER_NONNULL = YES; 236 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 237 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 238 | CLANG_CXX_LIBRARY = "libc++"; 239 | CLANG_ENABLE_MODULES = YES; 240 | CLANG_ENABLE_OBJC_ARC = YES; 241 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 242 | CLANG_WARN_BOOL_CONVERSION = YES; 243 | CLANG_WARN_COMMA = YES; 244 | CLANG_WARN_CONSTANT_CONVERSION = YES; 245 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 246 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 247 | CLANG_WARN_EMPTY_BODY = YES; 248 | CLANG_WARN_ENUM_CONVERSION = YES; 249 | CLANG_WARN_INFINITE_RECURSION = YES; 250 | CLANG_WARN_INT_CONVERSION = YES; 251 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 252 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 253 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 254 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 255 | CLANG_WARN_STRICT_PROTOTYPES = YES; 256 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 257 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 258 | CLANG_WARN_UNREACHABLE_CODE = YES; 259 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 260 | CODE_SIGN_IDENTITY = "iPhone Developer"; 261 | COPY_PHASE_STRIP = NO; 262 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 263 | ENABLE_NS_ASSERTIONS = NO; 264 | ENABLE_STRICT_OBJC_MSGSEND = YES; 265 | GCC_C_LANGUAGE_STANDARD = gnu11; 266 | GCC_NO_COMMON_BLOCKS = YES; 267 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 268 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 269 | GCC_WARN_UNDECLARED_SELECTOR = YES; 270 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 271 | GCC_WARN_UNUSED_FUNCTION = YES; 272 | GCC_WARN_UNUSED_VARIABLE = YES; 273 | IPHONEOS_DEPLOYMENT_TARGET = 11.0; 274 | MTL_ENABLE_DEBUG_INFO = NO; 275 | SDKROOT = iphoneos; 276 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 277 | VALIDATE_PRODUCT = YES; 278 | }; 279 | name = Release; 280 | }; 281 | 1A3CC8F91F54CEB700248D67 /* Debug */ = { 282 | isa = XCBuildConfiguration; 283 | buildSettings = { 284 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 285 | CODE_SIGN_STYLE = Automatic; 286 | DEVELOPMENT_TEAM = 7C938P24Q2; 287 | INFOPLIST_FILE = "GraphView iOS/Info.plist"; 288 | IPHONEOS_DEPLOYMENT_TARGET = 10.3; 289 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 290 | PRODUCT_BUNDLE_IDENTIFIER = "com.vegather.GraphView-iOS"; 291 | PRODUCT_NAME = "$(TARGET_NAME)"; 292 | SWIFT_VERSION = 4.0; 293 | TARGETED_DEVICE_FAMILY = "1,2"; 294 | }; 295 | name = Debug; 296 | }; 297 | 1A3CC8FA1F54CEB700248D67 /* Release */ = { 298 | isa = XCBuildConfiguration; 299 | buildSettings = { 300 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 301 | CODE_SIGN_STYLE = Automatic; 302 | DEVELOPMENT_TEAM = 7C938P24Q2; 303 | INFOPLIST_FILE = "GraphView iOS/Info.plist"; 304 | IPHONEOS_DEPLOYMENT_TARGET = 10.3; 305 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 306 | PRODUCT_BUNDLE_IDENTIFIER = "com.vegather.GraphView-iOS"; 307 | PRODUCT_NAME = "$(TARGET_NAME)"; 308 | SWIFT_VERSION = 4.0; 309 | TARGETED_DEVICE_FAMILY = "1,2"; 310 | }; 311 | name = Release; 312 | }; 313 | /* End XCBuildConfiguration section */ 314 | 315 | /* Begin XCConfigurationList section */ 316 | 1A3CC8E11F54CEB700248D67 /* Build configuration list for PBXProject "GraphView iOS" */ = { 317 | isa = XCConfigurationList; 318 | buildConfigurations = ( 319 | 1A3CC8F61F54CEB700248D67 /* Debug */, 320 | 1A3CC8F71F54CEB700248D67 /* Release */, 321 | ); 322 | defaultConfigurationIsVisible = 0; 323 | defaultConfigurationName = Release; 324 | }; 325 | 1A3CC8F81F54CEB700248D67 /* Build configuration list for PBXNativeTarget "GraphView iOS" */ = { 326 | isa = XCConfigurationList; 327 | buildConfigurations = ( 328 | 1A3CC8F91F54CEB700248D67 /* Debug */, 329 | 1A3CC8FA1F54CEB700248D67 /* Release */, 330 | ); 331 | defaultConfigurationIsVisible = 0; 332 | defaultConfigurationName = Release; 333 | }; 334 | /* End XCConfigurationList section */ 335 | }; 336 | rootObject = 1A3CC8DE1F54CEB700248D67 /* Project object */; 337 | } 338 | -------------------------------------------------------------------------------- /Sample Code/GraphView iOS/GraphView iOS.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Sample Code/GraphView iOS/GraphView iOS/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // GraphView iOS 4 | // 5 | // Created by Vegard Solheim Theriault on 29/08/2017. 6 | // Copyright © 2017 Vegard Solheim Theriault. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | var window: UIWindow? 15 | 16 | 17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { 18 | // Override point for customization after application launch. 19 | return true 20 | } 21 | 22 | func applicationWillResignActive(_ application: UIApplication) { 23 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 24 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 25 | } 26 | 27 | func applicationDidEnterBackground(_ application: UIApplication) { 28 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 29 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 30 | } 31 | 32 | func applicationWillEnterForeground(_ application: UIApplication) { 33 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 34 | } 35 | 36 | func applicationDidBecomeActive(_ application: UIApplication) { 37 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 38 | } 39 | 40 | func applicationWillTerminate(_ application: UIApplication) { 41 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 42 | } 43 | 44 | 45 | } 46 | 47 | -------------------------------------------------------------------------------- /Sample Code/GraphView iOS/GraphView iOS/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "20x20", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "20x20", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "29x29", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "29x29", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "size" : "40x40", 66 | "scale" : "1x" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "size" : "40x40", 71 | "scale" : "2x" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "size" : "76x76", 76 | "scale" : "1x" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "size" : "76x76", 81 | "scale" : "2x" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "size" : "83.5x83.5", 86 | "scale" : "2x" 87 | } 88 | ], 89 | "info" : { 90 | "version" : 1, 91 | "author" : "xcode" 92 | } 93 | } -------------------------------------------------------------------------------- /Sample Code/GraphView iOS/GraphView iOS/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /Sample Code/GraphView iOS/GraphView iOS/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /Sample Code/GraphView iOS/GraphView iOS/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UILaunchStoryboardName 24 | LaunchScreen 25 | UIMainStoryboardFile 26 | Main 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /Sample Code/GraphView iOS/GraphView iOS/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // GraphView iOS 4 | // 5 | // Created by Vegard Solheim Theriault on 29/08/2017. 6 | // Copyright © 2017 Vegard Solheim Theriault. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class ViewController: UIViewController { 12 | 13 | @IBOutlet weak var graph1: GraphView! 14 | @IBOutlet weak var graph2: GraphView! 15 | @IBOutlet weak var graph3: GraphView! 16 | @IBOutlet weak var graph4: GraphView! 17 | 18 | var i: Float = 0 19 | 20 | override func viewDidLoad() { 21 | super.viewDidLoad() 22 | 23 | graph1.backgroundTint = .red 24 | graph1.title = "Orange" 25 | graph1.subtitle = "λ = 590nm" 26 | graph1.capacity = 500 27 | 28 | graph2.backgroundTint = .green 29 | graph2.capacity = 1200 30 | graph2.isAutoscaling = false 31 | graph2.visibleRange = (-18)...3 32 | graph2.title = "Kiwi" 33 | graph2.subtitle = "λ = 530nm" 34 | 35 | graph3.backgroundTint = .blue 36 | graph3.capacity = 1000 37 | graph3.gesturesEnabled = false 38 | graph3.title = "Blueberry" 39 | graph3.subtitle = "λ = 460nm" 40 | 41 | graph4.backgroundTint = .yellow 42 | graph4.capacity = 1400 43 | graph4.title = "Lemon" 44 | graph4.subtitle = "λ = 575nm" 45 | graph4.sampleSize = .large 46 | 47 | let updater = CADisplayLink(target: self, selector: #selector(update)) 48 | updater.add(to: RunLoop.current, forMode: .defaultRunLoopMode) 49 | updater.add(to: RunLoop.current, forMode: .UITrackingRunLoopMode) // Makes sure update is called while scrolling 50 | } 51 | 52 | func square(for input: Float) -> Float { 53 | return stride(from: 1, to: 30, by: 2).reduce(0) { $0 + (1/$1) * sin($1 * input) } 54 | } 55 | 56 | func sawtooth(for input: Float) -> Float { 57 | return stride(from: 1, to: 15, by: 1).reduce(0) { $0 + (1/$1) * sin($1 * input) } 58 | } 59 | 60 | @objc func update() { 61 | let sineValue = sin(i) 62 | 63 | graph1.add(sample: sawtooth(for: i)) 64 | graph2.add(sample: sineValue + sin(i * 5) / 3.0) 65 | graph3.add(sample: sineValue) 66 | graph4.add(sample: square(for: i)) 67 | 68 | i += 0.05 69 | } 70 | 71 | } 72 | 73 | -------------------------------------------------------------------------------- /Sample Code/OS X (deprecated)/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vegather/GraphView/a0bbe2c3963077a1204b0e51cf34df40e423228d/Sample Code/OS X (deprecated)/.DS_Store -------------------------------------------------------------------------------- /Sample Code/OS X (deprecated)/OS X Example/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vegather/GraphView/a0bbe2c3963077a1204b0e51cf34df40e423228d/Sample Code/OS X (deprecated)/OS X Example/.DS_Store -------------------------------------------------------------------------------- /Sample Code/OS X (deprecated)/OS X Example/MOONGraphView/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 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | NSHumanReadableCopyright 24 | Copyright © 2016 MOON Wearables. All rights reserved. 25 | NSPrincipalClass 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /Sample Code/OS X (deprecated)/OS X Example/MOONGraphView/MOONGraphView.h: -------------------------------------------------------------------------------- 1 | // 2 | // MOONGraphView.h 3 | // MOONGraphView 4 | // 5 | // Created by Vegard Solheim Theriault on 07/05/16. 6 | // Copyright © 2016 MOON Wearables. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for MOONGraphView. 12 | FOUNDATION_EXPORT double MOONGraphViewVersionNumber; 13 | 14 | //! Project version string for MOONGraphView. 15 | FOUNDATION_EXPORT const unsigned char MOONGraphViewVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import 18 | 19 | 20 | -------------------------------------------------------------------------------- /Sample Code/OS X (deprecated)/OS X Example/MOONGraphView/MOONGraphView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // GraphView.swift 3 | // OS X Example 4 | // 5 | // Created by Vegard Solheim Theriault on 28/02/16. 6 | // Copyright © 2016 MOON Wearables. All rights reserved. 7 | // 8 | // .___ ___. ______ ______ .__ __. 9 | // | \/ | / __ \ / __ \ | \ | | 10 | // | \ / | | | | | | | | | | \| | 11 | // | |\/| | | | | | | | | | | . ` | 12 | // | | | | | `--' | | `--' | | |\ | 13 | // |__| |__| \______/ \______/ |__| \__| 14 | // ___ _____ _____ _ ___ ___ ___ ___ 15 | // | \| __\ \ / / __| | / _ \| _ \ __| _ \ 16 | // | |) | _| \ V /| _|| |_| (_) | _/ _|| / 17 | // |___/|___| \_/ |___|____\___/|_| |___|_|_\ 18 | // 19 | 20 | 21 | import Cocoa 22 | 23 | private struct Constants { 24 | static let FontName = "HelveticaNeue" 25 | static let ValueLabelWidth : CGFloat = 70.0 26 | static let TickMargin : CGFloat = 15.0 27 | static let TickWidth : CGFloat = 10.0 28 | static let Alpha : CGFloat = 0.6 29 | static let CornerRadius : CGFloat = 10.0 30 | static let GraphWidth : CGFloat = 2.0 31 | static let ScatterPointRadius : CGFloat = 4.0 32 | } 33 | 34 | 35 | @IBDesignable 36 | public class MOONGraphView: NSView { 37 | 38 | public enum GraphColor { 39 | case Gray 40 | case Red 41 | case Green 42 | case Blue 43 | case Turquoise 44 | case Yellow 45 | case Purple 46 | 47 | private func colors() -> [CGColorRef] { 48 | switch self { 49 | case Gray: 50 | return [NSColor(red: 141.0/255.0, green: 140.0/255.0, blue: 146.0/255.0, alpha: 1.0).CGColor, 51 | NSColor(red: 210.0/255.0, green: 209.0/255.0, blue: 215.0/255.0, alpha: 1.0).CGColor] 52 | case .Red: 53 | return [NSColor(red: 253.0/255.0, green: 58.0/255.0, blue: 52.0/255.0, alpha: 1.0).CGColor, 54 | NSColor(red: 255.0/255.0, green: 148.0/255.0, blue: 86.0/255.0, alpha: 1.0).CGColor] 55 | case .Green: 56 | return [NSColor(red: 28.0/255.0, green: 180.0/255.0, blue: 28.0/255.0, alpha: 1.0).CGColor, 57 | NSColor(red: 78.0/255.0, green: 238.0/255.0, blue: 92.0/255.0, alpha: 1.0).CGColor] 58 | case .Blue: 59 | return [NSColor(red: 0.0/255.0, green: 108.0/255.0, blue: 250.0/255.0, alpha: 1.0).CGColor, 60 | NSColor(red: 90.0/255.0, green: 202.0/255.0, blue: 251.0/255.0, alpha: 1.0).CGColor] 61 | case .Turquoise: 62 | return [NSColor(red: 54.0/255.0, green: 174.0/255.0, blue: 220.0/255.0, alpha: 1.0).CGColor, 63 | NSColor(red: 82.0/255.0, green: 234.0/255.0, blue: 208.0/255.0, alpha: 1.0).CGColor] 64 | case .Yellow: 65 | return [NSColor(red: 255.0/255.0, green: 160.0/255.0, blue: 33.0/255.0, alpha: 1.0).CGColor, 66 | NSColor(red: 254.0/255.0, green: 209.0/255.0, blue: 48.0/255.0, alpha: 1.0).CGColor] 67 | case .Purple: 68 | return [NSColor(red: 140.0/255.0, green: 70.0/255.0, blue: 250.0/255.0, alpha: 1.0).CGColor, 69 | NSColor(red: 217.0/255.0, green: 168.0/255.0, blue: 252.0/255.0, alpha: 1.0).CGColor] 70 | } 71 | } 72 | } 73 | 74 | public enum GraphDirection { 75 | case LeftToRight 76 | case RightToLeft 77 | } 78 | 79 | public enum GraphType { 80 | case Line 81 | case Scatter 82 | } 83 | 84 | 85 | 86 | private let gradientBackground = CAGradientLayer() 87 | private var lineView: LineView? 88 | private var accessoryView: AccessoryView? 89 | 90 | 91 | 92 | 93 | // ------------------------------- 94 | // MARK: Initialization 95 | // ------------------------------- 96 | 97 | override public func awakeFromNib() { 98 | super.awakeFromNib() 99 | 100 | addSubviews() 101 | } 102 | 103 | private func addSubviews() { 104 | wantsLayer = true 105 | guard let layer = layer else { return } 106 | 107 | NSBezierPath.setDefaultLineWidth(Constants.GraphWidth) 108 | 109 | gradientBackground.frame = layer.bounds 110 | gradientBackground.colors = themeColor.colors() 111 | gradientBackground.cornerRadius = roundedCorners ? Constants.CornerRadius : 0.0 112 | gradientBackground.removeAllAnimations() 113 | layer.addSublayer(gradientBackground) 114 | 115 | lineView = LineView(frame: bounds) 116 | lineView!.maxSamples = maxSamples 117 | lineView!.maxValue = maxValue 118 | lineView!.minValue = minValue 119 | lineView!.graphDirection = graphDirection 120 | lineView!.numberOfGraphs = numberOfGraphs 121 | lineView!.cornerRadius = roundedCorners ? Constants.CornerRadius : 0.0 122 | lineView!.graphType = graphType 123 | addSubview(lineView!) 124 | 125 | accessoryView = AccessoryView(frame: bounds) 126 | accessoryView!.title = title 127 | accessoryView!.subtitle = subtitle 128 | accessoryView!.maxValue = maxValue 129 | accessoryView!.minValue = minValue 130 | accessoryView!.graphDirection = graphDirection 131 | addSubview(accessoryView!) 132 | } 133 | 134 | 135 | 136 | 137 | // ------------------------------- 138 | // MARK: Public API 139 | // ------------------------------- 140 | 141 | /// Used to set the title of the graph in one of the upper corners. The default value for this is `""`, meaning that it will not be displayed. 142 | @IBInspectable public var title: String = "" { 143 | didSet { 144 | accessoryView?.title = title 145 | } 146 | } 147 | 148 | /// Used to set a subtitle that will go right underneath the title. The default value for this is `""`, and will thus not be displayed. 149 | @IBInspectable public var subtitle: String = "" { 150 | didSet { 151 | accessoryView?.subtitle = subtitle 152 | } 153 | } 154 | 155 | /// Specifies which way the graph will go. This is an enum with two possible options: `.LeftToRight`, and `.RightToLeft`. Setting this will also change which corner the title and subtitle will get drawn in (upper left corner for `.RightToLeft`, and vice versa). It also changes which side the values for the y-axis gets drawn (right side for `.RightToLeft`, and vice versa). The default is `.RightToLeft`. 156 | public var graphDirection = GraphDirection.RightToLeft { 157 | didSet { 158 | accessoryView?.graphDirection = graphDirection 159 | lineView?.graphDirection = graphDirection 160 | } 161 | } 162 | 163 | /// This will set the background gradient of the graph. It's an enum with seven colors to pick from: `.Gray`, `.Red`, `.Green`, `.Blue`, `.Turquoise`, `.Yellow`, and `.Purple`. The default is `.Red`. 164 | public var themeColor = GraphColor.Red { 165 | didSet { 166 | gradientBackground.colors = themeColor.colors() 167 | } 168 | } 169 | 170 | /// This sets how many samples will fit within the view. E.g., if you set this to 200, what you will see in the view is the last 200 samples. You can't set it to any lower than 2 (for obvious reasons). The default value of this is 150. 171 | public var maxSamples = 150 { 172 | didSet { 173 | lineView?.maxSamples = max(2, maxSamples) 174 | } 175 | } 176 | 177 | /// Determines what the maximum expected value is. It is used as an upper limit for the view. The default is 1.0. 178 | @IBInspectable public var maxValue: CGFloat = 1.0 { 179 | didSet { 180 | accessoryView?.maxValue = maxValue 181 | lineView?.maxValue = maxValue 182 | } 183 | } 184 | 185 | /// Determines what the minimum expected value is. It is used as an lower limit for the view. The default is -1.0. 186 | @IBInspectable public var minValue: CGFloat = -1.0 { 187 | didSet { 188 | accessoryView?.minValue = minValue 189 | lineView?.minValue = minValue 190 | } 191 | } 192 | 193 | /// If you want your view to draw more than one graph at the same time (say x, y, z values of an accelerometer), you can specify that using this property. Notice that the `addSamples` method takes an argument of type `Double...` (called a variadic parameter). Whatever value you set for the `numberOfGraphs` property, you need to pass in the same number of arguments to this method, otherwise it will do nothing. If you change this property, all the samples you've added so far will be removed. The default is 1, meaning the `addSamples` method takes 1 argument. 194 | public var numberOfGraphs = 1 { 195 | didSet { 196 | lineView?.numberOfGraphs = max(1, numberOfGraphs) 197 | } 198 | } 199 | 200 | /// Use this to make the corners rounded or square. The default is true, meaning rounded corners. 201 | @IBInspectable public var roundedCorners = true { 202 | didSet { 203 | gradientBackground.cornerRadius = roundedCorners ? Constants.CornerRadius : 0.0 204 | lineView?.cornerRadius = roundedCorners ? Constants.CornerRadius : 0.0 205 | } 206 | } 207 | 208 | /// Changes how the samples are drawn. The current options are .Line and .Scatter. The default is .Line 209 | public var graphType = GraphType.Line { 210 | didSet { 211 | lineView?.graphType = graphType 212 | } 213 | } 214 | 215 | /// This method is where you add your data to the graph. The value of the samples you add should be within the range `[minValue, maxValue]`, otherwise the graph will draw outside the view. Notice that this takes `Double...` as an argument (called a variadic parameter), which means that you can pass it one or more `Double` values as arguments. This is so that you can draw multiple graphs in the same view at the same time (say x, y, z data from an accelerometer). The number of arguments you pass needs to correspond to the `numberOfGraphs` property, otherwise this method will do nothing. 216 | public func addSamples(newSamples: Double...) { 217 | lineView?.addSamples(newSamples) 218 | } 219 | 220 | /// Removes all the samples you've added to the graph. All the other properties like `roundedCorners` and `maxSamples` etc are kept the same. Useful if you want to reuse the same graph view. 221 | public func reset() { 222 | lineView?.reset() 223 | } 224 | 225 | 226 | 227 | 228 | // ------------------------------- 229 | // MARK: Drawing 230 | // ------------------------------- 231 | 232 | override public func layoutSublayersOfLayer(layer: CALayer) { 233 | if let selfLayer = self.layer { 234 | gradientBackground.frame = selfLayer.bounds 235 | accessoryView?.frame = selfLayer.bounds 236 | lineView?.frame = selfLayer.bounds 237 | } 238 | 239 | gradientBackground.removeAllAnimations() 240 | } 241 | 242 | override public func prepareForInterfaceBuilder() { 243 | addSubviews() 244 | 245 | if title == "" { title = "Heading" } 246 | if subtitle == "" { subtitle = "Subtitle" } 247 | 248 | for i in 0.. 0 else { continue } // Skip the first one 374 | 375 | let x1: CGFloat = currentXValue 376 | let y1: CGFloat = (CGFloat(sample) - minValue) * pointsToSampleValueRatio + Constants.TickMargin 377 | let point1 = NSPoint(x: x1, y: y1) 378 | 379 | switch graphType { 380 | case .Line: 381 | var x2 = currentXValue 382 | switch graphDirection { 383 | case .RightToLeft: x2 -= widthPerSample 384 | case .LeftToRight: x2 += widthPerSample 385 | } 386 | 387 | let y2: CGFloat = (CGFloat(samples[index - 1]) - minValue) * pointsToSampleValueRatio + Constants.TickMargin 388 | let point2 = NSPoint(x: x2, y: y2) 389 | 390 | NSBezierPath.strokeLineFromPoint(point1, toPoint: point2) 391 | 392 | case .Scatter: 393 | NSBezierPath(ovalInRect: NSRect( 394 | x: x1 - Constants.ScatterPointRadius / 2.0, 395 | y: y1 - Constants.ScatterPointRadius / 2.0, 396 | width: Constants.ScatterPointRadius, 397 | height: Constants.ScatterPointRadius 398 | ) 399 | ).fill() 400 | } 401 | 402 | switch graphDirection { 403 | case .RightToLeft: currentXValue += widthPerSample 404 | case .LeftToRight: currentXValue -= widthPerSample 405 | } 406 | } 407 | } 408 | } 409 | 410 | 411 | } 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | private class AccessoryView: NSView { 420 | 421 | 422 | // ------------------------------- 423 | // MARK: Properties 424 | // ------------------------------- 425 | 426 | var title = "" { 427 | didSet { setNeedsDisplayInRect(bounds) } 428 | } 429 | 430 | var subtitle = "" { 431 | didSet { setNeedsDisplayInRect(bounds) } 432 | } 433 | 434 | var maxValue: CGFloat = 0.0 { 435 | didSet { setNeedsDisplayInRect(bounds) } 436 | } 437 | 438 | var minValue: CGFloat = 0.0 { 439 | didSet { setNeedsDisplayInRect(bounds) } 440 | } 441 | 442 | var graphDirection = MOONGraphView.GraphDirection.LeftToRight { 443 | didSet { setNeedsDisplayInRect(bounds) } 444 | } 445 | 446 | 447 | 448 | 449 | // ------------------------------- 450 | // MARK: Drawing 451 | // ------------------------------- 452 | 453 | override func drawRect(dirtyRect: NSRect) { 454 | // drawValueLabelsFill() // Not yet sure if I prefer this on or off 455 | drawSeparatorLine() 456 | drawTicks() 457 | drawValueLabels() 458 | drawInformationLabels() 459 | } 460 | 461 | private func drawValueLabelsFill() { 462 | let fill = NSBezierPath() 463 | 464 | switch graphDirection { 465 | case .RightToLeft: 466 | fill.moveToPoint(NSPoint(x: bounds.width - Constants.ValueLabelWidth, y: 0.0)) 467 | fill.lineToPoint(NSPoint(x: bounds.width, y: 0.0)) 468 | fill.lineToPoint(NSPoint(x: bounds.width, y: bounds.height)) 469 | fill.lineToPoint(NSPoint(x: bounds.width - Constants.ValueLabelWidth, y: bounds.height)) 470 | case .LeftToRight: 471 | fill.moveToPoint(NSPoint(x: 0.0, y: 0.0)) 472 | fill.lineToPoint(NSPoint(x: Constants.ValueLabelWidth, y: 0.0)) 473 | fill.lineToPoint(NSPoint(x: Constants.ValueLabelWidth, y: bounds.height)) 474 | fill.lineToPoint(NSPoint(x: 0.0, y: bounds.height)) 475 | } 476 | 477 | NSColor(white: 1.0, alpha: 0.2).setFill() 478 | fill.fill() 479 | } 480 | 481 | private func drawSeparatorLine() { 482 | let separatorLine = NSBezierPath() 483 | 484 | switch graphDirection { 485 | case .RightToLeft: 486 | separatorLine.moveToPoint(NSPoint(x: bounds.width - Constants.ValueLabelWidth, y: 0.0)) 487 | separatorLine.lineToPoint(NSPoint(x: bounds.width - Constants.ValueLabelWidth, y: bounds.height)) 488 | case .LeftToRight: 489 | separatorLine.moveToPoint(NSPoint(x: Constants.ValueLabelWidth, y: 0.0)) 490 | separatorLine.lineToPoint(NSPoint(x: Constants.ValueLabelWidth, y: bounds.height)) 491 | } 492 | 493 | NSColor(white: 1.0, alpha: Constants.Alpha).setStroke() 494 | separatorLine.lineWidth = 1.0 495 | separatorLine.stroke() 496 | } 497 | 498 | private func drawTicks() { 499 | let tick1 = NSBezierPath() 500 | let tick2 = NSBezierPath() 501 | let tick3 = NSBezierPath() 502 | 503 | switch graphDirection { 504 | case .RightToLeft: 505 | tick1.moveToPoint(NSPoint(x: bounds.width - Constants.ValueLabelWidth, y: Constants.TickMargin)) 506 | tick1.lineToPoint(NSPoint(x: bounds.width - Constants.ValueLabelWidth + Constants.TickWidth, y: Constants.TickMargin)) 507 | 508 | tick2.moveToPoint(NSPoint(x: bounds.width - Constants.ValueLabelWidth, y: bounds.height / 2.0)) 509 | tick2.lineToPoint(NSPoint(x: bounds.width - Constants.ValueLabelWidth + Constants.TickWidth / 2.0, y: bounds.height / 2.0)) 510 | 511 | tick3.moveToPoint(NSPoint(x: bounds.width - Constants.ValueLabelWidth, y: bounds.height - Constants.TickMargin)) 512 | tick3.lineToPoint(NSPoint(x: bounds.width - Constants.ValueLabelWidth + Constants.TickWidth, y: bounds.height - Constants.TickMargin)) 513 | case .LeftToRight: 514 | tick1.moveToPoint(NSPoint(x: Constants.ValueLabelWidth, y: Constants.TickMargin)) 515 | tick1.lineToPoint(NSPoint(x: Constants.ValueLabelWidth - Constants.TickWidth, y: Constants.TickMargin)) 516 | 517 | tick2.moveToPoint(NSPoint(x: Constants.ValueLabelWidth, y: bounds.height / 2.0)) 518 | tick2.lineToPoint(NSPoint(x: Constants.ValueLabelWidth - Constants.TickWidth / 2.0, y: bounds.height / 2.0)) 519 | 520 | tick3.moveToPoint(NSPoint(x: Constants.ValueLabelWidth, y: bounds.height - Constants.TickMargin)) 521 | tick3.lineToPoint(NSPoint(x: Constants.ValueLabelWidth - Constants.TickWidth, y: bounds.height - Constants.TickMargin)) 522 | } 523 | 524 | NSColor(white: 1.0, alpha: Constants.Alpha).setStroke() 525 | tick1.lineWidth = 1.0 526 | tick2.lineWidth = 1.0 527 | tick3.lineWidth = 1.0 528 | tick1.stroke() 529 | tick2.stroke() 530 | tick3.stroke() 531 | } 532 | 533 | private func drawValueLabels() { 534 | let attributes = [ 535 | NSFontAttributeName : NSFont(name: Constants.FontName, size: 15)!, 536 | NSForegroundColorAttributeName: NSColor(white: 1.0, alpha: 0.8) 537 | ] as Dictionary 538 | 539 | let label1 = NSAttributedString(string: String(format: "%.2f", arguments: [minValue]), attributes: attributes) 540 | let label2 = NSAttributedString(string: String(format: "%.2f", arguments: [(maxValue-minValue)/2.0 + minValue]), attributes: attributes) 541 | let label3 = NSAttributedString(string: String(format: "%.2f", arguments: [maxValue]), attributes: attributes) 542 | 543 | let alignmentCoefficient: CGFloat = 2.0 544 | 545 | switch graphDirection { 546 | case .RightToLeft: 547 | let x = bounds.width - Constants.ValueLabelWidth + Constants.TickWidth + 5.0 548 | label1.drawInRect(NSRect( 549 | x : x, 550 | y : Constants.TickMargin - (label1.size().height / 2.0) + alignmentCoefficient, 551 | width : label1.size().width, 552 | height : label1.size().height) 553 | ) 554 | label2.drawInRect(NSRect( 555 | x : x, 556 | y: bounds.height / 2.0 - (label2.size().height / 2.0) + alignmentCoefficient, 557 | width : label2.size().width, 558 | height : label2.size().height) 559 | ) 560 | label3.drawInRect(NSRect( 561 | x : x, 562 | y : bounds.height - Constants.TickMargin - (label3.size().height / 2.0) + alignmentCoefficient, 563 | width : label3.size().width, 564 | height : label3.size().height) 565 | ) 566 | case .LeftToRight: 567 | let x = Constants.ValueLabelWidth - Constants.TickWidth - 5.0 568 | label1.drawInRect(NSRect( 569 | x : x - label1.size().width, 570 | y : Constants.TickMargin - (label1.size().height / 2.0) + alignmentCoefficient, 571 | width : label1.size().width, 572 | height : label1.size().height) 573 | ) 574 | label2.drawInRect(NSRect( 575 | x : x - label2.size().width, 576 | y : bounds.height / 2.0 - (label2.size().height / 2.0) + alignmentCoefficient, 577 | width : label2.size().width, 578 | height : label2.size().height) 579 | ) 580 | label3.drawInRect(NSRect( 581 | x : x - label3.size().width, 582 | y : bounds.height - Constants.TickMargin - (label3.size().height / 2.0) + alignmentCoefficient, 583 | width : label3.size().width, 584 | height : label3.size().height) 585 | ) 586 | } 587 | } 588 | 589 | private func drawInformationLabels() { 590 | let titleAttributes = [ 591 | NSFontAttributeName : NSFont(name: Constants.FontName, size: 30)!, 592 | NSForegroundColorAttributeName: NSColor.whiteColor() 593 | ] as Dictionary 594 | 595 | let subTitleAttributes = [ 596 | NSFontAttributeName : NSFont(name: Constants.FontName, size: 20)!, 597 | NSForegroundColorAttributeName: NSColor(white: 1.0, alpha: Constants.Alpha) 598 | ] as Dictionary 599 | 600 | let titleLabel = NSAttributedString(string: title, attributes: titleAttributes) 601 | let subTitleLabel = NSAttributedString(string: subtitle, attributes: subTitleAttributes) 602 | 603 | let horizontalMargin : CGFloat = 20.0 604 | let verticalMargin : CGFloat = 30.0 605 | 606 | let titleY = bounds.height - titleLabel.size().height - horizontalMargin 607 | let subTitleY = titleY - subTitleLabel.size().height 608 | 609 | switch graphDirection { 610 | case .RightToLeft: 611 | titleLabel .drawInRect(NSRect( 612 | x : verticalMargin, 613 | y : titleY, 614 | width : titleLabel.size().width, 615 | height : titleLabel.size().height) 616 | ) 617 | subTitleLabel.drawInRect(NSRect( 618 | x : verticalMargin, 619 | y : subTitleY, 620 | width : subTitleLabel.size().width, 621 | height : subTitleLabel.size().height)) 622 | case .LeftToRight: 623 | let x = bounds.width - verticalMargin - max(titleLabel.size().width, subTitleLabel.size().width) 624 | titleLabel .drawInRect(NSRect( 625 | x : x, 626 | y : titleY, 627 | width : titleLabel.size().width, 628 | height : titleLabel.size().height) 629 | ) 630 | subTitleLabel.drawInRect(NSRect( 631 | x : x, 632 | y : subTitleY, 633 | width : subTitleLabel.size().width, 634 | height : subTitleLabel.size().height) 635 | ) 636 | } 637 | } 638 | 639 | } 640 | 641 | -------------------------------------------------------------------------------- /Sample Code/OS X (deprecated)/OS X Example/OS X Example.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 9A2555C81C8384AD00951A57 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A2555C71C8384AD00951A57 /* AppDelegate.swift */; }; 11 | 9A2555CA1C8384AD00951A57 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A2555C91C8384AD00951A57 /* ViewController.swift */; }; 12 | 9A2555CC1C8384AD00951A57 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 9A2555CB1C8384AD00951A57 /* Assets.xcassets */; }; 13 | 9A4B7B341CDE55BC003E94A8 /* MOONGraphView.h in Headers */ = {isa = PBXBuildFile; fileRef = 9A4B7B331CDE55BC003E94A8 /* MOONGraphView.h */; settings = {ATTRIBUTES = (Public, ); }; }; 14 | 9A4B7B381CDE55BC003E94A8 /* MOONGraphView.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9A4B7B311CDE55BC003E94A8 /* MOONGraphView.framework */; }; 15 | 9A4B7B391CDE55BC003E94A8 /* MOONGraphView.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9A4B7B311CDE55BC003E94A8 /* MOONGraphView.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 16 | 9A4B7B3E1CDE55D4003E94A8 /* MOONGraphView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A4B7B3D1CDE55D4003E94A8 /* MOONGraphView.swift */; }; 17 | 9AC405831C862EB7006B02D4 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 9AC405811C862EB7006B02D4 /* Main.storyboard */; }; 18 | /* End PBXBuildFile section */ 19 | 20 | /* Begin PBXContainerItemProxy section */ 21 | 9A4B7B361CDE55BC003E94A8 /* PBXContainerItemProxy */ = { 22 | isa = PBXContainerItemProxy; 23 | containerPortal = 9A2555BC1C8384AD00951A57 /* Project object */; 24 | proxyType = 1; 25 | remoteGlobalIDString = 9A4B7B301CDE55BC003E94A8; 26 | remoteInfo = MOONGraphView; 27 | }; 28 | /* End PBXContainerItemProxy section */ 29 | 30 | /* Begin PBXCopyFilesBuildPhase section */ 31 | 9A4B7B2A1CDE4BF1003E94A8 /* Embed Frameworks */ = { 32 | isa = PBXCopyFilesBuildPhase; 33 | buildActionMask = 2147483647; 34 | dstPath = ""; 35 | dstSubfolderSpec = 10; 36 | files = ( 37 | 9A4B7B391CDE55BC003E94A8 /* MOONGraphView.framework in Embed Frameworks */, 38 | ); 39 | name = "Embed Frameworks"; 40 | runOnlyForDeploymentPostprocessing = 0; 41 | }; 42 | /* End PBXCopyFilesBuildPhase section */ 43 | 44 | /* Begin PBXFileReference section */ 45 | 9A2555C41C8384AD00951A57 /* OS X Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "OS X Example.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 46 | 9A2555C71C8384AD00951A57 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 47 | 9A2555C91C8384AD00951A57 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 48 | 9A2555CB1C8384AD00951A57 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 49 | 9A2555D01C8384AD00951A57 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 50 | 9A4B7B311CDE55BC003E94A8 /* MOONGraphView.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = MOONGraphView.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 51 | 9A4B7B331CDE55BC003E94A8 /* MOONGraphView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MOONGraphView.h; sourceTree = ""; }; 52 | 9A4B7B351CDE55BC003E94A8 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 53 | 9A4B7B3D1CDE55D4003E94A8 /* MOONGraphView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MOONGraphView.swift; sourceTree = ""; }; 54 | 9AC405821C862EB7006B02D4 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 55 | /* End PBXFileReference section */ 56 | 57 | /* Begin PBXFrameworksBuildPhase section */ 58 | 9A2555C11C8384AD00951A57 /* Frameworks */ = { 59 | isa = PBXFrameworksBuildPhase; 60 | buildActionMask = 2147483647; 61 | files = ( 62 | 9A4B7B381CDE55BC003E94A8 /* MOONGraphView.framework in Frameworks */, 63 | ); 64 | runOnlyForDeploymentPostprocessing = 0; 65 | }; 66 | 9A4B7B2D1CDE55BC003E94A8 /* Frameworks */ = { 67 | isa = PBXFrameworksBuildPhase; 68 | buildActionMask = 2147483647; 69 | files = ( 70 | ); 71 | runOnlyForDeploymentPostprocessing = 0; 72 | }; 73 | /* End PBXFrameworksBuildPhase section */ 74 | 75 | /* Begin PBXGroup section */ 76 | 9A2555BB1C8384AD00951A57 = { 77 | isa = PBXGroup; 78 | children = ( 79 | 9A2555C61C8384AD00951A57 /* OS X Example */, 80 | 9A4B7B321CDE55BC003E94A8 /* MOONGraphView */, 81 | 9A2555C51C8384AD00951A57 /* Products */, 82 | ); 83 | sourceTree = ""; 84 | }; 85 | 9A2555C51C8384AD00951A57 /* Products */ = { 86 | isa = PBXGroup; 87 | children = ( 88 | 9A2555C41C8384AD00951A57 /* OS X Example.app */, 89 | 9A4B7B311CDE55BC003E94A8 /* MOONGraphView.framework */, 90 | ); 91 | name = Products; 92 | sourceTree = ""; 93 | }; 94 | 9A2555C61C8384AD00951A57 /* OS X Example */ = { 95 | isa = PBXGroup; 96 | children = ( 97 | 9A2555C91C8384AD00951A57 /* ViewController.swift */, 98 | 9AC405811C862EB7006B02D4 /* Main.storyboard */, 99 | 9A2555DA1C83864D00951A57 /* Supporting Files */, 100 | ); 101 | path = "OS X Example"; 102 | sourceTree = ""; 103 | }; 104 | 9A2555DA1C83864D00951A57 /* Supporting Files */ = { 105 | isa = PBXGroup; 106 | children = ( 107 | 9A2555C71C8384AD00951A57 /* AppDelegate.swift */, 108 | 9A2555CB1C8384AD00951A57 /* Assets.xcassets */, 109 | 9A2555D01C8384AD00951A57 /* Info.plist */, 110 | ); 111 | name = "Supporting Files"; 112 | sourceTree = ""; 113 | }; 114 | 9A4B7B321CDE55BC003E94A8 /* MOONGraphView */ = { 115 | isa = PBXGroup; 116 | children = ( 117 | 9A4B7B3D1CDE55D4003E94A8 /* MOONGraphView.swift */, 118 | 9A4B7B331CDE55BC003E94A8 /* MOONGraphView.h */, 119 | 9A4B7B351CDE55BC003E94A8 /* Info.plist */, 120 | ); 121 | path = MOONGraphView; 122 | sourceTree = ""; 123 | }; 124 | /* End PBXGroup section */ 125 | 126 | /* Begin PBXHeadersBuildPhase section */ 127 | 9A4B7B2E1CDE55BC003E94A8 /* Headers */ = { 128 | isa = PBXHeadersBuildPhase; 129 | buildActionMask = 2147483647; 130 | files = ( 131 | 9A4B7B341CDE55BC003E94A8 /* MOONGraphView.h in Headers */, 132 | ); 133 | runOnlyForDeploymentPostprocessing = 0; 134 | }; 135 | /* End PBXHeadersBuildPhase section */ 136 | 137 | /* Begin PBXNativeTarget section */ 138 | 9A2555C31C8384AD00951A57 /* OS X Example */ = { 139 | isa = PBXNativeTarget; 140 | buildConfigurationList = 9A2555D31C8384AD00951A57 /* Build configuration list for PBXNativeTarget "OS X Example" */; 141 | buildPhases = ( 142 | 9A2555C01C8384AD00951A57 /* Sources */, 143 | 9A2555C11C8384AD00951A57 /* Frameworks */, 144 | 9A2555C21C8384AD00951A57 /* Resources */, 145 | 9A4B7B2A1CDE4BF1003E94A8 /* Embed Frameworks */, 146 | ); 147 | buildRules = ( 148 | ); 149 | dependencies = ( 150 | 9A4B7B371CDE55BC003E94A8 /* PBXTargetDependency */, 151 | ); 152 | name = "OS X Example"; 153 | productName = "OS X Example"; 154 | productReference = 9A2555C41C8384AD00951A57 /* OS X Example.app */; 155 | productType = "com.apple.product-type.application"; 156 | }; 157 | 9A4B7B301CDE55BC003E94A8 /* MOONGraphView */ = { 158 | isa = PBXNativeTarget; 159 | buildConfigurationList = 9A4B7B3A1CDE55BC003E94A8 /* Build configuration list for PBXNativeTarget "MOONGraphView" */; 160 | buildPhases = ( 161 | 9A4B7B2C1CDE55BC003E94A8 /* Sources */, 162 | 9A4B7B2D1CDE55BC003E94A8 /* Frameworks */, 163 | 9A4B7B2E1CDE55BC003E94A8 /* Headers */, 164 | 9A4B7B2F1CDE55BC003E94A8 /* Resources */, 165 | ); 166 | buildRules = ( 167 | ); 168 | dependencies = ( 169 | ); 170 | name = MOONGraphView; 171 | productName = MOONGraphView; 172 | productReference = 9A4B7B311CDE55BC003E94A8 /* MOONGraphView.framework */; 173 | productType = "com.apple.product-type.framework"; 174 | }; 175 | /* End PBXNativeTarget section */ 176 | 177 | /* Begin PBXProject section */ 178 | 9A2555BC1C8384AD00951A57 /* Project object */ = { 179 | isa = PBXProject; 180 | attributes = { 181 | LastSwiftUpdateCheck = 0730; 182 | LastUpgradeCheck = 0720; 183 | ORGANIZATIONNAME = "MOON Wearables"; 184 | TargetAttributes = { 185 | 9A2555C31C8384AD00951A57 = { 186 | CreatedOnToolsVersion = 7.2.1; 187 | }; 188 | 9A4B7B301CDE55BC003E94A8 = { 189 | CreatedOnToolsVersion = 7.3.1; 190 | }; 191 | }; 192 | }; 193 | buildConfigurationList = 9A2555BF1C8384AD00951A57 /* Build configuration list for PBXProject "OS X Example" */; 194 | compatibilityVersion = "Xcode 3.2"; 195 | developmentRegion = English; 196 | hasScannedForEncodings = 0; 197 | knownRegions = ( 198 | en, 199 | Base, 200 | ); 201 | mainGroup = 9A2555BB1C8384AD00951A57; 202 | productRefGroup = 9A2555C51C8384AD00951A57 /* Products */; 203 | projectDirPath = ""; 204 | projectRoot = ""; 205 | targets = ( 206 | 9A2555C31C8384AD00951A57 /* OS X Example */, 207 | 9A4B7B301CDE55BC003E94A8 /* MOONGraphView */, 208 | ); 209 | }; 210 | /* End PBXProject section */ 211 | 212 | /* Begin PBXResourcesBuildPhase section */ 213 | 9A2555C21C8384AD00951A57 /* Resources */ = { 214 | isa = PBXResourcesBuildPhase; 215 | buildActionMask = 2147483647; 216 | files = ( 217 | 9A2555CC1C8384AD00951A57 /* Assets.xcassets in Resources */, 218 | 9AC405831C862EB7006B02D4 /* Main.storyboard in Resources */, 219 | ); 220 | runOnlyForDeploymentPostprocessing = 0; 221 | }; 222 | 9A4B7B2F1CDE55BC003E94A8 /* Resources */ = { 223 | isa = PBXResourcesBuildPhase; 224 | buildActionMask = 2147483647; 225 | files = ( 226 | ); 227 | runOnlyForDeploymentPostprocessing = 0; 228 | }; 229 | /* End PBXResourcesBuildPhase section */ 230 | 231 | /* Begin PBXSourcesBuildPhase section */ 232 | 9A2555C01C8384AD00951A57 /* Sources */ = { 233 | isa = PBXSourcesBuildPhase; 234 | buildActionMask = 2147483647; 235 | files = ( 236 | 9A2555CA1C8384AD00951A57 /* ViewController.swift in Sources */, 237 | 9A2555C81C8384AD00951A57 /* AppDelegate.swift in Sources */, 238 | ); 239 | runOnlyForDeploymentPostprocessing = 0; 240 | }; 241 | 9A4B7B2C1CDE55BC003E94A8 /* Sources */ = { 242 | isa = PBXSourcesBuildPhase; 243 | buildActionMask = 2147483647; 244 | files = ( 245 | 9A4B7B3E1CDE55D4003E94A8 /* MOONGraphView.swift in Sources */, 246 | ); 247 | runOnlyForDeploymentPostprocessing = 0; 248 | }; 249 | /* End PBXSourcesBuildPhase section */ 250 | 251 | /* Begin PBXTargetDependency section */ 252 | 9A4B7B371CDE55BC003E94A8 /* PBXTargetDependency */ = { 253 | isa = PBXTargetDependency; 254 | target = 9A4B7B301CDE55BC003E94A8 /* MOONGraphView */; 255 | targetProxy = 9A4B7B361CDE55BC003E94A8 /* PBXContainerItemProxy */; 256 | }; 257 | /* End PBXTargetDependency section */ 258 | 259 | /* Begin PBXVariantGroup section */ 260 | 9AC405811C862EB7006B02D4 /* Main.storyboard */ = { 261 | isa = PBXVariantGroup; 262 | children = ( 263 | 9AC405821C862EB7006B02D4 /* Base */, 264 | ); 265 | name = Main.storyboard; 266 | sourceTree = ""; 267 | }; 268 | /* End PBXVariantGroup section */ 269 | 270 | /* Begin XCBuildConfiguration section */ 271 | 9A2555D11C8384AD00951A57 /* Debug */ = { 272 | isa = XCBuildConfiguration; 273 | buildSettings = { 274 | ALWAYS_SEARCH_USER_PATHS = NO; 275 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 276 | CLANG_CXX_LIBRARY = "libc++"; 277 | CLANG_ENABLE_MODULES = YES; 278 | CLANG_ENABLE_OBJC_ARC = YES; 279 | CLANG_WARN_BOOL_CONVERSION = YES; 280 | CLANG_WARN_CONSTANT_CONVERSION = YES; 281 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 282 | CLANG_WARN_EMPTY_BODY = YES; 283 | CLANG_WARN_ENUM_CONVERSION = YES; 284 | CLANG_WARN_INT_CONVERSION = YES; 285 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 286 | CLANG_WARN_UNREACHABLE_CODE = YES; 287 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 288 | CODE_SIGN_IDENTITY = "-"; 289 | COPY_PHASE_STRIP = NO; 290 | DEBUG_INFORMATION_FORMAT = dwarf; 291 | ENABLE_STRICT_OBJC_MSGSEND = YES; 292 | ENABLE_TESTABILITY = YES; 293 | GCC_C_LANGUAGE_STANDARD = gnu99; 294 | GCC_DYNAMIC_NO_PIC = NO; 295 | GCC_NO_COMMON_BLOCKS = YES; 296 | GCC_OPTIMIZATION_LEVEL = 0; 297 | GCC_PREPROCESSOR_DEFINITIONS = ( 298 | "DEBUG=1", 299 | "$(inherited)", 300 | ); 301 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 302 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 303 | GCC_WARN_UNDECLARED_SELECTOR = YES; 304 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 305 | GCC_WARN_UNUSED_FUNCTION = YES; 306 | GCC_WARN_UNUSED_VARIABLE = YES; 307 | MACOSX_DEPLOYMENT_TARGET = 10.11; 308 | MTL_ENABLE_DEBUG_INFO = YES; 309 | ONLY_ACTIVE_ARCH = YES; 310 | SDKROOT = macosx; 311 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 312 | }; 313 | name = Debug; 314 | }; 315 | 9A2555D21C8384AD00951A57 /* Release */ = { 316 | isa = XCBuildConfiguration; 317 | buildSettings = { 318 | ALWAYS_SEARCH_USER_PATHS = NO; 319 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 320 | CLANG_CXX_LIBRARY = "libc++"; 321 | CLANG_ENABLE_MODULES = YES; 322 | CLANG_ENABLE_OBJC_ARC = YES; 323 | CLANG_WARN_BOOL_CONVERSION = YES; 324 | CLANG_WARN_CONSTANT_CONVERSION = YES; 325 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 326 | CLANG_WARN_EMPTY_BODY = YES; 327 | CLANG_WARN_ENUM_CONVERSION = YES; 328 | CLANG_WARN_INT_CONVERSION = YES; 329 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 330 | CLANG_WARN_UNREACHABLE_CODE = YES; 331 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 332 | CODE_SIGN_IDENTITY = "-"; 333 | COPY_PHASE_STRIP = NO; 334 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 335 | ENABLE_NS_ASSERTIONS = NO; 336 | ENABLE_STRICT_OBJC_MSGSEND = YES; 337 | GCC_C_LANGUAGE_STANDARD = gnu99; 338 | GCC_NO_COMMON_BLOCKS = YES; 339 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 340 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 341 | GCC_WARN_UNDECLARED_SELECTOR = YES; 342 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 343 | GCC_WARN_UNUSED_FUNCTION = YES; 344 | GCC_WARN_UNUSED_VARIABLE = YES; 345 | MACOSX_DEPLOYMENT_TARGET = 10.11; 346 | MTL_ENABLE_DEBUG_INFO = NO; 347 | SDKROOT = macosx; 348 | }; 349 | name = Release; 350 | }; 351 | 9A2555D41C8384AD00951A57 /* Debug */ = { 352 | isa = XCBuildConfiguration; 353 | buildSettings = { 354 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 355 | COMBINE_HIDPI_IMAGES = YES; 356 | EMBEDDED_CONTENT_CONTAINS_SWIFT = YES; 357 | INFOPLIST_FILE = "OS X Example/Info.plist"; 358 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; 359 | PRODUCT_BUNDLE_IDENTIFIER = "com.moonwearables.OS-X-Example"; 360 | PRODUCT_NAME = "$(TARGET_NAME)"; 361 | }; 362 | name = Debug; 363 | }; 364 | 9A2555D51C8384AD00951A57 /* Release */ = { 365 | isa = XCBuildConfiguration; 366 | buildSettings = { 367 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 368 | COMBINE_HIDPI_IMAGES = YES; 369 | EMBEDDED_CONTENT_CONTAINS_SWIFT = YES; 370 | INFOPLIST_FILE = "OS X Example/Info.plist"; 371 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; 372 | PRODUCT_BUNDLE_IDENTIFIER = "com.moonwearables.OS-X-Example"; 373 | PRODUCT_NAME = "$(TARGET_NAME)"; 374 | }; 375 | name = Release; 376 | }; 377 | 9A4B7B3B1CDE55BC003E94A8 /* Debug */ = { 378 | isa = XCBuildConfiguration; 379 | buildSettings = { 380 | CLANG_ANALYZER_NONNULL = YES; 381 | CLANG_ENABLE_MODULES = YES; 382 | COMBINE_HIDPI_IMAGES = YES; 383 | CURRENT_PROJECT_VERSION = 1; 384 | DEFINES_MODULE = YES; 385 | DYLIB_COMPATIBILITY_VERSION = 1; 386 | DYLIB_CURRENT_VERSION = 1; 387 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 388 | FRAMEWORK_VERSION = A; 389 | INFOPLIST_FILE = MOONGraphView/Info.plist; 390 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 391 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; 392 | PRODUCT_BUNDLE_IDENTIFIER = com.vegather.MOONGraphView; 393 | PRODUCT_NAME = "$(TARGET_NAME)"; 394 | SKIP_INSTALL = YES; 395 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 396 | VERSIONING_SYSTEM = "apple-generic"; 397 | VERSION_INFO_PREFIX = ""; 398 | }; 399 | name = Debug; 400 | }; 401 | 9A4B7B3C1CDE55BC003E94A8 /* Release */ = { 402 | isa = XCBuildConfiguration; 403 | buildSettings = { 404 | CLANG_ANALYZER_NONNULL = YES; 405 | CLANG_ENABLE_MODULES = YES; 406 | COMBINE_HIDPI_IMAGES = YES; 407 | CURRENT_PROJECT_VERSION = 1; 408 | DEFINES_MODULE = YES; 409 | DYLIB_COMPATIBILITY_VERSION = 1; 410 | DYLIB_CURRENT_VERSION = 1; 411 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 412 | FRAMEWORK_VERSION = A; 413 | INFOPLIST_FILE = MOONGraphView/Info.plist; 414 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 415 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; 416 | PRODUCT_BUNDLE_IDENTIFIER = com.vegather.MOONGraphView; 417 | PRODUCT_NAME = "$(TARGET_NAME)"; 418 | SKIP_INSTALL = YES; 419 | VERSIONING_SYSTEM = "apple-generic"; 420 | VERSION_INFO_PREFIX = ""; 421 | }; 422 | name = Release; 423 | }; 424 | /* End XCBuildConfiguration section */ 425 | 426 | /* Begin XCConfigurationList section */ 427 | 9A2555BF1C8384AD00951A57 /* Build configuration list for PBXProject "OS X Example" */ = { 428 | isa = XCConfigurationList; 429 | buildConfigurations = ( 430 | 9A2555D11C8384AD00951A57 /* Debug */, 431 | 9A2555D21C8384AD00951A57 /* Release */, 432 | ); 433 | defaultConfigurationIsVisible = 0; 434 | defaultConfigurationName = Release; 435 | }; 436 | 9A2555D31C8384AD00951A57 /* Build configuration list for PBXNativeTarget "OS X Example" */ = { 437 | isa = XCConfigurationList; 438 | buildConfigurations = ( 439 | 9A2555D41C8384AD00951A57 /* Debug */, 440 | 9A2555D51C8384AD00951A57 /* Release */, 441 | ); 442 | defaultConfigurationIsVisible = 0; 443 | defaultConfigurationName = Release; 444 | }; 445 | 9A4B7B3A1CDE55BC003E94A8 /* Build configuration list for PBXNativeTarget "MOONGraphView" */ = { 446 | isa = XCConfigurationList; 447 | buildConfigurations = ( 448 | 9A4B7B3B1CDE55BC003E94A8 /* Debug */, 449 | 9A4B7B3C1CDE55BC003E94A8 /* Release */, 450 | ); 451 | defaultConfigurationIsVisible = 0; 452 | }; 453 | /* End XCConfigurationList section */ 454 | }; 455 | rootObject = 9A2555BC1C8384AD00951A57 /* Project object */; 456 | } 457 | -------------------------------------------------------------------------------- /Sample Code/OS X (deprecated)/OS X Example/OS X Example.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Sample Code/OS X (deprecated)/OS X Example/OS X Example/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // OS X Example 4 | // 5 | // Created by Vegard Solheim Theriault on 28/02/16. 6 | // Copyright © 2016 MOON Wearables. All rights reserved. 7 | // 8 | // .___ ___. ______ ______ .__ __. 9 | // | \/ | / __ \ / __ \ | \ | | 10 | // | \ / | | | | | | | | | | \| | 11 | // | |\/| | | | | | | | | | | . ` | 12 | // | | | | | `--' | | `--' | | |\ | 13 | // |__| |__| \______/ \______/ |__| \__| 14 | // ___ _____ _____ _ ___ ___ ___ ___ 15 | // | \| __\ \ / / __| | / _ \| _ \ __| _ \ 16 | // | |) | _| \ V /| _|| |_| (_) | _/ _|| / 17 | // |___/|___| \_/ |___|____\___/|_| |___|_|_\ 18 | // 19 | 20 | 21 | import Cocoa 22 | 23 | @NSApplicationMain 24 | class AppDelegate: NSObject, NSApplicationDelegate { 25 | 26 | 27 | 28 | func applicationDidFinishLaunching(aNotification: NSNotification) { 29 | // Insert code here to initialize your application 30 | } 31 | 32 | func applicationWillTerminate(aNotification: NSNotification) { 33 | // Insert code here to tear down your application 34 | } 35 | 36 | 37 | } 38 | 39 | -------------------------------------------------------------------------------- /Sample Code/OS X (deprecated)/OS X Example/OS X Example/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "size" : "16x16", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "mac", 10 | "size" : "16x16", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "mac", 15 | "size" : "32x32", 16 | "scale" : "1x" 17 | }, 18 | { 19 | "idiom" : "mac", 20 | "size" : "32x32", 21 | "scale" : "2x" 22 | }, 23 | { 24 | "idiom" : "mac", 25 | "size" : "128x128", 26 | "scale" : "1x" 27 | }, 28 | { 29 | "idiom" : "mac", 30 | "size" : "128x128", 31 | "scale" : "2x" 32 | }, 33 | { 34 | "idiom" : "mac", 35 | "size" : "256x256", 36 | "scale" : "1x" 37 | }, 38 | { 39 | "idiom" : "mac", 40 | "size" : "256x256", 41 | "scale" : "2x" 42 | }, 43 | { 44 | "idiom" : "mac", 45 | "size" : "512x512", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "mac", 50 | "size" : "512x512", 51 | "scale" : "2x" 52 | } 53 | ], 54 | "info" : { 55 | "version" : 1, 56 | "author" : "xcode" 57 | } 58 | } -------------------------------------------------------------------------------- /Sample Code/OS X (deprecated)/OS X Example/OS X Example/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 | 449 | 450 | 451 | 452 | 453 | 454 | 455 | 456 | 457 | 458 | 459 | 460 | 461 | 462 | 463 | 464 | 465 | 466 | 467 | 468 | 469 | 470 | 471 | 472 | 473 | 474 | 475 | 476 | 477 | 478 | 479 | 480 | 481 | 482 | 483 | 484 | 485 | 486 | 487 | 488 | 489 | 490 | 491 | 492 | 493 | 494 | 495 | 496 | 497 | 498 | 499 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 509 | 510 | Default 511 | 512 | 513 | 514 | 515 | 516 | 517 | Left to Right 518 | 519 | 520 | 521 | 522 | 523 | 524 | Right to Left 525 | 526 | 527 | 528 | 529 | 530 | 531 | 532 | 533 | 534 | 535 | Default 536 | 537 | 538 | 539 | 540 | 541 | 542 | Left to Right 543 | 544 | 545 | 546 | 547 | 548 | 549 | Right to Left 550 | 551 | 552 | 553 | 554 | 555 | 556 | 557 | 558 | 559 | 560 | 561 | 562 | 563 | 564 | 565 | 566 | 567 | 568 | 569 | 570 | 571 | 572 | 573 | 574 | 575 | 576 | 577 | 578 | 579 | 580 | 581 | 582 | 583 | 584 | 585 | 586 | 587 | 588 | 589 | 590 | 591 | 592 | 593 | 594 | 595 | 596 | 597 | 598 | 599 | 600 | 601 | 602 | 603 | 604 | 605 | 606 | 607 | 608 | 609 | 610 | 611 | 612 | 613 | 614 | 615 | 616 | 617 | 618 | 619 | 620 | 621 | 622 | 623 | 624 | 625 | 626 | 627 | 628 | 629 | 630 | 631 | 632 | 633 | 634 | 635 | 636 | 637 | 638 | 639 | 640 | 641 | 642 | 643 | 644 | 645 | 646 | 647 | 648 | 649 | 650 | 651 | 652 | 653 | 654 | 655 | 656 | 657 | 658 | 659 | 660 | 661 | 662 | 663 | 664 | 665 | 666 | 667 | 668 | 669 | 670 | 671 | 672 | 673 | 674 | 675 | 676 | 677 | 678 | 679 | 680 | 681 | 682 | 683 | 684 | 685 | 686 | 687 | 688 | 689 | 690 | 691 | 692 | 693 | 694 | 695 | 696 | 697 | 698 | 699 | 700 | 701 | 702 | 703 | 704 | 705 | 706 | 707 | 708 | 709 | 710 | 711 | 712 | 713 | 714 | 715 | 716 | 717 | 718 | 719 | 720 | 721 | 722 | 723 | 724 | 725 | 726 | 727 | 728 | 729 | 730 | 731 | 732 | 733 | 734 | 735 | 736 | 737 | 738 | 739 | 740 | 741 | 742 | 743 | 744 | 745 | 746 | 747 | 748 | 749 | 750 | 751 | 752 | 753 | -------------------------------------------------------------------------------- /Sample Code/OS X (deprecated)/OS X Example/OS X Example/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIconFile 10 | 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 25 | LSMinimumSystemVersion 26 | $(MACOSX_DEPLOYMENT_TARGET) 27 | NSHumanReadableCopyright 28 | Copyright © 2016 MOON Wearables. All rights reserved. 29 | NSMainStoryboardFile 30 | Main 31 | NSPrincipalClass 32 | NSApplication 33 | 34 | 35 | -------------------------------------------------------------------------------- /Sample Code/OS X (deprecated)/OS X Example/OS X Example/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // OS X Example 4 | // 5 | // Created by Vegard Solheim Theriault on 28/02/16. 6 | // Copyright © 2016 MOON Wearables. All rights reserved. 7 | // 8 | // .___ ___. ______ ______ .__ __. 9 | // | \/ | / __ \ / __ \ | \ | | 10 | // | \ / | | | | | | | | | | \| | 11 | // | |\/| | | | | | | | | | | . ` | 12 | // | | | | | `--' | | `--' | | |\ | 13 | // |__| |__| \______/ \______/ |__| \__| 14 | // ___ _____ _____ _ ___ ___ ___ ___ 15 | // | \| __\ \ / / __| | / _ \| _ \ __| _ \ 16 | // | |) | _| \ V /| _|| |_| (_) | _/ _|| / 17 | // |___/|___| \_/ |___|____\___/|_| |___|_|_\ 18 | // 19 | 20 | 21 | import Cocoa 22 | import MOONGraphView 23 | 24 | class ViewController: NSViewController { 25 | 26 | @IBOutlet weak var graph1: MOONGraphView! 27 | @IBOutlet weak var graph2: MOONGraphView! 28 | @IBOutlet weak var graph3: MOONGraphView! 29 | @IBOutlet weak var graph4: MOONGraphView! 30 | @IBOutlet weak var graph5: MOONGraphView! 31 | @IBOutlet weak var graph6: MOONGraphView! 32 | @IBOutlet weak var graph7: MOONGraphView! 33 | 34 | var displayLink: CVDisplayLink? 35 | var i = 0.0 36 | 37 | 38 | override func viewDidLoad() { 39 | super.viewDidLoad() 40 | 41 | view.wantsLayer = true 42 | view.layer?.backgroundColor = NSColor.whiteColor().CGColor 43 | 44 | graph1.themeColor = .Gray 45 | graph1.title = "Dates" 46 | graph1.subtitle = "λ = 690nm" 47 | graph1.maxSamples = 50 48 | 49 | graph2.themeColor = .Red 50 | graph2.title = "Orange" 51 | graph2.subtitle = "λ = 590nm" 52 | graph2.graphDirection = .LeftToRight 53 | graph2.maxSamples = 500 54 | graph2.maxValue = 8.0 55 | graph2.minValue = -8.0 56 | 57 | graph3.themeColor = .Green 58 | graph3.title = "Kiwi" 59 | graph3.subtitle = "λ = 530nm" 60 | graph3.graphDirection = .LeftToRight 61 | graph3.maxSamples = 400 62 | graph3.maxValue = 2.0 63 | graph3.minValue = -2.0 64 | 65 | graph4.themeColor = .Yellow 66 | graph4.title = "Lemon" 67 | graph4.subtitle = "λ = 575nm" 68 | graph4.roundedCorners = false 69 | graph4.maxSamples = 400 70 | graph4.maxValue = 2.0 71 | graph4.numberOfGraphs = 3 72 | 73 | graph5.themeColor = .Purple 74 | graph5.graphType = .Scatter 75 | graph5.title = "Aubergine" 76 | graph5.subtitle = "λ = 430nm" 77 | graph5.roundedCorners = false 78 | graph5.maxSamples = 200 79 | graph5.numberOfGraphs = 3 80 | 81 | graph6.themeColor = .Blue 82 | graph6.title = "Blueberry" 83 | graph6.subtitle = "λ = 460nm" 84 | graph6.maxSamples = 1000 85 | graph6.maxValue = 5.0 86 | graph6.minValue = -1.1 87 | 88 | graph7.themeColor = .Turquoise 89 | graph7.title = "Blue Grapes" 90 | graph7.subtitle = "λ = 480nm" 91 | graph7.maxSamples = 400 92 | graph7.maxValue = 6.0 93 | graph7.minValue = -6.0 94 | 95 | 96 | func displayLinkOutputCallback( 97 | displayLink : CVDisplayLink, 98 | _ inNow : UnsafePointer, 99 | _ inOutputTime : UnsafePointer, 100 | _ flagsIn : CVOptionFlags, 101 | _ flagsOut : UnsafeMutablePointer, 102 | _ displayLinkContext: UnsafeMutablePointer) -> CVReturn 103 | { 104 | unsafeBitCast(displayLinkContext, ViewController.self).update() 105 | return kCVReturnSuccess 106 | } 107 | 108 | CVDisplayLinkCreateWithActiveCGDisplays(&displayLink) 109 | if let displayLink = displayLink { 110 | CVDisplayLinkSetOutputCallback(displayLink, displayLinkOutputCallback, UnsafeMutablePointer(unsafeAddressOf(self))) 111 | CVDisplayLinkStart(displayLink) 112 | } 113 | } 114 | 115 | func squareForI(input: Double) -> Double { 116 | return (1...20).filter({$0 % 2 != 0}).reduce(0.0, combine: {$0 + sin(input * Double($1))}) 117 | } 118 | 119 | func triangleForI(input: Double) -> Double { 120 | return (1...20).reduce(0.0, combine: {$0 + sin(input * Double($1))}) 121 | } 122 | 123 | 124 | func update() { 125 | dispatch_async(dispatch_get_main_queue()) { 126 | let value = sin(self.i) 127 | 128 | self.graph1.addSamples(value) 129 | self.graph2.addSamples(self.triangleForI(self.i)) 130 | self.graph3.addSamples(value + sin(self.i * 5) / 3.0) 131 | self.graph6.addSamples(value) 132 | self.graph7.addSamples(self.squareForI(self.i)) 133 | self.graph4.addSamples(sin(self.i * 19) / 2.0 + sin(self.i * 21) / 2.0, cos(self.i), cos(self.i + M_PI)) 134 | self.graph5.addSamples(value, sin(self.i + 2 * M_PI / 3), sin(self.i + 4 * M_PI / 3)) 135 | 136 | self.i += 0.1 137 | } 138 | } 139 | 140 | } 141 | -------------------------------------------------------------------------------- /Sample Code/iOS (deprecated)/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vegather/GraphView/a0bbe2c3963077a1204b0e51cf34df40e423228d/Sample Code/iOS (deprecated)/.DS_Store -------------------------------------------------------------------------------- /Sample Code/iOS (deprecated)/iOS Example/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vegather/GraphView/a0bbe2c3963077a1204b0e51cf34df40e423228d/Sample Code/iOS (deprecated)/iOS Example/.DS_Store -------------------------------------------------------------------------------- /Sample Code/iOS (deprecated)/iOS Example/iOS Example.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 9A2555A71C83819000951A57 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A2555A61C83819000951A57 /* AppDelegate.swift */; }; 11 | 9A2555A91C83819000951A57 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A2555A81C83819000951A57 /* ViewController.swift */; }; 12 | 9A2555AC1C83819000951A57 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 9A2555AA1C83819000951A57 /* Main.storyboard */; }; 13 | 9A2555AE1C83819000951A57 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 9A2555AD1C83819000951A57 /* Assets.xcassets */; }; 14 | 9A2555B11C83819000951A57 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 9A2555AF1C83819000951A57 /* LaunchScreen.storyboard */; }; 15 | 9A2555B91C83819D00951A57 /* MOONGraphView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A2555B81C83819D00951A57 /* MOONGraphView.swift */; }; 16 | /* End PBXBuildFile section */ 17 | 18 | /* Begin PBXFileReference section */ 19 | 9A2555A31C83819000951A57 /* iOS Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "iOS Example.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 20 | 9A2555A61C83819000951A57 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 21 | 9A2555A81C83819000951A57 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 22 | 9A2555AB1C83819000951A57 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 23 | 9A2555AD1C83819000951A57 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 24 | 9A2555B01C83819000951A57 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 25 | 9A2555B21C83819000951A57 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 26 | 9A2555B81C83819D00951A57 /* MOONGraphView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MOONGraphView.swift; sourceTree = ""; }; 27 | /* End PBXFileReference section */ 28 | 29 | /* Begin PBXFrameworksBuildPhase section */ 30 | 9A2555A01C83819000951A57 /* Frameworks */ = { 31 | isa = PBXFrameworksBuildPhase; 32 | buildActionMask = 2147483647; 33 | files = ( 34 | ); 35 | runOnlyForDeploymentPostprocessing = 0; 36 | }; 37 | /* End PBXFrameworksBuildPhase section */ 38 | 39 | /* Begin PBXGroup section */ 40 | 9A25559A1C83819000951A57 = { 41 | isa = PBXGroup; 42 | children = ( 43 | 9A2555A51C83819000951A57 /* iOS Example */, 44 | 9A2555A41C83819000951A57 /* Products */, 45 | ); 46 | sourceTree = ""; 47 | }; 48 | 9A2555A41C83819000951A57 /* Products */ = { 49 | isa = PBXGroup; 50 | children = ( 51 | 9A2555A31C83819000951A57 /* iOS Example.app */, 52 | ); 53 | name = Products; 54 | sourceTree = ""; 55 | }; 56 | 9A2555A51C83819000951A57 /* iOS Example */ = { 57 | isa = PBXGroup; 58 | children = ( 59 | 9A2555A81C83819000951A57 /* ViewController.swift */, 60 | 9A2555B81C83819D00951A57 /* MOONGraphView.swift */, 61 | 9A2555AA1C83819000951A57 /* Main.storyboard */, 62 | 9A2555BA1C83836500951A57 /* Supporting Files */, 63 | ); 64 | path = "iOS Example"; 65 | sourceTree = ""; 66 | }; 67 | 9A2555BA1C83836500951A57 /* Supporting Files */ = { 68 | isa = PBXGroup; 69 | children = ( 70 | 9A2555AD1C83819000951A57 /* Assets.xcassets */, 71 | 9A2555A61C83819000951A57 /* AppDelegate.swift */, 72 | 9A2555AF1C83819000951A57 /* LaunchScreen.storyboard */, 73 | 9A2555B21C83819000951A57 /* Info.plist */, 74 | ); 75 | name = "Supporting Files"; 76 | sourceTree = ""; 77 | }; 78 | /* End PBXGroup section */ 79 | 80 | /* Begin PBXNativeTarget section */ 81 | 9A2555A21C83819000951A57 /* iOS Example */ = { 82 | isa = PBXNativeTarget; 83 | buildConfigurationList = 9A2555B51C83819000951A57 /* Build configuration list for PBXNativeTarget "iOS Example" */; 84 | buildPhases = ( 85 | 9A25559F1C83819000951A57 /* Sources */, 86 | 9A2555A01C83819000951A57 /* Frameworks */, 87 | 9A2555A11C83819000951A57 /* Resources */, 88 | ); 89 | buildRules = ( 90 | ); 91 | dependencies = ( 92 | ); 93 | name = "iOS Example"; 94 | productName = "iOS Example"; 95 | productReference = 9A2555A31C83819000951A57 /* iOS Example.app */; 96 | productType = "com.apple.product-type.application"; 97 | }; 98 | /* End PBXNativeTarget section */ 99 | 100 | /* Begin PBXProject section */ 101 | 9A25559B1C83819000951A57 /* Project object */ = { 102 | isa = PBXProject; 103 | attributes = { 104 | LastSwiftUpdateCheck = 0720; 105 | LastUpgradeCheck = 0720; 106 | ORGANIZATIONNAME = "MOON Wearables"; 107 | TargetAttributes = { 108 | 9A2555A21C83819000951A57 = { 109 | CreatedOnToolsVersion = 7.2.1; 110 | }; 111 | }; 112 | }; 113 | buildConfigurationList = 9A25559E1C83819000951A57 /* Build configuration list for PBXProject "iOS Example" */; 114 | compatibilityVersion = "Xcode 3.2"; 115 | developmentRegion = English; 116 | hasScannedForEncodings = 0; 117 | knownRegions = ( 118 | en, 119 | Base, 120 | ); 121 | mainGroup = 9A25559A1C83819000951A57; 122 | productRefGroup = 9A2555A41C83819000951A57 /* Products */; 123 | projectDirPath = ""; 124 | projectRoot = ""; 125 | targets = ( 126 | 9A2555A21C83819000951A57 /* iOS Example */, 127 | ); 128 | }; 129 | /* End PBXProject section */ 130 | 131 | /* Begin PBXResourcesBuildPhase section */ 132 | 9A2555A11C83819000951A57 /* Resources */ = { 133 | isa = PBXResourcesBuildPhase; 134 | buildActionMask = 2147483647; 135 | files = ( 136 | 9A2555B11C83819000951A57 /* LaunchScreen.storyboard in Resources */, 137 | 9A2555AE1C83819000951A57 /* Assets.xcassets in Resources */, 138 | 9A2555AC1C83819000951A57 /* Main.storyboard in Resources */, 139 | ); 140 | runOnlyForDeploymentPostprocessing = 0; 141 | }; 142 | /* End PBXResourcesBuildPhase section */ 143 | 144 | /* Begin PBXSourcesBuildPhase section */ 145 | 9A25559F1C83819000951A57 /* Sources */ = { 146 | isa = PBXSourcesBuildPhase; 147 | buildActionMask = 2147483647; 148 | files = ( 149 | 9A2555B91C83819D00951A57 /* MOONGraphView.swift in Sources */, 150 | 9A2555A91C83819000951A57 /* ViewController.swift in Sources */, 151 | 9A2555A71C83819000951A57 /* AppDelegate.swift in Sources */, 152 | ); 153 | runOnlyForDeploymentPostprocessing = 0; 154 | }; 155 | /* End PBXSourcesBuildPhase section */ 156 | 157 | /* Begin PBXVariantGroup section */ 158 | 9A2555AA1C83819000951A57 /* Main.storyboard */ = { 159 | isa = PBXVariantGroup; 160 | children = ( 161 | 9A2555AB1C83819000951A57 /* Base */, 162 | ); 163 | name = Main.storyboard; 164 | sourceTree = ""; 165 | }; 166 | 9A2555AF1C83819000951A57 /* LaunchScreen.storyboard */ = { 167 | isa = PBXVariantGroup; 168 | children = ( 169 | 9A2555B01C83819000951A57 /* Base */, 170 | ); 171 | name = LaunchScreen.storyboard; 172 | sourceTree = ""; 173 | }; 174 | /* End PBXVariantGroup section */ 175 | 176 | /* Begin XCBuildConfiguration section */ 177 | 9A2555B31C83819000951A57 /* Debug */ = { 178 | isa = XCBuildConfiguration; 179 | buildSettings = { 180 | ALWAYS_SEARCH_USER_PATHS = NO; 181 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 182 | CLANG_CXX_LIBRARY = "libc++"; 183 | CLANG_ENABLE_MODULES = YES; 184 | CLANG_ENABLE_OBJC_ARC = YES; 185 | CLANG_WARN_BOOL_CONVERSION = YES; 186 | CLANG_WARN_CONSTANT_CONVERSION = YES; 187 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 188 | CLANG_WARN_EMPTY_BODY = YES; 189 | CLANG_WARN_ENUM_CONVERSION = YES; 190 | CLANG_WARN_INT_CONVERSION = YES; 191 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 192 | CLANG_WARN_UNREACHABLE_CODE = YES; 193 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 194 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 195 | COPY_PHASE_STRIP = NO; 196 | DEBUG_INFORMATION_FORMAT = dwarf; 197 | ENABLE_STRICT_OBJC_MSGSEND = YES; 198 | ENABLE_TESTABILITY = YES; 199 | GCC_C_LANGUAGE_STANDARD = gnu99; 200 | GCC_DYNAMIC_NO_PIC = NO; 201 | GCC_NO_COMMON_BLOCKS = YES; 202 | GCC_OPTIMIZATION_LEVEL = 0; 203 | GCC_PREPROCESSOR_DEFINITIONS = ( 204 | "DEBUG=1", 205 | "$(inherited)", 206 | ); 207 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 208 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 209 | GCC_WARN_UNDECLARED_SELECTOR = YES; 210 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 211 | GCC_WARN_UNUSED_FUNCTION = YES; 212 | GCC_WARN_UNUSED_VARIABLE = YES; 213 | IPHONEOS_DEPLOYMENT_TARGET = 9.2; 214 | MTL_ENABLE_DEBUG_INFO = YES; 215 | ONLY_ACTIVE_ARCH = YES; 216 | SDKROOT = iphoneos; 217 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 218 | TARGETED_DEVICE_FAMILY = "1,2"; 219 | }; 220 | name = Debug; 221 | }; 222 | 9A2555B41C83819000951A57 /* Release */ = { 223 | isa = XCBuildConfiguration; 224 | buildSettings = { 225 | ALWAYS_SEARCH_USER_PATHS = NO; 226 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 227 | CLANG_CXX_LIBRARY = "libc++"; 228 | CLANG_ENABLE_MODULES = YES; 229 | CLANG_ENABLE_OBJC_ARC = YES; 230 | CLANG_WARN_BOOL_CONVERSION = YES; 231 | CLANG_WARN_CONSTANT_CONVERSION = YES; 232 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 233 | CLANG_WARN_EMPTY_BODY = YES; 234 | CLANG_WARN_ENUM_CONVERSION = YES; 235 | CLANG_WARN_INT_CONVERSION = YES; 236 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 237 | CLANG_WARN_UNREACHABLE_CODE = YES; 238 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 239 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 240 | COPY_PHASE_STRIP = NO; 241 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 242 | ENABLE_NS_ASSERTIONS = NO; 243 | ENABLE_STRICT_OBJC_MSGSEND = YES; 244 | GCC_C_LANGUAGE_STANDARD = gnu99; 245 | GCC_NO_COMMON_BLOCKS = YES; 246 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 247 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 248 | GCC_WARN_UNDECLARED_SELECTOR = YES; 249 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 250 | GCC_WARN_UNUSED_FUNCTION = YES; 251 | GCC_WARN_UNUSED_VARIABLE = YES; 252 | IPHONEOS_DEPLOYMENT_TARGET = 9.2; 253 | MTL_ENABLE_DEBUG_INFO = NO; 254 | SDKROOT = iphoneos; 255 | TARGETED_DEVICE_FAMILY = "1,2"; 256 | VALIDATE_PRODUCT = YES; 257 | }; 258 | name = Release; 259 | }; 260 | 9A2555B61C83819000951A57 /* Debug */ = { 261 | isa = XCBuildConfiguration; 262 | buildSettings = { 263 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 264 | INFOPLIST_FILE = "iOS Example/Info.plist"; 265 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 266 | PRODUCT_BUNDLE_IDENTIFIER = "com.moonwearables.iOS-Example"; 267 | PRODUCT_NAME = "$(TARGET_NAME)"; 268 | }; 269 | name = Debug; 270 | }; 271 | 9A2555B71C83819000951A57 /* Release */ = { 272 | isa = XCBuildConfiguration; 273 | buildSettings = { 274 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 275 | INFOPLIST_FILE = "iOS Example/Info.plist"; 276 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 277 | PRODUCT_BUNDLE_IDENTIFIER = "com.moonwearables.iOS-Example"; 278 | PRODUCT_NAME = "$(TARGET_NAME)"; 279 | }; 280 | name = Release; 281 | }; 282 | /* End XCBuildConfiguration section */ 283 | 284 | /* Begin XCConfigurationList section */ 285 | 9A25559E1C83819000951A57 /* Build configuration list for PBXProject "iOS Example" */ = { 286 | isa = XCConfigurationList; 287 | buildConfigurations = ( 288 | 9A2555B31C83819000951A57 /* Debug */, 289 | 9A2555B41C83819000951A57 /* Release */, 290 | ); 291 | defaultConfigurationIsVisible = 0; 292 | defaultConfigurationName = Release; 293 | }; 294 | 9A2555B51C83819000951A57 /* Build configuration list for PBXNativeTarget "iOS Example" */ = { 295 | isa = XCConfigurationList; 296 | buildConfigurations = ( 297 | 9A2555B61C83819000951A57 /* Debug */, 298 | 9A2555B71C83819000951A57 /* Release */, 299 | ); 300 | defaultConfigurationIsVisible = 0; 301 | }; 302 | /* End XCConfigurationList section */ 303 | }; 304 | rootObject = 9A25559B1C83819000951A57 /* Project object */; 305 | } 306 | -------------------------------------------------------------------------------- /Sample Code/iOS (deprecated)/iOS Example/iOS Example.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Sample Code/iOS (deprecated)/iOS Example/iOS Example/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vegather/GraphView/a0bbe2c3963077a1204b0e51cf34df40e423228d/Sample Code/iOS (deprecated)/iOS Example/iOS Example/.DS_Store -------------------------------------------------------------------------------- /Sample Code/iOS (deprecated)/iOS Example/iOS Example/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // iOS Example 4 | // 5 | // Created by Vegard Solheim Theriault on 28/02/16. 6 | // Copyright © 2016 MOON Wearables. All rights reserved. 7 | // 8 | // .___ ___. ______ ______ .__ __. 9 | // | \/ | / __ \ / __ \ | \ | | 10 | // | \ / | | | | | | | | | | \| | 11 | // | |\/| | | | | | | | | | | . ` | 12 | // | | | | | `--' | | `--' | | |\ | 13 | // |__| |__| \______/ \______/ |__| \__| 14 | // ___ _____ _____ _ ___ ___ ___ ___ 15 | // | \| __\ \ / / __| | / _ \| _ \ __| _ \ 16 | // | |) | _| \ V /| _|| |_| (_) | _/ _|| / 17 | // |___/|___| \_/ |___|____\___/|_| |___|_|_\ 18 | // 19 | 20 | 21 | import UIKit 22 | 23 | @UIApplicationMain 24 | class AppDelegate: UIResponder, UIApplicationDelegate { 25 | 26 | var window: UIWindow? 27 | 28 | 29 | func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool { 30 | // Override point for customization after application launch. 31 | return true 32 | } 33 | 34 | func applicationWillResignActive(application: UIApplication) { 35 | // 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. 36 | // 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. 37 | } 38 | 39 | func applicationDidEnterBackground(application: UIApplication) { 40 | // 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. 41 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 42 | } 43 | 44 | func applicationWillEnterForeground(application: UIApplication) { 45 | // 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. 46 | } 47 | 48 | func applicationDidBecomeActive(application: UIApplication) { 49 | // 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. 50 | } 51 | 52 | func applicationWillTerminate(application: UIApplication) { 53 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 54 | } 55 | 56 | 57 | } 58 | 59 | -------------------------------------------------------------------------------- /Sample Code/iOS (deprecated)/iOS Example/iOS Example/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "ipad", 35 | "size" : "29x29", 36 | "scale" : "1x" 37 | }, 38 | { 39 | "idiom" : "ipad", 40 | "size" : "29x29", 41 | "scale" : "2x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "40x40", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "40x40", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "76x76", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "76x76", 61 | "scale" : "2x" 62 | } 63 | ], 64 | "info" : { 65 | "version" : 1, 66 | "author" : "xcode" 67 | } 68 | } -------------------------------------------------------------------------------- /Sample Code/iOS (deprecated)/iOS Example/iOS Example/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /Sample Code/iOS (deprecated)/iOS Example/iOS Example/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /Sample Code/iOS (deprecated)/iOS Example/iOS Example/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 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationLandscapeLeft 37 | UIInterfaceOrientationLandscapeRight 38 | 39 | UISupportedInterfaceOrientations~ipad 40 | 41 | UIInterfaceOrientationPortrait 42 | UIInterfaceOrientationPortraitUpsideDown 43 | UIInterfaceOrientationLandscapeLeft 44 | UIInterfaceOrientationLandscapeRight 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /Sample Code/iOS (deprecated)/iOS Example/iOS Example/MOONGraphView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MOONGraphView.swift 3 | // iOS Example 4 | // 5 | // Created by Vegard Solheim Theriault on 28/02/16. 6 | // Copyright © 2016 MOON Wearables. All rights reserved. 7 | // 8 | // .___ ___. ______ ______ .__ __. 9 | // | \/ | / __ \ / __ \ | \ | | 10 | // | \ / | | | | | | | | | | \| | 11 | // | |\/| | | | | | | | | | | . ` | 12 | // | | | | | `--' | | `--' | | |\ | 13 | // |__| |__| \______/ \______/ |__| \__| 14 | // ___ _____ _____ _ ___ ___ ___ ___ 15 | // | \| __\ \ / / __| | / _ \| _ \ __| _ \ 16 | // | |) | _| \ V /| _|| |_| (_) | _/ _|| / 17 | // |___/|___| \_/ |___|____\___/|_| |___|_|_\ 18 | // 19 | 20 | 21 | import UIKit 22 | 23 | private struct Constants { 24 | static let FontName = "HelveticaNeue" 25 | static let ValueLabelWidth : CGFloat = 70.0 26 | static let TickMargin : CGFloat = 15.0 27 | static let TickWidth : CGFloat = 10.0 28 | static let Alpha : CGFloat = 0.6 29 | static let CornerRadius : CGFloat = 10.0 30 | static let GraphLineWidth : CGFloat = 2.0 31 | static let ScatterPointRadius : CGFloat = 2.0 32 | } 33 | 34 | 35 | @IBDesignable 36 | class MOONGraphView: UIView { 37 | 38 | enum GraphColor { 39 | case Gray 40 | case Red 41 | case Green 42 | case Blue 43 | case Turquoise 44 | case Yellow 45 | case Purple 46 | 47 | private func colors() -> [CGColorRef] { 48 | switch self { 49 | case Gray: 50 | return [UIColor(red: 210.0/255.0, green: 209.0/255.0, blue: 215.0/255.0, alpha: 1.0).CGColor, 51 | UIColor(red: 141.0/255.0, green: 140.0/255.0, blue: 146.0/255.0, alpha: 1.0).CGColor] 52 | case .Red: 53 | return [UIColor(red: 255.0/255.0, green: 148.0/255.0, blue: 86.0/255.0, alpha: 1.0).CGColor, 54 | UIColor(red: 253.0/255.0, green: 58.0/255.0, blue: 52.0/255.0, alpha: 1.0).CGColor] 55 | case .Green: 56 | return [UIColor(red: 78.0/255.0, green: 238.0/255.0, blue: 92.0/255.0, alpha: 1.0).CGColor, 57 | UIColor(red: 28.0/255.0, green: 180.0/255.0, blue: 28.0/255.0, alpha: 1.0).CGColor] 58 | case .Blue: 59 | return [UIColor(red: 90.0/255.0, green: 202.0/255.0, blue: 251.0/255.0, alpha: 1.0).CGColor, 60 | UIColor(red: 0.0/255.0, green: 108.0/255.0, blue: 250.0/255.0, alpha: 1.0).CGColor] 61 | case .Turquoise: 62 | return [UIColor(red: 82.0/255.0, green: 234.0/255.0, blue: 208.0/255.0, alpha: 1.0).CGColor, 63 | UIColor(red: 54.0/255.0, green: 174.0/255.0, blue: 220.0/255.0, alpha: 1.0).CGColor] 64 | case .Yellow: 65 | return [UIColor(red: 254.0/255.0, green: 209.0/255.0, blue: 48.0/255.0, alpha: 1.0).CGColor, 66 | UIColor(red: 255.0/255.0, green: 160.0/255.0, blue: 33.0/255.0, alpha: 1.0).CGColor] 67 | case .Purple: 68 | return [UIColor(red: 217.0/255.0, green: 168.0/255.0, blue: 252.0/255.0, alpha: 1.0).CGColor, 69 | UIColor(red: 140.0/255.0, green: 70.0/255.0, blue: 250.0/255.0, alpha: 1.0).CGColor] 70 | } 71 | } 72 | } 73 | 74 | enum GraphDirection { 75 | case LeftToRight 76 | case RightToLeft 77 | } 78 | 79 | enum GraphType { 80 | case Line 81 | case Scatter 82 | } 83 | 84 | 85 | private let gradientBackground = CAGradientLayer() 86 | private var lineView: LineView! 87 | private var accessoryView: AccessoryView! 88 | 89 | 90 | 91 | 92 | // ------------------------------- 93 | // MARK: Initialization 94 | // ------------------------------- 95 | 96 | override init(frame: CGRect) { 97 | super.init(frame: frame) 98 | setup() 99 | } 100 | 101 | required init?(coder aDecoder: NSCoder) { 102 | super.init(coder: aDecoder) 103 | setup() 104 | } 105 | 106 | private func setup() { 107 | gradientBackground.frame = layer.bounds 108 | gradientBackground.colors = themeColor.colors() 109 | gradientBackground.cornerRadius = roundedCorners ? Constants.CornerRadius : 0.0 110 | layer.addSublayer(gradientBackground) 111 | 112 | lineView = LineView(frame: bounds) 113 | lineView.layer.cornerRadius = roundedCorners ? Constants.CornerRadius : 0.0 114 | lineView.maxSamples = maxSamples 115 | lineView.maxValue = maxValue 116 | lineView.minValue = minValue 117 | lineView.graphDirection = graphDirection 118 | lineView.numberOfGraphs = numberOfGraphs 119 | lineView.graphType = graphType 120 | addSubview(lineView) 121 | 122 | accessoryView = AccessoryView(frame: bounds) 123 | accessoryView.layer.cornerRadius = roundedCorners ? Constants.CornerRadius : 0.0 124 | accessoryView.title = title 125 | accessoryView.subtitle = subtitle 126 | accessoryView.maxValue = maxValue 127 | accessoryView.minValue = minValue 128 | accessoryView.graphDirection = graphDirection 129 | addSubview(accessoryView) 130 | } 131 | 132 | 133 | 134 | 135 | // ------------------------------- 136 | // MARK: Public API 137 | // ------------------------------- 138 | 139 | /// Used to set the title of the graph in one of the upper corners. The default value for this is `""`, meaning that it will not be displayed. 140 | @IBInspectable var title: String = "" { 141 | didSet { 142 | accessoryView.title = title 143 | } 144 | } 145 | 146 | /// Used to set a subtitle that will go right underneath the title. The default value for this is `""`, and will thus not be displayed. 147 | @IBInspectable var subtitle: String = "" { 148 | didSet { 149 | accessoryView.subtitle = subtitle 150 | } 151 | } 152 | 153 | /// Specifies which way the graph will go. This is an enum with two possible options: `.LeftToRight`, and `.RightToLeft`. Setting this will also change which corner the title and subtitle will get drawn in (upper left corner for `.RightToLeft`, and vice versa). It also changes which side the values for the y-axis gets drawn (right side for `.RightToLeft`, and vice versa). The default is `.RightToLeft`. 154 | @IBInspectable var graphDirection = GraphDirection.RightToLeft { 155 | didSet { 156 | accessoryView.graphDirection = graphDirection 157 | lineView.graphDirection = graphDirection 158 | } 159 | } 160 | 161 | /// This will set the background gradient of the graph. It's an enum with seven colors to pick from: `.Gray`, `.Red`, `.Green`, `.Blue`, `.Turquoise`, `.Yellow`, and `.Purple`. The default is `.Red`. 162 | @IBInspectable var themeColor = GraphColor.Red { 163 | didSet { 164 | gradientBackground.colors = themeColor.colors() 165 | } 166 | } 167 | 168 | /// This sets how many samples will fit within the view. E.g., if you set this to 200, what you will see in the view is the last 200 samples. You can't set it to any lower than 2 (for obvious reasons). The default value of this is 150. 169 | @IBInspectable var maxSamples = 150 { 170 | didSet { 171 | lineView.maxSamples = max(2, maxSamples) 172 | } 173 | } 174 | 175 | /// Determines what the maximum expected value is. It is used as an upper limit for the view. The default is 1.0. 176 | @IBInspectable var maxValue: CGFloat = 1.0 { 177 | didSet { 178 | accessoryView.maxValue = maxValue 179 | lineView.maxValue = maxValue 180 | } 181 | } 182 | 183 | /// Determines what the minimum expected value is. It is used as an lower limit for the view. The default is -1.0. 184 | @IBInspectable var minValue: CGFloat = -1.0 { 185 | didSet { 186 | accessoryView.minValue = minValue 187 | lineView.minValue = minValue 188 | } 189 | } 190 | 191 | /// If you want your view to draw more than one graph at the same time (say x, y, z values of an accelerometer), you can specify that using this property. Notice that the `addSamples` method takes an argument of type `Double...` (called a variadic parameter). Whatever value you set for the `numberOfGraphs` property, you need to pass in the same number of arguments to this method, otherwise it will do nothing. If you change this property, all the samples you've added so far will be removed. The default is 1, meaning the `addSamples` method takes 1 argument. 192 | var numberOfGraphs = 1 { 193 | didSet { 194 | lineView.numberOfGraphs = max(1, numberOfGraphs) 195 | } 196 | } 197 | 198 | /// Use this to make the corners rounded or square. The default is true, meaning rounded corners. 199 | @IBInspectable var roundedCorners = true { 200 | didSet { 201 | gradientBackground.cornerRadius = roundedCorners ? Constants.CornerRadius : 0.0 202 | lineView.layer.cornerRadius = roundedCorners ? Constants.CornerRadius : 0.0 203 | accessoryView.layer.cornerRadius = roundedCorners ? Constants.CornerRadius : 0.0 204 | } 205 | } 206 | 207 | /// Changes how the samples are drawn. The current options are `.Line` and `.Scatter`. The default is `.Line`. 208 | @IBInspectable var graphType = GraphType.Line { 209 | didSet { 210 | lineView.graphType = graphType 211 | } 212 | } 213 | 214 | /// This method is where you add your data to the graph. The value of the samples you add should be within the range `[minValue, maxValue]`, otherwise the graph will draw outside the view. Notice that this takes `Double...` as an argument (called a variadic parameter), which means that you can pass it one or more `Double` values as arguments. This is so that you can draw multiple graphs in the same view at the same time (say x, y, z data from an accelerometer). The number of arguments you pass needs to correspond to the `numberOfGraphs` property, otherwise this method will do nothing. 215 | func addSamples(newSamples: Double...) { 216 | lineView.addSamples(newSamples) 217 | } 218 | 219 | /// Removes all the samples you've added to the graph. All the other properties like `roundedCorners` and `maxSamples` etc are kept the same. Useful if you want to reuse the same graph view. 220 | func reset() { 221 | lineView.reset() 222 | } 223 | 224 | 225 | 226 | // ------------------------------- 227 | // MARK: Drawing 228 | // ------------------------------- 229 | 230 | override func layoutSublayersOfLayer(layer: CALayer) { 231 | gradientBackground.frame = self.layer.bounds 232 | accessoryView.frame = self.layer.bounds 233 | lineView.frame = self.layer.bounds 234 | 235 | gradientBackground.setNeedsDisplay() 236 | accessoryView.setNeedsDisplay() 237 | lineView.setNeedsDisplay() 238 | 239 | gradientBackground.removeAllAnimations() 240 | } 241 | 242 | override func prepareForInterfaceBuilder() { 243 | if title == "" { title = "Heading" } 244 | if subtitle == "" { subtitle = "Subtitle" } 245 | 246 | for i in 0.. 568 | 569 | let label1 = NSAttributedString(string: String(format: "%.2f", arguments: [maxValue]), attributes: attributes) 570 | let label2 = NSAttributedString(string: String(format: "%.2f", arguments: [(maxValue-minValue)/2.0 + minValue]), attributes: attributes) 571 | let label3 = NSAttributedString(string: String(format: "%.2f", arguments: [minValue]), attributes: attributes) 572 | 573 | let alignmentCoefficient: CGFloat = -1.0 574 | 575 | switch graphDirection { 576 | case .RightToLeft: 577 | let x = bounds.width - Constants.ValueLabelWidth + Constants.TickWidth + 5.0 578 | label1.drawInRect(CGRect( 579 | x : x, 580 | y : Constants.TickMargin - (label1.size().height / 2.0) + alignmentCoefficient, 581 | width : label1.size().width, 582 | height : label1.size().height) 583 | ) 584 | label2.drawInRect(CGRect( 585 | x : x, 586 | y: bounds.height / 2.0 - (label2.size().height / 2.0) + alignmentCoefficient, 587 | width : label2.size().width, 588 | height : label2.size().height) 589 | ) 590 | label3.drawInRect(CGRect( 591 | x : x, 592 | y : bounds.height - Constants.TickMargin - (label3.size().height / 2.0) + alignmentCoefficient, 593 | width : label3.size().width, 594 | height : label3.size().height) 595 | ) 596 | case .LeftToRight: 597 | let x = Constants.ValueLabelWidth - Constants.TickWidth - 5.0 598 | label1.drawInRect(CGRect( 599 | x : x - label1.size().width, 600 | y : Constants.TickMargin - (label1.size().height / 2.0) + alignmentCoefficient, 601 | width : label1.size().width, 602 | height : label1.size().height) 603 | ) 604 | label2.drawInRect(CGRect( 605 | x : x - label2.size().width, 606 | y : bounds.height / 2.0 - (label2.size().height / 2.0) + alignmentCoefficient, 607 | width : label2.size().width, 608 | height : label2.size().height) 609 | ) 610 | label3.drawInRect(CGRect( 611 | x : x - label3.size().width, 612 | y : bounds.height - Constants.TickMargin - (label3.size().height / 2.0) + alignmentCoefficient, 613 | width : label3.size().width, 614 | height : label3.size().height) 615 | ) 616 | } 617 | } 618 | 619 | /// Draws the title label and the subtitle label 620 | private func drawInformationLabels() { 621 | let titleAttributes = [ 622 | NSFontAttributeName : UIFont(name: Constants.FontName, size: 30)!, 623 | NSForegroundColorAttributeName: UIColor.whiteColor() 624 | ] as Dictionary 625 | 626 | let subTitleAttributes = [ 627 | NSFontAttributeName : UIFont(name: Constants.FontName, size: 20)!, 628 | NSForegroundColorAttributeName: UIColor(white: 1.0, alpha: Constants.Alpha) 629 | ] as Dictionary 630 | 631 | let titleLabel = NSAttributedString(string: title, attributes: titleAttributes) 632 | let subTitleLabel = NSAttributedString(string: subtitle, attributes: subTitleAttributes) 633 | 634 | let horizontalMargin : CGFloat = 20.0 635 | let verticalMargin : CGFloat = 30.0 636 | 637 | let titleY = horizontalMargin 638 | let subTitleY = horizontalMargin + titleLabel.size().height 639 | 640 | switch graphDirection { 641 | case .RightToLeft: 642 | titleLabel .drawInRect(CGRect( 643 | x : verticalMargin, 644 | y : titleY, 645 | width : titleLabel.size().width, 646 | height : titleLabel.size().height) 647 | ) 648 | subTitleLabel.drawInRect(CGRect( 649 | x : verticalMargin, 650 | y : subTitleY, 651 | width : subTitleLabel.size().width, 652 | height : subTitleLabel.size().height)) 653 | case .LeftToRight: 654 | let x = bounds.width - verticalMargin - max(titleLabel.size().width, subTitleLabel.size().width) 655 | titleLabel .drawInRect(CGRect( 656 | x : x, 657 | y : titleY, 658 | width : titleLabel.size().width, 659 | height : titleLabel.size().height) 660 | ) 661 | subTitleLabel.drawInRect(CGRect( 662 | x : x, 663 | y : subTitleY, 664 | width : subTitleLabel.size().width, 665 | height : subTitleLabel.size().height) 666 | ) 667 | } 668 | } 669 | 670 | } 671 | -------------------------------------------------------------------------------- /Sample Code/iOS (deprecated)/iOS Example/iOS Example/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // iOS Example 4 | // 5 | // Created by Vegard Solheim Theriault on 28/02/16. 6 | // Copyright © 2016 MOON Wearables. All rights reserved. 7 | // 8 | // .___ ___. ______ ______ .__ __. 9 | // | \/ | / __ \ / __ \ | \ | | 10 | // | \ / | | | | | | | | | | \| | 11 | // | |\/| | | | | | | | | | | . ` | 12 | // | | | | | `--' | | `--' | | |\ | 13 | // |__| |__| \______/ \______/ |__| \__| 14 | // ___ _____ _____ _ ___ ___ ___ ___ 15 | // | \| __\ \ / / __| | / _ \| _ \ __| _ \ 16 | // | |) | _| \ V /| _|| |_| (_) | _/ _|| / 17 | // |___/|___| \_/ |___|____\___/|_| |___|_|_\ 18 | // 19 | 20 | 21 | import UIKit 22 | 23 | class ViewController: UIViewController { 24 | 25 | @IBOutlet weak var scrollView: UIScrollView! 26 | var graphs = [MOONGraphView]() 27 | var i = 0.0 28 | 29 | override func viewDidAppear(animated: Bool) { 30 | super.viewDidAppear(animated) 31 | 32 | let graphHeight: CGFloat = 150.0 33 | var currentY: CGFloat = 20.0 34 | let separator: CGFloat = 8.0 35 | 36 | let graph1 = MOONGraphView(frame: CGRect(x: 0.0, y: currentY, width: scrollView.bounds.width, height: graphHeight)) 37 | graph1.themeColor = .Gray 38 | graph1.maxSamples = 50 39 | graph1.title = "Dates" 40 | graph1.subtitle = "λ = 690nm" 41 | graph1.graphDirection = .LeftToRight 42 | graph1.roundedCorners = false 43 | graph1.graphType = .Scatter 44 | scrollView.addSubview(graph1) 45 | graphs.append(graph1) 46 | 47 | currentY += graphHeight + separator 48 | 49 | let graph2 = MOONGraphView(frame: CGRect(x: 0.0, y: currentY, width: scrollView.bounds.width, height: graphHeight)) 50 | graph2.themeColor = .Red 51 | graph2.maxSamples = 330 52 | graph2.maxValue = 4.0 53 | graph2.minValue = -4.0 54 | graph2.title = "Orange" 55 | graph2.subtitle = "λ = 590nm" 56 | graph2.roundedCorners = false 57 | graph2.graphType = .Scatter 58 | scrollView.addSubview(graph2) 59 | graphs.append(graph2) 60 | 61 | currentY += graphHeight + separator 62 | 63 | let graph3 = MOONGraphView(frame: CGRect(x: 0.0, y: currentY, width: scrollView.bounds.width, height: graphHeight)) 64 | graph3.themeColor = .Green 65 | graph3.maxSamples = 200 66 | graph3.maxValue = 2.0 67 | graph3.minValue = -2.0 68 | graph3.title = "Kiwi" 69 | graph3.subtitle = "λ = 530nm" 70 | graph3.roundedCorners = false 71 | scrollView.addSubview(graph3) 72 | graphs.append(graph3) 73 | 74 | currentY += graphHeight + separator 75 | 76 | let graph4 = MOONGraphView(frame: CGRect(x: 0.0, y: currentY, width: scrollView.bounds.width, height: graphHeight)) 77 | graph4.themeColor = .Blue 78 | graph4.maxValue = 5.0 79 | graph4.minValue = -1.1 80 | graph4.maxSamples = 1000 81 | graph4.title = "Blueberry" 82 | graph4.subtitle = "λ = 460nm" 83 | graph4.roundedCorners = false 84 | scrollView.addSubview(graph4) 85 | graphs.append(graph4) 86 | 87 | currentY += graphHeight + separator 88 | 89 | let graph5 = MOONGraphView(frame: CGRect(x: 0.0, y: currentY, width: scrollView.bounds.width, height: graphHeight)) 90 | graph5.themeColor = .Turquoise 91 | graph5.maxSamples = 280 92 | graph5.maxValue = 6.0 93 | graph5.minValue = -6.0 94 | graph5.title = "Blue Grapes" 95 | graph5.subtitle = "λ = 480nm" 96 | graph5.roundedCorners = false 97 | scrollView.addSubview(graph5) 98 | graphs.append(graph5) 99 | 100 | currentY += graphHeight + separator 101 | 102 | let graph6 = MOONGraphView(frame: CGRect(x: 0.0, y: currentY, width: scrollView.bounds.width, height: graphHeight)) 103 | graph6.themeColor = .Yellow 104 | graph6.maxSamples = 300 105 | graph6.maxValue = 2.0 106 | graph6.title = "Lemon" 107 | graph6.subtitle = "λ = 575nm" 108 | graph6.numberOfGraphs = 3 109 | graph6.roundedCorners = false 110 | scrollView.addSubview(graph6) 111 | graphs.append(graph6) 112 | 113 | currentY += graphHeight + separator 114 | 115 | let graph7 = MOONGraphView(frame: CGRect(x: 0.0, y: currentY, width: scrollView.bounds.width, height: graphHeight)) 116 | graph7.themeColor = .Purple 117 | graph7.title = "Aubergine" 118 | graph7.subtitle = "λ = 430nm" 119 | graph7.numberOfGraphs = 3 120 | graph7.roundedCorners = false 121 | graph7.graphType = .Scatter 122 | scrollView.addSubview(graph7) 123 | graphs.append(graph7) 124 | 125 | scrollView.contentSize = CGSize(width: scrollView.bounds.width, height: currentY + graphHeight) 126 | 127 | let updater = CADisplayLink(target: self, selector: #selector(update)) 128 | updater.addToRunLoop(NSRunLoop.currentRunLoop(), forMode: NSDefaultRunLoopMode) 129 | updater.addToRunLoop(NSRunLoop.currentRunLoop(), forMode: UITrackingRunLoopMode) // Makes sure update is called while scrolling 130 | } 131 | 132 | override func viewDidLayoutSubviews() { 133 | super.viewDidLayoutSubviews() 134 | 135 | for i in 0.. Double { 145 | return (1...15).filter({$0 % 2 != 0}).reduce(0.0, combine: {$0 + sin(input * Double($1))}) 146 | } 147 | 148 | func triangleForI(input: Double) -> Double { 149 | return (1...15).reduce(0.0, combine: {$0 + sin(input * Double($1))}) 150 | } 151 | 152 | func update() { 153 | let sineValue = sin(i) 154 | 155 | graphs[0].addSamples(sineValue) 156 | graphs[1].addSamples(triangleForI(i)) 157 | graphs[2].addSamples(sineValue + sin(i * 5) / 3.0) 158 | graphs[3].addSamples(sineValue) 159 | graphs[4].addSamples(squareForI(i)) 160 | graphs[5].addSamples(sin(i * 19) / 2.0 + sin(i * 21) / 2.0, cos(i), cos(i + M_PI)) 161 | graphs[6].addSamples(sineValue, sin(i + 2 * M_PI / 3), sin(i + 4 * M_PI / 3)) 162 | 163 | self.i += 0.1 164 | } 165 | } 166 | 167 | -------------------------------------------------------------------------------- /graph_shader.metal: -------------------------------------------------------------------------------- 1 | // 2 | // shaders.metal 3 | // Metal Graph 4 | // 5 | // Created by Vegard Solheim Theriault on 13/01/2017. 6 | // Copyright © 2017 Vegard Solheim Theriault. All rights reserved. 7 | // 8 | 9 | #include 10 | using namespace metal; 11 | 12 | struct VertexIn { 13 | float value; 14 | }; 15 | 16 | struct VertexOut { 17 | float4 position [[position]]; 18 | float pointSize [[point_size]]; 19 | float4 color; 20 | }; 21 | 22 | struct Uniforms { 23 | uint32_t offset; 24 | uint32_t capacity; 25 | float minValue; 26 | float maxValue; 27 | uint8_t pointSize; 28 | float4 topColor; 29 | float4 bottomColor; 30 | }; 31 | 32 | vertex VertexOut vertexShader(device VertexIn *vertices [[buffer(0)]], 33 | constant Uniforms *uniforms [[buffer(1)]], 34 | uint vid [[vertex_id]]) 35 | { 36 | // normalizedY is in the range [0, 1], where 0 is bottom, 1 is top 37 | float normalizedY = (vertices[vid].value - uniforms->minValue) / (uniforms->maxValue - uniforms->minValue); 38 | // transform normalizedY to the range [-1, 1] 39 | float y = normalizedY * 2.0f - 1.0f; 40 | 41 | // Use the offset and the vid to find the index. xIndex is in the range [0, uniforms->numSamples - 1] 42 | float xIndex = float((vid + (uniforms->capacity - uniforms->offset)) % uniforms->capacity); 43 | // Transforming xIndex to the range [-1, 1] 44 | float x = (xIndex / float(uniforms->capacity - 1)) * 2.0f - 1.0f; 45 | 46 | VertexOut vOut; 47 | vOut.pointSize = uniforms->pointSize; 48 | vOut.position = {x, y, 1.0f, 1.0f}; 49 | vOut.color = mix(uniforms->bottomColor, uniforms->topColor, normalizedY); 50 | 51 | return vOut; 52 | } 53 | 54 | fragment float4 fragmentShader(VertexOut input [[stage_in]]) { 55 | return input.color; 56 | } 57 | --------------------------------------------------------------------------------