    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     * XYStepRenderer.java
    029     * -------------------
    030     * (C) Copyright 2002-2007, by Roger Studner and Contributors.
    031     *
    032     * Original Author:  Roger Studner;
    033     * Contributor(s):   David Gilbert (for Object Refinery Limited);
    034     *                   Matthias Rose;
    035     *                   Gerald Struck (fix for bug 1569094);
    036     *
    037     * Changes
    038     * -------
    039     * 13-May-2002 : Version 1, contributed by Roger Studner (DG);
    040     * 25-Jun-2002 : Updated import statements (DG);
    041     * 22-Jul-2002 : Added check for null data items (DG);
    042     * 25-Mar-2003 : Implemented Serializable (DG);
    043     * 01-May-2003 : Modified drawItem() method signature (DG);
    044     * 20-Aug-2003 : Implemented Cloneable and PublicCloneable (DG);
    045     * 16-Sep-2003 : Changed ChartRenderingInfo --> PlotRenderingInfo (DG);
    046     * 28-Oct-2003 : Added tooltips, code contributed by Matthias Rose
    047     *               (RFE 824857) (DG);
    048     * 10-Feb-2004 : Removed working line (use line from state object instead) (DG);
    049     * 25-Feb-2004 : Replaced CrosshairInfo with CrosshairState.  Renamed
    050     *               XYToolTipGenerator --> XYItemLabelGenerator (DG);
    051     * 19-Jan-2005 : Now accesses only primitives from dataset (DG);
    052     * 15-Mar-2005 : Fix silly bug in drawItem() method (DG);
    053     * 19-Sep-2005 : Extend XYLineAndShapeRenderer (fixes legend shapes), added
    054     *               support for series visibility, and use getDefaultEntityRadius()
    055     *               for entity hotspot size (DG);
    056     * ------------- JFREECHART 1.0.x ---------------------------------------------
    057     * 15-Jun-2006 : Added basic support for item labels (DG);
    058     * 11-Oct-2006 : Fixed rendering with horizontal orientation (see bug 1569094),
    059     *               thanks to Gerald Struck (DG);
    060     * 06-Feb-2007 : Fixed bug 1086307, crosshairs with multiple axes (DG);
    061     *
    062     */
    063
    064    package org.jfree.chart.renderer.xy;
    065
    066    import java.awt.Graphics2D;
    067    import java.awt.Paint;
    068    import java.awt.Shape;
    069    import java.awt.Stroke;
    070    import java.awt.geom.Line2D;
    071    import java.awt.geom.Rectangle2D;
    072    import java.io.Serializable;
    073
    074    import org.jfree.chart.axis.ValueAxis;
    075    import org.jfree.chart.entity.EntityCollection;
    076    import org.jfree.chart.entity.XYItemEntity;
    077    import org.jfree.chart.labels.XYToolTipGenerator;
    078    import org.jfree.chart.plot.CrosshairState;
    079    import org.jfree.chart.plot.PlotOrientation;
    080    import org.jfree.chart.plot.PlotRenderingInfo;
    081    import org.jfree.chart.plot.XYPlot;
    082    import org.jfree.chart.urls.XYURLGenerator;
    083    import org.jfree.data.xy.XYDataset;
    084    import org.jfree.ui.RectangleEdge;
    085    import org.jfree.util.PublicCloneable;
    086
    087    /**
    088     * Line/Step item renderer for an {@link XYPlot}.  This class draws lines
    089     * between data points, only allowing horizontal or vertical lines (steps).
    090     */
    091    public class XYStepRenderer extends XYLineAndShapeRenderer
    092                                implements XYItemRenderer,
    093                                           Cloneable,
    094                                           PublicCloneable,
    095                                           Serializable {
    096
    097        /** For serialization. */
    098        private static final long serialVersionUID = -8918141928884796108L;
    099
    100        /**
    101         * Constructs a new renderer with no tooltip or URL generation.
    102         */
    103        public XYStepRenderer() {
    104            this(null, null);
    105        }
    106
    107        /**
    108         * Constructs a new renderer with the specified tool tip and URL
    109         * generators.
    110         *
    111         * @param toolTipGenerator  the item label generator (<code>null</code>
    112         *     permitted).
    113         * @param urlGenerator  the URL generator (<code>null</code> permitted).
    114         */
    115        public XYStepRenderer(XYToolTipGenerator toolTipGenerator,
    116                              XYURLGenerator urlGenerator) {
    117            super();
    118            setBaseToolTipGenerator(toolTipGenerator);
    119            setURLGenerator(urlGenerator);
    120            setShapesVisible(false);
    121        }
    122
    123        /**
    124         * Draws the visual representation of a single data item.
    125         *
    126         * @param g2  the graphics device.
    127         * @param state  the renderer state.
    128         * @param dataArea  the area within which the data is being drawn.
    129         * @param info  collects information about the drawing.
    130         * @param plot  the plot (can be used to obtain standard color
    131         *              information etc).
    132         * @param domainAxis  the domain axis.
    133         * @param rangeAxis  the vertical axis.
    134         * @param dataset  the dataset.
    135         * @param series  the series index (zero-based).
    136         * @param item  the item index (zero-based).
    137         * @param crosshairState  crosshair information for the plot
    138         *                        (<code>null</code> permitted).
    139         * @param pass  the pass index (ignored here).
    140         */
    141        public void drawItem(Graphics2D g2,
    142                             XYItemRendererState state,
    143                             Rectangle2D dataArea,
    144                             PlotRenderingInfo info,
    145                             XYPlot plot,
    146                             ValueAxis domainAxis,
    147                             ValueAxis rangeAxis,
    148                             XYDataset dataset,
    149                             int series,
    150                             int item,
    151                             CrosshairState crosshairState,
    152                             int pass) {
    153
    154            // do nothing if item is not visible
    155            if (!getItemVisible(series, item)) {
    156                return;
    157            }
    158
    159            PlotOrientation orientation = plot.getOrientation();
    160
    161            Paint seriesPaint = getItemPaint(series, item);
    162            Stroke seriesStroke = getItemStroke(series, item);
    163            g2.setPaint(seriesPaint);
    164            g2.setStroke(seriesStroke);
    165
    166            // get the data point...
    167            double x1 = dataset.getXValue(series, item);
    168            double y1 = dataset.getYValue(series, item);
    169            if (Double.isNaN(y1)) {
    170                return;
    171            }
    172
    173            RectangleEdge xAxisLocation = plot.getDomainAxisEdge();
    174            RectangleEdge yAxisLocation = plot.getRangeAxisEdge();
    175            double transX1 = domainAxis.valueToJava2D(x1, dataArea, xAxisLocation);
    176            double transY1 = rangeAxis.valueToJava2D(y1, dataArea, yAxisLocation);
    177
    178            if (item > 0) {
    179                // get the previous data point...
    180                double x0 = dataset.getXValue(series, item - 1);
    181                double y0 = dataset.getYValue(series, item - 1);
    182                if (!Double.isNaN(y0)) {
    183                    double transX0 = domainAxis.valueToJava2D(x0, dataArea,
    184                            xAxisLocation);
    185                    double transY0 = rangeAxis.valueToJava2D(y0, dataArea,
    186                            yAxisLocation);
    187
    188                    Line2D line = state.workingLine;
    189                    if (orientation == PlotOrientation.HORIZONTAL) {
    190                        if (transY0 == transY1) { //this represents the situation
    191                                                  // for drawing a horizontal bar.
    192                            line.setLine(transY0, transX0, transY1, transX1);
    193                            g2.draw(line);
    194                        }
    195                        else {  //this handles the need to perform a 'step'.
    196                            line.setLine(transY0, transX0, transY0, transX1);
    197                            g2.draw(line);
    198                            line.setLine(transY0, transX1, transY1, transX1);
    199                            g2.draw(line);
    200                        }
    201                    }
    202                    else if (orientation == PlotOrientation.VERTICAL) {
    203                        if (transY0 == transY1) { // this represents the situation
    204                                                  // for drawing a horizontal bar.
    205                            line.setLine(transX0, transY0, transX1, transY1);
    206                            g2.draw(line);
    207                        }
    208                        else {  //this handles the need to perform a 'step'.
    209                            line.setLine(transX0, transY0, transX1, transY0);
    210                            g2.draw(line);
    211                            line.setLine(transX1, transY0, transX1, transY1);
    212                            g2.draw(line);
    213                        }
    214                    }
    215
    216                }
    217            }
    218
    219            // draw the item label if there is one...
    220            if (isItemLabelVisible(series, item)) {
    221                double xx = transX1;
    222                double yy = transY1;
    223                if (orientation == PlotOrientation.HORIZONTAL) {
    224                    xx = transY1;
    225                    yy = transX1;
    226                }
    227                drawItemLabel(g2, orientation, dataset, series, item, xx, yy,
    228                        (y1 < 0.0));
    229            }
    230
    231            int domainAxisIndex = plot.getDomainAxisIndex(domainAxis);
    232            int rangeAxisIndex = plot.getRangeAxisIndex(rangeAxis);
    233            updateCrosshairValues(crosshairState, x1, y1, domainAxisIndex,
    234                    rangeAxisIndex, transX1, transY1, orientation);
    235
    236            // collect entity and tool tip information...
    237            if (state.getInfo() != null) {
    238                EntityCollection entities = state.getEntityCollection();
    239                if (entities != null) {
    240                    int r = getDefaultEntityRadius();
    241                    Shape shape = orientation == PlotOrientation.VERTICAL
    242                        ? new Rectangle2D.Double(transX1 - r, transY1 - r, 2 * r,
    243                                2 * r)
    244                        : new Rectangle2D.Double(transY1 - r, transX1 - r, 2 * r,
    245                                2 * r);
    246                    if (shape != null) {
    247                        String tip = null;
    248                        XYToolTipGenerator generator
    249                            = getToolTipGenerator(series, item);
    250                        if (generator != null) {
    251                            tip = generator.generateToolTip(dataset, series, item);
    252                        }
    253                        String url = null;
    254                        if (getURLGenerator() != null) {
    255                            url = getURLGenerator().generateURL(dataset, series,
    256                                    item);
    257                        }
    258                        XYItemEntity entity = new XYItemEntity(shape, dataset,
    259                                series, item, tip, url);
    260                        entities.add(entity);
    261                    }
    262                }
    263            }
    264        }
    265
    266        /**
    267         * Returns a clone of the renderer.
    268         *
    269         * @return A clone.
    270         *
    271         * @throws CloneNotSupportedException  if the renderer cannot be cloned.
    272         */
    273        public Object clone() throws CloneNotSupportedException {
    274            return super.clone();
    275        }
    276
    277    }