KickJava   Java API By Example, From Geeks To Geeks.

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


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  * XYStepAreaRenderer.java
24  * -----------------------
25  * (C) Copyright 2003 by Matthias Rose and Contributors.
26  *
27  * Original Author: Matthias Rose (based on AreaXYRenderer.java);
28  * Contributor(s): Hari (ourhari@hotmail.com);
29  * David Gilbert (for Object Refinery Limited);
30  * Richard Atkinson;
31  * Christian W. Zuckschwerdt;
32  * Matthias Rose;
33  *
34  * $Id: XYStepAreaRenderer.java,v 1.2 2003/11/03 14:21:28 mungady Exp $
35  *
36  * Changes:
37  * --------
38  * 07-Oct-2003 : Version 1, contributed by Matthias Rose (DG);
39  *
40  */

41
42 package org.jfree.chart.renderer;
43
44 import java.awt.Graphics2D JavaDoc;
45 import java.awt.Paint JavaDoc;
46 import java.awt.Polygon JavaDoc;
47 import java.awt.Shape JavaDoc;
48 import java.awt.Stroke JavaDoc;
49 import java.awt.geom.Rectangle2D JavaDoc;
50 import java.io.Serializable JavaDoc;
51
52 import org.jfree.chart.CrosshairInfo;
53 import org.jfree.chart.axis.ValueAxis;
54 import org.jfree.chart.entity.EntityCollection;
55 import org.jfree.chart.entity.XYItemEntity;
56 import org.jfree.chart.labels.XYToolTipGenerator;
57 import org.jfree.chart.plot.PlotOrientation;
58 import org.jfree.chart.plot.PlotRenderingInfo;
59 import org.jfree.chart.plot.XYPlot;
60 import org.jfree.chart.urls.XYURLGenerator;
61 import org.jfree.data.XYDataset;
62 import org.jfree.util.PublicCloneable;
63
64 /**
65  * A step chart renderer that fills the area between the step and the x-axis.
66  *
67  * @author Matthias Rose
68  */

