KickJava   Java API By Example, From Geeks To Geeks.

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


1 /* ===========================================================
2  * JFreeChart : a free chart library for the Java(tm) platform
3  * ===========================================================
4  *
5  * (C) Copyright 2000-2006, 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  * LayeredBarRenderer.java
29  * -----------------------
30  * (C) Copyright 2003-2006, by Arnaud Lelievre and Contributors.
31  *
32  * Original Author: Arnaud Lelievre (for Garden);
33  * Contributor(s): David Gilbert (for Object Refinery Limited);
34  * Zoheb Borbora;
35  *
36  * Changes
37  * -------
38  * 28-Aug-2003 : Version 1 (AL);
39  * 16-Sep-2003 : Changed ChartRenderingInfo --> PlotRenderingInfo (DG);
40  * 07-Oct-2003 : Added renderer state (DG);
41  * 21-Oct-2003 : Bar width moved to renderer state (DG);
42  * 05-Nov-2004 : Modified drawItem() signature (DG);
43  * 20-Apr-2005 : Renamed CategoryLabelGenerator
44  * --> CategoryItemLabelGenerator (DG);
45  * 17-Nov-2005 : Added support for gradient paint (DG);
46  * ------------- JFREECHART 1.0.0 ---------------------------------------------
47  * 18-Aug-2006 : Fixed the bar width calculation to respect the maximum bar
48  * width setting (thanks to Zoheb Borbora) (DG);
49  *
50  */

51
52 package org.jfree.chart.renderer.category;
53
54 import java.awt.GradientPaint JavaDoc;
55 import java.awt.Graphics2D JavaDoc;
56 import java.awt.Paint JavaDoc;
57 import java.awt.Stroke JavaDoc;
58 import java.awt.geom.Rectangle2D JavaDoc;
59 import java.io.Serializable JavaDoc;
60
61 import org.jfree.chart.axis.CategoryAxis;
62 import org.jfree.chart.axis.ValueAxis;
63 import org.jfree.chart.entity.CategoryItemEntity;
64 import org.jfree.chart.entity.EntityCollection;
65 import org.jfree.chart.labels.CategoryItemLabelGenerator;
66 import org.jfree.chart.labels.CategoryToolTipGenerator;
67 import org.jfree.chart.plot.CategoryPlot;
68 import org.jfree.chart.plot.PlotOrientation;
69 import org.jfree.data.category.CategoryDataset;
70 import org.jfree.ui.GradientPaintTransformer;
71 import org.jfree.ui.RectangleEdge;
72 import org.jfree.util.ObjectList;
73
74 /**
75  * A {@link CategoryItemRenderer} that represents data using bars which are
76  * superimposed.
77  *
78  * @author Arnaud Lelievre
79  */

