001/* =========================================================== 002 * JFreeChart : a free chart library for the Java(tm) platform 003 * =========================================================== 004 * 005 * (C) Copyright 2000-2013, 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}