Frames | No Frames |
1: /* =========================================================== 2: * JFreeChart : a free chart library for the Java(tm) platform 3: * =========================================================== 4: * 5: * (C) Copyright 2000-2006, 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: * ClusteredXYBarRenderer.java 29: * --------------------------- 30: * (C) Copyright 2003-2006, by Paolo Cova and Contributors. 31: * 32: * Original Author: Paolo Cova; 33: * Contributor(s): David Gilbert (for Object Refinery Limited); 34: * Christian W. Zuckschwerdt; 35: * Matthias Rose; 36: * 37: * $Id: ClusteredXYBarRenderer.java,v 1.8.2.3 2006/12/11 15:31:33 mungady Exp $ 38: * 39: * Changes 40: * ------- 41: * 24-Jan-2003 : Version 1, contributed by Paolo Cova (DG); 42: * 25-Mar-2003 : Implemented Serializable (DG); 43: * 01-May-2003 : Modified drawItem() method signature (DG); 44: * 30-Jul-2003 : Modified entity constructor (CZ); 45: * 20-Aug-2003 : Implemented Cloneable and PublicCloneable (DG); 46: * 16-Sep-2003 : Changed ChartRenderingInfo --> PlotRenderingInfo (DG); 47: * 07-Oct-2003 : Added renderer state (DG); 48: * 03-Nov-2003 : In draw method added state parameter and y==null value 49: * handling (MR); 50: * 25-Feb-2004 : Replaced CrosshairInfo with CrosshairState (DG); 51: * 15-Jul-2004 : Switched getX() with getXValue() and getY() with 52: * getYValue() (DG); 53: * 01-Oct-2004 : Fixed bug where 'drawBarOutline' flag is ignored (DG); 54: * 16-May-2005 : Fixed to used outline stroke for bar outlines. Removed some 55: * redundant code with the result that the renderer now respects 56: * the 'base' setting from the super-class. Added an equals() 57: * method (DG); 58: * 19-May-2005 : Added minimal item label implementation - needs improving (DG); 59: * ------------- JFREECHART 1.0.x --------------------------------------------- 60: * 11-Dec-2006 : Added support for GradientPaint (DG); 61: * 62: */ 63: 64: package org.jfree.chart.renderer.xy; 65: 66: import java.awt.GradientPaint; 67: import java.awt.Graphics2D; 68: import java.awt.Paint; 69: import java.awt.geom.Rectangle2D; 70: import java.io.Serializable; 71: 72: import org.jfree.chart.axis.ValueAxis; 73: import org.jfree.chart.entity.EntityCollection; 74: import org.jfree.chart.entity.XYItemEntity; 75: import org.jfree.chart.labels.XYItemLabelGenerator; 76: import org.jfree.chart.labels.XYToolTipGenerator; 77: import org.jfree.chart.plot.CrosshairState; 78: import org.jfree.chart.plot.PlotOrientation; 79: import org.jfree.chart.plot.PlotRenderingInfo; 80: import org.jfree.chart.plot.XYPlot; 81: import org.jfree.data.xy.IntervalXYDataset; 82: import org.jfree.data.xy.XYDataset; 83: import org.jfree.ui.RectangleEdge; 84: import org.jfree.util.PublicCloneable; 85: 86: /** 87: * An extension of {@link XYBarRenderer} that displays bars for different 88: * series values at the same x next to each other. The assumption here is 89: * that for each x (time or else) there is a y value for each series. If 90: * this is not the case, there will be spaces between bars for a given x. 91: * <P> 92: * This renderer does not include code to calculate the crosshair point for the 93: * plot. 94: */ 95: public class ClusteredXYBarRenderer extends XYBarRenderer 96: implements Cloneable, PublicCloneable, 97: Serializable { 98: 99: /** For serialization. */ 100: private static final long serialVersionUID = 5864462149177133147L; 101: 102: /** Determines whether bar center should be interval start. */ 103: private boolean centerBarAtStartValue; 104: 105: /** 106: * Default constructor. Bar margin is set to 0.0. 107: */ 108: public ClusteredXYBarRenderer() { 109: this(0.0, false); 110: } 111: 112: /** 113: * Constructs a new XY clustered bar renderer. 114: * 115: * @param margin the percentage amount to trim from the width of each bar. 116: * @param centerBarAtStartValue if true, bars will be centered on the start 117: * of the time period. 118: */ 119: public ClusteredXYBarRenderer(double margin, 120: boolean centerBarAtStartValue) { 121: super(margin); 122: this.centerBarAtStartValue = centerBarAtStartValue; 123: } 124: 125: /** 126: * Draws the visual representation of a single data item. This method 127: * is mostly copied from the superclass, the change is that in the 128: * calculated space for a singe bar we draw bars for each series next to 129: * each other. The width of each bar is the available width divided by 130: * the number of series. Bars for each series are drawn in order left to 131: * right. 132: * 133: * @param g2 the graphics device. 134: * @param state the renderer state. 135: * @param dataArea the area within which the plot is being drawn. 136: * @param info collects information about the drawing. 137: * @param plot the plot (can be used to obtain standard color 138: * information etc). 139: * @param domainAxis the domain axis. 140: * @param rangeAxis the range axis. 141: * @param dataset the dataset. 142: * @param series the series index. 143: * @param item the item index. 144: * @param crosshairState crosshair information for the plot 145: * (<code>null</code> permitted). 146: * @param pass the pass index. 147: */ 148: public void drawItem(Graphics2D g2, 149: XYItemRendererState state, 150: Rectangle2D dataArea, 151: PlotRenderingInfo info, 152: XYPlot plot, 153: ValueAxis domainAxis, 154: ValueAxis rangeAxis, 155: XYDataset dataset, int series, int item, 156: CrosshairState crosshairState, 157: int pass) { 158: 159: IntervalXYDataset intervalDataset = (IntervalXYDataset) dataset; 160: 161: double value0; 162: double value1; 163: if (getUseYInterval()) { 164: value0 = intervalDataset.getStartYValue(series, item); 165: value1 = intervalDataset.getEndYValue(series, item); 166: } 167: else { 168: value0 = getBase(); 169: value1 = intervalDataset.getYValue(series, item); 170: } 171: if (Double.isNaN(value0) || Double.isNaN(value1)) { 172: return; 173: } 174: 175: double translatedValue0 = rangeAxis.valueToJava2D(value0, dataArea, 176: plot.getRangeAxisEdge()); 177: double translatedValue1 = rangeAxis.valueToJava2D(value1, dataArea, 178: plot.getRangeAxisEdge()); 179: 180: RectangleEdge xAxisLocation = plot.getDomainAxisEdge(); 181: double x1 = intervalDataset.getStartXValue(series, item); 182: double translatedX1 = domainAxis.valueToJava2D(x1, dataArea, 183: xAxisLocation); 184: 185: double x2 = intervalDataset.getEndXValue(series, item); 186: double translatedX2 = domainAxis.valueToJava2D(x2, dataArea, 187: xAxisLocation); 188: 189: double translatedWidth = Math.max(1, Math.abs(translatedX2 190: - translatedX1)); 191: double translatedHeight = Math.abs(translatedValue0 - translatedValue1); 192: 193: if (this.centerBarAtStartValue) { 194: translatedX1 -= translatedWidth / 2; 195: } 196: 197: PlotOrientation orientation = plot.getOrientation(); 198: double m = getMargin(); 199: if (m > 0.0) { 200: double cut = translatedWidth * getMargin(); 201: translatedWidth = translatedWidth - cut; 202: if (orientation == PlotOrientation.HORIZONTAL) 203: translatedX1 = translatedX1 - cut / 2; 204: else 205: translatedX1 = translatedX1 + cut / 2; 206: } 207: 208: int numSeries = dataset.getSeriesCount(); 209: double seriesBarWidth = translatedWidth / numSeries; 210: 211: Rectangle2D bar = null; 212: if (orientation == PlotOrientation.HORIZONTAL) { 213: bar = new Rectangle2D.Double(Math.min(translatedValue0, 214: translatedValue1), translatedX1 - seriesBarWidth 215: * (numSeries - series), translatedHeight, seriesBarWidth); 216: } 217: else if (orientation == PlotOrientation.VERTICAL) { 218: bar = new Rectangle2D.Double(translatedX1 + seriesBarWidth * series, 219: Math.min(translatedValue0, translatedValue1), 220: seriesBarWidth, translatedHeight); 221: } 222: Paint itemPaint = getItemPaint(series, item); 223: if (getGradientPaintTransformer() 224: != null && itemPaint instanceof GradientPaint) { 225: GradientPaint gp = (GradientPaint) itemPaint; 226: itemPaint = getGradientPaintTransformer().transform(gp, bar); 227: } 228: g2.setPaint(itemPaint); 229: 230: g2.fill(bar); 231: if (isDrawBarOutline() && Math.abs(translatedX2 - translatedX1) > 3) { 232: g2.setStroke(getItemOutlineStroke(series, item)); 233: g2.setPaint(getItemOutlinePaint(series, item)); 234: g2.draw(bar); 235: } 236: 237: if (isItemLabelVisible(series, item)) { 238: XYItemLabelGenerator generator = getItemLabelGenerator(series, 239: item); 240: drawItemLabel(g2, dataset, series, item, plot, generator, bar, 241: value1 < 0.0); 242: } 243: 244: // add an entity for the item... 245: if (info != null) { 246: EntityCollection entities = info.getOwner().getEntityCollection(); 247: if (entities != null) { 248: String tip = null; 249: XYToolTipGenerator generator 250: = getToolTipGenerator(series, item); 251: if (generator != null) { 252: tip = generator.generateToolTip(dataset, series, item); 253: } 254: String url = null; 255: if (getURLGenerator() != null) { 256: url = getURLGenerator().generateURL(dataset, series, item); 257: } 258: XYItemEntity entity = new XYItemEntity(bar, dataset, series, 259: item, tip, url); 260: entities.add(entity); 261: } 262: } 263: 264: } 265: 266: /** 267: * Tests this renderer for equality with an arbitrary object, returning 268: * <code>true</code> if <code>obj</code> is a 269: * <code>ClusteredXYBarRenderer</code> with the same settings as this 270: * renderer, and <code>false</code> otherwise. 271: * 272: * @param obj the object (<code>null</code> permitted). 273: * 274: * @return A boolean. 275: */ 276: public boolean equals(Object obj) { 277: if (obj == this) { 278: return true; 279: } 280: if (!(obj instanceof ClusteredXYBarRenderer)) { 281: return false; 282: } 283: if (!super.equals(obj)) { 284: return false; 285: } 286: ClusteredXYBarRenderer that = (ClusteredXYBarRenderer) obj; 287: if (this.centerBarAtStartValue != that.centerBarAtStartValue) { 288: return false; 289: } 290: return true; 291: } 292: 293: /** 294: * Returns a clone of the renderer. 295: * 296: * @return A clone. 297: * 298: * @throws CloneNotSupportedException if the renderer cannot be cloned. 299: */ 300: public Object clone() throws CloneNotSupportedException { 301: return super.clone(); 302: } 303: 304: }