001 /* ===========================================================
002 * JFreeChart : a free chart library for the Java(tm) platform
003 * ===========================================================
004 *
005 * (C) Copyright 2000-2008, 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-2008, by Object Refinery Limited and Contributors.
031 *
032 * Original Author: David Gilbert (for Object Refinery Limited);
033 * Contributor(s): Mike Harris;
034 *
035 * Changes:
036 * --------
037 * 01-Dec-2003 : Version 1 (DG);
038 * 21-Jan-2004 : Update for renamed method in ValueAxis (DG);
039 * 18-May-2004 : Fixed bug with plot orientation (DG);
040 * 29-Sep-2004 : Now extends AbstractXYAnnotation, with modified draw()
041 * method signature and updated equals() method (DG);
042 * ------------- JFREECHART 1.0.x ---------------------------------------------
043 * 01-Dec-2006 : Added anchor attribute (see patch 1584860 from
044 * Mike Harris) (DG);
045 */
046
047 package org.jfree.chart.annotations;
048
049 import java.awt.Graphics2D;
050 import java.awt.Image;
051 import java.awt.geom.Point2D;
052 import java.awt.geom.Rectangle2D;
053 import java.io.IOException;
054 import java.io.ObjectInputStream;
055 import java.io.ObjectOutputStream;
056 import java.io.Serializable;
057
058 import org.jfree.chart.axis.AxisLocation;
059 import org.jfree.chart.axis.ValueAxis;
060 import org.jfree.chart.plot.Plot;
061 import org.jfree.chart.plot.PlotOrientation;
062 import org.jfree.chart.plot.PlotRenderingInfo;
063 import org.jfree.chart.plot.XYPlot;
064 import org.jfree.ui.RectangleAnchor;
065 import org.jfree.ui.RectangleEdge;
066 import org.jfree.util.ObjectUtilities;
067 import org.jfree.util.PublicCloneable;
068
069 /**
070 * An annotation that allows an image to be placed at some location on
071 * an {@link XYPlot}.
072 *
073 * TODO: implement serialization properly (image is not serializable).
074 */
075 public class XYImageAnnotation extends AbstractXYAnnotation
076 implements Cloneable, PublicCloneable, Serializable {
077
078 /** For serialization. */
079 private static final long serialVersionUID = -4364694501921559958L;
080
081 /** The x-coordinate (in data space). */
082 private double x;
083
084 /** The y-coordinate (in data space). */
085 private double y;
086
087 /** The image. */
088 private transient Image image;
089
090 /**
091 * The image anchor point.
092 *
093 * @since 1.0.4
094 */
095 private RectangleAnchor anchor;
096
097 /**
098 * Creates a new annotation to be displayed at the specified (x, y)
099 * location.
100 *
101 * @param x the x-coordinate (in data space).
102 * @param y the y-coordinate (in data space).
103 * @param image the image (<code>null</code> not permitted).
104 */
105 public XYImageAnnotation(double x, double y, Image image) {
106 this(x, y, image, RectangleAnchor.CENTER);
107 }
108
109 /**
110 * Creates a new annotation to be displayed at the specified (x, y)
111 * location.
112 *
113 * @param x the x-coordinate (in data space).
114 * @param y the y-coordinate (in data space).
115 * @param image the image (<code>null</code> not permitted).
116 * @param anchor the image anchor (<code>null</code> not permitted).
117 *
118 * @since 1.0.4
119 */
120 public XYImageAnnotation(double x, double y, Image image,
121 RectangleAnchor anchor) {
122 if (image == null) {
123 throw new IllegalArgumentException("Null 'image' argument.");
124 }
125 if (anchor == null) {
126 throw new IllegalArgumentException("Null 'anchor' argument.");
127 }
128 this.x = x;
129 this.y = y;
130 this.image = image;
131 this.anchor = anchor;
132 }
133
134 /**
135 * Returns the x-coordinate (in data space) for the annotation.
136 *
137 * @return The x-coordinate.
138 *
139 * @since 1.0.4
140 */
141 public double getX() {
142 return this.x;
143 }
144
145 /**
146 * Returns the y-coordinate (in data space) for the annotation.
147 *
148 * @return The y-coordinate.
149 *
150 * @since 1.0.4
151 */
152 public double getY() {
153 return this.y;
154 }
155
156 /**
157 * Returns the image for the annotation.
158 *
159 * @return The image.
160 *
161 * @since 1.0.4
162 */
163 public Image getImage() {
164 return this.image;
165 }
166
167 /**
168 * Returns the image anchor for the annotation.
169 *
170 * @return The image anchor.
171 *
172 * @since 1.0.4
173 */
174 public RectangleAnchor getImageAnchor() {
175 return this.anchor;
176 }
177
178 /**
179 * Draws the annotation. This method is called by the drawing code in the
180 * {@link XYPlot} class, you don't normally need to call this method
181 * directly.
182 *
183 * @param g2 the graphics device.
184 * @param plot the plot.
185 * @param dataArea the data area.
186 * @param domainAxis the domain axis.
187 * @param rangeAxis the range axis.
188 * @param rendererIndex the renderer index.
189 * @param info if supplied, this info object will be populated with
190 * entity information.
191 */
192 public void draw(Graphics2D g2, XYPlot plot, Rectangle2D dataArea,
193 ValueAxis domainAxis, ValueAxis rangeAxis,
194 int rendererIndex,
195 PlotRenderingInfo info) {
196
197 PlotOrientation orientation = plot.getOrientation();
198 AxisLocation domainAxisLocation = plot.getDomainAxisLocation();
199 AxisLocation rangeAxisLocation = plot.getRangeAxisLocation();
200 RectangleEdge domainEdge
201 = Plot.resolveDomainAxisLocation(domainAxisLocation, orientation);
202 RectangleEdge rangeEdge
203 = Plot.resolveRangeAxisLocation(rangeAxisLocation, orientation);
204 float j2DX
205 = (float) domainAxis.valueToJava2D(this.x, dataArea, domainEdge);
206 float j2DY
207 = (float) rangeAxis.valueToJava2D(this.y, dataArea, rangeEdge);
208 float xx = 0.0f;
209 float yy = 0.0f;
210 if (orientation == PlotOrientation.HORIZONTAL) {
211 xx = j2DY;
212 yy = j2DX;
213 }
214 else if (orientation == PlotOrientation.VERTICAL) {
215 xx = j2DX;
216 yy = j2DY;
217 }
218 int w = this.image.getWidth(null);
219 int h = this.image.getHeight(null);
220
221 Rectangle2D imageRect = new Rectangle2D.Double(0, 0, w, h);
222 Point2D anchorPoint = RectangleAnchor.coordinates(imageRect,
223 this.anchor);
224 xx = xx - (float) anchorPoint.getX();
225 yy = yy - (float) anchorPoint.getY();
226 g2.drawImage(this.image, (int) xx, (int) yy, null);
227
228 String toolTip = getToolTipText();
229 String url = getURL();
230 if (toolTip != null || url != null) {
231 addEntity(info, new Rectangle2D.Float(xx, yy, w, h), rendererIndex,
232 toolTip, url);
233 }
234 }
235
236 /**
237 * Tests this object for equality with an arbitrary object.
238 *
239 * @param obj the object (<code>null</code> permitted).
240 *
241 * @return A boolean.
242 */
243 public boolean equals(Object obj) {
244 if (obj == this) {
245 return true;
246 }
247 // now try to reject equality...
248 if (!super.equals(obj)) {
249 return false;
250 }
251 if (!(obj instanceof XYImageAnnotation)) {
252 return false;
253 }
254 XYImageAnnotation that = (XYImageAnnotation) obj;
255 if (this.x != that.x) {
256 return false;
257 }
258 if (this.y != that.y) {
259 return false;
260 }
261 if (!ObjectUtilities.equal(this.image, that.image)) {
262 return false;
263 }
264 if (!this.anchor.equals(that.anchor)) {
265 return false;
266 }
267 // seems to be the same...
268 return true;
269 }
270
271 /**
272 * Returns a hash code for this object.
273 *
274 * @return A hash code.
275 */
276 public int hashCode() {
277 return this.image.hashCode();
278 }
279
280 /**
281 * Returns a clone of the annotation.
282 *
283 * @return A clone.
284 *
285 * @throws CloneNotSupportedException if the annotation can't be cloned.
286 */
287 public Object clone() throws CloneNotSupportedException {
288 return super.clone();
289 }
290
291 /**
292 * Provides serialization support.
293 *
294 * @param stream the output stream.
295 *
296 * @throws IOException if there is an I/O error.
297 */
298 private void writeObject(ObjectOutputStream stream) throws IOException {
299 stream.defaultWriteObject();
300 //SerialUtilities.writeImage(this.image, stream);
301 }
302
303 /**
304 * Provides serialization support.
305 *
306 * @param stream the input stream.
307 *
308 * @throws IOException if there is an I/O error.
309 * @throws ClassNotFoundException if there is a classpath problem.
310 */
311 private void readObject(ObjectInputStream stream)
312 throws IOException, ClassNotFoundException {
313 stream.defaultReadObject();
314 //this.image = SerialUtilities.readImage(stream);
315 }
316
317
318 }