KickJava   Java API By Example, From Geeks To Geeks.

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


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  * WaterfallBarRenderer.java
29  * -------------------------
30  * (C) Copyright 2003-2005, by Object Refinery Limited and Contributors.
31  *
32  * Original Author: Darshan Shah;
33  * Contributor(s): David Gilbert (for Object Refinery Limited);
34  *
35  * $Id: WaterfallBarRenderer.java,v 1.9.2.2 2005/10/25 20:54:16 mungady Exp $
36  *
37  * Changes
38  * -------
39  * 20-Oct-2003 : Version 1, contributed by Darshan Shah (DG);
40  * 06-Nov-2003 : Changed order of parameters in constructor, and added support
41  * for GradientPaint (DG);
42  * 10-Feb-2004 : Updated drawItem() method to make cut-and-paste overriding
43  * easier. Also fixed a bug that meant the minimum bar length
44  * was being ignored (DG);
45  * 04-Oct-2004 : Reworked equals() method and renamed PaintUtils
46  * --> PaintUtilities (DG);
47  * 05-Nov-2004 : Modified drawItem() signature (DG);
48  * 07-Jan-2005 : Renamed getRangeExtent() --> findRangeBounds (DG);
49  * 23-Feb-2005 : Added argument checking (DG);
50  * 20-Apr-2005 : Renamed CategoryLabelGenerator
51  * --> CategoryItemLabelGenerator (DG);
52  * 09-Jun-2005 : Use addItemEntity() from superclass (DG);
53  */

54
55 package org.jfree.chart.renderer.category;
56
57 import java.awt.Color JavaDoc;
58 import java.awt.GradientPaint JavaDoc;
59 import java.awt.Graphics2D JavaDoc;
60 import java.awt.Paint JavaDoc;
61 import java.awt.Stroke JavaDoc;
62 import java.awt.geom.Rectangle2D JavaDoc;
63 import java.io.IOException JavaDoc;
64 import java.io.ObjectInputStream JavaDoc;
65 import java.io.ObjectOutputStream JavaDoc;
66 import java.io.Serializable JavaDoc;
67
68 import org.jfree.chart.axis.CategoryAxis;
69 import org.jfree.chart.axis.ValueAxis;
70 import org.jfree.chart.entity.EntityCollection;
71 import org.jfree.chart.event.RendererChangeEvent;
72 import org.jfree.chart.labels.CategoryItemLabelGenerator;
73 import org.jfree.chart.plot.CategoryPlot;
74 import org.jfree.chart.plot.PlotOrientation;
75 import org.jfree.chart.renderer.AbstractRenderer;
76 import org.jfree.data.Range;
77 import org.jfree.data.category.CategoryDataset;
78 import org.jfree.data.general.DatasetUtilities;
79 import org.jfree.io.SerialUtilities;
80 import org.jfree.ui.GradientPaintTransformType;
81 import org.jfree.ui.RectangleEdge;
82 import org.jfree.ui.StandardGradientPaintTransformer;
83 import org.jfree.util.PaintUtilities;
84 import org.jfree.util.PublicCloneable;
85
86 /**
87  * A renderer that handles the drawing of waterfall bar charts, for use with
88  * the {@link CategoryPlot} class. Note that the bar colors are defined
89  * using special methods in this class - the inherited methods (for example,
90  * {@link AbstractRenderer#setSeriesPaint(int, Paint)}) are ignored.
91  */

