001    /* ===========================================================
002     * JFreeChart : a free chart library for the Java(tm) platform
003     * ===========================================================
004     *
005     * (C) Copyright 2000-2005, 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, by Object Refinery Limited.
031     *
032     * Original Author:  Thomas Morgner;
033     * Contributor(s):   David Gilbert (for Object Refinery Limited);
034     *
035     * $Id: XYLine3DRenderer.java,v 1.4.2.1 2005/10/25 20:56:21 mungady Exp $
036     *
037     * Changes
038     * -------
039     * 14-Jan-2005 : Added standard header (DG);
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.Serializable;
049    
050    import org.jfree.chart.Effect3D;
051    import org.jfree.chart.event.RendererChangeEvent;
052    
053    /**
054     * A XYLineAndShapeRenderer that adds a shadow line to the graph
055     * to emulate a 3D-effect.
056     */
057    public class XYLine3DRenderer extends XYLineAndShapeRenderer 
058                                  implements Effect3D, Serializable {
059    
060        /** For serialization. */
061        private static final long serialVersionUID = 588933208243446087L;
062        
063        /** The default x-offset for the 3D effect. */
064        public static final double DEFAULT_X_OFFSET = 12.0;
065    
066        /** The default y-offset for the 3D effect. */
067        public static final double DEFAULT_Y_OFFSET = 8.0;
068    
069        /** The default wall paint. */
070        public static final Paint DEFAULT_WALL_PAINT = new Color(0xDD, 0xDD, 0xDD);
071    
072        /** The size of x-offset for the 3D effect. */
073        private double xOffset;
074    
075        /** The size of y-offset for the 3D effect. */
076        private double yOffset;
077    
078        /** The paint used to shade the left and lower 3D wall. */
079        private transient Paint wallPaint;
080    
081        /**
082         * Creates a new renderer.
083         */
084        public XYLine3DRenderer() {
085            this.wallPaint = DEFAULT_WALL_PAINT;
086            this.xOffset = DEFAULT_X_OFFSET;
087            this.yOffset = DEFAULT_Y_OFFSET;
088        }
089    
090        /**
091         * Returns the x-offset for the 3D effect.
092         *
093         * @return The 3D effect.
094         */
095        public double getXOffset() {
096            return this.xOffset;
097        }
098    
099        /**
100         * Returns the y-offset for the 3D effect.
101         *
102         * @return The 3D effect.
103         */
104        public double getYOffset() {
105            return this.yOffset;
106        }
107    
108        /**
109         * Sets the x-offset and sends a {@link RendererChangeEvent} to all 
110         * registered listeners.
111         * 
112         * @param xOffset  the x-offset.
113         */
114        public void setXOffset(double xOffset) {
115            this.xOffset = xOffset;
116            notifyListeners(new RendererChangeEvent(this));
117        }
118    
119        /**
120         * Sets the y-offset and sends a {@link RendererChangeEvent} to all 
121         * registered listeners.
122         * 
123         * @param yOffset  the y-offset.
124         */
125        public void setYOffset(double yOffset) {
126            this.yOffset = yOffset;
127            notifyListeners(new RendererChangeEvent(this));
128        }
129    
130        /**
131         * Returns the paint used to highlight the left and bottom wall in the plot
132         * background.
133         *
134         * @return The paint.
135         */
136        public Paint getWallPaint() {
137            return this.wallPaint;
138        }
139    
140        /**
141         * Sets the paint used to hightlight the left and bottom walls in the plot 
142         * background.
143         *
144         * @param paint  the paint.
145         */
146        public void setWallPaint(Paint paint) {
147            this.wallPaint = paint;
148            notifyListeners(new RendererChangeEvent(this));
149        }
150    
151        /**
152         * Returns the number of passes through the data that the renderer requires 
153         * in order to draw the chart.  Most charts will require a single pass, 
154         * but some require two passes.
155         *
156         * @return The pass count.
157         */
158        public int getPassCount() {
159            return 3;
160        }
161    
162        /**
163         * Returns <code>true</code> if the specified pass involves drawing lines.
164         * 
165         * @param pass  the pass.
166         * 
167         * @return A boolean.
168         */
169        protected boolean isLinePass(int pass) {
170            return pass == 0 || pass == 1;
171        }
172    
173        /**
174         * Returns <code>true</code> if the specified pass involves drawing items.
175         * 
176         * @param pass  the pass.
177         * 
178         * @return A boolean.
179         */
180        protected boolean isItemPass(int pass) {
181            return pass == 2;
182        }
183    
184        /**
185         * Returns <code>true</code> if the specified pass involves drawing shadows.
186         * 
187         * @param pass  the pass.
188         * 
189         * @return A boolean.
190         */
191        protected boolean isShadowPass (int pass) {
192            return pass == 0;
193        }
194    
195        /**
196         * Overrides the method in the subclass to draw a shadow in the first pass.
197         * 
198         * @param g2  the graphics device.
199         * @param pass  the pass.
200         * @param series  the series index (zero-based).
201         * @param item  the item index (zero-based).
202         * @param shape  the shape.
203         */
204        protected void drawFirstPassShape(Graphics2D g2,
205                                          int pass,
206                                          int series,
207                                          int item,
208                                          Shape shape) {
209            if (isShadowPass(pass)) {
210                if (getWallPaint() != null) {
211                    g2.setStroke(getItemStroke(series, item));
212                    g2.setPaint(getWallPaint());
213                    g2.translate(getXOffset(), getYOffset());
214                    g2.draw(shape);
215                    g2.translate(-getXOffset(), -getYOffset());
216                }
217            }
218            else {
219                // now draw the real shape
220                super.drawFirstPassShape(g2, pass, series, item, shape);
221            }
222        }
223    
224    }