Source for org.jfree.chart.renderer.xy.XYLine3DRenderer

   1: /* ===========================================================
   2:  * JFreeChart : a free chart library for the Java(tm) platform
   3:  * ===========================================================
   4:  *
   5:  * (C) Copyright 2000-2007, 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:  * XYLine3DRenderer.java
  29:  * ---------------------
  30:  * (C) Copyright 2005, 2007, by Object Refinery Limited.
  31:  *
  32:  * Original Author:  Thomas Morgner;
  33:  * Contributor(s):   David Gilbert (for Object Refinery Limited);
  34:  *
  35:  * Changes
  36:  * -------
  37:  * 14-Jan-2005 : Added standard header (DG);
  38:  * 01-May-2007 : Fixed equals() and serialization bugs (DG);
  39:  * 
  40:  */
  41: 
  42: package org.jfree.chart.renderer.xy;
  43: 
  44: import java.awt.Color;
  45: import java.awt.Graphics2D;
  46: import java.awt.Paint;
  47: import java.awt.Shape;
  48: import java.io.IOException;
  49: import java.io.ObjectInputStream;
  50: import java.io.ObjectOutputStream;
  51: import java.io.Serializable;
  52: 
  53: import org.jfree.chart.Effect3D;
  54: import org.jfree.chart.event.RendererChangeEvent;
  55: import org.jfree.io.SerialUtilities;
  56: import org.jfree.util.PaintUtilities;
  57: 
  58: /**
  59:  * A XYLineAndShapeRenderer that adds a shadow line to the graph
  60:  * to emulate a 3D-effect.
  61:  */
  62: public class XYLine3DRenderer extends XYLineAndShapeRenderer 
  63:                               implements Effect3D, Serializable {
  64: 
  65:     /** For serialization. */
  66:     private static final long serialVersionUID = 588933208243446087L;
  67:     
  68:     /** The default x-offset for the 3D effect. */
  69:     public static final double DEFAULT_X_OFFSET = 12.0;
  70: 
  71:     /** The default y-offset for the 3D effect. */
  72:     public static final double DEFAULT_Y_OFFSET = 8.0;
  73: 
  74:     /** The default wall paint. */
  75:     public static final Paint DEFAULT_WALL_PAINT = new Color(0xDD, 0xDD, 0xDD);
  76: 
  77:     /** The size of x-offset for the 3D effect. */
  78:     private double xOffset;
  79: 
  80:     /** The size of y-offset for the 3D effect. */
  81:     private double yOffset;
  82: 
  83:     /** The paint used to shade the left and lower 3D wall. */
  84:     private transient Paint wallPaint;
  85: 
  86:     /**
  87:      * Creates a new renderer.
  88:      */
  89:     public XYLine3DRenderer() {
  90:         this.wallPaint = DEFAULT_WALL_PAINT;
  91:         this.xOffset = DEFAULT_X_OFFSET;
  92:         this.yOffset = DEFAULT_Y_OFFSET;
  93:     }
  94: 
  95:     /**
  96:      * Returns the x-offset for the 3D effect.
  97:      *
  98:      * @return The 3D effect.
  99:      */
 100:     public double getXOffset() {
 101:         return this.xOffset;
 102:     }
 103: 
 104:     /**
 105:      * Returns the y-offset for the 3D effect.
 106:      *
 107:      * @return The 3D effect.
 108:      */
 109:     public double getYOffset() {
 110:         return this.yOffset;
 111:     }
 112: 
 113:     /**
 114:      * Sets the x-offset and sends a {@link RendererChangeEvent} to all 
 115:      * registered listeners.
 116:      * 
 117:      * @param xOffset  the x-offset.
 118:      */
 119:     public void setXOffset(double xOffset) {
 120:         this.xOffset = xOffset;
 121:         notifyListeners(new RendererChangeEvent(this));
 122:     }
 123: 
 124:     /**
 125:      * Sets the y-offset and sends a {@link RendererChangeEvent} to all 
 126:      * registered listeners.
 127:      * 
 128:      * @param yOffset  the y-offset.
 129:      */
 130:     public void setYOffset(double yOffset) {
 131:         this.yOffset = yOffset;
 132:         notifyListeners(new RendererChangeEvent(this));
 133:     }
 134: 
 135:     /**
 136:      * Returns the paint used to highlight the left and bottom wall in the plot
 137:      * background.
 138:      *
 139:      * @return The paint.
 140:      */
 141:     public Paint getWallPaint() {
 142:         return this.wallPaint;
 143:     }
 144: 
 145:     /**
 146:      * Sets the paint used to hightlight the left and bottom walls in the plot 
 147:      * background.
 148:      *
 149:      * @param paint  the paint.
 150:      */
 151:     public void setWallPaint(Paint paint) {
 152:         this.wallPaint = paint;
 153:         notifyListeners(new RendererChangeEvent(this));
 154:     }
 155: 
 156:     /**
 157:      * Returns the number of passes through the data that the renderer requires 
 158:      * in order to draw the chart.  Most charts will require a single pass, 
 159:      * but some require two passes.
 160:      *
 161:      * @return The pass count.
 162:      */
 163:     public int getPassCount() {
 164:         return 3;
 165:     }
 166: 
 167:     /**
 168:      * Returns <code>true</code> if the specified pass involves drawing lines.
 169:      * 
 170:      * @param pass  the pass.
 171:      * 
 172:      * @return A boolean.
 173:      */
 174:     protected boolean isLinePass(int pass) {
 175:         return pass == 0 || pass == 1;
 176:     }
 177: 
 178:     /**
 179:      * Returns <code>true</code> if the specified pass involves drawing items.
 180:      * 
 181:      * @param pass  the pass.
 182:      * 
 183:      * @return A boolean.
 184:      */
 185:     protected boolean isItemPass(int pass) {
 186:         return pass == 2;
 187:     }
 188: 
 189:     /**
 190:      * Returns <code>true</code> if the specified pass involves drawing shadows.
 191:      * 
 192:      * @param pass  the pass.
 193:      * 
 194:      * @return A boolean.
 195:      */
 196:     protected boolean isShadowPass (int pass) {
 197:         return pass == 0;
 198:     }
 199: 
 200:     /**
 201:      * Overrides the method in the subclass to draw a shadow in the first pass.
 202:      * 
 203:      * @param g2  the graphics device.
 204:      * @param pass  the pass.
 205:      * @param series  the series index (zero-based).
 206:      * @param item  the item index (zero-based).
 207:      * @param shape  the shape.
 208:      */
 209:     protected void drawFirstPassShape(Graphics2D g2,
 210:                                       int pass,
 211:                                       int series,
 212:                                       int item,
 213:                                       Shape shape) {
 214:         if (isShadowPass(pass)) {
 215:             if (getWallPaint() != null) {
 216:                 g2.setStroke(getItemStroke(series, item));
 217:                 g2.setPaint(getWallPaint());
 218:                 g2.translate(getXOffset(), getYOffset());
 219:                 g2.draw(shape);
 220:                 g2.translate(-getXOffset(), -getYOffset());
 221:             }
 222:         }
 223:         else {
 224:             // now draw the real shape
 225:             super.drawFirstPassShape(g2, pass, series, item, shape);
 226:         }
 227:     }
 228: 
 229:     /**
 230:      * Tests this renderer for equality with an arbitrary object.
 231:      * 
 232:      * @param obj  the object (<code>null</code> permitted).
 233:      * 
 234:      * @return A boolean.
 235:      */
 236:     public boolean equals(Object obj) {
 237:         if (obj == this) {
 238:             return true;
 239:         }
 240:         if (!(obj instanceof XYLine3DRenderer)) {
 241:             return false;
 242:         }
 243:         XYLine3DRenderer that = (XYLine3DRenderer) obj;
 244:         if (this.xOffset != that.xOffset) {
 245:             return false;
 246:         }
 247:         if (this.yOffset != that.yOffset) {
 248:             return false;
 249:         }
 250:         if (!PaintUtilities.equal(this.wallPaint, that.wallPaint)) {
 251:             return false;
 252:         }
 253:         return super.equals(obj);
 254:     }
 255:     
 256:     /**
 257:      * Provides serialization support.
 258:      *
 259:      * @param stream  the input stream.
 260:      *
 261:      * @throws IOException  if there is an I/O error.
 262:      * @throws ClassNotFoundException  if there is a classpath problem.
 263:      */
 264:     private void readObject(ObjectInputStream stream) 
 265:             throws IOException, ClassNotFoundException {
 266:         stream.defaultReadObject();
 267:         this.wallPaint = SerialUtilities.readPaint(stream);
 268:     }
 269:     
 270:     /**
 271:      * Provides serialization support.
 272:      *
 273:      * @param stream  the output stream.
 274:      *
 275:      * @throws IOException  if there is an I/O error.
 276:      */
 277:     private void writeObject(ObjectOutputStream stream) throws IOException {
 278:         stream.defaultWriteObject();
 279:         SerialUtilities.writePaint(this.wallPaint, stream);
 280:     }
 281: 
 282: }