69 public class XYStepAreaRenderer extends AbstractXYItemRenderer
70                                 implements XYItemRenderer,
71                                            Cloneable JavaDoc,
72                                            PublicCloneable,
73                                            Serializable JavaDoc {
74
75     /** Useful constant for specifying the type of rendering (shapes only). */
76     public static final int SHAPES = 1;
77
78     /** Useful constant for specifying the type of rendering (area only). */
79     public static final int AREA = 2;
80
81     /** Useful constant for specifying the type of rendering (area and shapes). */
82     public static final int AREA_AND_SHAPES = 3;
83
84     /** A flag indicating whether or not shapes are drawn at each XY point. */
85     private boolean plotShapes;
86
87     /** A flag that controls whether or not shapes are filled for ALL series. */
88     private boolean shapesFilled;
89
90     /** A flag indicating whether or not Area are drawn at each XY point. */
91     private boolean plotArea;
92
93     /** A flag that controls whether or not the outline is shown. */
94     private boolean showOutline;
95
96     /** Area of the complete series */
97     protected transient Polygon JavaDoc pArea = null;
98
99     /** The value on the range axis which defines the 'lower' border of the area. */
100     private double rangeBase;
101
102     /**
103      * Constructs a new renderer.
104      */

105     public XYStepAreaRenderer() {
106         this(AREA);
107     }
108
109     /**
110      * Constructs a new renderer.
111      *
112      * @param type the type of the renderer.
113      */

114     public XYStepAreaRenderer(int type) {
115         this(type, null, null);
116     }
117
118     /**
119      * Constructs a new renderer.
120      * <p>
121      * To specify the type of renderer, use one of the constants:
122      * AREA, SHAPES or AREA_AND_SHAPES.
123      *
124      * @param type the type of renderer.
125      * @param toolTipGenerator the tool tip generator to use. <code>null</code> is none.
126      * @param urlGenerator the URL generator (null permitted).
127      */

128     public XYStepAreaRenderer(int type,
129                               XYToolTipGenerator toolTipGenerator, XYURLGenerator urlGenerator) {
130
131         super();
132         setToolTipGenerator(toolTipGenerator);
133         setURLGenerator(urlGenerator);
134
135         if (type == AREA) {
136             this.plotArea = true;
137         }
138         else if (type == SHAPES) {
139             this.plotShapes = true;
140         }
141         else if (type == AREA_AND_SHAPES) {
142             this.plotArea = true;
143             this.plotShapes = true;
144         }
145         showOutline = false;
146     }
147
148     /**
149      * Returns a flag that controls whether or not outlines of the areas are drawn.
150      *
151      * @return the flag.
152      */

153     public boolean isOutline() {
154         return showOutline;
155     }
156
157     /**
158      * Sets a flag that controls whether or not outlines of the areas are drawn.
159      *
160      * @param show the flag.
161      */

162     public void setOutline(boolean show) {
163         showOutline = show;
164     }
165
166     /**
167      * Returns true if shapes are being plotted by the renderer.
168      *
169      * @return <code>true</code> if shapes are being plotted by the renderer.
170      */

171     public boolean getPlotShapes() {
172         return this.plotShapes;
173     }
174
175     /**
176      * Sets the 'shapes filled' for ALL series.
177      *
178      * @param filled the flag.
179      */

180     public void setShapesFilled(boolean filled) {
181         this.shapesFilled = filled;
182     }
183
184     /**
185      * Returns true if Area is being plotted by the renderer.
186      *
187      * @return <code>true</code> if Area is being plotted by the renderer.
188      */

189     public boolean getPlotArea() {
190         return this.plotArea;
191     }
192
193     /**
194      * Sets the value on the range axis which defines the default border of the area.
195      * E.g. setRangeBase(Double.NEGATIVE_INFINITY) lets areas always reach the lower border of the
196      * plotArea.
197      *
198      * @param val the value on the range axis which defines the default border of the area.
199      */

200     public void setRangeBase(double val) {
201         this.rangeBase = val;
202     }
203
204     /**
205      * Returns the value on the range axis which defines the 'lower' border of the area.
206      *
207      * @return <code>double</code> the value on the range axis which defines the 'lower' border of
208      * the area.
209      */

210     public double getRangeBase() {
211         return this.rangeBase;
212     }
213
214     /**
215      * Initialises the renderer. Here we calculate the Java2D y-coordinate for
216      * zero, since all the bars have their bases fixed at zero.
217      *
218      * @param g2 the graphics device.
219      * @param dataArea the area inside the axes.
220      * @param plot the plot.
221      * @param data the data.
222      * @param info an optional info collection object to return data back to the caller.
223      *
224      * @return The number of passes required by the renderer.
225      */

226     public XYItemRendererState initialise(Graphics2D JavaDoc g2,
227                                           Rectangle2D JavaDoc dataArea,
228                                           XYPlot plot,
229                                           XYDataset data,
230                                           PlotRenderingInfo info) {
231
232        return super.initialise(g2, dataArea, plot, data, info);
233
234     }
235
236
237     /**
238      * Draws the visual representation of a single data item.
239      *
240      * @param g2 the graphics device.
241      * @param state the renderer state.
242      * @param dataArea the area within which the data is being drawn.
243      * @param info collects information about the drawing.
244      * @param plot the plot (can be used to obtain standard color information etc).
245      * @param domainAxis the domain axis.
246      * @param rangeAxis the range axis.
247      * @param dataset the dataset.
248      * @param series the series index (zero-based).
249      * @param item the item index (zero-based).
250      * @param crosshairInfo information about crosshairs on a plot.
251      * @param pass the pass index.
252      */

253     public void drawItem(Graphics2D JavaDoc g2,
254                          XYItemRendererState state,
255                          Rectangle2D JavaDoc dataArea,
256                          PlotRenderingInfo info,
257                          XYPlot plot,
258                          ValueAxis domainAxis,
259                          ValueAxis rangeAxis,
260                          XYDataset dataset,
261                          int series,
262                          int item,
263                          CrosshairInfo crosshairInfo,
264                          int pass) {
265                              
266         // Get the item count for the series, so that we can know which is the end of the series.
267
int itemCount = dataset.getItemCount(series);
268
269         Paint JavaDoc paint = getItemPaint(series, item);
270         Stroke JavaDoc seriesStroke = getItemStroke(series, item);
271         g2.setPaint(paint);
272         g2.setStroke(seriesStroke);
273
274         // get the data point...
275
Number JavaDoc x1 = dataset.getXValue(series, item);
276         Number JavaDoc y1 = dataset.getYValue(series, item);
277         double x = x1.doubleValue();
278         double y = y1 == null ? this.rangeBase : y1.doubleValue();
279         double transX1 = domainAxis.translateValueToJava2D(x, dataArea,
280                                               plot.getDomainAxisEdge());
281         double transY1 = rangeAxis.translateValueToJava2D(y, dataArea,
282                                               plot.getRangeAxisEdge());
283                                                           
284         // avoid possible sun.dc.pr.PRException: endPath: bad path
285
transY1 = restrictValueToDataArea(transY1, plot, dataArea);
286
287         if (pArea == null && y1 != null) {
288
289             // Create a new Area for the series
290
pArea = new Polygon JavaDoc();
291         
292             // start from Y = rangeBase
293
double transY2 = rangeAxis.translateValueToJava2D(this.rangeBase, dataArea,
294                 plot.getRangeAxisEdge());
295         
296             // avoid possible sun.dc.pr.PRException: endPath: bad path
297
transY2 = restrictValueToDataArea(transY2, plot, dataArea);
298         
299             // The first point is (x, this.baseYValue)
300
if (plot.getOrientation() == PlotOrientation.VERTICAL) {
301                 pArea.addPoint((int) transX1, (int) transY2);
302             }
303             else if (plot.getOrientation() == PlotOrientation.HORIZONTAL) {
304                 pArea.addPoint((int) transY2, (int) transX1);
305             }
306         }
307
308         double transX0 = 0;
309         double transY0 = restrictValueToDataArea(this.rangeBase, plot, dataArea);
310         
311         Number JavaDoc x0 = null;
312         Number JavaDoc y0 = null;
313         if (item > 0) {
314             // get the previous data point...
315
x0 = dataset.getXValue(series, item - 1);
316             y0 = y1 == null ? null : dataset.getYValue(series, item - 1);
317
318             x = x0.doubleValue();
319             y = y0 == null ? this.rangeBase : y0.doubleValue();
320             transX0 = domainAxis.translateValueToJava2D(x, dataArea, plot.getDomainAxisEdge());
321             transY0 = rangeAxis.translateValueToJava2D(y, dataArea, plot.getRangeAxisEdge());
322
323             // avoid possible sun.dc.pr.PRException: endPath: bad path
324
transY0 = restrictValueToDataArea(transY0, plot, dataArea);
325                         
326             if (y1 == null) {
327                 // NULL value -> insert point on base line
328
// instead of 'step point'
329
transX1 = transX0;
330                 transY0 = transY1;
331             }
332             if (transY0 != transY1) {
333                 // not just a horizontal bar but need to perform a 'step'.
334
if (plot.getOrientation() == PlotOrientation.VERTICAL) {
335                     pArea.addPoint((int) transX1, (int) transY0);
336                 }
337                 else if (plot.getOrientation() == PlotOrientation.HORIZONTAL) {
338                     pArea.addPoint((int) transY0, (int) transX1);
339                 }
340             }
341         }
342
343         Shape JavaDoc shape = null;
344         if (y1 != null) {
345             // Add each point to Area (x, y)
346
if (plot.getOrientation() == PlotOrientation.VERTICAL) {
347                 pArea.addPoint((int) transX1, (int) transY1);
348             }
349             else if (plot.getOrientation() == PlotOrientation.HORIZONTAL) {
350                 pArea.addPoint((int) transY1, (int) transX1);
351             }
352
353             if (this.plotShapes) {
354                 shape = getItemShape(series, item);
355                 if (plot.getOrientation() == PlotOrientation.VERTICAL) {
356                     shape = createTransformedShape(shape, transX1, transY1);
357                 }
358                 else if (plot.getOrientation() == PlotOrientation.HORIZONTAL) {
359                     shape = createTransformedShape(shape, transY1, transX1);
360                 }
361                 if (shapesFilled)
362                     g2.fill(shape);
363                 else
364                     g2.draw(shape);
365             }
366             else {
367                 if (plot.getOrientation() == PlotOrientation.VERTICAL) {
368                     shape = new Rectangle2D.Double JavaDoc(transX1 - 2, transY1 - 2, 4.0, 4.0);
369                 }
370                 else if (plot.getOrientation() == PlotOrientation.HORIZONTAL) {
371                     shape = new Rectangle2D.Double JavaDoc(transY1 - 2, transX1 - 2, 4.0, 4.0);
372                 }
373             }
374         }
375
376         // Check if the item is the last item for the series or if it
377
// is a NULL value and number of items > 0. We can't draw an area for a single point.
378
if (this.plotArea && item > 0 && pArea != null && (item == (itemCount - 1) || y1 == null)) {
379
380             double transY2 = rangeAxis.translateValueToJava2D(this.rangeBase, dataArea,
381                                                               plot.getRangeAxisEdge());
382
383             // avoid possible sun.dc.pr.PRException: endPath: bad path
384
transY2 = restrictValueToDataArea(transY2, plot, dataArea);
385
386             if (plot.getOrientation() == PlotOrientation.VERTICAL) {
387                 // Add the last point (x,0)
388
pArea.addPoint((int) transX1, (int) transY2);
389             }
390             else if (plot.getOrientation() == PlotOrientation.HORIZONTAL) {
391                 // Add the last point (x,0)
392
pArea.addPoint((int) transY2, (int) transX1);
393             }
394
395             // fill the polygon
396
g2.fill(pArea);
397
398             // draw an outline around the Area.
399
if (showOutline) {
400                 g2.setStroke(plot.getOutlineStroke());
401                 g2.setPaint(plot.getOutlinePaint());
402                 g2.draw(pArea);
403             }
404
405             // start new area when needed (see above)
406
pArea = null;
407         }
408
409         // do we need to update the crosshair values?
410
if (y1 != null) {
411             if (plot.isDomainCrosshairLockedOnData()) {
412                 if (plot.isRangeCrosshairLockedOnData()) {
413                     // both axes
414
crosshairInfo.updateCrosshairPoint(x1.doubleValue(), y1.doubleValue(),
415                                                        transX1, transY1);
416                 }
417                 else {
418                     // just the horizontal axis...
419
crosshairInfo.updateCrosshairX(x1.doubleValue());
420
421                 }
422             }
423             else {
424                 if (plot.isRangeCrosshairLockedOnData()) {
425                     // just the vertical axis...
426
crosshairInfo.updateCrosshairY(y1.doubleValue());
427                 }
428             }
429         }
430
431         // collect entity and tool tip information...
432
if (state.getInfo() != null) {
433             EntityCollection entities = state.getInfo().getOwner().getEntityCollection();
434             if (entities != null && shape != null) {
435                 String JavaDoc tip = null;
436                 if (getToolTipGenerator() != null) {
437                     tip = getToolTipGenerator().generateToolTip(dataset, series, item);
438                 }
439                 String JavaDoc url = null;
440                 if (getURLGenerator() != null) {
441                     url = getURLGenerator().generateURL(dataset, series, item);
442                 }
443                 XYItemEntity entity = new XYItemEntity(shape, dataset, series, item, tip, url);
444                 entities.addEntity(entity);
445             }
446         }
447     }
448
449     /**
450      * Returns a clone of the renderer.
451      *
452      * @return A clone.
453      *
454      * @throws CloneNotSupportedException if the renderer cannot be cloned.
455      */

456     public Object JavaDoc clone() throws CloneNotSupportedException JavaDoc {
457         return super.clone();
458     }
459     
460     /**
461      * Private helper method which returns a value if it lies
462      * inside the visible dataArea and otherwise the corresponding
463      * coordinate on the border of the dataArea. The PlotOrientation
464      * is taken into account.
465      * Useful to avoid possible sun.dc.pr.PRException: endPath: bad path
466      * which occurs when trying to draw lines/shapes which in large part
467      * lie outside of the visible dataArea.
468      *
469      * @param value the value which shall be
470      * @param dataArea the area within which the data is being drawn.
471      * @param plot the plot (can be used to obtain standard color information etc).
472      * @return <code>double</code> value inside the data area.
473      */

474     private static double restrictValueToDataArea(double value, XYPlot plot, Rectangle2D JavaDoc dataArea) {
475         double min = 0;
476         double max = 0;
477         if (plot.getOrientation() == PlotOrientation.VERTICAL) {
478             min = dataArea.getMinY();
479             max = dataArea.getMaxY();
480         }
481         else if (plot.getOrientation() == PlotOrientation.HORIZONTAL) {
482             min = dataArea.getMinX();
483             max = dataArea.getMaxX();
484         }
485         if (value < min) {
486             value = min;
487         }
488         else if (value > max) {
489             value = max;
490         }
491         return value;
492     }
493
494 }
495
Popular Tags