-
-
Notifications
You must be signed in to change notification settings - Fork 6k
Add gradient bars for BarChart [master branch] #4411
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
e6f82b3
842b0d8
b7af4db
30c8b21
be3ddb3
204f66e
e59ade1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -328,14 +328,11 @@ open class BarChartRenderer: BarLineScatterCandleBubbleRenderer | |
| guard let dataProvider = dataProvider else { return } | ||
|
|
||
| let trans = dataProvider.getTransformer(forAxis: dataSet.axisDependency) | ||
|
|
||
| let valueToPixelMatrix = trans.valueToPixelMatrix | ||
|
|
||
| prepareBuffer(dataSet: dataSet, index: index) | ||
| trans.rectValuesToPixel(&_buffers[index].rects) | ||
|
|
||
| let borderWidth = dataSet.barBorderWidth | ||
| let borderColor = dataSet.barBorderColor | ||
| let drawBorder = borderWidth > 0.0 | ||
|
|
||
| context.saveGState() | ||
|
|
||
| // draw the bar shadow before the values | ||
|
|
@@ -399,9 +396,123 @@ open class BarChartRenderer: BarLineScatterCandleBubbleRenderer | |
| context.fill(barRect) | ||
| } | ||
| } | ||
|
|
||
|
|
||
| if dataSet.drawBarGradientEnabled | ||
| { | ||
| drawGradientBars(context: context, dataSet: dataSet, dateSetIndex: index, buffer: buffer, matrix: valueToPixelMatrix) | ||
| } | ||
| else | ||
| { | ||
| drawNormalBars(context: context, dataSet: dataSet, dateSetIndex: index, buffer: buffer) | ||
| } | ||
| } | ||
|
|
||
| private func drawGradientBars(context: CGContext, dataSet: IBarChartDataSet, dateSetIndex index: Int, buffer: BarChartRenderer.Buffer, matrix: CGAffineTransform) | ||
| { | ||
|
|
||
| guard let gradientPositions = dataSet.gradientPositions else | ||
| { | ||
| assertionFailure("Must set `gradientPositions if `dataSet.drawBarGradientEnabled` is true") | ||
| return | ||
| } | ||
|
|
||
| guard let boundingBox = buffer.rects.union() else { return } | ||
| guard !boundingBox.isNull, !boundingBox.isInfinite, !boundingBox.isEmpty else { return } | ||
|
|
||
| let drawBorder = dataSet.barBorderWidth > 0 | ||
|
|
||
| let gradientStart = dataSet.gradientEnd.isInfinite ? | ||
| CGPoint(x: boundingBox.minX, y: boundingBox.minY) : | ||
| dataSet.gradientEnd.applying(matrix) | ||
|
|
||
| let gradientEnd = dataSet.gradientStart.isInfinite ? | ||
| CGPoint(x: boundingBox.minX, y: boundingBox.maxY) : | ||
| dataSet.gradientStart.applying(matrix) | ||
|
|
||
| var gradientColorComponents: [CGFloat] = [] | ||
| var gradientLocations: [CGFloat] = [] | ||
|
|
||
| for position in gradientPositions.reversed() | ||
| { | ||
| let location = CGPoint(x: boundingBox.minX, y: position) | ||
| .applying(matrix) | ||
| let normalizedLocation = | ||
| (location.y - boundingBox.minY) / (boundingBox.maxY - boundingBox.minY) | ||
| switch normalizedLocation { | ||
| case ..<0: | ||
| gradientLocations.append(0) | ||
| case 0..<1: | ||
| gradientLocations.append(normalizedLocation) | ||
| case 1...: | ||
| gradientLocations.append(1) | ||
| default: | ||
| assertionFailure() | ||
| } | ||
| } | ||
|
|
||
| for color in dataSet.colors.reversed() | ||
| { | ||
| guard let (r, g, b, a) = color.nsuirgba else { | ||
| continue | ||
| } | ||
| gradientColorComponents += [r, g, b, a] | ||
| } | ||
|
|
||
| let baseColorSpace = CGColorSpaceCreateDeviceRGB() | ||
| guard let gradient = CGGradient( | ||
| colorSpace: baseColorSpace, | ||
| colorComponents: &gradientColorComponents, | ||
| locations: &gradientLocations, | ||
| count: gradientLocations.count) else { | ||
| return | ||
| } | ||
|
|
||
| // In case the chart is stacked, we need to accomodate individual bars within accessibilityOrdereredElements | ||
| let isStacked = dataSet.isStacked | ||
| let stackSize = isStacked ? dataSet.stackSize : 1 | ||
|
|
||
| for (barIndex, barRect) in buffer.rects.enumerated() | ||
| { | ||
| context.saveGState() | ||
| defer { context.restoreGState() } | ||
|
|
||
| guard viewPortHandler.isInBoundsLeft(barRect.maxX) else { continue } | ||
| guard viewPortHandler.isInBoundsRight(barRect.minX) else { break } | ||
|
|
||
| context.beginPath() | ||
| context.addRect(barRect) | ||
| context.clip() | ||
| context.drawLinearGradient(gradient, start: gradientStart, end: gradientEnd, options: []) | ||
|
|
||
| if drawBorder | ||
| { | ||
| context.setStrokeColor(dataSet.barBorderColor.cgColor) | ||
| context.setLineWidth(dataSet.barBorderWidth) | ||
| context.stroke(barRect) | ||
| } | ||
|
|
||
| // Create and append the corresponding accessibility element to accessibilityOrderedElements | ||
| if let chart = dataProvider as? BarChartView | ||
| { | ||
| let element = createAccessibleElement(withIndex: barIndex, | ||
| container: chart, | ||
| dataSet: dataSet, | ||
| dataSetIndex: index, | ||
| stackSize: stackSize) | ||
| { (element) in | ||
| element.accessibilityFrame = barRect | ||
| } | ||
|
|
||
| accessibilityOrderedElements[barIndex/stackSize].append(element) | ||
| } | ||
| } | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. in gradient bars,
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @liuxuan30 pushed commit. Hope that I did it correct. |
||
| } | ||
|
|
||
| private func drawNormalBars(context: CGContext, dataSet: IBarChartDataSet, dateSetIndex index: Int, buffer: BarChartRenderer.Buffer) | ||
| { | ||
| let drawBorder = dataSet.barBorderWidth > 0 | ||
| let isSingleColor = dataSet.colors.count == 1 | ||
|
|
||
| if isSingleColor | ||
| { | ||
| context.setFillColor(dataSet.color(atIndex: 0).cgColor) | ||
|
|
@@ -430,13 +541,13 @@ 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 | ||
| { | ||
| context.setStrokeColor(borderColor.cgColor) | ||
| context.setLineWidth(borderWidth) | ||
| context.setStrokeColor(dataSet.barBorderColor.cgColor) | ||
| context.setLineWidth(dataSet.barBorderWidth) | ||
| context.stroke(barRect) | ||
| } | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -14,6 +14,22 @@ public typealias NSUIScrollView = UIScrollView | |
| public typealias NSUIScreen = UIScreen | ||
| public typealias NSUIDisplayLink = CADisplayLink | ||
|
|
||
| extension NSUIColor | ||
| { | ||
| var nsuirgba: (red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat)? { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. move { to a new line |
||
| var red: CGFloat = 0 | ||
| var green: CGFloat = 0 | ||
| var blue: CGFloat = 0 | ||
| var alpha: CGFloat = 0 | ||
|
|
||
| guard getRed(&red, green: &green, blue: &blue, alpha: &alpha) else { | ||
| return nil | ||
| } | ||
|
|
||
| return (red: red, green: green, blue: blue, alpha: alpha) | ||
| } | ||
| } | ||
|
|
||
| open class NSUIView: UIView | ||
| { | ||
| @objc var nsuiLayer: CALayer? | ||
|
|
@@ -124,6 +140,26 @@ public class NSUIDisplayLink | |
| } | ||
| } | ||
|
|
||
| extension NSUIColor | ||
| { | ||
| var nsuirgba: (red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat)? { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. though the imp is different, here are two
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @larryonoff can you get the notification? I basically finished the review, jsut some minor issues to address. |
||
| var red: CGFloat = 0 | ||
| var green: CGFloat = 0 | ||
| var blue: CGFloat = 0 | ||
| var alpha: CGFloat = 0 | ||
|
|
||
| guard let colorSpaceModel = cgColor.colorSpace?.model else { | ||
| return nil | ||
| } | ||
| guard colorSpaceModel == .rgb else { | ||
| return nil | ||
| } | ||
|
|
||
| getRed(&red, green: &green, blue: &blue, alpha: &alpha) | ||
| return (red: red, green: green, blue: blue, alpha: alpha) | ||
| } | ||
| } | ||
|
|
||
| extension NSView | ||
| { | ||
| final var nsuiGestureRecognizers: [NSGestureRecognizer]? | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is it possible for you to add the objc portion? (feel free to say no)