From 1de4e19faf45766fe7be065fa90095418646a503 Mon Sep 17 00:00:00 2001 From: RiuHDuo Date: Fri, 8 Dec 2017 15:37:47 +0800 Subject: [PATCH 1/3] fix leaks --- Classes/Plots/Plot.swift | 2 +- Classes/Protocols/ScrollableGraphViewDataSource.swift | 2 +- Classes/Protocols/ScrollableGraphViewDrawingDelegate.swift | 2 +- Classes/ScrollableGraphView.swift | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Classes/Plots/Plot.swift b/Classes/Plots/Plot.swift index 4f32e34..ed930e2 100644 --- a/Classes/Plots/Plot.swift +++ b/Classes/Plots/Plot.swift @@ -6,7 +6,7 @@ open class Plot { // The id for this plot. Used when determining which data to give it in the dataSource open var identifier: String! - var graphViewDrawingDelegate: ScrollableGraphViewDrawingDelegate! = nil + weak var graphViewDrawingDelegate: ScrollableGraphViewDrawingDelegate! = nil // Animation Settings // ################## diff --git a/Classes/Protocols/ScrollableGraphViewDataSource.swift b/Classes/Protocols/ScrollableGraphViewDataSource.swift index 2ffff65..13bbd2c 100644 --- a/Classes/Protocols/ScrollableGraphViewDataSource.swift +++ b/Classes/Protocols/ScrollableGraphViewDataSource.swift @@ -1,7 +1,7 @@ import UIKit -public protocol ScrollableGraphViewDataSource { +public protocol ScrollableGraphViewDataSource: class { func value(forPlot plot: Plot, atIndex pointIndex: Int) -> Double func label(atIndex pointIndex: Int) -> String func numberOfPoints() -> Int // This now forces the same number of points in each plot. diff --git a/Classes/Protocols/ScrollableGraphViewDrawingDelegate.swift b/Classes/Protocols/ScrollableGraphViewDrawingDelegate.swift index 5b49c55..20e1de1 100644 --- a/Classes/Protocols/ScrollableGraphViewDrawingDelegate.swift +++ b/Classes/Protocols/ScrollableGraphViewDrawingDelegate.swift @@ -2,7 +2,7 @@ import UIKit // Delegate definition that provides the data required by the drawing layers. -internal protocol ScrollableGraphViewDrawingDelegate { +internal protocol ScrollableGraphViewDrawingDelegate: class{ func intervalForActivePoints() -> CountableRange func rangeForActivePoints() -> (min: Double, max: Double) func paddingForPoints() -> (leftmostPointPadding: CGFloat, rightmostPointPadding: CGFloat) diff --git a/Classes/ScrollableGraphView.swift b/Classes/ScrollableGraphView.swift index 5bf1715..6fab5de 100644 --- a/Classes/ScrollableGraphView.swift +++ b/Classes/ScrollableGraphView.swift @@ -96,7 +96,7 @@ import UIKit private var labelPool = LabelPool() // Data Source - open var dataSource: ScrollableGraphViewDataSource? { + weak open var dataSource: ScrollableGraphViewDataSource? { didSet { if(plots.count > 0) { reload() From d1b5dc80f896cf5980f84ce710623adfcdb7ad4f Mon Sep 17 00:00:00 2001 From: RiuHDuo Date: Fri, 8 Dec 2017 17:15:21 +0800 Subject: [PATCH 2/3] add value plot and fix crash when graphicView destroy with animating --- Classes/Drawing/ValueDrawingLayer.swift | 66 +++++++++++++++++++++++++ Classes/Plots/Plot.swift | 40 ++++++++------- Classes/Plots/ValuePlot.swift | 31 ++++++++++++ Classes/ScrollableGraphView.swift | 1 + 4 files changed, 121 insertions(+), 17 deletions(-) create mode 100644 Classes/Drawing/ValueDrawingLayer.swift create mode 100644 Classes/Plots/ValuePlot.swift diff --git a/Classes/Drawing/ValueDrawingLayer.swift b/Classes/Drawing/ValueDrawingLayer.swift new file mode 100644 index 0000000..1ca27a8 --- /dev/null +++ b/Classes/Drawing/ValueDrawingLayer.swift @@ -0,0 +1,66 @@ +// +// ValueDrawingLayer.swift +// ScrollableGraphView +// +// Created by RiuHDuo on 2017/12/8. +// Copyright © 2017年 SGV. All rights reserved. +// + +import UIKit + +class ValueDrawingLayer: ScrollableGraphViewDrawingLayer { + + let font: UIFont + let color: UIColor + + private var textLayers = [CATextLayer]() + + init(frame: CGRect, font: UIFont, color: UIColor) { + + self.font = font + self.color = color + + super.init(viewportWidth: frame.size.width, viewportHeight: frame.size.height) + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + private func createDataPointPath() { + + for layer in self.textLayers{ + layer.removeFromSuperlayer() + } + + guard let activePointsInterval = self.owner?.graphViewDrawingDelegate?.intervalForActivePoints() else{ return} + for i in activePointsInterval { + + var location = CGPoint.zero + + if let pointLocation = owner?.graphPoint(forIndex: i) { + location = pointLocation.location + } + + let layer = CATextLayer() + layer.contentsScale = UIScreen.main.scale + layer.string = String(format:"%.2f", self.owner?.data[i] ?? 0) + layer.bounds = CGRect(x: 0, y: 0, width: 60, height: 14) + layer.font = self.font.fontName as CFTypeRef + layer.fontSize = self.font.pointSize + layer.alignmentMode = kCAAlignmentCenter + layer.position = CGPoint(x: location.x, y: location.y - 10) + layer.foregroundColor = UIColor.black.cgColor + self.addSublayer(layer) + self.textLayers.append(layer) + } + + + } + + + + override func updatePath() { + createDataPointPath() + } +} diff --git a/Classes/Plots/Plot.swift b/Classes/Plots/Plot.swift index ed930e2..25909e7 100644 --- a/Classes/Plots/Plot.swift +++ b/Classes/Plots/Plot.swift @@ -6,7 +6,7 @@ open class Plot { // The id for this plot. Used when determining which data to give it in the dataSource open var identifier: String! - weak var graphViewDrawingDelegate: ScrollableGraphViewDrawingDelegate! = nil + weak var graphViewDrawingDelegate: ScrollableGraphViewDrawingDelegate? = nil // Animation Settings // ################## @@ -22,6 +22,8 @@ open class Plot { } } } + + var data = [Int:Double]() /// The animation style. open var adaptAnimationType = ScrollableGraphViewAnimationType.easeOut /// If adaptAnimationType is set to .Custom, then this is the easing function you would like applied for the animation. @@ -64,7 +66,7 @@ open class Plot { } } - graphViewDrawingDelegate.updatePaths() + graphViewDrawingDelegate?.updatePaths() } private func animate(point: GraphPoint, to position: CGPoint, withDelay delay: Double = 0) { @@ -151,9 +153,10 @@ open class Plot { let value = range.min - let position = graphViewDrawingDelegate.calculatePosition(atIndex: i, value: value) - let point = GraphPoint(position: position) - graphPoints.append(point) + if let position = graphViewDrawingDelegate?.calculatePosition(atIndex: i, value: value){ + let point = GraphPoint(position: position) + graphPoints.append(point) + } } } @@ -170,9 +173,10 @@ open class Plot { let value = data[dataPosition] - let newPosition = graphViewDrawingDelegate.calculatePosition(atIndex: i, value: value) - graphPoints[i].x = newPosition.x - graphPoints[i].y = newPosition.y + if let newPosition = graphViewDrawingDelegate?.calculatePosition(atIndex: i, value: value){ + graphPoints[i].x = newPosition.x + graphPoints[i].y = newPosition.y + } } } @@ -185,11 +189,12 @@ open class Plot { let dataPosition = index let value = data[dataPosition] - let newPosition = graphViewDrawingDelegate.calculatePosition(atIndex: activatedPointIndex, value: value) - graphPoints[activatedPointIndex].x = newPosition.x - graphPoints[activatedPointIndex].y = newPosition.y - - index += 1 + if let newPosition = graphViewDrawingDelegate?.calculatePosition(atIndex: activatedPointIndex, value: value){ + graphPoints[activatedPointIndex].x = newPosition.x + graphPoints[activatedPointIndex].y = newPosition.y + + index += 1 + } } } @@ -200,10 +205,11 @@ open class Plot { // For any visible points, kickoff the animation to their new position after the axis' min/max has changed. var dataIndex = 0 for pointIndex in pointsToAnimate { - let newPosition = graphViewDrawingDelegate.calculatePosition(atIndex: pointIndex, value: data[dataIndex]) - let point = graphPoints[pointIndex] - animate(point: point, to: newPosition, withDelay: Double(dataIndex) * delay) - dataIndex += 1 + if let newPosition = graphViewDrawingDelegate?.calculatePosition(atIndex: pointIndex, value: data[dataIndex]){ + let point = graphPoints[pointIndex] + animate(point: point, to: newPosition, withDelay: Double(dataIndex) * delay) + dataIndex += 1 + } } } diff --git a/Classes/Plots/ValuePlot.swift b/Classes/Plots/ValuePlot.swift new file mode 100644 index 0000000..df7de93 --- /dev/null +++ b/Classes/Plots/ValuePlot.swift @@ -0,0 +1,31 @@ +// +// ValuePlot.swift +// ScrollableGraphView +// +// Created by RiuHDuo on 2017/12/8. +// Copyright © 2017年 SGV. All rights reserved. +// + +import UIKit + +open class ValuePlot: Plot { + private var dataPointLayer: ValueDrawingLayer? + + open var font = UIFont.systemFont(ofSize: 10) + open var color = UIColor.black + + public init(identifier: String) { + super.init() + self.identifier = identifier + } + + override func layers(forViewport viewport: CGRect) -> [ScrollableGraphViewDrawingLayer?] { + createLayers(viewport: viewport) + return [dataPointLayer] + } + + private func createLayers(viewport: CGRect) { + dataPointLayer = ValueDrawingLayer(frame: viewport, font: font, color: color) + dataPointLayer?.owner = self + } +} diff --git a/Classes/ScrollableGraphView.swift b/Classes/ScrollableGraphView.swift index 6fab5de..6356ca0 100644 --- a/Classes/ScrollableGraphView.swift +++ b/Classes/ScrollableGraphView.swift @@ -659,6 +659,7 @@ import UIKit for i in activeInterval.startIndex ..< activeInterval.endIndex { let dataForIndexI = dataSource?.value(forPlot: plot, atIndex: i) ?? 0 + plot.data[i] = dataForIndexI dataForInterval.append(dataForIndexI) } From b024c513e90ad0503386f2d0b942e9982f85ecda Mon Sep 17 00:00:00 2001 From: RiuHDuo Date: Fri, 8 Dec 2017 17:20:50 +0800 Subject: [PATCH 3/3] add example value plot --- .../ScrollableGraphView.xcodeproj/project.pbxproj | 9 +++++++++ .../GraphView.xcodeproj/project.pbxproj | 8 ++++++++ graphview_example_code/GraphView/ViewController.swift | 7 ++++++- 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/carthage/ScrollableGraphView/ScrollableGraphView.xcodeproj/project.pbxproj b/carthage/ScrollableGraphView/ScrollableGraphView.xcodeproj/project.pbxproj index 18d9c62..b2284ca 100644 --- a/carthage/ScrollableGraphView/ScrollableGraphView.xcodeproj/project.pbxproj +++ b/carthage/ScrollableGraphView/ScrollableGraphView.xcodeproj/project.pbxproj @@ -26,6 +26,8 @@ 298BFD581F121BB00062F5C8 /* LabelPool.swift in Sources */ = {isa = PBXBuildFile; fileRef = 298BFD461F121BB00062F5C8 /* LabelPool.swift */; }; 298BFD591F121BB00062F5C8 /* ReferenceLines.swift in Sources */ = {isa = PBXBuildFile; fileRef = 298BFD471F121BB00062F5C8 /* ReferenceLines.swift */; }; 298BFD5A1F121BB00062F5C8 /* ScrollableGraphView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 298BFD481F121BB00062F5C8 /* ScrollableGraphView.swift */; }; + 58A6E0061FDA79900047F7E0 /* ValueDrawingLayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58A6E0051FDA79900047F7E0 /* ValueDrawingLayer.swift */; }; + 58A6E0081FDA7D990047F7E0 /* ValuePlot.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58A6E0071FDA7D990047F7E0 /* ValuePlot.swift */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -50,6 +52,8 @@ 298BFD461F121BB00062F5C8 /* LabelPool.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LabelPool.swift; sourceTree = ""; }; 298BFD471F121BB00062F5C8 /* ReferenceLines.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReferenceLines.swift; sourceTree = ""; }; 298BFD481F121BB00062F5C8 /* ScrollableGraphView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ScrollableGraphView.swift; sourceTree = ""; }; + 58A6E0051FDA79900047F7E0 /* ValueDrawingLayer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ValueDrawingLayer.swift; sourceTree = ""; }; + 58A6E0071FDA7D990047F7E0 /* ValuePlot.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ValuePlot.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -112,6 +116,7 @@ 298BFD371F121BB00062F5C8 /* LineDrawingLayer.swift */, 298BFD381F121BB00062F5C8 /* ReferenceLineDrawingView.swift */, 298BFD391F121BB00062F5C8 /* ScrollableGraphViewDrawingLayer.swift */, + 58A6E0051FDA79900047F7E0 /* ValueDrawingLayer.swift */, ); path = Drawing; sourceTree = ""; @@ -124,6 +129,7 @@ 298BFD3F1F121BB00062F5C8 /* DotPlot.swift */, 298BFD401F121BB00062F5C8 /* LinePlot.swift */, 298BFD411F121BB00062F5C8 /* Plot.swift */, + 58A6E0071FDA7D990047F7E0 /* ValuePlot.swift */, ); path = Plots; sourceTree = ""; @@ -251,6 +257,8 @@ 298BFD511F121BB00062F5C8 /* GraphPointAnimation.swift in Sources */, 298BFD531F121BB00062F5C8 /* DotPlot.swift in Sources */, 298BFD5A1F121BB00062F5C8 /* ScrollableGraphView.swift in Sources */, + 58A6E0061FDA79900047F7E0 /* ValueDrawingLayer.swift in Sources */, + 58A6E0081FDA7D990047F7E0 /* ValuePlot.swift in Sources */, 298BFD501F121BB00062F5C8 /* GraphPoint.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -414,6 +422,7 @@ 298BFD301F121BA10062F5C8 /* Release */, ); defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; diff --git a/graphview_example_code/GraphView.xcodeproj/project.pbxproj b/graphview_example_code/GraphView.xcodeproj/project.pbxproj index 08a5095..9669e51 100644 --- a/graphview_example_code/GraphView.xcodeproj/project.pbxproj +++ b/graphview_example_code/GraphView.xcodeproj/project.pbxproj @@ -31,6 +31,8 @@ 29A590461F0503BD004D219C /* ReferenceLineDrawingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29A590451F0503BD004D219C /* ReferenceLineDrawingView.swift */; }; 29A590481F05049F004D219C /* LineDrawingLayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29A590471F05049F004D219C /* LineDrawingLayer.swift */; }; 29A5904B1F0509C0004D219C /* Plot.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29A5904A1F0509C0004D219C /* Plot.swift */; }; + 58A6E00A1FDA7E910047F7E0 /* ValueDrawingLayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58A6E0091FDA7E910047F7E0 /* ValueDrawingLayer.swift */; }; + 58A6E00C1FDA7E9C0047F7E0 /* ValuePlot.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58A6E00B1FDA7E9C0047F7E0 /* ValuePlot.swift */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -60,6 +62,8 @@ 29A590451F0503BD004D219C /* ReferenceLineDrawingView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ReferenceLineDrawingView.swift; path = ../../Classes/Drawing/ReferenceLineDrawingView.swift; sourceTree = ""; }; 29A590471F05049F004D219C /* LineDrawingLayer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = LineDrawingLayer.swift; path = ../../Classes/Drawing/LineDrawingLayer.swift; sourceTree = ""; }; 29A5904A1F0509C0004D219C /* Plot.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Plot.swift; path = ../../Classes/Plots/Plot.swift; sourceTree = ""; }; + 58A6E0091FDA7E910047F7E0 /* ValueDrawingLayer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ValueDrawingLayer.swift; path = ../../Classes/Drawing/ValueDrawingLayer.swift; sourceTree = ""; }; + 58A6E00B1FDA7E9C0047F7E0 /* ValuePlot.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ValuePlot.swift; path = ../../Classes/Plots/ValuePlot.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -156,6 +160,7 @@ 29A590381F0500F5004D219C /* Drawing */ = { isa = PBXGroup; children = ( + 58A6E0091FDA7E910047F7E0 /* ValueDrawingLayer.swift */, 29A5903B1F05030F004D219C /* ScrollableGraphViewDrawingLayer.swift */, 29A590471F05049F004D219C /* LineDrawingLayer.swift */, 29A5903F1F050378004D219C /* DotDrawingLayer.swift */, @@ -175,6 +180,7 @@ 299482EA1F060CBE007BCDCA /* LinePlot.swift */, 299482EC1F060CDC007BCDCA /* DotPlot.swift */, 299482EE1F060CEA007BCDCA /* BarPlot.swift */, + 58A6E00B1FDA7E9C0047F7E0 /* ValuePlot.swift */, ); name = Plots; sourceTree = ""; @@ -262,6 +268,7 @@ 29A2477E1F09ED4E00F75511 /* ReferenceLines.swift in Sources */, 299482F71F06931F007BCDCA /* GraphPointAnimation.swift in Sources */, 299482EB1F060CBE007BCDCA /* LinePlot.swift in Sources */, + 58A6E00C1FDA7E9C0047F7E0 /* ValuePlot.swift in Sources */, 299482F91F069337007BCDCA /* GraphPoint.swift in Sources */, 299482EF1F060CEA007BCDCA /* BarPlot.swift in Sources */, 299482F41F060FE0007BCDCA /* ScrollableGraphViewDrawingDelegate.swift in Sources */, @@ -270,6 +277,7 @@ 291839A41C72E6A400753A45 /* ViewController.swift in Sources */, 29559B801C742D7800E77931 /* UIColor+colorFromHex.swift in Sources */, 299482ED1F060CDC007BCDCA /* DotPlot.swift in Sources */, + 58A6E00A1FDA7E910047F7E0 /* ValueDrawingLayer.swift in Sources */, 291839A21C72E6A400753A45 /* AppDelegate.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/graphview_example_code/GraphView/ViewController.swift b/graphview_example_code/GraphView/ViewController.swift index f0b29f4..3a1ab65 100644 --- a/graphview_example_code/GraphView/ViewController.swift +++ b/graphview_example_code/GraphView/ViewController.swift @@ -114,7 +114,8 @@ class ViewController: UIViewController, ScrollableGraphViewDataSource { let linePlot = LinePlot(identifier: "simple") // Identifier should be unique for each plot. let referenceLines = ReferenceLines() - + let dot = ValuePlot(identifier: "simple") + graphView.addPlot(plot: dot) graphView.addPlot(plot: linePlot) graphView.addReferenceLines(referenceLines: referenceLines) @@ -183,6 +184,10 @@ class ViewController: UIViewController, ScrollableGraphViewDataSource { graphView.addPlot(plot: orangeLinePlot) graphView.addPlot(plot: orangeSquarePlot) + let dot = ValuePlot(identifier: "multiBlue") + dot.adaptAnimationType = ScrollableGraphViewAnimationType.elastic + graphView.addPlot(plot: dot) + return graphView }