Frames | No Frames |
1: /* =========================================================== 2: * JFreeChart : a free chart library for the Java(tm) platform 3: * =========================================================== 4: * 5: * (C) Copyright 2000-2008, 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: * YIntervalRenderer.java 29: * ---------------------- 30: * (C) Copyright 2002-2008, by Object Refinery Limited. 31: * 32: * Original Author: David Gilbert (for Object Refinery Limited); 33: * Contributor(s): -; 34: * 35: * Changes 36: * ------- 37: * 05-Nov-2002 : Version 1 (DG); 38: * 25-Mar-2003 : Implemented Serializable (DG); 39: * 01-May-2003 : Modified drawItem() method signature (DG); 40: * 20-Aug-2003 : Implemented Cloneable and PublicCloneable (DG); 41: * 16-Sep-2003 : Changed ChartRenderingInfo --> PlotRenderingInfo (DG); 42: * 25-Feb-2004 : Replaced CrosshairInfo with CrosshairState (DG); 43: * 27-Sep-2004 : Access double values from dataset (DG); 44: * 11-Nov-2004 : Now uses ShapeUtilities to translate shapes (DG); 45: * 11-Apr-2008 : New override for findRangeBounds() (DG); 46: * 26-May-2008 : Added item label support (DG); 47: * 48: */ 49: 50: package org.jfree.chart.renderer.xy; 51: 52: import java.awt.Font; 53: import java.awt.Graphics2D; 54: import java.awt.Paint; 55: import java.awt.Shape; 56: import java.awt.Stroke; 57: import java.awt.geom.Line2D; 58: import java.awt.geom.Point2D; 59: import java.awt.geom.Rectangle2D; 60: import java.io.Serializable; 61: 62: import org.jfree.chart.axis.ValueAxis; 63: import org.jfree.chart.entity.EntityCollection; 64: import org.jfree.chart.entity.XYItemEntity; 65: import org.jfree.chart.event.RendererChangeEvent; 66: import org.jfree.chart.labels.ItemLabelPosition; 67: import org.jfree.chart.labels.XYItemLabelGenerator; 68: import org.jfree.chart.labels.XYToolTipGenerator; 69: import org.jfree.chart.plot.CrosshairState; 70: import org.jfree.chart.plot.PlotOrientation; 71: import org.jfree.chart.plot.PlotRenderingInfo; 72: import org.jfree.chart.plot.XYPlot; 73: import org.jfree.data.Range; 74: import org.jfree.data.general.DatasetUtilities; 75: import org.jfree.data.xy.IntervalXYDataset; 76: import org.jfree.data.xy.XYDataset; 77: import org.jfree.text.TextUtilities; 78: import org.jfree.ui.RectangleEdge; 79: import org.jfree.util.ObjectUtilities; 80: import org.jfree.util.PublicCloneable; 81: import org.jfree.util.ShapeUtilities; 82: 83: /** 84: * A renderer that draws a line connecting the start and end Y values for an 85: * {@link XYPlot}. 86: */ 87: public class YIntervalRenderer extends AbstractXYItemRenderer 88: implements XYItemRenderer, Cloneable, PublicCloneable, Serializable { 89: 90: /** For serialization. */ 91: private static final long serialVersionUID = -2951586537224143260L; 92: 93: /** 94: * An additional item label generator. If this is non-null, the item 95: * label generated will be displayed near the lower y-value at the 96: * position given by getNegativeItemLabelPosition(). 97: * 98: * @since 1.0.10 99: */ 100: private XYItemLabelGenerator additionalItemLabelGenerator; 101: 102: /** 103: * The default constructor. 104: */ 105: public YIntervalRenderer() { 106: super(); 107: this.additionalItemLabelGenerator = null; 108: } 109: 110: /** 111: * Returns the generator for the item labels that appear near the lower 112: * y-value. 113: * 114: * @return The generator (possibly <code>null</code>). 115: * 116: * @see #setAdditionalItemLabelGenerator(XYItemLabelGenerator) 117: * 118: * @since 1.0.10 119: */ 120: public XYItemLabelGenerator getAdditionalItemLabelGenerator() { 121: return this.additionalItemLabelGenerator; 122: } 123: 124: /** 125: * Sets the generator for the item labels that appear near the lower 126: * y-value and sends a {@link RendererChangeEvent} to all registered 127: * listeners. If this is set to <code>null</code>, no item labels will be 128: * drawn. 129: * 130: * @param generator the generator (<code>null</code> permitted). 131: * 132: * @see #getAdditionalItemLabelGenerator() 133: * 134: * @since 1.0.10 135: */ 136: public void setAdditionalItemLabelGenerator( 137: XYItemLabelGenerator generator) { 138: this.additionalItemLabelGenerator = generator; 139: fireChangeEvent(); 140: } 141: 142: /** 143: * Returns the range of values the renderer requires to display all the 144: * items from the specified dataset. 145: * 146: * @param dataset the dataset (<code>null</code> permitted). 147: * 148: * @return The range (<code>null</code> if the dataset is <code>null</code> 149: * or empty). 150: */ 151: public Range findRangeBounds(XYDataset dataset) { 152: if (dataset != null) { 153: return DatasetUtilities.findRangeBounds(dataset, true); 154: } 155: else { 156: return null; 157: } 158: } 159: 160: /** 161: * Draws the visual representation of a single data item. 162: * 163: * @param g2 the graphics device. 164: * @param state the renderer state. 165: * @param dataArea the area within which the plot is being drawn. 166: * @param info collects information about the drawing. 167: * @param plot the plot (can be used to obtain standard color 168: * information etc). 169: * @param domainAxis the domain axis. 170: * @param rangeAxis the range axis. 171: * @param dataset the dataset. 172: * @param series the series index (zero-based). 173: * @param item the item index (zero-based). 174: * @param crosshairState crosshair information for the plot 175: * (<code>null</code> permitted). 176: * @param pass the pass index (ignored here). 177: */ 178: public void drawItem(Graphics2D g2, 179: XYItemRendererState state, 180: Rectangle2D dataArea, 181: PlotRenderingInfo info, 182: XYPlot plot, 183: ValueAxis domainAxis, 184: ValueAxis rangeAxis, 185: XYDataset dataset, 186: int series, 187: int item, 188: CrosshairState crosshairState, 189: int pass) { 190: 191: // setup for collecting optional entity info... 192: Shape entityArea = null; 193: EntityCollection entities = null; 194: if (info != null) { 195: entities = info.getOwner().getEntityCollection(); 196: } 197: 198: IntervalXYDataset intervalDataset = (IntervalXYDataset) dataset; 199: 200: double x = intervalDataset.getXValue(series, item); 201: double yLow = intervalDataset.getStartYValue(series, item); 202: double yHigh = intervalDataset.getEndYValue(series, item); 203: 204: RectangleEdge xAxisLocation = plot.getDomainAxisEdge(); 205: RectangleEdge yAxisLocation = plot.getRangeAxisEdge(); 206: 207: double xx = domainAxis.valueToJava2D(x, dataArea, xAxisLocation); 208: double yyLow = rangeAxis.valueToJava2D(yLow, dataArea, yAxisLocation); 209: double yyHigh = rangeAxis.valueToJava2D(yHigh, dataArea, yAxisLocation); 210: 211: Paint p = getItemPaint(series, item); 212: Stroke s = getItemStroke(series, item); 213: 214: Line2D line = null; 215: Shape shape = getItemShape(series, item); 216: Shape top = null; 217: Shape bottom = null; 218: PlotOrientation orientation = plot.getOrientation(); 219: if (orientation == PlotOrientation.HORIZONTAL) { 220: line = new Line2D.Double(yyLow, xx, yyHigh, xx); 221: top = ShapeUtilities.createTranslatedShape(shape, yyHigh, xx); 222: bottom = ShapeUtilities.createTranslatedShape(shape, yyLow, xx); 223: } 224: else if (orientation == PlotOrientation.VERTICAL) { 225: line = new Line2D.Double(xx, yyLow, xx, yyHigh); 226: top = ShapeUtilities.createTranslatedShape(shape, xx, yyHigh); 227: bottom = ShapeUtilities.createTranslatedShape(shape, xx, yyLow); 228: } 229: g2.setPaint(p); 230: g2.setStroke(s); 231: g2.draw(line); 232: 233: g2.fill(top); 234: g2.fill(bottom); 235: 236: // for item labels, we have a special case because there is the 237: // possibility to draw (a) the regular item label near to just the 238: // upper y-value, or (b) the regular item label near the upper y-value 239: // PLUS an additional item label near the lower y-value. 240: if (isItemLabelVisible(series, item)) { 241: drawItemLabel(g2, orientation, dataset, series, item, xx, yyHigh, 242: false); 243: drawAdditionalItemLabel(g2, orientation, dataset, series, item, 244: xx, yyLow); 245: } 246: 247: // add an entity for the item... 248: if (entities != null) { 249: if (entityArea == null) { 250: entityArea = line.getBounds(); 251: } 252: String tip = null; 253: XYToolTipGenerator generator = getToolTipGenerator(series, item); 254: if (generator != null) { 255: tip = generator.generateToolTip(dataset, series, item); 256: } 257: String url = null; 258: if (getURLGenerator() != null) { 259: url = getURLGenerator().generateURL(dataset, series, item); 260: } 261: XYItemEntity entity = new XYItemEntity(entityArea, dataset, series, 262: item, tip, url); 263: entities.add(entity); 264: } 265: 266: } 267: 268: /** 269: * Draws an item label. 270: * 271: * @param g2 the graphics device. 272: * @param orientation the orientation. 273: * @param dataset the dataset. 274: * @param series the series index (zero-based). 275: * @param item the item index (zero-based). 276: * @param x the x coordinate (in Java2D space). 277: * @param y the y coordinate (in Java2D space). 278: * @param negative indicates a negative value (which affects the item 279: * label position). 280: */ 281: private void drawAdditionalItemLabel(Graphics2D g2, 282: PlotOrientation orientation, XYDataset dataset, int series, 283: int item, double x, double y) { 284: 285: if (this.additionalItemLabelGenerator == null) { 286: return; 287: } 288: 289: Font labelFont = getItemLabelFont(series, item); 290: Paint paint = getItemLabelPaint(series, item); 291: g2.setFont(labelFont); 292: g2.setPaint(paint); 293: String label = this.additionalItemLabelGenerator.generateLabel(dataset, 294: series, item); 295: 296: ItemLabelPosition position = getNegativeItemLabelPosition(series, item); 297: Point2D anchorPoint = calculateLabelAnchorPoint( 298: position.getItemLabelAnchor(), x, y, orientation); 299: TextUtilities.drawRotatedString(label, g2, 300: (float) anchorPoint.getX(), (float) anchorPoint.getY(), 301: position.getTextAnchor(), position.getAngle(), 302: position.getRotationAnchor()); 303: } 304: 305: /** 306: * Tests this renderer for equality with an arbitrary object. 307: * 308: * @param obj the object (<code>null</code> permitted). 309: * 310: * @return A boolean. 311: */ 312: public boolean equals(Object obj) { 313: if (obj == this) { 314: return true; 315: } 316: if (!(obj instanceof YIntervalRenderer)) { 317: return false; 318: } 319: YIntervalRenderer that = (YIntervalRenderer) obj; 320: if (!ObjectUtilities.equal(this.additionalItemLabelGenerator, 321: that.additionalItemLabelGenerator)) { 322: return false; 323: } 324: return super.equals(obj); 325: } 326: 327: /** 328: * Returns a clone of the renderer. 329: * 330: * @return A clone. 331: * 332: * @throws CloneNotSupportedException if the renderer cannot be cloned. 333: */ 334: public Object clone() throws CloneNotSupportedException { 335: return super.clone(); 336: } 337: 338: }