KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jfree > chart > renderer > LineAndShapeRenderer


1 /* ======================================
2  * JFreeChart : a free Java chart library
3  * ======================================
4  *
5  * Project Info: http://www.jfree.org/jfreechart/index.html
6  * Project Lead: David Gilbert (david.gilbert@object-refinery.com);
7  *
8  * (C) Copyright 2000-2003, by Object Refinery Limited and Contributors.
9  *
10  * This library is free software; you can redistribute it and/or modify it under the terms
11  * of the GNU Lesser General Public License as published by the Free Software Foundation;
12  * either version 2.1 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
15  * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16  * See the GNU Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public License along with this
19  * library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
20  * Boston, MA 02111-1307, USA.
21  *
22  * -------------------------
23  * LineAndShapeRenderer.java
24  * -------------------------
25  * (C) Copyright 2001-2003, by Object Refinery Limited and Contributors.
26  *
27  * Original Author: David Gilbert (for Object Refinery Limited);
28  * Contributor(s): Mark Watson (www.markwatson.com);
29  * Jeremy Bowman;
30  * Richard Atkinson;
31  * Christian W. Zuckschwerdt;
32  *
33  * $Id: LineAndShapeRenderer.java,v 1.23 2003/11/03 14:21:27 mungady Exp $
34  *
35  * Changes
36  * -------
37  * 23-Oct-2001 : Version 1 (DG);
38  * 15-Nov-2001 : Modified to allow for null data values (DG);
39  * 16-Jan-2002 : Renamed HorizontalCategoryItemRenderer.java --> CategoryItemRenderer.java (DG);
40  * 05-Feb-2002 : Changed return type of the drawCategoryItem method from void to Shape, as part
41  * of the tooltips implementation (DG);
42  * 11-May-2002 : Support for value label drawing (JB);
43  * 29-May-2002 : Now extends AbstractCategoryItemRenderer (DG);
44  * 25-Jun-2002 : Removed redundant import (DG);
45  * 05-Aug-2002 : Small modification to drawCategoryItem method to support URLs for
46  * HTML image maps (RA);
47  * 26-Sep-2002 : Fixed errors reported by Checkstyle (DG);
48  * 11-Oct-2002 : Added new constructor to incorporate tool tip and URL generators (DG);
49  * 24-Oct-2002 : Amendments for changes in CategoryDataset interface and CategoryToolTipGenerator
50  * interface (DG);
51  * 05-Nov-2002 : Base dataset is now TableDataset not CategoryDataset (DG);
52  * 06-Nov-2002 : Renamed drawCategoryItem(...) --> drawItem(...) and now using axis for
53  * category spacing (DG);
54  * 17-Jan-2003 : Moved plot classes to a separate package (DG);
55  * 10-Apr-2003 : Changed CategoryDataset to KeyedValues2DDataset in drawItem(...) method (DG);
56  * 12-May-2003 : Modified to take into account the plot orientation (DG);
57  * 29-Jul-2003 : Amended code that doesn't compile with JDK 1.2.2 (DG);
58  * 30-Jul-2003 : Modified entity constructor (CZ);
59  * 22-Sep-2003 : Fixed cloning (DG);
60  *
61  */

62
63 package org.jfree.chart.renderer;
64
65 import java.awt.Graphics2D JavaDoc;
66 import java.awt.Shape JavaDoc;
67 import java.awt.geom.Line2D JavaDoc;
68 import java.awt.geom.Rectangle2D JavaDoc;
69 import java.io.Serializable JavaDoc;
70
71 import org.jfree.chart.axis.CategoryAxis;
72 import org.jfree.chart.axis.ValueAxis;
73 import org.jfree.chart.entity.CategoryItemEntity;
74 import org.jfree.chart.entity.EntityCollection;
75 import org.jfree.chart.labels.CategoryItemLabelGenerator;
76 import org.jfree.chart.plot.CategoryPlot;
77 import org.jfree.chart.plot.PlotOrientation;
78 import org.jfree.data.CategoryDataset;
79 import org.jfree.util.BooleanList;
80 import org.jfree.util.ObjectUtils;
81 import org.jfree.util.PublicCloneable;
82
83 /**
84  * A renderer that draws shapes for each data item, and lines between data items.
85  * <p>
86  * For use with the {@link CategoryPlot} class.
87  *
88  * @author David Gilbert
89  */

