Source for org.jfree.chart.annotations.XYImageAnnotation

   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:  * XYImageAnnotation.java
  29:  * ----------------------
  30:  * (C) Copyright 2003-2006, by Object Refinery Limited and Contributors.
  31:  *
  32:  * Original Author:  David Gilbert (for Object Refinery Limited);
  33:  * Contributor(s):   Mike Harris;
  34:  *
  35:  * $Id: XYImageAnnotation.java,v 1.8.2.2 2006/12/01 15:57:33 mungady Exp $
  36:  *
  37:  * Changes:
  38:  * --------
  39:  * 01-Dec-2003 : Version 1 (DG);
  40:  * 21-Jan-2004 : Update for renamed method in ValueAxis (DG);
  41:  * 18-May-2004 : Fixed bug with plot orientation (DG);
  42:  * 29-Sep-2004 : Now extends AbstractXYAnnotation, with modified draw() 
  43:  *               method signature and updated equals() method (DG);
  44:  * ------------- JFREECHART 1.0.x ---------------------------------------------
  45:  * 01-Dec-2006 : Added anchor attribute (see patch 1584860 from 
  46:  *               Mike Harris) (DG); 
  47:  */
  48: 
  49: package org.jfree.chart.annotations;
  50: 
  51: import java.awt.Graphics2D;
  52: import java.awt.Image;
  53: import java.awt.geom.Point2D;
  54: import java.awt.geom.Rectangle2D;
  55: import java.io.IOException;
  56: import java.io.ObjectInputStream;
  57: import java.io.ObjectOutputStream;
  58: import java.io.Serializable;
  59: 
  60: import org.jfree.chart.axis.AxisLocation;
  61: import org.jfree.chart.axis.ValueAxis;
  62: import org.jfree.chart.plot.Plot;
  63: import org.jfree.chart.plot.PlotOrientation;
  64: import org.jfree.chart.plot.PlotRenderingInfo;
  65: import org.jfree.chart.plot.XYPlot;
  66: import org.jfree.ui.RectangleAnchor;
  67: import org.jfree.ui.RectangleEdge;
  68: import org.jfree.util.ObjectUtilities;
  69: import org.jfree.util.PublicCloneable;
  70: 
  71: /**
  72:  * An annotation that allows an image to be placed at some location on 
  73:  * an {@link XYPlot}.
  74:  * 
  75:  * TODO:  implement serialization properly (image is not serializable).
  76:  */
  77: public class XYImageAnnotation extends AbstractXYAnnotation
  78:                                implements Cloneable, PublicCloneable, 
  79:                                           Serializable {
  80: 
  81:     /** For serialization. */
  82:     private static final long serialVersionUID = -4364694501921559958L;
  83:     
  84:     /** The x-coordinate (in data space). */
  85:     private double x;
  86: 
  87:     /** The y-coordinate (in data space). */
  88:     private double y;
  89: 
  90:     /** The image. */
  91:     private transient Image image;
  92: 
  93:     /** 
  94:      * The image anchor point. 
  95:      * 
  96:      * @since 1.0.4
  97:      */
  98:     private RectangleAnchor anchor;
  99:     
 100:     /**
 101:      * Creates a new annotation to be displayed at the specified (x, y) 
 102:      * location.
 103:      *
 104:      * @param x  the x-coordinate (in data space).
 105:      * @param y  the y-coordinate (in data space).
 106:      * @param image  the image (<code>null</code> not permitted).
 107:      */
 108:     public XYImageAnnotation(double x, double y, Image image) {
 109:         this(x, y, image, RectangleAnchor.CENTER);
 110:     }
 111:     
 112:     /**
 113:      * Creates a new annotation to be displayed at the specified (x, y) 
 114:      * location.
 115:      *
 116:      * @param x  the x-coordinate (in data space).
 117:      * @param y  the y-coordinate (in data space).
 118:      * @param image  the image (<code>null</code> not permitted).
 119:      * @param anchor  the image anchor (<code>null</code> not permitted).
 120:      * 
 121:      * @since 1.0.4
 122:      */
 123:     public XYImageAnnotation(double x, double y, Image image, 
 124:             RectangleAnchor anchor) {
 125:         if (image == null) {
 126:             throw new IllegalArgumentException("Null 'image' argument.");      
 127:         }
 128:         if (anchor == null) {
 129:             throw new IllegalArgumentException("Null 'anchor' argument.");
 130:         }
 131:         this.x = x;
 132:         this.y = y;
 133:         this.image = image;
 134:         this.anchor = anchor;
 135:     }    
 136:     
 137:     /**
 138:      * Returns the x-coordinate (in data space) for the annotation.
 139:      * 
 140:      * @return The x-coordinate.
 141:      * 
 142:      * @since 1.0.4
 143:      */
 144:     public double getX() {
 145:         return this.x;
 146:     }
 147:     
 148:     /**
 149:      * Returns the y-coordinate (in data space) for the annotation.
 150:      * 
 151:      * @return The y-coordinate.
 152:      * 
 153:      * @since 1.0.4
 154:      */
 155:     public double getY() {
 156:         return this.y;
 157:     }
 158:     
 159:     /**
 160:      * Returns the image for the annotation.
 161:      * 
 162:      * @return The image.
 163:      * 
 164:      * @since 1.0.4
 165:      */
 166:     public Image getImage() {
 167:         return this.image;
 168:     }
 169:     
 170:     /**
 171:      * Returns the image anchor for the annotation.
 172:      * 
 173:      * @return The image anchor.
 174:      * 
 175:      * @since 1.0.4
 176:      */
 177:     public RectangleAnchor getImageAnchor() {
 178:         return this.anchor;
 179:     }
 180: 
 181:     /**
 182:      * Draws the annotation.  This method is called by the drawing code in the 
 183:      * {@link XYPlot} class, you don't normally need to call this method 
 184:      * directly.
 185:      *
 186:      * @param g2  the graphics device.
 187:      * @param plot  the plot.
 188:      * @param dataArea  the data area.
 189:      * @param domainAxis  the domain axis.
 190:      * @param rangeAxis  the range axis.
 191:      * @param rendererIndex  the renderer index.
 192:      * @param info  if supplied, this info object will be populated with
 193:      *              entity information.
 194:      */
 195:     public void draw(Graphics2D g2, XYPlot plot, Rectangle2D dataArea,
 196:                      ValueAxis domainAxis, ValueAxis rangeAxis, 
 197:                      int rendererIndex,
 198:                      PlotRenderingInfo info) {
 199: 
 200:         PlotOrientation orientation = plot.getOrientation();
 201:         AxisLocation domainAxisLocation = plot.getDomainAxisLocation();
 202:         AxisLocation rangeAxisLocation = plot.getRangeAxisLocation();
 203:         RectangleEdge domainEdge 
 204:             = Plot.resolveDomainAxisLocation(domainAxisLocation, orientation);
 205:         RectangleEdge rangeEdge 
 206:             = Plot.resolveRangeAxisLocation(rangeAxisLocation, orientation);
 207:         float j2DX 
 208:             = (float) domainAxis.valueToJava2D(this.x, dataArea, domainEdge);
 209:         float j2DY 
 210:             = (float) rangeAxis.valueToJava2D(this.y, dataArea, rangeEdge);
 211:         float xx = 0.0f;
 212:         float yy = 0.0f;
 213:         if (orientation == PlotOrientation.HORIZONTAL) {
 214:             xx = j2DY;
 215:             yy = j2DX;
 216:         }
 217:         else if (orientation == PlotOrientation.VERTICAL) {
 218:             xx = j2DX;
 219:             yy = j2DY;
 220:         }
 221:         int w = this.image.getWidth(null);
 222:         int h = this.image.getHeight(null);
 223:         
 224:         Rectangle2D imageRect = new Rectangle2D.Double(0, 0, w, h);
 225:         Point2D anchorPoint = (Point2D) RectangleAnchor.coordinates(imageRect, 
 226:                 this.anchor);
 227:         xx = xx - (float) anchorPoint.getX();
 228:         yy = yy - (float) anchorPoint.getY();
 229:         g2.drawImage(this.image, (int) xx, (int) yy, null);
 230:         
 231:         String toolTip = getToolTipText();
 232:         String url = getURL();
 233:         if (toolTip != null || url != null) {
 234:             addEntity(info, new Rectangle2D.Float(xx, yy, w, h), rendererIndex, 
 235:                     toolTip, url);
 236:         }
 237:     }
 238: 
 239:     /**
 240:      * Tests this object for equality with an arbitrary object.
 241:      * 
 242:      * @param obj  the object (<code>null</code> permitted).
 243:      * 
 244:      * @return A boolean.
 245:      */
 246:     public boolean equals(Object obj) {
 247:         if (obj == this) {
 248:             return true;
 249:         }
 250:         // now try to reject equality...
 251:         if (!super.equals(obj)) {
 252:             return false;
 253:         }
 254:         if (!(obj instanceof XYImageAnnotation)) {
 255:             return false;
 256:         }
 257:         XYImageAnnotation that = (XYImageAnnotation) obj;
 258:         if (this.x != that.x) {
 259:             return false;
 260:         }
 261:         if (this.y != that.y) {
 262:             return false;
 263:         }
 264:         if (!ObjectUtilities.equal(this.image, that.image)) {
 265:             return false;
 266:         }
 267:         if (!this.anchor.equals(that.anchor)) {
 268:             return false;
 269:         }
 270:         // seems to be the same...
 271:         return true;
 272:     }
 273:     
 274:     /**
 275:      * Returns a hash code for this object.
 276:      * 
 277:      * @return A hash code.
 278:      */
 279:     public int hashCode() {
 280:         return this.image.hashCode();
 281:     }
 282:     
 283:     /**
 284:      * Returns a clone of the annotation.
 285:      * 
 286:      * @return A clone.
 287:      * 
 288:      * @throws CloneNotSupportedException  if the annotation can't be cloned.
 289:      */
 290:     public Object clone() throws CloneNotSupportedException {
 291:         return super.clone();
 292:     }
 293:     
 294:     /**
 295:      * Provides serialization support.
 296:      *
 297:      * @param stream  the output stream.
 298:      *
 299:      * @throws IOException  if there is an I/O error.
 300:      */
 301:     private void writeObject(ObjectOutputStream stream) throws IOException {
 302:         stream.defaultWriteObject();
 303:         //SerialUtilities.writeImage(this.image, stream);
 304:     }
 305:     
 306:     /**
 307:      * Provides serialization support.
 308:      *
 309:      * @param stream  the input stream.
 310:      *
 311:      * @throws IOException  if there is an I/O error.
 312:      * @throws ClassNotFoundException  if there is a classpath problem.
 313:      */
 314:     private void readObject(ObjectInputStream stream) 
 315:         throws IOException, ClassNotFoundException {
 316:         stream.defaultReadObject();
 317:         //this.image = SerialUtilities.readImage(stream);
 318:     }
 319: 
 320: 
 321: }