KickJava   Java API By Example, From Geeks To Geeks.

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


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  * GroupedStackedBarRenderer.java
29  * ------------------------------
30  * (C) Copyright 2004, 2005, by Object Refinery Limited and Contributors.
31  *
32  * Original Author: David Gilbert (for Object Refinery Limited);
33  * Contributor(s): -;
34  *
35  * $Id: GroupedStackedBarRenderer.java,v 1.7.2.3 2005/12/01 20:16:57 mungady Exp $
36  *
37  * Changes
38  * -------
39  * 29-Apr-2004 : Version 1 (DG);
40  * 08-Jul-2004 : Added equals() method (DG);
41  * 05-Nov-2004 : Modified drawItem() signature (DG);
42  * 07-Jan-2005 : Renamed getRangeExtent() --> findRangeBounds (DG);
43  * 20-Apr-2005 : Renamed CategoryLabelGenerator
44  * --> CategoryItemLabelGenerator (DG);
45  * 22-Sep-2005 : Renamed getMaxBarWidth() --> getMaximumBarWidth() (DG);
46  *
47  */

48  
49 package org.jfree.chart.renderer.category;
50
51 import java.awt.GradientPaint JavaDoc;
52 import java.awt.Graphics2D JavaDoc;
53 import java.awt.Paint JavaDoc;
54 import java.awt.geom.Rectangle2D JavaDoc;
55 import java.io.Serializable JavaDoc;
56
57 import org.jfree.chart.axis.CategoryAxis;
58 import org.jfree.chart.axis.ValueAxis;
59 import org.jfree.chart.entity.CategoryItemEntity;
60 import org.jfree.chart.entity.EntityCollection;
61 import org.jfree.chart.event.RendererChangeEvent;
62 import org.jfree.chart.labels.CategoryItemLabelGenerator;
63 import org.jfree.chart.labels.CategoryToolTipGenerator;
64 import org.jfree.chart.plot.CategoryPlot;
65 import org.jfree.chart.plot.PlotOrientation;
66 import org.jfree.data.KeyToGroupMap;
67 import org.jfree.data.Range;
68 import org.jfree.data.category.CategoryDataset;
69 import org.jfree.data.general.DatasetUtilities;
70 import org.jfree.ui.RectangleEdge;
71 import org.jfree.util.PublicCloneable;
72
73 /**
74  * A renderer that draws stacked bars within groups. This will probably be
75  * merged with the {@link StackedBarRenderer} class at some point.
76  */

