001 /* ===========================================================
002 * JFreeChart : a free chart library for the Java(tm) platform
003 * ===========================================================
004 *
005 * (C) Copyright 2000-2006, 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 * XYImageAnnotation.java
029 * ----------------------
030 * (C) Copyright 2003-2006, by Object Refinery Limited and Contributors.
031 *
032 * Original Author: David Gilbert (for Object Refinery Limited);
033 * Contributor(s): Mike Harris;
034 *
035 * $Id: XYImageAnnotation.java,v 1.8.2.2 2006/12/01 15:57:33 mungady Exp $
036 *
037 * Changes:
038 * --------
039 * 01-Dec-2003 : Version 1 (DG);
040 * 21-Jan-2004 : Update for renamed method in ValueAxis (DG);
041 * 18-May-2004 : Fixed bug with plot orientation (DG);
042 * 29-Sep-2004 : Now extends AbstractXYAnnotation, with modified draw()
043 * method signature and updated equals() method (DG);
044 * ------------- JFREECHART 1.0.x ---------------------------------------------
045 * 01-Dec-2006 : Added anchor attribute (see patch 1584860 from
046 * Mike Harris) (DG);
047 */
048
049 package org.jfree.chart.annotations;
050
051 import java.awt.Graphics2D;
052 import java.awt.Image;
053 import java.awt.geom.Point2D;
054 import java.awt.geom.Rectangle2D;
055 import java.io.IOException;
056 import java.io.ObjectInputStream;
057 import java.io.ObjectOutputStream;
058 import java.io.Serializable;
059
060 import org.jfree.chart.axis.AxisLocation;
061 import org.jfree.chart.axis.ValueAxis;
062 import org.jfree.chart.plot.Plot;
063 import org.jfree.chart.plot.PlotOrientation;
064 import org.jfree.chart.plot.PlotRenderingInfo;
065 import org.jfree.chart.plot.XYPlot;
066 import org.jfree.ui.RectangleAnchor;
067 import org.jfree.ui.RectangleEdge;
068 import org.jfree.util.ObjectUtilities;
069 import org.jfree.util.PublicCloneable;
070
071 /**
072 * An annotation that allows an image to be placed at some location on
073 * an {@link XYPlot}.
074 *
075 * TODO: implement serialization properly (image is not serializable).
076 */
077 public class XYImageAnnotation extends AbstractXYAnnotation
078 implements Cloneable, PublicCloneable,
079 Serializable {
080
081 /** For serialization. */
082 private static final long serialVersionUID = -4364694501921559958L;
083
084 /** The x-coordinate (in data space). */
085 private double x;
086
087 /** The y-coordinate (in data space). */
088 private double y;
089
090 /** The image. */
091 private transient Image image;
092
093 /**
094 * The image anchor point.
095 *
096 * @since 1.0.4
097 */
098 private RectangleAnchor anchor;
099
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 }