001/* =========================================================== 002 * JFreeChart : a free chart library for the Java(tm) platform 003 * =========================================================== 004 * 005 * (C) Copyright 2000-present, by David Gilbert 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-present, by David Gilbert. 031 * 032 * Original Author: David Gilbert; 033 * Contributor(s): -; 034 * 035 */ 036 037package org.jfree.chart.plot; 038 039import java.awt.geom.Point2D; 040 041/** 042 * Maintains state information about crosshairs on a plot between successive 043 * calls to the renderer's draw method. This class is used internally by 044 * JFreeChart - it is not intended for external use. 045 */ 046public class CrosshairState { 047 048 /** 049 * A flag that controls whether the distance is calculated in data space 050 * or Java2D space. 051 */ 052 private boolean calculateDistanceInDataSpace = false; 053 054 /** The x-value (in data space) for the anchor point. */ 055 private double anchorX; 056 057 /** The y-value (in data space) for the anchor point. */ 058 private double anchorY; 059 060 /** The anchor point in Java2D space - if null, don't update crosshair. */ 061 private Point2D anchor; 062 063 /** The x-value for the current crosshair point. */ 064 private double crosshairX; 065 066 /** The y-value for the current crosshair point. */ 067 private double crosshairY; 068 069 /** 070 * The dataset index that the crosshair point relates to (this determines 071 * the axes that the crosshairs will be plotted against). 072 */ 073 private int datasetIndex; 074 075 /** 076 * The smallest distance (so far) between the anchor point and a data 077 * point. 078 */ 079 private double distance; 080 081 /** 082 * Creates a new {@code crosshairState} instance that calculates 083 * distance in Java2D space. 084 */ 085 public CrosshairState() { 086 this(false); 087 } 088 089 /** 090 * Creates a new {@code crosshairState} instance. Determination of the 091 * data point nearest the anchor point can be calculated in either 092 * dataspace or Java2D space. The former should only be used for charts 093 * with a single set of axes. 094 * 095 * @param calculateDistanceInDataSpace a flag that controls whether the 096 * distance is calculated in data 097 * space or Java2D space. 098 */ 099 public CrosshairState(boolean calculateDistanceInDataSpace) { 100 this.calculateDistanceInDataSpace = calculateDistanceInDataSpace; 101 } 102 103 /** 104 * Returns the distance between the anchor point and the current crosshair 105 * point. 106 * 107 * @return The distance. 108 * 109 * @see #setCrosshairDistance(double) 110 */ 111 public double getCrosshairDistance() { 112 return this.distance; 113 } 114 115 /** 116 * Sets the distance between the anchor point and the current crosshair 117 * point. As each data point is processed, its distance to the anchor 118 * point is compared with this value and, if it is closer, the data point 119 * becomes the new crosshair point. 120 * 121 * @param distance the distance. 122 * 123 * @see #getCrosshairDistance() 124 */ 125 public void setCrosshairDistance(double distance) { 126 this.distance = distance; 127 } 128 129 /** 130 * Updates the crosshair point. 131 * 132 * @param x the x-value. 133 * @param y the y-value. 134 * @param datasetIndex the dataset index. 135 * @param transX the x-value in Java2D space. 136 * @param transY the y-value in Java2D space. 137 * @param orientation the plot orientation ({@code null} not permitted). 138 */ 139 public void updateCrosshairPoint(double x, double y, int datasetIndex, 140 double transX, double transY, PlotOrientation orientation) { 141 142 if (this.anchor != null) { 143 double d = 0.0; 144 if (this.calculateDistanceInDataSpace) { 145 d = (x - this.anchorX) * (x - this.anchorX) 146 + (y - this.anchorY) * (y - this.anchorY); 147 } 148 else { 149 // anchor point is in Java2D coordinates 150 double xx = this.anchor.getX(); 151 double yy = this.anchor.getY(); 152 if (orientation == PlotOrientation.HORIZONTAL) { 153 double temp = yy; 154 yy = xx; 155 xx = temp; 156 } 157 d = (transX - xx) * (transX - xx) 158 + (transY - yy) * (transY - yy); 159 } 160 161 if (d < this.distance) { 162 this.crosshairX = x; 163 this.crosshairY = y; 164 this.datasetIndex = datasetIndex; 165 this.distance = d; 166 } 167 } 168 169 } 170 171 /** 172 * Checks to see if the specified data point is the closest to the 173 * anchor point and, if yes, updates the current state. 174 * 175 * @param x the x-value. 176 * @param transX the x-value in Java2D space. 177 * @param datasetIndex the dataset index. 178 */ 179 public void updateCrosshairX(double x, double transX, int datasetIndex) { 180 if (this.anchor == null) { 181 return; 182 } 183 double d = Math.abs(transX - this.anchor.getX()); 184 if (d < this.distance) { 185 this.crosshairX = x; 186 this.datasetIndex = datasetIndex; 187 this.distance = d; 188 } 189 } 190 191 /** 192 * Evaluates a y-value and if it is the closest to the anchor y-value it 193 * becomes the new crosshair value. 194 * <P> 195 * Used in cases where only the y-axis is numerical. 196 * 197 * @param candidateY y position of the candidate for the new crosshair 198 * point. 199 * @param transY the y-value in Java2D space. 200 * @param datasetIndex the index of the range axis for this y-value. 201 */ 202 public void updateCrosshairY(double candidateY, double transY, int datasetIndex) { 203 if (this.anchor == null) { 204 return; 205 } 206 double d = Math.abs(transY - this.anchor.getY()); 207 if (d < this.distance) { 208 this.crosshairY = candidateY; 209 this.datasetIndex = datasetIndex; 210 this.distance = d; 211 } 212 213 } 214 215 /** 216 * Returns the anchor point. 217 * 218 * @return The anchor point. 219 * 220 * @see #setAnchor(Point2D) 221 */ 222 public Point2D getAnchor() { 223 return this.anchor; 224 } 225 226 /** 227 * Sets the anchor point. This is usually the mouse click point in a chart 228 * panel, and the crosshair point will often be the data item that is 229 * closest to the anchor point. 230 * <br><br> 231 * Note that the x and y coordinates (in data space) are not updated by 232 * this method - the caller is responsible for ensuring that this happens 233 * in sync. 234 * 235 * @param anchor the anchor point ({@code null} permitted). 236 * 237 * @see #getAnchor() 238 */ 239 public void setAnchor(Point2D anchor) { 240 this.anchor = anchor; 241 } 242 243 /** 244 * Returns the x-coordinate (in data space) for the anchor point. 245 * 246 * @return The x-coordinate of the anchor point. 247 */ 248 public double getAnchorX() { 249 return this.anchorX; 250 } 251 252 /** 253 * Sets the x-coordinate (in data space) for the anchor point. Note that 254 * this does NOT update the anchor itself - the caller is responsible for 255 * ensuring this is done in sync. 256 * 257 * @param x the x-coordinate. 258 */ 259 public void setAnchorX(double x) { 260 this.anchorX = x; 261 } 262 263 /** 264 * Returns the y-coordinate (in data space) for the anchor point. 265 * 266 * @return The y-coordinate of teh anchor point. 267 */ 268 public double getAnchorY() { 269 return this.anchorY; 270 } 271 272 /** 273 * Sets the y-coordinate (in data space) for the anchor point. Note that 274 * this does NOT update the anchor itself - the caller is responsible for 275 * ensuring this is done in sync. 276 * 277 * @param y the y-coordinate. 278 */ 279 public void setAnchorY(double y) { 280 this.anchorY = y; 281 } 282 283 /** 284 * Get the x-value for the crosshair point. 285 * 286 * @return The x position of the crosshair point. 287 * 288 * @see #setCrosshairX(double) 289 */ 290 public double getCrosshairX() { 291 return this.crosshairX; 292 } 293 294 /** 295 * Sets the x coordinate for the crosshair. This is the coordinate in data 296 * space measured against the domain axis. 297 * 298 * @param x the coordinate. 299 * 300 * @see #getCrosshairX() 301 * @see #setCrosshairY(double) 302 * @see #updateCrosshairPoint(double, double, int, double, double, 303 * PlotOrientation) 304 */ 305 public void setCrosshairX(double x) { 306 this.crosshairX = x; 307 } 308 309 /** 310 * Get the y-value for the crosshair point. This is the coordinate in data 311 * space measured against the range axis. 312 * 313 * @return The y position of the crosshair point. 314 * 315 * @see #setCrosshairY(double) 316 */ 317 public double getCrosshairY() { 318 return this.crosshairY; 319 } 320 321 /** 322 * Sets the y coordinate for the crosshair. 323 * 324 * @param y the y coordinate. 325 * 326 * @see #getCrosshairY() 327 * @see #setCrosshairX(double) 328 * @see #updateCrosshairPoint(double, double, int, double, double, 329 * PlotOrientation) 330 */ 331 public void setCrosshairY(double y) { 332 this.crosshairY = y; 333 } 334 335 /** 336 * Returns the dataset index that the crosshair values relate to. The 337 * dataset is mapped to specific axes, and this is how the crosshairs are 338 * mapped also. 339 * 340 * @return The dataset index. 341 * 342 * @see #setDatasetIndex(int) 343 */ 344 public int getDatasetIndex() { 345 return this.datasetIndex; 346 } 347 348 /** 349 * Sets the dataset index that the current crosshair values relate to. 350 * 351 * @param index the dataset index. 352 * 353 * @see #getDatasetIndex() 354 */ 355 public void setDatasetIndex(int index) { 356 this.datasetIndex = index; 357 } 358}