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: * 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: }