📄 dateaxis.java
字号:
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();
FontRenderContext frc = g2.getFontRenderContext();
LineMetrics lm = tickLabelFont.getLineMetrics("ABCxyz", frc);
if (isVerticalTickLabels()) {
// all tick labels have the same width (equal to the height of
// the font)...
result += lm.getHeight();
}
else {
// look at lower and upper bounds...
DateRange range = (DateRange) getRange();
Date lower = range.getLowerDate();
Date upper = range.getUpperDate();
String lowerStr = null;
String upperStr = null;
DateFormat formatter = getDateFormatOverride();
if (formatter != null) {
lowerStr = formatter.format(lower);
upperStr = formatter.format(upper);
}
else {
lowerStr = unit.dateToString(lower);
upperStr = unit.dateToString(upper);
}
FontMetrics fm = g2.getFontMetrics(tickLabelFont);
double w1 = fm.stringWidth(lowerStr);
double w2 = fm.stringWidth(upperStr);
result += Math.max(w1, w2);
}
return result;
}
/**
* 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 estimateMaximumTickLabelHeight(Graphics2D g2,
DateTickUnit unit) {
RectangleInsets tickLabelInsets = getTickLabelInsets();
double result = tickLabelInsets.getTop() + tickLabelInsets.getBottom();
Font tickLabelFont = getTickLabelFont();
FontRenderContext frc = g2.getFontRenderContext();
LineMetrics lm = tickLabelFont.getLineMetrics("ABCxyz", frc);
if (!isVerticalTickLabels()) {
// all tick labels have the same width (equal to the height of
// the font)...
result += lm.getHeight();
}
else {
// look at lower and upper bounds...
DateRange range = (DateRange) getRange();
Date lower = range.getLowerDate();
Date upper = range.getUpperDate();
String lowerStr = null;
String upperStr = null;
DateFormat formatter = getDateFormatOverride();
if (formatter != null) {
lowerStr = formatter.format(lower);
upperStr = formatter.format(upper);
}
else {
lowerStr = unit.dateToString(lower);
upperStr = unit.dateToString(upper);
}
FontMetrics fm = g2.getFontMetrics(tickLabelFont);
double w1 = fm.stringWidth(lowerStr);
double w2 = fm.stringWidth(upperStr);
result += Math.max(w1, w2);
}
return result;
}
/**
* Calculates the positions of the tick labels for the axis, storing the
* results in the tick label list (ready for drawing).
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -