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: * DialPointer.java
029: * ----------------
030: * (C) Copyright 2006, by Object Refinery Limited.
031: *
032: * Original Author: David Gilbert (for Object Refinery Limited);
033: * Contributor(s): -;
034: *
035: * $Id: DialPointer.java,v 1.1.2.4 2007/04/30 21:38:31 mungady Exp $
036: *
037: * Changes
038: * -------
039: * 03-Nov-2006 : Version 1 (DG);
040: *
041: */
042:
043: package org.jfree.experimental.chart.plot.dial;
044:
045: import java.awt.BasicStroke;
046: import java.awt.Color;
047: import java.awt.Graphics2D;
048: import java.awt.Paint;
049: import java.awt.Stroke;
050: import java.awt.geom.Arc2D;
051: import java.awt.geom.GeneralPath;
052: import java.awt.geom.Line2D;
053: import java.awt.geom.Point2D;
054: import java.awt.geom.Rectangle2D;
055: import java.io.Serializable;
056:
057: import org.jfree.util.PublicCloneable;
058:
059: /**
060: * A base class for the pointer in a {@link DialPlot}.
061: */
062: public abstract class DialPointer extends AbstractDialLayer implements
063: DialLayer, Cloneable, Serializable {
064:
065: /** The needle radius. */
066: double radius;
067:
068: /**
069: * The dataset index for the needle.
070: */
071: int datasetIndex;
072:
073: /**
074: * Creates a new <code>DialPointer</code> instance.
075: */
076: public DialPointer() {
077: this (0);
078: }
079:
080: /**
081: * Creates a new pointer for the specified dataset.
082: *
083: * @param datasetIndex the dataset index.
084: */
085: public DialPointer(int datasetIndex) {
086: this .radius = 0.675;
087: this .datasetIndex = datasetIndex;
088: }
089:
090: /**
091: * Returns the dataset index that the pointer maps to.
092: *
093: * @return The dataset index.
094: */
095: public int getDatasetIndex() {
096: return this .datasetIndex;
097: }
098:
099: /**
100: * Sets the dataset index for the pointer.
101: *
102: * @param index the index.
103: */
104: public void setDatasetIndex(int index) {
105: this .datasetIndex = index;
106: notifyListeners(new DialLayerChangeEvent(this ));
107: }
108:
109: /**
110: * Returns the radius of the pointer.
111: *
112: * @return The radius.
113: *
114: * @see #setRadius(double)
115: */
116: public double getRadius() {
117: return this .radius;
118: }
119:
120: /**
121: * Sets the radius of the pointer.
122: *
123: * @param radius the radius.
124: *
125: * @see #getRadius()
126: */
127: public void setRadius(double radius) {
128: this .radius = radius;
129: notifyListeners(new DialLayerChangeEvent(this ));
130: }
131:
132: /**
133: * Returns <code>true</code> to indicate that this layer should be
134: * clipped within the dial window.
135: *
136: * @return <code>true</code>.
137: */
138: public boolean isClippedToWindow() {
139: return true;
140: }
141:
142: /**
143: * Returns a clone of the pointer.
144: *
145: * @return a clone.
146: *
147: * @throws CloneNotSupportedException if one of the attributes cannot
148: * be cloned.
149: */
150: public Object clone() throws CloneNotSupportedException {
151: return super .clone();
152: }
153:
154: /**
155: * A dial pointer that draws a thin line (like a pin).
156: */
157: public static class Pin extends DialPointer implements
158: PublicCloneable {
159:
160: /** The paint. */
161: private transient Paint paint;
162:
163: /** The stroke. */
164: private transient Stroke stroke;
165:
166: /**
167: * Creates a new instance.
168: */
169: public Pin() {
170: this (0);
171: }
172:
173: /**
174: * Creates a new instance.
175: *
176: * @param datasetIndex the dataset index.
177: */
178: public Pin(int datasetIndex) {
179: super (datasetIndex);
180: this .paint = Color.red;
181: this .stroke = new BasicStroke(3.0f, BasicStroke.CAP_ROUND,
182: BasicStroke.JOIN_BEVEL);
183: }
184:
185: /**
186: * Returns the paint.
187: *
188: * @return The paint.
189: */
190: public Paint getPaint() {
191: return this .paint;
192: }
193:
194: /**
195: * Sets the paint.
196: *
197: * @param paint the paint (<code>null</code> not permitted).
198: */
199: public void setPaint(Paint paint) {
200: this .paint = paint;
201: notifyListeners(new DialLayerChangeEvent(this ));
202: }
203:
204: /**
205: * Returns the stroke.
206: *
207: * @return The stroke.
208: */
209: public Stroke getStroke() {
210: return this .stroke;
211: }
212:
213: /**
214: * Sets the stroke.
215: *
216: * @param stroke the stroke (<code>null</code> not permitted).
217: */
218: public void setStroke(Stroke stroke) {
219: this .stroke = stroke;
220: notifyListeners(new DialLayerChangeEvent(this ));
221: }
222:
223: /**
224: * Draws the pointer.
225: *
226: * @param g2 the graphics target.
227: * @param plot the plot.
228: * @param frame the dial's reference frame.
229: * @param view the dial's view.
230: */
231: public void draw(Graphics2D g2, DialPlot plot,
232: Rectangle2D frame, Rectangle2D view) {
233:
234: g2.setPaint(this .paint);
235: g2.setStroke(this .stroke);
236: Rectangle2D arcRect = DialPlot.rectangleByRadius(frame,
237: this .radius, this .radius);
238:
239: double value = plot.getValue(this .datasetIndex);
240: DialScale scale = plot
241: .getScaleForDataset(this .datasetIndex);
242: double angle = scale.valueToAngle(value);
243:
244: Arc2D arc = new Arc2D.Double(arcRect, angle, 0, Arc2D.OPEN);
245: Point2D pt = arc.getEndPoint();
246:
247: Line2D line = new Line2D.Double(frame.getCenterX(), frame
248: .getCenterY(), pt.getX(), pt.getY());
249: g2.draw(line);
250: }
251:
252: }
253:
254: /**
255: * A dial pointer.
256: */
257: public static class Pointer extends DialPointer implements
258: PublicCloneable {
259:
260: /**
261: * The radius that defines the width of the pointer at the base.
262: */
263: private double widthRadius;
264:
265: /**
266: * Creates a new instance.
267: */
268: public Pointer() {
269: this (0);
270: }
271:
272: /**
273: * Creates a new instance.
274: *
275: * @param datasetIndex the dataset index.
276: */
277: public Pointer(int datasetIndex) {
278: super (datasetIndex);
279: this .radius = 0.9;
280: this .widthRadius = 0.05;
281: }
282:
283: /**
284: * Returns the width radius.
285: *
286: * @return The width radius.
287: */
288: public double getWidthRadius() {
289: return this .widthRadius;
290: }
291:
292: /**
293: * Sets the width radius.
294: *
295: * @param radius the radius.
296: */
297: public void setWidthRadius(double radius) {
298: this .widthRadius = radius;
299: notifyListeners(new DialLayerChangeEvent(this ));
300: }
301:
302: /**
303: * Draws the pointer.
304: *
305: * @param g2 the graphics target.
306: * @param plot the plot.
307: * @param frame the dial's reference frame.
308: * @param view the dial's view.
309: */
310: public void draw(Graphics2D g2, DialPlot plot,
311: Rectangle2D frame, Rectangle2D view) {
312:
313: g2.setPaint(Color.blue);
314: g2.setStroke(new BasicStroke(1.0f));
315: Rectangle2D lengthRect = DialPlot.rectangleByRadius(frame,
316: this .radius, this .radius);
317: Rectangle2D widthRect = DialPlot.rectangleByRadius(frame,
318: this .widthRadius, this .widthRadius);
319: double value = plot.getValue(this .datasetIndex);
320: DialScale scale = plot
321: .getScaleForDataset(this .datasetIndex);
322: double angle = scale.valueToAngle(value);
323:
324: Arc2D arc1 = new Arc2D.Double(lengthRect, angle, 0,
325: Arc2D.OPEN);
326: Point2D pt1 = arc1.getEndPoint();
327: Arc2D arc2 = new Arc2D.Double(widthRect, angle - 90.0,
328: 180.0, Arc2D.OPEN);
329: Point2D pt2 = arc2.getStartPoint();
330: Point2D pt3 = arc2.getEndPoint();
331: Arc2D arc3 = new Arc2D.Double(widthRect, angle - 180.0,
332: 0.0, Arc2D.OPEN);
333: Point2D pt4 = arc3.getStartPoint();
334:
335: GeneralPath gp = new GeneralPath();
336: gp.moveTo((float) pt1.getX(), (float) pt1.getY());
337: gp.lineTo((float) pt2.getX(), (float) pt2.getY());
338: gp.lineTo((float) pt4.getX(), (float) pt4.getY());
339: gp.lineTo((float) pt3.getX(), (float) pt3.getY());
340: gp.closePath();
341: g2.setPaint(Color.gray);
342: g2.fill(gp);
343:
344: g2.setPaint(Color.black);
345: Line2D line = new Line2D.Double(frame.getCenterX(), frame
346: .getCenterY(), pt1.getX(), pt1.getY());
347: g2.draw(line);
348:
349: line.setLine(pt2, pt3);
350: g2.draw(line);
351:
352: line.setLine(pt3, pt1);
353: g2.draw(line);
354:
355: line.setLine(pt2, pt1);
356: g2.draw(line);
357:
358: line.setLine(pt2, pt4);
359: g2.draw(line);
360:
361: line.setLine(pt3, pt4);
362: g2.draw(line);
363: }
364:
365: }
366:
367: }
|