001    /* ===========================================================
002     * JFreeChart : a free chart library for the Java(tm) platform
003     * ===========================================================
004     *
005     * (C) Copyright 2000-2008, 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     * CrosshairState.java
029     * -------------------
030     * (C) Copyright 2002-2008, by Object Refinery Limited.
031     *
032     * Original Author:  David Gilbert (for Object Refinery Limited);
033     * Contributor(s):   -;
034     *
035     * Changes
036     * -------
037     * 24-Jan-2002 : Version 1 (DG);
038     * 05-Mar-2002 : Added Javadoc comments (DG);
039     * 26-Sep-2002 : Fixed errors reported by Checkstyle (DG);
040     * 19-Sep-2003 : Modified crosshair distance calculation (DG);
041     * 04-Dec-2003 : Crosshair anchor point now stored outside chart since it is
042     *               dependent on the display target (DG);
043     * 25-Feb-2004 : Replaced CrosshairInfo --> CrosshairState (DG);
044     * ------------- JFREECHART 1.0.x ---------------------------------------------
045     * 13-Oct-2006 : Fixed initialisation of CrosshairState - see bug report
046     *               1565168 (DG);
047     * 06-Feb-2007 : Added new fields and methods to fix bug 1086307 (DG);
048     * 26-Jun-2008 : Now tracks dataset index (DG);
049     *
050     */
051    
052    package org.jfree.chart.plot;
053    
054    import java.awt.geom.Point2D;
055    
056    /**
057     * Maintains state information about crosshairs on a plot between successive
058     * calls to the renderer's draw method.  This class is used internally by
059     * JFreeChart - it is not intended for external use.
060     */
061    public class CrosshairState {
062    
063        /**
064         * A flag that controls whether the distance is calculated in data space
065         * or Java2D space.
066         */
067        private boolean calculateDistanceInDataSpace = false;
068    
069        /** The x-value (in data space) for the anchor point. */
070        private double anchorX;
071    
072        /** The y-value (in data space) for the anchor point. */
073        private double anchorY;
074    
075        /** The anchor point in Java2D space - if null, don't update crosshair. */
076        private Point2D anchor;
077    
078        /** The x-value for the current crosshair point. */
079        private double crosshairX;
080    
081        /** The y-value for the current crosshair point. */
082        private double crosshairY;
083    
084        /**
085         * The dataset index that the crosshair point relates to (this determines
086         * the axes that the crosshairs will be plotted against).
087         *
088         * @since 1.0.11
089         */
090        private int datasetIndex;
091    
092        /**
093         * The index of the domain axis that the crosshair x-value is measured
094         * against.
095         *
096         * @since 1.0.4
097         */
098        private int domainAxisIndex;
099    
100        /**
101         * The index of the range axis that the crosshair y-value is measured
102         * against.
103         *
104         * @since 1.0.4
105         */
106        private int rangeAxisIndex;
107    
108        /**
109         * The smallest distance (so far) between the anchor point and a data
110         * point.
111         */
112        private double distance;
113    
114        /**
115         * Creates a new <code>CrosshairState</code> instance that calculates
116         * distance in Java2D space.
117         */
118        public CrosshairState() {
119            this(false);
120        }
121    
122        /**
123         * Creates a new <code>CrosshairState</code> instance.
124         *
125         * @param calculateDistanceInDataSpace  a flag that controls whether the
126         *                                      distance is calculated in data
127         *                                      space or Java2D space.
128         */
129        public CrosshairState(boolean calculateDistanceInDataSpace) {
130            this.calculateDistanceInDataSpace = calculateDistanceInDataSpace;
131        }
132    
133        /**
134         * Returns the distance between the anchor point and the current crosshair
135         * point.
136         *
137         * @return The distance.
138         *
139         * @see #setCrosshairDistance(double)
140         * @since 1.0.3
141         */
142        public double getCrosshairDistance() {
143            return this.distance;
144        }
145    
146        /**
147         * Sets the distance between the anchor point and the current crosshair
148         * point.  As each data point is processed, its distance to the anchor
149         * point is compared with this value and, if it is closer, the data point
150         * becomes the new crosshair point.
151         *
152         * @param distance  the distance.
153         *
154         * @see #getCrosshairDistance()
155         */
156        public void setCrosshairDistance(double distance) {
157            this.distance = distance;
158        }
159    
160        /**
161         * Evaluates a data point and if it is the closest to the anchor point it
162         * becomes the new crosshair point.
163         * <P>
164         * To understand this method, you need to know the context in which it will
165         * be called.  An instance of this class is passed to an
166         * {@link org.jfree.chart.renderer.xy.XYItemRenderer} as
167         * each data point is plotted.  As the point is plotted, it is passed to
168         * this method to see if it should be the new crosshair point.
169         *
170         * @param x  x coordinate (measured against the domain axis).
171         * @param y  y coordinate (measured against the range axis).
172         * @param transX  x translated into Java2D space.
173         * @param transY  y translated into Java2D space.
174         * @param orientation  the plot orientation.
175         *
176         * @deprecated Use {@link #updateCrosshairPoint(double, double, int, int,
177         *     double, double, PlotOrientation)}.  See bug report 1086307.
178         */
179        public void updateCrosshairPoint(double x, double y,
180                                         double transX, double transY,
181                                         PlotOrientation orientation) {
182            updateCrosshairPoint(x, y, 0, 0, transX, transY, orientation);
183        }
184    
185        /**
186         * Evaluates a data point and if it is the closest to the anchor point it
187         * becomes the new crosshair point.
188         * <P>
189         * To understand this method, you need to know the context in which it will
190         * be called.  An instance of this class is passed to an
191         * {@link org.jfree.chart.renderer.xy.XYItemRenderer} as
192         * each data point is plotted.  As the point is plotted, it is passed to
193         * this method to see if it should be the new crosshair point.
194         *
195         * @param x  x coordinate (measured against the domain axis).
196         * @param y  y coordinate (measured against the range axis).
197         * @param domainAxisIndex  the index of the domain axis for this point.
198         * @param rangeAxisIndex  the index of the range axis for this point.
199         * @param transX  x translated into Java2D space.
200         * @param transY  y translated into Java2D space.
201         * @param orientation  the plot orientation.
202         *
203         * @since 1.0.4
204         */
205        public void updateCrosshairPoint(double x, double y, int domainAxisIndex,
206                int rangeAxisIndex, double transX, double transY,
207                PlotOrientation orientation) {
208    
209            if (this.anchor != null) {
210                double d = 0.0;
211                if (this.calculateDistanceInDataSpace) {
212                    d = (x - this.anchorX) * (x - this.anchorX)
213                      + (y - this.anchorY) * (y - this.anchorY);
214                }
215                else {
216                    double xx = this.anchor.getX();
217                    double yy = this.anchor.getY();
218                    if (orientation == PlotOrientation.HORIZONTAL) {
219                        double temp = yy;
220                        yy = xx;
221                        xx = temp;
222                    }
223                    d = (transX - xx) * (transX - xx)
224                        + (transY - yy) * (transY - yy);
225                }
226    
227                if (d < this.distance) {
228                    this.crosshairX = x;
229                    this.crosshairY = y;
230                    this.domainAxisIndex = domainAxisIndex;
231                    this.rangeAxisIndex = rangeAxisIndex;
232                    this.distance = d;
233                }
234            }
235    
236        }
237    
238        /**
239         * Evaluates an x-value and if it is the closest to the anchor x-value it
240         * becomes the new crosshair value.
241         * <P>
242         * Used in cases where only the x-axis is numerical.
243         *
244         * @param candidateX  x position of the candidate for the new crosshair
245         *                    point.
246         *
247         * @deprecated Use {@link #updateCrosshairX(double, int)}.  See bug report
248         *     1086307.
249         */
250        public void updateCrosshairX(double candidateX) {
251            updateCrosshairX(candidateX, 0);
252        }
253    
254        /**
255         * Evaluates an x-value and if it is the closest to the anchor x-value it
256         * becomes the new crosshair value.
257         * <P>
258         * Used in cases where only the x-axis is numerical.
259         *
260         * @param candidateX  x position of the candidate for the new crosshair
261         *                    point.
262         * @param domainAxisIndex  the index of the domain axis for this x-value.
263         *
264         * @since 1.0.4
265         */
266        public void updateCrosshairX(double candidateX, int domainAxisIndex) {
267    
268            double d = Math.abs(candidateX - this.anchorX);
269            if (d < this.distance) {
270                this.crosshairX = candidateX;
271                this.domainAxisIndex = domainAxisIndex;
272                this.distance = d;
273            }
274    
275        }
276    
277        /**
278         * Evaluates a y-value and if it is the closest to the anchor y-value it
279         * becomes the new crosshair value.
280         * <P>
281         * Used in cases where only the y-axis is numerical.
282         *
283         * @param candidateY  y position of the candidate for the new crosshair
284         *                    point.
285         *
286         * @deprecated Use {@link #updateCrosshairY(double, int)}.  See bug report
287         *     1086307.
288         */
289        public void updateCrosshairY(double candidateY) {
290            updateCrosshairY(candidateY, 0);
291        }
292    
293        /**
294         * Evaluates a y-value and if it is the closest to the anchor y-value it
295         * becomes the new crosshair value.
296         * <P>
297         * Used in cases where only the y-axis is numerical.
298         *
299         * @param candidateY  y position of the candidate for the new crosshair
300         *                    point.
301         * @param rangeAxisIndex  the index of the range axis for this y-value.
302         *
303         * @since 1.0.4
304         */
305        public void updateCrosshairY(double candidateY, int rangeAxisIndex) {
306            double d = Math.abs(candidateY - this.anchorY);
307            if (d < this.distance) {
308                this.crosshairY = candidateY;
309                this.rangeAxisIndex = rangeAxisIndex;
310                this.distance = d;
311            }
312    
313        }
314    
315        /**
316         * Returns the anchor point.
317         *
318         * @return The anchor point.
319         *
320         * @see #setAnchor(Point2D)
321         *
322         * @since 1.0.3
323         */
324        public Point2D getAnchor() {
325            return this.anchor;
326        }
327    
328        /**
329         * Sets the anchor point.  This is usually the mouse click point in a chart
330         * panel, and the crosshair point will often be the data item that is
331         * closest to the anchor point.
332         * <br><br>
333         * Note that the x and y coordinates (in data space) are not updated by
334         * this method - the caller is responsible for ensuring that this happens
335         * in sync.
336         *
337         * @param anchor  the anchor point (<code>null</code> permitted).
338         *
339         * @see #getAnchor()
340         */
341        public void setAnchor(Point2D anchor) {
342            this.anchor = anchor;
343        }
344    
345        /**
346         * Returns the x-coordinate (in data space) for the anchor point.
347         *
348         * @return The x-coordinate of the anchor point.
349         *
350         * @since 1.0.3
351         */
352        public double getAnchorX() {
353            return this.anchorX;
354        }
355    
356        /**
357         * Sets the x-coordinate (in data space) for the anchor point.  Note that
358         * this does NOT update the anchor itself - the caller is responsible for
359         * ensuring this is done in sync.
360         *
361         * @param x  the x-coordinate.
362         *
363         * @since 1.0.3
364         */
365        public void setAnchorX(double x) {
366            this.anchorX = x;
367        }
368    
369        /**
370         * Returns the y-coordinate (in data space) for the anchor point.
371         *
372         * @return The y-coordinate of teh anchor point.
373         *
374         * @since 1.0.3
375         */
376        public double getAnchorY() {
377            return this.anchorY;
378        }
379    
380        /**
381         * Sets the y-coordinate (in data space) for the anchor point.  Note that
382         * this does NOT update the anchor itself - the caller is responsible for
383         * ensuring this is done in sync.
384         *
385         * @param y  the y-coordinate.
386         *
387         * @since 1.0.3
388         */
389        public void setAnchorY(double y) {
390            this.anchorY = y;
391        }
392    
393        /**
394         * Get the x-value for the crosshair point.
395         *
396         * @return The x position of the crosshair point.
397         *
398         * @see #setCrosshairX(double)
399         */
400        public double getCrosshairX() {
401            return this.crosshairX;
402        }
403    
404        /**
405         * Sets the x coordinate for the crosshair.  This is the coordinate in data
406         * space measured against the domain axis.
407         *
408         * @param x the coordinate.
409         *
410         * @see #getCrosshairX()
411         * @see #setCrosshairY(double)
412         * @see #updateCrosshairPoint(double, double, double, double,
413         * PlotOrientation)
414         */
415        public void setCrosshairX(double x) {
416            this.crosshairX = x;
417        }
418    
419        /**
420         * Get the y-value for the crosshair point.  This is the coordinate in data
421         * space measured against the range axis.
422         *
423         * @return The y position of the crosshair point.
424         *
425         * @see #setCrosshairY(double)
426         */
427        public double getCrosshairY() {
428            return this.crosshairY;
429        }
430    
431        /**
432         * Sets the y coordinate for the crosshair.
433         *
434         * @param y  the y coordinate.
435         *
436         * @see #getCrosshairY()
437         * @see #setCrosshairX(double)
438         * @see #updateCrosshairPoint(double, double, double, double,
439         * PlotOrientation)
440         */
441        public void setCrosshairY(double y) {
442            this.crosshairY = y;
443        }
444    
445        /**
446         * Returns the dataset index that the crosshair values relate to.  The
447         * dataset is mapped to specific axes, and this is how the crosshairs are
448         * mapped also.
449         *
450         * @return The dataset index.
451         *
452         * @see #setDatasetIndex(int)
453         *
454         * @since 1.0.11
455         */
456        public int getDatasetIndex() {
457            return this.datasetIndex;
458        }
459    
460        /**
461         * Sets the dataset index that the current crosshair values relate to.
462         *
463         * @param index  the dataset index.
464         *
465         * @see #getDatasetIndex()
466         *
467         * @since 1.0.11
468         */
469        public void setDatasetIndex(int index) {
470            this.datasetIndex = index;
471        }
472    
473        /**
474         * Returns the domain axis index for the crosshair x-value.
475         *
476         * @return The domain axis index.
477         *
478         * @since 1.0.4
479         *
480         * @deprecated As of version 1.0.11, the domain axis should be determined
481         *     using the dataset index.
482         */
483        public int getDomainAxisIndex() {
484            return this.domainAxisIndex;
485        }
486    
487        /**
488         * Returns the range axis index for the crosshair y-value.
489         *
490         * @return The range axis index.
491         *
492         * @since 1.0.4
493         *
494         * @deprecated As of version 1.0.11, the domain axis should be determined
495         *     using the dataset index.
496         */
497        public int getRangeAxisIndex() {
498            return this.rangeAxisIndex;
499        }
500    
501    }