    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    }