001 /* =========================================================== 002 * JFreeChart : a free chart library for the Java(tm) platform 003 * =========================================================== 004 * 005 * (C) Copyright 2000-2005, 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-2005, 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.4 2005/11/28 12:06:35 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 * 064 */ 065 066 package org.jfree.chart.renderer.category; 067 068 import java.awt.Graphics2D; 069 import java.awt.Paint; 070 import java.awt.Shape; 071 import java.awt.Stroke; 072 import java.awt.geom.GeneralPath; 073 import java.awt.geom.Rectangle2D; 074 import java.io.Serializable; 075 076 import org.jfree.chart.LegendItem; 077 import org.jfree.chart.axis.CategoryAxis; 078 import org.jfree.chart.axis.ValueAxis; 079 import org.jfree.chart.entity.EntityCollection; 080 import org.jfree.chart.event.RendererChangeEvent; 081 import org.jfree.chart.plot.CategoryPlot; 082 import org.jfree.chart.plot.PlotOrientation; 083 import org.jfree.chart.renderer.AreaRendererEndType; 084 import org.jfree.data.category.CategoryDataset; 085 import org.jfree.ui.RectangleEdge; 086 import org.jfree.util.PublicCloneable; 087 088 /** 089 * A category item renderer that draws area charts. You can use this renderer 090 * with the {@link org.jfree.chart.plot.CategoryPlot} class. 091 * 092 * @author Jon Iles 093 */ 094 public class AreaRenderer extends AbstractCategoryItemRenderer 095 implements Cloneable, PublicCloneable, Serializable { 096 097 /** For serialization. */ 098 private static final long serialVersionUID = -4231878281385812757L; 099 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 }