    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    }