Frames | No Frames |
1: /* =========================================================== 2: * JFreeChart : a free chart library for the Java(tm) platform 3: * =========================================================== 4: * 5: * (C) Copyright 2000-2006, by Object Refinery Limited and Contributors. 6: * 7: * Project Info: http://www.jfree.org/jfreechart/index.html 8: * 9: * This library is free software; you can redistribute it and/or modify it 10: * under the terms of the GNU Lesser General Public License as published by 11: * the Free Software Foundation; either version 2.1 of the License, or 12: * (at your option) any later version. 13: * 14: * This library is distributed in the hope that it will be useful, but 15: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 16: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 17: * License for more details. 18: * 19: * You should have received a copy of the GNU Lesser General Public 20: * License along with this library; if not, write to the Free Software 21: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 22: * USA. 23: * 24: * [Java is a trademark or registered trademark of Sun Microsystems, Inc. 25: * in the United States and other countries.] 26: * 27: * --------------------- 28: * XYTextAnnotation.java 29: * --------------------- 30: * (C) Copyright 2002-2006, by Object Refinery Limited. 31: * 32: * Original Author: David Gilbert (for Object Refinery Limited); 33: * Contributor(s): -; 34: * 35: * $Id: XYTextAnnotation.java,v 1.5.2.2 2006/01/26 15:30:24 mungady Exp $ 36: * 37: * Changes: 38: * -------- 39: * 28-Aug-2002 : Version 1 (DG); 40: * 07-Nov-2002 : Fixed errors reported by Checkstyle (DG); 41: * 13-Jan-2003 : Reviewed Javadocs (DG); 42: * 26-Mar-2003 : Implemented Serializable (DG); 43: * 02-Jul-2003 : Added new text alignment and rotation options (DG); 44: * 19-Aug-2003 : Implemented Cloneable (DG); 45: * 17-Jan-2003 : Added fix for bug 878706, where the annotation is placed 46: * incorrectly for a plot with horizontal orientation (thanks to 47: * Ed Yu for the fix) (DG); 48: * 21-Jan-2004 : Update for renamed method in ValueAxis (DG); 49: * ------------- JFREECHART 1.0.0 --------------------------------------------- 50: * 26-Jan-2006 : Fixed equals() method (bug 1415480) (DG); 51: * 52: */ 53: 54: package org.jfree.chart.annotations; 55: 56: import java.awt.Color; 57: import java.awt.Font; 58: import java.awt.Graphics2D; 59: import java.awt.Paint; 60: import java.awt.Shape; 61: import java.awt.geom.Rectangle2D; 62: import java.io.IOException; 63: import java.io.ObjectInputStream; 64: import java.io.ObjectOutputStream; 65: import java.io.Serializable; 66: 67: import org.jfree.chart.axis.ValueAxis; 68: import org.jfree.chart.plot.Plot; 69: import org.jfree.chart.plot.PlotOrientation; 70: import org.jfree.chart.plot.PlotRenderingInfo; 71: import org.jfree.chart.plot.XYPlot; 72: import org.jfree.io.SerialUtilities; 73: import org.jfree.text.TextUtilities; 74: import org.jfree.ui.RectangleEdge; 75: import org.jfree.ui.TextAnchor; 76: import org.jfree.util.PaintUtilities; 77: import org.jfree.util.PublicCloneable; 78: 79: /** 80: * A text annotation that can be placed at a particular (x, y) location on an 81: * {@link XYPlot}. 82: */ 83: public class XYTextAnnotation extends AbstractXYAnnotation 84: implements Cloneable, PublicCloneable, 85: Serializable { 86: 87: /** For serialization. */ 88: private static final long serialVersionUID = -2946063342782506328L; 89: 90: /** The default font. */ 91: public static final Font DEFAULT_FONT 92: = new Font("SansSerif", Font.PLAIN, 10); 93: 94: /** The default paint. */ 95: public static final Paint DEFAULT_PAINT = Color.black; 96: 97: /** The default text anchor. */ 98: public static final TextAnchor DEFAULT_TEXT_ANCHOR = TextAnchor.CENTER; 99: 100: /** The default rotation anchor. */ 101: public static final TextAnchor DEFAULT_ROTATION_ANCHOR = TextAnchor.CENTER; 102: 103: /** The default rotation angle. */ 104: public static final double DEFAULT_ROTATION_ANGLE = 0.0; 105: 106: /** The text. */ 107: private String text; 108: 109: /** The font. */ 110: private Font font; 111: 112: /** The paint. */ 113: private transient Paint paint; 114: 115: /** The x-coordinate. */ 116: private double x; 117: 118: /** The y-coordinate. */ 119: private double y; 120: 121: /** The text anchor (to be aligned with (x, y)). */ 122: private TextAnchor textAnchor; 123: 124: /** The rotation anchor. */ 125: private TextAnchor rotationAnchor; 126: 127: /** The rotation angle. */ 128: private double rotationAngle; 129: 130: /** 131: * Creates a new annotation to be displayed at the given coordinates. The 132: * coordinates are specified in data space (they will be converted to 133: * Java2D space for display). 134: * 135: * @param text the text (<code>null</code> not permitted). 136: * @param x the x-coordinate (in data space). 137: * @param y the y-coordinate (in data space). 138: */ 139: public XYTextAnnotation(String text, double x, double y) { 140: if (text == null) { 141: throw new IllegalArgumentException("Null 'text' argument."); 142: } 143: this.text = text; 144: this.font = DEFAULT_FONT; 145: this.paint = DEFAULT_PAINT; 146: this.x = x; 147: this.y = y; 148: this.textAnchor = DEFAULT_TEXT_ANCHOR; 149: this.rotationAnchor = DEFAULT_ROTATION_ANCHOR; 150: this.rotationAngle = DEFAULT_ROTATION_ANGLE; 151: } 152: 153: /** 154: * Returns the text for the annotation. 155: * 156: * @return The text (never <code>null</code>). 157: */ 158: public String getText() { 159: return this.text; 160: } 161: 162: /** 163: * Sets the text for the annotation. 164: * 165: * @param text the text (<code>null</code> not permitted). 166: */ 167: public void setText(String text) { 168: this.text = text; 169: } 170: 171: /** 172: * Returns the font for the annotation. 173: * 174: * @return The font. 175: */ 176: public Font getFont() { 177: return this.font; 178: } 179: 180: /** 181: * Sets the font for the annotation. 182: * 183: * @param font the font. 184: */ 185: public void setFont(Font font) { 186: this.font = font; 187: } 188: 189: /** 190: * Returns the paint for the annotation. 191: * 192: * @return The paint. 193: */ 194: public Paint getPaint() { 195: return this.paint; 196: } 197: 198: /** 199: * Sets the paint for the annotation. 200: * 201: * @param paint the paint. 202: */ 203: public void setPaint(Paint paint) { 204: this.paint = paint; 205: } 206: 207: /** 208: * Returns the text anchor. 209: * 210: * @return The text anchor. 211: */ 212: public TextAnchor getTextAnchor() { 213: return this.textAnchor; 214: } 215: 216: /** 217: * Sets the text anchor (the point on the text bounding rectangle that is 218: * aligned to the (x, y) coordinate of the annotation). 219: * 220: * @param anchor the anchor point. 221: */ 222: public void setTextAnchor(TextAnchor anchor) { 223: this.textAnchor = anchor; 224: } 225: 226: /** 227: * Returns the rotation anchor. 228: * 229: * @return The rotation anchor point. 230: */ 231: public TextAnchor getRotationAnchor() { 232: return this.rotationAnchor; 233: } 234: 235: /** 236: * Sets the rotation anchor point. 237: * 238: * @param anchor the anchor. 239: */ 240: public void setRotationAnchor(TextAnchor anchor) { 241: this.rotationAnchor = anchor; 242: } 243: 244: /** 245: * Returns the rotation angle. 246: * 247: * @return The rotation angle. 248: */ 249: public double getRotationAngle() { 250: return this.rotationAngle; 251: } 252: 253: /** 254: * Sets the rotation angle. 255: * <p> 256: * The angle is measured clockwise in radians. 257: * 258: * @param angle the angle (in radians). 259: */ 260: public void setRotationAngle(double angle) { 261: this.rotationAngle = angle; 262: } 263: 264: /** 265: * Returns the x coordinate for the text anchor point (measured against the 266: * domain axis). 267: * 268: * @return The x coordinate (in data space). 269: */ 270: public double getX() { 271: return this.x; 272: } 273: 274: /** 275: * Sets the x coordinate for the text anchor point (measured against the 276: * domain axis). 277: * 278: * @param x the x coordinate (in data space). 279: */ 280: public void setX(double x) { 281: this.x = x; 282: } 283: 284: /** 285: * Returns the y coordinate for the text anchor point (measured against the 286: * range axis). 287: * 288: * @return The y coordinate (in data space). 289: */ 290: public double getY() { 291: return this.y; 292: } 293: 294: /** 295: * Sets the y coordinate for the text anchor point (measured against the 296: * range axis). 297: * 298: * @param y the y coordinate. 299: */ 300: public void setY(double y) { 301: this.y = y; 302: } 303: 304: /** 305: * Draws the annotation. 306: * 307: * @param g2 the graphics device. 308: * @param plot the plot. 309: * @param dataArea the data area. 310: * @param domainAxis the domain axis. 311: * @param rangeAxis the range axis. 312: * @param rendererIndex the renderer index. 313: * @param info an optional info object that will be populated with 314: * entity information. 315: */ 316: public void draw(Graphics2D g2, XYPlot plot, Rectangle2D dataArea, 317: ValueAxis domainAxis, ValueAxis rangeAxis, 318: int rendererIndex, 319: PlotRenderingInfo info) { 320: 321: PlotOrientation orientation = plot.getOrientation(); 322: RectangleEdge domainEdge = Plot.resolveDomainAxisLocation( 323: plot.getDomainAxisLocation(), orientation 324: ); 325: RectangleEdge rangeEdge = Plot.resolveRangeAxisLocation( 326: plot.getRangeAxisLocation(), orientation 327: ); 328: 329: float anchorX = (float) domainAxis.valueToJava2D( 330: this.x, dataArea, domainEdge 331: ); 332: float anchorY = (float) rangeAxis.valueToJava2D( 333: this.y, dataArea, rangeEdge 334: ); 335: 336: if (orientation == PlotOrientation.HORIZONTAL) { 337: float tempAnchor = anchorX; 338: anchorX = anchorY; 339: anchorY = tempAnchor; 340: } 341: 342: g2.setFont(getFont()); 343: g2.setPaint(getPaint()); 344: TextUtilities.drawRotatedString( 345: getText(), 346: g2, 347: anchorX, 348: anchorY, 349: getTextAnchor(), 350: getRotationAngle(), 351: getRotationAnchor() 352: ); 353: Shape hotspot = TextUtilities.calculateRotatedStringBounds( 354: getText(), 355: g2, 356: anchorX, 357: anchorY, 358: getTextAnchor(), 359: getRotationAngle(), 360: getRotationAnchor() 361: ); 362: 363: String toolTip = getToolTipText(); 364: String url = getURL(); 365: if (toolTip != null || url != null) { 366: addEntity(info, hotspot, rendererIndex, toolTip, url); 367: } 368: 369: } 370: 371: /** 372: * Tests this annotation for equality with an arbitrary object. 373: * 374: * @param obj the object (<code>null</code> permitted). 375: * 376: * @return A boolean. 377: */ 378: public boolean equals(Object obj) { 379: if (obj == this) { 380: return true; 381: } 382: if (!(obj instanceof XYTextAnnotation)) { 383: return false; 384: } 385: if (!super.equals(obj)) { 386: return false; 387: } 388: XYTextAnnotation that = (XYTextAnnotation) obj; 389: if (!this.text.equals(that.text)) { 390: return false; 391: } 392: if (this.x != that.x) { 393: return false; 394: } 395: if (this.y != that.y) { 396: return false; 397: } 398: if (!this.font.equals(that.font)) { 399: return false; 400: } 401: if (!PaintUtilities.equal(this.paint, that.paint)) { 402: return false; 403: } 404: if (!this.rotationAnchor.equals(that.rotationAnchor)) { 405: return false; 406: } 407: if (this.rotationAngle != that.rotationAngle) { 408: return false; 409: } 410: if (!this.textAnchor.equals(that.textAnchor)) { 411: return false; 412: } 413: return true; 414: } 415: 416: /** 417: * Returns a hash code for the object. 418: * 419: * @return A hash code. 420: */ 421: public int hashCode() { 422: // TODO: implement this properly. 423: return this.text.hashCode(); 424: } 425: 426: /** 427: * Returns a clone of the annotation. 428: * 429: * @return A clone. 430: * 431: * @throws CloneNotSupportedException if the annotation can't be cloned. 432: */ 433: public Object clone() throws CloneNotSupportedException { 434: return super.clone(); 435: } 436: 437: /** 438: * Provides serialization support. 439: * 440: * @param stream the output stream. 441: * 442: * @throws IOException if there is an I/O error. 443: */ 444: private void writeObject(ObjectOutputStream stream) throws IOException { 445: stream.defaultWriteObject(); 446: SerialUtilities.writePaint(this.paint, stream); 447: } 448: 449: /** 450: * Provides serialization support. 451: * 452: * @param stream the input stream. 453: * 454: * @throws IOException if there is an I/O error. 455: * @throws ClassNotFoundException if there is a classpath problem. 456: */ 457: private void readObject(ObjectInputStream stream) 458: throws IOException, ClassNotFoundException { 459: stream.defaultReadObject(); 460: this.paint = SerialUtilities.readPaint(stream); 461: } 462: 463: 464: }