What's the plan to support radar/pie chart xAxis label wrapping?
Kind of important, because the radar chart radius is related to max xAxis label width.
Could you maybe add a screenshot for that feature? I don't quite get this requirement.
I can't since radar/pie chart does not support wrapping...
there are some properties in ChartXAxis:
/// if set to true, word wrapping the labels will be enabled.
/// word wrapping is done using (value width * labelWidth)
/// NOTE: currently supports all charts except pie/radar/horizontal-bar
public var wordWrapEnabled = false
/// :returns true if word wrapping the labels is enabled
public var isWordWrapEnabled: Bool { return wordWrapEnabled }
So I think the idea is the labels on xAxis can be wrapped. For example, the radar chart, the radius of the radar chart will rely on the label width. if the xAxis label width is too large, the chart will shrink. So I want the label to be multiple-lined.
Well it says in the docs that it doesn't currently support radar/pie/horizontal-bar charts, as it is takes some delicate work implementing this correctly and efficiently in every feature.
But the plan is that everything will support word-wrapping soon.
+1
I got horizontal bar label wrapped to two lines working with following implementation.
//use below functions for inserting "/n" at appropriate place in long text, to be assigned to xValues string
// it will insert line break character by calculating middle position in the given string and then finding nearest space to left or right of mid index, will break string based on nearest space found index
static func getWrapedText(str:String?) ->String {
if str == nil { return "" }
let lb = "\n"
let space = " "
let words = str!.componentsSeparatedByString(space)
let numberOfSpaces = words.count - 1
if numberOfSpaces == 0{
return str!
}
if numberOfSpaces == 1
{
return words.joinWithSeparator(lb)
}
else if numberOfSpaces == 2
{
return words[0] + space + words[1] + lb + words[2]
}
else
{
let parts = breakWordByNearestMidSpace(str!)
return parts.0 + lb + parts.1
}
}
static func breakWordByNearestMidSpace(txt:String) ->(String, String)
{
let count = txt.characters.count
let halfIndex = count/2
var firstPart = txt.substringToIndex(txt.startIndex.advancedBy(halfIndex))
var secondPart = txt.substringFromIndex(txt.startIndex.advancedBy(halfIndex))
let leftSpaceIndexFromMid = Int(firstPart.characters.reverse().indexOf(" ")!)
let rightSpaceIndexFromMid = (secondPart as NSString).rangeOfString(" ").location //int conversion wasn't working, hence nsstring used
// if left space is nearer than space on right from mid index
if leftSpaceIndexFromMid < rightSpaceIndexFromMid{
let breakIndex = halfIndex - leftSpaceIndexFromMid
firstPart = txt.substringToIndex(txt.startIndex.advancedBy(breakIndex-1)) //remove space by subtracting 1
secondPart = txt.substringFromIndex(txt.startIndex.advancedBy(breakIndex))
}
else
{
let breakIndex = halfIndex + rightSpaceIndexFromMid
firstPart = txt.substringToIndex(txt.startIndex.advancedBy(breakIndex)) //remove space by adding 1
secondPart = txt.substringFromIndex(txt.startIndex.advancedBy(breakIndex+1))
}
return (firstPart, secondPart)
}
//change in ChartXAxisRendererHorizontalBarChart
if (viewPortHandler.isInBoundsY(position.y))
{
var attributes = [NSFontAttributeName: labelFont, NSForegroundColorAttributeName: labelTextColor]
if align == .Right {
let style = NSMutableParagraphStyle()
style.alignment = NSTextAlignment.Right
attributes[NSParagraphStyleAttributeName] = style
}
drawLabel(context: context, label: label!, xIndex: i, x: pos, y: position.y - _xAxis.labelHeight / 2.0, align: align, attributes: attributes)
}
//change in ChartUtils.swift - drawAtPoint wasn't working with right alignment
internal class func drawText(context context: CGContext?, text: String, var point: CGPoint, align: NSTextAlignment, attributes: [String : AnyObject]?)
{
let width = text.sizeWithAttributes(attributes).width
let height = text.sizeWithAttributes(attributes).height
if (align == .Center)
{
point.x -= width / 2.0
}
else if (align == .Right)
{
point.x -= text.sizeWithAttributes(attributes).width
}
UIGraphicsPushContext(context)
// (text as NSString).drawAtPoint(point, withAttributes: attributes)
(text as NSString).drawInRect(CGRect(x: point.x, y: point.y, width: width, height: height), withAttributes: attributes)
UIGraphicsPopContext()
}
This should give:

