1 78 79 package org.jfree.chart.axis; 80 81 import java.awt.BasicStroke ; 82 import java.awt.Color ; 83 import java.awt.Font ; 84 import java.awt.FontMetrics ; 85 import java.awt.Graphics2D ; 86 import java.awt.Paint ; 87 import java.awt.Shape ; 88 import java.awt.Stroke ; 89 import java.awt.geom.AffineTransform ; 90 import java.awt.geom.Line2D ; 91 import java.awt.geom.Rectangle2D ; 92 import java.io.IOException ; 93 import java.io.ObjectInputStream ; 94 import java.io.ObjectOutputStream ; 95 import java.io.Serializable ; 96 import java.util.Arrays ; 97 import java.util.EventListener ; 98 import java.util.List ; 99 100 import javax.swing.event.EventListenerList ; 101 102 import org.jfree.chart.event.AxisChangeEvent; 103 import org.jfree.chart.event.AxisChangeListener; 104 import org.jfree.chart.plot.Plot; 105 import org.jfree.chart.plot.PlotRenderingInfo; 106 import org.jfree.io.SerialUtilities; 107 import org.jfree.text.TextUtilities; 108 import org.jfree.ui.RectangleEdge; 109 import org.jfree.ui.RectangleInsets; 110 import org.jfree.ui.TextAnchor; 111 import org.jfree.util.ObjectUtilities; 112 113 118 public abstract class Axis implements Cloneable , Serializable { 119 120 121 private static final long serialVersionUID = 7719289504573298271L; 122 123 124 public static final boolean DEFAULT_AXIS_VISIBLE = true; 125 126 127 public static final Font DEFAULT_AXIS_LABEL_FONT 128 = new Font ("SansSerif", Font.PLAIN, 12); 129 130 131 public static final Paint DEFAULT_AXIS_LABEL_PAINT = Color.black; 132 133 134 public static final RectangleInsets DEFAULT_AXIS_LABEL_INSETS 135 = new RectangleInsets(3.0, 3.0, 3.0, 3.0); 136 137 138 public static final Paint DEFAULT_AXIS_LINE_PAINT = Color.gray; 139 140 141 public static final Stroke DEFAULT_AXIS_LINE_STROKE = new BasicStroke (1.0f); 142 143 144 public static final boolean DEFAULT_TICK_LABELS_VISIBLE = true; 145 146 147 public static final Font DEFAULT_TICK_LABEL_FONT 148 = new Font ("SansSerif", Font.PLAIN, 10); 149 150 151 public static final Paint DEFAULT_TICK_LABEL_PAINT = Color.black; 152 153 154 public static final RectangleInsets DEFAULT_TICK_LABEL_INSETS 155 = new RectangleInsets(2.0, 4.0, 2.0, 4.0); 156 157 158 public static final boolean DEFAULT_TICK_MARKS_VISIBLE = true; 159 160 161 public static final Stroke DEFAULT_TICK_MARK_STROKE = new BasicStroke (1); 162 163 164 public static final Paint DEFAULT_TICK_MARK_PAINT = Color.gray; 165 166 167 public static final float DEFAULT_TICK_MARK_INSIDE_LENGTH = 0.0f; 168 169 170 public static final float DEFAULT_TICK_MARK_OUTSIDE_LENGTH = 2.0f; 171 172 173 private boolean visible; 174 175 176 private String label; 177 178 179 private Font labelFont; 180 181 182 private transient Paint labelPaint; 183 184 185 private RectangleInsets labelInsets; 186 187 188 private double labelAngle; 189 190 191 private boolean axisLineVisible; 192 193 194 private transient Stroke axisLineStroke; 195 196 197 private transient Paint axisLinePaint; 198 199 203 private boolean tickLabelsVisible; 204 205 206 private Font tickLabelFont; 207 208 209 private transient Paint tickLabelPaint; 210 211 212 private RectangleInsets tickLabelInsets; 213 214 218 private boolean tickMarksVisible; 219 220 221 private float tickMarkInsideLength; 222 223 224 private float tickMarkOutsideLength; 225 226 227 private transient Stroke tickMarkStroke; 228 229 230 private transient Paint tickMarkPaint; 231 232 233 private double fixedDimension; 234 235 239 private transient Plot plot; 240 241 242 private transient EventListenerList listenerList; 243 244 249 protected Axis(String label) { 250 251 this.label = label; 252 this.visible = DEFAULT_AXIS_VISIBLE; 253 this.labelFont = DEFAULT_AXIS_LABEL_FONT; 254 this.labelPaint = DEFAULT_AXIS_LABEL_PAINT; 255 this.labelInsets = DEFAULT_AXIS_LABEL_INSETS; 256 this.labelAngle = 0.0; 257 258 this.axisLineVisible = true; 259 this.axisLinePaint = DEFAULT_AXIS_LINE_PAINT; 260 this.axisLineStroke = DEFAULT_AXIS_LINE_STROKE; 261 262 this.tickLabelsVisible = DEFAULT_TICK_LABELS_VISIBLE; 263 this.tickLabelFont = DEFAULT_TICK_LABEL_FONT; 264 this.tickLabelPaint = DEFAULT_TICK_LABEL_PAINT; 265 this.tickLabelInsets = DEFAULT_TICK_LABEL_INSETS; 266 267 this.tickMarksVisible = DEFAULT_TICK_MARKS_VISIBLE; 268 this.tickMarkStroke = DEFAULT_TICK_MARK_STROKE; 269 this.tickMarkPaint = DEFAULT_TICK_MARK_PAINT; 270 this.tickMarkInsideLength = DEFAULT_TICK_MARK_INSIDE_LENGTH; 271 this.tickMarkOutsideLength = DEFAULT_TICK_MARK_OUTSIDE_LENGTH; 272 273 this.plot = null; 274 275 this.listenerList = new EventListenerList (); 276 277 } 278 279 285 public boolean isVisible() { 286 return this.visible; 287 } 288 289 295 public void setVisible(boolean flag) { 296 if (flag != this.visible) { 297 this.visible = flag; 298 notifyListeners(new AxisChangeEvent(this)); 299 } 300 } 301 302 307 public String getLabel() { 308 return this.label; 309 } 310 311 317 public void setLabel(String label) { 318 319 String existing = this.label; 320 if (existing != null) { 321 if (!existing.equals(label)) { 322 this.label = label; 323 notifyListeners(new AxisChangeEvent(this)); 324 } 325 } 326 else { 327 if (label != null) { 328 this.label = label; 329 notifyListeners(new AxisChangeEvent(this)); 330 } 331 } 332 333 } 334 335 340 public Font getLabelFont() { 341 return this.labelFont; 342 } 343 344 350 public void setLabelFont(Font font) { 351 if (font == null) { 352 throw new IllegalArgumentException ("Null 'font' argument."); 353 } 354 if (!this.labelFont.equals(font)) { 355 this.labelFont = font; 356 notifyListeners(new AxisChangeEvent(this)); 357 } 358 } 359 360 365 public Paint getLabelPaint() { 366 return this.labelPaint; 367 } 368 369 375 public void setLabelPaint(Paint paint) { 376 if (paint == null) { 377 throw new IllegalArgumentException ("Null 'paint' argument."); 378 } 379 this.labelPaint = paint; 380 notifyListeners(new AxisChangeEvent(this)); 381 } 382 383 389 public RectangleInsets getLabelInsets() { 390 return this.labelInsets; 391 } 392 393 399 public void setLabelInsets(RectangleInsets insets) { 400 if (insets == null) { 401 throw new IllegalArgumentException ("Null 'insets' argument."); 402 } 403 if (!insets.equals(this.labelInsets)) { 404 this.labelInsets = insets; 405 notifyListeners(new AxisChangeEvent(this)); 406 } 407 } 408 409 414 public double getLabelAngle() { 415 return this.labelAngle; 416 } 417 418 424 public void setLabelAngle(double angle) { 425 this.labelAngle = angle; 426 notifyListeners(new AxisChangeEvent(this)); 427 } 428 429 434 public boolean isAxisLineVisible() { 435 return this.axisLineVisible; 436 } 437 438 444 public void setAxisLineVisible(boolean visible) { 445 this.axisLineVisible = visible; 446 notifyListeners(new AxisChangeEvent(this)); 447 } 448 449 454 public Paint getAxisLinePaint() { 455 return this.axisLinePaint; 456 } 457 458 464 public void setAxisLinePaint(Paint paint) { 465 if (paint == null) { 466 throw new IllegalArgumentException ("Null 'paint' argument."); 467 } 468 this.axisLinePaint = paint; 469 notifyListeners(new AxisChangeEvent(this)); 470 } 471 472 477 public Stroke getAxisLineStroke() { 478 return this.axisLineStroke; 479 } 480 481 487 public void setAxisLineStroke(Stroke stroke) { 488 if (stroke == null) { 489 throw new IllegalArgumentException ("Null 'stroke' argument."); 490 } 491 this.axisLineStroke = stroke; 492 notifyListeners(new AxisChangeEvent(this)); 493 } 494 495 500 public boolean isTickLabelsVisible() { 501 return this.tickLabelsVisible; 502 } 503 504 511 public void setTickLabelsVisible(boolean flag) { 512 513 if (flag != this.tickLabelsVisible) { 514 this.tickLabelsVisible = flag; 515 notifyListeners(new AxisChangeEvent(this)); 516 } 517 518 } 519 520 525 public Font getTickLabelFont() { 526 return this.tickLabelFont; 527 } 528 529 535 public void setTickLabelFont(Font font) { 536 537 if (font == null) { 539 throw new IllegalArgumentException ("Null 'font' argument."); 540 } 541 542 if (!this.tickLabelFont.equals(font)) { 544 this.tickLabelFont = font; 545 notifyListeners(new AxisChangeEvent(this)); 546 } 547 548 } 549 550 555 public Paint getTickLabelPaint() { 556 return this.tickLabelPaint; 557 } 558 559 565 public void setTickLabelPaint(Paint paint) { 566 if (paint == null) { 567 throw new IllegalArgumentException ("Null 'paint' argument."); 568 } 569 this.tickLabelPaint = paint; 570 notifyListeners(new AxisChangeEvent(this)); 571 } 572 573 578 public RectangleInsets getTickLabelInsets() { 579 return this.tickLabelInsets; 580 } 581 582 588 public void setTickLabelInsets(RectangleInsets insets) { 589 if (insets == null) { 590 throw new IllegalArgumentException ("Null 'insets' argument."); 591 } 592 if (!this.tickLabelInsets.equals(insets)) { 593 this.tickLabelInsets = insets; 594 notifyListeners(new AxisChangeEvent(this)); 595 } 596 } 597 598 605 public boolean isTickMarksVisible() { 606 return this.tickMarksVisible; 607 } 608 609 615 public void setTickMarksVisible(boolean flag) { 616 if (flag != this.tickMarksVisible) { 617 this.tickMarksVisible = flag; 618 notifyListeners(new AxisChangeEvent(this)); 619 } 620 } 621 622 627 public float getTickMarkInsideLength() { 628 return this.tickMarkInsideLength; 629 } 630 631 637 public void setTickMarkInsideLength(float length) { 638 this.tickMarkInsideLength = length; 639 notifyListeners(new AxisChangeEvent(this)); 640 } 641 642 647 public float getTickMarkOutsideLength() { 648 return this.tickMarkOutsideLength; 649 } 650 651 657 public void setTickMarkOutsideLength(float length) { 658 this.tickMarkOutsideLength = length; 659 notifyListeners(new AxisChangeEvent(this)); 660 } 661 662 667 public Stroke getTickMarkStroke() { 668 return this.tickMarkStroke; 669 } 670 671 677 public void setTickMarkStroke(Stroke stroke) { 678 if (stroke == null) { 679 throw new IllegalArgumentException ("Null 'stroke' argument."); 680 } 681 if (!this.tickMarkStroke.equals(stroke)) { 682 this.tickMarkStroke = stroke; 683 notifyListeners(new AxisChangeEvent(this)); 684 } 685 } 686 687 692 public Paint getTickMarkPaint() { 693 return this.tickMarkPaint; 694 } 695 696 702 public void setTickMarkPaint(Paint paint) { 703 if (paint == null) { 704 throw new IllegalArgumentException ("Null 'paint' argument."); 705 } 706 this.tickMarkPaint = paint; 707 notifyListeners(new AxisChangeEvent(this)); 708 } 709 710 717 public Plot getPlot() { 718 return this.plot; 719 } 720 721 728 public void setPlot(Plot plot) { 729 this.plot = plot; 730 configure(); 731 } 732 733 738 public double getFixedDimension() { 739 return this.fixedDimension; 740 } 741 742 753 public void setFixedDimension(double dimension) { 754 this.fixedDimension = dimension; 755 } 756 757 761 public abstract void configure(); 762 763 776 public abstract AxisSpace reserveSpace(Graphics2D g2, Plot plot, 777 Rectangle2D plotArea, 778 RectangleEdge edge, 779 AxisSpace space); 780 781 795 public abstract AxisState draw(Graphics2D g2, 796 double cursor, 797 Rectangle2D plotArea, 798 Rectangle2D dataArea, 799 RectangleEdge edge, 800 PlotRenderingInfo plotState); 801 802 813 public abstract List refreshTicks(Graphics2D g2, 814 AxisState state, 815 Rectangle2D dataArea, 816 RectangleEdge edge); 817 818 823 public void addChangeListener(AxisChangeListener listener) { 824 this.listenerList.add(AxisChangeListener.class, listener); 825 } 826 827 832 public void removeChangeListener(AxisChangeListener listener) { 833 this.listenerList.remove(AxisChangeListener.class, listener); 834 } 835 836 845 public boolean hasListener(EventListener listener) { 846 List list = Arrays.asList(this.listenerList.getListenerList()); 847 return list.contains(listener); 848 } 849 850 856 protected void notifyListeners(AxisChangeEvent event) { 857 858 Object [] listeners = this.listenerList.getListenerList(); 859 for (int i = listeners.length - 2; i >= 0; i -= 2) { 860 if (listeners[i] == AxisChangeListener.class) { 861 ((AxisChangeListener) listeners[i + 1]).axisChanged(event); 862 } 863 } 864 865 } 866 867 876 protected Rectangle2D getLabelEnclosure(Graphics2D g2, RectangleEdge edge) { 877 878 Rectangle2D result = new Rectangle2D.Double (); 879 String axisLabel = getLabel(); 880 if (axisLabel != null && !axisLabel.equals("")) { 881 FontMetrics fm = g2.getFontMetrics(getLabelFont()); 882 Rectangle2D bounds = TextUtilities.getTextBounds(axisLabel, g2, fm); 883 RectangleInsets insets = getLabelInsets(); 884 bounds = insets.createOutsetRectangle(bounds); 885 double angle = getLabelAngle(); 886 if (edge == RectangleEdge.LEFT || edge == RectangleEdge.RIGHT) { 887 angle = angle - Math.PI / 2.0; 888 } 889 double x = bounds.getCenterX(); 890 double y = bounds.getCenterY(); 891 AffineTransform transformer 892 = AffineTransform.getRotateInstance(angle, x, y); 893 Shape labelBounds = transformer.createTransformedShape(bounds); 894 result = labelBounds.getBounds2D(); 895 } 896 897 return result; 898 899 } 900 901 913 protected AxisState drawLabel(String label, 914 Graphics2D g2, 915 Rectangle2D plotArea, 916 Rectangle2D dataArea, 917 RectangleEdge edge, 918 AxisState state) { 919 920 if (state == null) { 922 throw new IllegalArgumentException ("Null 'state' argument."); 923 } 924 925 if ((label == null) || (label.equals(""))) { 926 return state; 927 } 928 929 Font font = getLabelFont(); 930 RectangleInsets insets = getLabelInsets(); 931 g2.setFont(font); 932 g2.setPaint(getLabelPaint()); 933 FontMetrics fm = g2.getFontMetrics(); 934 Rectangle2D labelBounds = TextUtilities.getTextBounds(label, g2, fm); 935 936 if (edge == RectangleEdge.TOP) { 937 938 AffineTransform t = AffineTransform.getRotateInstance( 939 getLabelAngle(), 940 labelBounds.getCenterX(), labelBounds.getCenterY() 941 ); 942 Shape rotatedLabelBounds = t.createTransformedShape(labelBounds); 943 labelBounds = rotatedLabelBounds.getBounds2D(); 944 double labelx = dataArea.getCenterX(); 945 double labely = state.getCursor() 946 - insets.getBottom() 947 - labelBounds.getHeight() / 2.0; 948 TextUtilities.drawRotatedString( 949 label, g2, (float) labelx, (float) labely, 950 TextAnchor.CENTER, getLabelAngle(), TextAnchor.CENTER 951 ); 952 state.cursorUp( 953 insets.getTop() + labelBounds.getHeight() + insets.getBottom() 954 ); 955 956 } 957 else if (edge == RectangleEdge.BOTTOM) { 958 959 AffineTransform t = AffineTransform.getRotateInstance( 960 getLabelAngle(), 961 labelBounds.getCenterX(), labelBounds.getCenterY() 962 ); 963 Shape rotatedLabelBounds = t.createTransformedShape(labelBounds); 964 labelBounds = rotatedLabelBounds.getBounds2D(); 965 double labelx = dataArea.getCenterX(); 966 double labely = state.getCursor() 967 + insets.getTop() + labelBounds.getHeight() / 2.0; 968 TextUtilities.drawRotatedString( 969 label, g2, (float) labelx, (float) labely, 970 TextAnchor.CENTER, getLabelAngle(), TextAnchor.CENTER 971 ); 972 state.cursorDown( 973 insets.getTop() + labelBounds.getHeight() + insets.getBottom() 974 ); 975 976 } 977 else if (edge == RectangleEdge.LEFT) { 978 979 AffineTransform t = AffineTransform.getRotateInstance( 980 getLabelAngle() - Math.PI / 2.0, 981 labelBounds.getCenterX(), labelBounds.getCenterY() 982 ); 983 Shape rotatedLabelBounds = t.createTransformedShape(labelBounds); 984 labelBounds = rotatedLabelBounds.getBounds2D(); 985 double labelx = state.getCursor() 986 - insets.getRight() - labelBounds.getWidth() / 2.0; 987 double labely = dataArea.getCenterY(); 988 TextUtilities.drawRotatedString( 989 label, g2, (float) labelx, (float) labely, TextAnchor.CENTER, 990 getLabelAngle() - Math.PI / 2.0, TextAnchor.CENTER 991 ); 992 state.cursorLeft( 993 insets.getLeft() + labelBounds.getWidth() + insets.getRight() 994 ); 995 } 996 else if (edge == RectangleEdge.RIGHT) { 997 998 AffineTransform t = AffineTransform.getRotateInstance( 999 getLabelAngle() + Math.PI / 2.0, 1000 labelBounds.getCenterX(), labelBounds.getCenterY() 1001 ); 1002 Shape rotatedLabelBounds = t.createTransformedShape(labelBounds); 1003 labelBounds = rotatedLabelBounds.getBounds2D(); 1004 double labelx = state.getCursor() 1005 + insets.getLeft() + labelBounds.getWidth() / 2.0; 1006 double labely = dataArea.getY() + dataArea.getHeight() / 2.0; 1007 TextUtilities.drawRotatedString( 1008 label, g2, (float) labelx, (float) labely, TextAnchor.CENTER, 1009 getLabelAngle() + Math.PI / 2.0, TextAnchor.CENTER 1010 ); 1011 state.cursorRight( 1012 insets.getLeft() + labelBounds.getWidth() + insets.getRight() 1013 ); 1014 1015 } 1016 1017 return state; 1018 1019 } 1020 1021 1029 protected void drawAxisLine(Graphics2D g2, double cursor, 1030 Rectangle2D dataArea, RectangleEdge edge) { 1031 1032 Line2D axisLine = null; 1033 if (edge == RectangleEdge.TOP) { 1034 axisLine = new Line2D.Double ( 1035 dataArea.getX(), cursor, dataArea.getMaxX(), cursor 1036 ); 1037 } 1038 else if (edge == RectangleEdge.BOTTOM) { 1039 axisLine = new Line2D.Double ( 1040 dataArea.getX(), cursor, dataArea.getMaxX(), cursor 1041 ); 1042 } 1043 else if (edge == RectangleEdge.LEFT) { 1044 axisLine = new Line2D.Double ( 1045 cursor, dataArea.getY(), cursor, dataArea.getMaxY() 1046 ); 1047 } 1048 else if (edge == RectangleEdge.RIGHT) { 1049 axisLine = new Line2D.Double ( 1050 cursor, dataArea.getY(), cursor, dataArea.getMaxY() 1051 ); 1052 } 1053 g2.setPaint(this.axisLinePaint); 1054 g2.setStroke(this.axisLineStroke); 1055 g2.draw(axisLine); 1056 1057 } 1058 1059 1067 public Object clone() throws CloneNotSupportedException { 1068 Axis clone = (Axis) super.clone(); 1069 clone.plot = null; 1071 clone.listenerList = new EventListenerList (); 1072 return clone; 1073 } 1074 1075 1082 public boolean equals(Object obj) { 1083 1084 if (obj == this) { 1085 return true; 1086 } 1087 1088 if (!(obj instanceof Axis)) { 1089 return false; 1090 } 1091 Axis that = (Axis) obj; 1092 1093 if (this.visible != that.visible) { 1094 return false; 1095 } 1096 1097 if (!ObjectUtilities.equal(this.label, that.label)) { 1098 return false; 1099 } 1100 if (!ObjectUtilities.equal(this.labelFont, that.labelFont)) { 1101 return false; 1102 } 1103 if (!ObjectUtilities.equal(this.labelPaint, that.labelPaint)) { 1104 return false; 1105 } 1106 if (!ObjectUtilities.equal(this.labelInsets, that.labelInsets)) { 1107 return false; 1108 } 1109 if (this.labelAngle != that.labelAngle) { 1110 return false; 1111 } 1112 1113 if (this.axisLineVisible != that.axisLineVisible) { 1114 return false; 1115 } 1116 if (!ObjectUtilities.equal(this.axisLineStroke, that.axisLineStroke)) { 1117 return false; 1118 } 1119 if (!ObjectUtilities.equal(this.axisLinePaint, that.axisLinePaint)) { 1120 return false; 1121 } 1122 1123 if (this.tickLabelsVisible != that.tickLabelsVisible) { 1124 return false; 1125 } 1126 if (!ObjectUtilities.equal(this.tickLabelFont, that.tickLabelFont)) { 1127 return false; 1128 } 1129 if (!ObjectUtilities.equal(this.tickLabelPaint, that.tickLabelPaint)) { 1130 return false; 1131 } 1132 if (!ObjectUtilities.equal( 1133 this.tickLabelInsets, that.tickLabelInsets 1134 )) { 1135 return false; 1136 } 1137 if (this.tickMarksVisible != that.tickMarksVisible) { 1138 return false; 1139 } 1140 if (this.tickMarkInsideLength != that.tickMarkInsideLength) { 1141 return false; 1142 } 1143 1144 if (this.tickMarkOutsideLength != that.tickMarkOutsideLength) { 1145 return false; 1146 } 1147 1148 if (!ObjectUtilities.equal(this.tickMarkPaint, that.tickMarkPaint)) { 1149 return false; 1150 } 1151 if (!ObjectUtilities.equal(this.tickMarkStroke, that.tickMarkStroke)) { 1152 return false; 1153 } 1154 1155 if (this.fixedDimension != that.fixedDimension) { 1156 return false; 1157 } 1158 1159 return true; 1160 1161 } 1162 1163 1170 private void writeObject(ObjectOutputStream stream) throws IOException { 1171 stream.defaultWriteObject(); 1172 SerialUtilities.writePaint(this.labelPaint, stream); 1173 SerialUtilities.writePaint(this.tickLabelPaint, stream); 1174 SerialUtilities.writeStroke(this.axisLineStroke, stream); 1175 SerialUtilities.writePaint(this.axisLinePaint, stream); 1176 SerialUtilities.writeStroke(this.tickMarkStroke, stream); 1177 SerialUtilities.writePaint(this.tickMarkPaint, stream); 1178 } 1179 1180 1188 private void readObject(ObjectInputStream stream) 1189 throws IOException , ClassNotFoundException { 1190 stream.defaultReadObject(); 1191 this.labelPaint = SerialUtilities.readPaint(stream); 1192 this.tickLabelPaint = SerialUtilities.readPaint(stream); 1193 this.axisLineStroke = SerialUtilities.readStroke(stream); 1194 this.axisLinePaint = SerialUtilities.readPaint(stream); 1195 this.tickMarkStroke = SerialUtilities.readStroke(stream); 1196 this.tickMarkPaint = SerialUtilities.readPaint(stream); 1197 this.listenerList = new EventListenerList (); 1198 } 1199 1200} 1201 | Popular Tags |