77 public class GroupedStackedBarRenderer extends StackedBarRenderer
78                                        implements Cloneable JavaDoc, PublicCloneable,
79                                                   Serializable JavaDoc {
80             
81     /** For serialization. */
82     private static final long serialVersionUID = -2725921399005922939L;
83     
84     /** A map used to assign each series to a group. */
85     private KeyToGroupMap seriesToGroupMap;
86     
87     /**
88      * Creates a new renderer.
89      */

90     public GroupedStackedBarRenderer() {
91         super();
92         this.seriesToGroupMap = new KeyToGroupMap();
93     }
94     
95     /**
96      * Updates the map used to assign each series to a group.
97      *
98      * @param map the map (<code>null</code> not permitted).
99      */

100     public void setSeriesToGroupMap(KeyToGroupMap map) {
101         if (map == null) {
102             throw new IllegalArgumentException JavaDoc("Null 'map' argument.");
103         }
104         this.seriesToGroupMap = map;
105         notifyListeners(new RendererChangeEvent(this));
106     }
107     
108     /**
109      * Returns the range of values the renderer requires to display all the
110      * items from the specified dataset.
111      *
112      * @param dataset the dataset (<code>null</code> permitted).
113      *
114      * @return The range (or <code>null</code> if the dataset is
115      * <code>null</code> or empty).
116      */

117     public Range findRangeBounds(CategoryDataset dataset) {
118         Range r = DatasetUtilities.findStackedRangeBounds(
119             dataset, this.seriesToGroupMap
120         );
121         return r;
122     }
123
124     /**
125      * Calculates the bar width and stores it in the renderer state. We
126      * override the method in the base class to take account of the
127      * series-to-group mapping.
128      *
129      * @param plot the plot.
130      * @param dataArea the data area.
131      * @param rendererIndex the renderer index.
132      * @param state the renderer state.
133      */

134     protected void calculateBarWidth(CategoryPlot plot,
135                                      Rectangle2D JavaDoc dataArea,
136                                      int rendererIndex,
137                                      CategoryItemRendererState state) {
138
139         // calculate the bar width
140
CategoryAxis xAxis = plot.getDomainAxisForDataset(rendererIndex);
141         CategoryDataset data = plot.getDataset(rendererIndex);
142         if (data != null) {
143             PlotOrientation orientation = plot.getOrientation();
144             double space = 0.0;
145             if (orientation == PlotOrientation.HORIZONTAL) {
146                 space = dataArea.getHeight();
147             }
148             else if (orientation == PlotOrientation.VERTICAL) {
149                 space = dataArea.getWidth();
150             }
151             double maxWidth = space * getMaximumBarWidth();
152             int groups = this.seriesToGroupMap.getGroupCount();
153             int categories = data.getColumnCount();
154             int columns = groups * categories;
155             double categoryMargin = 0.0;
156             double itemMargin = 0.0;
157             if (categories > 1) {
158                 categoryMargin = xAxis.getCategoryMargin();
159             }
160             if (groups > 1) {
161                 itemMargin = getItemMargin();
162             }
163
164             double used = space * (1 - xAxis.getLowerMargin()
165                                      - xAxis.getUpperMargin()
166                                      - categoryMargin - itemMargin);
167             if (columns > 0) {
168                 state.setBarWidth(Math.min(used / columns, maxWidth));
169             }
170             else {
171                 state.setBarWidth(Math.min(used, maxWidth));
172             }
173         }
174
175     }
176
177     /**
178      * Calculates the coordinate of the first "side" of a bar. This will be
179      * the minimum x-coordinate for a vertical bar, and the minimum
180      * y-coordinate for a horizontal bar.
181      *
182      * @param plot the plot.
183      * @param orientation the plot orientation.
184      * @param dataArea the data area.
185      * @param domainAxis the domain axis.
186      * @param state the renderer state (has the bar width precalculated).
187      * @param row the row index.
188      * @param column the column index.
189      *
190      * @return The coordinate.
191      */

192     protected double calculateBarW0(CategoryPlot plot,
193                                     PlotOrientation orientation,
194                                     Rectangle2D JavaDoc dataArea,
195                                     CategoryAxis domainAxis,
196                                     CategoryItemRendererState state,
197                                     int row,
198                                     int column) {
199         // calculate bar width...
200
double space = 0.0;
201         if (orientation == PlotOrientation.HORIZONTAL) {
202             space = dataArea.getHeight();
203         }
204         else {
205             space = dataArea.getWidth();
206         }
207         double barW0 = domainAxis.getCategoryStart(
208             column, getColumnCount(), dataArea, plot.getDomainAxisEdge()
209         );
210         int groupCount = this.seriesToGroupMap.getGroupCount();
211         int groupIndex = this.seriesToGroupMap.getGroupIndex(
212             this.seriesToGroupMap.getGroup(plot.getDataset().getRowKey(row))
213         );
214         int categoryCount = getColumnCount();
215         if (groupCount > 1) {
216             double groupGap = space * getItemMargin()
217                               / (categoryCount * (groupCount - 1));
218             double groupW = calculateSeriesWidth(
219                 space, domainAxis, categoryCount, groupCount
220             );
221             barW0 = barW0 + groupIndex * (groupW + groupGap)
222                           + (groupW / 2.0) - (state.getBarWidth() / 2.0);
223         }
224         else {
225             barW0 = domainAxis.getCategoryMiddle(
226                 column, getColumnCount(), dataArea, plot.getDomainAxisEdge()
227             ) - state.getBarWidth() / 2.0;
228         }
229         return barW0;
230     }
231     
232     /**
233      * Draws a stacked bar for a specific item.
234      *
235      * @param g2 the graphics device.
236      * @param state the renderer state.
237      * @param dataArea the plot area.
238      * @param plot the plot.
239      * @param domainAxis the domain (category) axis.
240      * @param rangeAxis the range (value) axis.
241      * @param dataset the data.
242      * @param row the row index (zero-based).
243      * @param column the column index (zero-based).
244      * @param pass the pass index.
245      */

246     public void drawItem(Graphics2D JavaDoc g2,
247                          CategoryItemRendererState state,
248                          Rectangle2D JavaDoc dataArea,
249                          CategoryPlot plot,
250                          CategoryAxis domainAxis,
251                          ValueAxis rangeAxis,
252                          CategoryDataset dataset,
253                          int row,
254                          int column,
255                          int pass) {
256      
257         // nothing is drawn for null values...
258
Number JavaDoc dataValue = dataset.getValue(row, column);
259         if (dataValue == null) {
260             return;
261         }
262         
263         double value = dataValue.doubleValue();
264         Comparable JavaDoc group
265             = this.seriesToGroupMap.getGroup(dataset.getRowKey(row));
266         PlotOrientation orientation = plot.getOrientation();
267         double barW0 = calculateBarW0(
268             plot, orientation, dataArea, domainAxis,
269             state, row, column
270         );
271
272         double positiveBase = 0.0;
273         double negativeBase = 0.0;
274
275         for (int i = 0; i < row; i++) {
276             if (group.equals(
277                 this.seriesToGroupMap.getGroup(dataset.getRowKey(i))
278             )) {
279                 Number JavaDoc v = dataset.getValue(i, column);
280                 if (v != null) {
281                     double d = v.doubleValue();
282                     if (d > 0) {
283                         positiveBase = positiveBase + d;
284                     }
285                     else {
286                         negativeBase = negativeBase + d;
287                     }
288                 }
289             }
290         }
291
292         double translatedBase;
293         double translatedValue;
294         RectangleEdge location = plot.getRangeAxisEdge();
295         if (value > 0.0) {
296             translatedBase
297                 = rangeAxis.valueToJava2D(positiveBase, dataArea, location);
298             translatedValue = rangeAxis.valueToJava2D(
299                 positiveBase + value, dataArea, location
300             );
301         }
302         else {
303             translatedBase = rangeAxis.valueToJava2D(
304                 negativeBase, dataArea, location
305             );
306             translatedValue = rangeAxis.valueToJava2D(
307                 negativeBase + value, dataArea, location
308             );
309         }
310         double barL0 = Math.min(translatedBase, translatedValue);
311         double barLength = Math.max(
312             Math.abs(translatedValue - translatedBase), getMinimumBarLength()
313         );
314
315         Rectangle2D JavaDoc bar = null;
316         if (orientation == PlotOrientation.HORIZONTAL) {
317             bar = new Rectangle2D.Double JavaDoc(
318                 barL0, barW0, barLength, state.getBarWidth()
319             );
320         }
321         else {
322             bar = new Rectangle2D.Double JavaDoc(
323                 barW0, barL0, state.getBarWidth(), barLength
324             );
325         }
326         Paint JavaDoc itemPaint = getItemPaint(row, column);
327         if (getGradientPaintTransformer() != null
328                 && itemPaint instanceof GradientPaint JavaDoc) {
329             GradientPaint JavaDoc gp = (GradientPaint JavaDoc) itemPaint;
330             itemPaint = getGradientPaintTransformer().transform(gp, bar);
331         }
332         g2.setPaint(itemPaint);
333         g2.fill(bar);
334         if (isDrawBarOutline()
335                 && state.getBarWidth() > BAR_OUTLINE_WIDTH_THRESHOLD) {
336             g2.setStroke(getItemStroke(row, column));
337             g2.setPaint(getItemOutlinePaint(row, column));
338             g2.draw(bar);
339         }
340
341         CategoryItemLabelGenerator generator
342             = getItemLabelGenerator(row, column);
343         if (generator != null && isItemLabelVisible(row, column)) {
344             drawItemLabel(
345                 g2, dataset, row, column, plot, generator, bar,
346                 (value < 0.0)
347             );
348         }
349                 
350         // collect entity and tool tip information...
351
if (state.getInfo() != null) {
352             EntityCollection entities = state.getEntityCollection();
353             if (entities != null) {
354                 String JavaDoc tip = null;
355                 CategoryToolTipGenerator tipster
356                     = getToolTipGenerator(row, column);
357                 if (tipster != null) {
358                     tip = tipster.generateToolTip(dataset, row, column);
359                 }
360                 String JavaDoc url = null;
361                 if (getItemURLGenerator(row, column) != null) {
362                     url = getItemURLGenerator(row, column).generateURL(
363                         dataset, row, column
364                     );
365                 }
366                 CategoryItemEntity entity = new CategoryItemEntity(
367                     bar, tip, url, dataset, row,
368                     dataset.getColumnKey(column), column
369                 );
370                 entities.add(entity);
371             }
372         }
373         
374     }
375    
376     /**
377      * Tests this renderer for equality with an arbitrary object.
378      *
379      * @param obj the object (<code>null</code> permitted).
380      *
381      * @return A boolean.
382      */

383     public boolean equals(Object JavaDoc obj) {
384         if (obj == this) {
385             return true;
386         }
387         if (obj instanceof GroupedStackedBarRenderer && super.equals(obj)) {
388             GroupedStackedBarRenderer r = (GroupedStackedBarRenderer) obj;
389             if (!r.seriesToGroupMap.equals(this.seriesToGroupMap)) {
390                 return false;
391             }
392             return true;
393         }
394         return false;
395     }
396     
397 }
398
Popular Tags