Hi, I would like to post modifications to your code concerning DateAxis and NumberAxis classes. Sorry I do not have time to do more than posting it here.
The problem: when you set a custom formatter for a date or a number axis you could end up with several ticks that have the same label (e.g. a "### ##0" format would produce "100" label for all the numbers between 99.5XXX and 100.4XXX). Which is ugly.
I propose to replace the following methods in both classes (unless you tell me you have another solution):
Code: Select all
protected List refreshTicksHorizontal(Graphics2D g2, Rectangle2D dataArea, RectangleEdge edge)
protected List refreshTicksVertical(Graphics2D g2, Rectangle2D dataArea, RectangleEdge edge)
With the following codes:
For NumberAxis.java:
Code: Select all
protected List refreshTicksHorizontal(Graphics2D g2, Rectangle2D dataArea, RectangleEdge edge)
{
try { return this.refreshTheTicks(g2, dataArea, edge, false); }
catch (Throwable ex) { ex.printStackTrace(); }
return null;
}
protected List refreshTicksVertical(Graphics2D g2, Rectangle2D dataArea, RectangleEdge edge)
{
try { return this.refreshTheTicks(g2, dataArea, edge, true); }
catch (Throwable ex) { ex.printStackTrace(); }
return null;
}
protected List refreshTheTicks(Graphics2D g2, Rectangle2D dataArea, RectangleEdge edge, boolean vertical) throws Throwable
{
List result = new java.util.ArrayList();
Font tickLabelFont = getTickLabelFont();
g2.setFont(tickLabelFont);
if (isAutoTickUnitSelection())
{
selectAutoTickUnit(g2, dataArea, edge);
}
TickUnit tu = getTickUnit();
double size = tu.getSize();
int count = calculateVisibleTickCount();
double lowestTickValue = calculateLowestVisibleTickValue();
if (count <= ValueAxis.MAXIMUM_TICK_COUNT)
{
int minorTickSpaces = getMinorTickCount();
if (minorTickSpaces <= 0)
{
minorTickSpaces = tu.getMinorTickCount();
}
for (int minorTick = 1; minorTick < minorTickSpaces; minorTick++)
{
double minorTickValue = lowestTickValue - size * minorTick / minorTickSpaces;
if (getRange().contains(minorTickValue)) result.add(new NumberTick(TickType.MINOR, minorTickValue, "", TextAnchor.TOP_CENTER, TextAnchor.CENTER, 0.0));
}
TextAnchor anchor;
TextAnchor rotationAnchor;
double angle = 0.0;
if (vertical)
{
if (isVerticalTickLabels())
{
if (edge == RectangleEdge.LEFT)
{
anchor = TextAnchor.BOTTOM_CENTER;
rotationAnchor = TextAnchor.BOTTOM_CENTER;
angle = -Math.PI / 2.0;
}
else
{
anchor = TextAnchor.BOTTOM_CENTER;
rotationAnchor = TextAnchor.BOTTOM_CENTER;
angle = Math.PI / 2.0;
}
}
else
{
if (edge == RectangleEdge.LEFT)
{
anchor = TextAnchor.CENTER_RIGHT;
rotationAnchor = TextAnchor.CENTER_RIGHT;
}
else
{
anchor = TextAnchor.CENTER_LEFT;
rotationAnchor = TextAnchor.CENTER_LEFT;
}
}
}
else
{
if (isVerticalTickLabels())
{
anchor = TextAnchor.CENTER_RIGHT;
rotationAnchor = TextAnchor.CENTER_RIGHT;
angle = edge == RectangleEdge.TOP ? angle = Math.PI / 2.0 : -Math.PI / 2.0;
}
else
{
if (edge == RectangleEdge.TOP)
{
anchor = TextAnchor.BOTTOM_CENTER;
rotationAnchor = TextAnchor.BOTTOM_CENTER;
}
else
{
anchor = TextAnchor.TOP_CENTER;
rotationAnchor = TextAnchor.TOP_CENTER;
}
}
}
NumberFormat formatter = getNumberFormatOverride();
java.util.Map<String, Object> map = new java.util.LinkedHashMap(count);
double tickValue = lowestTickValue;
for (int i = 0; i < count; i++, tickValue+= size)
{
String tickLabel = formatter != null ? formatter.format(tickValue) : getTickUnit().valueToString(tickValue);
Object obj = map.get(tickLabel);
if (obj == null) map.put(tickLabel, tickValue);
else if (obj instanceof Double)
{
List list = new java.util.ArrayList(2);
list.add(obj);
list.add(tickValue);
map.put(tickLabel, list);
}
else if (obj instanceof List) ((List) obj).add(tickValue);
}
String[] labels = new String[map.size()];
double[] values = new double[labels.length];
int counter = 0;
for (String tickLabel : map.keySet())
{
labels[counter] = tickLabel;
Object obj = map.get(tickLabel);
if (obj instanceof Double) values[counter] = (Double) obj;
else
{
List<Double> list = (List) obj;
double val = formatter != null ? formatter.parse(tickLabel).doubleValue() : new Double(tickLabel);
double foundVal = list.get(list.size() - 1);
for (double value : list)
{
if (val - value < 0)
{
foundVal = value;
break;
}
}
values[counter] = foundVal;
}
counter++;
}
for (int i=0, maxI=labels.length-1; i<labels.length; i++)
{
double currentTickValue = values[i];
result.add(new NumberTick(currentTickValue, labels[i], anchor, rotationAnchor, angle));
double nextTickValue = i < maxI ? values[i + 1] : calculateHighestVisibleTickValue();
for (int minorTick = 1; minorTick < minorTickSpaces; minorTick++)
{
double minorTickValue = currentTickValue + (nextTickValue - currentTickValue) * minorTick / minorTickSpaces;
if (getRange().contains(minorTickValue))
{
result.add(new NumberTick(TickType.MINOR, minorTickValue, "", TextAnchor.TOP_CENTER, TextAnchor.CENTER, 0.0));
}
}
}
}
return result;
}
For DateAxis.java:
Code: Select all
protected List refreshTicksHorizontal(Graphics2D g2, Rectangle2D dataArea, RectangleEdge edge)
{
try { return this.refreshTheTicks(g2, dataArea, edge, false); }
catch (Throwable ex) { ex.printStackTrace(); }
return null;
}
protected List refreshTicksVertical(Graphics2D g2, Rectangle2D dataArea, RectangleEdge edge)
{
try { return this.refreshTheTicks(g2, dataArea, edge, true); }
catch (Throwable ex) { ex.printStackTrace(); }
return null;
}
protected List refreshTheTicks(Graphics2D g2, Rectangle2D dataArea, RectangleEdge edge, boolean vertical) throws Throwable
{
List result = new java.util.ArrayList();
Font tickLabelFont = getTickLabelFont();
g2.setFont(tickLabelFont);
if (isAutoTickUnitSelection())
{
selectAutoTickUnit(g2, dataArea, edge);
}
DateTickUnit unit = getTickUnit();
Date tickDate = calculateLowestVisibleTickValue(unit);
Date upperDate = getMaximumDate();
TextAnchor anchor, rotationAnchor;
double angle = 0.0;
if (vertical)
{
if (isVerticalTickLabels())
{
anchor = TextAnchor.BOTTOM_CENTER;
rotationAnchor = TextAnchor.BOTTOM_CENTER;
if (edge == RectangleEdge.LEFT)
{
angle = -Math.PI / 2.0;
}
else
{
angle = Math.PI / 2.0;
}
}
else
{
if (edge == RectangleEdge.LEFT)
{
anchor = TextAnchor.CENTER_RIGHT;
rotationAnchor = TextAnchor.CENTER_RIGHT;
}
else
{
anchor = TextAnchor.CENTER_LEFT;
rotationAnchor = TextAnchor.CENTER_LEFT;
}
}
}
else
{
if (isVerticalTickLabels())
{
anchor = TextAnchor.CENTER_RIGHT;
rotationAnchor = TextAnchor.CENTER_RIGHT;
if (edge == RectangleEdge.TOP)
{
angle = Math.PI / 2.0;
}
else
{
angle = -Math.PI / 2.0;
}
}
else
{
if (edge == RectangleEdge.TOP)
{
anchor = TextAnchor.BOTTOM_CENTER;
rotationAnchor = TextAnchor.BOTTOM_CENTER;
}
else
{
anchor = TextAnchor.TOP_CENTER;
rotationAnchor = TextAnchor.TOP_CENTER;
}
}
}
String prevTickLabel = null;
DateFormat formatter = getDateFormatOverride();
boolean hasRolled = false;
long currentTickTime = tickDate.getTime();
while (tickDate.before(upperDate))
{
// could add a flag to make the following correction optional...
if (!hasRolled)
{
tickDate = correctTickDateForPosition(tickDate, unit, this.tickMarkPosition);
}
long lowestTickTime = tickDate.getTime();
long distance = unit.addToDate(tickDate, this.timeZone).getTime() - lowestTickTime;
int minorTickSpaces = getMinorTickCount();
if (minorTickSpaces <= 0)
{
minorTickSpaces = unit.getMinorTickCount();
}
for (int minorTick = 1; minorTick < minorTickSpaces; minorTick++)
{
long minorTickTime = lowestTickTime - distance * minorTick / minorTickSpaces;
if (minorTickTime > 0 && getRange().contains(minorTickTime) && (!isHiddenValue(minorTickTime)))
{
result.add(new DateTick(TickType.MINOR, new Date(minorTickTime), "", TextAnchor.TOP_CENTER, TextAnchor.CENTER, 0.0));
}
}
if (!isHiddenValue(tickDate.getTime()))
{
// work out the value, label and position
String tickLabel = formatter != null ? formatter.format(tickDate) : this.tickUnit.dateToString(tickDate);
if (tickLabel.equals(prevTickLabel))
{
tickDate = unit.addToDate(tickDate, this.timeZone);
continue;
}
prevTickLabel = tickLabel;
Tick tick = new DateTick(tickDate, tickLabel, anchor, rotationAnchor, angle);
result.add(tick);
hasRolled = false;
tickDate = unit.addToDate(tickDate, this.timeZone);
long nextTickTime = tickDate.getTime();
for (int minorTick = 1; minorTick < minorTickSpaces; minorTick++)
{
long minorTickTime = currentTickTime + (nextTickTime - currentTickTime) * minorTick / minorTickSpaces;
if (getRange().contains(minorTickTime) && (!isHiddenValue(minorTickTime)))
{
result.add(new DateTick(TickType.MINOR, new Date(minorTickTime), "", TextAnchor.TOP_CENTER, TextAnchor.CENTER, 0.0));
}
}
currentTickTime = tickDate.getTime();
}
else
{
tickDate = unit.rollDate(tickDate, this.timeZone);
hasRolled = true;
}
}
return result;
}