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