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     * XYDotRenderer.java
029     * ------------------
030     * (C) Copyright 2002-2007, by Object Refinery Limited.
031     *
032     * Original Author:  David Gilbert (for Object Refinery Limited);
033     * Contributor(s):   Christian W. Zuckschwerdt;
034     *
035     * $Id: XYDotRenderer.java,v 1.5.2.4 2007/02/06 16:29:11 mungady Exp $
036     *
037     * Changes (from 29-Oct-2002)
038     * --------------------------
039     * 29-Oct-2002 : Added standard header (DG);
040     * 25-Mar-2003 : Implemented Serializable (DG);
041     * 01-May-2003 : Modified drawItem() method signature (DG);
042     * 30-Jul-2003 : Modified entity constructor (CZ);
043     * 20-Aug-2003 : Implemented Cloneable and PublicCloneable (DG);
044     * 16-Sep-2003 : Changed ChartRenderingInfo --> PlotRenderingInfo (DG);
045     * 25-Feb-2004 : Replaced CrosshairInfo with CrosshairState (DG);
046     * 19-Jan-2005 : Now uses only primitives from dataset (DG);
047     * ------------- JFREECHART 1.0.x ---------------------------------------------
048     * 10-Jul-2006 : Added dotWidth and dotHeight attributes (DG);
049     * 06-Feb-2007 : Fixed bug 1086307, crosshairs with multiple axes (DG);
050     *
051     */
052    
053    package org.jfree.chart.renderer.xy;
054    
055    import java.awt.Graphics2D;
056    import java.awt.geom.Rectangle2D;
057    import java.io.Serializable;
058    
059    import org.jfree.chart.axis.ValueAxis;
060    import org.jfree.chart.event.RendererChangeEvent;
061    import org.jfree.chart.plot.CrosshairState;
062    import org.jfree.chart.plot.PlotOrientation;
063    import org.jfree.chart.plot.PlotRenderingInfo;
064    import org.jfree.chart.plot.XYPlot;
065    import org.jfree.data.xy.XYDataset;
066    import org.jfree.ui.RectangleEdge;
067    import org.jfree.util.PublicCloneable;
068    
069    /**
070     * A renderer that draws a small dot at each data point for an {@link XYPlot}.
071     */
072    public class XYDotRenderer extends AbstractXYItemRenderer 
073                               implements XYItemRenderer, 
074                                          Cloneable,
075                                          PublicCloneable,
076                                          Serializable {
077    
078        /** For serialization. */
079        private static final long serialVersionUID = -2764344339073566425L;
080        
081        /** The dot width. */
082        private int dotWidth;
083        
084        /** The dot height. */
085        private int dotHeight;
086        
087        /**
088         * Constructs a new renderer.
089         */
090        public XYDotRenderer() {
091            super();
092            this.dotWidth = 1;
093            this.dotHeight = 1;
094        }
095    
096        /**
097         * Returns the dot width (the default value is 1).
098         * 
099         * @return The dot width.
100         * 
101         * @since 1.0.2
102         * @see #setDotWidth(int)
103         */
104        public int getDotWidth() {
105            return this.dotWidth;
106        }
107        
108        /**
109         * Sets the dot width and sends a {@link RendererChangeEvent} to all 
110         * registered listeners.
111         * 
112         * @param w  the new width (must be greater than zero).
113         * 
114         * @throws IllegalArgumentException if <code>w</code> is less than one.
115         * 
116         * @since 1.0.2
117         * @see #getDotWidth()
118         */
119        public void setDotWidth(int w) {
120            if (w < 1) {
121                throw new IllegalArgumentException("Requires w > 0.");
122            }
123            this.dotWidth = w;
124            notifyListeners(new RendererChangeEvent(this));
125        }
126        
127        /**
128         * Returns the dot height (the default value is 1).
129         * 
130         * @return The dot height.
131         * 
132         * @since 1.0.2
133         * @see #setDotHeight(int)
134         */
135        public int getDotHeight() {
136            return this.dotHeight;
137        }
138        
139        /**
140         * Sets the dot height and sends a {@link RendererChangeEvent} to all 
141         * registered listeners.
142         * 
143         * @param h  the new height (must be greater than zero).
144         * 
145         * @throws IllegalArgumentException if <code>h</code> is less than one.
146         * 
147         * @since 1.0.2
148         * @see #getDotHeight()
149         */
150        public void setDotHeight(int h) {
151            if (h < 1) {
152                throw new IllegalArgumentException("Requires h > 0.");
153            }
154            this.dotHeight = h;
155            notifyListeners(new RendererChangeEvent(this));
156        }
157        
158        /**
159         * Draws the visual representation of a single data item.
160         *
161         * @param g2  the graphics device.
162         * @param state  the renderer state.
163         * @param dataArea  the area within which the data is being drawn.
164         * @param info  collects information about the drawing.
165         * @param plot  the plot (can be used to obtain standard color 
166         *              information etc).
167         * @param domainAxis  the domain (horizontal) axis.
168         * @param rangeAxis  the range (vertical) axis.
169         * @param dataset  the dataset.
170         * @param series  the series index (zero-based).
171         * @param item  the item index (zero-based).
172         * @param crosshairState  crosshair information for the plot 
173         *                        (<code>null</code> permitted).
174         * @param pass  the pass index.
175         */
176        public void drawItem(Graphics2D g2,
177                             XYItemRendererState state,
178                             Rectangle2D dataArea,
179                             PlotRenderingInfo info,
180                             XYPlot plot,
181                             ValueAxis domainAxis,
182                             ValueAxis rangeAxis,
183                             XYDataset dataset,
184                             int series,
185                             int item,
186                             CrosshairState crosshairState,
187                             int pass) {
188    
189            // get the data point...
190            double x = dataset.getXValue(series, item);
191            double y = dataset.getYValue(series, item);
192            double adjx = (this.dotWidth - 1) / 2.0;
193            double adjy = (this.dotHeight - 1) / 2.0;
194            if (!Double.isNaN(y)) {
195                RectangleEdge xAxisLocation = plot.getDomainAxisEdge();
196                RectangleEdge yAxisLocation = plot.getRangeAxisEdge();
197                double transX = domainAxis.valueToJava2D(x, dataArea, 
198                        xAxisLocation) - adjx;
199                double transY = rangeAxis.valueToJava2D(y, dataArea, yAxisLocation) 
200                        - adjy;
201    
202                g2.setPaint(getItemPaint(series, item));
203                PlotOrientation orientation = plot.getOrientation();
204                if (orientation == PlotOrientation.HORIZONTAL) {
205                    g2.fillRect((int) transY, (int) transX, this.dotHeight, 
206                            this.dotWidth);
207                }
208                else if (orientation == PlotOrientation.VERTICAL) {
209                    g2.fillRect((int) transX, (int) transY, this.dotWidth, 
210                            this.dotHeight);
211                }
212    
213                int domainAxisIndex = plot.getDomainAxisIndex(domainAxis);
214                int rangeAxisIndex = plot.getRangeAxisIndex(rangeAxis);
215                updateCrosshairValues(crosshairState, x, y, domainAxisIndex, 
216                        rangeAxisIndex, transX, transY, orientation);
217            }
218    
219        }
220    
221        /**
222         * Tests this renderer for equality with an arbitrary object.  This method
223         * returns <code>true</code> if and only if:
224         * 
225         * <ul>
226         * <li><code>obj</code> is not <code>null</code>;</li>
227         * <li><code>obj</code> is an instance of <code>XYDotRenderer</code>;</li>
228         * <li>both renderers have the same attribute values.
229         * </ul>
230         * 
231         * @param obj  the object (<code>null</code> permitted).
232         * 
233         * @return A boolean.
234         */
235        public boolean equals(Object obj) {
236            if (obj == this) {
237                return true;
238            }
239            if (!(obj instanceof XYDotRenderer)) {
240                return false;
241            }
242            XYDotRenderer that = (XYDotRenderer) obj;
243            if (this.dotWidth != that.dotWidth) {
244                return false;
245            }
246            if (this.dotHeight != that.dotHeight) {
247                return false;
248            }
249            return super.equals(obj);    
250        }
251        
252        /**
253         * Returns a clone of the renderer.
254         * 
255         * @return A clone.
256         * 
257         * @throws CloneNotSupportedException  if the renderer cannot be cloned.
258         */
259        public Object clone() throws CloneNotSupportedException {
260            return super.clone();
261        }
262    
263    }