Frames | No Frames |
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: * StackedAreaRenderer.java 29: * ------------------------ 30: * (C) Copyright 2002-2005, by Dan Rivett (d.rivett@ukonline.co.uk) and 31: * Contributors. 32: * 33: * Original Author: Dan Rivett (adapted from AreaCategoryItemRenderer); 34: * Contributor(s): Jon Iles; 35: * David Gilbert (for Object Refinery Limited); 36: * Christian W. Zuckschwerdt; 37: * 38: * $Id: StackedAreaRenderer.java,v 1.6.2.2 2005/10/25 20:54:16 mungady Exp $ 39: * 40: * Changes: 41: * -------- 42: * 20-Sep-2002 : Version 1, contributed by Dan Rivett; 43: * 24-Oct-2002 : Amendments for changes in CategoryDataset interface and 44: * CategoryToolTipGenerator interface (DG); 45: * 01-Nov-2002 : Added tooltips (DG); 46: * 06-Nov-2002 : Renamed drawCategoryItem() --> drawItem() and now using axis 47: * for category spacing. Renamed StackedAreaCategoryItemRenderer 48: * --> StackedAreaRenderer (DG); 49: * 26-Nov-2002 : Switched CategoryDataset --> TableDataset (DG); 50: * 26-Nov-2002 : Replaced isStacked() method with getRangeType() method (DG); 51: * 17-Jan-2003 : Moved plot classes to a separate package (DG); 52: * 25-Mar-2003 : Implemented Serializable (DG); 53: * 13-May-2003 : Modified to take into account the plot orientation (DG); 54: * 30-Jul-2003 : Modified entity constructor (CZ); 55: * 07-Oct-2003 : Added renderer state (DG); 56: * 29-Apr-2004 : Added getRangeExtent() override (DG); 57: * 05-Nov-2004 : Modified drawItem() signature (DG); 58: * 07-Jan-2005 : Renamed getRangeExtent() --> findRangeBounds() (DG); 59: * 60: */ 61: 62: package org.jfree.chart.renderer.category; 63: 64: import java.awt.Graphics2D; 65: import java.awt.Polygon; 66: import java.awt.Shape; 67: import java.awt.geom.Rectangle2D; 68: import java.io.Serializable; 69: 70: import org.jfree.chart.axis.CategoryAxis; 71: import org.jfree.chart.axis.ValueAxis; 72: import org.jfree.chart.entity.EntityCollection; 73: import org.jfree.chart.plot.CategoryPlot; 74: import org.jfree.chart.plot.PlotOrientation; 75: import org.jfree.data.Range; 76: import org.jfree.data.category.CategoryDataset; 77: import org.jfree.data.general.DatasetUtilities; 78: import org.jfree.ui.RectangleEdge; 79: import org.jfree.util.PublicCloneable; 80: 81: /** 82: * A renderer that draws stacked area charts for a 83: * {@link org.jfree.chart.plot.CategoryPlot}. 84: * 85: * @author Dan Rivett 86: */ 87: public class StackedAreaRenderer extends AreaRenderer 88: implements Cloneable, PublicCloneable, 89: Serializable { 90: 91: /** For serialization. */ 92: private static final long serialVersionUID = -3595635038460823663L; 93: 94: /** 95: * Creates a new renderer. 96: */ 97: public StackedAreaRenderer() { 98: super(); 99: } 100: 101: /** 102: * Returns the range of values the renderer requires to display all the 103: * items from the specified dataset. 104: * 105: * @param dataset the dataset (<code>null</code> not permitted). 106: * 107: * @return The range (or <code>null</code> if the dataset is empty). 108: */ 109: public Range findRangeBounds(CategoryDataset dataset) { 110: return DatasetUtilities.findStackedRangeBounds(dataset); 111: } 112: 113: /** 114: * Draw a single data item. 115: * 116: * @param g2 the graphics device. 117: * @param state the renderer state. 118: * @param dataArea the data plot area. 119: * @param plot the plot. 120: * @param domainAxis the domain axis. 121: * @param rangeAxis the range axis. 122: * @param dataset the data. 123: * @param row the row index (zero-based). 124: * @param column the column index (zero-based). 125: * @param pass the pass index. 126: */ 127: public void drawItem(Graphics2D g2, 128: CategoryItemRendererState state, 129: Rectangle2D dataArea, 130: CategoryPlot plot, 131: CategoryAxis domainAxis, 132: ValueAxis rangeAxis, 133: CategoryDataset dataset, 134: int row, 135: int column, 136: int pass) { 137: 138: // plot non-null values... 139: Number value = dataset.getValue(row, column); 140: if (value == null) { 141: return; 142: } 143: 144: // leave the y values (y1, y0) untranslated as it is going to be be 145: // stacked up later by previous series values, after this it will be 146: // translated. 147: double x1 = domainAxis.getCategoryMiddle( 148: column, getColumnCount(), dataArea, plot.getDomainAxisEdge() 149: ); 150: double y1 = 0.0; // calculate later 151: double y1Untranslated = value.doubleValue(); 152: 153: g2.setPaint(getItemPaint(row, column)); 154: g2.setStroke(getItemStroke(row, column)); 155: 156: if (column != 0) { 157: 158: Number previousValue = dataset.getValue(row, column - 1); 159: if (previousValue != null) { 160: 161: double x0 = domainAxis.getCategoryMiddle( 162: column - 1, getColumnCount(), dataArea, 163: plot.getDomainAxisEdge() 164: ); 165: double y0Untranslated = previousValue.doubleValue(); 166: 167: // Get the previous height, but this will be different for both 168: // y0 and y1 as the previous series values could differ. 169: double previousHeightx0Untranslated 170: = getPreviousHeight(dataset, row, column - 1); 171: double previousHeightx1Untranslated 172: = getPreviousHeight(dataset, row, column); 173: 174: // Now stack the current y values on top of the previous values. 175: y0Untranslated += previousHeightx0Untranslated; 176: y1Untranslated += previousHeightx1Untranslated; 177: 178: // Now translate the previous heights 179: RectangleEdge location = plot.getRangeAxisEdge(); 180: double previousHeightx0 = rangeAxis.valueToJava2D( 181: previousHeightx0Untranslated, dataArea, location 182: ); 183: double previousHeightx1 = rangeAxis.valueToJava2D( 184: previousHeightx1Untranslated, dataArea, location 185: ); 186: 187: // Now translate the current y values. 188: double y0 = rangeAxis.valueToJava2D( 189: y0Untranslated, dataArea, location 190: ); 191: y1 = rangeAxis.valueToJava2D( 192: y1Untranslated, dataArea, location 193: ); 194: 195: Polygon p = null; 196: PlotOrientation orientation = plot.getOrientation(); 197: if (orientation == PlotOrientation.HORIZONTAL) { 198: p = new Polygon(); 199: p.addPoint((int) y0, (int) x0); 200: p.addPoint((int) y1, (int) x1); 201: p.addPoint((int) previousHeightx1, (int) x1); 202: p.addPoint((int) previousHeightx0, (int) x0); 203: } 204: else if (orientation == PlotOrientation.VERTICAL) { 205: p = new Polygon(); 206: p.addPoint((int) x0, (int) y0); 207: p.addPoint((int) x1, (int) y1); 208: p.addPoint((int) x1, (int) previousHeightx1); 209: p.addPoint((int) x0, (int) previousHeightx0); 210: } 211: g2.setPaint(getItemPaint(row, column)); 212: g2.setStroke(getItemStroke(row, column)); 213: g2.fill(p); 214: } 215: 216: } 217: 218: // add an item entity, if this information is being collected 219: EntityCollection entities = state.getEntityCollection(); 220: if (entities != null) { 221: Shape shape = new Rectangle2D.Double(x1 - 3.0, y1 - 3.0, 6.0, 6.0); 222: addItemEntity(entities, dataset, row, column, shape); 223: } 224: 225: } 226: 227: /** 228: * Calculates the stacked value of the all series up to, but not including 229: * <code>series</code> for the specified category, <code>category</code>. 230: * It returns 0.0 if <code>series</code> is the first series, i.e. 0. 231: * 232: * @param data the data. 233: * @param series the series. 234: * @param category the category. 235: * 236: * @return double returns a cumulative value for all series' values up to 237: * but excluding <code>series</code> for Object 238: * <code>category</code>. 239: */ 240: protected double getPreviousHeight(CategoryDataset data, 241: int series, int category) { 242: 243: double result = 0.0; 244: Number tmp; 245: for (int i = 0; i < series; i++) { 246: tmp = data.getValue(i, category); 247: if (tmp != null) { 248: result += tmp.doubleValue(); 249: } 250: } 251: return result; 252: 253: } 254: 255: }