80 public class LayeredBarRenderer extends BarRenderer
81                                 implements Serializable JavaDoc {
82     
83     /** For serialization. */
84     private static final long serialVersionUID = -8716572894780469487L;
85
86     /** A list of the width of each series bar. */
87     protected ObjectList seriesBarWidthList;
88
89     /**
90      * Default constructor.
91      */

92     public LayeredBarRenderer() {
93         super();
94         this.seriesBarWidthList = new ObjectList();
95     }
96
97     /**
98      * Returns the bar width for a series, or <code>Double.NaN</code> if no
99      * width has been set.
100      *
101      * @param series the series index (zero based).
102      *
103      * @return The width for the series (1.0=100%, it is the maximum).
104      */

105     public double getSeriesBarWidth(int series) {
106         double result = Double.NaN;
107         Number JavaDoc n = (Number JavaDoc) this.seriesBarWidthList.get(series);
108         if (n != null) {
109             result = n.doubleValue();
110         }
111         return result;
112     }
113
114     /**
115      * Sets the width of the bars of a series.
116      *
117      * @param series the series index (zero based).
118      * @param width the width of the series bar in percentage (1.0=100%, it is
119      * the maximum).
120      */

121     public void setSeriesBarWidth(int series, double width) {
122         this.seriesBarWidthList.set(series, new Double JavaDoc(width));
123     }
124
125     /**
126      * Calculates the bar width and stores it in the renderer state.
127      *
128      * @param plot the plot.
129      * @param dataArea the data area.
130      * @param rendererIndex the renderer index.
131      * @param state the renderer state.
132      */

133     protected void calculateBarWidth(CategoryPlot plot,
134                                      Rectangle2D JavaDoc dataArea,
135                                      int rendererIndex,
136                                      CategoryItemRendererState state) {
137
138         // calculate the bar width - this calculation differs from the
139
// BarRenderer calculation because the bars are layered on top of one
140
// another, so there is effectively only one bar per category for
141
// the purpose of the bar width calculation
142
CategoryAxis domainAxis = getDomainAxis(plot, rendererIndex);
143         CategoryDataset dataset = plot.getDataset(rendererIndex);
144         if (dataset != null) {
145             int columns = dataset.getColumnCount();
146             int rows = dataset.getRowCount();
147             double space = 0.0;
148             PlotOrientation orientation = plot.getOrientation();
149             if (orientation == PlotOrientation.HORIZONTAL) {
150                 space = dataArea.getHeight();
151             }
152             else if (orientation == PlotOrientation.VERTICAL) {
153                 space = dataArea.getWidth();
154             }
155             double maxWidth = space * getMaximumBarWidth();
156             double categoryMargin = 0.0;
157             if (columns > 1) {
158                 categoryMargin = domainAxis.getCategoryMargin();
159             }
160             double used = space * (1 - domainAxis.getLowerMargin()
161                 - domainAxis.getUpperMargin() - categoryMargin);
162             if ((rows * columns) > 0) {
163                 state.setBarWidth(Math.min(used / (dataset.getColumnCount()),
164                         maxWidth));
165             }
166             else {
167                 state.setBarWidth(Math.min(used, maxWidth));
168             }
169         }
170     }
171
172     /**
173      * Draws the bar for one item in the dataset.
174      *
175      * @param g2 the graphics device.
176      * @param state the renderer state.
177      * @param dataArea the plot area.
178      * @param plot the plot.
179      * @param domainAxis the domain (category) axis.
180      * @param rangeAxis the range (value) axis.
181      * @param data the data.
182      * @param row the row index (zero-based).
183      * @param column the column index (zero-based).
184      * @param pass the pass index.
185      */

186     public void drawItem(Graphics2D JavaDoc g2,
187                          CategoryItemRendererState state,
188                          Rectangle2D JavaDoc dataArea,
189                          CategoryPlot plot,
190                          CategoryAxis domainAxis,
191                          ValueAxis rangeAxis,
192                          CategoryDataset data,
193                          int row,
194                          int column,
195                          int pass) {
196
197         PlotOrientation orientation = plot.getOrientation();
198         if (orientation == PlotOrientation.HORIZONTAL) {
199             drawHorizontalItem(g2, state, dataArea, plot, domainAxis, rangeAxis,
200                 data, row, column);
201         }
202         else if (orientation == PlotOrientation.VERTICAL) {
203             drawVerticalItem(g2, state, dataArea, plot, domainAxis, rangeAxis,
204                 data, row, column);
205         }
206
207     }
208
209     /**
210      * Draws the bar for a single (series, category) data item.
211      *
212      * @param g2 the graphics device.
213      * @param state the renderer state.
214      * @param dataArea the data area.
215      * @param plot the plot.
216      * @param domainAxis the domain axis.
217      * @param rangeAxis the range axis.
218      * @param data the data.
219      * @param row the row index (zero-based).
220      * @param column the column index (zero-based).
221      */

222     protected void drawHorizontalItem(Graphics2D JavaDoc g2,
223                                       CategoryItemRendererState state,
224                                       Rectangle2D JavaDoc dataArea,
225                                       CategoryPlot plot,
226                                       CategoryAxis domainAxis,
227                                       ValueAxis rangeAxis,
228                                       CategoryDataset data,
229                                       int row,
230                                       int column) {
231
232         // nothing is drawn for null values...
233
Number JavaDoc dataValue = data.getValue(row, column);
234         if (dataValue == null) {
235             return;
236         }
237
238         // X
239
double value = dataValue.doubleValue();
240         double base = 0.0;
241         double lclip = getLowerClip();
242         double uclip = getUpperClip();
243         if (uclip <= 0.0) { // cases 1, 2, 3 and 4
244
if (value >= uclip) {
245                 return; // bar is not visible
246
}
247             base = uclip;
248             if (value <= lclip) {
249                 value = lclip;
250             }
251         }
252         else if (lclip <= 0.0) { // cases 5, 6, 7 and 8
253
if (value >= uclip) {
254                 value = uclip;
255             }
256             else {
257                 if (value <= lclip) {
258                     value = lclip;
259                 }
260             }
261         }
262         else { // cases 9, 10, 11 and 12
263
if (value <= lclip) {
264                 return; // bar is not visible
265
}
266             base = lclip;
267             if (value >= uclip) {
268                 value = uclip;
269             }
270         }
271
272         RectangleEdge edge = plot.getRangeAxisEdge();
273         double transX1 = rangeAxis.valueToJava2D(base, dataArea, edge);
274         double transX2 = rangeAxis.valueToJava2D(value, dataArea, edge);
275         double rectX = Math.min(transX1, transX2);
276         double rectWidth = Math.abs(transX2 - transX1);
277
278         // Y
279
double rectY = domainAxis.getCategoryMiddle(column, getColumnCount(),
280                 dataArea, plot.getDomainAxisEdge()) - state.getBarWidth() / 2.0;
281
282         int seriesCount = getRowCount();
283
284         // draw the bar...
285
double shift = 0.0;
286         double rectHeight = 0.0;
287         double widthFactor = 1.0;
288         double seriesBarWidth = getSeriesBarWidth(row);
289         if (!Double.isNaN(seriesBarWidth)) {
290             widthFactor = seriesBarWidth;
291         }
292         rectHeight = widthFactor * state.getBarWidth();
293         rectY = rectY + (1 - widthFactor) * state.getBarWidth() / 2.0;
294         if (seriesCount > 1) {
295             shift = rectHeight * 0.20 / (seriesCount - 1);
296         }
297
298         Rectangle2D JavaDoc bar = new Rectangle2D.Double JavaDoc(rectX,
299                 (rectY + ((seriesCount - 1 - row) * shift)), rectWidth,
300                 (rectHeight - (seriesCount - 1 - row) * shift * 2));
301
302         Paint JavaDoc itemPaint = getItemPaint(row, column);
303         GradientPaintTransformer t = getGradientPaintTransformer();
304         if (t != null && itemPaint instanceof GradientPaint JavaDoc) {
305             itemPaint = t.transform((GradientPaint JavaDoc) itemPaint, bar);
306         }
307         g2.setPaint(itemPaint);
308         g2.fill(bar);
309
310         // draw the outline...
311
if (isDrawBarOutline()
312                 && state.getBarWidth() > BAR_OUTLINE_WIDTH_THRESHOLD) {
313             Stroke JavaDoc stroke = getItemOutlineStroke(row, column);
314             Paint JavaDoc paint = getItemOutlinePaint(row, column);
315             if (stroke != null && paint != null) {
316                 g2.setStroke(stroke);
317                 g2.setPaint(paint);
318                 g2.draw(bar);
319             }
320         }
321
322         CategoryItemLabelGenerator generator
323             = getItemLabelGenerator(row, column);
324         if (generator != null && isItemLabelVisible(row, column)) {
325             drawItemLabel(g2, data, row, column, plot, generator, bar,
326                     (transX1 > transX2));
327         }
328
329         // collect entity and tool tip information...
330
if (state.getInfo() != null) {
331             EntityCollection entities = state.getEntityCollection();
332             if (entities != null) {
333                 String JavaDoc tip = null;
334                 CategoryToolTipGenerator tipster
335                     = getToolTipGenerator(row, column);
336                 if (tipster != null) {
337                     tip = tipster.generateToolTip(data, row, column);
338                 }
339                 String JavaDoc url = null;
340                 if (getItemURLGenerator(row, column) != null) {
341                     url = getItemURLGenerator(row, column).generateURL(data,
342                             row, column);
343                 }
344                 CategoryItemEntity entity = new CategoryItemEntity(bar, tip,
345                         url, data, row, data.getColumnKey(column), column);
346                 entities.add(entity);
347             }
348         }
349     }
350
351     /**
352      * Draws the bar for a single (series, category) data item.
353      *
354      * @param g2 the graphics device.
355      * @param state the renderer state.
356      * @param dataArea the data area.
357      * @param plot the plot.
358      * @param domainAxis the domain axis.
359      * @param rangeAxis the range axis.
360      * @param data the data.
361      * @param row the row index (zero-based).
362      * @param column the column index (zero-based).
363      */

364     protected void drawVerticalItem(Graphics2D JavaDoc g2,
365                                     CategoryItemRendererState state,
366                                     Rectangle2D JavaDoc dataArea,
367                                     CategoryPlot plot,
368                                     CategoryAxis domainAxis,
369                                     ValueAxis rangeAxis,
370                                     CategoryDataset data,
371                                     int row,
372                                     int column) {
373
374         // nothing is drawn for null values...
375
Number JavaDoc dataValue = data.getValue(row, column);
376         if (dataValue == null) {
377             return;
378         }
379
380         // BAR X
381
double rectX = domainAxis.getCategoryMiddle(column, getColumnCount(),
382                 dataArea, plot.getDomainAxisEdge()) - state.getBarWidth() / 2.0;
383
384         int seriesCount = getRowCount();
385
386         // BAR Y
387
double value = dataValue.doubleValue();
388         double base = 0.0;
389         double lclip = getLowerClip();
390         double uclip = getUpperClip();
391
392         if (uclip <= 0.0) { // cases 1, 2, 3 and 4
393
if (value >= uclip) {
394                 return; // bar is not visible
395
}
396             base = uclip;
397             if (value <= lclip) {
398                 value = lclip;
399             }
400         }
401         else if (lclip <= 0.0) { // cases 5, 6, 7 and 8
402
if (value >= uclip) {
403                 value = uclip;
404             }
405             else {
406                 if (value <= lclip) {
407                     value = lclip;
408                 }
409             }
410         }
411         else { // cases 9, 10, 11 and 12
412
if (value <= lclip) {
413                 return; // bar is not visible
414
}
415             base = getLowerClip();
416             if (value >= uclip) {
417                value = uclip;
418             }
419         }
420
421         RectangleEdge edge = plot.getRangeAxisEdge();
422         double transY1 = rangeAxis.valueToJava2D(base, dataArea, edge);
423         double transY2 = rangeAxis.valueToJava2D(value, dataArea, edge);
424         double rectY = Math.min(transY2, transY1);
425
426         double rectWidth = state.getBarWidth();
427         double rectHeight = Math.abs(transY2 - transY1);
428
429         // draw the bar...
430
double shift = 0.0;
431         rectWidth = 0.0;
432         double widthFactor = 1.0;
433         double seriesBarWidth = getSeriesBarWidth(row);
434         if (!Double.isNaN(seriesBarWidth)) {
435             widthFactor = seriesBarWidth;
436         }
437         rectWidth = widthFactor * state.getBarWidth();
438         rectX = rectX + (1 - widthFactor) * state.getBarWidth() / 2.0;
439         if (seriesCount > 1) {
440             // needs to be improved !!!
441
shift = rectWidth * 0.20 / (seriesCount - 1);
442         }
443
444         Rectangle2D JavaDoc bar = new Rectangle2D.Double JavaDoc(
445             (rectX + ((seriesCount - 1 - row) * shift)), rectY,
446             (rectWidth - (seriesCount - 1 - row) * shift * 2), rectHeight);
447         Paint JavaDoc itemPaint = getItemPaint(row, column);
448         GradientPaintTransformer t = getGradientPaintTransformer();
449         if (t != null && itemPaint instanceof GradientPaint JavaDoc) {
450             itemPaint = t.transform((GradientPaint JavaDoc) itemPaint, bar);
451         }
452         g2.setPaint(itemPaint);
453         g2.fill(bar);
454
455         // draw the outline...
456
if (isDrawBarOutline()
457                 && state.getBarWidth() > BAR_OUTLINE_WIDTH_THRESHOLD) {
458             Stroke JavaDoc stroke = getItemOutlineStroke(row, column);
459             Paint JavaDoc paint = getItemOutlinePaint(row, column);
460             if (stroke != null && paint != null) {
461                 g2.setStroke(stroke);
462                 g2.setPaint(paint);
463                 g2.draw(bar);
464             }
465         }
466
467         // draw the item labels if there are any...
468
double transX1 = rangeAxis.valueToJava2D(base, dataArea, edge);
469         double transX2 = rangeAxis.valueToJava2D(value, dataArea, edge);
470
471         CategoryItemLabelGenerator generator
472             = getItemLabelGenerator(row, column);
473         if (generator != null && isItemLabelVisible(row, column)) {
474             drawItemLabel(g2, data, row, column, plot, generator, bar,
475                     (transX1 > transX2));
476         }
477
478         // collect entity and tool tip information...
479
if (state.getInfo() != null) {
480             EntityCollection entities = state.getEntityCollection();
481             if (entities != null) {
482                 String JavaDoc tip = null;
483                 CategoryToolTipGenerator tipster
484                     = getToolTipGenerator(row, column);
485                 if (tipster != null) {
486                     tip = tipster.generateToolTip(data, row, column);
487                 }
488                 String JavaDoc url = null;
489                 if (getItemURLGenerator(row, column) != null) {
490                     url = getItemURLGenerator(row, column).generateURL(
491                         data, row, column);
492                 }
493                 CategoryItemEntity entity = new CategoryItemEntity(bar, tip,
494                         url, data, row, data.getColumnKey(column), column);
495                 entities.add(entity);
496             }
497         }
498     }
499
500 }
501
Popular Tags