As you can see, when the range axis is spanning over a large area, and the ticklabels are too close together, they start overlapping. I would like to implement some kind of logic to detect if they are overlapping, and if so, just show a preferred one (or as many as will fit). I am a bit unsure of how to accomplish this, however.
The logic would be something like this:
But which methods are available to do this? From the API docs I bought I found this method
public double valueToJava2D(double value, Rectangle2D area, RectangleEdge edge);
But what is this area and edge I need to supply the function with? And how would I get a hold of the width and height if a ticklabel? And is this the right way to go about it, or is there a better way that will lead to success?
I posted the question on the JFree forums (as trashgod found) and got a few nice hints there. The final code I posted there that solved my problem was as follows:
@SuppressWarnings({"RawUseOfParameterizedType", "serial"})
private static class CustomTickMarkNumberAxis extends NumberAxis {
private double[] customTicksSortedOnImportance;
/**
* A list ticks sorted after importance. In case of overlapping,
* a higher ranked tick will trump a lower ranked tick, thus <i>not showing</i>
* the lower ranked (overlapping) tick.
* Other lower ranked ticks might still be shown, if they are not overlapping
*/
public CustomTickMarkNumberAxis(double[] customTicksSortedOnImportance) {
this.customTicksSortedOnImportance = customTicksSortedOnImportance;
}
protected List<NumberTick> refreshTicksVertical(Graphics2D g2, Rectangle2D dataArea, RectangleEdge edge) {
List<NumberTick> result = new java.util.ArrayList<NumberTick>();
//(... snip ...)
Area tickLabelArea = new Area(); /** Used for overlap detection */
for (int i = 0; i < customTicksSortedOnImportance.length; i++) {
// The next lines of code are different from NumberAxis
double currentTickValue = customTicksSortedOnImportance[i];
currentTickValue = NumberUtil.round(currentTickValue, precision);
//(... snip ...)
/* Overlapping logic here */
NumberTick numberTick = new NumberTick(currentTickValue, tickLabel, anchor, rotationAnchor, angle);
Rectangle2D labelBounds = getTickBounds(numberTick, g2);
double java2dValue = valueToJava2D(currentTickValue, g2.getClipBounds(), edge);
labelBounds.setRect(labelBounds.getX(), java2dValue, labelBounds.getWidth(), labelBounds.getHeight());
if (!tickLabelIsOverlapping(tickLabelArea, labelBounds)) {
result.add(numberTick);
tickLabelArea.add(new Area(labelBounds));
}
//(... snip ...)
}
return result;
}
private boolean tickLabelIsOverlapping(Area area, Rectangle2D rectangle) {
return area.intersects(rectangle);
}
private Rectangle2D getTickBounds(NumberTick numberTick, Graphics2D g2) {
FontMetrics fm = g2.getFontMetrics(getTickLabelFont());
return TextUtilities.getTextBounds(numberTick.getText(), g2, fm);
}
}