KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jfree > chart > renderer > xy > XYAreaRenderer


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  * XYAreaRenderer.java
29  * -------------------
30  * (C) Copyright 2002-2005, by Hari and Contributors.
31  *
32  * Original Author: Hari (ourhari@hotmail.com);
33  * Contributor(s): David Gilbert (for Object Refinery Limited);
34  * Richard Atkinson;
35  * Christian W. Zuckschwerdt;
36  *
37  * $Id: XYAreaRenderer.java,v 1.12.2.5 2005/12/22 15:53:05 mungady Exp $
38  *
39  * Changes:
40  * --------
41  * 03-Apr-2002 : Version 1, contributed by Hari. This class is based on the
42  * StandardXYItemRenderer class (DG);
43  * 09-Apr-2002 : Removed the translated zero from the drawItem method -
44  * overridden the initialise() method to calculate it (DG);
45  * 30-May-2002 : Added tool tip generator to constructor to match super
46  * class (DG);
47  * 25-Jun-2002 : Removed unnecessary local variable (DG);
48  * 05-Aug-2002 : Small modification to drawItem method to support URLs for HTML
49  * image maps (RA);
50  * 01-Oct-2002 : Fixed errors reported by Checkstyle (DG);
51  * 07-Nov-2002 : Renamed AreaXYItemRenderer --> XYAreaRenderer (DG);
52  * 25-Mar-2003 : Implemented Serializable (DG);
53  * 01-May-2003 : Modified drawItem() method signature (DG);
54  * 27-Jul-2003 : Made line and polygon properties protected rather than
55  * private (RA);
56  * 30-Jul-2003 : Modified entity constructor (CZ);
57  * 20-Aug-2003 : Implemented Cloneable and PublicCloneable (DG);
58  * 16-Sep-2003 : Changed ChartRenderingInfo --> PlotRenderingInfo (DG);
59  * 07-Oct-2003 : Added renderer state (DG);
60  * 08-Dec-2003 : Modified hotspot for chart entity (DG);
61  * 10-Feb-2004 : Changed the drawItem() method to make cut-and-paste overriding
62  * easier. Also moved state class into this class (DG);
63  * 25-Feb-2004 : Replaced CrosshairInfo with CrosshairState. Renamed
64  * XYToolTipGenerator --> XYItemLabelGenerator (DG);
65  * 15-Jul-2004 : Switched getX() with getXValue() and getY() with
66  * getYValue() (DG);
67  * 11-Nov-2004 : Now uses ShapeUtilities to translate shapes (DG);
68  * 19-Jan-2005 : Now accesses primitives only from dataset (DG);
69  * 21-Mar-2005 : Override getLegendItem() and equals() methods (DG);
70  * 20-Apr-2005 : Use generators for legend tooltips and URLs (DG);
71  *
72  */

73
74 package org.jfree.chart.renderer.xy;
75
76 import java.awt.Graphics2D JavaDoc;
77 import java.awt.Paint JavaDoc;
78 import java.awt.Polygon JavaDoc;
79 import java.awt.Shape JavaDoc;
80 import java.awt.Stroke JavaDoc;
81 import java.awt.geom.GeneralPath JavaDoc;
82 import java.awt.geom.Line2D JavaDoc;
83 import java.awt.geom.Rectangle2D JavaDoc;
84 import java.io.IOException JavaDoc;
85 import java.io.ObjectInputStream JavaDoc;
86 import java.io.ObjectOutputStream JavaDoc;
87 import java.io.Serializable JavaDoc;
88
89 import org.jfree.chart.LegendItem;
90 import org.jfree.chart.axis.ValueAxis;
91 import org.jfree.chart.entity.EntityCollection;
92 import org.jfree.chart.entity.XYItemEntity;
93 import org.jfree.chart.event.RendererChangeEvent;
94 import org.jfree.chart.labels.XYSeriesLabelGenerator;
95 import org.jfree.chart.labels.XYToolTipGenerator;
96 import org.jfree.chart.plot.CrosshairState;
97 import org.jfree.chart.plot.PlotOrientation;
98 import org.jfree.chart.plot.PlotRenderingInfo;
99 import org.jfree.chart.plot.XYPlot;
100 import org.jfree.chart.urls.XYURLGenerator;
101 import org.jfree.data.xy.XYDataset;
102 import org.jfree.io.SerialUtilities;
103 import org.jfree.util.PublicCloneable;
104 import org.jfree.util.ShapeUtilities;
105
106 /**
107  * Area item renderer for an {@link XYPlot}. This class can draw (a) shapes at
108  * each point, or (b) lines between points, or (c) both shapes and lines,
109  * or (d) filled areas, or (e) filled areas and shapes.
110  */

111 public class XYAreaRenderer extends AbstractXYItemRenderer
112                             implements XYItemRenderer,
113                                        Cloneable JavaDoc,
114                                        PublicCloneable,
115                                        Serializable JavaDoc {
116
117     /** For serialization. */
118     private static final long serialVersionUID = -4481971353973876747L;
119     
120     /**
121      * A state object used by this renderer.
122      */

123     static class XYAreaRendererState extends XYItemRendererState {
124         
125         /** Working storage for the area under one series. */
126         public Polygon JavaDoc area;
127         
128         /** Working line that can be recycled. */
129         public Line2D JavaDoc line;
130         
131         /**
132          * Creates a new state.
133          *
134          * @param info the plot rendering info.
135          */

136         public XYAreaRendererState(PlotRenderingInfo info) {
137             super(info);
138             this.area = new Polygon JavaDoc();
139             this.line = new Line2D.Double JavaDoc();
140         }
141         
142     }
143     
144     /** Useful constant for specifying the type of rendering (shapes only). */
145     public static final int SHAPES = 1;
146
147     /** Useful constant for specifying the type of rendering (lines only). */
148     public static final int LINES = 2;
149
150     /**
151      * Useful constant for specifying the type of rendering (shapes and lines).
152      */

153     public static final int SHAPES_AND_LINES = 3;
154
155     /** Useful constant for specifying the type of rendering (area only). */
156     public static final int AREA = 4;
157
158     /**
159      * Useful constant for specifying the type of rendering (area and shapes).
160      */

161     public static final int AREA_AND_SHAPES = 5;
162
163     /** A flag indicating whether or not shapes are drawn at each XY point. */
164     private boolean plotShapes;
165
166     /** A flag indicating whether or not lines are drawn between XY points. */
167     private boolean plotLines;
168
169     /** A flag indicating whether or not Area are drawn at each XY point. */
170     private boolean plotArea;
171
172     /** A flag that controls whether or not the outline is shown. */
173     private boolean showOutline;
174
175     /**
176      * The shape used to represent an area in each legend item (this should
177      * never be <code>null</code>).
178      */

179     private transient Shape JavaDoc legendArea;
180
181     /**
182      * Constructs a new renderer.
183      */

184     public XYAreaRenderer() {
185         this(AREA);
186     }
187
188     /**
189      * Constructs a new renderer.
190      *
191      * @param type the type of the renderer.
192      */

193     public XYAreaRenderer(int type) {
194         this(type, null, null);
195     }
196
197     /**
198      * Constructs a new renderer.
199      * <p>
200      * To specify the type of renderer, use one of the constants: SHAPES, LINES,
201      * SHAPES_AND_LINES, AREA or AREA_AND_SHAPES.
202      *
203      * @param type the type of renderer.
204      * @param toolTipGenerator the tool tip generator to use
205      * (<code>null</code> permitted).
206      * @param urlGenerator the URL generator (<code>null</code> permitted).
207      */

208     public XYAreaRenderer(int type, XYToolTipGenerator toolTipGenerator,
209                           XYURLGenerator urlGenerator) {
210
211         super();
212         setBaseToolTipGenerator(toolTipGenerator);
213         setURLGenerator(urlGenerator);
214
215         if (type == SHAPES) {
216             this.plotShapes = true;
217         }
218         if (type == LINES) {
219             this.plotLines = true;
220         }
221         if (type == SHAPES_AND_LINES) {
222             this.plotShapes = true;
223             this.plotLines = true;
224         }
225         if (type == AREA) {
226             this.plotArea = true;
227         }
228         if (type == AREA_AND_SHAPES) {
229             this.plotArea = true;
230             this.plotShapes = true;
231         }
232         this.showOutline = false;
233         GeneralPath JavaDoc area = new GeneralPath JavaDoc();
234         area.moveTo(0.0f, -4.0f);
235         area.lineTo(3.0f, -2.0f);
236         area.lineTo(4.0f, 4.0f);
237         area.lineTo(-4.0f, 4.0f);
238         area.lineTo(-3.0f, -2.0f);
239         area.closePath();
240         this.legendArea = area;
241
242     }
243
244     /**
245      * Returns a flag that controls whether or not outlines of the areas are
246      * drawn.
247      *
248      * @return The flag.
249      */

250     public boolean isOutline() {
251         return this.showOutline;
252     }
253
254     /**
255      * Sets a flag that controls whether or not outlines of the areas are drawn.
256      *
257      * @param show the flag.
258      */

259     public void setOutline(boolean show) {
260         this.showOutline = show;
261     }
262
263     /**
264      * Returns true if shapes are being plotted by the renderer.
265      *
266      * @return <code>true</code> if shapes are being plotted by the renderer.
267      */

268     public boolean getPlotShapes() {
269         return this.plotShapes;
270     }
271
272     /**
273      * Returns true if lines are being plotted by the renderer.
274      *
275      * @return <code>true</code> if lines are being plotted by the renderer.
276      */

277     public boolean getPlotLines() {
278         return this.plotLines;
279     }
280
281     /**
282      * Returns true if Area is being plotted by the renderer.
283      *
284      * @return <code>true</code> if Area is being plotted by the renderer.
285      */

286     public boolean getPlotArea() {
287         return this.plotArea;
288     }
289
290     /**
291      * Returns the shape used to represent an area in the legend.
292      *
293      * @return The legend area (never <code>null</code>).
294      */

295     public Shape JavaDoc getLegendArea() {
296         return this.legendArea;
297     }
298     
299     /**
300      * Sets the shape used as an area in each legend item and sends a
301      * {@link RendererChangeEvent} to all registered listeners.
302      *
303      * @param area the area (<code>null</code> not permitted).
304      */

305     public void setLegendArea(Shape JavaDoc area) {
306         if (area == null) {
307             throw new IllegalArgumentException JavaDoc("Null 'area' argument.");
308         }
309         this.legendArea = area;
310         notifyListeners(new RendererChangeEvent(this));
311     }
312
313     /**
314      * Initialises the renderer and returns a state object that should be
315      * passed to all subsequent calls to the drawItem() method.
316      *
317      * @param g2 the graphics device.
318      * @param dataArea the area inside the axes.
319      * @param plot the plot.
320      * @param data the data.
321      * @param info an optional info collection object to return data back to
322      * the caller.
323      *
324      * @return A state object for use by the renderer.
325      */

326     public XYItemRendererState initialise(Graphics2D JavaDoc g2, Rectangle2D JavaDoc dataArea,
327             XYPlot plot, XYDataset data, PlotRenderingInfo info) {
328         XYAreaRendererState state = new XYAreaRendererState(info);
329         return state;
330     }
331
332     /**
333      * Returns a default legend item for the specified series. Subclasses
334      * should override this method to generate customised items.
335      *
336      * @param datasetIndex the dataset index (zero-based).
337      * @param series the series index (zero-based).
338      *
339      * @return A legend item for the series.
340      */

341     public LegendItem getLegendItem(int datasetIndex, int series) {
342         LegendItem result = null;
343         XYPlot xyplot = getPlot();
344         if (xyplot != null) {
345             XYDataset dataset = xyplot.getDataset(datasetIndex);
346             if (dataset != null) {
347                 XYSeriesLabelGenerator lg = getLegendItemLabelGenerator();
348                 String JavaDoc label = lg.generateLabel(dataset, series);
349                 String JavaDoc description = label;
350                 String JavaDoc toolTipText = null;
351                 if (getLegendItemToolTipGenerator() != null) {
352                     toolTipText = getLegendItemToolTipGenerator().generateLabel(
353                             dataset, series);
354                 }
355                 String JavaDoc urlText = null;
356                 if (getLegendItemURLGenerator() != null) {
357                     urlText = getLegendItemURLGenerator().generateLabel(
358                             dataset, series);
359                 }
360                 Paint JavaDoc paint = getSeriesPaint(series);
361                 result = new LegendItem(label, description, toolTipText,
362                         urlText, this.legendArea, paint);
363             }
364         }
365         return result;
366     }
367
368     /**
369      * Draws the visual representation of a single data item.
370      *
371      * @param g2 the graphics device.
372      * @param state the renderer state.
373      * @param dataArea the area within which the data is being drawn.
374      * @param info collects information about the drawing.
375      * @param plot the plot (can be used to obtain standard color information
376      * etc).
377      * @param domainAxis the domain axis.
378      * @param rangeAxis the range axis.
379      * @param dataset the dataset.
380      * @param series the series index (zero-based).
381      * @param item the item index (zero-based).
382      * @param crosshairState crosshair information for the plot
383      * (<code>null</code> permitted).
384      * @param pass the pass index.
385      */

386     public void drawItem(Graphics2D JavaDoc g2, XYItemRendererState state,
387             Rectangle2D JavaDoc dataArea, PlotRenderingInfo info, XYPlot plot,
388             ValueAxis domainAxis, ValueAxis rangeAxis, XYDataset dataset,
389             int series, int item, CrosshairState crosshairState, int pass) {
390         
391         if (!getItemVisible(series, item)) {
392             return;
393         }
394         XYAreaRendererState areaState = (XYAreaRendererState) state;
395         
396         // get the data point...
397
double x1 = dataset.getXValue(series, item);
398         double y1 = dataset.getYValue(series, item);
399         if (Double.isNaN(y1)) {
400             y1 = 0.0;
401         }
402         double transX1 = domainAxis.valueToJava2D(x1, dataArea,
403                 plot.getDomainAxisEdge());
404         double transY1 = rangeAxis.valueToJava2D(y1, dataArea,
405                 plot.getRangeAxisEdge());
406         
407         // get the previous point and the next point so we can calculate a
408
// "hot spot" for the area (used by the chart entity)...
409
int itemCount = dataset.getItemCount(series);
410         double x0 = dataset.getXValue(series, Math.max(item - 1, 0));
411         double y0 = dataset.getYValue(series, Math.max(item - 1, 0));
412         if (Double.isNaN(y0)) {
413             y0 = 0.0;
414         }
415         double transX0 = domainAxis.valueToJava2D(x0, dataArea,
416                 plot.getDomainAxisEdge());
417         double transY0 = rangeAxis.valueToJava2D(y0, dataArea,
418                 plot.getRangeAxisEdge());
419         
420         double x2 = dataset.getXValue(series, Math.min(item + 1,
421                 itemCount - 1));
422         double y2 = dataset.getYValue(series, Math.min(item + 1,
423                 itemCount - 1));
424         if (Double.isNaN(y2)) {
425             y2 = 0.0;
426         }
427         double transX2 = domainAxis.valueToJava2D(x2, dataArea,
428                 plot.getDomainAxisEdge());
429         double transY2 = rangeAxis.valueToJava2D(y2, dataArea,
430                 plot.getRangeAxisEdge());
431         
432         double transZero = rangeAxis.valueToJava2D(0.0, dataArea,
433                 plot.getRangeAxisEdge());
434         Polygon JavaDoc hotspot = null;
435         if (plot.getOrientation() == PlotOrientation.HORIZONTAL) {
436             hotspot = new Polygon JavaDoc();
437             hotspot.addPoint((int) transZero,
438                     (int) ((transX0 + transX1) / 2.0));
439             hotspot.addPoint((int) ((transY0 + transY1) / 2.0),
440                     (int) ((transX0 + transX1) / 2.0));
441             hotspot.addPoint((int) transY1, (int) transX1);
442             hotspot.addPoint((int) ((transY1 + transY2) / 2.0),
443                     (int) ((transX1 + transX2) / 2.0));
444             hotspot.addPoint((int) transZero,
445                     (int) ((transX1 + transX2) / 2.0));
446         }
447         else { // vertical orientation
448
hotspot = new Polygon JavaDoc();
449             hotspot.addPoint((int) ((transX0 + transX1) / 2.0),
450                     (int) transZero);
451             hotspot.addPoint((int) ((transX0 + transX1) / 2.0),
452                     (int) ((transY0 + transY1) / 2.0));
453             hotspot.addPoint((int) transX1, (int) transY1);
454             hotspot.addPoint((int) ((transX1 + transX2) / 2.0),
455                     (int) ((transY1 + transY2) / 2.0));
456             hotspot.addPoint((int) ((transX1 + transX2) / 2.0),
457                     (int) transZero);
458         }
459         
460         if (item == 0) { // create a new area polygon for the series
461
areaState.area = new Polygon JavaDoc();
462             // the first point is (x, 0)
463
double zero = rangeAxis.valueToJava2D(0.0, dataArea,
464                     plot.getRangeAxisEdge());
465             if (plot.getOrientation() == PlotOrientation.VERTICAL) {
466                 areaState.area.addPoint((int) transX1, (int) zero);
467             }
468             else if (plot.getOrientation() == PlotOrientation.HORIZONTAL) {
469                 areaState.area.addPoint((int) zero, (int) transX1);
470             }
471         }
472
473         // Add each point to Area (x, y)
474
if (plot.getOrientation() == PlotOrientation.VERTICAL) {
475             areaState.area.addPoint((int) transX1, (int) transY1);
476         }
477         else if (plot.getOrientation() == PlotOrientation.HORIZONTAL) {
478             areaState.area.addPoint((int) transY1, (int) transX1);
479         }
480         
481         PlotOrientation orientation = plot.getOrientation();
482         Paint JavaDoc paint = getItemPaint(series, item);
483         Stroke JavaDoc stroke = getItemStroke(series, item);
484         g2.setPaint(paint);
485         g2.setStroke(stroke);
486         
487         Shape JavaDoc shape = null;
488         if (getPlotShapes()) {
489             shape = getItemShape(series, item);
490             if (orientation == PlotOrientation.VERTICAL) {
491                 shape = ShapeUtilities.createTranslatedShape(shape, transX1,
492                         transY1);
493             }
494             else if (orientation == PlotOrientation.HORIZONTAL) {
495                 shape = ShapeUtilities.createTranslatedShape(shape, transY1,
496                         transX1);
497             }
498             g2.draw(shape);
499         }
500
501         if (getPlotLines()) {
502             if (item > 0) {
503                 if (plot.getOrientation() == PlotOrientation.VERTICAL) {
504                     areaState.line.setLine(transX0, transY0, transX1, transY1);
505                 }
506                 else if (plot.getOrientation() == PlotOrientation.HORIZONTAL) {
507                     areaState.line.setLine(transY0, transX0, transY1, transX1);
508                 }
509                 g2.draw(areaState.line);
510             }
511         }
512
513         // Check if the item is the last item for the series.
514
// and number of items > 0. We can't draw an area for a single point.
515
if (getPlotArea() && item > 0 && item == (itemCount - 1)) {
516
517             if (orientation == PlotOrientation.VERTICAL) {
518                 // Add the last point (x,0)
519
areaState.area.addPoint((int) transX1, (int) transZero);
520             }
521             else if (orientation == PlotOrientation.HORIZONTAL) {
522                 // Add the last point (x,0)
523
areaState.area.addPoint((int) transZero, (int) transX1);
524             }
525
526             g2.fill(areaState.area);
527
528             // draw an outline around the Area.
529
if (isOutline()) {
530                 g2.setStroke(getItemOutlineStroke(series, item));
531                 g2.setPaint(getItemOutlinePaint(series, item));
532                 g2.draw(areaState.area);
533             }
534         }
535
536         updateCrosshairValues(
537             crosshairState, x1, y1, transX1, transY1, orientation
538         );
539         
540         // collect entity and tool tip information...
541
if (state.getInfo() != null) {
542             EntityCollection entities = state.getEntityCollection();
543             if (entities != null && hotspot != null) {
544                 String JavaDoc tip = null;
545                 XYToolTipGenerator generator
546                     = getToolTipGenerator(series, item);
547                 if (generator != null) {
548                     tip = generator.generateToolTip(dataset, series, item);
549                 }
550                 String JavaDoc url = null;
551                 if (getURLGenerator() != null) {
552                     url = getURLGenerator().generateURL(dataset, series, item);
553                 }
554                 XYItemEntity entity = new XYItemEntity(hotspot, dataset,
555                         series, item, tip, url);
556                 entities.add(entity);
557             }
558         }
559
560     }
561
562     /**
563      * Returns a clone of the renderer.
564      *
565      * @return A clone.
566      *
567      * @throws CloneNotSupportedException if the renderer cannot be cloned.
568      */

569     public Object JavaDoc clone() throws CloneNotSupportedException JavaDoc {
570         return super.clone();
571     }
572     
573     /**
574      * Tests this renderer for equality with an arbitrary object.
575      *
576      * @param obj the object (<code>null</code> permitted).
577      *
578      * @return A boolean.
579      */

580     public boolean equals(Object JavaDoc obj) {
581         if (obj == this) {
582             return true;
583         }
584         if (!(obj instanceof XYAreaRenderer)) {
585             return false;
586         }
587         XYAreaRenderer that = (XYAreaRenderer) obj;
588         if (this.plotArea != that.plotArea) {
589             return false;
590         }
591         if (this.plotLines != that.plotLines) {
592             return false;
593         }
594         if (this.plotShapes != that.plotShapes) {
595             return false;
596         }
597         if (this.showOutline != that.showOutline) {
598             return false;
599         }
600         if (!ShapeUtilities.equal(this.legendArea, that.legendArea)) {
601             return false;
602         }
603         return true;
604     }
605     
606     /**
607      * Provides serialization support.
608      *
609      * @param stream the input stream.
610      *
611      * @throws IOException if there is an I/O error.
612      * @throws ClassNotFoundException if there is a classpath problem.
613      */

614     private void readObject(ObjectInputStream JavaDoc stream)
615             throws IOException JavaDoc, ClassNotFoundException JavaDoc {
616         stream.defaultReadObject();
617         this.legendArea = SerialUtilities.readShape(stream);
618     }
619     
620     /**
621      * Provides serialization support.
622      *
623      * @param stream the output stream.
624      *
625      * @throws IOException if there is an I/O error.
626      */

627     private void writeObject(ObjectOutputStream JavaDoc stream) throws IOException JavaDoc {
628         stream.defaultWriteObject();
629         SerialUtilities.writeShape(this.legendArea, stream);
630     }
631 }
632
Popular Tags