KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jfree > chart > annotations > XYPointerAnnotation


1 /* ===========================================================
2  * JFreeChart : a free chart library for the Java(tm) platform
3  * ===========================================================
4  *
5  * (C) Copyright 2000-2005, 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 License
20  * along with this library; if not, write to the Free Software Foundation,
21  * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
22  *
23  * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
24  * in the United States and other countries.]
25  *
26  * ------------------------
27  * XYPointerAnnotation.java
28  * ------------------------
29  * (C) Copyright 2003-2005, by Object Refinery Limited.
30  *
31  * Original Author: David Gilbert (for Object Refinery Limited);
32  * Contributor(s): -;
33  *
34  * $Id: XYPointerAnnotation.java,v 1.4 2005/05/19 15:41:53 mungady Exp $
35  *
36  * Changes:
37  * --------
38  * 21-May-2003 : Version 1 (DG);
39  * 10-Jun-2003 : Changed BoundsAnchor to TextAnchor (DG);
40  * 02-Jul-2003 : Added accessor methods and simplified constructor (DG);
41  * 19-Aug-2003 : Implemented Cloneable (DG);
42  * 13-Oct-2003 : Fixed bug where arrow paint is not set correctly (DG);
43  * 21-Jan-2004 : Update for renamed method in ValueAxis (DG);
44  * 29-Sep-2004 : Changes to draw() method signature (DG);
45  *
46  */

47
48 package org.jfree.chart.annotations;
49
50 import java.awt.BasicStroke JavaDoc;
51 import java.awt.Color JavaDoc;
52 import java.awt.Graphics2D JavaDoc;
53 import java.awt.Paint JavaDoc;
54 import java.awt.Stroke JavaDoc;
55 import java.awt.geom.GeneralPath JavaDoc;
56 import java.awt.geom.Line2D JavaDoc;
57 import java.awt.geom.Rectangle2D JavaDoc;
58 import java.io.IOException JavaDoc;
59 import java.io.ObjectInputStream JavaDoc;
60 import java.io.ObjectOutputStream JavaDoc;
61 import java.io.Serializable JavaDoc;
62
63 import org.jfree.chart.axis.ValueAxis;
64 import org.jfree.chart.plot.Plot;
65 import org.jfree.chart.plot.PlotOrientation;
66 import org.jfree.chart.plot.PlotRenderingInfo;
67 import org.jfree.chart.plot.XYPlot;
68 import org.jfree.io.SerialUtilities;
69 import org.jfree.text.TextUtilities;
70 import org.jfree.ui.RectangleEdge;
71 import org.jfree.util.PublicCloneable;
72
73 /**
74  * An arrow and label that can be placed on an
75  * {@link org.jfree.chart.plot.XYPlot}. The arrow is drawn at a user-definable
76  * angle so that it points towards the (x, y) location for the annotation.
77  * <p>
78  * The arrow length (and its offset from the (x, y) location) is controlled by
79  * the tip radius and the base radius attributes. Imagine two circles around
80  * the (x, y) coordinate: the inner circle defined by the tip radius, and the
81  * outer circle defined by the base radius. Now, draw the arrow starting at
82  * some point on the outer circle (the point is determined by the angle), with
83  * the arrow tip being drawn at a corresponding point on the inner circle.
84  * <p>
85  * See the <code>MarkerDemo1.java</code> source file in the JFreeChart
86  * distribution for an example.
87  *
88  */

