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    }