From 4eeb90353c4eed46ae792d2ac487ee8613860252 Mon Sep 17 00:00:00 2001 From: morkrom Date: Sun, 16 Nov 2014 12:55:46 -0800 Subject: [PATCH 1/2] Axis labels Option to plot labels for either axis with LineChartDelegate or by setting the plotLabelForAxis (conforming to PlotLabelForAxis) variable implemented. - Using either of these options sizes the label to fit. --- linechart/linechart/LineChart.swift | 76 +++++++++++++++----- linechart/linechart/MainViewController.swift | 11 +-- 2 files changed, 65 insertions(+), 22 deletions(-) mode change 100644 => 100755 linechart/linechart/LineChart.swift mode change 100644 => 100755 linechart/linechart/MainViewController.swift diff --git a/linechart/linechart/LineChart.swift b/linechart/linechart/LineChart.swift old mode 100644 new mode 100755 index fe9ed1a..078bc19 --- a/linechart/linechart/LineChart.swift +++ b/linechart/linechart/LineChart.swift @@ -17,13 +17,19 @@ func - (left: Array, right: Array) -> Array { } - // delegate method @objc protocol LineChartDelegate { func didSelectDataPoint(x: CGFloat, yValues: Array) + optional func plotLabelForX(index: Int) -> String + optional func plotLabelForY(index: Int) -> String } +enum Axis { + case x + case y +} +typealias PlotLabelForAxis = (axis: Axis, index: Int) -> String // LineChart class class LineChart: UIControl { @@ -39,6 +45,7 @@ class LineChart: UIControl { var numberOfGridLinesY: CGFloat = 10 var animationEnabled = true var animationDuration: CFTimeInterval = 1 + var plotLabelForAxis: PlotLabelForAxis? var dotsBackgroundColor = UIColor.whiteColor() @@ -176,8 +183,6 @@ class LineChart: UIControl { return UIColor(red: red, green: green, blue: blue, alpha: 1) } - - /** * Lighten color. */ @@ -254,8 +259,6 @@ class LineChart: UIControl { return roundedDividend } - - /** * Highlight data points at index. */ @@ -479,8 +482,6 @@ class LineChart: UIControl { } - - /** * Draw x grid. */ @@ -496,7 +497,6 @@ class LineChart: UIControl { } - /** * Draw y grid. */ @@ -514,7 +514,6 @@ class LineChart: UIControl { } - /** * Draw grid. */ @@ -523,8 +522,6 @@ class LineChart: UIControl { drawYGrid() } - - /** * Draw x labels. */ @@ -535,13 +532,18 @@ class LineChart: UIControl { var label = UILabel(frame: CGRect(x: scaledValue + (axisInset/2), y: self.bounds.height-axisInset, width: axisInset, height: axisInset)) label.font = UIFont.systemFontOfSize(10) label.textAlignment = NSTextAlignment.Center - label.text = String(index) + + let labelTextAndSizeToFit = labelTextForAxis(Axis.x, index: index) + label.text = labelTextAndSizeToFit.0//String(index) + + if labelTextAndSizeToFit.1 == true { + label.sizeToFit() + } + self.addSubview(label) } } - - /** * Draw y labels. */ @@ -555,13 +557,51 @@ class LineChart: UIControl { var label = UILabel(frame: CGRect(x: 0, y: yValue, width: axisInset, height: axisInset)) label.font = UIFont.systemFontOfSize(10) label.textAlignment = NSTextAlignment.Center - label.text = String(index) + + let labelTextAndSizeToFit = labelTextForAxis(Axis.y, index: index) + label.text = labelTextAndSizeToFit.0 //String(index) + if labelTextAndSizeToFit.1 == true { + label.sizeToFit() + } + self.addSubview(label) } } - - - + + func labelTextForAxis(axis: Axis, index: Int) -> (String, Bool) { + + var text = String(index) + var sizeToFit = false + if let plotLabelForAxis = plotLabelForAxis as PlotLabelForAxis? { + + text = plotLabelForAxis(axis: axis, index: index) + sizeToFit = true + } else { + + if let delegate = delegate as LineChartDelegate? { + + switch axis { + + case .x: + + if let xPlot = delegate.plotLabelForX!(index) as String? { + text = xPlot + sizeToFit = true + } + + case .y: + + if let yPlot = delegate.plotLabelForY!(index) as String? { + text = yPlot + sizeToFit = true + } + } + } + } + + return (text, sizeToFit) + } + /** * Add line chart */ diff --git a/linechart/linechart/MainViewController.swift b/linechart/linechart/MainViewController.swift old mode 100644 new mode 100755 index 3effaaa..3032010 --- a/linechart/linechart/MainViewController.swift +++ b/linechart/linechart/MainViewController.swift @@ -3,8 +3,6 @@ import UIKit import QuartzCore class MainViewController: UIViewController, LineChartDelegate { - - var label = UILabel() var lineChart: LineChart? @@ -40,8 +38,6 @@ class MainViewController: UIViewController, LineChartDelegate { } - - override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() } @@ -55,7 +51,14 @@ class MainViewController: UIViewController, LineChartDelegate { label.text = "x: \(x) y: \(yValues)" } + func plotLabelForX(index: Int) -> String { + return String(index) + } + func plotLabelForY(index: Int) -> String { + return String(index) + } + /** * Redraw chart on device rotation. From 11b8d115ff7442866d7f6d9fbe3a2ef277a9a408 Mon Sep 17 00:00:00 2001 From: morkrom Date: Sun, 16 Nov 2014 20:21:50 -0800 Subject: [PATCH 2/2] Label offsets MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - PlotLabel typealias includes “degrees rotated” var. - X and yLabel percentageOfWidth offsets. --- linechart/linechart/LineChart.swift | 90 ++++++++++++++++++++++++----- 1 file changed, 74 insertions(+), 16 deletions(-) diff --git a/linechart/linechart/LineChart.swift b/linechart/linechart/LineChart.swift index 078bc19..9ce8b41 100755 --- a/linechart/linechart/LineChart.swift +++ b/linechart/linechart/LineChart.swift @@ -29,7 +29,7 @@ enum Axis { case y } -typealias PlotLabelForAxis = (axis: Axis, index: Int) -> String +typealias PlotLabelForAxis = (axis: Axis, index: Int) -> (text: String, degreesRotated: CGFloat) // LineChart class class LineChart: UIControl { @@ -40,6 +40,9 @@ class LineChart: UIControl { var dotsVisible = true var labelsXVisible = false var labelsYVisible = false + var xLabelPercentOffsetFromCenter: CGFloat = 0 + var yLabelPercentOffsetFromCenter: CGFloat = 0 + var areaUnderLinesVisible = false var numberOfGridLinesX: CGFloat = 10 var numberOfGridLinesY: CGFloat = 10 @@ -348,11 +351,10 @@ class LineChart: UIControl { maximum = newMaximum } } + return CGFloat(maximum) } - - /** * Scale to fit drawing width. */ @@ -510,6 +512,7 @@ class LineChart: UIControl { CGContextMoveToPoint(context, axisInset, self.bounds.height - (CGFloat(index) * height) - axisInset) CGContextAddLineToPoint(context, self.bounds.width - axisInset, self.bounds.height - (CGFloat(index) * height) - axisInset) } + CGContextStrokePath(context) } @@ -532,18 +535,60 @@ class LineChart: UIControl { var label = UILabel(frame: CGRect(x: scaledValue + (axisInset/2), y: self.bounds.height-axisInset, width: axisInset, height: axisInset)) label.font = UIFont.systemFontOfSize(10) label.textAlignment = NSTextAlignment.Center - + label.lineBreakMode = NSLineBreakMode.ByWordWrapping + label.numberOfLines = 0 let labelTextAndSizeToFit = labelTextForAxis(Axis.x, index: index) label.text = labelTextAndSizeToFit.0//String(index) - - if labelTextAndSizeToFit.1 == true { - label.sizeToFit() - } + + applyDimensionsToLabel( + + label, + labelTextAndScale: labelTextAndSizeToFit, + offset: xLabelPercentOffsetFromCenter, + axis: Axis.x + ) + self.addSubview(label) } } + func degreesToRad(deg: CGFloat) -> CGFloat { + + return deg / (180 * CGFloat(M_PI)) + + } + + func radToDeg(rad: CGFloat) -> CGFloat { + + return (rad * (180 / CGFloat(M_PI)) ) + } + + func applyDimensionsToLabel(label: UILabel, labelTextAndScale: (String, Bool, CGFloat), offset: CGFloat, axis: Axis) { + + if labelTextAndScale.1 == true { + + let labelSize = label.text?.sizeWithAttributes([NSFontAttributeName: label.font]) as CGSize? + let width = labelSize?.width + let height = labelSize?.height + let x = axis == .x ? label.frame.origin.x - (width! * offset) : label.frame.origin.x + let y = axis == .y ? label.frame.origin.y - (height! * offset) : label.frame.origin.y + + label.frame = CGRectMake( + + x, + y, + width!, + height! + ) + + let rads = degreesToRad(labelTextAndScale.2) + let tr: CGAffineTransform = CGAffineTransformMakeRotation(rads) + + label.transform = tr + } + } + /** * Draw y labels. */ @@ -557,25 +602,38 @@ class LineChart: UIControl { var label = UILabel(frame: CGRect(x: 0, y: yValue, width: axisInset, height: axisInset)) label.font = UIFont.systemFontOfSize(10) label.textAlignment = NSTextAlignment.Center - + label.numberOfLines = 0 + label.lineBreakMode = NSLineBreakMode.ByWordWrapping let labelTextAndSizeToFit = labelTextForAxis(Axis.y, index: index) label.text = labelTextAndSizeToFit.0 //String(index) - if labelTextAndSizeToFit.1 == true { - label.sizeToFit() - } + + applyDimensionsToLabel( + + label, + labelTextAndScale: labelTextAndSizeToFit, + offset: yLabelPercentOffsetFromCenter, + axis: Axis.y + + ) self.addSubview(label) } } - func labelTextForAxis(axis: Axis, index: Int) -> (String, Bool) { + func labelTextForAxis(axis: Axis, index: Int) -> (String, Bool, CGFloat) { var text = String(index) var sizeToFit = false + var rotationDegrees: CGFloat = 0 + if let plotLabelForAxis = plotLabelForAxis as PlotLabelForAxis? { - text = plotLabelForAxis(axis: axis, index: index) + let plotLabelForAxis = plotLabelForAxis(axis: axis, index: index) + text = plotLabelForAxis.0 + rotationDegrees = plotLabelForAxis.1 + sizeToFit = true + } else { if let delegate = delegate as LineChartDelegate? { @@ -583,7 +641,7 @@ class LineChart: UIControl { switch axis { case .x: - + if let xPlot = delegate.plotLabelForX!(index) as String? { text = xPlot sizeToFit = true @@ -599,7 +657,7 @@ class LineChart: UIControl { } } - return (text, sizeToFit) + return (text, sizeToFit, rotationDegrees) } /**