KickJava   Java API By Example, From Geeks To Geeks.

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


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  * StackedAreaXYRenderer.java
24  * --------------------------
25  * (C) Copyright 2003 by Richard Atkinson.
26  *
27  * Original Author: Richard Atkinson;
28  * Contributor(s): Christian W. Zuckschwerdt;
29  * David Gilbert (for Object Refinery Limited);
30  *
31  * $Id: StackedAreaXYRenderer.java,v 1.12 2003/11/03 14:21:28 mungady Exp $
32  *
33  * Changes:
34  * --------
35  * 27-Jul-2003 : Initial version (RA);
36  * 30-Jul-2003 : Modified entity constructor (CZ);
37  * 18-Aug-2003 : Now handles null values (RA);
38  * 20-Aug-2003 : Implemented Cloneable, PublicCloneable and Serializable (DG);
39  * 22-Sep-2003 : Changed to be a two pass renderer with optional shape Paint and Stroke (RA);
40  * 07-Oct-2003 : Added renderer state (DG);
41  *
42  */

43
44 package org.jfree.chart.renderer;
45
46 import java.awt.Graphics2D JavaDoc;
47 import java.awt.Paint JavaDoc;
48 import java.awt.Point JavaDoc;
49 import java.awt.Polygon JavaDoc;
50 import java.awt.Shape JavaDoc;
51 import java.awt.Stroke JavaDoc;
52 import java.awt.geom.Rectangle2D JavaDoc;
53 import java.io.Serializable JavaDoc;
54 import java.util.Stack JavaDoc;
55
56 import org.jfree.chart.CrosshairInfo;
57 import org.jfree.chart.axis.ValueAxis;
58 import org.jfree.chart.entity.EntityCollection;
59 import org.jfree.chart.entity.XYItemEntity;
60 import org.jfree.chart.labels.XYToolTipGenerator;
61 import org.jfree.chart.plot.PlotOrientation;
62 import org.jfree.chart.plot.PlotRenderingInfo;
63 import org.jfree.chart.plot.XYPlot;
64 import org.jfree.chart.urls.XYURLGenerator;
65 import org.jfree.data.TableXYDataset;
66 import org.jfree.data.XYDataset;
67 import org.jfree.util.PublicCloneable;
68
69 /**
70  * A stacked area renderer for the {@link XYPlot} class.
71  *
72  * @author Richard Atkinson
73  */

74 public class StackedAreaXYRenderer extends AreaXYRenderer implements Cloneable JavaDoc,
75                                                                      PublicCloneable,
76                                                                      Serializable JavaDoc {
77
78     /** Last series points to draw bottom edge of the polygon */
79     private transient Stack JavaDoc lastSeriesPoints = null;
80
81     /** This series points */
82     private transient Stack JavaDoc thisSeriesPoints = null;
83
84     /** Custom Paint for drawing all shapes, if null defaults to series shapes */
85     private Paint JavaDoc shapePaint = null;
86
87     /** Custom Stroke for drawing all shapes, if null defaults to series strokes */
88     private Stroke JavaDoc shapeStroke = null;
89
90     /**
91      * Creates a new renderer.
92      */

93     public StackedAreaXYRenderer() {
94         this(AREA);
95     }
96     /**
97      * Constructs a new renderer.
98      *
99      * @param type the type of the renderer.
100      */

101     public StackedAreaXYRenderer(int type) {
102         this(type, null, null);
103     }
104
105     /**
106      * Constructs a new renderer.
107      * <p>
108      * To specify the type of renderer, use one of the constants: SHAPES, LINES,
109      * SHAPES_AND_LINES, AREA or AREA_AND_SHAPES.
110      *
111      * @param type the type of renderer.
112      * @param toolTipGenerator the tool tip generator to use. <code>null</code> is none.
113      * @param urlGenerator the URL generator (null permitted).
114      */

115     public StackedAreaXYRenderer(int type,
116                                  XYToolTipGenerator toolTipGenerator, XYURLGenerator urlGenerator) {
117
118         super(type, toolTipGenerator, urlGenerator);
119     }
120
121     /**
122      * Returns the range type.
123      *
124      * @return the range type.
125      */

126     public RangeType getRangeType() {
127         return RangeType.STACKED;
128     }
129
130     /**
131      * Initialises the renderer.
132      * <P>
133      * This method will be called before the first item is rendered, giving the
134      * renderer an opportunity to initialise any state information it wants to maintain.
135      * The renderer can do nothing if it chooses.
136      *
137      * @param g2 the graphics device.
138      * @param dataArea the area inside the axes.
139      * @param plot the plot.
140      * @param data the data.
141      * @param info an optional info collection object to return data back to the caller.
142      *
143      * @return The number of passes required by the renderer.
144      */

145     public XYItemRendererState initialise(Graphics2D JavaDoc g2,
146                                           Rectangle2D JavaDoc dataArea,
147                                           XYPlot plot,
148                                           XYDataset data,
149                                           PlotRenderingInfo info) {
150
151         return super.initialise(g2, dataArea, plot, data, info);
152
153     }
154
155     /**
156      * Returns the number of passes required by the renderer.
157      *
158      * @return 2.
159      */

160     public int getPassCount() {
161         return 2;
162     }
163
164     /**
165      * Draws the visual representation of a single data item.
166      *
167      * @param g2 the graphics device.
168      * @param state the renderer state.
169      * @param dataArea the area within which the data is being drawn.
170      * @param info collects information about the drawing.
171      * @param plot the plot (can be used to obtain standard color information etc).
172      * @param domainAxis the domain axis.
173      * @param rangeAxis the range axis.
174      * @param dataset the dataset.
175      * @param series the series index (zero-based).
176      * @param item the item index (zero-based).
177      * @param crosshairInfo information about crosshairs on a plot.
178      * @param pass the pass index.
179      */

180     public void drawItem(Graphics2D JavaDoc g2,
181                          XYItemRendererState state,
182                          Rectangle2D JavaDoc dataArea,
183                          PlotRenderingInfo info,
184                          XYPlot plot,
185                          ValueAxis domainAxis,
186                          ValueAxis rangeAxis,
187                          XYDataset dataset,
188                          int series,
189                          int item,
190                          CrosshairInfo crosshairInfo,
191                          int pass) {
192
193         // Get the item count for the series, so that we can know which is the end of the series.
194
TableXYDataset tableXYDataset = (TableXYDataset) dataset;
195         int itemCount = tableXYDataset.getItemCount();
196
197         // get the data point...
198
Number JavaDoc x1 = dataset.getXValue(series, item);
199         Number JavaDoc y1 = dataset.getYValue(series, item);
200         boolean nullPoint = false;
201         if (y1 == null) {
202             y1 = new Double JavaDoc(0);
203             nullPoint = true;
204         }
205
206         // Get height adjustment based on stack and translate to Java2D values
207
double ph1 = this.getPreviousHeight(dataset, series, item);
208         double transX1 = domainAxis.translateValueToJava2D(x1.doubleValue(), dataArea,
209                                                            plot.getDomainAxisEdge());
210         double transY1 = rangeAxis.translateValueToJava2D(y1.doubleValue() + ph1, dataArea,
211                                                           plot.getRangeAxisEdge());
212
213         // Get series Paint and Stroke
214
Paint JavaDoc seriesPaint = getItemPaint(series, item);
215         Stroke JavaDoc seriesStroke = getItemStroke(series, item);
216
217         if (pass == 0) {
218             // On first pass renderer the areas, line and outlines
219

220             if (item == 0) {
221                 // Create a new Area for the series
222
pArea = new Polygon JavaDoc();
223                 this.lastSeriesPoints = this.thisSeriesPoints;
224                 this.thisSeriesPoints = new Stack JavaDoc();
225
226                 // start from previous height (ph1)
227
double transY2 = rangeAxis.translateValueToJava2D(ph1, dataArea,
228                                                                   plot.getRangeAxisEdge());
229
230                 // The first point is (x, 0)
231
if (plot.getOrientation() == PlotOrientation.VERTICAL) {
232                     pArea.addPoint((int) transX1, (int) transY2);
233                 } else if (plot.getOrientation() == PlotOrientation.HORIZONTAL) {
234                     pArea.addPoint((int) transY2, (int) transX1);
235                 }
236             }
237
238             // Add each point to Area (x, y)
239
if (plot.getOrientation() == PlotOrientation.VERTICAL) {
240                 Point JavaDoc point = new Point JavaDoc((int) transX1, (int) transY1);
241                 pArea.addPoint((int) point.getX(), (int) point.getY());
242                 this.thisSeriesPoints.push(point);
243             }
244             else if (plot.getOrientation() == PlotOrientation.HORIZONTAL) {
245                 pArea.addPoint((int) transY1, (int) transX1);
246             }
247
248             if (this.getPlotLines()) {
249                 if (item > 0) {
250                     // get the previous data point...
251
Number JavaDoc x0 = dataset.getXValue(series, item - 1);
252                     Number JavaDoc y0 = dataset.getYValue(series, item - 1);
253                     double ph0 = this.getPreviousHeight(dataset, series, item - 1);
254                     double transX0 = domainAxis.translateValueToJava2D(x0.doubleValue(), dataArea,
255                                                                        plot.getDomainAxisEdge());
256                     double transY0 = rangeAxis.translateValueToJava2D(y0.doubleValue() + ph0,
257                                                                       dataArea,
258                                                                       plot.getRangeAxisEdge());
259
260                     if (plot.getOrientation() == PlotOrientation.VERTICAL) {
261                         line.setLine(transX0, transY0, transX1, transY1);
262                     }
263                     else if (plot.getOrientation() == PlotOrientation.HORIZONTAL) {
264                         line.setLine(transY0, transX0, transY1, transX1);
265                     }
266                     g2.draw(line);
267                 }
268             }
269
270             // Check if the item is the last item for the series.
271
// and number of items > 0. We can't draw an area for a single point.
272
if (this.getPlotArea() && item > 0 && item == (itemCount - 1)) {
273
274                 double transY2 = rangeAxis.translateValueToJava2D(ph1, dataArea,
275                                                                   plot.getRangeAxisEdge());
276
277                 if (plot.getOrientation() == PlotOrientation.VERTICAL) {
278                     // Add the last point (x,0)
279
pArea.addPoint((int) transX1, (int) transY2);
280                 }
281                 else if (plot.getOrientation() == PlotOrientation.HORIZONTAL) {
282                     // Add the last point (x,0)
283
pArea.addPoint((int) transY2, (int) transX1);
284                 }
285
286                 // Add points from last series to complete the base of the polygon
287
if (series != 0) {
288                     while (!this.lastSeriesPoints.empty()) {
289                         Point JavaDoc point = (Point JavaDoc) this.lastSeriesPoints.pop();
290                         pArea.addPoint((int) point.getX(), (int) point.getY());
291                     }
292                 }
293
294                 // Fill the polygon
295
g2.setPaint(seriesPaint);
296                 g2.setStroke(seriesStroke);
297                 g2.fill(pArea);
298
299                 // Draw an outline around the Area.
300
if (this.isOutline()) {
301                     g2.setStroke(plot.getOutlineStroke());
302                     g2.setPaint(plot.getOutlinePaint());
303                     g2.draw(pArea);
304                 }
305             }
306
307             // do we need to update the crosshair values?
308
if (plot.isDomainCrosshairLockedOnData()) {
309                 if (plot.isRangeCrosshairLockedOnData()) {
310                     // both axes
311
crosshairInfo.updateCrosshairPoint(x1.doubleValue(), y1.doubleValue(),
312                                                        transX1, transY1);
313                 } else {
314                     // just the horizontal axis...
315
crosshairInfo.updateCrosshairX(x1.doubleValue());
316
317                 }
318             } else {
319                 if (plot.isRangeCrosshairLockedOnData()) {
320                     // just the vertical axis...
321
crosshairInfo.updateCrosshairY(y1.doubleValue());
322                 }
323             }
324
325         } else if (pass == 1) {
326             // On second pass render shapes and collect entity and tooltip information
327

328             Shape JavaDoc shape = null;
329             if (this.getPlotShapes()) {
330                 shape = getItemShape(series, item);
331                 if (plot.getOrientation() == PlotOrientation.VERTICAL) {
332                     shape = createTransformedShape(shape, transX1, transY1);
333                 } else if (plot.getOrientation() == PlotOrientation.HORIZONTAL) {
334                     shape = createTransformedShape(shape, transY1, transX1);
335                 }
336                 if (!nullPoint) {
337                     if (this.shapePaint != null) {
338                         g2.setPaint(this.shapePaint);
339                     } else {
340                         g2.setPaint(seriesPaint);
341                     }
342                     if (this.shapeStroke != null) {
343                         g2.setStroke(this.shapeStroke);
344                     } else {
345                         g2.setStroke(seriesStroke);
346                     }
347                     g2.draw(shape);
348                 }
349             } else {
350                 if (plot.getOrientation() == PlotOrientation.VERTICAL) {
351                     shape = new Rectangle2D.Double JavaDoc(transX1 - 3, transY1 - 3, 6.0, 6.0);
352                 } else if (plot.getOrientation() == PlotOrientation.HORIZONTAL) {
353                     shape = new Rectangle2D.Double JavaDoc(transY1 - 3, transX1 - 3, 6.0, 6.0);
354                 }
355             }
356
357             // collect entity and tool tip information...
358
if (state.getInfo() != null) {
359                 EntityCollection entities = state.getInfo().getOwner().getEntityCollection();
360                 if (entities != null && shape != null && !nullPoint) {
361                     String JavaDoc tip = null;
362                     if (getToolTipGenerator() != null) {
363                         tip = getToolTipGenerator().generateToolTip(dataset, series, item);
364                     }
365                     String JavaDoc url = null;
366                     if (getURLGenerator() != null) {
367                         url = getURLGenerator().generateURL(dataset, series, item);
368                     }
369                     XYItemEntity entity = new XYItemEntity(shape, dataset, series, item, tip, url);
370                     entities.addEntity(entity);
371                 }
372             }
373
374         }
375     }
376
377
378     /**
379      * Calculates the stacked value of the all series up to, but not including <code>series</code>
380      * for the specified category, <code>category</code>. It returns 0.0 if <code>series</code>
381      * is the first series, i.e. 0.
382      *
383      * @param data the data.
384      * @param series the series.
385      * @param index the index.
386      *
387      * @return double returns a cumulative value for all series' values up to
388      * but excluding <code>series</code> for <code>index</code>.
389      */

390     protected double getPreviousHeight(XYDataset data, int series, int index) {
391
392         double result = 0.0;
393
394         Number JavaDoc tmp;
395         for (int i = 0; i < series; i++) {
396             tmp = data.getYValue(i, index);
397             if (tmp != null) {
398                 result += tmp.doubleValue();
399             }
400         }
401
402         return result;
403
404     }
405
406     /**
407      * Returns a clone of the renderer.
408      *
409      * @return A clone.
410      *
411      * @throws CloneNotSupportedException if the renderer cannot be cloned.
412      */

413     public Object JavaDoc clone() throws CloneNotSupportedException JavaDoc {
414         return super.clone();
415     }
416
417     /**
418      * Returns the Paint used for rendering shapes, or null if using series Paints
419      *
420      * @return The Paint.
421      */

422     public Paint JavaDoc getShapePaint() {
423         return this.shapePaint;
424     }
425
426     /**
427      * Returns the Stroke used for rendering shapes, or null if using series Strokes.
428      *
429      * @return The Stroke.
430      */

431     public Stroke JavaDoc getShapeStroke() {
432         return this.shapeStroke;
433     }
434
435     /**
436      * Sets the Paint for rendering shapes.
437      *
438      * @param shapePaint The Paint.
439      */

440     public void setShapePaint(Paint JavaDoc shapePaint) {
441         this.shapePaint = shapePaint;
442     }
443
444     /**
445      * Sets the Stroke for rendering shapes.
446      *
447      * @param shapeStroke The Stroke.
448      */

449     public void setShapeStroke(Stroke JavaDoc shapeStroke) {
450         this.shapeStroke = shapeStroke;
451     }
452
453 }
454
Popular Tags