📄 periodaxis.java
字号:
}
else if (edge == RectangleEdge.TOP) {
delta1 = this.labelInfo[band].getPadding().calculateBottomOutset(
fm.getHeight());
}
state.moveCursor(delta1, edge);
long axisMin = this.first.getFirstMillisecond(this.calendar);
long axisMax = this.last.getLastMillisecond(this.calendar);
g2.setFont(this.labelInfo[band].getLabelFont());
g2.setPaint(this.labelInfo[band].getLabelPaint());
// work out the number of periods to skip for labelling
RegularTimePeriod p1 = this.labelInfo[band].createInstance(
new Date(axisMin), this.timeZone);
RegularTimePeriod p2 = this.labelInfo[band].createInstance(
new Date(axisMax), this.timeZone);
String label1 = this.labelInfo[band].getDateFormat().format(
new Date(p1.getMiddleMillisecond(this.calendar)));
String label2 = this.labelInfo[band].getDateFormat().format(
new Date(p2.getMiddleMillisecond(this.calendar)));
Rectangle2D b1 = TextUtilities.getTextBounds(label1, g2,
g2.getFontMetrics());
Rectangle2D b2 = TextUtilities.getTextBounds(label2, g2,
g2.getFontMetrics());
double w = Math.max(b1.getWidth(), b2.getWidth());
long ww = Math.round(java2DToValue(dataArea.getX() + w + 5.0,
dataArea, edge)) - axisMin;
long length = p1.getLastMillisecond(this.calendar)
- p1.getFirstMillisecond(this.calendar);
int periods = (int) (ww / length) + 1;
RegularTimePeriod p = this.labelInfo[band].createInstance(
new Date(axisMin), this.timeZone);
Rectangle2D b = null;
long lastXX = 0L;
float y = (float) (state.getCursor());
TextAnchor anchor = TextAnchor.TOP_CENTER;
float yDelta = (float) b1.getHeight();
if (edge == RectangleEdge.TOP) {
anchor = TextAnchor.BOTTOM_CENTER;
yDelta = -yDelta;
}
while (p.getFirstMillisecond(this.calendar) <= axisMax) {
float x = (float) valueToJava2D(p.getMiddleMillisecond(
this.calendar), dataArea, edge);
DateFormat df = this.labelInfo[band].getDateFormat();
String label = df.format(new Date(p.getMiddleMillisecond(
this.calendar)));
long first = p.getFirstMillisecond(this.calendar);
long last = p.getLastMillisecond(this.calendar);
if (last > axisMax) {
// this is the last period, but it is only partially visible
// so check that the label will fit before displaying it...
Rectangle2D bb = TextUtilities.getTextBounds(label, g2,
g2.getFontMetrics());
if ((x + bb.getWidth() / 2) > dataArea.getMaxX()) {
float xstart = (float) valueToJava2D(Math.max(first,
axisMin), dataArea, edge);
if (bb.getWidth() < (dataArea.getMaxX() - xstart)) {
x = ((float) dataArea.getMaxX() + xstart) / 2.0f;
}
else {
label = null;
}
}
}
if (first < axisMin) {
// this is the first period, but it is only partially visible
// so check that the label will fit before displaying it...
Rectangle2D bb = TextUtilities.getTextBounds(label, g2,
g2.getFontMetrics());
if ((x - bb.getWidth() / 2) < dataArea.getX()) {
float xlast = (float) valueToJava2D(Math.min(last,
axisMax), dataArea, edge);
if (bb.getWidth() < (xlast - dataArea.getX())) {
x = (xlast + (float) dataArea.getX()) / 2.0f;
}
else {
label = null;
}
}
}
if (label != null) {
g2.setPaint(this.labelInfo[band].getLabelPaint());
b = TextUtilities.drawAlignedString(label, g2, x, y, anchor);
}
if (lastXX > 0L) {
if (this.labelInfo[band].getDrawDividers()) {
long nextXX = p.getFirstMillisecond(this.calendar);
long mid = (lastXX + nextXX) / 2;
float mid2d = (float) valueToJava2D(mid, dataArea, edge);
g2.setStroke(this.labelInfo[band].getDividerStroke());
g2.setPaint(this.labelInfo[band].getDividerPaint());
g2.draw(new Line2D.Float(mid2d, y, mid2d, y + yDelta));
}
}
lastXX = last;
for (int i = 0; i < periods; i++) {
p = p.next();
}
}
double used = 0.0;
if (b != null) {
used = b.getHeight();
// work out the trailing gap
if (edge == RectangleEdge.BOTTOM) {
used += this.labelInfo[band].getPadding().calculateBottomOutset(
fm.getHeight());
}
else if (edge == RectangleEdge.TOP) {
used += this.labelInfo[band].getPadding().calculateTopOutset(
fm.getHeight());
}
}
state.moveCursor(used, edge);
return state;
}
/**
* Calculates the positions of the ticks for the axis, storing the results
* in the tick list (ready for drawing).
*
* @param g2 the graphics device.
* @param state the axis state.
* @param dataArea the area inside the axes.
* @param edge the edge on which the axis is located.
*
* @return The list of ticks.
*/
public List refreshTicks(Graphics2D g2,
AxisState state,
Rectangle2D dataArea,
RectangleEdge edge) {
return Collections.EMPTY_LIST;
}
/**
* Converts a data value to a coordinate in Java2D space, assuming that the
* axis runs along one edge of the specified dataArea.
* <p>
* Note that it is possible for the coordinate to fall outside the area.
*
* @param value the data value.
* @param area the area for plotting the data.
* @param edge the edge along which the axis lies.
*
* @return The Java2D coordinate.
*/
public double valueToJava2D(double value,
Rectangle2D area,
RectangleEdge edge) {
double result = Double.NaN;
double axisMin = this.first.getFirstMillisecond(this.calendar);
double axisMax = this.last.getLastMillisecond(this.calendar);
if (RectangleEdge.isTopOrBottom(edge)) {
double minX = area.getX();
double maxX = area.getMaxX();
if (isInverted()) {
result = maxX + ((value - axisMin) / (axisMax - axisMin))
* (minX - maxX);
}
else {
result = minX + ((value - axisMin) / (axisMax - axisMin))
* (maxX - minX);
}
}
else if (RectangleEdge.isLeftOrRight(edge)) {
double minY = area.getMinY();
double maxY = area.getMaxY();
if (isInverted()) {
result = minY + (((value - axisMin) / (axisMax - axisMin))
* (maxY - minY));
}
else {
result = maxY - (((value - axisMin) / (axisMax - axisMin))
* (maxY - minY));
}
}
return result;
}
/**
* Converts a coordinate in Java2D space to the corresponding data value,
* assuming that the axis runs along one edge of the specified dataArea.
*
* @param java2DValue the coordinate in Java2D space.
* @param area the area in which the data is plotted.
* @param edge the edge along which the axis lies.
*
* @return The data value.
*/
public double java2DToValue(double java2DValue,
Rectangle2D area,
RectangleEdge edge) {
double result = Double.NaN;
double min = 0.0;
double max = 0.0;
double axisMin = this.first.getFirstMillisecond(this.calendar);
double axisMax = this.last.getLastMillisecond(this.calendar);
if (RectangleEdge.isTopOrBottom(edge)) {
min = area.getX();
max = area.getMaxX();
}
else if (RectangleEdge.isLeftOrRight(edge)) {
min = area.getMaxY();
max = area.getY();
}
if (isInverted()) {
result = axisMax - ((java2DValue - min) / (max - min)
* (axisMax - axisMin));
}
else {
result = axisMin + ((java2DValue - min) / (max - min)
* (axisMax - axisMin));
}
return result;
}
/**
* 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) {
r = getDefaultAutoRange();
}
long upper = Math.round(r.getUpperBound());
long lower = Math.round(r.getLowerBound());
this.first = createInstance(this.autoRangeTimePeriodClass,
new Date(lower), this.timeZone);
this.last = createInstance(this.autoRangeTimePeriodClass,
new Date(upper), this.timeZone);
setRange(r, false, false);
}
}
/**
* Tests the axis for equality with an arbitrary object.
*
* @param obj the object (<code>null</code> permitted).
*
* @return A boolean.
*/
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (obj instanceof PeriodAxis && super.equals(obj)) {
PeriodAxis that = (PeriodAxis) obj;
if (!this.first.equals(that.first)) {
return false;
}
if (!this.last.equals(that.last)) {
return false;
}
if (!this.timeZone.equals(that.timeZone)) {
return false;
}
if (!this.autoRangeTimePeriodClass.equals(
that.autoRangeTimePeriodClass)) {
return false;
}
if (!(isMinorTickMarksVisible()
== that.isMinorTickMarksVisible())) {
return false;
}
if (!this.majorTickTimePeriodClass.equals(
that.majorTickTimePeriodClass)) {
return false;
}
if (!this.minorTickTimePeriodClass.equals(
that.minorTickTimePeriodClass)) {
return false;
}
if (!this.minorTickMarkPaint.equals(that.minorTickMarkPaint)) {
return false;
}
if (!this.minorTickMarkStroke.equals(that.minorTickMarkStroke)) {
return false;
}
if (!Arrays.equals(this.labelInfo, that.labelInfo)) {
return false;
}
return true;
}
return false;
}
/**
* Returns a hash code for this object.
*
* @return A hash code.
*/
public int hashCode() {
if (getLabel() != null) {
return getLabel().hashCode();
}
else {
return 0;
}
}
/**
* Returns a clone of the axis.
*
* @return A clone.
*
* @throws CloneNotSupportedException this class is cloneable, but
* subclasses may not be.
*/
public Object clone() throws CloneNotSupportedException {
PeriodAxis clone = (PeriodAxis) super.clone();
clone.timeZone = (TimeZone) this.timeZone.clone();
clone.labelInfo = new PeriodAxisLabelInfo[this.labelInfo.length];
for (int i = 0; i < this.labelInfo.length; i++) {
clone.labelInfo[i] = this.labelInfo[i]; // copy across references
// to immutable objs
}
return clone;
}
/**
* A utility method used to create a particular subclass of the
* {@link RegularTimePeriod} class that includes the specified millisecond,
* assuming the specified time zone.
*
* @param periodClass the class.
* @param millisecond the time.
* @param zone the time zone.
*
* @return The time period.
*/
private RegularTimePeriod createInstance(Class periodClass,
Date millisecond, TimeZone zone) {
RegularTimePeriod result = null;
try {
Constructor c = periodClass.getDeclaredConstructor(new Class[] {
Date.class, TimeZone.class});
result = (RegularTimePeriod) c.newInstance(new Object[] {
millisecond, zone});
}
catch (Exception e) {
// do nothing
}
return result;
}
/**
* Provides serialization support.
*
* @param stream the output stream.
*
* @throws IOException if there is an I/O error.
*/
private void writeObject(ObjectOutputStream stream) throws IOException {
stream.defaultWriteObject();
SerialUtilities.writeStroke(this.minorTickMarkStroke, stream);
SerialUtilities.writePaint(this.minorTickMarkPaint, stream);
}
/**
* Provides serialization support.
*
* @param stream the input stream.
*
* @throws IOException if there is an I/O error.
* @throws ClassNotFoundException if there is a classpath problem.
*/
private void readObject(ObjectInputStream stream)
throws IOException, ClassNotFoundException {
stream.defaultReadObject();
this.minorTickMarkStroke = SerialUtilities.readStroke(stream);
this.minorTickMarkPaint = SerialUtilities.readPaint(stream);
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -