Source for org.jfree.chart.renderer.category.CategoryStepRenderer

   1: /* ===========================================================
   2:  * JFreeChart : a free chart library for the Java(tm) platform
   3:  * ===========================================================
   4:  *
   5:  * (C) Copyright 2000-2005, 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:  * CategoryStepRenderer.java
  29:  * -------------------------
  30:  *
  31:  * (C) Copyright 2004, 2005, by Brian Cole and Contributors.
  32:  *
  33:  * Original Author:  Brian Cole;
  34:  * Contributor(s):   David Gilbert (for Object Refinery Limited);
  35:  *
  36:  * $Id: CategoryStepRenderer.java,v 1.5.2.1 2005/10/25 20:54:16 mungady Exp $
  37:  *
  38:  * Changes
  39:  * -------
  40:  * 21-Apr-2004 : Version 1, contributed by Brian Cole (DG);
  41:  * 22-Apr-2004 : Fixed Checkstyle complaints (DG);
  42:  * 05-Nov-2004 : Modified drawItem() signature (DG);
  43:  * 08-Mar-2005 : Added equals() method (DG);
  44:  * 
  45:  */
  46: 
  47: package org.jfree.chart.renderer.category;
  48: 
  49: import java.awt.Graphics2D;
  50: import java.awt.geom.Line2D;
  51: import java.awt.geom.Rectangle2D;
  52: import java.io.Serializable;
  53: 
  54: import org.jfree.chart.axis.CategoryAxis;
  55: import org.jfree.chart.axis.ValueAxis;
  56: import org.jfree.chart.event.RendererChangeEvent;
  57: import org.jfree.chart.plot.CategoryPlot;
  58: import org.jfree.chart.plot.PlotOrientation;
  59: import org.jfree.chart.renderer.xy.XYStepRenderer;
  60: import org.jfree.data.category.CategoryDataset;
  61: import org.jfree.util.PublicCloneable;
  62: 
  63: /**
  64:  * A "step" renderer similar to {@link XYStepRenderer} but
  65:  * that can be used with the {@link CategoryPlot} class.
  66:  *
  67:  * @author Brian Cole
  68:  */
  69: public class CategoryStepRenderer extends AbstractCategoryItemRenderer
  70:                                   implements Cloneable, PublicCloneable, 
  71:                                              Serializable {
  72: 
  73:     /** For serialization. */
  74:     private static final long serialVersionUID = -5121079703118261470L;
  75:     
  76:     /** The stagger width. */
  77:     public static final int STAGGER_WIDTH = 5; // could make this configurable
  78:   
  79:     /** 
  80:      * A flag that controls whether or not the steps for multiple series are 
  81:      * staggered. 
  82:      */
  83:     private boolean stagger = false;
  84:     
  85:     /** A working line - need to remove this. */
  86:     private transient Line2D line = new Line2D.Double(0.0, 0.0, 0.0, 0.0);
  87: 
  88:     /** 
  89:      * Creates a new renderer (stagger defaults to <code>false</code>).
  90:      */
  91:     public CategoryStepRenderer() {
  92:         this(false);
  93:     }
  94:     
  95:     /**
  96:      * Creates a new renderer.
  97:      *  
  98:      * @param stagger  should the horizontal part of the step be staggered by 
  99:      *                 series? 
 100:      */
 101:     public CategoryStepRenderer(boolean stagger) {
 102:         this.stagger = stagger;
 103:     }
 104:   
 105:     /**
 106:      * Returns the flag that controls whether the series steps are staggered.
 107:      * 
 108:      * @return A boolean.
 109:      */
 110:     public boolean getStagger() {
 111:         return this.stagger;
 112:     }
 113:     
 114:     /**
 115:      * Sets the flag that controls whether or not the series steps are 
 116:      * staggered and sends a {@link RendererChangeEvent} to all registered
 117:      * listeners.
 118:      * 
 119:      * @param shouldStagger  a boolean.
 120:      */
 121:     public void setStagger(boolean shouldStagger) {
 122:         this.stagger = shouldStagger;
 123:         notifyListeners(new RendererChangeEvent(this));
 124:     }
 125:    
 126:     /**
 127:      * Draws the line.
 128:      * 
 129:      * @param g2  the graphics device.
 130:      * @param orientation  the plot orientation.
 131:      * @param x0  the x-coordinate for the start of the line.
 132:      * @param y0  the y-coordinate for the start of the line.
 133:      * @param x1  the x-coordinate for the end of the line.
 134:      * @param y1  the y-coordinate for the end of the line.
 135:      */
 136:     protected void drawLine(Graphics2D g2, PlotOrientation orientation,
 137:                             double x0, double y0, double x1, double y1) {
 138:      
 139:         if (orientation == PlotOrientation.VERTICAL) {
 140:             this.line.setLine(x0, y0, x1, y1);
 141:             g2.draw(this.line);
 142:         }
 143:         else if (orientation == PlotOrientation.HORIZONTAL) {
 144:             this.line.setLine(y0, x0, y1, x1); // switch x and y
 145:             g2.draw(this.line);
 146:         }
 147:         // else unknown orientation (complain?)
 148:     }
 149: 
 150:     /**
 151:      * Draw a single data item.
 152:      *
 153:      * @param g2  the graphics device.
 154:      * @param state  the renderer state.
 155:      * @param dataArea  the area in which the data is drawn.
 156:      * @param plot  the plot.
 157:      * @param domainAxis  the domain axis.
 158:      * @param rangeAxis  the range axis.
 159:      * @param dataset  the dataset.
 160:      * @param row  the row index (zero-based).
 161:      * @param column  the column index (zero-based).
 162:      * @param pass  the pass index.
 163:      */
 164:     public void drawItem(Graphics2D g2,
 165:                          CategoryItemRendererState state,
 166:                          Rectangle2D dataArea,
 167:                          CategoryPlot plot,
 168:                          CategoryAxis domainAxis,
 169:                          ValueAxis rangeAxis,
 170:                          CategoryDataset dataset,
 171:                          int row,
 172:                          int column,
 173:                          int pass) {
 174: 
 175:         Number value = dataset.getValue(row, column);
 176:         if (value == null) {
 177:             return;
 178:         }
 179:         PlotOrientation orientation = plot.getOrientation();
 180: 
 181:         // current data point...
 182:         double x1s = domainAxis.getCategoryStart(
 183:             column, getColumnCount(), dataArea, plot.getDomainAxisEdge()
 184:         );
 185:         double x1 = domainAxis.getCategoryMiddle(
 186:             column, getColumnCount(), dataArea, plot.getDomainAxisEdge()
 187:         );
 188:         double x1e = 2 * x1 - x1s; // or: x1s + 2*(x1-x1s)
 189:         double y1 = rangeAxis.valueToJava2D(
 190:             value.doubleValue(), dataArea, plot.getRangeAxisEdge()
 191:         );
 192:         g2.setPaint(getItemPaint(row, column));
 193:         g2.setStroke(getItemStroke(row, column));
 194: 
 195:         if (column != 0) {
 196:             Number previousValue = dataset.getValue(row, column - 1);
 197:             if (previousValue != null) {
 198:                 // previous data point...
 199:                 double previous = previousValue.doubleValue();
 200:                 double x0s = domainAxis.getCategoryStart(
 201:                     column - 1, getColumnCount(), dataArea, 
 202:                     plot.getDomainAxisEdge()
 203:                 );
 204:                 double x0 = domainAxis.getCategoryMiddle(
 205:                     column - 1, getColumnCount(), dataArea, 
 206:                     plot.getDomainAxisEdge()
 207:                 );
 208:                 double x0e = 2 * x0 - x0s; // or: x0s + 2*(x0-x0s)
 209:                 double y0 = rangeAxis.valueToJava2D(
 210:                     previous, dataArea, plot.getRangeAxisEdge()
 211:                 );
 212:                 if (getStagger()) {
 213:                     int xStagger = row * STAGGER_WIDTH;
 214:                     if (xStagger > (x1s - x0e)) {
 215:                         xStagger = (int) (x1s - x0e);
 216:                     }
 217:                     x1s = x0e + xStagger;
 218:                 }
 219:                 drawLine(g2, orientation, x0e, y0, x1s, y0); 
 220:                     // extend x0's flat bar
 221: 
 222:                 drawLine(g2, orientation, x1s, y0, x1s, y1); // upright bar
 223:            }
 224:        }
 225:        drawLine(g2, orientation, x1s, y1, x1e, y1); // x1's flat bar
 226: 
 227:        // draw the item labels if there are any...
 228:        if (isItemLabelVisible(row, column)) {
 229:             drawItemLabel(
 230:                 g2, orientation, dataset, row, column, x1, y1, 
 231:                 (value.doubleValue() < 0.0)
 232:             );
 233:        }
 234:     /* This is how LineAndShapeRenderer.drawItem() handles tips and URLs, but
 235:        I omit it due to time pressure. It shouldn't be hard to put back
 236:  in.
 237: 
 238:        // collect entity and tool tip information...
 239:        if (state.getInfo() != null) {
 240:            EntityCollection entities =
 241:  state.getInfo().getOwner().getEntityCollection();
 242:            if (entities != null && shape != null) {
 243:                String tip = null;
 244:                CategoryItemLabelGenerator generator =
 245:  getItemLabelGenerator(row, column);
 246:                if (generator != null) {
 247:                    tip = generator.generateToolTip(dataset, row, column);
 248:                }
 249:                String url = null;
 250:                if (getItemURLGenerator(row, column) != null)                    
 251:                url = getItemURLGenerator(row, column).generateURL(dataset, row, 
 252:                  column);
 253:                }
 254:                CategoryItemEntity entity = new CategoryItemEntity(
 255:                    shape, tip, url, dataset, row,
 256:  dataset.getColumnKey(column), column);
 257:                entities.addEntity(entity);
 258:            }
 259:        }
 260:     */
 261: 
 262:     }
 263:     
 264:     /**
 265:      * Tests this renderer for equality with an arbitrary object.
 266:      * 
 267:      * @param obj  the object (<code>null</code> permitted).
 268:      * 
 269:      * @return A boolean.
 270:      */
 271:     public boolean equals(Object obj) {
 272:         if (obj == this) {
 273:             return true;   
 274:         }
 275:         if (!(obj instanceof CategoryStepRenderer)) {
 276:             return false;   
 277:         }
 278:         if (!super.equals(obj)) {
 279:             return false;   
 280:         }
 281:         CategoryStepRenderer that = (CategoryStepRenderer) obj;
 282:         if (this.stagger != that.stagger) {
 283:             return false;   
 284:         }
 285:         return true;
 286:     }
 287: 
 288: }