KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jfree > chart > renderer > category > MinMaxCategoryRenderer


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
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
22  * USA.
23  *
24  * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
25  * in the United States and other countries.]
26  *
27  * ---------------------------
28  * MinMaxCategoryRenderer.java
29  * ---------------------------
30  * (C) Copyright 2002-2005, by Object Refinery Limited.
31  *
32  * Original Author: Tomer Peretz;
33  * Contributor(s): David Gilbert (for Object Refinery Limited);
34  * Christian W. Zuckschwerdt;
35  * Nicolas Brodu (for Astrium and EADS Corporate Research
36  * Center);
37  *
38  * $Id: MinMaxCategoryRenderer.java,v 1.6.2.5 2005/12/02 10:05:57 mungady Exp $
39  *
40  * Changes:
41  * --------
42  * 29-May-2002 : Version 1 (TP);
43  * 02-Oct-2002 : Fixed errors reported by Checkstyle (DG);
44  * 24-Oct-2002 : Amendments for changes in CategoryDataset interface and
45  * CategoryToolTipGenerator interface (DG);
46  * 05-Nov-2002 : Base dataset is now TableDataset not CategoryDataset (DG);
47  * 17-Jan-2003 : Moved plot classes to a separate package (DG);
48  * 10-Apr-2003 : Changed CategoryDataset to KeyedValues2DDataset in drawItem()
49  * method (DG);
50  * 30-Jul-2003 : Modified entity constructor (CZ);
51  * 08-Sep-2003 : Implemented Serializable (NB);
52  * 29-Oct-2003 : Added workaround for font alignment in PDF output (DG);
53  * 05-Nov-2004 : Modified drawItem() signature (DG);
54  * 17-Nov-2005 : Added change events and argument checks (DG);
55  *
56  */

57
58 package org.jfree.chart.renderer.category;
59
60 import java.awt.BasicStroke JavaDoc;
61 import java.awt.Color JavaDoc;
62 import java.awt.Component JavaDoc;
63 import java.awt.Graphics JavaDoc;
64 import java.awt.Graphics2D JavaDoc;
65 import java.awt.Paint JavaDoc;
66 import java.awt.Shape JavaDoc;
67 import java.awt.Stroke JavaDoc;
68 import java.awt.geom.AffineTransform JavaDoc;
69 import java.awt.geom.Arc2D JavaDoc;
70 import java.awt.geom.GeneralPath JavaDoc;
71 import java.awt.geom.Line2D JavaDoc;
72 import java.awt.geom.Rectangle2D JavaDoc;
73 import java.io.IOException JavaDoc;
74 import java.io.ObjectInputStream JavaDoc;
75 import java.io.ObjectOutputStream JavaDoc;
76
77 import javax.swing.Icon JavaDoc;
78
79 import org.jfree.chart.axis.CategoryAxis;
80 import org.jfree.chart.axis.ValueAxis;
81 import org.jfree.chart.entity.CategoryItemEntity;
82 import org.jfree.chart.entity.EntityCollection;
83 import org.jfree.chart.event.RendererChangeEvent;
84 import org.jfree.chart.labels.CategoryToolTipGenerator;
85 import org.jfree.chart.plot.CategoryPlot;
86 import org.jfree.data.category.CategoryDataset;
87 import org.jfree.io.SerialUtilities;
88
89 /**
90  * Renderer for drawing min max plot. This renderer draws all the series under
91  * the same category in the same x position using <code>objectIcon</code> and
92  * a line from the maximum value to the minimum value.
93  * <p>
94  * For use with the {@link org.jfree.chart.plot.CategoryPlot} class.
95  *
96  * @author Tomer Peretz
97  */

