I am working with a LineChart
with a CategoryAxis
for the horizontal axis and I need each category to have a very custom formatted display. Using CategoryAxis.LabelFunction
is not powerful enough for my purposes, as it only allows custom formatting of the text field of a Label object. Specifically for this project I need each category to be a grid or HGroup of two different multi-line labels. The left label needs to be left aligned and the right to be right aligned.
I tried creating a custom class that extends Group
and implements IDataRenderer
. However, the public function set data(value:Object)
, defined in IDataRenderer
, always seems to be called with value as an AxisLabel
object, which does not pass an Object within it, just a string (AxisLabel.text
)
As a hack-ey alternative, I tried using the LabelFunction to pass an encoded string but even that causes problems. Somehow this code causes nothing to be displayed on the CategoryAxis:
public class HeatmapAxisLabelRenderer
extends HGroup
implements IDataRenderer
{
public function HeatmapAxisLabelRenderer()
{
super();
this.includeInLayout = true;
this.visible = true;
this.width = 100;
this.height = 40;
// this.percentWidth = 100;
// this.percentHeight = 100;
}
// Internal variable for the property value.
private var _data:Object;
// Make the data property bindable.
[Bindable("dataChange")]
// Define the getter method.
public function get data():Object {
return _data;
}
// Define the setter method, and dispatch an event when the property
// changes to support data binding.
public function set data(value:Object):void {
_data = value;
if (value is AxisLabel && AxisLabel(value).text!=null) {
var parts:Array = AxisLabel(value).text.split("|~|");
if (parts.length != 2) return;
var name:Label = new Label();
name.text = parts[0];
name.setStyle("textAlign","left");
name.width = 100;
var limit:Label = new Label();
limit.text = parts[1];
limit.setStyle("textAlign","right");
limit.width = 100;
this.addElement(name);
this.addElement(limit);
dispatchEvent(new FlexEvent(FlexEvent.DATA_CHANGE));
} else {
trace("renderer bad value");
}
}
The problem seems to be a weird interaction between Group
and AxisRenderer
, and the fact that your renderer (an HGroup
) has explicit width/height values (set in its constructor):
After setting the data
on your custom renderer, AxisRenderer` tells the custom renderer to invalidate it's size.
While doing so, the Group
correctly decides not to do anything because it has an explicit width/height.
I made some changes to get this to work:
Code:
package
{
import mx.charts.AxisLabel;
import mx.core.IDataRenderer;
import mx.events.FlexEvent;
import spark.components.HGroup;
import spark.components.Label;
public class HeatmapAxisLabelRenderer extends HGroup implements IDataRenderer
{
public function HeatmapAxisLabelRenderer()
{
super();
this.width=100;
}
private var _data:Object;
[Bindable("dataChange")]
public function get data():Object {
return _data;
}
private var nameLabel:Label;
private var limit:Label;
override protected function createChildren():void
{
super.createChildren();
if (!nameLabel)
{
nameLabel=new Label();
nameLabel.setStyle("textAlign","left");
limit = new Label();
limit.setStyle("textAlign", "right");
addElement(nameLabel);
addElement(limit);
}
}
public function set data(value:Object):void
{
if (_data === value)
return;
_data = value;
if (value is AxisLabel && AxisLabel(value).text!=null)
{
var parts:Array = AxisLabel(value).text.split("|~|");
if (parts.length == 2)
{
nameLabel.text = parts[0];
limit.text = parts[1];
}
}
else
{
trace("renderer bad value");
}
dispatchEvent(new FlexEvent(FlexEvent.DATA_CHANGE));
}
}
}