-
-
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
XAxis labels overlap in Charts 3.0 #1969
Comments
Another regression that is linked to this is that labelCount seems to be used, regardless of available space. On iPad, on Charts 2.x, the framework was showing as many xAxis labels as could possibly fit on screen. Now, with Charts 3.x, the framework will show 6 xAxis labels, always. I understand that I could calculate an optimal amount of xAxis labels and set the labelCount myself but Charts 2.x handled this for me automatically. It's also not that simple of a calculation. |
I had the exact same issue and it turns out that adding edit: Spoke to soon, this is still an issue for us too. I was able to alleviate the situation somewhat using |
Hello same issue :( |
hi! I have the same issue, is there any workaround? |
As mentioned before, the number of labels is fixed to six, which in itself is a bit odd. You would expect the library to dynamically determine how many labels could fit on the axis and make it fit. Perhaps having an optional configuration property to specify the maximum number of labels to render. Rendering the rects clearly shows the overlapping labels:
When changing the
UPDATE: I just noticed that you need to set the labelCount using One of the pieces of logic I found that is error prone is getLongestLabel that returns the String value of the axis label with the most characters. When using non-monospaced fonts this is actually a wrong assumption. A label with less characters might be rendered wider than the one that has the most characters and debugging the label widths actually shows that this is really happening: the label with the highest number of characters had a width that was 5 pixels less than a label that had less characters but renders wider. In all occurences where this code is being called it is only being used to afterwards determine the width of the string. Hence, a more accurate (although possibly more resource intensive) solution would be to replace that logic with something like this:
Or even more Swifty like this:
Unfortunately I have not yet found the root cause of the overlapping labels but it is clear the logic that renders the labels is faulty... |
Hi! |
I have a workaround for this issue. It basically skips rendering of overlapping labels but it could be improved as there is now more whitespace where labels could have been rendered. Still I think it is acceptable for now until this issue is solved... Create a new custom import Foundation
import Charts
#if !os(OSX)
import UIKit
#endif
// The original XAxisRender can result in overlapping labels on the
// x-axis (see https://github.com/danielgindi/Charts/issues/1969 ).
// This x-axis renderer will check if labels overlap and ignore drawing
// labels that overlap the previously drawn label.
class NoOverlappingLabelsXAxisRenderer: XAxisRenderer {
public var shouldDrawBoundingBoxes = false
public var labelSpacing = CGFloat(4.0)
// Keep track of the previous label's rect
private var previousLabelRect: CGRect?
override func renderAxisLabels(context: CGContext) {
previousLabelRect = nil
super.renderAxisLabels(context: context)
}
//swiftlint:disable function_parameter_count
override func drawLabel(context: CGContext, formattedLabel: String, x: CGFloat, y: CGFloat, attributes: [String : NSObject], constrainedToSize: CGSize, anchor: CGPoint, angleRadians: CGFloat) {
guard let axis = self.axis as? XAxis else { return }
// determine label rect
let labelRect = CGRect(x: x - (axis.labelWidth / 2), y: y, width: axis.labelWidth, height: axis.labelHeight)
// check if this label overlaps the previous label
if let previousLabelRect = previousLabelRect, labelRect.origin.x <= previousLabelRect.origin.x + previousLabelRect.size.width + labelSpacing {
// yes, skip drawing this label
self.previousLabelRect = nil
return
}
// remember this label's rect
self.previousLabelRect = labelRect
// draw label
super.drawLabel(context: context, formattedLabel: formattedLabel, x: x, y: y, attributes: attributes, constrainedToSize: constrainedToSize, anchor: anchor, angleRadians: angleRadians)
// draw label rect for debugging purposes
if shouldDrawBoundingBoxes {
#if !os(OSX)
// draw rect
UIGraphicsPushContext(context)
context.setStrokeColor(UIColor.red.cgColor)
context.setLineWidth(0.5)
context.addRect(labelRect)
context.drawPath(using: .stroke)
UIGraphicsPopContext()
// draw line
UIGraphicsPushContext(context)
context.move(to: CGPoint(x: x, y: y))
context.addLine(to: CGPoint(x: x, y: y - 4))
context.setLineWidth(0.5)
context.strokePath()
UIGraphicsPopContext()
#endif
}
}
//swiftlint:disable function_parameter_count
} And configure it when setting up your chart: // instantiate the chart
let lineChartView = PALineChartView(frame: ...)
...
// configure the x-axis
let xAxis = lineChartView.xAxis
...
// configure custom renderer
let xAxisRenderer = NoOverlappingLabelsXAxisRenderer(viewPortHandler: lineChartView.viewPortHandler, xAxis: lineChartView.xAxis, transformer: lineChartView.xAxisRenderer.transformer)
xAxisRenderer.shouldDrawBoundingBoxes = true // enable to debug label rects
lineChartView.xAxisRenderer = xAxisRenderer |
Dear 4np, It works fine for me. Thank you very much! I deleted this line, because the further neighbors were overlapped too in some cases: |
Unfortunately, this solution is not perfect because most of the times you want to always display the first and last items on the axis. One possible solution is to add labels from left and right (keeping two frames) alternately. |
How to make multiline label in Line chart using Chart lib. of x aixis label (objective c ) |
Is this issue fixed ? |
I want to scroll the chart on only x-axis without any zoom out or anything. Can you help me out from this? And can you advise me to how to leave some space between label on x-axis? |
In charts 2.x, the xAxis adjusted it's labelCount based on the width of the widest label. Here is an example from the 2.x demo:
However, in Charts 3, the labelWidth seems to be disregarded (computeAxis does not even consider it) when calculating the number of entries to show on the axis. Anything above 10 (about) characters has a chance to eventually get overlapped. Here's the same example, from Charts 3 demo:
This is a major regression for us from 2x. I've looked at the code and here is what I found:
XAxisRender.computeAxisValues calls super.computeAxisValues first, then calls computeSize. In my opinion, the result of computeSize should be an input to computeAxisValues and would need to be called first.
However modifying the AxisRendererBase.computeAxisValues to consider the labelWidth is beyond my comprehension level at this time.
The text was updated successfully, but these errors were encountered: