📄 dateaxis.java
字号:
* Returns the first "standard" date (based on the specified field and
* units).
*
* @param date the reference date.
* @param unit the date tick unit.
*
* @return The next "standard" date.
*/
protected Date nextStandardDate(Date date, DateTickUnit unit) {
Date previous = previousStandardDate(date, unit);
Calendar calendar = Calendar.getInstance(this.timeZone);
calendar.setTime(previous);
calendar.add(unit.getCalendarField(), unit.getCount());
return calendar.getTime();
}
/**
* Returns a collection of standard date tick units that uses the default
* time zone. This collection will be used by default, but you are free
* to create your own collection if you want to (see the
* {@link ValueAxis#setStandardTickUnits(TickUnitSource)} method inherited
* from the {@link ValueAxis} class).
*
* @return A collection of standard date tick units.
*/
public static TickUnitSource createStandardDateTickUnits() {
return createStandardDateTickUnits(TimeZone.getDefault());
}
/**
* Returns a collection of standard date tick units. This collection will
* be used by default, but you are free to create your own collection if
* you want to (see the
* {@link ValueAxis#setStandardTickUnits(TickUnitSource)} method inherited
* from the {@link ValueAxis} class).
*
* @param zone the time zone (<code>null</code> not permitted).
*
* @return A collection of standard date tick units.
*/
public static TickUnitSource createStandardDateTickUnits(TimeZone zone) {
if (zone == null) {
throw new IllegalArgumentException("Null 'zone' argument.");
}
TickUnits units = new TickUnits();
// date formatters
DateFormat f1 = new SimpleDateFormat("HH:mm:ss.SSS");
DateFormat f2 = new SimpleDateFormat("HH:mm:ss");
DateFormat f3 = new SimpleDateFormat("HH:mm");
DateFormat f4 = new SimpleDateFormat("d-MMM, HH:mm");
DateFormat f5 = new SimpleDateFormat("d-MMM");
DateFormat f6 = new SimpleDateFormat("MMM-yyyy");
DateFormat f7 = new SimpleDateFormat("yyyy");
f1.setTimeZone(zone);
f2.setTimeZone(zone);
f3.setTimeZone(zone);
f4.setTimeZone(zone);
f5.setTimeZone(zone);
f6.setTimeZone(zone);
f7.setTimeZone(zone);
// milliseconds
units.add(new DateTickUnit(DateTickUnit.MILLISECOND, 1, f1));
units.add(new DateTickUnit(DateTickUnit.MILLISECOND, 5,
DateTickUnit.MILLISECOND, 1, f1));
units.add(new DateTickUnit(DateTickUnit.MILLISECOND, 10,
DateTickUnit.MILLISECOND, 1, f1));
units.add(new DateTickUnit(DateTickUnit.MILLISECOND, 25,
DateTickUnit.MILLISECOND, 5, f1));
units.add(new DateTickUnit(DateTickUnit.MILLISECOND, 50,
DateTickUnit.MILLISECOND, 10, f1));
units.add(new DateTickUnit(DateTickUnit.MILLISECOND, 100,
DateTickUnit.MILLISECOND, 10, f1));
units.add(new DateTickUnit(DateTickUnit.MILLISECOND, 250,
DateTickUnit.MILLISECOND, 10, f1));
units.add(new DateTickUnit(DateTickUnit.MILLISECOND, 500,
DateTickUnit.MILLISECOND, 50, f1));
// seconds
units.add(new DateTickUnit(DateTickUnit.SECOND, 1,
DateTickUnit.MILLISECOND, 50, f2));
units.add(new DateTickUnit(DateTickUnit.SECOND, 5,
DateTickUnit.SECOND, 1, f2));
units.add(new DateTickUnit(DateTickUnit.SECOND, 10,
DateTickUnit.SECOND, 1, f2));
units.add(new DateTickUnit(DateTickUnit.SECOND, 30,
DateTickUnit.SECOND, 5, f2));
// minutes
units.add(new DateTickUnit(DateTickUnit.MINUTE, 1,
DateTickUnit.SECOND, 5, f3));
units.add(new DateTickUnit(DateTickUnit.MINUTE, 2,
DateTickUnit.SECOND, 10, f3));
units.add(new DateTickUnit(DateTickUnit.MINUTE, 5,
DateTickUnit.MINUTE, 1, f3));
units.add(new DateTickUnit(DateTickUnit.MINUTE, 10,
DateTickUnit.MINUTE, 1, f3));
units.add(new DateTickUnit(DateTickUnit.MINUTE, 15,
DateTickUnit.MINUTE, 5, f3));
units.add(new DateTickUnit(DateTickUnit.MINUTE, 20,
DateTickUnit.MINUTE, 5, f3));
units.add(new DateTickUnit(DateTickUnit.MINUTE, 30,
DateTickUnit.MINUTE, 5, f3));
// hours
units.add(new DateTickUnit(DateTickUnit.HOUR, 1,
DateTickUnit.MINUTE, 5, f3));
units.add(new DateTickUnit(DateTickUnit.HOUR, 2,
DateTickUnit.MINUTE, 10, f3));
units.add(new DateTickUnit(DateTickUnit.HOUR, 4,
DateTickUnit.MINUTE, 30, f3));
units.add(new DateTickUnit(DateTickUnit.HOUR, 6,
DateTickUnit.HOUR, 1, f3));
units.add(new DateTickUnit(DateTickUnit.HOUR, 12,
DateTickUnit.HOUR, 1, f4));
// days
units.add(new DateTickUnit(DateTickUnit.DAY, 1,
DateTickUnit.HOUR, 1, f5));
units.add(new DateTickUnit(DateTickUnit.DAY, 2,
DateTickUnit.HOUR, 1, f5));
units.add(new DateTickUnit(DateTickUnit.DAY, 7,
DateTickUnit.DAY, 1, f5));
units.add(new DateTickUnit(DateTickUnit.DAY, 15,
DateTickUnit.DAY, 1, f5));
// months
units.add(new DateTickUnit(DateTickUnit.MONTH, 1,
DateTickUnit.DAY, 1, f6));
units.add(new DateTickUnit(DateTickUnit.MONTH, 2,
DateTickUnit.DAY, 1, f6));
units.add(new DateTickUnit(DateTickUnit.MONTH, 3,
DateTickUnit.MONTH, 1, f6));
units.add(new DateTickUnit(DateTickUnit.MONTH, 4,
DateTickUnit.MONTH, 1, f6));
units.add(new DateTickUnit(DateTickUnit.MONTH, 6,
DateTickUnit.MONTH, 1, f6));
// years
units.add(new DateTickUnit(DateTickUnit.YEAR, 1,
DateTickUnit.MONTH, 1, f7));
units.add(new DateTickUnit(DateTickUnit.YEAR, 2,
DateTickUnit.MONTH, 3, f7));
units.add(new DateTickUnit(DateTickUnit.YEAR, 5,
DateTickUnit.YEAR, 1, f7));
units.add(new DateTickUnit(DateTickUnit.YEAR, 10,
DateTickUnit.YEAR, 1, f7));
units.add(new DateTickUnit(DateTickUnit.YEAR, 25,
DateTickUnit.YEAR, 5, f7));
units.add(new DateTickUnit(DateTickUnit.YEAR, 50,
DateTickUnit.YEAR, 10, f7));
units.add(new DateTickUnit(DateTickUnit.YEAR, 100,
DateTickUnit.YEAR, 20, f7));
return units;
}
/**
* Rescales the axis to ensure that all data is visible.
*/
protected void autoAdjustRange() {
Plot plot = getPlot();
if (plot == null) {
return; // no plot, no data
}
if (plot instanceof ValueAxisPlot) {
ValueAxisPlot vap = (ValueAxisPlot) plot;
Range r = vap.getDataRange(this);
if (r == null) {
if (this.timeline instanceof SegmentedTimeline) {
//Timeline hasn't method getStartTime()
r = new DateRange((
(SegmentedTimeline) this.timeline).getStartTime(),
((SegmentedTimeline) this.timeline).getStartTime()
+ 1);
}
else {
r = new DateRange();
}
}
long upper = this.timeline.toTimelineValue(
(long) r.getUpperBound());
long lower;
long fixedAutoRange = (long) getFixedAutoRange();
if (fixedAutoRange > 0.0) {
lower = upper - fixedAutoRange;
}
else {
lower = this.timeline.toTimelineValue((long) r.getLowerBound());
double range = upper - lower;
long minRange = (long) getAutoRangeMinimumSize();
if (range < minRange) {
long expand = (long) (minRange - range) / 2;
upper = upper + expand;
lower = lower - expand;
}
upper = upper + (long) (range * getUpperMargin());
lower = lower - (long) (range * getLowerMargin());
}
upper = this.timeline.toMillisecond(upper);
lower = this.timeline.toMillisecond(lower);
DateRange dr = new DateRange(new Date(lower), new Date(upper));
setRange(dr, false, false);
}
}
/**
* Selects an appropriate tick value for the axis. The strategy is to
* display as many ticks as possible (selected from an array of 'standard'
* tick units) without the labels overlapping.
*
* @param g2 the graphics device.
* @param dataArea the area defined by the axes.
* @param edge the axis location.
*/
protected void selectAutoTickUnit(Graphics2D g2,
Rectangle2D dataArea,
RectangleEdge edge) {
if (RectangleEdge.isTopOrBottom(edge)) {
selectHorizontalAutoTickUnit(g2, dataArea, edge);
}
else if (RectangleEdge.isLeftOrRight(edge)) {
selectVerticalAutoTickUnit(g2, dataArea, edge);
}
}
/**
* Selects an appropriate tick size for the axis. The strategy is to
* display as many ticks as possible (selected from a collection of
* 'standard' tick units) without the labels overlapping.
*
* @param g2 the graphics device.
* @param dataArea the area defined by the axes.
* @param edge the axis location.
*/
protected void selectHorizontalAutoTickUnit(Graphics2D g2,
Rectangle2D dataArea,
RectangleEdge edge) {
long shift = 0;
if (this.timeline instanceof SegmentedTimeline) {
shift = ((SegmentedTimeline) this.timeline).getStartTime();
}
double zero = valueToJava2D(shift + 0.0, dataArea, edge);
double tickLabelWidth
= estimateMaximumTickLabelWidth(g2, getTickUnit());
// start with the current tick unit...
TickUnitSource tickUnits = getStandardTickUnits();
TickUnit unit1 = tickUnits.getCeilingTickUnit(getTickUnit());
double x1 = valueToJava2D(shift + unit1.getSize(), dataArea, edge);
double unit1Width = Math.abs(x1 - zero);
// then extrapolate...
double guess = (tickLabelWidth / unit1Width) * unit1.getSize();
DateTickUnit unit2 = (DateTickUnit) tickUnits.getCeilingTickUnit(guess);
double x2 = valueToJava2D(shift + unit2.getSize(), dataArea, edge);
double unit2Width = Math.abs(x2 - zero);
tickLabelWidth = estimateMaximumTickLabelWidth(g2, unit2);
if (tickLabelWidth > unit2Width) {
unit2 = (DateTickUnit) tickUnits.getLargerTickUnit(unit2);
}
setTickUnit(unit2, false, false);
}
/**
* Selects an appropriate tick size for the axis. The strategy is to
* display as many ticks as possible (selected from a collection of
* 'standard' tick units) without the labels overlapping.
*
* @param g2 the graphics device.
* @param dataArea the area in which the plot should be drawn.
* @param edge the axis location.
*/
protected void selectVerticalAutoTickUnit(Graphics2D g2,
Rectangle2D dataArea,
RectangleEdge edge) {
// start with the current tick unit...
TickUnitSource tickUnits = getStandardTickUnits();
double zero = valueToJava2D(0.0, dataArea, edge);
// start with a unit that is at least 1/10th of the axis length
double estimate1 = getRange().getLength() / 10.0;
DateTickUnit candidate1
= (DateTickUnit) tickUnits.getCeilingTickUnit(estimate1);
double labelHeight1 = estimateMaximumTickLabelHeight(g2, candidate1);
double y1 = valueToJava2D(candidate1.getSize(), dataArea, edge);
double candidate1UnitHeight = Math.abs(y1 - zero);
// now extrapolate based on label height and unit height...
double estimate2
= (labelHeight1 / candidate1UnitHeight) * candidate1.getSize();
DateTickUnit candidate2
= (DateTickUnit) tickUnits.getCeilingTickUnit(estimate2);
double labelHeight2 = estimateMaximumTickLabelHeight(g2, candidate2);
double y2 = valueToJava2D(candidate2.getSize(), dataArea, edge);
double unit2Height = Math.abs(y2 - zero);
// make final selection...
DateTickUnit finalUnit;
if (labelHeight2 < unit2Height) {
finalUnit = candidate2;
}
else {
finalUnit = (DateTickUnit) tickUnits.getLargerTickUnit(candidate2);
}
setTickUnit(finalUnit, false, false);
}
/**
* Estimates the maximum width of the tick labels, assuming the specified
* tick unit is used.
* <P>
* Rather than computing the string bounds of every tick on the axis, we
* just look at two values: the lower bound and the upper bound for the
* axis. These two values will usually be representative.
*
* @param g2 the graphics device.
* @param unit the tick unit to use for calculation.
*
* @return The estimated maximum width of the tick labels.
*/
private double estimateMaximumTickLabelWidth(Graphics2D g2,
DateTickUnit unit) {
RectangleInsets tickLabelInsets = getTickLabelInsets();
double result = tickLabelInsets.getLeft() + tickLabelInsets.getRight();
Font tickLabelFont = getTickLabelFont();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -