001 /* ===========================================================
002 * JFreeChart : a free chart library for the Java(tm) platform
003 * ===========================================================
004 *
005 * (C) Copyright 2000-2007, 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 * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
025 * in the United States and other countries.]
026 *
027 * ---------------------
028 * XYLine3DRenderer.java
029 * ---------------------
030 * (C) Copyright 2005, 2007, by Object Refinery Limited.
031 *
032 * Original Author: Thomas Morgner;
033 * Contributor(s): David Gilbert (for Object Refinery Limited);
034 *
035 * Changes
036 * -------
037 * 14-Jan-2005 : Added standard header (DG);
038 * 01-May-2007 : Fixed equals() and serialization bugs (DG);
039 *
040 */
041
042 package org.jfree.chart.renderer.xy;
043
044 import java.awt.Color;
045 import java.awt.Graphics2D;
046 import java.awt.Paint;
047 import java.awt.Shape;
048 import java.io.IOException;
049 import java.io.ObjectInputStream;
050 import java.io.ObjectOutputStream;
051 import java.io.Serializable;
052
053 import org.jfree.chart.Effect3D;
054 import org.jfree.chart.event.RendererChangeEvent;
055 import org.jfree.io.SerialUtilities;
056 import org.jfree.util.PaintUtilities;
057
058 /**
059 * A XYLineAndShapeRenderer that adds a shadow line to the graph
060 * to emulate a 3D-effect.
061 */
062 public class XYLine3DRenderer extends XYLineAndShapeRenderer
063 implements Effect3D, Serializable {
064
065 /** For serialization. */
066 private static final long serialVersionUID = 588933208243446087L;
067
068 /** The default x-offset for the 3D effect. */
069 public static final double DEFAULT_X_OFFSET = 12.0;
070
071 /** The default y-offset for the 3D effect. */
072 public static final double DEFAULT_Y_OFFSET = 8.0;
073
074 /** The default wall paint. */
075 public static final Paint DEFAULT_WALL_PAINT = new Color(0xDD, 0xDD, 0xDD);
076
077 /** The size of x-offset for the 3D effect. */
078 private double xOffset;
079
080 /** The size of y-offset for the 3D effect. */
081 private double yOffset;
082
083 /** The paint used to shade the left and lower 3D wall. */
084 private transient Paint wallPaint;
085
086 /**
087 * Creates a new renderer.
088 */
089 public XYLine3DRenderer() {
090 this.wallPaint = DEFAULT_WALL_PAINT;
091 this.xOffset = DEFAULT_X_OFFSET;
092 this.yOffset = DEFAULT_Y_OFFSET;
093 }
094
095 /**
096 * Returns the x-offset for the 3D effect.
097 *
098 * @return The 3D effect.
099 */
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 fireChangeEvent();
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 fireChangeEvent();
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 and sends a {@link RendererChangeEvent} to all registered
148 * listeners.
149 *
150 * @param paint the paint.
151 */
152 public void setWallPaint(Paint paint) {
153 this.wallPaint = paint;
154 fireChangeEvent();
155 }
156
157 /**
158 * Returns the number of passes through the data that the renderer requires
159 * in order to draw the chart. Most charts will require a single pass,
160 * but some require two passes.
161 *
162 * @return The pass count.
163 */
164 public int getPassCount() {
165 return 3;
166 }
167
168 /**
169 * Returns <code>true</code> if the specified pass involves drawing lines.
170 *
171 * @param pass the pass.
172 *
173 * @return A boolean.
174 */
175 protected boolean isLinePass(int pass) {
176 return pass == 0 || pass == 1;
177 }
178
179 /**
180 * Returns <code>true</code> if the specified pass involves drawing items.
181 *
182 * @param pass the pass.
183 *
184 * @return A boolean.
185 */
186 protected boolean isItemPass(int pass) {
187 return pass == 2;
188 }
189
190 /**
191 * Returns <code>true</code> if the specified pass involves drawing shadows.
192 *
193 * @param pass the pass.
194 *
195 * @return A boolean.
196 */
197 protected boolean isShadowPass (int pass) {
198 return pass == 0;
199 }
200
201 /**
202 * Overrides the method in the subclass to draw a shadow in the first pass.
203 *
204 * @param g2 the graphics device.
205 * @param pass the pass.
206 * @param series the series index (zero-based).
207 * @param item the item index (zero-based).
208 * @param shape the shape.
209 */
210 protected void drawFirstPassShape(Graphics2D g2,
211 int pass,
212 int series,
213 int item,
214 Shape shape) {
215 if (isShadowPass(pass)) {
216 if (getWallPaint() != null) {
217 g2.setStroke(getItemStroke(series, item));
218 g2.setPaint(getWallPaint());
219 g2.translate(getXOffset(), getYOffset());
220 g2.draw(shape);
221 g2.translate(-getXOffset(), -getYOffset());
222 }
223 }
224 else {
225 // now draw the real shape
226 super.drawFirstPassShape(g2, pass, series, item, shape);
227 }
228 }
229
230 /**
231 * Tests this renderer for equality with an arbitrary object.
232 *
233 * @param obj the object (<code>null</code> permitted).
234 *
235 * @return A boolean.
236 */
237 public boolean equals(Object obj) {
238 if (obj == this) {
239 return true;
240 }
241 if (!(obj instanceof XYLine3DRenderer)) {
242 return false;
243 }
244 XYLine3DRenderer that = (XYLine3DRenderer) obj;
245 if (this.xOffset != that.xOffset) {
246 return false;
247 }
248 if (this.yOffset != that.yOffset) {
249 return false;
250 }
251 if (!PaintUtilities.equal(this.wallPaint, that.wallPaint)) {
252 return false;
253 }
254 return super.equals(obj);
255 }
256
257 /**
258 * Provides serialization support.
259 *
260 * @param stream the input stream.
261 *
262 * @throws IOException if there is an I/O error.
263 * @throws ClassNotFoundException if there is a classpath problem.
264 */
265 private void readObject(ObjectInputStream stream)
266 throws IOException, ClassNotFoundException {
267 stream.defaultReadObject();
268 this.wallPaint = SerialUtilities.readPaint(stream);
269 }
270
271 /**
272 * Provides serialization support.
273 *
274 * @param stream the output stream.
275 *
276 * @throws IOException if there is an I/O error.
277 */
278 private void writeObject(ObjectOutputStream stream) throws IOException {
279 stream.defaultWriteObject();
280 SerialUtilities.writePaint(this.wallPaint, stream);
281 }
282
283 }