90 public class LineAndShapeRenderer extends AbstractCategoryItemRenderer
91                                   implements Cloneable JavaDoc, PublicCloneable, Serializable JavaDoc {
92
93     /** Useful constant for specifying the type of rendering (shapes only). */
94     public static final int SHAPES = 1;
95
96     /** Useful constant for specifying the type of rendering (lines only). */
97     public static final int LINES = 2;
98
99     /** Useful constant for specifying the type of rendering (shapes and lines). */
100     public static final int SHAPES_AND_LINES = 3;
101
102     /** Constant indicating that labels are to be shown above data points */
103     public static final int TOP = 1;
104
105     /** Constant indicating that labels are to be shown below data points */
106     public static final int BOTTOM = 2;
107
108     /** Constant indicating that labels are to be shown left of data points */
109     public static final int LEFT = 3;
110
111     /** Constant indicating that labels are to be shown right of data points */
112     public static final int RIGHT = 4;
113
114     /** A flag indicating whether or not shapes are drawn at each XY point. */
115     private boolean drawShapes;
116
117     /** A flag indicating whether or not lines are drawn between XY points. */
118     private boolean drawLines;
119
120     /** A flag that controls whether or not shapes are filled for ALL series. */
121     private Boolean JavaDoc shapesFilled;
122     
123     /** A table of flags that control (per series) whether or not shapes are filled. */
124     private BooleanList seriesShapesFilled;
125     
126     /** The default value returned by the getShapeFilled(...) method. */
127     private Boolean JavaDoc defaultShapesFilled;
128
129     /**
130      * Constructs a default renderer (draws shapes and lines).
131      */

132     public LineAndShapeRenderer() {
133         this(SHAPES_AND_LINES);
134     }
135
136     /**
137      * Constructs a renderer of the specified type.
138      * <P>
139      * Use one of the constants SHAPES, LINES or SHAPES_AND_LINES.
140      *
141      * @param type the type of renderer.
142      *
143      */

144     public LineAndShapeRenderer(int type) {
145         super();
146         if (type == SHAPES) {
147             this.drawShapes = true;
148         }
149         if (type == LINES) {
150             this.drawLines = true;
151         }
152         if (type == SHAPES_AND_LINES) {
153             this.drawShapes = true;
154             this.drawLines = true;
155         }
156
157         this.shapesFilled = null;
158         this.seriesShapesFilled = new BooleanList();
159         this.defaultShapesFilled = Boolean.TRUE;
160     }
161
162     /**
163      * Returns <code>true</code> if a shape should be drawn to represent each data point, and
164      * <code>false</code> otherwise.
165      *
166      * @return A boolean flag.
167      */

168     public boolean isDrawShapes() {
169         return this.drawShapes;
170     }
171
172     /**
173      * Sets the flag that controls whether or not a shape should be drawn to represent each data
174      * point.
175      *
176      * @param draw the new value of the flag.
177      */

178     public void setDrawShapes(boolean draw) {
179         if (draw != this.drawShapes) {
180             this.drawShapes = draw;
181             this.firePropertyChanged("Shapes", new Boolean JavaDoc (!draw), new Boolean JavaDoc (draw));
182         }
183     }
184
185     /**
186      * Returns <code>true</code> if a line should be drawn from the previous to the current data
187      * point, and <code>false</code> otherwise.
188      *
189      * @return A boolean flag.
190      */

191     public boolean isDrawLines() {
192         return this.drawLines;
193     }
194
195     /**
196      * Sets the flag that controls whether or not lines are drawn between consecutive data points.
197      *
198      * @param draw the new value of the flag.
199      */

200     public void setDrawLines(boolean draw) {
201         if (draw != this.drawLines) {
202             this.drawLines = draw;
203             this.firePropertyChanged("Lines", new Boolean JavaDoc (!draw), new Boolean JavaDoc (draw));
204         }
205     }
206
207     // SHAPES FILLED
208

209     /**
210      * Returns the flag used to control whether or not the shape for an item is filled.
211      * <p>
212      * The default implementation passes control to the <code>getSeriesShapesFilled</code> method.
213      * You can override this method if you require different behaviour.
214      *
215      * @param series the series index (zero-based).
216      * @param item the item index (zero-based).
217      *
218      * @return A boolean.
219      */

220     public boolean getItemShapeFilled(int series, int item) {
221         return getSeriesShapesFilled(series);
222     }
223
224     /**
225      * Returns the flag used to control whether or not the shapes for a series are filled.
226      *
227      * @param series the series index (zero-based).
228      *
229      * @return A boolean.
230      */

231     public boolean getSeriesShapesFilled(int series) {
232
233         // return the overall setting, if there is one...
234
if (this.shapesFilled != null) {
235             return this.shapesFilled.booleanValue();
236         }
237
238         // otherwise look up the paint table
239
Boolean JavaDoc flag = this.seriesShapesFilled.getBoolean(series);
240         if (flag != null) {
241             return flag.booleanValue();
242         }
243         else {
244             return this.defaultShapesFilled.booleanValue();
245         }
246
247     }
248     
249     /**
250      * Returns the flag that controls whether or not shapes are filled for ALL series.
251      *
252      * @return A Boolean.
253      */

254     public Boolean JavaDoc getShapesFilled() {
255         return this.shapesFilled;
256     }
257
258     /**
259      * Sets the 'shapes filled' for ALL series.
260      *
261      * @param filled the flag.
262      */

263     public void setShapesFilled(boolean filled) {
264         if (filled) {
265             setShapesFilled(Boolean.TRUE);
266         }
267         else {
268             setShapesFilled(Boolean.FALSE);
269         }
270     }
271     
272     /**
273      * Sets the 'shapes filled' for ALL series.
274      *
275      * @param filled the flag (<code>null</code> permitted).
276      */

277     public void setShapesFilled(Boolean JavaDoc filled) {
278         this.shapesFilled = filled;
279     }
280     
281     /**
282      * Sets the 'shapes filled' flag for a series.
283      *
284      * @param series the series index (zero-based).
285      * @param filled the flag.
286      */

287     public void setSeriesShapesFilled(int series, Boolean JavaDoc filled) {
288         this.seriesShapesFilled.setBoolean(series, filled);
289     }
290
291     /**
292      * Sets the 'shapes filled' flag for a series.
293      *
294      * @param series the series index (zero-based).
295      * @param filled the flag.
296      */

297     public void setSeriesShapesFilled(int series, boolean filled) {
298         this.seriesShapesFilled.setBoolean(series, new Boolean JavaDoc(filled));
299     }
300
301     /**
302      * Returns the default 'shape filled' attribute.
303      *
304      * @return The default flag.
305      */

306     public Boolean JavaDoc getDefaultShapesFilled() {
307         return this.defaultShapesFilled;
308     }
309
310     /**
311      * Sets the default 'shapes filled' flag.
312      *
313      * @param flag the flag.
314      */

315     public void setDefaultShapesFilled(Boolean JavaDoc flag) {
316         this.defaultShapesFilled = flag;
317     }
318     
319     /**
320      * Sets the default 'shapes filled' flag.
321      *
322      * @param flag the flag.
323      */

324     public void setDefaultShapesFilled(boolean flag) {
325         setDefaultShapesFilled(new Boolean JavaDoc(flag));
326     }
327
328     /**
329      * Draw a single data item.
330      *
331      * @param g2 the graphics device.
332      * @param state the renderer state.
333      * @param dataArea the area in which the data is drawn.
334      * @param plot the plot.
335      * @param domainAxis the domain axis.
336      * @param rangeAxis the range axis.
337      * @param dataset the dataset.
338      * @param row the row index (zero-based).
339      * @param column the column index (zero-based).
340      */

341     public void drawItem(Graphics2D JavaDoc g2,
342                          CategoryItemRendererState state,
343                          Rectangle2D JavaDoc dataArea,
344                          CategoryPlot plot,
345                          CategoryAxis domainAxis,
346                          ValueAxis rangeAxis,
347                          CategoryDataset dataset,
348                          int row,
349                          int column) {
350
351         // nothing is drawn for null...
352
Number JavaDoc value = dataset.getValue(row, column);
353         if (value == null) {
354             return;
355         }
356
357         PlotOrientation orientation = plot.getOrientation();
358
359         // current data point...
360
double x1 = domainAxis.getCategoryMiddle(column, getColumnCount(), dataArea,
361                                                  plot.getDomainAxisEdge());
362         double y1 = rangeAxis.translateValueToJava2D(value.doubleValue(), dataArea,
363                                                      plot.getRangeAxisEdge());
364
365         g2.setPaint(getItemPaint(row, column));
366         g2.setStroke(getItemStroke(row, column));
367
368         Shape JavaDoc shape = getItemShape(row, column);
369         if (orientation == PlotOrientation.HORIZONTAL) {
370             shape = createTransformedShape(shape, y1, x1);
371         }
372         else if (orientation == PlotOrientation.VERTICAL) {
373             shape = createTransformedShape(shape, x1, y1);
374         }
375         if (this.drawShapes) {
376             
377             if (getItemShapeFilled(row, column)) {
378                 g2.fill(shape);
379             }
380             else {
381                 g2.draw(shape);
382             }
383         }
384
385         if (this.drawLines) {
386             if (column != 0) {
387
388                 Number JavaDoc previousValue = dataset.getValue(row, column - 1);
389                 if (previousValue != null) {
390
391                     // previous data point...
392
double previous = previousValue.doubleValue();
393                     double x0 = domainAxis.getCategoryMiddle(column - 1,
394                                                              getColumnCount(), dataArea,
395                                                              plot.getDomainAxisEdge());
396                     double y0 = rangeAxis.translateValueToJava2D(previous, dataArea,
397                                                                  plot.getRangeAxisEdge());
398
399                     g2.setPaint(getItemPaint(row, column));
400                     g2.setStroke(getItemStroke(row, column));
401                     Line2D JavaDoc line = null;
402                     if (orientation == PlotOrientation.HORIZONTAL) {
403                         line = new Line2D.Double JavaDoc(y0, x0, y1, x1);
404                     }
405                     else if (orientation == PlotOrientation.VERTICAL) {
406                         line = new Line2D.Double JavaDoc(x0, y0, x1, y1);
407                     }
408                     g2.draw(line);
409                 }
410             }
411         }
412
413         // draw the item labels if there are any...
414
if (isItemLabelVisible(row, column)) {
415             drawItemLabel(g2, orientation,
416                           dataset, row, column, x1, y1, (value.doubleValue() < 0.0));
417         }
418
419         // collect entity and tool tip information...
420
if (state.getInfo() != null) {
421             EntityCollection entities = state.getInfo().getOwner().getEntityCollection();
422             if (entities != null && shape != null) {
423                 String JavaDoc tip = null;
424                 CategoryItemLabelGenerator generator = getItemLabelGenerator(row, column);
425                 if (generator != null) {
426                     tip = generator.generateToolTip(dataset, row, column);
427                 }
428                 String JavaDoc url = null;
429                 if (getItemURLGenerator(row, column) != null) {
430                     url = getItemURLGenerator(row, column).generateURL(dataset, row, column);
431                 }
432                 CategoryItemEntity entity = new CategoryItemEntity(
433                     shape, tip, url, dataset, row, dataset.getColumnKey(column), column
434                 );
435                 entities.addEntity(entity);
436
437             }
438
439         }
440
441     }
442     
443     /**
444      * Tests this renderer for equality with another object.
445      *
446      * @param obj the object.
447      *
448      * @return <code>true</code> or <code>false</code>.
449      */

450     public boolean equals(Object JavaDoc obj) {
451
452         boolean result = super.equals(obj);
453
454         if (obj instanceof LineAndShapeRenderer) {
455             LineAndShapeRenderer r = (LineAndShapeRenderer) obj;
456             boolean b0 = (r.drawLines == this.drawLines);
457             boolean b1 = (r.drawShapes == this.drawShapes);
458             boolean b2 = ObjectUtils.equal(r.shapesFilled, this.shapesFilled);
459             boolean b3 = ObjectUtils.equal(r.seriesShapesFilled, this.seriesShapesFilled);
460             boolean b4 = ObjectUtils.equal(r.defaultShapesFilled, this.defaultShapesFilled);
461     
462             result = result && b0 && b1 && b2 && b3 && b4;
463         }
464
465         return result;
466
467     }
468
469     /**
470      * Returns an independent copy of the renderer.
471      *
472      * @return A clone.
473      *
474      * @throws CloneNotSupportedException should not happen.
475      */

476     public Object JavaDoc clone() throws CloneNotSupportedException JavaDoc {
477         LineAndShapeRenderer clone = (LineAndShapeRenderer) super.clone();
478         clone.seriesShapesFilled = (BooleanList) this.seriesShapesFilled.clone();
479         return clone;
480     }
481 }
482
Popular Tags