/*******************************************************************************
* Copyright (c) 2008-2011 SWTChart project. All rights reserved.
*
* This code is distributed under the terms of the Eclipse Public License v1.0
* which is available at http://www.eclipse.org/legal/epl-v10.html
*******************************************************************************/
package org.swtchart.internal.axis;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.text.Format;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.PaintEvent;
import org.eclipse.swt.events.PaintListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.graphics.Transform;
import org.eclipse.swt.widgets.Display;
import org.swtchart.Chart;
import org.swtchart.IAxis.Position;
import org.swtchart.internal.ChartLayoutData;
import org.swtchart.internal.Util;
/**
* Axis tick labels.
*/
public class AxisTickLabels implements PaintListener {
/** the chart */
private Chart chart;
/** the axis */
private Axis axis;
/** the foreground color */
private Color foreground;
/** the width hint of tick labels area */
private int widthHint;
/** the height hint of tick labels area */
private int heightHint;
/** the bounds of tick labels area */
private Rectangle bounds;
/** the array of tick label vales */
private ArrayList<Double> tickLabelValues;
/** the array of tick label */
private ArrayList<String> tickLabels;
/** the array of tick label position in pixels */
private ArrayList<Integer> tickLabelPositions;
/** the array of visibility state of tick label */
private ArrayList<Boolean> tickVisibilities;
/** the maximum length of tick labels */
private int tickLabelMaxLength;
/** the format for tick labels */
private Format format;
/** the default foreground */
private static final int DEFAULT_FOREGROUND = SWT.COLOR_BLUE;
/** the default font */
private static final Font DEFAULT_FONT = Display.getDefault()
.getSystemFont();
/** the default label format */
private static final String DEFAULT_DECIMAL_FORMAT = "#.###########";
/** the possible tick steps */
private Map<Integer, Integer[]> possibleTickSteps;
/** the time unit for tick step */
private int timeUnit;
/** the font */
private Font font;
/**
* Constructor.
*
* @param chart
* the chart
* @param axis
* the axis
*/
protected AxisTickLabels(Chart chart, Axis axis) {
this.chart = chart;
this.axis = axis;
tickLabelValues = new ArrayList<Double>();
tickLabels = new ArrayList<String>();
tickLabelPositions = new ArrayList<Integer>();
tickVisibilities = new ArrayList<Boolean>();
initializePossibleTickSteps();
font = DEFAULT_FONT;
foreground = Display.getDefault().getSystemColor(DEFAULT_FOREGROUND);
chart.addPaintListener(this);
}
/**
* Initialized the possible tick steps.
*/
private void initializePossibleTickSteps() {
final Integer[] milliseconds = { 1, 2, 5, 10, 20, 50, 100, 200, 500,
999 };
final Integer[] seconds = { 1, 2, 5, 10, 15, 20, 30, 59 };
final Integer[] minutes = { 1, 2, 3, 5, 10, 15, 20, 30, 59 };
final Integer[] hours = { 1, 2, 3, 4, 6, 12, 22 };
final Integer[] dates = { 1, 7, 14, 28 };
final Integer[] months = { 1, 2, 3, 4, 6, 11 };
final Integer[] years = { 1, 2, 5, 10, 20, 50, 100, 200, 500, 1000 };
possibleTickSteps = new HashMap<Integer, Integer[]>();
possibleTickSteps.put(Calendar.MILLISECOND, milliseconds);
possibleTickSteps.put(Calendar.SECOND, seconds);
possibleTickSteps.put(Calendar.MINUTE, minutes);
possibleTickSteps.put(Calendar.HOUR_OF_DAY, hours);
possibleTickSteps.put(Calendar.DATE, dates);
possibleTickSteps.put(Calendar.MONTH, months);
possibleTickSteps.put(Calendar.YEAR, years);
}
/**
* Sets the foreground color.
*
* @param color
* the foreground color
*/
public void setForeground(Color color) {
if (color == null) {
foreground = Display.getDefault()
.getSystemColor(DEFAULT_FOREGROUND);
} else {
foreground = color;
}
}
/**
* Gets the foreground color.
*
* @return the foreground color
*/
protected Color getForeground() {
if (foreground.isDisposed()) {
foreground = Display.getDefault()
.getSystemColor(DEFAULT_FOREGROUND);
}
return foreground;
}
/**
* Updates the tick labels.
*
* @param length
* the axis length
*/
protected void update(int length) {
tickLabelValues.clear();
tickLabels.clear();
tickLabelPositions.clear();
if (axis.isValidCategoryAxis()) {
updateTickLabelForCategoryAxis(length);
} else if (axis.isLogScaleEnabled()) {
updateTickLabelForLogScale(length);
} else if (axis.isDateEnabled()) {
updateTickLabelForDateAxis(length);
} else {
updateTickLabelForLinearScale(length);
}
updateTickVisibility();
updateTickLabelMaxLength();
}
/**
* Updates tick label for date axis.
*
* @param length
* the length of axis
*/
private void updateTickLabelForDateAxis(int length) {
double min = axis.getRange().lower;
double max = axis.getRange().upper;
double gridStepHint = Math.abs(max - min) / length
* axis.getTick().getTickMarkStepHint();
timeUnit = getTimeUnit(gridStepHint);
if (timeUnit == Calendar.MILLISECOND || timeUnit == Calendar.SECOND
|| timeUnit == Calendar.MINUTE
|| timeUnit == Calendar.HOUR_OF_DAY
|| timeUnit == Calendar.DATE) {
Integer[] steps = possibleTickSteps.get(timeUnit);
for (int i = 0; i < steps.length - 1; i++) {
if (gridStepHint < (getPeriodInMillis(timeUnit, steps[i]) + getPeriodInMillis(
timeUnit, steps[i + 1])) / 2d) {
BigDecimal gridStep = new BigDecimal(Long.valueOf(
getPeriodInMillis(timeUnit, steps[i])).toString());
updateTickLabelForLinearScale(length, gridStep);
break;
}
}
} else if (timeUnit == Calendar.MONTH || timeUnit == Calendar.YEAR) {
updateTickLabelForMonthOrYear(length, gridStepHint, timeUnit);
}
}
/**
* Updates the tick label for month or year. The month and year are handled
* differently from other units of time, since 1 month and 1 year can be
* different depending on which time to start counting.
*
* @param length
* the length of axis
* @param gridStepHint
* the grid step hint
* @param tickStepUnit
* the tick step unit of time
*/
private void updateTickLabelForMonthOrYear(int length, double gridStepHint,
int tickStepUnit) {
double min = axis.getRange().lower;
double max = axis.getRange().upper;
// get initial position
Calendar cal = Calendar.getInstance();
cal.setTime(new Date((long) min));
int month = cal.get(Calendar.MONTH);
int year = cal.get(Calendar.YEAR);
if (tickStepUnit == Calendar.MONTH) {
if (month == Calendar.DECEMBER) {
year++;
month = Calendar.JANUARY;
} else {
month++;
}
} else if (tickStepUnit == Calendar.YEAR) {
month = Calendar.JANUARY;
year++;
}
// get tick step
Integer[] steps = possibleTickSteps.get(tickStepUnit);
int step = steps[steps.length - 1];
for (int i = 0; i < steps.length - 1; i++) {
if (gridStepHint < (getPeriodInMillis(tickStepUnit, steps[i]) + getPeriodInMillis(
tickStepUnit, steps[i + 1])) / 2d) {
step = steps[i];
break;
}
}
// set tick labels
cal.clear();
cal.set(year, month, 1);
while (cal.getTimeInMillis() < max) {
tickLabelValues.add(Double.valueOf(cal.getTimeInMillis()));
tickLabels.add(format(cal.getTimeInMillis()));
int tickLabelPosition = (int) ((cal.getTimeInMillis() - min)
/ (max - min) * length);
tickLabelPositions.add(tickLabelPosition);
if (tickStepUnit == Calendar.MONTH) {
month += step;
if (month + step > Calendar.DECEMBER) {
year++;
month -= Calendar.DECEMBER + 1;
}
} else if (tickStepUnit == Calendar.YEAR) {
year += step;
}
cal.clear();
cal.set(year, month, 1);
}
}
/**
* Updates tick label for category axis.
*
* @param length
* the length of axis
*/
private void updateTickLabelForCategoryAxis(int length) {
String[] series = axis.getCategorySeries();
if (series == null) {
return;
}
int min = (int) axis.getRange().lower;
int max = (int) axis.getRange().upper;
int sizeOfTickLabels = (series.length < max - min + 1) ? series.length
: max - min + 1;
int initialIndex = (min < 0) ? 0 : min;
for (int i = 0; i < sizeOfTickLabels; i++) {
tickLabels.add(series[i + initialIndex]);
int tickLabelPosition = (int) (length * (i + 0.5) / sizeOfTickLabels);
tickLabelPositions.add(tickLabelPosition);
}
}
/**
* Updates tick label for log scale.
*
* @param length
* the length of axis
*/
private void updateTickLabelForLogScale(int length) {
double min = axis.getRange().lower;
double max = axis.getRange().upper;
int digitMin = (int) Math.ceil(Math.log10(min));
int digitMax = (int) Math.ceil(Math.log10(max));
final BigDecimal MIN = new BigDecimal(new Double(min).toString());
BigDecimal tickStep = pow(10, digitMin - 1);
BigDecimal firstPosition;
if (MIN.remainder(tickStep).doubleValue() <= 0) {
firstPosition = MIN.subtract(MIN.remainder(tickStep));
} else {
firstPosition = MIN.subtract(MIN.remainder(tickStep)).add(tickStep);
}
for (int i = digitMin; i <= digitMax; i++) {
for (BigDecimal j = firstPosition; j.doubleValue() <= pow(10, i)
.doubleValue(); j = j.add(tickStep)) {
if (j.doubleValue() > max) {
break;
}
if (axis.isDateEnabled()) {
Date date = new Date((long) j.doubleValue());
tickLabels.add(format(date));
} else {
tickLabels.add(format(j.doubleValue()));
}
tickLabelValues.add(j.doubleValue());
int tickLabelPosition = (int) ((Math.log10(j.doubleValue()) - Math
.log10(min)) / (Math.log10(max) - Math.log10(min)) * length);
tickLabelPositions.add(tickLabelPosition);
}
tickStep = tickStep.multiply(pow(10, 1));
firstPosition = tickStep.add(pow(10, i));
}
}
/**
* Updates tick label for normal scale.
*
* @param length
* axis length (>0)
*/
private void updateTickLabelForLinearScale(int length) {
double min = axis.getRange().lower;
double max = axis.getRange().upper;
updateTickLabelForLinearScale(length, getGridStep(length, min, max));
}
/**
* Updates tick label for normal scale.
*
* @param length
* axis length (>0)
* @param tickStep
* the tick step
*/
private void updateTickLabelForLinearScale(int length, BigDecimal tickStep) {
double min = axis.getRange().lower;
double max = axis.getRange().upper;
final BigDecimal MIN = new BigDecimal(new Double(min).toString());
BigDecimal firstPosition;
/* if (min % tickStep <= 0) */
if (MIN.remainder(tickStep).doubleValue() <= 0) {
/* firstPosition = min - min % tickStep */
firstPosition = MIN.subtract(MIN.remainder(tickStep));
} else {
/* firstPosition = min - min % tickStep + tickStep */
firstPosition = MIN.subtract(MIN.remainder(tickStep)).add(tickStep);
}
// the unit time starts from 1:00
if (axis.isDateEnabled()) {
BigDecimal zeroOclock = firstPosition.subtract(new BigDecimal(
new Double(3600000).toString()));
if (MIN.compareTo(zeroOclock) == -1) {
firstPosition = zeroOclock;
}
}
for (BigDecimal b = firstPosition; b.doubleValue() <= max; b = b
.add(tickStep)) {
if (axis.isDateEnabled()) {
Date date = new Date((long) b.doubleValue());
tickLabels.add(format(date));
} else {
tickLabels.add(format(b.doubleValue()));
}
tickLabelValues.add(b.doubleValue());
int tickLabelPosition = (int) ((b.doubleValue() - min)
/ (max - min) * length);
tickLabelPositions.add(tickLabelPosition);
}
}
/**
* Updates the visibility of tick labels.
*/
private void updateTickVisibility() {
// initialize the array of tick label visibility state
tickVisibilities.clear();
for (int i = 0; i < tickLabelPositions.size(); i++) {
tickVisibilities.add(Boolean.TRUE);
}
if (tickLabelPositions.size() == 0
|| axis.getTick().getTickLabelAngle() != 0) {
return;
}
// set the tick label visibility
int previousPosition = 0;
for (int i = 0; i < tickLabelPositions.size(); i++) {
// check if there is enough space to draw tick label
boolean hasSpaceToDraw = true;
if (i != 0) {
hasSpaceToDraw = hasSpaceToDraw(previousPosition,
tickLabelPositions.get(i), tickLabels.get(i));
}
// check if the tick label value is major
boolean isMajorTick = true;
if (!axis.isValidCategoryAxis()) {
if (axis.isLogScaleEnabled()) {
isMajorTick = isMajorTick(tickLabelValues.get(i));
}
// check if the same tick label is repeated
String currentLabel = tickLabels.get(i);
try {
double value = Double.parseDouble(currentLabel);
if (value != tickLabelValues.get(i)) {
isMajorTick = false;
}
} catch (NumberFormatException e) {
// label is not decimal value but string
}
}
if (hasSpaceToDraw && isMajorTick) {
previousPosition = tickLabelPositions.get(i);
} else {
tickVisibilities.set(i, Boolean.FALSE);
}
}
}
/**
* Gets the tick step unit.
*
* @param gridStepHint
* the grid step hint
* @return the tick step unit.
*/
private int getTimeUnit(double gridStepHint) {
final Integer[] units = { Calendar.MILLISECOND, Calendar.SECOND,
Calendar.MINUTE, Calendar.HOUR_OF_DAY, Calendar.DATE,
Calendar.MONTH, Calendar.YEAR };
for (Integer unit : units) {
Integer[] steps = possibleTickSteps.get(unit);
if (gridStepHint < (getPeriodInMillis(unit, steps[steps.length - 2]) + getPeriodInMillis(
unit, steps[steps.length - 1])) / 2d) {
return unit;
}
}
return Calendar.YEAR;
}
/**
* Gets the period in milliseconds of given unit of date and amount. The
* period is calculated based on UTC of January 1, 1970.
*
* @param unit
* the unit of time like <tt>Calendar.YEAR<tt>.
* @param amount
* the amount of period.
* @return the period in milliseconds
*/
private long getPeriodInMillis(int unit, int amount) {
Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(0);
cal.roll(unit, amount);
return cal.getTimeInMillis();
}
/**
* Formats the given object.
*
* @param obj
* the object
* @return the formatted string
*/
private String format(Object obj) {
if (format == null) {
if (axis.isDateEnabled()) {
String dateFormat = "yyyyy.MMMMM.dd";
if (timeUnit == Calendar.MILLISECOND) {
dateFormat = "HH:mm:ss.SSS";
} else if (timeUnit == Calendar.SECOND) {
dateFormat = "HH:mm:ss";
} else if (timeUnit == Calendar.MINUTE) {
dateFormat = "HH:mm";
} else if (timeUnit == Calendar.HOUR_OF_DAY) {
dateFormat = "dd HH:mm";
} else if (timeUnit == Calendar.DATE) {
dateFormat = "MMMMM d";
} else if (timeUnit == Calendar.MONTH) {
dateFormat = "yyyy MMMMM";
} else if (timeUnit == Calendar.YEAR) {
dateFormat = "yyyy";
}
return new SimpleDateFormat(dateFormat).format(obj);
}
return new DecimalFormat(DEFAULT_DECIMAL_FORMAT).format(obj);
}
return format.format(obj);
}
/**
* Checks if the tick label is major (...,0.01,0.1,1,10,100,...).
*
* @param tickValue
* the tick label value
* @return true if the tick label is major
*/
private boolean isMajorTick(double tickValue) {
if (!axis.isLogScaleEnabled()) {
return true;
}
if (Math.log10(tickValue) % 1 == 0) {
return true;
}
return false;
}
/**
* Returns the state indicating if there is a space to draw tick label.
*
* @param previousPosition
* the previously drawn tick label position.
* @param tickLabelPosition
* the tick label position.
* @param tickLabel
* the tick label text
* @return true if there is a space to draw tick label
*/
private boolean hasSpaceToDraw(int previousPosition, int tickLabelPosition,
String tickLabel) {
Point p = Util.getExtentInGC(axis.getTick().getFont(), tickLabel);
int interval = tickLabelPosition - previousPosition;
int textLength = axis.isHorizontalAxis() ? p.x : p.y;
return interval > textLength;
}
/**
* Gets max length of tick label.
*/
private void updateTickLabelMaxLength() {
int maxLength = 0;
for (int i = 0; i < tickLabels.size(); i++) {
if (tickVisibilities.size() > i && tickVisibilities.get(i) == true) {
Point p = Util.getExtentInGC(axis.getTick().getFont(),
tickLabels.get(i));
if (p.x > maxLength) {
maxLength = p.x;
}
}
}
if (tickLabelMaxLength != maxLength) {
tickLabelMaxLength = maxLength;
if (axis.getTick().getTickLabelAngle() != 0) {
chart.updateLayout();
}
}
}
/**
* Calculates the value of the first argument raised to the power of the
* second argument.
*
* @param base
* the base
* @param expornent
* the exponent
* @return the value <tt>a<sup>b</sup></tt> in <tt>BigDecimal</tt>
*/
private BigDecimal pow(double base, int expornent) {
BigDecimal value;
if (expornent > 0) {
value = new BigDecimal(new Double(base).toString()).pow(expornent);
} else {
value = BigDecimal.ONE.divide(new BigDecimal(new Double(base)
.toString()).pow(-expornent));
}
return value;
}
/**
* Gets the grid step.
*
* @param lengthInPixels
* axis length in pixels
* @param min
* minimum value
* @param max
* maximum value
* @return rounded value.
*/
private BigDecimal getGridStep(int lengthInPixels, double min, double max) {
if (lengthInPixels <= 0) {
throw new IllegalArgumentException(
"lengthInPixels must be positive value.");
}
if (min >= max) {
throw new IllegalArgumentException("min must be less than max.");
}
double length = Math.abs(max - min);
double gridStepHint = length / lengthInPixels
* axis.getTick().getTickMarkStepHint();
// gridStepHint --> mantissa * 10 ** exponent
// e.g. 724.1 --> 7.241 * 10 ** 2
double mantissa = gridStepHint;
int exponent = 0;
if (mantissa < 1) {
while (mantissa < 1) {
mantissa *= 10.0;
exponent--;
}
} else {
while (mantissa >= 10) {
mantissa /= 10.0;
exponent++;
}
}
// calculate the grid step with hint.
BigDecimal gridStep;
if (mantissa > 7.5) {
// gridStep = 10.0 * 10 ** exponent
gridStep = BigDecimal.TEN.multiply(pow(10, exponent));
} else if (mantissa > 3.5) {
// gridStep = 5.0 * 10 ** exponent
gridStep = new BigDecimal(new Double(5).toString()).multiply(pow(
10, exponent));
} else if (mantissa > 1.5) {
// gridStep = 2.0 * 10 ** exponent
gridStep = new BigDecimal(new Double(2).toString()).multiply(pow(
10, exponent));
} else {
// gridStep = 1.0 * 10 ** exponent
gridStep = pow(10, exponent);
}
return gridStep;
}
/**
* Gets the tick label positions.
*
* @return the tick label positions
*/
public ArrayList<Integer> getTickLabelPositions() {
return tickLabelPositions;
}
/**
* Sets the font.
*
* @param font
* the font
*/
protected void setFont(Font font) {
if (font == null) {
this.font = DEFAULT_FONT;
} else {
this.font = font;
}
}
/**
* Gets the font.
*
* @return the font
*/
protected Font getFont() {
if (font.isDisposed()) {
font = DEFAULT_FONT;
}
return font;
}
/**
* Gets the layout data.
*
* @return the layout data
*/
public ChartLayoutData getLayoutData() {
return new ChartLayoutData(widthHint, heightHint);
}
/**
* Sets the bounds on chart panel.
*
* @param x
* the x coordinate
* @param y
* the y coordinate
* @param width
* the width
* @param height
* the height
*/
public void setBounds(int x, int y, int width, int height) {
bounds = new Rectangle(x, y, width, height);
}
/**
* Gets the bounds on chart panel.
*
* @return the bounds on chart panel
*/
protected Rectangle getBounds() {
return bounds;
}
/**
* Disposes the resources.
*/
protected void dispose() {
if (!chart.isDisposed()) {
chart.removePaintListener(this);
}
}
/**
* Updates the tick labels layout.
*/
protected void updateLayoutData() {
widthHint = SWT.DEFAULT;
heightHint = SWT.DEFAULT;
if (!axis.getTick().isVisible()) {
widthHint = 0;
heightHint = 0;
} else {
if (axis.isHorizontalAxis()) {
double angle = axis.getTick().getTickLabelAngle();
heightHint = Axis.MARGIN
+ (int) (tickLabelMaxLength
* Math.sin(Math.toRadians(angle)) + Util
.getExtentInGC(getFont(), "dummy").y
* Math.cos(Math.toRadians(angle)));
} else {
widthHint = tickLabelMaxLength + Axis.MARGIN;
}
}
}
/*
* @see PaintListener#paintControl(PaintEvent)
*/
public void paintControl(PaintEvent e) {
if (!axis.getTick().isVisible()) {
return;
}
e.gc.setBackground(chart.getBackground());
e.gc.setForeground(getForeground());
if (axis.isHorizontalAxis()) {
drawXTick(e.gc);
} else {
drawYTick(e.gc);
}
}
/**
* Draw the X tick.
*
* @param gc
* the graphics context
*/
private void drawXTick(GC gc) {
int offset = axis.getTick().getAxisTickMarks().getBounds().x;
// draw tick labels
gc.setFont(axis.getTick().getFont());
int angle = axis.getTick().getTickLabelAngle();
for (int i = 0; i < tickLabelPositions.size(); i++) {
if (axis.isValidCategoryAxis() || tickVisibilities.get(i) == true) {
String text = tickLabels.get(i);
int textWidth = gc.textExtent(text).x;
int textHeight = gc.textExtent(text).y;
if (angle == 0) {
int x = (int) (tickLabelPositions.get(i) - textWidth / 2d + offset);
gc.drawText(text, bounds.x + x, bounds.y);
continue;
}
float x, y;
if (axis.getPosition() == Position.Primary) {
x = (float) (offset + bounds.x + tickLabelPositions.get(i)
- textWidth * Math.cos(Math.toRadians(angle)) - textHeight
/ 2d * Math.sin(Math.toRadians(angle)));
y = (float) (bounds.y + textWidth
* Math.sin(Math.toRadians(angle)));
} else {
x = (float) (offset + bounds.x + tickLabelPositions.get(i) - textHeight
/ 2d * Math.sin(Math.toRadians(angle)));
y = (float) (bounds.y + tickLabelMaxLength
* Math.sin(Math.toRadians(angle)));
}
drawRotatedText(gc, text, x, y, angle);
}
}
}
/**
* Draws the rotated text.
*
* @param gc
* the graphics context
* @param text
* the text
* @param x
* the x coordinate
* @param y
* the y coordinate
* @param angle
* the angle
*/
private void drawRotatedText(GC gc, String text, float x, float y,
int angle) {
int textWidth = gc.textExtent(text).x;
int textHeight = gc.textExtent(text).y;
// create image to draw text
Image image = new Image(Display.getCurrent(), textWidth, textHeight);
GC tmpGc = new GC(image);
tmpGc.setForeground(getForeground());
tmpGc.setBackground(gc.getBackground());
tmpGc.setFont(getFont());
tmpGc.drawText(text, 0, 0);
// set transform to rotate
Transform transform = new Transform(gc.getDevice());
transform.translate(x, y);
transform.rotate(360 - angle);
gc.setTransform(transform);
// draw the image on the rotated graphics context
gc.drawImage(image, 0, 0);
// dispose resources
tmpGc.dispose();
transform.dispose();
image.dispose();
gc.setTransform(null);
}
/**
* Draw the Y tick.
*
* @param gc
* the graphics context
*/
private void drawYTick(GC gc) {
int margin = Axis.MARGIN + AxisTickMarks.TICK_LENGTH;
// draw tick labels
gc.setFont(axis.getTick().getFont());
int figureHeight = gc.textExtent("dummy").y;
for (int i = 0; i < tickLabelPositions.size(); i++) {
if (tickVisibilities.size() == 0 || tickLabels.size() == 0) {
break;
}
if (tickVisibilities.get(i) == true) {
String text = tickLabels.get(i);
int x = 0;
if (tickLabels.get(0).startsWith("-") && !text.startsWith("-")) {
x += gc.textExtent("-").x;
}
int y = (int) (bounds.height - 1 - tickLabelPositions.get(i)
- figureHeight / 2.0 - margin);
gc.drawText(text, bounds.x + x, bounds.y + y);
}
}
}
/**
* Sets the format for axis tick label. <tt>DecimalFormat</tt> and
* <tt>DateFormat</tt> should be used for <tt>double[]</tt> series and
* <tt>Data[]</tt> series respectively.
* <p>
* If <tt>null</tt> is set, default format will be used.
*
* @param format
* the format
*/
protected void setFormat(Format format) {
this.format = format;
}
/**
* Gets the format for axis tick label.
*
* @return the format
*/
protected Format getFormat() {
return format;
}
}