-
-
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
Recalculate space on label formatting. #561
Comments
I think this is related to #513. This is the x axis label rotation PR. In the PR there is some explainations how it works. However, I don't see an obvious problem from your images, the first image has 7 chars and 3 ellipsis, seems totally fine with the length. What's the problem? alignment or something else? |
The alignment is ok, the problem is that i think that the chart needs to be bigger in the first image, this because the labels are smaller than in the second image just to take advantage of the extra space that we gain adding the ellipsis at the labels. In the following images i added an extra bottom offset just to fix and explain my point. It would be great if we can recalculate the space available after apply the format to the labels. Thanks in advance 🤓 |
I may understand your point, but still It's a little hard to see the difference of sizes. Are you talking about the height? Could you please check the chartView's frame size and the viewPortHandler.contentRect? There is some different size for the whole UIView and the area to draw the chart itself, excluding the axis and axis labels. I am guessing the chart view's contentRect is defined once the label size, offset is calculated. Then it won't re-calculate the contentRect based on the new label size after you applied the formatter? |
OK so I took a quick look about this, it seems that it does not take the formatter will change the size into account. We should apply the formater before we calculate label size, like we may add $ after the profit. or cut some chars. @danielgindi, what do you think? public func computeAxis(xValAverageLength xValAverageLength: Double, xValues: [String?])
{
var a = ""
let max = Int(round(xValAverageLength + Double(_xAxis.spaceBetweenLabels)))
for (var i = 0; i < max; i++)
{
a += "h"
}
let widthText = a as NSString
let labelSize = widthText.sizeWithAttributes([NSFontAttributeName: _xAxis.labelFont])
let labelWidth = labelSize.width
let labelHeight = labelSize.height
let labelRotatedSize = ChartUtils.sizeOfRotatedRectangle(labelSize, degrees: _xAxis.labelRotationAngle)
_xAxis.labelWidth = labelWidth
_xAxis.labelHeight = labelHeight
_xAxis.labelRotatedWidth = labelRotatedSize.width
_xAxis.labelRotatedHeight = labelRotatedSize.height
_xAxis.values = xValues
} public func requiredSize() -> CGSize
{
let label = getLongestLabel() as NSString
var size = label.sizeWithAttributes([NSFontAttributeName: labelFont])
size.width += xOffset * 2.0
size.height += yOffset * 2.0
size.width = max(minWidth, min(size.width, maxWidth > 0.0 ? maxWidth : size.width))
return size
} |
Exactly! Thats the problem, I fixed in a dirty way because i need to implement my custom formatter in the ChartData object and in the x-Axis, I implemented the same logic for the y-Axis too. let me explain. The functions which is in charge to calculate the space is the xValsAverageLength, this one needs to apply the format to the labels that why i added the format to the data object. // calculates the average length (in characters) across all x-value strings
internal func calcXValAverageLength()
{
if (_xVals.count == 0)
{
_xValAverageLength = 1
return
}
var sum = 1
for (var i = 0; i < _xVals.count; i++)
{
let label = _xVals[i]! as String
//Apply the format
let formattedLabel = _xValsValueFormatter.stringForXValue(i, original: label) ?? label
sum += _xVals[i] == nil ? 0 : (formattedLabel).characters.count
}
_xValAverageLength = Double(sum) / Double(_xVals.count)
} I'm using the same formatter that i pass to the x-Axis because this is the one which display the labels in the chart, If you have any idea or help how to implement this i'd love to contribute with you guys. Fort the y-Axis i did the same, i guess that this is a clean implementation. /// formatter for the x-Values
public var yValsValueFormatter: ChartXAxisValueFormatter?{
get{
return _yValsValueFormatter
}
set{
_yValsValueFormatter = newValue ?? ChartDefaultXAxisValueFormatter()
}
} /// - returns: the formatted y-label at the specified index. This will either use the auto-formatter or the custom formatter (if one is set).
public func getFormattedLabel(index: Int) -> String
{
if (index < 0 || index >= entries.count)
{
return ""
}
let formattedValue = _yValsValueFormatter.stringForXValue(index, original: (valueFormatter ?? _defaultValueFormatter).stringFromNumber(entries[index])!)
return formattedValue
} In this case i'm still using your number formatter the problem was that i needed a non standard format for the y-Axis ( 1000 = 1K, 1000000 = 1M ) that why i sued a custom formatter. I think that this feature also need to be in the iOS api not just un the Android one. Thanks in advance 🤓 UpdatedAlso i have to update the following methods to add the feature to the horizontal bar chart public override func computeAxis(xValAverageLength xValAverageLength: Double, xValues: [String?])
{
_xAxis.values = xValues
let longest = _xAxis.getLongestLabel() as NSString
let labelSize = longest.sizeWithAttributes([NSFontAttributeName: _xAxis.labelFont])
let labelWidth = floor(labelSize.width + _xAxis.xOffset * 3.5)
let labelHeight = labelSize.height
let labelRotatedSize = ChartUtils.sizeOfRotatedRectangle(rectangleWidth: labelSize.width, rectangleHeight: labelHeight, degrees: _xAxis.labelRotationAngle)
_xAxis.labelWidth = labelWidth
_xAxis.labelHeight = labelHeight
_xAxis.labelRotatedWidth = round(labelRotatedSize.width + _xAxis.xOffset * 3.5)
_xAxis.labelRotatedHeight = round(labelRotatedSize.height)
} public override func getLongestLabel() -> String
{
var longest = ""
for (var i = 0; i < values.count; i++)
{
var label = values[i]
//Apply the format
label = valueFormatter?.stringForXValue(i, original: label!) ?? label
if (label != nil && longest.characters.count < (label!).characters.count)
{
longest = label!
}
}
return longest
} |
if possible, follow the code style and not the 'dirty' way to create a PR :) |
@lidgardo Can you explain in details how to customize Y-axis. Honestly, I tried to read your comments above, but still can not implement. I worked with ChartYAxisValueFormatter Android version. I'm porting my App to IOS, but I can not find ChartYAxisValueFormatter IOS version. I'm not senior on ios dev, can you help. Pls. |
@hetpin if you are looking for y axis formater, it is here: /// the formatter used to customly format the y-labels
public var valueFormatter: NSNumberFormatter?
/// the formatter used to customly format the y-labels
internal var _defaultValueFormatter = NSNumberFormatter()` |
Hi @hetpin as @liuxuan30 said those are the properties to format the Y-Axis, you need to take in consideration that this are only functionals to standard number format, if this is your case that property will be useful. if not You i'll need to implement your formatter extends from the class ChartXAxisValueFormatter Now according my comments above all of them were to fix the process of calculate the space. I'm working on a pull request to add this enhancement. If you have doubts about the custom formatter I can explain you better, in other case you can use the valueFormatter property which is already there. Sorry for the late response. |
Thanks for help, I ended up with a simple customization of NSNumberFormatter. In short, I subclassed NSNumberFormatter and override two methods: - (id)init; and - (NSString *)stringForObjectValue:(id const)aObj; Simple and effective. |
reopen - oops. the original issue is not solved yet |
This is a problematic one, requiring some changes to the api. @PhilJay what do you think about passing the |
@PhilJay ? |
Sorry, didn't see this. |
I'm not sure, but I think that this one is also solved by Charts 3.0, am I right? |
Hey guys, I didn't get what the solution was! I'm still having the same spacing problem, any solution? |
I believe I'm having the same issue, but with some additional details: However, when I come back and it redraws, it does... Full video: Any idea what race case could be causing the initial draw to not have the correct height? Here's the chart code:
|
Hi. I found a little issue which i have been struggling a lot, it seems that if i apply a format on the x-labels the API doesn't recalculate the space in the wit the new format.
I'm adding a formatter to add an elipsis (...) when the label is more than 7 characters length just like you can see in the image.
All the gray area is the barChartView, If i don't use the formatter i got this
The code that i'm using to add the formatter is the following:
Container class:
ChartXAxis *xAxis = barView.xAxis; LargeValueFormatter *formatter = [LargeValueFormatter new]; xAxis.valueFormatter = formatter;
Formatter class:
As you can see, without the formatter the chart use in a better way the space, i guess that the problem is that API don't recalculate the bottomContent once that the labels are formatted. I'd like to help with this if you guys can give a little explanations if my diagnosis of the issue is ok and where i can find the code that i need to call to recalculate with the new labels. I guess this could be a great feature.
Thanks in advance. 🤓
The text was updated successfully, but these errors were encountered: