001: /* ===========================================================
002: * JFreeChart : a free chart library for the Java(tm) platform
003: * ===========================================================
004: *
005: * (C) Copyright 2000-2007, by Object Refinery Limited and Contributors.
006: *
007: * Project Info: http://www.jfree.org/jfreechart/index.html
008: *
009: * This library is free software; you can redistribute it and/or modify it
010: * under the terms of the GNU Lesser General Public License as published by
011: * the Free Software Foundation; either version 2.1 of the License, or
012: * (at your option) any later version.
013: *
014: * This library is distributed in the hope that it will be useful, but
015: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
016: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
017: * License for more details.
018: *
019: * You should have received a copy of the GNU Lesser General Public
020: * License along with this library; if not, write to the Free Software
021: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
022: * USA.
023: *
024: * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
025: * in the United States and other countries.]
026: *
027: * -----------------
028: * AreaRenderer.java
029: * -----------------
030: * (C) Copyright 2002-2007, by Jon Iles and Contributors.
031: *
032: * Original Author: Jon Iles;
033: * Contributor(s): David Gilbert (for Object Refinery Limited);
034: * Christian W. Zuckschwerdt;
035: *
036: * $Id: AreaRenderer.java,v 1.6.2.9 2007/05/18 10:28:27 mungady Exp $
037: *
038: * Changes:
039: * --------
040: * 21-May-2002 : Version 1, contributed by John Iles (DG);
041: * 29-May-2002 : Now extends AbstractCategoryItemRenderer (DG);
042: * 11-Jun-2002 : Updated Javadoc comments (DG);
043: * 25-Jun-2002 : Removed unnecessary imports (DG);
044: * 01-Oct-2002 : Fixed errors reported by Checkstyle (DG);
045: * 10-Oct-2002 : Added constructors and basic entity support (DG);
046: * 24-Oct-2002 : Amendments for changes in CategoryDataset interface and
047: * CategoryToolTipGenerator interface (DG);
048: * 05-Nov-2002 : Replaced references to CategoryDataset with TableDataset (DG);
049: * 06-Nov-2002 : Renamed drawCategoryItem() --> drawItem() and now using axis
050: * for category spacing. Renamed AreaCategoryItemRenderer
051: * --> AreaRenderer (DG);
052: * 17-Jan-2003 : Moved plot classes into a separate package (DG);
053: * 25-Mar-2003 : Implemented Serializable (DG);
054: * 10-Apr-2003 : Changed CategoryDataset to KeyedValues2DDataset in
055: * drawItem() method (DG);
056: * 12-May-2003 : Modified to take into account the plot orientation (DG);
057: * 30-Jul-2003 : Modified entity constructor (CZ);
058: * 13-Aug-2003 : Implemented Cloneable (DG);
059: * 07-Oct-2003 : Added renderer state (DG);
060: * 05-Nov-2004 : Modified drawItem() signature (DG);
061: * 20-Apr-2005 : Apply tooltips and URLs to legend items (DG);
062: * 09-Jun-2005 : Use addItemEntity() method from superclass (DG);
063: * ------------- JFREECHART 1.0.x ---------------------------------------------
064: * 11-Oct-2006 : Fixed bug in equals() method (DG);
065: * 30-Nov-2006 : Added checks for series visibility (DG);
066: * 20-Apr-2007 : Updated getLegendItem() for renderer change (DG);
067: * 17-May-2007 : Set datasetIndex and seriesIndex in getLegendItem() (DG);
068: * 18-May-2007 : Set dataset and seriesKey for LegendItem (DG);
069: *
070: */
071:
072: package org.jfree.chart.renderer.category;
073:
074: import java.awt.Graphics2D;
075: import java.awt.Paint;
076: import java.awt.Shape;
077: import java.awt.Stroke;
078: import java.awt.geom.GeneralPath;
079: import java.awt.geom.Rectangle2D;
080: import java.io.Serializable;
081:
082: import org.jfree.chart.LegendItem;
083: import org.jfree.chart.axis.CategoryAxis;
084: import org.jfree.chart.axis.ValueAxis;
085: import org.jfree.chart.entity.EntityCollection;
086: import org.jfree.chart.event.RendererChangeEvent;
087: import org.jfree.chart.plot.CategoryPlot;
088: import org.jfree.chart.plot.PlotOrientation;
089: import org.jfree.chart.renderer.AreaRendererEndType;
090: import org.jfree.data.category.CategoryDataset;
091: import org.jfree.ui.RectangleEdge;
092: import org.jfree.util.PublicCloneable;
093:
094: /**
095: * A category item renderer that draws area charts. You can use this renderer
096: * with the {@link org.jfree.chart.plot.CategoryPlot} class.
097: */
098: public class AreaRenderer extends AbstractCategoryItemRenderer
099: implements Cloneable, PublicCloneable, Serializable {
100:
101: /** For serialization. */
102: private static final long serialVersionUID = -4231878281385812757L;
103:
104: /** A flag that controls how the ends of the areas are drawn. */
105: private AreaRendererEndType endType;
106:
107: /**
108: * Creates a new renderer.
109: */
110: public AreaRenderer() {
111: super ();
112: this .endType = AreaRendererEndType.TAPER;
113: }
114:
115: /**
116: * Returns a token that controls how the renderer draws the end points.
117: * The default value is {@link AreaRendererEndType#TAPER}.
118: *
119: * @return The end type (never <code>null</code>).
120: *
121: * @see #setEndType
122: */
123: public AreaRendererEndType getEndType() {
124: return this .endType;
125: }
126:
127: /**
128: * Sets a token that controls how the renderer draws the end points, and
129: * sends a {@link RendererChangeEvent} to all registered listeners.
130: *
131: * @param type the end type (<code>null</code> not permitted).
132: *
133: * @see #getEndType()
134: */
135: public void setEndType(AreaRendererEndType type) {
136: if (type == null) {
137: throw new IllegalArgumentException("Null 'type' argument.");
138: }
139: this .endType = type;
140: notifyListeners(new RendererChangeEvent(this ));
141: }
142:
143: /**
144: * Returns a legend item for a series.
145: *
146: * @param datasetIndex the dataset index (zero-based).
147: * @param series the series index (zero-based).
148: *
149: * @return The legend item.
150: */
151: public LegendItem getLegendItem(int datasetIndex, int series) {
152:
153: // if there is no plot, there is no dataset to access...
154: CategoryPlot cp = getPlot();
155: if (cp == null) {
156: return null;
157: }
158:
159: // check that a legend item needs to be displayed...
160: if (!isSeriesVisible(series)
161: || !isSeriesVisibleInLegend(series)) {
162: return null;
163: }
164:
165: CategoryDataset dataset = cp.getDataset(datasetIndex);
166: String label = getLegendItemLabelGenerator().generateLabel(
167: dataset, series);
168: String description = label;
169: String toolTipText = null;
170: if (getLegendItemToolTipGenerator() != null) {
171: toolTipText = getLegendItemToolTipGenerator()
172: .generateLabel(dataset, series);
173: }
174: String urlText = null;
175: if (getLegendItemURLGenerator() != null) {
176: urlText = getLegendItemURLGenerator().generateLabel(
177: dataset, series);
178: }
179: Shape shape = new Rectangle2D.Double(-4.0, -4.0, 8.0, 8.0);
180: Paint paint = lookupSeriesPaint(series);
181: Paint outlinePaint = lookupSeriesOutlinePaint(series);
182: Stroke outlineStroke = lookupSeriesOutlineStroke(series);
183:
184: LegendItem result = new LegendItem(label, description,
185: toolTipText, urlText, shape, paint, outlineStroke,
186: outlinePaint);
187: result.setDataset(dataset);
188: result.setDatasetIndex(datasetIndex);
189: result.setSeriesKey(dataset.getRowKey(series));
190: result.setSeriesIndex(series);
191: return result;
192:
193: }
194:
195: /**
196: * Draw a single data item.
197: *
198: * @param g2 the graphics device.
199: * @param state the renderer state.
200: * @param dataArea the data plot area.
201: * @param plot the plot.
202: * @param domainAxis the domain axis.
203: * @param rangeAxis the range axis.
204: * @param dataset the dataset.
205: * @param row the row index (zero-based).
206: * @param column the column index (zero-based).
207: * @param pass the pass index.
208: */
209: public void drawItem(Graphics2D g2,
210: CategoryItemRendererState state, Rectangle2D dataArea,
211: CategoryPlot plot, CategoryAxis domainAxis,
212: ValueAxis rangeAxis, CategoryDataset dataset, int row,
213: int column, int pass) {
214:
215: // do nothing if item is not visible
216: if (!getItemVisible(row, column)) {
217: return;
218: }
219:
220: // plot non-null values only...
221: Number value = dataset.getValue(row, column);
222: if (value != null) {
223: PlotOrientation orientation = plot.getOrientation();
224: RectangleEdge axisEdge = plot.getDomainAxisEdge();
225: int count = dataset.getColumnCount();
226: float x0 = (float) domainAxis.getCategoryStart(column,
227: count, dataArea, axisEdge);
228: float x1 = (float) domainAxis.getCategoryMiddle(column,
229: count, dataArea, axisEdge);
230: float x2 = (float) domainAxis.getCategoryEnd(column, count,
231: dataArea, axisEdge);
232:
233: x0 = Math.round(x0);
234: x1 = Math.round(x1);
235: x2 = Math.round(x2);
236:
237: if (this .endType == AreaRendererEndType.TRUNCATE) {
238: if (column == 0) {
239: x0 = x1;
240: } else if (column == getColumnCount() - 1) {
241: x2 = x1;
242: }
243: }
244:
245: double yy1 = value.doubleValue();
246:
247: double yy0 = 0.0;
248: if (column > 0) {
249: Number n0 = dataset.getValue(row, column - 1);
250: if (n0 != null) {
251: yy0 = (n0.doubleValue() + yy1) / 2.0;
252: }
253: }
254:
255: double yy2 = 0.0;
256: if (column < dataset.getColumnCount() - 1) {
257: Number n2 = dataset.getValue(row, column + 1);
258: if (n2 != null) {
259: yy2 = (n2.doubleValue() + yy1) / 2.0;
260: }
261: }
262:
263: RectangleEdge edge = plot.getRangeAxisEdge();
264: float y0 = (float) rangeAxis.valueToJava2D(yy0, dataArea,
265: edge);
266: float y1 = (float) rangeAxis.valueToJava2D(yy1, dataArea,
267: edge);
268: float y2 = (float) rangeAxis.valueToJava2D(yy2, dataArea,
269: edge);
270: float yz = (float) rangeAxis.valueToJava2D(0.0, dataArea,
271: edge);
272:
273: g2.setPaint(getItemPaint(row, column));
274: g2.setStroke(getItemStroke(row, column));
275:
276: GeneralPath area = new GeneralPath();
277:
278: if (orientation == PlotOrientation.VERTICAL) {
279: area.moveTo(x0, yz);
280: area.lineTo(x0, y0);
281: area.lineTo(x1, y1);
282: area.lineTo(x2, y2);
283: area.lineTo(x2, yz);
284: } else if (orientation == PlotOrientation.HORIZONTAL) {
285: area.moveTo(yz, x0);
286: area.lineTo(y0, x0);
287: area.lineTo(y1, x1);
288: area.lineTo(y2, x2);
289: area.lineTo(yz, x2);
290: }
291: area.closePath();
292:
293: g2.setPaint(getItemPaint(row, column));
294: g2.fill(area);
295:
296: // draw the item labels if there are any...
297: if (isItemLabelVisible(row, column)) {
298: drawItemLabel(g2, orientation, dataset, row, column,
299: x1, y1, (value.doubleValue() < 0.0));
300: }
301:
302: // add an item entity, if this information is being collected
303: EntityCollection entities = state.getEntityCollection();
304: if (entities != null) {
305: addItemEntity(entities, dataset, row, column, area);
306: }
307: }
308:
309: }
310:
311: /**
312: * Tests this instance for equality with an arbitrary object.
313: *
314: * @param obj the object to test (<code>null</code> permitted).
315: *
316: * @return A boolean.
317: */
318: public boolean equals(Object obj) {
319: if (obj == this ) {
320: return true;
321: }
322: if (!(obj instanceof AreaRenderer)) {
323: return false;
324: }
325: AreaRenderer that = (AreaRenderer) obj;
326: if (!this .endType.equals(that.endType)) {
327: return false;
328: }
329: return super .equals(obj);
330: }
331:
332: /**
333: * Returns an independent copy of the renderer.
334: *
335: * @return A clone.
336: *
337: * @throws CloneNotSupportedException should not happen.
338: */
339: public Object clone() throws CloneNotSupportedException {
340: return super.clone();
341: }
342:
343: }
|