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