    001/* ===========================================================
    002 * JFreeChart : a free chart library for the Java(tm) platform
    003 * ===========================================================
    004 *
    005 * (C) Copyright 2000-2011, 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 * [Oracle and Java are registered trademarks of Oracle and/or its affiliates.
    025 * Other names may be trademarks of their respective owners.]
    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
    052package org.jfree.chart.plot;
    053
    054import 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 */
    061public 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}