89
90 public class XYPointerAnnotation extends XYTextAnnotation
91                                  implements Cloneable JavaDoc, PublicCloneable,
92                                             Serializable JavaDoc {
93
94     /** For serialization. */
95     private static final long serialVersionUID = -4031161445009858551L;
96     
97     /** The default tip radius (in Java2D units). */
98     public static final double DEFAULT_TIP_RADIUS = 10.0;
99     
100     /** The default base radius (in Java2D units). */
101     public static final double DEFAULT_BASE_RADIUS = 30.0;
102     
103     /** The default label offset (in Java2D units). */
104     public static final double DEFAULT_LABEL_OFFSET = 3.0;
105     
106     /** The default arrow length (in Java2D units). */
107     public static final double DEFAULT_ARROW_LENGTH = 5.0;
108
109     /** The default arrow width (in Java2D units). */
110     public static final double DEFAULT_ARROW_WIDTH = 3.0;
111     
112     /** The angle of the arrow's line (in radians). */
113     private double angle;
114
115     /**
116      * The radius from the (x, y) point to the tip of the arrow (in Java2D
117      * units).
118      */

119     private double tipRadius;
120
121     /**
122      * The radius from the (x, y) point to the start of the arrow line (in
123      * Java2D units).
124      */

125     private double baseRadius;
126
127     /** The length of the arrow head (in Java2D units). */
128     private double arrowLength;
129
130     /** The arrow width (in Java2D units, per side). */
131     private double arrowWidth;
132     
133     /** The arrow stroke. */
134     private transient Stroke JavaDoc arrowStroke;
135
136     /** The arrow paint. */
137     private transient Paint JavaDoc arrowPaint;
138     
139     /** The radius from the base point to the anchor point for the label. */
140     private double labelOffset;
141
142     /**
143      * Creates a new label and arrow annotation.
144      *
145      * @param label the label (<code>null</code> permitted).
146      * @param x the x-coordinate (measured against the chart's domain axis).
147      * @param y the y-coordinate (measured against the chart's range axis).
148      * @param angle the angle of the arrow's line (in radians).
149      */

150     public XYPointerAnnotation(String JavaDoc label, double x, double y, double angle) {
151
152         super(label, x, y);
153         this.angle = angle;
154         this.tipRadius = DEFAULT_TIP_RADIUS;
155         this.baseRadius = DEFAULT_BASE_RADIUS;
156         this.arrowLength = DEFAULT_ARROW_LENGTH;
157         this.arrowWidth = DEFAULT_ARROW_WIDTH;
158         this.labelOffset = DEFAULT_LABEL_OFFSET;
159         this.arrowStroke = new BasicStroke JavaDoc(1.0f);
160         this.arrowPaint = Color.black;
161
162     }
163     
164     /**
165      * Returns the angle of the arrow.
166      *
167      * @return The angle (in radians).
168      */

169     public double getAngle() {
170         return this.angle;
171     }
172     
173     /**
174      * Sets the angle of the arrow.
175      *
176      * @param angle the angle (in radians).
177      */

178     public void setAngle(double angle) {
179         this.angle = angle;
180     }
181     
182     /**
183      * Returns the tip radius.
184      *
185      * @return The tip radius (in Java2D units).
186      */

187     public double getTipRadius() {
188         return this.tipRadius;
189     }
190     
191     /**
192      * Sets the tip radius.
193      *
194      * @param radius the radius (in Java2D units).
195      */

196     public void setTipRadius(double radius) {
197         this.tipRadius = radius;
198     }
199     
200     /**
201      * Sets the base radius.
202      *
203      * @return The base radius (in Java2D units).
204      */

205     public double getBaseRadius() {
206         return this.baseRadius;
207     }
208     
209     /**
210      * Sets the base radius.
211      *
212      * @param radius the radius (in Java2D units).
213      */

214     public void setBaseRadius(double radius) {
215         this.baseRadius = radius;
216     }
217
218     /**
219      * Sets the label offset.
220      *
221      * @return The label offset (in Java2D units).
222      */

223     public double getLabelOffset() {
224         return this.labelOffset;
225     }
226     
227     /**
228      * Sets the label offset (from the arrow base, continuing in a straight
229      * line, in Java2D units).
230      *
231      * @param offset the offset (in Java2D units).
232      */

233     public void setLabelOffset(double offset) {
234         this.labelOffset = offset;
235     }
236     
237     /**
238      * Returns the arrow length.
239      *
240      * @return The arrow length.
241      */

242     public double getArrowLength() {
243         return this.arrowLength;
244     }
245     
246     /**
247      * Sets the arrow length.
248      *
249      * @param length the length.
250      */

251     public void setArrowLength(double length) {
252         this.arrowLength = length;
253     }
254
255     /**
256      * Returns the arrow width.
257      *
258      * @return The arrow width (in Java2D units).
259      */

260     public double getArrowWidth() {
261         return this.arrowWidth;
262     }
263     
264     /**
265      * Sets the arrow width.
266      *
267      * @param width the width (in Java2D units).
268      */

269     public void setArrowWidth(double width) {
270         this.arrowWidth = width;
271     }
272     
273     /**
274      * Returns the stroke used to draw the arrow line.
275      *
276      * @return The arrow stroke (never <code>null</code>).
277      */

278     public Stroke JavaDoc getArrowStroke() {
279         return this.arrowStroke;
280     }
281
282     /**
283      * Sets the stroke used to draw the arrow line.
284      *
285      * @param stroke the stroke (<code>null</code> not permitted).
286      */

287     public void setArrowStroke(Stroke JavaDoc stroke) {
288         if (stroke == null) {
289             throw new IllegalArgumentException JavaDoc("Null 'stroke' not permitted.");
290         }
291         this.arrowStroke = stroke;
292     }
293     
294     /**
295      * Sets the paint used for the arrow.
296      *
297      * @return The arrow paint (never <code>null</code>).
298      */

299     public Paint JavaDoc getArrowPaint() {
300         return this.arrowPaint;
301     }
302     
303     /**
304      * Sets the paint used for the arrow.
305      *
306      * @param paint the arrow paint (<code>null</code> not permitted).
307      */

308     public void setArrowPaint(Paint JavaDoc paint) {
309         this.arrowPaint = paint;
310     }
311     
312     /**
313      * Draws the annotation.
314      *
315      * @param g2 the graphics device.
316      * @param plot the plot.
317      * @param dataArea the data area.
318      * @param domainAxis the domain axis.
319      * @param rangeAxis the range axis.
320      * @param rendererIndex the renderer index.
321      * @param info the plot rendering info.
322      */

323     public void draw(Graphics2D JavaDoc g2, XYPlot plot, Rectangle2D JavaDoc dataArea,
324                      ValueAxis domainAxis, ValueAxis rangeAxis,
325                      int rendererIndex,
326                      PlotRenderingInfo info) {
327
328         PlotOrientation orientation = plot.getOrientation();
329         RectangleEdge domainEdge = Plot.resolveDomainAxisLocation(
330             plot.getDomainAxisLocation(), orientation
331         );
332         RectangleEdge rangeEdge = Plot.resolveRangeAxisLocation(
333             plot.getRangeAxisLocation(), orientation
334         );
335         double j2DX = domainAxis.valueToJava2D(getX(), dataArea, domainEdge);
336         double j2DY = rangeAxis.valueToJava2D(getY(), dataArea, rangeEdge);
337
338         double startX = j2DX + Math.cos(this.angle) * this.baseRadius;
339         double startY = j2DY + Math.sin(this.angle) * this.baseRadius;
340
341         double endX = j2DX + Math.cos(this.angle) * this.tipRadius;
342         double endY = j2DY + Math.sin(this.angle) * this.tipRadius;
343
344         double arrowBaseX = endX + Math.cos(this.angle) * this.arrowLength;
345         double arrowBaseY = endY + Math.sin(this.angle) * this.arrowLength;
346
347         double arrowLeftX = arrowBaseX
348             + Math.cos(this.angle + Math.PI / 2.0) * this.arrowWidth;
349         double arrowLeftY = arrowBaseY
350             + Math.sin(this.angle + Math.PI / 2.0) * this.arrowWidth;
351
352         double arrowRightX = arrowBaseX
353             - Math.cos(this.angle + Math.PI / 2.0) * this.arrowWidth;
354         double arrowRightY = arrowBaseY
355             - Math.sin(this.angle + Math.PI / 2.0) * this.arrowWidth;
356
357         GeneralPath JavaDoc arrow = new GeneralPath JavaDoc();
358         arrow.moveTo((float) endX, (float) endY);
359         arrow.lineTo((float) arrowLeftX, (float) arrowLeftY);
360         arrow.lineTo((float) arrowRightX, (float) arrowRightY);
361         arrow.closePath();
362
363         g2.setStroke(this.arrowStroke);
364         g2.setPaint(this.arrowPaint);
365         Line2D JavaDoc line = new Line2D.Double JavaDoc(startX, startY, endX, endY);
366         g2.draw(line);
367         g2.fill(arrow);
368
369         // draw the label
370
g2.setFont(getFont());
371         g2.setPaint(getPaint());
372         double labelX = j2DX
373             + Math.cos(this.angle) * (this.baseRadius + this.labelOffset);
374         double labelY = j2DY
375             + Math.sin(this.angle) * (this.baseRadius + this.labelOffset);
376         Rectangle2D JavaDoc hotspot = TextUtilities.drawAlignedString(
377             getText(),
378             g2,
379             (float) labelX,
380             (float) labelY,
381             getTextAnchor()
382         );
383
384         String JavaDoc toolTip = getToolTipText();
385         String JavaDoc url = getURL();
386         if (toolTip != null || url != null) {
387             addEntity(info, hotspot, rendererIndex, toolTip, url);
388         }
389         
390     }
391     
392     /**
393      * Tests this annotation for equality with an object.
394      *
395      * @param object the object to test against.
396      *
397      * @return <code>true</code> or <code>false</code>.
398      */

399     public boolean equals(Object JavaDoc object) {
400         
401         if (object == null) {
402             return false;
403         }
404         
405         if (object == this) {
406             return true;
407         }
408         
409         if (object instanceof XYPointerAnnotation) {
410         
411             XYPointerAnnotation a = (XYPointerAnnotation) object;
412             boolean b0 = (this.angle == a.angle);
413             boolean b1 = (this.tipRadius == a.tipRadius);
414             boolean b2 = (this.baseRadius == a.baseRadius);
415             boolean b3 = (this.arrowLength == a.arrowLength);
416             boolean b4 = (this.arrowWidth == a.arrowWidth);
417             boolean b5 = (this.arrowPaint.equals(a.arrowPaint));
418             boolean b6 = (this.arrowStroke.equals(a.arrowStroke));
419             boolean b7 = (this.labelOffset == a.labelOffset);
420             return b0 && b1 && b2 && b3 && b4 && b5 && b6 && b7;
421         }
422        
423         return false;
424         
425     }
426     
427     /**
428      * Returns a clone of the annotation.
429      *
430      * @return A clone.
431      *
432      * @throws CloneNotSupportedException if the annotation can't be cloned.
433      */

434     public Object JavaDoc clone() throws CloneNotSupportedException JavaDoc {
435         return super.clone();
436     }
437
438     /**
439      * Provides serialization support.
440      *
441      * @param stream the output stream.
442      *
443      * @throws IOException if there is an I/O error.
444      */

445     private void writeObject(ObjectOutputStream JavaDoc stream) throws IOException JavaDoc {
446         stream.defaultWriteObject();
447         SerialUtilities.writePaint(this.arrowPaint, stream);
448         SerialUtilities.writeStroke(this.arrowStroke, stream);
449     }
450
451     /**
452      * Provides serialization support.
453      *
454      * @param stream the input stream.
455      *
456      * @throws IOException if there is an I/O error.
457      * @throws ClassNotFoundException if there is a classpath problem.
458      */

459     private void readObject(ObjectInputStream JavaDoc stream)
460         throws IOException JavaDoc, ClassNotFoundException JavaDoc {
461         stream.defaultReadObject();
462         this.arrowPaint = SerialUtilities.readPaint(stream);
463         this.arrowStroke = SerialUtilities.readStroke(stream);
464     }
465
466 }
467
Popular Tags