001 /* =========================================================== 002 * JFreeChart : a free chart library for the Java(tm) platform 003 * =========================================================== 004 * 005 * (C) Copyright 2000-2005, by Object Refinery Limited and Contributors. 006 * 007 * Project Info: http://www.jfree.org/jfreechart/index.html 008 * 009 * This library is free software; you can redistribute it and/or modify it 010 * under the terms of the GNU Lesser General Public License as published by 011 * the Free Software Foundation; either version 2.1 of the License, or 012 * (at your option) any later version. 013 * 014 * This library is distributed in the hope that it will be useful, but 015 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 016 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 017 * License for more details. 018 * 019 * You should have received a copy of the GNU Lesser General Public 020 * License along with this library; if not, write to the Free Software 021 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 022 * USA. 023 * 024 * [Java is a trademark or registered trademark of Sun Microsystems, Inc. 025 * in the United States and other countries.] 026 * 027 * --------------------- 028 * XYTextAnnotation.java 029 * --------------------- 030 * (C) Copyright 2002-2005, by Object Refinery Limited. 031 * 032 * Original Author: David Gilbert (for Object Refinery Limited); 033 * Contributor(s): -; 034 * 035 * $Id: XYTextAnnotation.java,v 1.5.2.1 2005/10/25 16:51:15 mungady Exp $ 036 * 037 * Changes: 038 * -------- 039 * 28-Aug-2002 : Version 1 (DG); 040 * 07-Nov-2002 : Fixed errors reported by Checkstyle (DG); 041 * 13-Jan-2003 : Reviewed Javadocs (DG); 042 * 26-Mar-2003 : Implemented Serializable (DG); 043 * 02-Jul-2003 : Added new text alignment and rotation options (DG); 044 * 19-Aug-2003 : Implemented Cloneable (DG); 045 * 17-Jan-2003 : Added fix for bug 878706, where the annotation is placed 046 * incorrectly for a plot with horizontal orientation (thanks to 047 * Ed Yu for the fix) (DG); 048 * 21-Jan-2004 : Update for renamed method in ValueAxis (DG); 049 * 050 */ 051 052 package org.jfree.chart.annotations; 053 054 import java.awt.Color; 055 import java.awt.Font; 056 import java.awt.Graphics2D; 057 import java.awt.Paint; 058 import java.awt.Shape; 059 import java.awt.geom.Rectangle2D; 060 import java.io.IOException; 061 import java.io.ObjectInputStream; 062 import java.io.ObjectOutputStream; 063 import java.io.Serializable; 064 065 import org.jfree.chart.axis.ValueAxis; 066 import org.jfree.chart.plot.Plot; 067 import org.jfree.chart.plot.PlotOrientation; 068 import org.jfree.chart.plot.PlotRenderingInfo; 069 import org.jfree.chart.plot.XYPlot; 070 import org.jfree.io.SerialUtilities; 071 import org.jfree.text.TextUtilities; 072 import org.jfree.ui.RectangleEdge; 073 import org.jfree.ui.TextAnchor; 074 import org.jfree.util.PaintUtilities; 075 import org.jfree.util.PublicCloneable; 076 077 /** 078 * A text annotation that can be placed at a particular (x, y) location on an 079 * {@link XYPlot}. 080 */ 081 public class XYTextAnnotation extends AbstractXYAnnotation 082 implements Cloneable, PublicCloneable, 083 Serializable { 084 085 /** For serialization. */ 086 private static final long serialVersionUID = -2946063342782506328L; 087 088 /** The default font. */ 089 public static final Font DEFAULT_FONT 090 = new Font("SansSerif", Font.PLAIN, 10); 091 092 /** The default paint. */ 093 public static final Paint DEFAULT_PAINT = Color.black; 094 095 /** The default text anchor. */ 096 public static final TextAnchor DEFAULT_TEXT_ANCHOR = TextAnchor.CENTER; 097 098 /** The default rotation anchor. */ 099 public static final TextAnchor DEFAULT_ROTATION_ANCHOR = TextAnchor.CENTER; 100 101 /** The default rotation angle. */ 102 public static final double DEFAULT_ROTATION_ANGLE = 0.0; 103 104 /** The text. */ 105 private String text; 106 107 /** The font. */ 108 private Font font; 109 110 /** The paint. */ 111 private transient Paint paint; 112 113 /** The x-coordinate. */ 114 private double x; 115 116 /** The y-coordinate. */ 117 private double y; 118 119 /** The text anchor (to be aligned with (x, y)). */ 120 private TextAnchor textAnchor; 121 122 /** The rotation anchor. */ 123 private TextAnchor rotationAnchor; 124 125 /** The rotation angle. */ 126 private double rotationAngle; 127 128 /** 129 * Creates a new annotation to be displayed at the given coordinates. The 130 * coordinates are specified in data space (they will be converted to 131 * Java2D space for display). 132 * 133 * @param text the text (<code>null</code> not permitted). 134 * @param x the x-coordinate (in data space). 135 * @param y the y-coordinate (in data space). 136 */ 137 public XYTextAnnotation(String text, double x, double y) { 138 if (text == null) { 139 throw new IllegalArgumentException("Null 'text' argument."); 140 } 141 this.text = text; 142 this.font = DEFAULT_FONT; 143 this.paint = DEFAULT_PAINT; 144 this.x = x; 145 this.y = y; 146 this.textAnchor = DEFAULT_TEXT_ANCHOR; 147 this.rotationAnchor = DEFAULT_ROTATION_ANCHOR; 148 this.rotationAngle = DEFAULT_ROTATION_ANGLE; 149 } 150 151 /** 152 * Returns the text for the annotation. 153 * 154 * @return The text (never <code>null</code>). 155 */ 156 public String getText() { 157 return this.text; 158 } 159 160 /** 161 * Sets the text for the annotation. 162 * 163 * @param text the text (<code>null</code> not permitted). 164 */ 165 public void setText(String text) { 166 this.text = text; 167 } 168 169 /** 170 * Returns the font for the annotation. 171 * 172 * @return The font. 173 */ 174 public Font getFont() { 175 return this.font; 176 } 177 178 /** 179 * Sets the font for the annotation. 180 * 181 * @param font the font. 182 */ 183 public void setFont(Font font) { 184 this.font = font; 185 } 186 187 /** 188 * Returns the paint for the annotation. 189 * 190 * @return The paint. 191 */ 192 public Paint getPaint() { 193 return this.paint; 194 } 195 196 /** 197 * Sets the paint for the annotation. 198 * 199 * @param paint the paint. 200 */ 201 public void setPaint(Paint paint) { 202 this.paint = paint; 203 } 204 205 /** 206 * Returns the text anchor. 207 * 208 * @return The text anchor. 209 */ 210 public TextAnchor getTextAnchor() { 211 return this.textAnchor; 212 } 213 214 /** 215 * Sets the text anchor (the point on the text bounding rectangle that is 216 * aligned to the (x, y) coordinate of the annotation). 217 * 218 * @param anchor the anchor point. 219 */ 220 public void setTextAnchor(TextAnchor anchor) { 221 this.textAnchor = anchor; 222 } 223 224 /** 225 * Returns the rotation anchor. 226 * 227 * @return The rotation anchor point. 228 */ 229 public TextAnchor getRotationAnchor() { 230 return this.rotationAnchor; 231 } 232 233 /** 234 * Sets the rotation anchor point. 235 * 236 * @param anchor the anchor. 237 */ 238 public void setRotationAnchor(TextAnchor anchor) { 239 this.rotationAnchor = anchor; 240 } 241 242 /** 243 * Returns the rotation angle. 244 * 245 * @return The rotation angle. 246 */ 247 public double getRotationAngle() { 248 return this.rotationAngle; 249 } 250 251 /** 252 * Sets the rotation angle. 253 * <p> 254 * The angle is measured clockwise in radians. 255 * 256 * @param angle the angle (in radians). 257 */ 258 public void setRotationAngle(double angle) { 259 this.rotationAngle = angle; 260 } 261 262 /** 263 * Returns the x coordinate for the text anchor point (measured against the 264 * domain axis). 265 * 266 * @return The x coordinate (in data space). 267 */ 268 public double getX() { 269 return this.x; 270 } 271 272 /** 273 * Sets the x coordinate for the text anchor point (measured against the 274 * domain axis). 275 * 276 * @param x the x coordinate (in data space). 277 */ 278 public void setX(double x) { 279 this.x = x; 280 } 281 282 /** 283 * Returns the y coordinate for the text anchor point (measured against the 284 * range axis). 285 * 286 * @return The y coordinate (in data space). 287 */ 288 public double getY() { 289 return this.y; 290 } 291 292 /** 293 * Sets the y coordinate for the text anchor point (measured against the 294 * range axis). 295 * 296 * @param y the y coordinate. 297 */ 298 public void setY(double y) { 299 this.y = y; 300 } 301 302 /** 303 * Draws the annotation. 304 * 305 * @param g2 the graphics device. 306 * @param plot the plot. 307 * @param dataArea the data area. 308 * @param domainAxis the domain axis. 309 * @param rangeAxis the range axis. 310 * @param rendererIndex the renderer index. 311 * @param info an optional info object that will be populated with 312 * entity information. 313 */ 314 public void draw(Graphics2D g2, XYPlot plot, Rectangle2D dataArea, 315 ValueAxis domainAxis, ValueAxis rangeAxis, 316 int rendererIndex, 317 PlotRenderingInfo info) { 318 319 PlotOrientation orientation = plot.getOrientation(); 320 RectangleEdge domainEdge = Plot.resolveDomainAxisLocation( 321 plot.getDomainAxisLocation(), orientation 322 ); 323 RectangleEdge rangeEdge = Plot.resolveRangeAxisLocation( 324 plot.getRangeAxisLocation(), orientation 325 ); 326 327 float anchorX = (float) domainAxis.valueToJava2D( 328 this.x, dataArea, domainEdge 329 ); 330 float anchorY = (float) rangeAxis.valueToJava2D( 331 this.y, dataArea, rangeEdge 332 ); 333 334 if (orientation == PlotOrientation.HORIZONTAL) { 335 float tempAnchor = anchorX; 336 anchorX = anchorY; 337 anchorY = tempAnchor; 338 } 339 340 g2.setFont(getFont()); 341 g2.setPaint(getPaint()); 342 TextUtilities.drawRotatedString( 343 getText(), 344 g2, 345 anchorX, 346 anchorY, 347 getTextAnchor(), 348 getRotationAngle(), 349 getRotationAnchor() 350 ); 351 Shape hotspot = TextUtilities.calculateRotatedStringBounds( 352 getText(), 353 g2, 354 anchorX, 355 anchorY, 356 getTextAnchor(), 357 getRotationAngle(), 358 getRotationAnchor() 359 ); 360 361 String toolTip = getToolTipText(); 362 String url = getURL(); 363 if (toolTip != null || url != null) { 364 addEntity(info, hotspot, rendererIndex, toolTip, url); 365 } 366 367 } 368 369 /** 370 * Tests this annotation for equality with an arbitrary object. 371 * 372 * @param obj the object (<code>null</code> permitted). 373 * 374 * @return A boolean. 375 */ 376 public boolean equals(Object obj) { 377 if (obj == this) { 378 return true; 379 } 380 if (!(obj instanceof XYTextAnnotation)) { 381 return false; 382 } 383 if (!super.equals(obj)) { 384 return false; 385 } 386 XYTextAnnotation that = (XYTextAnnotation) obj; 387 if (!this.text.equals(that.text)) { 388 return false; 389 } 390 if (!this.font.equals(that.font)) { 391 return false; 392 } 393 if (!PaintUtilities.equal(this.paint, that.paint)) { 394 return false; 395 } 396 if (!this.rotationAnchor.equals(that.rotationAnchor)) { 397 return false; 398 } 399 if (this.rotationAngle != that.rotationAngle) { 400 return false; 401 } 402 if (!this.textAnchor.equals(that.textAnchor)) { 403 return false; 404 } 405 return true; 406 } 407 408 /** 409 * Returns a hash code for the object. 410 * 411 * @return A hash code. 412 */ 413 public int hashCode() { 414 // TODO: implement this properly. 415 return this.text.hashCode(); 416 } 417 418 /** 419 * Returns a clone of the annotation. 420 * 421 * @return A clone. 422 * 423 * @throws CloneNotSupportedException if the annotation can't be cloned. 424 */ 425 public Object clone() throws CloneNotSupportedException { 426 return super.clone(); 427 } 428 429 /** 430 * Provides serialization support. 431 * 432 * @param stream the output stream. 433 * 434 * @throws IOException if there is an I/O error. 435 */ 436 private void writeObject(ObjectOutputStream stream) throws IOException { 437 stream.defaultWriteObject(); 438 SerialUtilities.writePaint(this.paint, stream); 439 } 440 441 /** 442 * Provides serialization support. 443 * 444 * @param stream the input stream. 445 * 446 * @throws IOException if there is an I/O error. 447 * @throws ClassNotFoundException if there is a classpath problem. 448 */ 449 private void readObject(ObjectInputStream stream) 450 throws IOException, ClassNotFoundException { 451 stream.defaultReadObject(); 452 this.paint = SerialUtilities.readPaint(stream); 453 } 454 455 456 }