-
-
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 support for rounded corners for BarChart #3754
Conversation
except for CI errors, is problem solved for what I asked #1066 (comment) ? |
|
@skarol I mean if the bars are thin enough, it becomes an oval more like a bar with rounded corners. That's what I said a flaw in #1066 (comment), and hold similar PRs till now. Have you solved this? (sorry I don't have time to download your PR and test it on my side so far) If so, I could take a deep look and maybe we could fix the CI errors and get this merged. |
@liuxuan30 yes, I've solved it. Basically, corner radius is half of bar's width for |
That's fantastic. we will take time for this. But maybe longer :( |
@jjatie which branch do you think we should use to merge this PR? I'm asking because this is a nice feature that waited for too long (if it solves my questions), so I'm hoping to add them soon in master. But I'm seeing conflicts with 4.0 refactor. |
@@ -377,9 +377,9 @@ open class BarChartRenderer: BarLineScatterCandleBubbleRenderer | |||
// draw the bar shadow before the values | |||
if dataProvider.isDrawBarShadowEnabled | |||
{ | |||
for j in stride(from: 0, to: buffer.rects.count, by: 1) | |||
for firstIndexInBar in stride(from: 0, to: buffer.rects.count, by: 1) |
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.
why change name here? seems nothing about first index
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.
I have the same question. If anything the change should be:
for barRect in buffer.rects
where viewPortHandler.isInBoundsLeft(barRect.maxX)
{
guard viewPortHandler.isInBoundsRight(barRect.origin.x) else
{
break
}
context.setFillColor(dataSet.barShadowColor.cgColor)
context.fill(barRect)
}
@@ -896,4 +934,32 @@ open class BarChartRenderer: BarLineScatterCandleBubbleRenderer | |||
|
|||
return element | |||
} | |||
|
|||
private func findTopRectInBar(barRects: [CGRect], firstIndexInBar: Int, lastIndexInBar: Int) -> CGRect { |
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 put all {
to another line. This is the code style for this library
@@ -628,4 +655,31 @@ open class HorizontalBarChartRenderer: BarChartRenderer | |||
{ | |||
high.setDraw(x: barRect.midY, y: barRect.origin.x + barRect.size.width) | |||
} | |||
|
|||
override internal func createBarPath(for rect: CGRect, roundedCorners: UIRectCorner) -> UIBezierPath { |
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.
could bar renderer and horizontal bar renderer share the same createBarPath
and findMostLeftRectInBar
somehow?
@@ -339,4 +339,12 @@ class BarChartTests: FBSnapshotTestCase | |||
chart.notifyDataSetChanged() | |||
FBSnapshotVerifyView(chart, identifier: Snapshot.identifier(UIScreen.main.bounds.size), tolerance: Snapshot.tolerance) | |||
} | |||
|
|||
func testRoundedCorners() { |
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.
not seeing updated images for testing rounded corners.
@@ -402,53 +402,81 @@ open class BarChartRenderer: BarLineScatterCandleBubbleRenderer | |||
{ | |||
context.setFillColor(dataSet.color(atIndex: 0).cgColor) | |||
} | |||
|
|||
context.setStrokeColor(borderColor.cgColor) |
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.
it seems you are using drawBorder
properties for rounded corners. Why force setting setLineCap(.square)
?
But what if people disable drawBorder
?
|
||
// 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 j in stride(from: 0, to: buffer.rects.count, by: 1) | ||
for firstIndexInBar in stride(from: 0, to: buffer.rects.count, by: stackSize) |
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.
why stackSize here?
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.
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.
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.
Hello @panncherry
You can check my fork/branch. Do not remember if bothered with an example adjustment as not going to upload a pull request, but the changes should be pretty straightforward to update existing StackedBarChar from the ChartsDemo-iOS
@skarol it seems CI failed because multiple bar chart tests failures. If rounded corner is turned on by default, then that's the reason. we need to have a switch to turn it off and add a new rounded bar test. |
@@ -377,9 +377,9 @@ open class BarChartRenderer: BarLineScatterCandleBubbleRenderer | |||
// draw the bar shadow before the values | |||
if dataProvider.isDrawBarShadowEnabled | |||
{ | |||
for j in stride(from: 0, to: buffer.rects.count, by: 1) | |||
for firstIndexInBar in stride(from: 0, to: buffer.rects.count, by: 1) |
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.
I have the same question. If anything the change should be:
for barRect in buffer.rects
where viewPortHandler.isInBoundsLeft(barRect.maxX)
{
guard viewPortHandler.isInBoundsRight(barRect.origin.x) else
{
break
}
context.setFillColor(dataSet.barShadowColor.cgColor)
context.fill(barRect)
}
{ | ||
// Set the color for the currently drawn value. If the index is out of bounds, reuse colors. | ||
context.setFillColor(dataSet.color(atIndex: j).cgColor) | ||
for index in firstIndexInBar...lastIndexInBar { |
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 barRects = buffer.rects[firstIndexInBar...lastIndexInBar]
for (index, rect) in zip(barRects, barRects.indices)
where viewPortHandler.isInBoundsLeft(barRect.maxX)
{
...
}
} | ||
|
||
var height: CGFloat = 0 | ||
for index in firstIndexInBar...lastIndexInBar { |
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.
topRectInBar.size.height = barRects[firstIndexInBar...lastIndexInBar]
.reduce(0) { $0 + $1.height }
} | ||
|
||
/// Creates path for bar in rect with rounded corners | ||
internal func createBarPath(for rect: CGRect, roundedCorners: UIRectCorner) -> UIBezierPath { |
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.
internal
is default and is not needed.
@liuxuan30 I think we should start only targeting 4.0.0. Will encourage us to get it out faster and with more features in it, encourage people to update and help us keep it bug free. |
Any update on this @skarol? @liuxuan30? :) |
not really.. have to postpone, working on 3.3 release and PRs |
Sorry, have been busy lately :/ I'll try to address this soon |
One more question about this PR for @skarol and @liuxuan30 - the rounded corners seem to be perfectly semicircular - what about exposing the option to round corners with a given corner radius? This would be much more flexible and design agnostic. I'm guessing it is not really in the spirit of such a library to dictate design decisions like this? :) |
@samjarman I decided to not expose corner radius and calculate it as a semicircular on a purpose. When creating a chart you have no idea about bars width and height so it is hard to pass good looking corner radius and semicircular always looks good :) |
Hmm, I thought it'd be possible for a developer to calculate their own corner radius (such as the one on these input fields and comments on github) based on the width of the bar? If you can't get the width of the bar, maybe set a corner radius and then a minimum width for the corner radius to be used? |
I think "semicircular always looks good" is our designers decisions not really a framework's decision, y'know? :) |
All changes taken from: ChartsOrg#3754
Some news about this? |
Really hoping to see this feature implemented |
If the main problem is that it does not look "right" in some situations, why not add an additional parameter? Something like enum Radius {
case none
case widthPercentage(CGFLoat)
case absolute(CGFLoat)
} With |
Some news about this? |
Looking forward to use this feature, any news? Thanks for the great work on this lib :D |
Can someone help me? I got This one works: This one doesn't: Anybody faced with this problem? pod 'Charts', :git => 'https://github.com/danielgindi/Charts.git', :branch => 'master' |
Maybe it helps someone. To get this feature works, add these to your pod file: If you have the same crash as me, just reinstall Charts in pod file. |
|
||
let cornerRadius = rect.width / 2.0 | ||
|
||
let path = UIBezierPath(roundedRect: rect, |
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.
@skarol I see a problem here when the rect is smaller than the cornerRadius, in this case you'll have a smashed rounded rectangle that looks bad(I haven't tested this code, but I worked in this feature in my fork, and at the start I had used the UIBezierPath like you with the result that I have commented, some screenshots at the end, apologies for the quality).
My proposal to solve this is to split it into two cases(Take into consideration that I haven't used the open var roundedCorners: UIRectCorner = []
. I will always round all corners)
rect.height >= rect.width
in this case we can perform the UIBezierPath as you dorect.height < rect.width
in this case we can draw a portion of a circumference, I leave the algorithm
let height = rect.size.height
let hypotenuse = width / 2.0
let radius = hypotenuse
let startAngle: CGFloat
let endAngle: CGFloat
if height < radius {
let oLeg = radius - height
startAngle = asin(oLeg/hypotenuse)
endAngle = CGFloat(Double.pi) - startAngle
} else {
let oLeg = height - radius
startAngle = -asin(oLeg/hypotenuse)
endAngle = CGFloat(Double.pi) - startAngle
}
let y = rect.origin.y - (width - rect.size.height)
let center = CGPoint(x: rect.origin.x + radius, y: y + radius)
let bezierPath = UIBezierPath(arcCenter: center, radius: radius, startAngle: startAngle, endAngle: endAngle, clockwise: true)
why this was closed? @danielgindi |
Rounded Rect seems an important requirement @danielgindi . Please reopen it and merge changes. |
Friends I canβt remember every PR but please read the history here. There are issues that werenβt addressed and there is another branch that does this. |
@danielgindi it's weird our branch |
I will reopen this one as this seems the best rounded bar by far. The poblem is we need help from @skarol, or we take it from here. |
Hi! Could you be nice to process this pull request? Cheers |
Hi everyone! There is something I could do to add the feature ASAP? Thanks, |
I put up a PR that adds this functionality as well: #4375 No clue if it will get in (likely not, for similar reasons as this one) - but its a more up to date approach you can probably pull in / play with. |
Hello.
Edge cases:
Corners |
just FYI that we are actively working on the long waited 4.0 merge right now, so if anyone want to contribute on this one, wait until we merge 4.0. |
Can I use this function for rounded corner? |
@liuxuan30 Could you say when this feature will be in the master branch? |
nope, not any estimatable time. I mean it's a big change and the author seems not responding. Besides, we are having 4.0 branch merging ahead, and 4.0 branch is already big enough and will cause more code break for this PR. Without the author's help, I don't think we can merge this fairly. |
Hello @liuxuan30 |
I want to give a corner radius to shadow in a bar chart view graph. How can I do this? @liuxuan30 |
why this was closed? @jjatie |
Issue Link π
Rounding the corners of bars #1066
Goals β½
BarChartView
andHorizontalBarChartView
.dataSet.roundedCorners = [.allCorners]
.Implementation Details π§
roundedCorners
property forBarChartDataSet
, where you can specify which corners should be rounded.drawDataSet
function inBarChartRenderer
andHorizontalBarChartRenderer
, whereUIBezierPath
is created to clip bar filling.drawHighlighted
function inBarChartRenderer
.Testing Details π
Add
testRoundedCorners
test toBarChartTests
.