Actually after the latest changes to support rotations, we simply need to remove the dtawLabel override from the horz renderer- and account for the multiline text in labelHeight calculation (currently reverting to lineHeight, ignoring the calculated height).
This is true, I think, to the other renderers as well. As they all call drawLabel, which now uses the utility drawing function from ChartUtils.
For the android counterpart it will be a little more complex because of the use of StaticLayout and so, but I think that we will take care of it soon. (Phil and I are currently working hard on dynamic data and stuff).
what is dynamic data?
I got horizontal bar label wrapped to two lines working with following implementation.
//use below functions for inserting "/n" at appropriate place in long text, to be assigned to xValues string
// it will insert line break character by calculating middle position in the given string and then finding nearest space to left or right of mid index, will break string based on nearest space found index
static func getWrapedText(str:String?) ->String {if str == nil { return "" } let lb = "\n" let space = " " let words = str!.componentsSeparatedByString(space) let numberOfSpaces = words.count - 1 if numberOfSpaces == 0{ return str! } if numberOfSpaces == 1 { return words.joinWithSeparator(lb) } else if numberOfSpaces == 2 { return words[0] + space + words[1] + lb + words[2] } else { let parts = breakWordByNearestMidSpace(str!) return parts.0 + lb + parts.1 } } static func breakWordByNearestMidSpace(txt:String) ->(String, String) { let count = txt.characters.count let halfIndex = count/2 var firstPart = txt.substringToIndex(txt.startIndex.advancedBy(halfIndex)) var secondPart = txt.substringFromIndex(txt.startIndex.advancedBy(halfIndex)) let leftSpaceIndexFromMid = Int(firstPart.characters.reverse().indexOf(" ")!) let rightSpaceIndexFromMid = (secondPart as NSString).rangeOfString(" ").location //int conversion wasn't working, hence nsstring used// if left space is nearer than space on right from mid index
if leftSpaceIndexFromMid < rightSpaceIndexFromMid{
let breakIndex = halfIndex - leftSpaceIndexFromMid
firstPart = txt.substringToIndex(txt.startIndex.advancedBy(breakIndex-1)) //remove space by subtracting 1
secondPart = txt.substringFromIndex(txt.startIndex.advancedBy(breakIndex))
}
else
{
let breakIndex = halfIndex + rightSpaceIndexFromMid
firstPart = txt.substringToIndex(txt.startIndex.advancedBy(breakIndex)) //remove space by adding 1
secondPart = txt.substringFromIndex(txt.startIndex.advancedBy(breakIndex+1))
}return (firstPart, secondPart) }//change in ChartXAxisRendererHorizontalBarChart
if (viewPortHandler.isInBoundsY(position.y))
{
var attributes = [NSFontAttributeName: labelFont, NSForegroundColorAttributeName: labelTextColor]if align == .Right { let style = NSMutableParagraphStyle() style.alignment = NSTextAlignment.Right attributes[NSParagraphStyleAttributeName] = style } drawLabel(context: context, label: label!, xIndex: i, x: pos, y: position.y - _xAxis.labelHeight / 2.0, align: align, attributes: attributes) }//change in ChartUtils.swift - drawAtPoint wasn't working with right alignment
internal class func drawText(context context: CGContext?, text: String, var point: CGPoint, align: NSTextAlignment, attributes: [String : AnyObject]?)
{
let width = text.sizeWithAttributes(attributes).width
let height = text.sizeWithAttributes(attributes).heightif (align == .Center) { point.x -= width / 2.0 } else if (align == .Right) { point.x -= text.sizeWithAttributes(attributes).width } UIGraphicsPushContext(context)// (text as NSString).drawAtPoint(point, withAttributes: attributes)
(text as NSString).drawInRect(CGRect(x: point.x, y: point.y, width: width, height: height), withAttributes: attributes)
UIGraphicsPopContext()
}This should give:
Please convert to swift5
Hello! I'm wondering if there has been any update to this open issue, or if we should implement workarounds for horizontal bar charts like the one listed above =]
Most helpful comment
I got horizontal bar label wrapped to two lines working with following implementation.
//use below functions for inserting "/n" at appropriate place in long text, to be assigned to xValues string
// it will insert line break character by calculating middle position in the given string and then finding nearest space to left or right of mid index, will break string based on nearest space found index
static func getWrapedText(str:String?) ->String {
// if left space is nearer than space on right from mid index
if leftSpaceIndexFromMid < rightSpaceIndexFromMid{
let breakIndex = halfIndex - leftSpaceIndexFromMid
firstPart = txt.substringToIndex(txt.startIndex.advancedBy(breakIndex-1)) //remove space by subtracting 1
secondPart = txt.substringFromIndex(txt.startIndex.advancedBy(breakIndex))
}
else
{
let breakIndex = halfIndex + rightSpaceIndexFromMid
firstPart = txt.substringToIndex(txt.startIndex.advancedBy(breakIndex)) //remove space by adding 1
secondPart = txt.substringFromIndex(txt.startIndex.advancedBy(breakIndex+1))
}
//change in ChartXAxisRendererHorizontalBarChart
if (viewPortHandler.isInBoundsY(position.y))
{
var attributes = [NSFontAttributeName: labelFont, NSForegroundColorAttributeName: labelTextColor]
//change in ChartUtils.swift - drawAtPoint wasn't working with right alignment
internal class func drawText(context context: CGContext?, text: String, var point: CGPoint, align: NSTextAlignment, attributes: [String : AnyObject]?)
{
let width = text.sizeWithAttributes(attributes).width
let height = text.sizeWithAttributes(attributes).height
// (text as NSString).drawAtPoint(point, withAttributes: attributes)
(text as NSString).drawInRect(CGRect(x: point.x, y: point.y, width: width, height: height), withAttributes: attributes)
UIGraphicsPopContext()
}
This should give: