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