I have an issue with displaying axis labels for a bottom axis in TeeChart. Axis labels in my case are rather long and represent dates in format dd.MM.yyyy
In some cases when labels are placed close to each other they're shown one on top of each other (overlapping occurs). I add labels to the axis manually for every N values. What can I do to prevent overlapping?
The second issue is that the part of the first label sometimes is shown out of the left bound of the chart. So instead e.g. 11.02.2015 user can see only the part of the label e.g. 2.2015 etc. How can I detect such situations in my code?
I've tried to use AxisLabelResolver
in my chart but I've ran into issue that AxisLabelResolver
's methods are not called. What can be a reason?
Using Custom Labels you are who should control under what conditions a label should or shouldn't be drawn. Overlapping and labels drawn partially out of the chart rectangle are examples of common situations to control but we prefer to give this responsibilities to the developer in such custom tools.
You can use this to know the size of a string:
int tmpWidth = tChart1.getGraphics3D().textWidth(myLabel);
You can get the rectangle defined by the axes with this:
Rectangle tmpChartRect = tChart1.getChart().getChartRect();
You can calculate the position in pixels for an axis value with this:
int tmpX = tChart1.getAxes().getBottom().calcPosValue(myXValue);
So you can loop the list of CustomLabels before adding the next one. Ie:
private void addXCustomLabel(double myXValue, String myLabel) {
boolean overlaps = false;
tChart1.getGraphics3D().setFont(tChart1.getAxes().getBottom().getLabels().getFont());
int tmpWidth = tChart1.getGraphics3D().textWidth(myLabel);
int tmpX = tChart1.getAxes().getBottom().calcPosValue(myXValue) - tmpWidth / 2;
for (int i=0; i<tChart1.getAxes().getBottom().getCustomLabels().size(); i++) {
AxisLabelItem tmpI =tChart1.getAxes().getBottom().getCustomLabels().getItem(i);
int tmpWidth2 = tChart1.getGraphics3D().textWidth(tmpI.getText());
int tmpX2 = tChart1.getAxes().getBottom().calcPosValue(tmpI.getValue()) - tmpWidth2 / 2;
if (((tmpX>tmpX2) && (tmpX<tmpX2+tmpWidth2)) ||
((tmpX+tmpWidth>tmpX2) && (tmpX+tmpWidth<tmpX2+tmpWidth2)) ||
((tmpX<tmpX2) && (tmpX+tmpWidth>tmpX2+tmpWidth2))) {
overlaps = true;
}
}
Rectangle chartRect = tChart1.getChart().getChartRect();
if ((!overlaps) && (tmpX>chartRect.x) && (tmpX+tmpWidth<chartRect.x+chartRect.width)) {
tChart1.getAxes().getBottom().getCustomLabels().add(myXValue, myLabel);
}
}
The only problem here is that calcPosValue needs the chart to be drawn once to work properly. And, since Android controls the repaints, the trick is to do it at the chartPainted event, and remove the event doing it for not repeating the process. Ie:
private void createCustomLabels() {
tChart1.addChartPaintListener(new ChartPaintAdapter() {
@Override
public void chartPainted(ChartDrawEvent e) {
for (int i=0; i<tChart1.getAxes().getBottom().getMaximum(); i++) {
addXCustomLabel(i, "Value " + i + " here");
}
tChart1.removeChartPaintListener(this);
tChart1.refreshControl();
}
});
}
As you've observed, the AxisLabelResolver isn't called for the custom labels. This is per design.