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