diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000..61eb3f9 Binary files /dev/null and b/.DS_Store differ diff --git a/Example/.DS_Store b/Example/.DS_Store new file mode 100644 index 0000000..ec96f4c Binary files /dev/null and b/Example/.DS_Store differ diff --git a/Example/Athlee-InteractiveGraphView/.DS_Store b/Example/Athlee-InteractiveGraphView/.DS_Store new file mode 100644 index 0000000..4636525 Binary files /dev/null and b/Example/Athlee-InteractiveGraphView/.DS_Store differ diff --git a/Example/Athlee-InteractiveGraphView/Athlee-InteractiveGraphView.xcodeproj/project.pbxproj b/Example/Athlee-InteractiveGraphView/Athlee-InteractiveGraphView.xcodeproj/project.pbxproj index 4af9ec1..1460483 100644 --- a/Example/Athlee-InteractiveGraphView/Athlee-InteractiveGraphView.xcodeproj/project.pbxproj +++ b/Example/Athlee-InteractiveGraphView/Athlee-InteractiveGraphView.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 040670441D56805100521457 /* CubicCurveAlgorithm.swift in Sources */ = {isa = PBXBuildFile; fileRef = 040670431D56805100521457 /* CubicCurveAlgorithm.swift */; }; 04A488E01D49803F00BCB35E /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04A488DF1D49803F00BCB35E /* AppDelegate.swift */; }; 04A488E21D49803F00BCB35E /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04A488E11D49803F00BCB35E /* ViewController.swift */; }; 04A488E51D49803F00BCB35E /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 04A488E31D49803F00BCB35E /* Main.storyboard */; }; @@ -37,6 +38,7 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ + 040670431D56805100521457 /* CubicCurveAlgorithm.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CubicCurveAlgorithm.swift; sourceTree = ""; }; 04A488DC1D49803F00BCB35E /* Athlee-InteractiveGraphView.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Athlee-InteractiveGraphView.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 04A488DF1D49803F00BCB35E /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 04A488E11D49803F00BCB35E /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; @@ -133,6 +135,7 @@ 04A489081D49805000BCB35E /* InteractiveGraphViewDataSource.swift */, 04A489091D49805000BCB35E /* InteractiveGraphViewDelegate.swift */, 04A4890A1D49805000BCB35E /* PathBuilder.swift */, + 040670431D56805100521457 /* CubicCurveAlgorithm.swift */, ); name = Source; path = ../../Source; @@ -188,9 +191,12 @@ TargetAttributes = { 04A488DB1D49803F00BCB35E = { CreatedOnToolsVersion = 7.3.1; + DevelopmentTeam = RG4N372RZE; + LastSwiftMigration = 0810; }; 04A488EF1D49803F00BCB35E = { CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 0810; TestTargetID = 04A488DB1D49803F00BCB35E; }; }; @@ -247,6 +253,7 @@ 04A4890E1D49805000BCB35E /* Drawable.swift in Sources */, 04A4890C1D49805000BCB35E /* CurveView.swift in Sources */, 04A489101D49805000BCB35E /* InteractiveGraphDecorator.swift in Sources */, + 040670441D56805100521457 /* CubicCurveAlgorithm.swift in Sources */, 04A489141D49805000BCB35E /* InteractiveGraphViewDelegate.swift in Sources */, 04A4890F1D49805000BCB35E /* InteractiveGraphDecorations.swift in Sources */, 04A489121D49805000BCB35E /* InteractiveGraphView.swift in Sources */, @@ -380,10 +387,12 @@ isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + DEVELOPMENT_TEAM = RG4N372RZE; INFOPLIST_FILE = "Athlee-InteractiveGraphView/Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = "io.athlee.Athlee-InteractiveGraphView"; + PRODUCT_BUNDLE_IDENTIFIER = "io.athlee.Athlee-InteractiveGraphView-Demo"; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 3.0; }; name = Debug; }; @@ -391,10 +400,12 @@ isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + DEVELOPMENT_TEAM = RG4N372RZE; INFOPLIST_FILE = "Athlee-InteractiveGraphView/Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = "io.athlee.Athlee-InteractiveGraphView"; + PRODUCT_BUNDLE_IDENTIFIER = "io.athlee.Athlee-InteractiveGraphView-Demo"; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 3.0; }; name = Release; }; @@ -406,6 +417,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "io.athlee.Athlee-InteractiveGraphViewTests"; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 3.0; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Athlee-InteractiveGraphView.app/Athlee-InteractiveGraphView"; }; name = Debug; @@ -418,6 +430,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "io.athlee.Athlee-InteractiveGraphViewTests"; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 3.0; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Athlee-InteractiveGraphView.app/Athlee-InteractiveGraphView"; }; name = Release; @@ -441,6 +454,7 @@ 04A488FB1D49803F00BCB35E /* Release */, ); defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; }; 04A488FC1D49803F00BCB35E /* Build configuration list for PBXNativeTarget "Athlee-InteractiveGraphViewTests" */ = { isa = XCConfigurationList; @@ -449,6 +463,7 @@ 04A488FE1D49803F00BCB35E /* Release */, ); defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; diff --git a/Example/Athlee-InteractiveGraphView/Athlee-InteractiveGraphView/AppDelegate.swift b/Example/Athlee-InteractiveGraphView/Athlee-InteractiveGraphView/AppDelegate.swift index 71eac57..c056624 100644 --- a/Example/Athlee-InteractiveGraphView/Athlee-InteractiveGraphView/AppDelegate.swift +++ b/Example/Athlee-InteractiveGraphView/Athlee-InteractiveGraphView/AppDelegate.swift @@ -14,30 +14,30 @@ class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? - func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool { + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { // Override point for customization after application launch. return true } - func applicationWillResignActive(application: UIApplication) { + func applicationWillResignActive(_ application: UIApplication) { // 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. // 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. } - func applicationDidEnterBackground(application: UIApplication) { + func applicationDidEnterBackground(_ application: UIApplication) { // 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. // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. } - func applicationWillEnterForeground(application: UIApplication) { + func applicationWillEnterForeground(_ application: UIApplication) { // 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. } - func applicationDidBecomeActive(application: UIApplication) { + func applicationDidBecomeActive(_ application: UIApplication) { // 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. } - func applicationWillTerminate(application: UIApplication) { + func applicationWillTerminate(_ application: UIApplication) { // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. } diff --git a/Example/Athlee-InteractiveGraphView/Athlee-InteractiveGraphView/Base.lproj/Main.storyboard b/Example/Athlee-InteractiveGraphView/Athlee-InteractiveGraphView/Base.lproj/Main.storyboard index 86025a2..4f2e1cb 100644 --- a/Example/Athlee-InteractiveGraphView/Athlee-InteractiveGraphView/Base.lproj/Main.storyboard +++ b/Example/Athlee-InteractiveGraphView/Athlee-InteractiveGraphView/Base.lproj/Main.storyboard @@ -1,9 +1,13 @@ - - + + + + + - + + @@ -15,15 +19,15 @@ - + - - + + - + diff --git a/Example/Athlee-InteractiveGraphView/Athlee-InteractiveGraphView/ViewController.swift b/Example/Athlee-InteractiveGraphView/Athlee-InteractiveGraphView/ViewController.swift index cedab78..f482a1c 100644 --- a/Example/Athlee-InteractiveGraphView/Athlee-InteractiveGraphView/ViewController.swift +++ b/Example/Athlee-InteractiveGraphView/Athlee-InteractiveGraphView/ViewController.swift @@ -25,7 +25,7 @@ extension ViewController: InteractiveGraphViewDataSource, InteractiveGraphViewDe return 7 } - func interactiveGraphView(interactiveGraphView: InteractiveGraphView, valueAtIndex index: Int) -> Double { + func interactiveGraphView(_ interactiveGraphView: InteractiveGraphView, valueAtIndex index: Int) -> Double { switch index { case 0: return 10 @@ -46,7 +46,7 @@ extension ViewController: InteractiveGraphViewDataSource, InteractiveGraphViewDe } } - func interactiveGraphView(interactiveGraphView: InteractiveGraphView, titleAtIndex index: Int) -> String { + func interactiveGraphView(_ interactiveGraphView: InteractiveGraphView, titleAtIndex index: Int) -> String { switch index { case 0: return "MON" @@ -67,9 +67,9 @@ extension ViewController: InteractiveGraphViewDataSource, InteractiveGraphViewDe } } - func interactiveGraphView(interactiveGraphView: InteractiveGraphView, didSelectPointAtIndex index: Int) { + func interactiveGraphView(_ interactiveGraphView: InteractiveGraphView, didSelectPointAtIndex index: Int) { if let value = interactiveGraphView.valueForIndex(index) { print("Selected value=\(value)") } } -} \ No newline at end of file +} diff --git a/Example/Athlee-InteractiveGraphView/Athlee-InteractiveGraphViewTests/Athlee_InteractiveGraphViewTests.swift b/Example/Athlee-InteractiveGraphView/Athlee-InteractiveGraphViewTests/Athlee_InteractiveGraphViewTests.swift index 7e0d7f1..167c66b 100644 --- a/Example/Athlee-InteractiveGraphView/Athlee-InteractiveGraphViewTests/Athlee_InteractiveGraphViewTests.swift +++ b/Example/Athlee-InteractiveGraphView/Athlee-InteractiveGraphViewTests/Athlee_InteractiveGraphViewTests.swift @@ -28,7 +28,7 @@ class Athlee_InteractiveGraphViewTests: XCTestCase { func testPerformanceExample() { // This is an example of a performance test case. - self.measureBlock { + self.measure { // Put the code you want to measure the time of here. } } diff --git a/Source/.DS_Store b/Source/.DS_Store new file mode 100644 index 0000000..6b08ce8 Binary files /dev/null and b/Source/.DS_Store differ diff --git a/Source/CubicCurveAlgorithm.swift b/Source/CubicCurveAlgorithm.swift new file mode 100644 index 0000000..a076f7a --- /dev/null +++ b/Source/CubicCurveAlgorithm.swift @@ -0,0 +1,182 @@ +// +// CubicCurveAlgorithm.swift +// Bezier +// +// Created by Ramsundar Shandilya on 10/12/15. +// Copyright © 2015 Y Media Labs. All rights reserved. +// + +//import Foundation +//import UIKit +// +//struct CubicCurveSegment +//{ +// let controlPoint1: CGPoint +// let controlPoint2: CGPoint +//} +// +//class CubicCurveAlgorithm +//{ +// fileprivate var firstControlPoints: [CGPoint?] = [] +// fileprivate var secondControlPoints: [CGPoint?] = [] +// +// func controlPointsFromPoints(_ dataPoints: [CGPoint]) -> [CubicCurveSegment] { +// +// //Number of Segments +// let count = dataPoints.count - 1 +// +// //P0, P1, P2, P3 are the points for each segment, where P0 & P3 are the knots and P1, P2 are the control points. +// if count == 1 { +// let P0 = dataPoints[0] +// let P3 = dataPoints[1] +// +// //Calculate First Control Point +// //3P1 = 2P0 + P3 +// +// let P1x = (2*P0.x + P3.x)/3 +// let P1y = (2*P0.y + P3.y)/3 +// +// firstControlPoints.append(CGPoint(x: P1x, y: P1y)) +// +// //Calculate second Control Point +// //P2 = 2P1 - P0 +// let P2x = (2*P1x - P0.x) +// let P2y = (2*P1y - P0.y) +// +// secondControlPoints.append(CGPoint(x: P2x, y: P2y)) +// } else { +// firstControlPoints = Array(repeating: nil, count: count) +// +// var rhsArray = [CGPoint]() +// +// //Array of Coefficients +// var a = [Double]() +// var b = [Double]() +// var c = [Double]() +// +// for i in 0 ..< count { +// +// var rhsValueX: CGFloat = 0 +// var rhsValueY: CGFloat = 0 +// +// let P0 = dataPoints[i]; +// let P3 = dataPoints[i+1]; +// +// if i==0 { +// a.append(0) +// b.append(2) +// c.append(1) +// +// //rhs for first segment +// rhsValueX = P0.x + 2*P3.x; +// rhsValueY = P0.y + 2*P3.y; +// +// } else if i == count-1 { +// a.append(2) +// b.append(7) +// c.append(0) +// +// //rhs for last segment +// rhsValueX = 8*P0.x + P3.x; +// rhsValueY = 8*P0.y + P3.y; +// } else { +// a.append(1) +// b.append(4) +// c.append(1) +// +// rhsValueX = 4*P0.x + 2*P3.x; +// rhsValueY = 4*P0.y + 2*P3.y; +// } +// +// rhsArray.append(CGPoint(x: rhsValueX, y: rhsValueY)) +// } +// +// //Solve Ax=B. Use Tridiagonal matrix algorithm a.k.a Thomas Algorithm +// +// for i in 1 ..< count { +// let rhsValueX = rhsArray[i].x +// let rhsValueY = rhsArray[i].y +// +// let prevRhsValueX = rhsArray[i-1].x +// let prevRhsValueY = rhsArray[i-1].y +// +// let m = a[i]/b[i-1] +// +// let b1 = b[i] - m * c[i-1]; +// b[i] = b1 +// +// let r2x = rhsValueX.f - m * prevRhsValueX.f +// let r2y = rhsValueY.f - m * prevRhsValueY.f +// +// rhsArray[i] = CGPoint(x: r2x, y: r2y) +// +// } +// +// //Get First Control Points +// +// //Last control Point +// let lastControlPointX = rhsArray[count-1].x.f/b[count-1] +// let lastControlPointY = rhsArray[count-1].y.f/b[count-1] +// +// firstControlPoints[count-1] = CGPoint(x: lastControlPointX, y: lastControlPointY) +// +// for var i=count-2; i>=0; i -= 1 { +// if let nextControlPoint = firstControlPoints[i+1] { +// let controlPointX = (rhsArray[i].x.f - c[i] * nextControlPoint.x.f)/b[i] +// let controlPointY = (rhsArray[i].y.f - c[i] * nextControlPoint.y.f)/b[i] +// +// firstControlPoints[i] = CGPoint(x: controlPointX, y: controlPointY) +// +// } +// } +// +// //Compute second Control Points from first +// +// for i in 0 ..< count { +// +// if i == count-1 { +// let P3 = dataPoints[i+1] +// +// guard let P1 = firstControlPoints[i] else{ +// continue +// } +// +// let controlPointX = (P3.x + P1.x)/2 +// let controlPointY = (P3.y + P1.y)/2 +// +// secondControlPoints.append(CGPoint(x: controlPointX, y: controlPointY)) +// +// } else { +// let P3 = dataPoints[i+1] +// +// guard let nextP1 = firstControlPoints[i+1] else { +// continue +// } +// +// let controlPointX = 2*P3.x - nextP1.x +// let controlPointY = 2*P3.y - nextP1.y +// +// secondControlPoints.append(CGPoint(x: controlPointX, y: controlPointY)) +// } +// } +// } +// +// var controlPoints = [CubicCurveSegment]() +// +// for i in 0 ..< count { +// if let firstControlPoint = firstControlPoints[i], +// let secondControlPoint = secondControlPoints[i] { +// let segment = CubicCurveSegment(controlPoint1: firstControlPoint, controlPoint2: secondControlPoint) +// controlPoints.append(segment) +// } +// } +// +// return controlPoints +// } +//} +// +//extension CGFloat { +// var f: Double { +// return Double(self) +// } +//} diff --git a/Source/CurveView.swift b/Source/CurveView.swift index 70b1c25..e37b1e0 100644 --- a/Source/CurveView.swift +++ b/Source/CurveView.swift @@ -9,7 +9,7 @@ import UIKit public extension UIColor { - func alpha(alpha: CGFloat) -> UIColor { + func alpha(_ alpha: CGFloat) -> UIColor { var red: CGFloat = 0 var green: CGFloat = 0 var blue: CGFloat = 0 @@ -56,64 +56,64 @@ func (lhs: CGPoint, rhs: CGPoint) -> CGPoint { return point } -public class CurveView: UIView, PathBuilder { - public var points: [CGPoint] = [] { +open class CurveView: UIView, PathBuilder { + open var points: [CGPoint] = [] { didSet { setNeedsDisplay() } } - public var startColor: UIColor = UIColor.whiteColor() { + open var startColor: UIColor = UIColor.white { didSet { setNeedsDisplay() } } - public var endColor: UIColor = UIColor.whiteColor() { + open var endColor: UIColor = UIColor.white { didSet { setNeedsDisplay() } } - public var curveColor: UIColor = UIColor.whiteColor() { + open var curveColor: UIColor = UIColor.white { didSet { setNeedsDisplay() } } - public var startAlpha: CGFloat = 0.8 { + open var startAlpha: CGFloat = 0.8 { didSet { setNeedsDisplay() } } - public var endAlpha: CGFloat = 0.2 { + open var endAlpha: CGFloat = 0.2 { didSet { setNeedsDisplay() } } - @available(*, unavailable, deprecated=0.0.5, message="The curve view is now using a bitmap images for better performance.") - public private(set) var curveLayer: CAShapeLayer? + @available(*, unavailable, deprecated: 0.0.5, message: "The curve view is now using a bitmap images for better performance.") + open fileprivate(set) var curveLayer: CAShapeLayer? - @available(*, unavailable, deprecated=0.0.5, message="The curve view is now using a bitmap images for better performance.") - public private(set) var gradientLayer: CAGradientLayer? + @available(*, unavailable, deprecated: 0.0.5, message: "The curve view is now using a bitmap images for better performance.") + open fileprivate(set) var gradientLayer: CAGradientLayer? - @available(*, unavailable, deprecated=0.0.5, message="The curve view is now using a bitmap images for better performance.") - public private(set) var gradientView: UIView? + @available(*, unavailable, deprecated: 0.0.5, message: "The curve view is now using a bitmap images for better performance.") + open fileprivate(set) var gradientView: UIView? - override public func drawRect(rect: CGRect) { + override open func draw(_ rect: CGRect) { //// Draw the curve line. - guard let path = quadCurvedPathWithPoints(points) else { + guard let path = quadCurvedPathWithPoints(points: points) else { return } - guard let first = points.first, last = points.last else { + guard let first = points.first, let last = points.last else { return } - opaque = true + isOpaque = true layer.rasterizationScale = traitCollection.displayScale layer.shouldRasterize = true @@ -122,31 +122,34 @@ public class CurveView: UIView, PathBuilder { //// Clip the curve, so we can get the final shape. let clippingPath = path.copy() as! UIBezierPath - clippingPath.addLineToPoint(CGPoint(x: last.x, y: bounds.height)) - clippingPath.addLineToPoint(CGPoint(x: first.x, y: bounds.height)) - clippingPath.closePath() + clippingPath.addLine(to: CGPoint(x: last.x, y: bounds.height)) + clippingPath.addLine(to: CGPoint(x: first.x, y: bounds.height)) + clippingPath.close() let context = UIGraphicsGetCurrentContext() //// Gradient Declarations - let gradient = CGGradientCreateWithColors(CGColorSpaceCreateDeviceRGB(), - [startColor.alpha(startAlpha).CGColor, - endColor.alpha(endAlpha).CGColor], - [0.05, 1])! + + + + let colors = [startColor.alpha(startAlpha).cgColor, + endColor.alpha(endAlpha).cgColor] as CFArray + let gradient = CGGradient(colorsSpace: CGColorSpaceCreateDeviceRGB(), + colors: colors, + locations: [0.05, 1])! //// Oval Drawing - CGContextSaveGState(context) + context?.saveGState() clippingPath.addClip() - CGContextDrawLinearGradient(context, - gradient, - CGPoint(x: bounds.midX, y: bounds.minY), - CGPoint(x: bounds.midX, y: bounds.maxY), - CGGradientDrawingOptions()) + context?.drawLinearGradient(gradient, + start: CGPoint(x: bounds.midX, y: bounds.minY), + end: CGPoint(x: bounds.midX, y: bounds.maxY), + options: CGGradientDrawingOptions()) - CGContextRestoreGState(context) + context?.restoreGState() // let gradientLayer = CAGradientLayer() // gradientLayer.frame = bounds @@ -165,15 +168,15 @@ public class CurveView: UIView, PathBuilder { //// Shadow Declarations let shadow = NSShadow() - shadow.shadowColor = UIColor.blackColor() - shadow.shadowOffset = CGSizeMake(0.1, 1.1) + shadow.shadowColor = UIColor.black + shadow.shadowOffset = CGSize(width: 0.1, height: 1.1) shadow.shadowBlurRadius = 2 - CGContextSaveGState(context) - CGContextSetShadowWithColor(context, shadow.shadowOffset, shadow.shadowBlurRadius, (shadow.shadowColor as! UIColor).CGColor) + context?.saveGState() + context?.setShadow(offset: shadow.shadowOffset, blur: shadow.shadowBlurRadius, color: (shadow.shadowColor as! UIColor).cgColor) curveColor.set() path.lineWidth = 3.5 path.stroke() - CGContextRestoreGState(context) + context?.restoreGState() } -} \ No newline at end of file +} diff --git a/Source/Drawable.swift b/Source/Drawable.swift index 74b5a76..dc1a866 100644 --- a/Source/Drawable.swift +++ b/Source/Drawable.swift @@ -15,13 +15,13 @@ public protocol Drawable { var canvas: Canvas { get } var decorator: Decorator { get } - func drawLine(startPoint startPoint: CGPoint, endPoint: CGPoint) - func drawCircle(center center: CGPoint, radius: CGFloat) - func drawCurve(points points: [CGPoint]) + func drawLine(startPoint: CGPoint, endPoint: CGPoint) + func drawCircle(center: CGPoint, radius: CGFloat) + func drawCurve(points: [CGPoint]) } public extension Drawable { - func drawLine(startPoint startPoint: CGPoint, endPoint: CGPoint) { } - func drawCircle(center center: CGPoint, radius: CGFloat) { } - func drawCurve(points points: [CGPoint]) { } -} \ No newline at end of file + func drawLine(startPoint: CGPoint, endPoint: CGPoint) { } + func drawCircle(center: CGPoint, radius: CGFloat) { } + func drawCurve(points: [CGPoint]) { } +} diff --git a/Source/InteractiveGraphDrawable.swift b/Source/InteractiveGraphDrawable.swift index 95bb91a..9121679 100644 --- a/Source/InteractiveGraphDrawable.swift +++ b/Source/InteractiveGraphDrawable.swift @@ -8,14 +8,14 @@ import UIKit -public struct InteractiveGraphDrawable: Drawable { +public struct InteractiveGraphDrawable: Drawable where T.View == UIView, U.Decorations == InteractiveGraphDecorations { public let canvas: T public let decorator: U - public func drawCurve(points points: [CGPoint]) { + public func drawCurve(points: [CGPoint]) { let curve = CurveView() - curve.backgroundColor = .clearColor() + curve.backgroundColor = .clear curve.frame = canvas.view.bounds curve.points = points curve.startColor = decorator.decorations.startColor @@ -27,23 +27,23 @@ public struct InteractiveGraphDrawable Double? { + public func valueForIndex(_ index: Int) -> Double? { return values[index]?.value } - public func reloadData(animated animated: Bool = false) { + public func reloadData(animated: Bool = false) { selectedDot.removeFromSuperlayer() - selectedDot.backgroundColor = decorator.decorations.dotTintColor.CGColor + selectedDot.backgroundColor = decorator.decorations.dotTintColor.cgColor if animated { - UIView.animateWithDuration(0.1) { + UIView.animate(withDuration: 0.1, animations: { self.alpha = 0 - } + }) } reset() @@ -135,19 +135,19 @@ public final class InteractiveGraphView: UIView, CanvasType, UIGestureRecognizer selectedIndex = points.count - 1 if animated { - UIView.animateWithDuration(0.3) { + UIView.animate(withDuration: 0.3, animations: { self.alpha = 1 - } + }) } } // MARK: Private utils - private func reset() { + fileprivate func reset() { values = [:] } - private func updateSelectedDot() { + fileprivate func updateSelectedDot() { guard !points.isEmpty else { return } guard let index = selectedIndex else { return } @@ -163,7 +163,7 @@ public final class InteractiveGraphView: UIView, CanvasType, UIGestureRecognizer // MARK: Setup - private func collectDataPoints() { + fileprivate func collectDataPoints() { guard let dataSource = dataSource else { return } @@ -179,7 +179,7 @@ public final class InteractiveGraphView: UIView, CanvasType, UIGestureRecognizer } } - private func buildCurve() { + fileprivate func buildCurve() { layer.sublayers?.forEach { $0.removeFromSuperlayer() } let horizontalSpace = bounds.width / CGFloat(self.values.count) @@ -188,7 +188,7 @@ public final class InteractiveGraphView: UIView, CanvasType, UIGestureRecognizer return value }.map { $0 } - guard let maxValue = values.maxElement() else { + guard let maxValue = values.max() else { return } @@ -222,18 +222,20 @@ public final class InteractiveGraphView: UIView, CanvasType, UIGestureRecognizer addSelectionLayer() } - private func addDataPoints() { + fileprivate func addDataPoints() { for point in points { drawable.drawCircle(center: point, radius: dotCircleRadius) } } - private func addDataPointValueLabels() { - for (i, point) in points.enumerate() { + fileprivate func addDataPointValueLabels() { + for (i, point) in points.enumerated() { let label = UILabel() - label.font = UIFont.systemFontOfSize(15) + let value = values[i]!.value + + label.font = UIFont.systemFont(ofSize: 15) label.textColor = textColor.alpha(0.7) - label.text = formatter.stringFromNumber(values[i]!.value) + label.text = formatter.string(from: NSNumber(value: value)) label.sizeToFit() label.center = CGPoint(x: point.x, y: point.y - dotCircleRadius * 2.5) @@ -241,36 +243,36 @@ public final class InteractiveGraphView: UIView, CanvasType, UIGestureRecognizer } } - private func addDataPointLabels() { - for (i, point) in points.enumerate() { + fileprivate func addDataPointLabels() { + for (i, point) in points.enumerated() { let label = UILabel() - label.font = UIFont.systemFontOfSize(13) + label.font = UIFont.systemFont(ofSize: 13) label.textColor = textColor.alpha(0.7) label.text = values[i]!.title label.sizeToFit() label.center = CGPoint(x: point.x, y: bounds.maxY - (label.frame.height)) - label.layer.shadowColor = UIColor.blackColor().CGColor + label.layer.shadowColor = UIColor.black.cgColor label.layer.shadowOffset = .zero label.layer.shadowRadius = 1 label.layer.shadowOpacity = 0.6 label.layer.masksToBounds = false label.layer.shouldRasterize = true label.layer.rasterizationScale = traitCollection.displayScale - label.layer.opaque = false + label.layer.isOpaque = false addSubview(label) } } - private func addSelectionLayer() { + fileprivate func addSelectionLayer() { let width = bounds.width / CGFloat(self.values.count) for subview in subviews { if let subview = subview as? CurveView { selectionLayer.frame.size = CGSize(width: width, height: bounds.height) - selectionLayer.opaque = true + selectionLayer.isOpaque = true selectionLayer.rasterizationScale = traitCollection.displayScale selectionLayer.shouldRasterize = true @@ -279,28 +281,28 @@ public final class InteractiveGraphView: UIView, CanvasType, UIGestureRecognizer let selectionColor = decorator.decorations.selectionColor let gradientLayer = CAGradientLayer() - gradientLayer.opaque = false + gradientLayer.isOpaque = false gradientLayer.frame = selectionLayer.bounds gradientLayer.startPoint = CGPoint(x: 0.5, y: 0) gradientLayer.endPoint = CGPoint(x: 0.5, y: 1) gradientLayer.colors = [ - selectionColor.alpha(0).CGColor, - selectionColor.alpha(0.45).CGColor, - selectionColor.alpha(0.7).CGColor + selectionColor.alpha(0).cgColor, + selectionColor.alpha(0.45).cgColor, + selectionColor.alpha(0.7).cgColor ] gradientLayer.locations = [ 0, 0.8, 1 ] selectionLayer.addSublayer(gradientLayer) - selectionLayer.backgroundColor = UIColor.clearColor().CGColor + selectionLayer.backgroundColor = UIColor.clear.cgColor - subview.layer.insertSublayer(selectionLayer, atIndex: 1) + subview.layer.insertSublayer(selectionLayer, at: 1) let point = points.last! CATransaction.begin() CATransaction.setCompletionBlock { - NSOperationQueue.mainQueue().addOperationWithBlock { + OperationQueue.main.addOperation { self.updateSelectedDot() } } @@ -318,22 +320,22 @@ public final class InteractiveGraphView: UIView, CanvasType, UIGestureRecognizer // MARK: Gesture recognizers - internal func didRecognizeTapGesture(recognizer: UITapGestureRecognizer) { - let point = nearestPoint(to: recognizer.locationInView(self)) + internal func didRecognizeTapGesture(_ recognizer: UITapGestureRecognizer) { + let point = nearestPoint(to: recognizer.location(in: self)) selectionLayer.position.x = point.x - if let index = points.indexOf(point) where selectedIndex != index { + if let index = points.index(of: point), selectedIndex != index { selectedIndex = index delegate?.interactiveGraphView(self, didSelectPointAtIndex: index) updateSelectedDot() } } - private var previousPoint: CGPoint = .zero - internal func didRecognizePanGesture(recognizer: UIPanGestureRecognizer) { + fileprivate var previousPoint: CGPoint = .zero + internal func didRecognizePanGesture(_ recognizer: UIPanGestureRecognizer) { selectionLayer.removeAllAnimations() - let point = recognizer.locationInView(self) - guard recognizer.state != .Began else { + let point = recognizer.location(in: self) + guard recognizer.state != .began else { let centerPoint = nearestPoint(to: point) selectionLayer.position.x = centerPoint.x @@ -352,14 +354,14 @@ public final class InteractiveGraphView: UIView, CanvasType, UIGestureRecognizer CATransaction.commit() let centerPoint = nearestPoint(to: point) - if let index = points.indexOf(centerPoint) where selectedIndex != index { + if let index = points.index(of: centerPoint), selectedIndex != index { selectedIndex = index delegate?.interactiveGraphView(self, didSelectPointAtIndex: index) updateSelectedDot() } } - if recognizer.state == .Ended { + if recognizer.state == .ended { let centerPoint = nearestPoint(to: point) selectionLayer.position.x = centerPoint.x } @@ -367,14 +369,14 @@ public final class InteractiveGraphView: UIView, CanvasType, UIGestureRecognizer // MARK: Animation helpers - private func showSelectionLayer(show: Bool, animated: Bool = true) { + fileprivate func showSelectionLayer(_ show: Bool, animated: Bool = true) { if animated { let animation = CABasicAnimation(keyPath: "opacity") animation.toValue = show ? 1 : 0 - animation.removedOnCompletion = false + animation.isRemovedOnCompletion = false animation.fillMode = kCAFillModeBoth - selectionLayer.addAnimation(animation, forKey: nil) + selectionLayer.add(animation, forKey: nil) } else { selectionLayer.opacity = show ? 1 : 0 } @@ -382,19 +384,19 @@ public final class InteractiveGraphView: UIView, CanvasType, UIGestureRecognizer // MARK: Geometry helpers - private func nearestPoint(to point: CGPoint) -> CGPoint { + fileprivate func nearestPoint(to point: CGPoint) -> CGPoint { let width = bounds.width / CGFloat(self.points.count) return points.filter { abs(point.x - $0.x) <= width / 2 }.first! } // MARK: Gesture recognizer delegate - public override func gestureRecognizerShouldBegin(gestureRecognizer: UIGestureRecognizer) -> Bool { + public override func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool { return true } - public func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, - shouldRecognizeSimultaneouslyWithGestureRecognizer otherGestureRecognizer: UIGestureRecognizer) -> Bool { + public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, + shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool { return true } -} \ No newline at end of file +} diff --git a/Source/InteractiveGraphViewDataSource.swift b/Source/InteractiveGraphViewDataSource.swift index 5dfe451..06f47c1 100644 --- a/Source/InteractiveGraphViewDataSource.swift +++ b/Source/InteractiveGraphViewDataSource.swift @@ -10,6 +10,6 @@ import Foundation public protocol InteractiveGraphViewDataSource: class { func numberOfPoints() -> Int - func interactiveGraphView(interactiveGraphView: InteractiveGraphView, valueAtIndex index: Int) -> Double - func interactiveGraphView(interactiveGraphView: InteractiveGraphView, titleAtIndex index: Int) -> String -} \ No newline at end of file + func interactiveGraphView(_ interactiveGraphView: InteractiveGraphView, valueAtIndex index: Int) -> Double + func interactiveGraphView(_ interactiveGraphView: InteractiveGraphView, titleAtIndex index: Int) -> String +} diff --git a/Source/InteractiveGraphViewDelegate.swift b/Source/InteractiveGraphViewDelegate.swift index ad9f4c7..30f18fe 100644 --- a/Source/InteractiveGraphViewDelegate.swift +++ b/Source/InteractiveGraphViewDelegate.swift @@ -9,12 +9,12 @@ import Foundation public protocol InteractiveGraphViewDelegate: class { - func interactiveGraphView(interactiveGraphView: InteractiveGraphView, didSelectPointAtIndex index: Int) + func interactiveGraphView(_ interactiveGraphView: InteractiveGraphView, didSelectPointAtIndex index: Int) } // optional implementations public extension InteractiveGraphViewDelegate { - func interactiveGraphView(interactiveGraphView: InteractiveGraphView, didSelectPointAtIndex index: Int) { + func interactiveGraphView(_ interactiveGraphView: InteractiveGraphView, didSelectPointAtIndex index: Int) { } -} \ No newline at end of file +} diff --git a/Source/PathBuilder.swift b/Source/PathBuilder.swift index 2a53559..77d2b41 100644 --- a/Source/PathBuilder.swift +++ b/Source/PathBuilder.swift @@ -22,10 +22,10 @@ public extension PathBuilder where Point == CGPoint { } let path = UIBezierPath() - path.moveToPoint(firstPoint) + path.move(to: firstPoint) if points.count == 2 { - path.addLineToPoint(points[1]) + path.addLine(to: points[1]) return path } @@ -36,12 +36,12 @@ public extension PathBuilder where Point == CGPoint { for point in points { let midPoint = prevPoint <> point - path.addQuadCurveToPoint(midPoint, controlPoint: midPoint prevPoint) - path.addQuadCurveToPoint(point, controlPoint: midPoint point) + path.addQuadCurve(to: midPoint, controlPoint: midPoint prevPoint) + path.addQuadCurve(to: point, controlPoint: midPoint point) prevPoint = point } return path } -} \ No newline at end of file +}