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    }