📄 cyclicnumberaxis.java
字号:
* @param plotArea the plot area.
* @param dataArea the data area.
* @param edge the edge.
*
* @return a list of ticks.
*/
public List refreshHorizontalTicks(Graphics2D g2,
double cursor,
Rectangle2D plotArea,
Rectangle2D dataArea,
RectangleEdge edge) {
List result = new java.util.ArrayList();
Font tickLabelFont = getTickLabelFont();
g2.setFont(tickLabelFont);
if (isAutoTickUnitSelection()) {
selectAutoTickUnit(g2, plotArea, dataArea, edge);
}
double unit = getTickUnit().getSize();
double cycleBound = getCycleBound();
double currentTickValue = Math.ceil(cycleBound / unit) * unit;
double upperValue = getRange().getUpperBound();
boolean cycled = false;
boolean boundMapping = this.boundMappedToLastCycle;
this.boundMappedToLastCycle = false;
CycleBoundTick lastTick = null;
float lastX = 0.0f;
if (upperValue == cycleBound) {
currentTickValue = calculateLowestVisibleTickValue();
cycled = true;
this.boundMappedToLastCycle = true;
}
while (currentTickValue <= upperValue) {
// Cycle when necessary
boolean cyclenow = false;
if ((currentTickValue + unit > upperValue) && !cycled) {
cyclenow = true;
}
double xx = valueToJava2D(currentTickValue, dataArea, edge);
String tickLabel;
NumberFormat formatter = getNumberFormatOverride();
if (formatter != null) {
tickLabel = formatter.format(currentTickValue);
}
else {
tickLabel = getTickUnit().valueToString(currentTickValue);
}
float x = (float) xx;
float y = 0.0f;
TextAnchor anchor = null;
TextAnchor rotationAnchor = null;
double angle = 0.0;
Insets tickLabelInsets = getTickLabelInsets();
if (isVerticalTickLabels()) {
if (edge == RectangleEdge.TOP) {
y = (float) (cursor - tickLabelInsets.right);
angle = Math.PI / 2.0;
}
else {
y = (float) (cursor + tickLabelInsets.right);
angle = -Math.PI / 2.0;
}
anchor = TextAnchor.CENTER_RIGHT;
// If tick overlap when cycling, update last tick too
if ((lastTick != null) && (lastX == x) && (currentTickValue != cycleBound)) {
anchor = isInverted() ? TextAnchor.TOP_RIGHT : TextAnchor.BOTTOM_RIGHT;
result.remove(result.size() - 1);
result.add(new CycleBoundTick(
this.boundMappedToLastCycle, lastTick.getNumber(),
lastTick.getText(), x, y, anchor, anchor, lastTick.getAngle())
);
this.internalMarkerWhenTicksOverlap = true;
anchor = isInverted() ? TextAnchor.BOTTOM_RIGHT : TextAnchor.TOP_RIGHT;
}
rotationAnchor = anchor;
}
else {
if (edge == RectangleEdge.TOP) {
y = (float) (cursor - tickLabelInsets.bottom);
anchor = TextAnchor.BOTTOM_CENTER;
if ((lastTick != null) && (lastX == x) && (currentTickValue != cycleBound)) {
anchor = isInverted() ? TextAnchor.BOTTOM_LEFT : TextAnchor.BOTTOM_RIGHT;
result.remove(result.size() - 1);
result.add(new CycleBoundTick(
this.boundMappedToLastCycle, lastTick.getNumber(),
lastTick.getText(), x, y, anchor, anchor, lastTick.getAngle())
);
this.internalMarkerWhenTicksOverlap = true;
anchor = isInverted() ? TextAnchor.BOTTOM_RIGHT : TextAnchor.BOTTOM_LEFT;
}
rotationAnchor = anchor;
}
else {
y = (float) (cursor + tickLabelInsets.top);
anchor = TextAnchor.TOP_CENTER;
if ((lastTick != null) && (lastX == x) && (currentTickValue != cycleBound)) {
anchor = isInverted() ? TextAnchor.TOP_LEFT : TextAnchor.TOP_RIGHT;
result.remove(result.size() - 1);
result.add(new CycleBoundTick(
this.boundMappedToLastCycle, lastTick.getNumber(),
lastTick.getText(), x, y, anchor, anchor, lastTick.getAngle())
);
this.internalMarkerWhenTicksOverlap = true;
anchor = isInverted() ? TextAnchor.TOP_RIGHT : TextAnchor.TOP_LEFT;
}
rotationAnchor = anchor;
}
}
CycleBoundTick tick = new CycleBoundTick(this.boundMappedToLastCycle,
new Double(currentTickValue), tickLabel, x, y, anchor, rotationAnchor, angle);
if (currentTickValue == cycleBound) {
this.internalMarkerCycleBoundTick = tick;
}
result.add(tick);
lastTick = tick;
lastX = x;
currentTickValue += unit;
if (cyclenow) {
currentTickValue = calculateLowestVisibleTickValue();
upperValue = cycleBound;
cycled = true;
this.boundMappedToLastCycle = true;
}
}
this.boundMappedToLastCycle = boundMapping;
return result;
}
/**
* Builds a list of ticks for the axis. This method is called when the axis is at the left or
* right of the chart (so the axis is "vertical").
*
* @param g2 the graphics device.
* @param cursor the cursor position.
* @param plotArea the plot area.
* @param dataArea the data area.
* @param edge the edge.
*
* @return a list of ticks.
*/
public List refreshVerticalTicks(Graphics2D g2,
double cursor,
Rectangle2D plotArea,
Rectangle2D dataArea,
RectangleEdge edge) {
List result = new java.util.ArrayList();
result.clear();
Font tickLabelFont = getTickLabelFont();
g2.setFont(tickLabelFont);
if (isAutoTickUnitSelection()) {
selectAutoTickUnit(g2, plotArea, dataArea, edge);
}
double unit = getTickUnit().getSize();
double cycleBound = getCycleBound();
double currentTickValue = Math.ceil(cycleBound / unit) * unit;
double upperValue = getRange().getUpperBound();
boolean cycled = false;
boolean boundMapping = this.boundMappedToLastCycle;
this.boundMappedToLastCycle = true;
NumberTick lastTick = null;
float lastY = 0.0f;
if (upperValue == cycleBound) {
currentTickValue = calculateLowestVisibleTickValue();
cycled = true;
this.boundMappedToLastCycle = true;
}
while (currentTickValue <= upperValue) {
// Cycle when necessary
boolean cyclenow = false;
if ((currentTickValue + unit > upperValue) && !cycled) {
cyclenow = true;
}
double yy = valueToJava2D(currentTickValue, dataArea, edge);
String tickLabel;
NumberFormat formatter = getNumberFormatOverride();
if (formatter != null) {
tickLabel = formatter.format(currentTickValue);
}
else {
tickLabel = getTickUnit().valueToString(currentTickValue);
}
float x = 0.0f;
float y = (float) yy;
TextAnchor anchor = null;
TextAnchor rotationAnchor = null;
double angle = 0.0;
if (isVerticalTickLabels()) {
if (edge == RectangleEdge.LEFT) {
x = (float) (cursor - getTickLabelInsets().right);
anchor = TextAnchor.BOTTOM_CENTER;
if ((lastTick != null) && (lastY == y) && (currentTickValue != cycleBound)) {
anchor = isInverted() ? TextAnchor.BOTTOM_LEFT : TextAnchor.BOTTOM_RIGHT;
result.remove(result.size() - 1);
result.add(new CycleBoundTick(
this.boundMappedToLastCycle, lastTick.getNumber(),
lastTick.getText(), x, y, anchor, anchor, lastTick.getAngle())
);
this.internalMarkerWhenTicksOverlap = true;
anchor = isInverted() ? TextAnchor.BOTTOM_RIGHT : TextAnchor.BOTTOM_LEFT;
}
rotationAnchor = anchor;
angle = -Math.PI / 2.0;
}
else {
x = (float) (cursor + getTickLabelInsets().left);
anchor = TextAnchor.BOTTOM_CENTER;
if ((lastTick != null) && (lastY == y) && (currentTickValue != cycleBound)) {
anchor = isInverted() ? TextAnchor.BOTTOM_RIGHT : TextAnchor.BOTTOM_LEFT;
result.remove(result.size() - 1);
result.add(new CycleBoundTick(
this.boundMappedToLastCycle, lastTick.getNumber(),
lastTick.getText(), x, y, anchor, anchor, lastTick.getAngle())
);
this.internalMarkerWhenTicksOverlap = true;
anchor = isInverted() ? TextAnchor.BOTTOM_LEFT : TextAnchor.BOTTOM_RIGHT;
}
rotationAnchor = anchor;
angle = Math.PI / 2.0;
}
}
else {
if (edge == RectangleEdge.LEFT) {
x = (float) (cursor - getTickLabelInsets().right);
anchor = TextAnchor.CENTER_RIGHT;
if ((lastTick != null) && (lastY == y) && (currentTickValue != cycleBound)) {
anchor = isInverted() ? TextAnchor.BOTTOM_RIGHT : TextAnchor.TOP_RIGHT;
result.remove(result.size() - 1);
result.add(new CycleBoundTick(
this.boundMappedToLastCycle, lastTick.getNumber(),
lastTick.getText(), x, y, anchor, anchor, lastTick.getAngle())
);
this.internalMarkerWhenTicksOverlap = true;
anchor = isInverted() ? TextAnchor.TOP_RIGHT : TextAnchor.BOTTOM_RIGHT;
}
rotationAnchor = anchor;
}
else {
x = (float) (cursor + getTickLabelInsets().left);
anchor = TextAnchor.CENTER_LEFT;
if ((lastTick != null) && (lastY == y) && (currentTickValue != cycleBound)) {
anchor = isInverted() ? TextAnchor.BOTTOM_LEFT : TextAnchor.TOP_LEFT;
result.remove(result.size() - 1);
result.add(new CycleBoundTick(
this.boundMappedToLastCycle, lastTick.getNumber(),
lastTick.getText(), x, y, anchor, anchor, lastTick.getAngle())
);
this.internalMarkerWhenTicksOverlap = true;
anchor = isInverted() ? TextAnchor.TOP_LEFT : TextAnchor.BOTTOM_LEFT;
}
rotationAnchor = anchor;
}
}
CycleBoundTick tick = new CycleBoundTick(this.boundMappedToLastCycle,
new Double(currentTickValue), tickLabel, x, y, anchor, rotationAnchor, angle);
if (currentTickValue == cycleBound) {
this.internalMarkerCycleBoundTick = tick;
}
result.add(tick);
lastTick = tick;
lastY = y;
if (currentTickValue == cycleBound) {
this.internalMarkerCycleBoundTick = tick;
}
currentTickValue += unit;
if (cyclenow) {
currentTickValue = calculateLowestVisibleTickValue();
upperValue = cycleBound;
cycled = true;
this.boundMappedToLastCycle = false;
}
}
this.boundMappedToLastCycle = boundMapping;
return result;
}
/**
* Converts a coordinate from Java 2D space to data space.
*
* @param java2DValue the coordinate in Java2D space.
* @param dataArea the data area.
* @param edge the edge.
*
* @return the data value.
*/
public double java2DToValue(double java2DValue, Rectangle2D dataArea, RectangleEdge edge) {
Range range = getRange();
double vmax = range.getUpperBound();
double vp = getCycleBound();
double jmin = 0.0;
double jmax = 0.0;
if (RectangleEdge.isTopOrBottom(edge)) {
jmin = dataArea.getMinX();
jmax = dataArea.getMaxX();
}
else if (RectangleEdge.isLeftOrRight(edge)) {
jmin = dataArea.getMaxY();
jmax = dataArea.getMinY();
}
if (isInverted()) {
double jbreak = jmax - (vmax - vp) * (jmax - jmin) / this.period;
if (java2DValue >= jbreak) {
return vp + (jmax - java2DValue) * this.period / (jmax - jmin);
}
else {
return vp - (java2DValue - jmin) * this.period / (jmax - jmin);
}
}
else {
double jbreak = (vmax - vp) * (jmax - jmin) / this.period + jmin;
if (java2DValue <= jbreak) {
return vp + (java2DValue - jmin) * this.period / (jmax - jmin);
}
else {
return vp - (jmax - java2DValue) * this.period / (jmax - jmin);
}
}
}
/**
* Translates a value from data space to Java 2D space.
*
* @param value the data value.
* @param dataArea the data area.
* @param edge the edge.
*
* @return the Java 2D value.
*/
public double valueToJava2D(double value, Rectangle2D dataArea, RectangleEdge edge) {
Range range = getRange();
double vmin = range.getLowerBound();
double vmax = range.getUpperBound();
double vp = getCycleBound();
if ((value < vmin) || (value > vmax)) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -