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