98 public class MinMaxCategoryRenderer extends AbstractCategoryItemRenderer {
99
100     /** For serialization. */
101     private static final long serialVersionUID = 2935615937671064911L;
102     
103     /** A flag indicating whether or not lines are drawn between XY points. */
104     private boolean plotLines = false;
105
106     /**
107      * The paint of the line between the minimum value and the maximum value.
108      */

109     private transient Paint JavaDoc groupPaint = Color.black;
110
111     /**
112      * The stroke of the line between the minimum value and the maximum value.
113      */

114     private transient Stroke JavaDoc groupStroke = new BasicStroke JavaDoc(1.0f);
115
116     /** The icon used to indicate the minimum value.*/
117     private transient Icon JavaDoc minIcon = getIcon(new Arc2D.Double JavaDoc(-4, -4, 8, 8, 0,
118             360, Arc2D.OPEN), null, Color.black);
119
120     /** The icon used to indicate the maximum value.*/
121     private transient Icon JavaDoc maxIcon = getIcon(new Arc2D.Double JavaDoc(-4, -4, 8, 8, 0,
122             360, Arc2D.OPEN), null, Color.black);
123
124     /** The icon used to indicate the values.*/
125     private transient Icon JavaDoc objectIcon = getIcon(new Line2D.Double JavaDoc(-4, 0, 4, 0),
126             false, true);
127
128     /** The last category. */
129     private int lastCategory = -1;
130
131     /** The minimum. */
132     private double min;
133
134     /** The maximum. */
135     private double max;
136
137     /**
138      * Default constructor.
139      */

140     public MinMaxCategoryRenderer() {
141         super();
142     }
143
144     /**
145      * Gets whether or not lines are drawn between category points.
146      *
147      * @return boolean true if line will be drawn between sequenced categories,
148      * otherwise false.
149      *
150      * @see #setDrawLines(boolean)
151      */

152     public boolean isDrawLines() {
153         return this.plotLines;
154     }
155
156     /**
157      * Sets the flag that controls whether or not lines are drawn to connect
158      * the items within a series and sends a {@link RendererChangeEvent} to
159      * all registered listeners.
160      *
161      * @param draw the new value of the flag.
162      *
163      * @see #isDrawLines()
164      */

165     public void setDrawLines(boolean draw) {
166         if (this.plotLines != draw) {
167             this.plotLines = draw;
168             this.notifyListeners(new RendererChangeEvent(this));
169         }
170         
171     }
172
173     /**
174      * Returns the paint used to draw the line between the minimum and maximum
175      * value items in each category.
176      *
177      * @return The paint (never <code>null</code>).
178      *
179      * @see #setGroupPaint(Paint)
180      */

181     public Paint JavaDoc getGroupPaint() {
182         return this.groupPaint;
183     }
184
185     /**
186      * Sets the paint used to draw the line between the minimum and maximum
187      * value items in each category and sends a {@link RendererChangeEvent} to
188      * all registered listeners.
189      *
190      * @param paint the paint (<code>null</code> not permitted).
191      *
192      * @see #getGroupPaint()
193      */

194     public void setGroupPaint(Paint JavaDoc paint) {
195         if (paint == null) {
196             throw new IllegalArgumentException JavaDoc("Null 'paint' argument.");
197         }
198         this.groupPaint = paint;
199         notifyListeners(new RendererChangeEvent(this));
200     }
201
202     /**
203      * Returns the stroke used to draw the line between the minimum and maximum
204      * value items in each category.
205      *
206      * @return The stroke (never <code>null</code>).
207      *
208      * @see #setGroupStroke(Stroke)
209      */

210     public Stroke JavaDoc getGroupStroke() {
211         return this.groupStroke;
212     }
213
214     /**
215      * Sets the stroke of the line between the minimum value and the maximum
216      * value.
217      *
218      * @param groupStroke The new stroke
219      */

220     public void setGroupStroke(Stroke JavaDoc groupStroke) {
221         this.groupStroke = groupStroke;
222     }
223
224     /**
225      * Returns the icon drawn for each data item.
226      *
227      * @return The icon (never <code>null</code>).
228      *
229      * @see #setObjectIcon(Icon)
230      */

231     public Icon JavaDoc getObjectIcon() {
232         return this.objectIcon;
233     }
234
235     /**
236      * Sets the icon drawn for each data item.
237      *
238      * @param icon the icon.
239      *
240      * @see #getObjectIcon()
241      */

242     public void setObjectIcon(Icon JavaDoc icon) {
243         if (icon == null) {
244             throw new IllegalArgumentException JavaDoc("Null 'icon' argument.");
245         }
246         this.objectIcon = icon;
247         notifyListeners(new RendererChangeEvent(this));
248     }
249
250     /**
251      * Returns the icon displayed for the maximum value data item within each
252      * category.
253      *
254      * @return The icon (never <code>null</code>).
255      *
256      * @see #setMaxIcon(Icon)
257      */

258     public Icon JavaDoc getMaxIcon() {
259         return this.maxIcon;
260     }
261
262     /**
263      * Sets the icon displayed for the maximum value data item within each
264      * category and sends a {@link RendererChangeEvent} to all registered
265      * listeners.
266      *
267      * @param icon the icon (<code>null</code> not permitted).
268      *
269      * @see #getMaxIcon()
270      */

271     public void setMaxIcon(Icon JavaDoc icon) {
272         if (icon == null) {
273             throw new IllegalArgumentException JavaDoc("Null 'icon' argument.");
274         }
275         this.maxIcon = icon;
276         notifyListeners(new RendererChangeEvent(this));
277     }
278
279     /**
280      * Returns the icon displayed for the minimum value data item within each
281      * category.
282      *
283      * @return The icon (never <code>null</code>).
284      *
285      * @see #setMinIcon(Icon)
286      */

287     public Icon JavaDoc getMinIcon() {
288         return this.minIcon;
289     }
290
291     /**
292      * Sets the icon displayed for the minimum value data item within each
293      * category and sends a {@link RendererChangeEvent} to all registered
294      * listeners.
295      *
296      * @param icon the icon (<code>null</code> not permitted).
297      *
298      * @see #getMinIcon()
299      */

300     public void setMinIcon(Icon JavaDoc icon) {
301         if (icon == null) {
302             throw new IllegalArgumentException JavaDoc("Null 'icon' argument.");
303         }
304         this.minIcon = icon;
305         notifyListeners(new RendererChangeEvent(this));
306     }
307
308     /**
309      * Draw a single data item.
310      *
311      * @param g2 the graphics device.
312      * @param state the renderer state.
313      * @param dataArea the area in which the data is drawn.
314      * @param plot the plot.
315      * @param domainAxis the domain axis.
316      * @param rangeAxis the range axis.
317      * @param dataset the dataset.
318      * @param row the row index (zero-based).
319      * @param column the column index (zero-based).
320      * @param pass the pass index.
321      */

322     public void drawItem(Graphics2D JavaDoc g2, CategoryItemRendererState state,
323             Rectangle2D JavaDoc dataArea, CategoryPlot plot, CategoryAxis domainAxis,
324             ValueAxis rangeAxis, CategoryDataset dataset, int row, int column,
325             int pass) {
326
327         // first check the number we are plotting...
328
Number JavaDoc value = dataset.getValue(row, column);
329         if (value != null) {
330             // current data point...
331
double x1 = domainAxis.getCategoryMiddle(
332                 column, getColumnCount(), dataArea, plot.getDomainAxisEdge());
333             double y1 = rangeAxis.valueToJava2D(
334                 value.doubleValue(), dataArea, plot.getRangeAxisEdge());
335             g2.setPaint(getItemPaint(row, column));
336             g2.setStroke(getItemStroke(row, column));
337             Shape JavaDoc shape = null;
338             shape = new Rectangle2D.Double JavaDoc(x1 - 4, y1 - 4, 8.0, 8.0);
339             this.objectIcon.paintIcon(null, g2, (int) x1, (int) y1);
340             if (this.lastCategory == column) {
341                 if (this.min > value.doubleValue()) {
342                     this.min = value.doubleValue();
343                 }
344                 if (this.max < value.doubleValue()) {
345                     this.max = value.doubleValue();
346                 }
347                 if (dataset.getRowCount() - 1 == row) {
348                     g2.setPaint(this.groupPaint);
349                     g2.setStroke(this.groupStroke);
350                     double minY = rangeAxis.valueToJava2D(this.min, dataArea,
351                             plot.getRangeAxisEdge());
352                     double maxY = rangeAxis.valueToJava2D(this.max, dataArea,
353                             plot.getRangeAxisEdge());
354                     g2.draw(new Line2D.Double JavaDoc(x1, minY, x1, maxY));
355                     this.minIcon.paintIcon(null, g2, (int) x1, (int) minY);
356                     this.maxIcon.paintIcon(null, g2, (int) x1, (int) maxY);
357                 }
358             }
359             else { // reset the min and max
360
this.lastCategory = column;
361                 this.min = value.doubleValue();
362                 this.max = value.doubleValue();
363             }
364             // connect to the previous point
365
if (this.plotLines) {
366                 if (column != 0) {
367                     Number JavaDoc previousValue = dataset.getValue(row, column - 1);
368                     if (previousValue != null) {
369                         // previous data point...
370
double previous = previousValue.doubleValue();
371                         double x0 = domainAxis.getCategoryMiddle(
372                             column - 1, getColumnCount(), dataArea,
373                             plot.getDomainAxisEdge());
374                         double y0 = rangeAxis.valueToJava2D(
375                             previous, dataArea, plot.getRangeAxisEdge());
376                         g2.setPaint(getItemPaint(row, column));
377                         g2.setStroke(getItemStroke(row, column));
378                         Line2D JavaDoc line = new Line2D.Double JavaDoc(x0, y0, x1, y1);
379                         g2.draw(line);
380                     }
381                 }
382             }
383
384             // collect entity and tool tip information...
385
if (state.getInfo() != null) {
386                 EntityCollection entities = state.getEntityCollection();
387                 if (entities != null && shape != null) {
388                     String JavaDoc tip = null;
389                     CategoryToolTipGenerator tipster
390                         = getToolTipGenerator(row, column);
391                     if (tipster != null) {
392                         tip = tipster.generateToolTip(dataset, row, column);
393                     }
394                     CategoryItemEntity entity = new CategoryItemEntity(
395                         shape, tip, null, dataset, row,
396                         dataset.getColumnKey(column), column);
397                     entities.add(entity);
398                 }
399             }
400         }
401     }
402
403     /**
404      * Returns an icon.
405      *
406      * @param shape the shape.
407      * @param fillPaint the fill paint.
408      * @param outlinePaint the outline paint.
409      *
410      * @return The icon.
411      */

412     private Icon JavaDoc getIcon(Shape JavaDoc shape, final Paint JavaDoc fillPaint,
413                         final Paint JavaDoc outlinePaint) {
414
415       final int width = shape.getBounds().width;
416       final int height = shape.getBounds().height;
417       final GeneralPath JavaDoc path = new GeneralPath JavaDoc(shape);
418       return new Icon JavaDoc() {
419           public void paintIcon(Component JavaDoc c, Graphics JavaDoc g, int x, int y) {
420               Graphics2D JavaDoc g2 = (Graphics2D JavaDoc) g;
421               path.transform(AffineTransform.getTranslateInstance(x, y));
422               if (fillPaint != null) {
423                   g2.setPaint(fillPaint);
424                   g2.fill(path);
425               }
426               if (outlinePaint != null) {
427                   g2.setPaint(outlinePaint);
428                   g2.draw(path);
429               }
430               path.transform(AffineTransform.getTranslateInstance(-x, -y));
431         }
432
433         public int getIconWidth() {
434             return width;
435         }
436
437         public int getIconHeight() {
438             return height;
439         }
440
441       };
442     }
443
444     /**
445      * Returns an icon.
446      *
447      * @param shape the shape.
448      * @param fill the fill flag.
449      * @param outline the outline flag.
450      *
451      * @return The icon.
452      */

453     private Icon JavaDoc getIcon(Shape JavaDoc shape, final boolean fill,
454                          final boolean outline) {
455         final int width = shape.getBounds().width;
456         final int height = shape.getBounds().height;
457         final GeneralPath JavaDoc path = new GeneralPath JavaDoc(shape);
458         return new Icon JavaDoc() {
459             public void paintIcon(Component JavaDoc c, Graphics JavaDoc g, int x, int y) {
460                 Graphics2D JavaDoc g2 = (Graphics2D JavaDoc) g;
461                 path.transform(AffineTransform.getTranslateInstance(x, y));
462                 if (fill) {
463                     g2.fill(path);
464                 }
465                 if (outline) {
466                     g2.draw(path);
467                 }
468                 path.transform(AffineTransform.getTranslateInstance(-x, -y));
469             }
470
471             public int getIconWidth() {
472                 return width;
473             }
474
475             public int getIconHeight() {
476                 return height;
477             }
478         };
479     }
480     
481     /**
482      * Provides serialization support.
483      *
484      * @param stream the output stream.
485      *
486      * @throws IOException if there is an I/O error.
487      */

488     private void writeObject(ObjectOutputStream JavaDoc stream) throws IOException JavaDoc {
489         stream.defaultWriteObject();
490         SerialUtilities.writeStroke(this.groupStroke, stream);
491         SerialUtilities.writePaint(this.groupPaint, stream);
492     }
493     
494     /**
495      * Provides serialization support.
496      *
497      * @param stream the input stream.
498      *
499      * @throws IOException if there is an I/O error.
500      * @throws ClassNotFoundException if there is a classpath problem.
501      */

502     private void readObject(ObjectInputStream JavaDoc stream)
503         throws IOException JavaDoc, ClassNotFoundException JavaDoc {
504         stream.defaultReadObject();
505         this.groupStroke = SerialUtilities.readStroke(stream);
506         this.groupPaint = SerialUtilities.readPaint(stream);
507           
508         this.minIcon = getIcon(
509             new Arc2D.Double JavaDoc(-4, -4, 8, 8, 0, 360, Arc2D.OPEN), null,
510             Color.black);
511         this.maxIcon = getIcon(
512             new Arc2D.Double JavaDoc(-4, -4, 8, 8, 0, 360, Arc2D.OPEN), null,
513             Color.black);
514         this.objectIcon = getIcon(new Line2D.Double JavaDoc(-4, 0, 4, 0), false, true);
515     }
516     
517 }
518
Popular Tags