92 public class WaterfallBarRenderer extends BarRenderer
93                                   implements Cloneable JavaDoc, PublicCloneable,
94                                              Serializable JavaDoc {
95
96     /** For serialization. */
97     private static final long serialVersionUID = -2482910643727230911L;
98     
99     /** The paint used to draw the first bar. */
100     private transient Paint JavaDoc firstBarPaint;
101
102     /** The paint used to draw the last bar. */
103     private transient Paint JavaDoc lastBarPaint;
104
105     /** The paint used to draw bars having positive values. */
106     private transient Paint JavaDoc positiveBarPaint;
107
108     /** The paint used to draw bars having negative values. */
109     private transient Paint JavaDoc negativeBarPaint;
110
111     /**
112      * Constructs a new renderer with default values for the bar colors.
113      */

114     public WaterfallBarRenderer() {
115         this(
116             new GradientPaint JavaDoc(
117                 0.0f, 0.0f, new Color JavaDoc(0x22, 0x22, 0xFF),
118                 0.0f, 0.0f, new Color JavaDoc(0x66, 0x66, 0xFF)
119             ),
120             new GradientPaint JavaDoc(
121                 0.0f, 0.0f, new Color JavaDoc(0x22, 0xFF, 0x22),
122                 0.0f, 0.0f, new Color JavaDoc(0x66, 0xFF, 0x66)
123             ),
124             new GradientPaint JavaDoc(
125                 0.0f, 0.0f, new Color JavaDoc(0xFF, 0x22, 0x22),
126                 0.0f, 0.0f, new Color JavaDoc(0xFF, 0x66, 0x66)
127             ),
128             new GradientPaint JavaDoc(
129                 0.0f, 0.0f, new Color JavaDoc(0xFF, 0xFF, 0x22),
130                 0.0f, 0.0f, new Color JavaDoc(0xFF, 0xFF, 0x66)
131             )
132         );
133     }
134
135     /**
136      * Constructs a new waterfall renderer.
137      *
138      * @param firstBarPaint the color of the first bar (<code>null</code> not
139      * permitted).
140      * @param positiveBarPaint the color for bars with positive values
141      * (<code>null</code> not permitted).
142      * @param negativeBarPaint the color for bars with negative values
143      * (<code>null</code> not permitted).
144      * @param lastBarPaint the color of the last bar (<code>null</code> not
145      * permitted).
146      */

147     public WaterfallBarRenderer(Paint JavaDoc firstBarPaint,
148                                 Paint JavaDoc positiveBarPaint,
149                                 Paint JavaDoc negativeBarPaint,
150                                 Paint JavaDoc lastBarPaint) {
151         super();
152         if (firstBarPaint == null) {
153             throw new IllegalArgumentException JavaDoc("Null 'firstBarPaint' argument");
154         }
155         if (positiveBarPaint == null) {
156             throw new IllegalArgumentException JavaDoc(
157                 "Null 'positiveBarPaint' argument"
158             );
159         }
160         if (negativeBarPaint == null) {
161             throw new IllegalArgumentException JavaDoc(
162                 "Null 'negativeBarPaint' argument"
163             );
164         }
165         if (lastBarPaint == null) {
166             throw new IllegalArgumentException JavaDoc("Null 'lastBarPaint' argument");
167         }
168         this.firstBarPaint = firstBarPaint;
169         this.lastBarPaint = lastBarPaint;
170         this.positiveBarPaint = positiveBarPaint;
171         this.negativeBarPaint = negativeBarPaint;
172         setGradientPaintTransformer(
173             new StandardGradientPaintTransformer(
174                 GradientPaintTransformType.CENTER_VERTICAL
175             )
176         );
177         setMinimumBarLength(1.0);
178     }
179
180     /**
181      * Returns the range of values the renderer requires to display all the
182      * items from the specified dataset.
183      *
184      * @param dataset the dataset (<code>null</code> not permitted).
185      *
186      * @return The range (or <code>null</code> if the dataset is empty).
187      */

188     public Range findRangeBounds(CategoryDataset dataset) {
189         return DatasetUtilities.findCumulativeRangeBounds(dataset);
190     }
191
192     /**
193      * Returns the paint used to draw the first bar.
194      *
195      * @return The paint (never <code>null</code>).
196      */

197     public Paint JavaDoc getFirstBarPaint() {
198         return this.firstBarPaint;
199     }
200     
201     /**
202      * Sets the paint that will be used to draw the first bar and sends a
203      * {@link RendererChangeEvent} to all registered listeners.
204      *
205      * @param paint the paint (<code>null</code> not permitted).
206      */

207     public void setFirstBarPaint(Paint JavaDoc paint) {
208         if (paint == null) {
209             throw new IllegalArgumentException JavaDoc("Null 'paint' argument");
210         }
211         this.firstBarPaint = paint;
212         notifyListeners(new RendererChangeEvent(this));
213     }
214
215     /**
216      * Returns the paint used to draw the last bar.
217      *
218      * @return The paint (never <code>null</code>).
219      */

220     public Paint JavaDoc getLastBarPaint() {
221         return this.lastBarPaint;
222     }
223     
224     /**
225      * Sets the paint that will be used to draw the last bar.
226      *
227      * @param paint the paint (<code>null</code> not permitted).
228      */

229     public void setLastBarPaint(Paint JavaDoc paint) {
230         if (paint == null) {
231             throw new IllegalArgumentException JavaDoc("Null 'paint' argument");
232         }
233         this.lastBarPaint = paint;
234         notifyListeners(new RendererChangeEvent(this));
235     }
236
237     /**
238      * Returns the paint used to draw bars with positive values.
239      *
240      * @return The paint (never <code>null</code>).
241      */

242     public Paint JavaDoc getPositiveBarPaint() {
243         return this.positiveBarPaint;
244     }
245     
246     /**
247      * Sets the paint that will be used to draw bars having positive values.
248      *
249      * @param paint the paint (<code>null</code> not permitted).
250      */

251     public void setPositiveBarPaint(Paint JavaDoc paint) {
252         if (paint == null) {
253             throw new IllegalArgumentException JavaDoc("Null 'paint' argument");
254         }
255         this.positiveBarPaint = paint;
256         notifyListeners(new RendererChangeEvent(this));
257     }
258
259     /**
260      * Returns the paint used to draw bars with negative values.
261      *
262      * @return The paint (never <code>null</code>).
263      */

264     public Paint JavaDoc getNegativeBarPaint() {
265         return this.negativeBarPaint;
266     }
267     
268     /**
269      * Sets the paint that will be used to draw bars having negative values.
270      *
271      * @param paint the paint (<code>null</code> not permitted).
272      */

273     public void setNegativeBarPaint(Paint JavaDoc paint) {
274         if (paint == null) {
275             throw new IllegalArgumentException JavaDoc("Null 'paint' argument");
276         }
277         this.negativeBarPaint = paint;
278         notifyListeners(new RendererChangeEvent(this));
279     }
280
281     /**
282      * Draws the bar for a single (series, category) data item.
283      *
284      * @param g2 the graphics device.
285      * @param state the renderer state.
286      * @param dataArea the data area.
287      * @param plot the plot.
288      * @param domainAxis the domain axis.
289      * @param rangeAxis the range axis.
290      * @param dataset the dataset.
291      * @param row the row index (zero-based).
292      * @param column the column index (zero-based).
293      * @param pass the pass index.
294      */

295     public void drawItem(Graphics2D JavaDoc g2,
296                          CategoryItemRendererState state,
297                          Rectangle2D JavaDoc dataArea,
298                          CategoryPlot plot,
299                          CategoryAxis domainAxis,
300                          ValueAxis rangeAxis,
301                          CategoryDataset dataset,
302                          int row,
303                          int column,
304                          int pass) {
305
306         double previous = state.getSeriesRunningTotal();
307         if (column == dataset.getColumnCount() - 1) {
308             previous = 0.0;
309         }
310         double current = 0.0;
311         Number JavaDoc n = dataset.getValue(row, column);
312         if (n != null) {
313             current = previous + n.doubleValue();
314         }
315         state.setSeriesRunningTotal(current);
316         
317         int seriesCount = getRowCount();
318         int categoryCount = getColumnCount();
319         PlotOrientation orientation = plot.getOrientation();
320         
321         double rectX = 0.0;
322         double rectY = 0.0;
323
324         RectangleEdge domainAxisLocation = plot.getDomainAxisEdge();
325         RectangleEdge rangeAxisLocation = plot.getRangeAxisEdge();
326         
327         // Y0
328
double j2dy0 = rangeAxis.valueToJava2D(
329             previous, dataArea, rangeAxisLocation
330         );
331
332         // Y1
333
double j2dy1 = rangeAxis.valueToJava2D(
334             current, dataArea, rangeAxisLocation
335         );
336
337         double valDiff = current - previous;
338         if (j2dy1 < j2dy0) {
339             double temp = j2dy1;
340             j2dy1 = j2dy0;
341             j2dy0 = temp;
342         }
343
344         // BAR WIDTH
345
double rectWidth = state.getBarWidth();
346
347         // BAR HEIGHT
348
double rectHeight = Math.max(
349             getMinimumBarLength(), Math.abs(j2dy1 - j2dy0)
350         );
351
352         if (orientation == PlotOrientation.HORIZONTAL) {
353             // BAR Y
354
rectY = domainAxis.getCategoryStart(
355                 column, getColumnCount(), dataArea, domainAxisLocation
356             );
357             if (seriesCount > 1) {
358                 double seriesGap = dataArea.getHeight() * getItemMargin()
359                                    / (categoryCount * (seriesCount - 1));
360                 rectY = rectY + row * (state.getBarWidth() + seriesGap);
361             }
362             else {
363                 rectY = rectY + row * state.getBarWidth();
364             }
365              
366             rectX = j2dy0;
367             rectHeight = state.getBarWidth();
368             rectWidth = Math.max(
369                 getMinimumBarLength(), Math.abs(j2dy1 - j2dy0)
370             );
371
372         }
373         else if (orientation == PlotOrientation.VERTICAL) {
374             // BAR X
375
rectX = domainAxis.getCategoryStart(
376                 column, getColumnCount(), dataArea, domainAxisLocation
377             );
378
379             if (seriesCount > 1) {
380                 double seriesGap = dataArea.getWidth() * getItemMargin()
381                                    / (categoryCount * (seriesCount - 1));
382                 rectX = rectX + row * (state.getBarWidth() + seriesGap);
383             }
384             else {
385                 rectX = rectX + row * state.getBarWidth();
386             }
387
388             rectY = j2dy0;
389         }
390         Rectangle2D JavaDoc bar = new Rectangle2D.Double JavaDoc(
391             rectX, rectY, rectWidth, rectHeight
392         );
393         Paint JavaDoc seriesPaint = getFirstBarPaint();
394         if (column == 0) {
395             seriesPaint = getFirstBarPaint();
396         }
397         else if (column == categoryCount - 1) {
398             seriesPaint = getLastBarPaint();
399         }
400         else {
401             if (valDiff < 0.0) {
402                 seriesPaint = getNegativeBarPaint();
403             }
404             else if (valDiff > 0.0) {
405                 seriesPaint = getPositiveBarPaint();
406             }
407             else {
408                 seriesPaint = getLastBarPaint();
409             }
410         }
411         if (getGradientPaintTransformer() != null
412                 && seriesPaint instanceof GradientPaint JavaDoc) {
413             GradientPaint JavaDoc gp = (GradientPaint JavaDoc) seriesPaint;
414             seriesPaint = getGradientPaintTransformer().transform(gp, bar);
415         }
416         g2.setPaint(seriesPaint);
417         g2.fill(bar);
418         
419         // draw the outline...
420
if (isDrawBarOutline()
421                 && state.getBarWidth() > BAR_OUTLINE_WIDTH_THRESHOLD) {
422             Stroke JavaDoc stroke = getItemOutlineStroke(row, column);
423             Paint JavaDoc paint = getItemOutlinePaint(row, column);
424             if (stroke != null && paint != null) {
425                 g2.setStroke(stroke);
426                 g2.setPaint(paint);
427                 g2.draw(bar);
428             }
429         }
430         
431         CategoryItemLabelGenerator generator
432             = getItemLabelGenerator(row, column);
433         if (generator != null && isItemLabelVisible(row, column)) {
434             drawItemLabel(
435                 g2, dataset, row, column, plot, generator, bar, (valDiff < 0.0)
436             );
437         }
438
439         // add an item entity, if this information is being collected
440
EntityCollection entities = state.getEntityCollection();
441         if (entities != null) {
442             addItemEntity(entities, dataset, row, column, bar);
443         }
444
445     }
446     
447     /**
448      * Tests an object for equality with this instance.
449      *
450      * @param obj the object (<code>null</code> permitted).
451      *
452      * @return A boolean.
453      */

454     public boolean equals(Object JavaDoc obj) {
455         
456         if (obj == this) {
457             return true;
458         }
459         if (!super.equals(obj)) {
460             return false;
461         }
462         if (!(obj instanceof WaterfallBarRenderer)) {
463             return false;
464         }
465         WaterfallBarRenderer that = (WaterfallBarRenderer) obj;
466         if (!PaintUtilities.equal(this.firstBarPaint, that.firstBarPaint)) {
467             return false;
468         }
469         if (!PaintUtilities.equal(this.lastBarPaint, that.lastBarPaint)) {
470             return false;
471         }
472         if (!PaintUtilities.equal(this.positiveBarPaint,
473                 that.positiveBarPaint)) {
474             return false;
475         }
476         if (!PaintUtilities.equal(this.negativeBarPaint,
477                 that.negativeBarPaint)) {
478             return false;
479         }
480         return true;
481         
482     }
483     
484     /**
485      * Provides serialization support.
486      *
487      * @param stream the output stream.
488      *
489      * @throws IOException if there is an I/O error.
490      */

491     private void writeObject(ObjectOutputStream JavaDoc stream) throws IOException JavaDoc {
492         stream.defaultWriteObject();
493         SerialUtilities.writePaint(this.firstBarPaint, stream);
494         SerialUtilities.writePaint(this.lastBarPaint, stream);
495         SerialUtilities.writePaint(this.positiveBarPaint, stream);
496         SerialUtilities.writePaint(this.negativeBarPaint, stream);
497     }
498
499     /**
500      * Provides serialization support.
501      *
502      * @param stream the input stream.
503      *
504      * @throws IOException if there is an I/O error.
505      * @throws ClassNotFoundException if there is a classpath problem.
506      */

507     private void readObject(ObjectInputStream JavaDoc stream)
508         throws IOException JavaDoc, ClassNotFoundException JavaDoc {
509         stream.defaultReadObject();
510         this.firstBarPaint = SerialUtilities.readPaint(stream);
511         this.lastBarPaint = SerialUtilities.readPaint(stream);
512         this.positiveBarPaint = SerialUtilities.readPaint(stream);
513         this.negativeBarPaint = SerialUtilities.readPaint(stream);
514     }
515
516 }
517
Popular Tags