-
-
Notifications
You must be signed in to change notification settings - Fork 6k
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
Add gradient bars for BarChart [master branch] #4411
base: master
Are you sure you want to change the base?
Changes from 4 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 |
---|---|---|
|
@@ -32,6 +32,7 @@ class LineChart1ViewController: DemoBaseViewController { | |
.toggleIcons, | ||
.toggleStepped, | ||
.toggleHighlight, | ||
.toggleGradient, | ||
.animateX, | ||
.animateY, | ||
.animateXY, | ||
|
@@ -174,6 +175,11 @@ class LineChart1ViewController: DemoBaseViewController { | |
set.mode = (set.mode == .cubicBezier) ? .horizontalBezier : .cubicBezier | ||
} | ||
chartView.setNeedsDisplay() | ||
case .toggleGradient: | ||
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. is it possible for you to add the objc portion? (feel free to say no) |
||
for set in chartView.data!.dataSets as! [LineChartDataSet] { | ||
set.mode = (set.mode == .cubicBezier) ? .horizontalBezier : .cubicBezier | ||
} | ||
chartView.setNeedsDisplay() | ||
|
||
default: | ||
super.handleOption(option, forChartView: chartView) | ||
|
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,104 @@ open class BarChartRenderer: BarLineScatterCandleBubbleRenderer | |
context.fill(barRect) | ||
} | ||
} | ||
|
||
|
||
if dataSet.drawBarGradientEnabled | ||
{ | ||
drawGradientBars(context: context, dataSet: dataSet, buffer: buffer, matrix: valueToPixelMatrix) | ||
} | ||
else | ||
{ | ||
drawDefaultBars(context: context, dataSet: dataSet, dateSetIndex: index, buffer: buffer) | ||
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. maybe drawNormalBars or standard bars, etc? not sure which is better. @jjatie idea? |
||
} | ||
} | ||
|
||
private func drawGradientBars(context: CGContext, dataSet: IBarChartDataSet, 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 | ||
} | ||
|
||
for barRect in buffer.rects | ||
{ | ||
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) | ||
} | ||
} | ||
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, 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 drawDefaultBars(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 +522,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)? { | ||
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)? { | ||
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 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.
let's rename to a more meaningful name to imply it's about setup gradient