From ba56599eec64604c8d76a7bff82b4b4a4eccf08f Mon Sep 17 00:00:00 2001 From: Nerijus Lasauskas Date: Mon, 5 Dec 2016 07:39:29 +0200 Subject: [PATCH 1/2] Add rounded corners on the bar chart --- ChartsDemo/Classes/DemoBaseViewController.m | 22 +++++++++ .../Classes/Demos/BarChartViewController.m | 2 + Source/Charts/Charts/BarChartView.swift | 17 +++++++ Source/Charts/Charts/CombinedChartView.swift | 10 ++++ .../Standard/BarChartDataSet.swift | 3 ++ .../Data/Interfaces/IBarChartDataSet.swift | 3 ++ .../Interfaces/BarChartDataProvider.swift | 3 +- .../Charts/Renderers/BarChartRenderer.swift | 47 +++++++++++++++---- .../Renderers/CombinedChartRenderer.swift | 3 ++ Source/ChartsRealm/Data/RealmBarDataSet.swift | 3 ++ 10 files changed, 104 insertions(+), 9 deletions(-) diff --git a/ChartsDemo/Classes/DemoBaseViewController.m b/ChartsDemo/Classes/DemoBaseViewController.m index 3a142369fd..33a6fe60c8 100644 --- a/ChartsDemo/Classes/DemoBaseViewController.m +++ b/ChartsDemo/Classes/DemoBaseViewController.m @@ -143,6 +143,28 @@ - (void)handleOption:(NSString *)key forChartView:(ChartViewBase *)chartView [chartView setNeedsDisplay]; } + + if ([key isEqualToString:@"toggleRoundedBarsAllCorners"]) + { + ((BarChartView *)chartView).drawRoundedBarEnabled = YES; + + [chartView setNeedsDisplay]; + } + + if ([key isEqualToString:@"toggleRoundedBarsTopCorners"]) + { + ((BarChartView *)chartView).drawRoundedBarEnabled = YES; + + for (id set in chartView.data.dataSets) + { + if ([set conformsToProtocol:@protocol(IBarChartDataSet)]) + { + set.barRoundingCorners = UIRectCornerTopLeft | UIRectCornerTopRight; + } + } + + [chartView setNeedsDisplay]; + } } #pragma mark - Actions diff --git a/ChartsDemo/Classes/Demos/BarChartViewController.m b/ChartsDemo/Classes/Demos/BarChartViewController.m index cdf8583cec..b0dc8c0029 100644 --- a/ChartsDemo/Classes/Demos/BarChartViewController.m +++ b/ChartsDemo/Classes/Demos/BarChartViewController.m @@ -42,6 +42,8 @@ - (void)viewDidLoad @{@"key": @"toggleAutoScaleMinMax", @"label": @"Toggle auto scale min/max"}, @{@"key": @"toggleData", @"label": @"Toggle Data"}, @{@"key": @"toggleBarBorders", @"label": @"Show Bar Borders"}, + @{@"key": @"toggleRoundedBarsAllCorners", @"label": @"All Corners Rounded"}, + @{@"key": @"toggleRoundedBarsTopCorners", @"label": @"Top Corners Rounded"}, ]; [self setupBarLineChartView:_chartView]; diff --git a/Source/Charts/Charts/BarChartView.swift b/Source/Charts/Charts/BarChartView.swift index a9e060b48b..08bc347e10 100644 --- a/Source/Charts/Charts/BarChartView.swift +++ b/Source/Charts/Charts/BarChartView.swift @@ -21,6 +21,9 @@ open class BarChartView: BarLineChartViewBase, BarChartDataProvider /// if set to true, a grey area is drawn behind each bar that indicates the maximum value fileprivate var _drawBarShadowEnabled = false + /// if set to true, a rounded rectangle with the corners is drawn on each bar + fileprivate var _drawRoundedBarEnabled = false + internal override func initialize() { super.initialize() @@ -159,6 +162,17 @@ open class BarChartView: BarLineChartViewBase, BarChartDataProvider setNeedsDisplay() } } + + /// if set to true, a rounded rectangle with the corners is drawn on each bar + open var drawRoundedBarEnabled: Bool + { + get { return _drawRoundedBarEnabled } + set + { + _drawRoundedBarEnabled = newValue + setNeedsDisplay() + } + } /// Adds half of the bar width to each side of the x-axis range in order to allow the bars of the barchart to be fully displayed. /// **default**: false @@ -180,4 +194,7 @@ open class BarChartView: BarLineChartViewBase, BarChartDataProvider /// - returns: `true` if drawing shadows (maxvalue) for each bar is enabled, `false` ifnot open var isDrawBarShadowEnabled: Bool { return drawBarShadowEnabled } + + /// - returns: `true` if drawing rounded bars is enabled, `false` ifnot + open var isDrawRoundedBarEnabled: Bool { return drawRoundedBarEnabled } } diff --git a/Source/Charts/Charts/CombinedChartView.swift b/Source/Charts/Charts/CombinedChartView.swift index 0fce9e8d94..3ffe1767ce 100644 --- a/Source/Charts/Charts/CombinedChartView.swift +++ b/Source/Charts/Charts/CombinedChartView.swift @@ -195,6 +195,13 @@ open class CombinedChartView: BarLineChartViewBase, CombinedChartDataProvider get { return (renderer as! CombinedChartRenderer!).drawBarShadowEnabled } set { (renderer as! CombinedChartRenderer!).drawBarShadowEnabled = newValue } } + + /// if set to true, a rounded rectangle with the corners is drawn on each bar + open var drawRoundedBarEnabled: Bool + { + get { return (renderer as! CombinedChartRenderer!).drawRoundedBarEnabled } + set { (renderer as! CombinedChartRenderer!).drawRoundedBarEnabled = newValue } + } /// - returns: `true` if drawing values above bars is enabled, `false` ifnot open var isDrawValueAboveBarEnabled: Bool { return (renderer as! CombinedChartRenderer!).drawValueAboveBarEnabled } @@ -222,4 +229,7 @@ open class CombinedChartView: BarLineChartViewBase, CombinedChartDataProvider /// - returns: `true` the highlight is be full-bar oriented, `false` ifsingle-value open var isHighlightFullBarEnabled: Bool { return highlightFullBarEnabled } + + /// - returns: `true` if drawing rounded bars is enabled, `false` ifnot + open var isDrawRoundedBarEnabled: Bool { return drawRoundedBarEnabled } } diff --git a/Source/Charts/Data/Implementations/Standard/BarChartDataSet.swift b/Source/Charts/Data/Implementations/Standard/BarChartDataSet.swift index bba2cac4ad..a82b22471d 100644 --- a/Source/Charts/Data/Implementations/Standard/BarChartDataSet.swift +++ b/Source/Charts/Data/Implementations/Standard/BarChartDataSet.swift @@ -146,6 +146,9 @@ open class BarChartDataSet: BarLineScatterCandleBubbleChartDataSet, IBarChartDat /// the color drawing borders around the bars. open var barBorderColor = NSUIColor.black + /// the option rounding bar corners + open var barRoundingCorners: UIRectCorner = .allCorners + /// the alpha value (transparency) that is used for drawing the highlight indicator bar. min = 0.0 (fully transparent), max = 1.0 (fully opaque) open var highlightAlpha = CGFloat(120.0 / 255.0) diff --git a/Source/Charts/Data/Interfaces/IBarChartDataSet.swift b/Source/Charts/Data/Interfaces/IBarChartDataSet.swift index 6f5cad081c..c58766ccfc 100644 --- a/Source/Charts/Data/Interfaces/IBarChartDataSet.swift +++ b/Source/Charts/Data/Interfaces/IBarChartDataSet.swift @@ -34,6 +34,9 @@ public protocol IBarChartDataSet: IBarLineScatterCandleBubbleChartDataSet /// the color drawing borders around the bars. var barBorderColor: NSUIColor { get set } + /// the option rounding bar corners + var barRoundingCorners: UIRectCorner { get set } + /// the alpha value (transparency) that is used for drawing the highlight indicator bar. min = 0.0 (fully transparent), max = 1.0 (fully opaque) var highlightAlpha: CGFloat { get set } diff --git a/Source/Charts/Interfaces/BarChartDataProvider.swift b/Source/Charts/Interfaces/BarChartDataProvider.swift index e1d0a8d0b5..fb0eae961c 100644 --- a/Source/Charts/Interfaces/BarChartDataProvider.swift +++ b/Source/Charts/Interfaces/BarChartDataProvider.swift @@ -18,6 +18,7 @@ public protocol BarChartDataProvider: BarLineScatterCandleBubbleChartDataProvide var barData: BarChartData? { get } var isDrawBarShadowEnabled: Bool { get } + var isDrawRoundedBarEnabled: Bool { get } var isDrawValueAboveBarEnabled: Bool { get } var isHighlightFullBarEnabled: Bool { get } -} \ No newline at end of file +} diff --git a/Source/Charts/Renderers/BarChartRenderer.swift b/Source/Charts/Renderers/BarChartRenderer.swift index 579810f844..d2771894e8 100644 --- a/Source/Charts/Renderers/BarChartRenderer.swift +++ b/Source/Charts/Renderers/BarChartRenderer.swift @@ -216,6 +216,8 @@ open class BarChartRenderer: BarLineScatterCandleBubbleRenderer let borderWidth = dataSet.barBorderWidth let borderColor = dataSet.barBorderColor let drawBorder = borderWidth > 0.0 + + let roundingCorners = dataSet.barRoundingCorners context.saveGState() @@ -310,14 +312,31 @@ open class BarChartRenderer: BarLineScatterCandleBubbleRenderer // Set the color for the currently drawn value. If the index is out of bounds, reuse colors. context.setFillColor(dataSet.color(atIndex: j).cgColor) } - - context.fill(barRect) - - if drawBorder + + if dataProvider.isDrawRoundedBarEnabled { - context.setStrokeColor(borderColor.cgColor) - context.setLineWidth(borderWidth) - context.stroke(barRect) + let cornerRadius = CGSize(width: barRect.width / 2.0, height: barRect.width / 2.0) + let bezierPath = UIBezierPath(roundedRect: barRect, byRoundingCorners: roundingCorners, cornerRadii: cornerRadius) + context.addPath(bezierPath.cgPath) + context.fillPath() + + if drawBorder + { + bezierPath.lineWidth = borderWidth + borderColor.setStroke() + bezierPath.stroke() + } + } + else + { + context.fill(barRect) + + if drawBorder + { + context.setStrokeColor(borderColor.cgColor) + context.setLineWidth(borderWidth) + context.stroke(barRect) + } } } @@ -575,6 +594,8 @@ open class BarChartRenderer: BarLineScatterCandleBubbleRenderer set.isHighlightEnabled else { continue } + let roundingCorners = set.barRoundingCorners + if let e = set.entryForXValue(high.x, closestToY: high.y) as? BarChartDataEntry { if !isInBoundsX(entry: e, dataSet: set) @@ -617,7 +638,17 @@ open class BarChartRenderer: BarLineScatterCandleBubbleRenderer setHighlightDrawPos(highlight: high, barRect: barRect) - context.fill(barRect) + if dataProvider.isDrawRoundedBarEnabled + { + let cornerRadius = CGSize(width: barRect.width / 2.0, height: barRect.width / 2.0) + let bezierPath = UIBezierPath(roundedRect: barRect, byRoundingCorners: roundingCorners, cornerRadii: cornerRadius) + context.addPath(bezierPath.cgPath) + context.fillPath() + } + else + { + context.fill(barRect) + } } } diff --git a/Source/Charts/Renderers/CombinedChartRenderer.swift b/Source/Charts/Renderers/CombinedChartRenderer.swift index 7c24d1cdee..93da083527 100644 --- a/Source/Charts/Renderers/CombinedChartRenderer.swift +++ b/Source/Charts/Renderers/CombinedChartRenderer.swift @@ -22,6 +22,9 @@ open class CombinedChartRenderer: DataRenderer /// if set to true, a grey area is drawn behind each bar that indicates the maximum value open var drawBarShadowEnabled = false + /// if set to true, a rounded rectangle with the corners is drawn on each bar + open var drawRoundedBarEnabled = false + internal var _renderers = [DataRenderer]() internal var _drawOrder: [CombinedChartView.DrawOrder] = [.bar, .bubble, .line, .candle, .scatter] diff --git a/Source/ChartsRealm/Data/RealmBarDataSet.swift b/Source/ChartsRealm/Data/RealmBarDataSet.swift index 3d1b600ecc..fa31a8f60c 100644 --- a/Source/ChartsRealm/Data/RealmBarDataSet.swift +++ b/Source/ChartsRealm/Data/RealmBarDataSet.swift @@ -214,6 +214,9 @@ open class RealmBarDataSet: RealmBarLineScatterCandleBubbleDataSet, IBarChartDat /// the color drawing borders around the bars. open var barBorderColor = NSUIColor(red: 0.0/255.0, green: 0.0/255.0, blue: 0.0/255.0, alpha: 1.0) + /// the option rounding bar corners + open var barRoundingCorners: UIRectCorner = .allCorners + /// the alpha value (transparency) that is used for drawing the highlight indicator bar. min = 0.0 (fully transparent), max = 1.0 (fully opaque) open var highlightAlpha = CGFloat(120.0 / 255.0) From 2922a34bfe0c453bf37f929153a28fc51e8b52b8 Mon Sep 17 00:00:00 2001 From: Nerijus Lasauskas Date: Thu, 22 Dec 2016 15:37:10 +0200 Subject: [PATCH 2/2] Fix rounded corners on the chart bar for macOS --- .../Standard/BarChartDataSet.swift | 2 + .../Data/Interfaces/IBarChartDataSet.swift | 2 + .../Charts/Renderers/BarChartRenderer.swift | 22 +++++---- Source/Charts/Utils/Platform.swift | 48 +++++++++++++++++++ Source/ChartsRealm/Data/RealmBarDataSet.swift | 2 + 5 files changed, 68 insertions(+), 8 deletions(-) diff --git a/Source/Charts/Data/Implementations/Standard/BarChartDataSet.swift b/Source/Charts/Data/Implementations/Standard/BarChartDataSet.swift index a82b22471d..49b165ffab 100644 --- a/Source/Charts/Data/Implementations/Standard/BarChartDataSet.swift +++ b/Source/Charts/Data/Implementations/Standard/BarChartDataSet.swift @@ -146,8 +146,10 @@ open class BarChartDataSet: BarLineScatterCandleBubbleChartDataSet, IBarChartDat /// the color drawing borders around the bars. open var barBorderColor = NSUIColor.black + #if !os(OSX) /// the option rounding bar corners open var barRoundingCorners: UIRectCorner = .allCorners + #endif /// the alpha value (transparency) that is used for drawing the highlight indicator bar. min = 0.0 (fully transparent), max = 1.0 (fully opaque) open var highlightAlpha = CGFloat(120.0 / 255.0) diff --git a/Source/Charts/Data/Interfaces/IBarChartDataSet.swift b/Source/Charts/Data/Interfaces/IBarChartDataSet.swift index c58766ccfc..e2d2a863a6 100644 --- a/Source/Charts/Data/Interfaces/IBarChartDataSet.swift +++ b/Source/Charts/Data/Interfaces/IBarChartDataSet.swift @@ -34,8 +34,10 @@ public protocol IBarChartDataSet: IBarLineScatterCandleBubbleChartDataSet /// the color drawing borders around the bars. var barBorderColor: NSUIColor { get set } + #if !os(OSX) /// the option rounding bar corners var barRoundingCorners: UIRectCorner { get set } + #endif /// the alpha value (transparency) that is used for drawing the highlight indicator bar. min = 0.0 (fully transparent), max = 1.0 (fully opaque) var highlightAlpha: CGFloat { get set } diff --git a/Source/Charts/Renderers/BarChartRenderer.swift b/Source/Charts/Renderers/BarChartRenderer.swift index d2771894e8..b5a7c88a47 100644 --- a/Source/Charts/Renderers/BarChartRenderer.swift +++ b/Source/Charts/Renderers/BarChartRenderer.swift @@ -216,8 +216,6 @@ open class BarChartRenderer: BarLineScatterCandleBubbleRenderer let borderWidth = dataSet.barBorderWidth let borderColor = dataSet.barBorderColor let drawBorder = borderWidth > 0.0 - - let roundingCorners = dataSet.barRoundingCorners context.saveGState() @@ -316,8 +314,13 @@ open class BarChartRenderer: BarLineScatterCandleBubbleRenderer if dataProvider.isDrawRoundedBarEnabled { let cornerRadius = CGSize(width: barRect.width / 2.0, height: barRect.width / 2.0) - let bezierPath = UIBezierPath(roundedRect: barRect, byRoundingCorners: roundingCorners, cornerRadii: cornerRadius) - context.addPath(bezierPath.cgPath) + #if os(OSX) + let bezierPath = NSBezierPath(roundedRect: barRect, xRadius: cornerRadius.width, yRadius: cornerRadius.height) + context.addPath(bezierPath.cgPath) + #else + let bezierPath = UIBezierPath(roundedRect: barRect, byRoundingCorners: dataSet.barRoundingCorners, cornerRadii: cornerRadius) + context.addPath(bezierPath.cgPath) + #endif context.fillPath() if drawBorder @@ -593,8 +596,6 @@ open class BarChartRenderer: BarLineScatterCandleBubbleRenderer let set = barData.getDataSetByIndex(high.dataSetIndex) as? IBarChartDataSet, set.isHighlightEnabled else { continue } - - let roundingCorners = set.barRoundingCorners if let e = set.entryForXValue(high.x, closestToY: high.y) as? BarChartDataEntry { @@ -641,8 +642,13 @@ open class BarChartRenderer: BarLineScatterCandleBubbleRenderer if dataProvider.isDrawRoundedBarEnabled { let cornerRadius = CGSize(width: barRect.width / 2.0, height: barRect.width / 2.0) - let bezierPath = UIBezierPath(roundedRect: barRect, byRoundingCorners: roundingCorners, cornerRadii: cornerRadius) - context.addPath(bezierPath.cgPath) + #if os(OSX) + let bezierPath = NSBezierPath(roundedRect: barRect, xRadius: cornerRadius.width, yRadius: cornerRadius.height) + context.addPath(bezierPath.cgPath) + #else + let bezierPath = UIBezierPath(roundedRect: barRect, byRoundingCorners: set.barRoundingCorners, cornerRadii: cornerRadius) + context.addPath(bezierPath.cgPath) + #endif context.fillPath() } else diff --git a/Source/Charts/Utils/Platform.swift b/Source/Charts/Utils/Platform.swift index 00baaec3ef..c85184cc77 100644 --- a/Source/Charts/Utils/Platform.swift +++ b/Source/Charts/Utils/Platform.swift @@ -515,6 +515,54 @@ types are aliased to either their UI* implementation (on iOS) or their NS* imple } } } + + extension NSBezierPath + { + var cgPath: CGPath + { + let mutablePath = CGMutablePath() + var points = [CGPoint](repeating: .zero, count: 3) + for i in 0 ..< elementCount + { + let type = element(at: i, associatedPoints: &points) + switch type + { + case .moveToBezierPathElement: + mutablePath.move( + to: CGPoint( + x: points[0].x, + y: points[0].y + ) + ) + case .lineToBezierPathElement: + mutablePath.addLine( + to: CGPoint( + x: points[0].x, + y: points[0].y + ) + ) + case .curveToBezierPathElement: + mutablePath.addCurve( + to: CGPoint( + x: points[2].x, + y: points[2].y + ), + control1: CGPoint( + x: points[0].x, + y: points[0].y + ), + control2: CGPoint( + x: points[1].x, + y: points[1].y + ) + ) + case .closePathBezierPathElement: + mutablePath.closeSubpath() + } + } + return mutablePath + } + } extension NSString { diff --git a/Source/ChartsRealm/Data/RealmBarDataSet.swift b/Source/ChartsRealm/Data/RealmBarDataSet.swift index fa31a8f60c..9c2810170a 100644 --- a/Source/ChartsRealm/Data/RealmBarDataSet.swift +++ b/Source/ChartsRealm/Data/RealmBarDataSet.swift @@ -214,8 +214,10 @@ open class RealmBarDataSet: RealmBarLineScatterCandleBubbleDataSet, IBarChartDat /// the color drawing borders around the bars. open var barBorderColor = NSUIColor(red: 0.0/255.0, green: 0.0/255.0, blue: 0.0/255.0, alpha: 1.0) + #if !os(OSX) /// the option rounding bar corners open var barRoundingCorners: UIRectCorner = .allCorners + #endif /// the alpha value (transparency) that is used for drawing the highlight indicator bar. min = 0.0 (fully transparent), max = 1.0 (fully opaque) open var highlightAlpha = CGFloat(120.0 / 255.0)