001/* =========================================================== 002 * JFreeChart : a free chart library for the Java(tm) platform 003 * =========================================================== 004 * 005 * (C) Copyright 2000-2014, 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 * [Oracle and Java are registered trademarks of Oracle and/or its affiliates. 025 * Other names may be trademarks of their respective owners.] 026 * 027 * ---------------------- 028 * YIntervalRenderer.java 029 * ---------------------- 030 * (C) Copyright 2002-2014, 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 051package org.jfree.chart.renderer.xy; 052 053import java.awt.Font; 054import java.awt.Graphics2D; 055import java.awt.Paint; 056import java.awt.Shape; 057import java.awt.Stroke; 058import java.awt.geom.Line2D; 059import java.awt.geom.Point2D; 060import java.awt.geom.Rectangle2D; 061import java.io.Serializable; 062 063import org.jfree.chart.axis.ValueAxis; 064import org.jfree.chart.entity.EntityCollection; 065import org.jfree.chart.event.RendererChangeEvent; 066import org.jfree.chart.labels.ItemLabelPosition; 067import org.jfree.chart.labels.XYItemLabelGenerator; 068import org.jfree.chart.plot.CrosshairState; 069import org.jfree.chart.plot.PlotOrientation; 070import org.jfree.chart.plot.PlotRenderingInfo; 071import org.jfree.chart.plot.XYPlot; 072import org.jfree.data.Range; 073import org.jfree.data.xy.IntervalXYDataset; 074import org.jfree.data.xy.XYDataset; 075import org.jfree.text.TextUtilities; 076import org.jfree.ui.RectangleEdge; 077import org.jfree.util.ObjectUtilities; 078import org.jfree.util.PublicCloneable; 079import org.jfree.util.ShapeUtilities; 080 081/** 082 * A renderer that draws a line connecting the start and end Y values for an 083 * {@link XYPlot}. The example shown here is generated by the 084 * <code>YIntervalRendererDemo1.java</code> program included in the JFreeChart 085 * demo collection: 086 * <br><br> 087 * <img src="../../../../../images/YIntervalRendererSample.png" 088 * alt="YIntervalRendererSample.png"> 089 */ 090public class YIntervalRenderer extends AbstractXYItemRenderer 091 implements XYItemRenderer, Cloneable, PublicCloneable, Serializable { 092 093 /** For serialization. */ 094 private static final long serialVersionUID = -2951586537224143260L; 095 096 /** 097 * An additional item label generator. If this is non-null, the item 098 * label generated will be displayed near the lower y-value at the 099 * position given by getNegativeItemLabelPosition(). 100 * 101 * @since 1.0.10 102 */ 103 private XYItemLabelGenerator additionalItemLabelGenerator; 104 105 /** 106 * The default constructor. 107 */ 108 public YIntervalRenderer() { 109 super(); 110 this.additionalItemLabelGenerator = null; 111 } 112 113 /** 114 * Returns the generator for the item labels that appear near the lower 115 * y-value. 116 * 117 * @return The generator (possibly <code>null</code>). 118 * 119 * @see #setAdditionalItemLabelGenerator(XYItemLabelGenerator) 120 * 121 * @since 1.0.10 122 */ 123 public XYItemLabelGenerator getAdditionalItemLabelGenerator() { 124 return this.additionalItemLabelGenerator; 125 } 126 127 /** 128 * Sets the generator for the item labels that appear near the lower 129 * y-value and sends a {@link RendererChangeEvent} to all registered 130 * listeners. If this is set to <code>null</code>, no item labels will be 131 * drawn. 132 * 133 * @param generator the generator (<code>null</code> permitted). 134 * 135 * @see #getAdditionalItemLabelGenerator() 136 * 137 * @since 1.0.10 138 */ 139 public void setAdditionalItemLabelGenerator( 140 XYItemLabelGenerator generator) { 141 this.additionalItemLabelGenerator = generator; 142 fireChangeEvent(); 143 } 144 145 /** 146 * Returns the range of values the renderer requires to display all the 147 * items from the specified dataset. 148 * 149 * @param dataset the dataset (<code>null</code> permitted). 150 * 151 * @return The range (<code>null</code> if the dataset is <code>null</code> 152 * or empty). 153 */ 154 @Override 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 @Override 178 public void drawItem(Graphics2D g2, XYItemRendererState state, 179 Rectangle2D dataArea, PlotRenderingInfo info, XYPlot plot, 180 ValueAxis domainAxis, ValueAxis rangeAxis, XYDataset dataset, 181 int series, int item, CrosshairState crosshairState, int pass) { 182 183 // setup for collecting optional entity info... 184 EntityCollection entities = null; 185 if (info != null) { 186 entities = info.getOwner().getEntityCollection(); 187 } 188 189 IntervalXYDataset intervalDataset = (IntervalXYDataset) dataset; 190 191 double x = intervalDataset.getXValue(series, item); 192 double yLow = intervalDataset.getStartYValue(series, item); 193 double yHigh = intervalDataset.getEndYValue(series, item); 194 195 RectangleEdge xAxisLocation = plot.getDomainAxisEdge(); 196 RectangleEdge yAxisLocation = plot.getRangeAxisEdge(); 197 198 double xx = domainAxis.valueToJava2D(x, dataArea, xAxisLocation); 199 double yyLow = rangeAxis.valueToJava2D(yLow, dataArea, yAxisLocation); 200 double yyHigh = rangeAxis.valueToJava2D(yHigh, dataArea, yAxisLocation); 201 202 Paint p = getItemPaint(series, item); 203 Stroke s = getItemStroke(series, item); 204 205 Line2D line = null; 206 Shape shape = getItemShape(series, item); 207 Shape top = null; 208 Shape bottom = null; 209 PlotOrientation orientation = plot.getOrientation(); 210 if (orientation == PlotOrientation.HORIZONTAL) { 211 line = new Line2D.Double(yyLow, xx, yyHigh, xx); 212 top = ShapeUtilities.createTranslatedShape(shape, yyHigh, xx); 213 bottom = ShapeUtilities.createTranslatedShape(shape, yyLow, xx); 214 } 215 else if (orientation == PlotOrientation.VERTICAL) { 216 line = new Line2D.Double(xx, yyLow, xx, yyHigh); 217 top = ShapeUtilities.createTranslatedShape(shape, xx, yyHigh); 218 bottom = ShapeUtilities.createTranslatedShape(shape, xx, yyLow); 219 } else { 220 throw new IllegalStateException(); 221 } 222 g2.setPaint(p); 223 g2.setStroke(s); 224 g2.draw(line); 225 226 g2.fill(top); 227 g2.fill(bottom); 228 229 // for item labels, we have a special case because there is the 230 // possibility to draw (a) the regular item label near to just the 231 // upper y-value, or (b) the regular item label near the upper y-value 232 // PLUS an additional item label near the lower y-value. 233 if (isItemLabelVisible(series, item)) { 234 drawItemLabel(g2, orientation, dataset, series, item, xx, yyHigh, 235 false); 236 drawAdditionalItemLabel(g2, orientation, dataset, series, item, 237 xx, yyLow); 238 } 239 240 // add an entity for the item... 241 if (entities != null) { 242 addEntity(entities, line.getBounds(), dataset, series, item, 0.0, 243 0.0); 244 } 245 246 } 247 248 /** 249 * Draws an item label. 250 * 251 * @param g2 the graphics device. 252 * @param orientation the orientation. 253 * @param dataset the dataset. 254 * @param series the series index (zero-based). 255 * @param item the item index (zero-based). 256 * @param x the x coordinate (in Java2D space). 257 * @param y the y coordinate (in Java2D space). 258 */ 259 private void drawAdditionalItemLabel(Graphics2D g2, 260 PlotOrientation orientation, XYDataset dataset, int series, 261 int item, double x, double y) { 262 263 if (this.additionalItemLabelGenerator == null) { 264 return; 265 } 266 267 Font labelFont = getItemLabelFont(series, item); 268 Paint paint = getItemLabelPaint(series, item); 269 g2.setFont(labelFont); 270 g2.setPaint(paint); 271 String label = this.additionalItemLabelGenerator.generateLabel(dataset, 272 series, item); 273 274 ItemLabelPosition position = getNegativeItemLabelPosition(series, item); 275 Point2D anchorPoint = calculateLabelAnchorPoint( 276 position.getItemLabelAnchor(), x, y, orientation); 277 TextUtilities.drawRotatedString(label, g2, 278 (float) anchorPoint.getX(), (float) anchorPoint.getY(), 279 position.getTextAnchor(), position.getAngle(), 280 position.getRotationAnchor()); 281 } 282 283 /** 284 * Tests this renderer for equality with an arbitrary object. 285 * 286 * @param obj the object (<code>null</code> permitted). 287 * 288 * @return A boolean. 289 */ 290 @Override 291 public boolean equals(Object obj) { 292 if (obj == this) { 293 return true; 294 } 295 if (!(obj instanceof YIntervalRenderer)) { 296 return false; 297 } 298 YIntervalRenderer that = (YIntervalRenderer) obj; 299 if (!ObjectUtilities.equal(this.additionalItemLabelGenerator, 300 that.additionalItemLabelGenerator)) { 301 return false; 302 } 303 return super.equals(obj); 304 } 305 306 /** 307 * Returns a clone of the renderer. 308 * 309 * @return A clone. 310 * 311 * @throws CloneNotSupportedException if the renderer cannot be cloned. 312 */ 313 @Override 314 public Object clone() throws CloneNotSupportedException { 315 return super.clone(); 316 } 317 318}