Source for org.jfree.chart.renderer.category.AreaRenderer

   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:  * AreaRenderer.java
  29:  * -----------------
  30:  * (C) Copyright 2002-2005, by Jon Iles and Contributors.
  31:  *
  32:  * Original Author:  Jon Iles;
  33:  * Contributor(s):   David Gilbert (for Object Refinery Limited);
  34:  *                   Christian W. Zuckschwerdt;
  35:  *
  36:  * $Id: AreaRenderer.java,v 1.6.2.4 2005/11/28 12:06:35 mungady Exp $
  37:  *
  38:  * Changes:
  39:  * --------
  40:  * 21-May-2002 : Version 1, contributed by John Iles (DG);
  41:  * 29-May-2002 : Now extends AbstractCategoryItemRenderer (DG);
  42:  * 11-Jun-2002 : Updated Javadoc comments (DG);
  43:  * 25-Jun-2002 : Removed unnecessary imports (DG);
  44:  * 01-Oct-2002 : Fixed errors reported by Checkstyle (DG);
  45:  * 10-Oct-2002 : Added constructors and basic entity support (DG);
  46:  * 24-Oct-2002 : Amendments for changes in CategoryDataset interface and 
  47:  *               CategoryToolTipGenerator interface (DG);
  48:  * 05-Nov-2002 : Replaced references to CategoryDataset with TableDataset (DG);
  49:  * 06-Nov-2002 : Renamed drawCategoryItem() --> drawItem() and now using axis 
  50:  *               for category spacing.  Renamed AreaCategoryItemRenderer 
  51:  *               --> AreaRenderer (DG);
  52:  * 17-Jan-2003 : Moved plot classes into a separate package (DG);
  53:  * 25-Mar-2003 : Implemented Serializable (DG);
  54:  * 10-Apr-2003 : Changed CategoryDataset to KeyedValues2DDataset in 
  55:  *               drawItem() method (DG);
  56:  * 12-May-2003 : Modified to take into account the plot orientation (DG);
  57:  * 30-Jul-2003 : Modified entity constructor (CZ);
  58:  * 13-Aug-2003 : Implemented Cloneable (DG);
  59:  * 07-Oct-2003 : Added renderer state (DG);
  60:  * 05-Nov-2004 : Modified drawItem() signature (DG);
  61:  * 20-Apr-2005 : Apply tooltips and URLs to legend items (DG);
  62:  * 09-Jun-2005 : Use addItemEntity() method from superclass (DG);
  63:  * 
  64:  */
  65: 
  66: package org.jfree.chart.renderer.category;
  67: 
  68: import java.awt.Graphics2D;
  69: import java.awt.Paint;
  70: import java.awt.Shape;
  71: import java.awt.Stroke;
  72: import java.awt.geom.GeneralPath;
  73: import java.awt.geom.Rectangle2D;
  74: import java.io.Serializable;
  75: 
  76: import org.jfree.chart.LegendItem;
  77: import org.jfree.chart.axis.CategoryAxis;
  78: import org.jfree.chart.axis.ValueAxis;
  79: import org.jfree.chart.entity.EntityCollection;
  80: import org.jfree.chart.event.RendererChangeEvent;
  81: import org.jfree.chart.plot.CategoryPlot;
  82: import org.jfree.chart.plot.PlotOrientation;
  83: import org.jfree.chart.renderer.AreaRendererEndType;
  84: import org.jfree.data.category.CategoryDataset;
  85: import org.jfree.ui.RectangleEdge;
  86: import org.jfree.util.PublicCloneable;
  87: 
  88: /**
  89:  * A category item renderer that draws area charts.  You can use this renderer 
  90:  * with the {@link org.jfree.chart.plot.CategoryPlot} class.
  91:  *
  92:  * @author Jon Iles
  93:  */
  94: public class AreaRenderer extends AbstractCategoryItemRenderer 
  95:                           implements Cloneable, PublicCloneable, Serializable {
  96: 
  97:     /** For serialization. */
  98:     private static final long serialVersionUID = -4231878281385812757L;
  99:     
 100:     /** A flag that controls how the ends of the areas are drawn. */
 101:     private AreaRendererEndType endType;
 102:     
 103:     /**
 104:      * Creates a new renderer.
 105:      */
 106:     public AreaRenderer() {
 107:         super();
 108:         this.endType = AreaRendererEndType.TAPER;
 109:     }
 110: 
 111:     /**
 112:      * Returns a token that controls how the renderer draws the end points.
 113:      * 
 114:      * @return The end type (never <code>null</code>).
 115:      */
 116:     public AreaRendererEndType getEndType() {
 117:         return this.endType;   
 118:     }
 119:     
 120:     /**
 121:      * Sets a token that controls how the renderer draws the end points, and 
 122:      * sends a {@link RendererChangeEvent} to all registered listeners.
 123:      * 
 124:      * @param type  the end type (<code>null</code> not permitted).
 125:      */
 126:     public void setEndType(AreaRendererEndType type) {
 127:         if (type == null) {
 128:             throw new IllegalArgumentException("Null 'type' argument.");   
 129:         }
 130:         this.endType = type;
 131:         notifyListeners(new RendererChangeEvent(this));
 132:     }
 133:     
 134:     /**
 135:      * Returns a legend item for a series.
 136:      *
 137:      * @param datasetIndex  the dataset index (zero-based).
 138:      * @param series  the series index (zero-based).
 139:      *
 140:      * @return The legend item.
 141:      */
 142:     public LegendItem getLegendItem(int datasetIndex, int series) {
 143: 
 144:         CategoryPlot cp = getPlot();
 145:         if (cp == null) {
 146:             return null;
 147:         }
 148: 
 149:         CategoryDataset dataset;
 150:         dataset = cp.getDataset(datasetIndex);
 151:         String label = getLegendItemLabelGenerator().generateLabel(
 152:             dataset, series
 153:         );
 154:         String description = label;
 155:         String toolTipText = null; 
 156:         if (getLegendItemToolTipGenerator() != null) {
 157:             toolTipText = getLegendItemToolTipGenerator().generateLabel(
 158:                 dataset, series
 159:             );   
 160:         }
 161:         String urlText = null;
 162:         if (getLegendItemURLGenerator() != null) {
 163:             urlText = getLegendItemURLGenerator().generateLabel(
 164:                 dataset, series
 165:             );   
 166:         }
 167:         Shape shape = new Rectangle2D.Double(-4.0, -4.0, 8.0, 8.0);
 168:         Paint paint = getSeriesPaint(series);
 169:         Paint outlinePaint = getSeriesOutlinePaint(series);
 170:         Stroke outlineStroke = getSeriesOutlineStroke(series);
 171: 
 172:         return new LegendItem(label, description, toolTipText, urlText, 
 173:             shape, paint, outlineStroke, outlinePaint);
 174: 
 175:     }
 176: 
 177:     /**
 178:      * Draw a single data item.
 179:      *
 180:      * @param g2  the graphics device.
 181:      * @param state  the renderer state.
 182:      * @param dataArea  the data plot area.
 183:      * @param plot  the plot.
 184:      * @param domainAxis  the domain axis.
 185:      * @param rangeAxis  the range axis.
 186:      * @param dataset  the dataset.
 187:      * @param row  the row index (zero-based).
 188:      * @param column  the column index (zero-based).
 189:      * @param pass  the pass index.
 190:      */
 191:     public void drawItem(Graphics2D g2,
 192:                          CategoryItemRendererState state,
 193:                          Rectangle2D dataArea,
 194:                          CategoryPlot plot,
 195:                          CategoryAxis domainAxis,
 196:                          ValueAxis rangeAxis,
 197:                          CategoryDataset dataset,
 198:                          int row,
 199:                          int column,
 200:                          int pass) {
 201: 
 202:         // plot non-null values only...
 203:         Number value = dataset.getValue(row, column);
 204:         if (value != null) {
 205:             PlotOrientation orientation = plot.getOrientation();
 206:             RectangleEdge axisEdge = plot.getDomainAxisEdge();
 207:             int count = dataset.getColumnCount();
 208:             float x0 = (float) domainAxis.getCategoryStart(
 209:                 column, count, dataArea, axisEdge
 210:             );
 211:             float x1 = (float) domainAxis.getCategoryMiddle(
 212:                 column, count, dataArea, axisEdge
 213:             );
 214:             float x2 = (float) domainAxis.getCategoryEnd(
 215:                 column, count, dataArea, axisEdge
 216:             );
 217: 
 218:             x0 = Math.round(x0);
 219:             x1 = Math.round(x1);
 220:             x2 = Math.round(x2);
 221: 
 222:             if (this.endType == AreaRendererEndType.TRUNCATE) {
 223:                 if (column == 0) {
 224:                     x0 = x1;   
 225:                 }
 226:                 else if (column == getColumnCount() - 1) {
 227:                     x2 = x1;   
 228:                 }
 229:             }
 230:             
 231:             double yy1 = value.doubleValue();
 232: 
 233:             double yy0 = 0.0;
 234:             if (column > 0) {
 235:                 Number n0 = dataset.getValue(row, column - 1);
 236:                 if (n0 != null) {
 237:                     yy0 = (n0.doubleValue() + yy1) / 2.0;
 238:                 }
 239:             }
 240: 
 241:             double yy2 = 0.0;
 242:             if (column < dataset.getColumnCount() - 1) {
 243:                 Number n2 = dataset.getValue(row, column + 1);
 244:                 if (n2 != null) {
 245:                     yy2 = (n2.doubleValue() + yy1) / 2.0;
 246:                 }
 247:             }
 248: 
 249:             RectangleEdge edge = plot.getRangeAxisEdge();
 250:             float y0 = (float) rangeAxis.valueToJava2D(yy0, dataArea, edge);
 251:             float y1 = (float) rangeAxis.valueToJava2D(yy1, dataArea, edge);
 252:             float y2 = (float) rangeAxis.valueToJava2D(yy2, dataArea, edge);
 253:             float yz = (float) rangeAxis.valueToJava2D(0.0, dataArea, edge);
 254: 
 255:             g2.setPaint(getItemPaint(row, column));
 256:             g2.setStroke(getItemStroke(row, column));
 257: 
 258:             GeneralPath area = new GeneralPath();
 259: 
 260:             if (orientation == PlotOrientation.VERTICAL) {
 261:                 area.moveTo(x0, yz);
 262:                 area.lineTo(x0, y0);
 263:                 area.lineTo(x1, y1);
 264:                 area.lineTo(x2, y2);
 265:                 area.lineTo(x2, yz);
 266:             }
 267:             else if (orientation == PlotOrientation.HORIZONTAL) {
 268:                 area.moveTo(yz, x0);
 269:                 area.lineTo(y0, x0);
 270:                 area.lineTo(y1, x1);
 271:                 area.lineTo(y2, x2);
 272:                 area.lineTo(yz, x2);
 273:             }
 274:             area.closePath();
 275: 
 276:             g2.setPaint(getItemPaint(row, column));
 277:             g2.fill(area);
 278: 
 279:             // draw the item labels if there are any...
 280:             if (isItemLabelVisible(row, column)) {
 281:                 drawItemLabel(
 282:                     g2, orientation, dataset, row, column, x1, y1, 
 283:                     (value.doubleValue() < 0.0)
 284:                 );
 285:             }
 286: 
 287:             // add an item entity, if this information is being collected
 288:             EntityCollection entities = state.getEntityCollection();
 289:             if (entities != null) {
 290:                 addItemEntity(entities, dataset, row, column, area);
 291:             }
 292:         }
 293: 
 294:     }
 295:     
 296:     /**
 297:      * Returns an independent copy of the renderer.
 298:      * 
 299:      * @return A clone.
 300:      * 
 301:      * @throws CloneNotSupportedException  should not happen.
 302:      */
 303:     public Object clone() throws CloneNotSupportedException {
 304:         return super.clone();
 305:     }
 306: 
 307: }