package jas.plot; import java.awt.Color; import java.awt.Font; import java.awt.FontMetrics; import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectOutput; /** * An axis type for representing times. *
Note that this is not the same as dates. A date represents a particular
* point in time (e.g., when an event took place). This axis represents
* time values, such as the time between two events. Therefore, while a date
* value may be represented as "Jan 31, 1994", a time value might be represented as "3 weeks".
* @see DateAxis
* @author Jonas Gifford
*/
final public class TimeAxis extends AxisType implements TimeCoordinateTransformation
{
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* begin code for handling unit size
*/
/** The integer code for millisecond units. */
public static final int MILLISECONDS = 0;
/** The integer code for second units. */
public static final int SECONDS = 1;
/** The integer code for minute units. */
public static final int MINUTES = 2;
/** The integer code for hour units. */
public static final int HOURS = 3;
/** The integer code for day units. */
public static final int DAYS = 4;
/** The integer code for week units. */
public static final int WEEKS = 5;
/** The integer code for month units. */
public static final int MONTHS = 6;
/** The integer code for year units. */
public static final int YEARS = 7;
/**
* Set OMIT
as the length of a time unit to have that unit not
* considered as a candidate for axis units.
*/
public static final long OMIT = 0L;
private long[] unitLengths =
{
1L, // milliseconds
1000L, // seconds
1000L * 60L, // minutes
1000L * 60L * 60L, // hours
1000L * 60L * 60L * 24L, // days
1000L * 60L * 60L * 24L * 7L, // weeks
OMIT, // months
1000L * 60L * 60L * 24L * 365L // years
};
/**
* Allows units to be viewed as valued different from the default. For example,
* a year by default is 1000L * 60L * 60L * 24L * 365L
milliseconds,
* but a call such as this may be desirable:
* setUnitLength(TimeAxis.YEARS, (long) (1000 * 60 * 60 * 24 * 365.24));
*/
public void setUnitLength(final int unit, final long length)
{
if (length < 0L || length != OMIT &&
(unit != MILLISECONDS && length <= unitLengths[unit - 1] ||
unit != YEARS && length >= unitLengths[unit + 1]))
{
throw new IllegalArgumentException();
}
if (length == OMIT && unitIndex == unit)
labelsValid = false; // these labels are no good, so on the next validation we'll get a new set
unitLengths[unit] = length;
}
/**
* Returns the number of milliseconds for this unit, or OMIT
.
* @see #OMIT
*/
public long getUnitLength(int unit)
{
return unitLengths[unit];
}
/*
* end code for handling unit size
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* begin interface to unit description
*/
private final String[] unitNames =
{
"milliseconds",
"seconds",
"minutes",
"hours",
"days",
"weeks",
"months",
"years"
};
/** Returns a string representation of the units showing on the axis. */
public String getUnits()
{
return unitNames[unitIndex];
}
/*
* end interface to unit description
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/**
* Sets whether this object should round the minimum down and the maximum
* up to make labels land exactly on the min and max of the axis range.
*/
public void setUseSuggestedRange(final boolean useSuggestedRange)
{
if (this.useSuggestedRange != useSuggestedRange)
labelsValid = false; // these labels are no good, so on the next validation we'll get a new set
this.useSuggestedRange = useSuggestedRange;
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* begin interface to range
*/
/** Sets the minimum value for the axis data. */
public void setMin(final long min)
{
if (dataMin != min)
labelsValid = false; // these labels are no good, so on the next validation we'll get a new set
dataMin = min;
}
/** Sets the maximum value for the axis data. */
public void setMax(final long max)
{
if (dataMax != max)
labelsValid = false; // these labels are no good, so on the next validation we'll get a new set
dataMax = max;
}
/**
* Returns the minimum value on the axis range. This value may be
* smaller than the data minimum if the axis has been told to use the
* suggested range.
* @see #setUseSuggestedRange(boolean)
* @see #setMin(long)
* @see #getDataMin()
*/
public long getAxisMin()
{
return axisMin;
}
/**
* Returns the maximum value on the axis range. This value may be
* larger than the data maximum if the axis has been told to use the
* suggested range.
* @see #setUseSuggestedRange(boolean)
* @see #setMax(long)
* @see #getDataMax()
*/
public long getAxisMax()
{
return axisMax;
}
/**
* Returns the minimum value on the data range, as set by the method
* setMin(long)
. This value may be
* larger than the axis minimum if the axis has been told to use the
* suggested range.
* @see #setMin(long)
* @see #setUseSuggestedRange(boolean)
* @see #getAxisMin()
*/
public long getDataMin()
{
return dataMin;
}
/**
* Returns the maximum value on the axis range, as set by the method
* setMax(long)
. This value may be
* smaller than the axis maximum if the axis has been told to use the
* suggested range.
* @see #setMax(long)
* @see #setUseSuggestedRange(boolean)
* @see #getAxisMax()
*/
public long getDataMax()
{
return dataMax;
}
/*
* end interface to range
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* begin AxisType methods
*/
/**
* Returns an instance of TimeCoordinateTransformation.
* @see TimeCoordinateTransformation
*/
CoordinateTransformation getCoordinateTransformation()
{
return this;
}
void paintAxis(final PlotGraphics g, final double originX, final double originY, final double axisLength,
final Color textColor, final Color majorTickColor, final Color minorTickColor)
{
final FontMetrics fm = g.getFontMetrics();
if (axis.getAxisOrientation() == Axis.HORIZONTAL)
{
final double y = originY + fm.getMaxAscent() + Axis.padFromAxis;
for (int i = 0; i < labels.length; i++)
{
final String text = labels[i].text;
final double x = originX + labels[i].position * axisLength;
g.setColor(textColor);
g.drawString(text, x - fm.stringWidth(text) / 2, y);
g.setColor(majorTickColor);
g.drawLine(x, originY + majorTickLength, x, originY - majorTickLength);
}
}
else
{
final double x = axis.onLeftSide ? originX - Axis.padFromAxis : originX + Axis.padFromAxis;
final double height = fm.getAscent() / 2;
for (int i = 0; i < labels.length; i++)
{
final String text = labels[i].text;
final double y = originY - labels[i].position * axisLength;
g.setColor(textColor);
g.drawString(text, axis.onLeftSide ? x - fm.stringWidth(text) : x, y + height);
g.setColor(majorTickColor);
g.drawLine(originX - majorTickLength, y, originX + majorTickLength, y);
}
}
}
// The method below uses several calculations with the same idea:
// Math.max(