001 /* =========================================================== 002 * JFreeChart : a free chart library for the Java(tm) platform 003 * =========================================================== 004 * 005 * (C) Copyright 2000-2009, 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 * YIntervalRenderer.java 029 * ---------------------- 030 * (C) Copyright 2002-2009, by Object Refinery Limited. 031 * 032 * Original Author: David Gilbert (for Object Refinery Limited); 033 * Contributor(s): -; 034 * 035 * Changes 036 * ------- 037 * 05-Nov-2002 : Version 1 (DG); 038 * 25-Mar-2003 : Implemented Serializable (DG); 039 * 01-May-2003 : Modified drawItem() method signature (DG); 040 * 20-Aug-2003 : Implemented Cloneable and PublicCloneable (DG); 041 * 16-Sep-2003 : Changed ChartRenderingInfo --> PlotRenderingInfo (DG); 042 * 25-Feb-2004 : Replaced CrosshairInfo with CrosshairState (DG); 043 * 27-Sep-2004 : Access double values from dataset (DG); 044 * 11-Nov-2004 : Now uses ShapeUtilities to translate shapes (DG); 045 * 11-Apr-2008 : New override for findRangeBounds() (DG); 046 * 26-May-2008 : Added item label support (DG); 047 * 27-Mar-2009 : Updated findRangeBounds() (DG); 048 * 049 */ 050 051 package org.jfree.chart.renderer.xy; 052 053 import java.awt.Font; 054 import java.awt.Graphics2D; 055 import java.awt.Paint; 056 import java.awt.Shape; 057 import java.awt.Stroke; 058 import java.awt.geom.Line2D; 059 import java.awt.geom.Point2D; 060 import java.awt.geom.Rectangle2D; 061 import java.io.Serializable; 062 063 import org.jfree.chart.axis.ValueAxis; 064 import org.jfree.chart.entity.EntityCollection; 065 import org.jfree.chart.event.RendererChangeEvent; 066 import org.jfree.chart.labels.ItemLabelPosition; 067 import org.jfree.chart.labels.XYItemLabelGenerator; 068 import org.jfree.chart.plot.CrosshairState; 069 import org.jfree.chart.plot.PlotOrientation; 070 import org.jfree.chart.plot.PlotRenderingInfo; 071 import org.jfree.chart.plot.XYPlot; 072 import org.jfree.data.Range; 073 import org.jfree.data.general.DatasetUtilities; 074 import org.jfree.data.xy.IntervalXYDataset; 075 import org.jfree.data.xy.XYDataset; 076 import org.jfree.text.TextUtilities; 077 import org.jfree.ui.RectangleEdge; 078 import org.jfree.util.ObjectUtilities; 079 import org.jfree.util.PublicCloneable; 080 import org.jfree.util.ShapeUtilities; 081 082 /** 083 * A renderer that draws a line connecting the start and end Y values for an 084 * {@link XYPlot}. The example shown here is generated by the 085 * <code>YIntervalRendererDemo1.java</code> program included in the JFreeChart 086 * demo collection: 087 * <br><br> 088 * <img src="../../../../../images/YIntervalRendererSample.png" 089 * alt="YIntervalRendererSample.png" /> 090 */ 091 public class YIntervalRenderer extends AbstractXYItemRenderer 092 implements XYItemRenderer, Cloneable, PublicCloneable, Serializable { 093 094 /** For serialization. */ 095 private static final long serialVersionUID = -2951586537224143260L; 096 097 /** 098 * An additional item label generator. If this is non-null, the item 099 * label generated will be displayed near the lower y-value at the 100 * position given by getNegativeItemLabelPosition(). 101 * 102 * @since 1.0.10 103 */ 104 private XYItemLabelGenerator additionalItemLabelGenerator; 105 106 /** 107 * The default constructor. 108 */ 109 public YIntervalRenderer() { 110 super(); 111 this.additionalItemLabelGenerator = null; 112 } 113 114 /** 115 * Returns the generator for the item labels that appear near the lower 116 * y-value. 117 * 118 * @return The generator (possibly <code>null</code>). 119 * 120 * @see #setAdditionalItemLabelGenerator(XYItemLabelGenerator) 121 * 122 * @since 1.0.10 123 */ 124 public XYItemLabelGenerator getAdditionalItemLabelGenerator() { 125 return this.additionalItemLabelGenerator; 126 } 127 128 /** 129 * Sets the generator for the item labels that appear near the lower 130 * y-value and sends a {@link RendererChangeEvent} to all registered 131 * listeners. If this is set to <code>null</code>, no item labels will be 132 * drawn. 133 * 134 * @param generator the generator (<code>null</code> permitted). 135 * 136 * @see #getAdditionalItemLabelGenerator() 137 * 138 * @since 1.0.10 139 */ 140 public void setAdditionalItemLabelGenerator( 141 XYItemLabelGenerator generator) { 142 this.additionalItemLabelGenerator = generator; 143 fireChangeEvent(); 144 } 145 146 /** 147 * Returns the range of values the renderer requires to display all the 148 * items from the specified dataset. 149 * 150 * @param dataset the dataset (<code>null</code> permitted). 151 * 152 * @return The range (<code>null</code> if the dataset is <code>null</code> 153 * or empty). 154 */ 155 public Range findRangeBounds(XYDataset dataset) { 156 return findRangeBounds(dataset, true); 157 } 158 159 /** 160 * Draws the visual representation of a single data item. 161 * 162 * @param g2 the graphics device. 163 * @param state the renderer state. 164 * @param dataArea the area within which the plot is being drawn. 165 * @param info collects information about the drawing. 166 * @param plot the plot (can be used to obtain standard color 167 * information etc). 168 * @param domainAxis the domain axis. 169 * @param rangeAxis the range axis. 170 * @param dataset the dataset. 171 * @param series the series index (zero-based). 172 * @param item the item index (zero-based). 173 * @param crosshairState crosshair information for the plot 174 * (<code>null</code> permitted). 175 * @param pass the pass index (ignored here). 176 */ 177 public void drawItem(Graphics2D g2, 178 XYItemRendererState state, 179 Rectangle2D dataArea, 180 PlotRenderingInfo info, 181 XYPlot plot, 182 ValueAxis domainAxis, 183 ValueAxis rangeAxis, 184 XYDataset dataset, 185 int series, 186 int item, 187 CrosshairState crosshairState, 188 int pass) { 189 190 // setup for collecting optional entity info... 191 EntityCollection entities = null; 192 if (info != null) { 193 entities = info.getOwner().getEntityCollection(); 194 } 195 196 IntervalXYDataset intervalDataset = (IntervalXYDataset) dataset; 197 198 double x = intervalDataset.getXValue(series, item); 199 double yLow = intervalDataset.getStartYValue(series, item); 200 double yHigh = intervalDataset.getEndYValue(series, item); 201 202 RectangleEdge xAxisLocation = plot.getDomainAxisEdge(); 203 RectangleEdge yAxisLocation = plot.getRangeAxisEdge(); 204 205 double xx = domainAxis.valueToJava2D(x, dataArea, xAxisLocation); 206 double yyLow = rangeAxis.valueToJava2D(yLow, dataArea, yAxisLocation); 207 double yyHigh = rangeAxis.valueToJava2D(yHigh, dataArea, yAxisLocation); 208 209 Paint p = getItemPaint(series, item); 210 Stroke s = getItemStroke(series, item); 211 212 Line2D line = null; 213 Shape shape = getItemShape(series, item); 214 Shape top = null; 215 Shape bottom = null; 216 PlotOrientation orientation = plot.getOrientation(); 217 if (orientation == PlotOrientation.HORIZONTAL) { 218 line = new Line2D.Double(yyLow, xx, yyHigh, xx); 219 top = ShapeUtilities.createTranslatedShape(shape, yyHigh, xx); 220 bottom = ShapeUtilities.createTranslatedShape(shape, yyLow, xx); 221 } 222 else if (orientation == PlotOrientation.VERTICAL) { 223 line = new Line2D.Double(xx, yyLow, xx, yyHigh); 224 top = ShapeUtilities.createTranslatedShape(shape, xx, yyHigh); 225 bottom = ShapeUtilities.createTranslatedShape(shape, xx, yyLow); 226 } 227 g2.setPaint(p); 228 g2.setStroke(s); 229 g2.draw(line); 230 231 g2.fill(top); 232 g2.fill(bottom); 233 234 // for item labels, we have a special case because there is the 235 // possibility to draw (a) the regular item label near to just the 236 // upper y-value, or (b) the regular item label near the upper y-value 237 // PLUS an additional item label near the lower y-value. 238 if (isItemLabelVisible(series, item)) { 239 drawItemLabel(g2, orientation, dataset, series, item, xx, yyHigh, 240 false); 241 drawAdditionalItemLabel(g2, orientation, dataset, series, item, 242 xx, yyLow); 243 } 244 245 // add an entity for the item... 246 if (entities != null) { 247 addEntity(entities, line.getBounds(), dataset, series, item, 0.0, 248 0.0); 249 } 250 251 } 252 253 /** 254 * Draws an item label. 255 * 256 * @param g2 the graphics device. 257 * @param orientation the orientation. 258 * @param dataset the dataset. 259 * @param series the series index (zero-based). 260 * @param item the item index (zero-based). 261 * @param x the x coordinate (in Java2D space). 262 * @param y the y coordinate (in Java2D space). 263 * @param negative indicates a negative value (which affects the item 264 * label position). 265 */ 266 private void drawAdditionalItemLabel(Graphics2D g2, 267 PlotOrientation orientation, XYDataset dataset, int series, 268 int item, double x, double y) { 269 270 if (this.additionalItemLabelGenerator == null) { 271 return; 272 } 273 274 Font labelFont = getItemLabelFont(series, item); 275 Paint paint = getItemLabelPaint(series, item); 276 g2.setFont(labelFont); 277 g2.setPaint(paint); 278 String label = this.additionalItemLabelGenerator.generateLabel(dataset, 279 series, item); 280 281 ItemLabelPosition position = getNegativeItemLabelPosition(series, item); 282 Point2D anchorPoint = calculateLabelAnchorPoint( 283 position.getItemLabelAnchor(), x, y, orientation); 284 TextUtilities.drawRotatedString(label, g2, 285 (float) anchorPoint.getX(), (float) anchorPoint.getY(), 286 position.getTextAnchor(), position.getAngle(), 287 position.getRotationAnchor()); 288 } 289 290 /** 291 * Tests this renderer for equality with an arbitrary object. 292 * 293 * @param obj the object (<code>null</code> permitted). 294 * 295 * @return A boolean. 296 */ 297 public boolean equals(Object obj) { 298 if (obj == this) { 299 return true; 300 } 301 if (!(obj instanceof YIntervalRenderer)) { 302 return false; 303 } 304 YIntervalRenderer that = (YIntervalRenderer) obj; 305 if (!ObjectUtilities.equal(this.additionalItemLabelGenerator, 306 that.additionalItemLabelGenerator)) { 307 return false; 308 } 309 return super.equals(obj); 310 } 311 312 /** 313 * Returns a clone of the renderer. 314 * 315 * @return A clone. 316 * 317 * @throws CloneNotSupportedException if the renderer cannot be cloned. 318 */ 319 public Object clone() throws CloneNotSupportedException { 320 return super.clone(); 321 } 322 323 }