001/* =========================================================== 002 * JFreeChart : a free chart library for the Java(tm) platform 003 * =========================================================== 004 * 005 * (C) Copyright 2000-2014, 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 * AbstractXYItemRenderer.java 029 * --------------------------- 030 * (C) Copyright 2002-2014, by Object Refinery Limited and Contributors. 031 * 032 * Original Author: David Gilbert (for Object Refinery Limited); 033 * Contributor(s): Richard Atkinson; 034 * Focus Computer Services Limited; 035 * Tim Bardzil; 036 * Sergei Ivanov; 037 * Peter Kolb (patch 2809117); 038 * Martin Krauskopf; 039 * 040 * Changes: 041 * -------- 042 * 15-Mar-2002 : Version 1 (DG); 043 * 09-Apr-2002 : Added a getToolTipGenerator() method reflecting the change in 044 * the XYItemRenderer interface (DG); 045 * 05-Aug-2002 : Added a urlGenerator member variable to support HTML image 046 * maps (RA); 047 * 20-Aug-2002 : Added property change events for the tooltip and URL 048 * generators (DG); 049 * 22-Aug-2002 : Moved property change support into AbstractRenderer class (DG); 050 * 23-Sep-2002 : Fixed errors reported by Checkstyle tool (DG); 051 * 18-Nov-2002 : Added methods for drawing grid lines (DG); 052 * 17-Jan-2003 : Moved plot classes into a separate package (DG); 053 * 25-Mar-2003 : Implemented Serializable (DG); 054 * 01-May-2003 : Modified initialise() return type and drawItem() method 055 * signature (DG); 056 * 15-May-2003 : Modified to take into account the plot orientation (DG); 057 * 21-May-2003 : Added labels to markers (DG); 058 * 05-Jun-2003 : Added domain and range grid bands (sponsored by Focus Computer 059 * Services Ltd) (DG); 060 * 27-Jul-2003 : Added getRangeType() to support stacked XY area charts (RA); 061 * 31-Jul-2003 : Deprecated all but the default constructor (DG); 062 * 13-Aug-2003 : Implemented Cloneable (DG); 063 * 16-Sep-2003 : Changed ChartRenderingInfo --> PlotRenderingInfo (DG); 064 * 29-Oct-2003 : Added workaround for font alignment in PDF output (DG); 065 * 05-Nov-2003 : Fixed marker rendering bug (833623) (DG); 066 * 11-Feb-2004 : Updated labelling for markers (DG); 067 * 25-Feb-2004 : Added updateCrosshairValues() method. Moved deprecated code 068 * to bottom of source file (DG); 069 * 16-Apr-2004 : Added support for IntervalMarker in drawRangeMarker() method 070 * - thanks to Tim Bardzil (DG); 071 * 05-May-2004 : Fixed bug (948310) where interval markers extend beyond axis 072 * range (DG); 073 * 03-Jun-2004 : Fixed more bugs in drawing interval markers (DG); 074 * 26-Aug-2004 : Added the addEntity() method (DG); 075 * 29-Sep-2004 : Added annotation support (with layers) (DG); 076 * 30-Sep-2004 : Moved drawRotatedString() from RefineryUtilities --> 077 * TextUtilities (DG); 078 * 06-Oct-2004 : Added findDomainBounds() method and renamed 079 * getRangeExtent() --> findRangeBounds() (DG); 080 * 07-Jan-2005 : Removed deprecated code (DG); 081 * 27-Jan-2005 : Modified getLegendItem() to omit hidden series (DG); 082 * 24-Feb-2005 : Added getLegendItems() method (DG); 083 * 08-Mar-2005 : Fixed positioning of marker labels (DG); 084 * 20-Apr-2005 : Renamed XYLabelGenerator --> XYItemLabelGenerator and 085 * added generators for legend labels, tooltips and URLs (DG); 086 * 01-Jun-2005 : Handle one dimension of the marker label adjustment 087 * automatically (DG); 088 * ------------- JFREECHART 1.0.x --------------------------------------------- 089 * 20-Jul-2006 : Set dataset and series indices in LegendItem (DG); 090 * 24-Oct-2006 : Respect alpha setting in markers (see patch 1567843 by Sergei 091 * Ivanov) (DG); 092 * 24-Oct-2006 : Added code to draw outlines for interval markers (DG); 093 * 24-Nov-2006 : Fixed cloning for legend item generators (DG); 094 * 06-Feb-2007 : Added new updateCrosshairValues() method that takes into 095 * account multiple axis plots (see bug 1086307) (DG); 096 * 20-Feb-2007 : Fixed equals() method implementation (DG); 097 * 01-Mar-2007 : Fixed interval marker drawing (patch 1670686 thanks to 098 * Sergei Ivanov) (DG); 099 * 22-Mar-2007 : Modified the tool tip generator look up (DG); 100 * 23-Mar-2007 : Added drawDomainLine() method (DG); 101 * 20-Apr-2007 : Updated getLegendItem() for renderer change, and deprecated 102 * itemLabelGenerator and toolTipGenerator override fields (DG); 103 * 18-May-2007 : Set dataset and seriesKey for LegendItem (DG); 104 * 12-Nov-2007 : Fixed domain and range band drawing methods (DG); 105 * 07-Apr-2008 : Minor API doc update (DG); 106 * 14-May-2008 : Updated addEntity() method to take plot orientation into 107 * account when the incoming area is null (DG); 108 * 02-Jun-2008 : Added isPointInRect() method (DG); 109 * 17-Jun-2008 : Apply legend shape, font and paint attributes (DG); 110 * 09-Mar-2009 : Added getAnnotations() method (DG); 111 * 27-Mar-2009 : Added new findDomainBounds() and findRangeBounds() methods to 112 * take account of hidden series (DG); 113 * 01-Apr-2009 : Moved defaultEntityRadius up to superclass (DG); 114 * 28-Apr-2009 : Updated getLegendItem() method to observe new 115 * 'treatLegendShapeAsLine' flag (DG); 116 * 24-Jun-2009 : Added support for annotation events - see patch 2809117 117 * by PK (DG); 118 * 01-Sep-2009 : Bug 2840132 - set renderer index when drawing 119 * annotations (DG); 120 * 06-Oct-2011 : Add utility methods to work with 1.4 API in GeneralPath (MK) 121 * 03-Jul-2013 : Use ParamChecks (DG); 122 * 11-Jan-2014 : Fix error in fillDomainGridBand method (DG); 123 * 07-Apr-2014 : Don't use ObjectList anymore (DG); 124 * 29-Jul-2014 : Add rendering hint to normalise domain and range lines (DG); 125 * 126 */ 127 128package org.jfree.chart.renderer.xy; 129 130import java.awt.AlphaComposite; 131import java.awt.Composite; 132import java.awt.Font; 133import java.awt.GradientPaint; 134import java.awt.Graphics2D; 135import java.awt.Paint; 136import java.awt.RenderingHints; 137import java.awt.Shape; 138import java.awt.Stroke; 139import java.awt.geom.Ellipse2D; 140import java.awt.geom.GeneralPath; 141import java.awt.geom.Line2D; 142import java.awt.geom.Point2D; 143import java.awt.geom.Rectangle2D; 144import java.io.Serializable; 145import java.util.ArrayList; 146import java.util.Collection; 147import java.util.HashMap; 148import java.util.Iterator; 149import java.util.List; 150import java.util.Map; 151 152import org.jfree.chart.LegendItem; 153import org.jfree.chart.LegendItemCollection; 154import org.jfree.chart.annotations.Annotation; 155import org.jfree.chart.annotations.XYAnnotation; 156import org.jfree.chart.axis.ValueAxis; 157import org.jfree.chart.entity.EntityCollection; 158import org.jfree.chart.entity.XYItemEntity; 159import org.jfree.chart.event.AnnotationChangeEvent; 160import org.jfree.chart.event.AnnotationChangeListener; 161import org.jfree.chart.event.RendererChangeEvent; 162import org.jfree.chart.labels.ItemLabelPosition; 163import org.jfree.chart.labels.StandardXYSeriesLabelGenerator; 164import org.jfree.chart.labels.XYItemLabelGenerator; 165import org.jfree.chart.labels.XYSeriesLabelGenerator; 166import org.jfree.chart.labels.XYToolTipGenerator; 167import org.jfree.chart.plot.CrosshairState; 168import org.jfree.chart.plot.DrawingSupplier; 169import org.jfree.chart.plot.IntervalMarker; 170import org.jfree.chart.plot.Marker; 171import org.jfree.chart.plot.Plot; 172import org.jfree.chart.plot.PlotOrientation; 173import org.jfree.chart.plot.PlotRenderingInfo; 174import org.jfree.chart.plot.ValueMarker; 175import org.jfree.chart.plot.XYPlot; 176import org.jfree.chart.renderer.AbstractRenderer; 177import org.jfree.chart.urls.XYURLGenerator; 178import org.jfree.chart.util.CloneUtils; 179import org.jfree.chart.util.ParamChecks; 180import org.jfree.data.Range; 181import org.jfree.data.general.DatasetUtilities; 182import org.jfree.data.xy.XYDataset; 183import org.jfree.text.TextUtilities; 184import org.jfree.ui.GradientPaintTransformer; 185import org.jfree.ui.Layer; 186import org.jfree.ui.LengthAdjustmentType; 187import org.jfree.ui.RectangleAnchor; 188import org.jfree.ui.RectangleInsets; 189import org.jfree.util.ObjectUtilities; 190import org.jfree.util.PublicCloneable; 191 192/** 193 * A base class that can be used to create new {@link XYItemRenderer} 194 * implementations. 195 */ 196public abstract class AbstractXYItemRenderer extends AbstractRenderer 197 implements XYItemRenderer, AnnotationChangeListener, 198 Cloneable, Serializable { 199 200 /** For serialization. */ 201 private static final long serialVersionUID = 8019124836026607990L; 202 203 /** The plot. */ 204 private XYPlot plot; 205 206 /** A list of item label generators (one per series). */ 207 private Map<Integer, XYItemLabelGenerator> itemLabelGeneratorMap; 208 209 /** The base item label generator. */ 210 private XYItemLabelGenerator baseItemLabelGenerator; 211 212 /** A list of tool tip generators (one per series). */ 213 private Map<Integer, XYToolTipGenerator> toolTipGeneratorMap; 214 215 /** The base tool tip generator. */ 216 private XYToolTipGenerator baseToolTipGenerator; 217 218 /** The URL text generator. */ 219 private XYURLGenerator urlGenerator; 220 221 /** 222 * Annotations to be drawn in the background layer ('underneath' the data 223 * items). 224 */ 225 private List backgroundAnnotations; 226 227 /** 228 * Annotations to be drawn in the foreground layer ('on top' of the data 229 * items). 230 */ 231 private List foregroundAnnotations; 232 233 /** The legend item label generator. */ 234 private XYSeriesLabelGenerator legendItemLabelGenerator; 235 236 /** The legend item tool tip generator. */ 237 private XYSeriesLabelGenerator legendItemToolTipGenerator; 238 239 /** The legend item URL generator. */ 240 private XYSeriesLabelGenerator legendItemURLGenerator; 241 242 /** 243 * Creates a renderer where the tooltip generator and the URL generator are 244 * both <code>null</code>. 245 */ 246 protected AbstractXYItemRenderer() { 247 super(); 248 this.itemLabelGenerator = null; 249 this.itemLabelGeneratorMap 250 = new HashMap<Integer, XYItemLabelGenerator>(); 251 this.toolTipGenerator = null; 252 this.toolTipGeneratorMap = new HashMap<Integer, XYToolTipGenerator>(); 253 this.urlGenerator = null; 254 this.backgroundAnnotations = new java.util.ArrayList(); 255 this.foregroundAnnotations = new java.util.ArrayList(); 256 this.legendItemLabelGenerator = new StandardXYSeriesLabelGenerator( 257 "{0}"); 258 } 259 260 /** 261 * Returns the number of passes through the data that the renderer requires 262 * in order to draw the chart. Most charts will require a single pass, but 263 * some require two passes. 264 * 265 * @return The pass count. 266 */ 267 @Override 268 public int getPassCount() { 269 return 1; 270 } 271 272 /** 273 * Returns the plot that the renderer is assigned to. 274 * 275 * @return The plot (possibly <code>null</code>). 276 */ 277 @Override 278 public XYPlot getPlot() { 279 return this.plot; 280 } 281 282 /** 283 * Sets the plot that the renderer is assigned to. 284 * 285 * @param plot the plot (<code>null</code> permitted). 286 */ 287 @Override 288 public void setPlot(XYPlot plot) { 289 this.plot = plot; 290 } 291 292 /** 293 * Initialises the renderer and returns a state object that should be 294 * passed to all subsequent calls to the drawItem() method. 295 * <P> 296 * This method will be called before the first item is rendered, giving the 297 * renderer an opportunity to initialise any state information it wants to 298 * maintain. The renderer can do nothing if it chooses. 299 * 300 * @param g2 the graphics device. 301 * @param dataArea the area inside the axes. 302 * @param plot the plot. 303 * @param data the data. 304 * @param info an optional info collection object to return data back to 305 * the caller. 306 * 307 * @return The renderer state (never <code>null</code>). 308 */ 309 @Override 310 public XYItemRendererState initialise(Graphics2D g2, Rectangle2D dataArea, 311 XYPlot plot, XYDataset data, PlotRenderingInfo info) { 312 return new XYItemRendererState(info); 313 } 314 315 // ITEM LABEL GENERATOR 316 317 /** 318 * Returns the label generator for a data item. This implementation simply 319 * passes control to the {@link #getSeriesItemLabelGenerator(int)} method. 320 * If, for some reason, you want a different generator for individual 321 * items, you can override this method. 322 * 323 * @param series the series index (zero based). 324 * @param item the item index (zero based). 325 * 326 * @return The generator (possibly <code>null</code>). 327 */ 328 @Override 329 public XYItemLabelGenerator getItemLabelGenerator(int series, int item) { 330 // return the generator for ALL series, if there is one... 331 if (this.itemLabelGenerator != null) { 332 return this.itemLabelGenerator; 333 } 334 335 // otherwise look up the generator table 336 XYItemLabelGenerator generator 337 = (XYItemLabelGenerator) this.itemLabelGeneratorMap.get(series); 338 if (generator == null) { 339 generator = this.baseItemLabelGenerator; 340 } 341 return generator; 342 } 343 344 /** 345 * Returns the item label generator for a series. 346 * 347 * @param series the series index (zero based). 348 * 349 * @return The generator (possibly <code>null</code>). 350 */ 351 @Override 352 public XYItemLabelGenerator getSeriesItemLabelGenerator(int series) { 353 return this.itemLabelGeneratorMap.get(series); 354 } 355 356 /** 357 * Sets the item label generator for a series and sends a 358 * {@link RendererChangeEvent} to all registered listeners. 359 * 360 * @param series the series index (zero based). 361 * @param generator the generator (<code>null</code> permitted). 362 */ 363 @Override 364 public void setSeriesItemLabelGenerator(int series, 365 XYItemLabelGenerator generator) { 366 this.itemLabelGeneratorMap.put(series, generator); 367 fireChangeEvent(); 368 } 369 370 /** 371 * Returns the base item label generator. 372 * 373 * @return The generator (possibly <code>null</code>). 374 */ 375 @Override 376 public XYItemLabelGenerator getBaseItemLabelGenerator() { 377 return this.baseItemLabelGenerator; 378 } 379 380 /** 381 * Sets the base item label generator and sends a 382 * {@link RendererChangeEvent} to all registered listeners. 383 * 384 * @param generator the generator (<code>null</code> permitted). 385 */ 386 @Override 387 public void setBaseItemLabelGenerator(XYItemLabelGenerator generator) { 388 this.baseItemLabelGenerator = generator; 389 fireChangeEvent(); 390 } 391 392 // TOOL TIP GENERATOR 393 394 /** 395 * Returns the tool tip generator for a data item. If, for some reason, 396 * you want a different generator for individual items, you can override 397 * this method. 398 * 399 * @param series the series index (zero based). 400 * @param item the item index (zero based). 401 * 402 * @return The generator (possibly <code>null</code>). 403 */ 404 @Override 405 public XYToolTipGenerator getToolTipGenerator(int series, int item) { 406 // return the generator for ALL series, if there is one... 407 if (this.toolTipGenerator != null) { 408 return this.toolTipGenerator; 409 } 410 411 // otherwise look up the generator table 412 XYToolTipGenerator generator 413 = (XYToolTipGenerator) this.toolTipGeneratorMap.get(series); 414 if (generator == null) { 415 generator = this.baseToolTipGenerator; 416 } 417 return generator; 418 } 419 420 /** 421 * Returns the tool tip generator for a series. 422 * 423 * @param series the series index (zero based). 424 * 425 * @return The generator (possibly <code>null</code>). 426 */ 427 @Override 428 public XYToolTipGenerator getSeriesToolTipGenerator(int series) { 429 return this.toolTipGeneratorMap.get(series); 430 } 431 432 /** 433 * Sets the tool tip generator for a series and sends a 434 * {@link RendererChangeEvent} to all registered listeners. 435 * 436 * @param series the series index (zero based). 437 * @param generator the generator (<code>null</code> permitted). 438 */ 439 @Override 440 public void setSeriesToolTipGenerator(int series, 441 XYToolTipGenerator generator) { 442 this.toolTipGeneratorMap.put(series, generator); 443 fireChangeEvent(); 444 } 445 446 /** 447 * Returns the base tool tip generator. 448 * 449 * @return The generator (possibly <code>null</code>). 450 * 451 * @see #setBaseToolTipGenerator(XYToolTipGenerator) 452 */ 453 @Override 454 public XYToolTipGenerator getBaseToolTipGenerator() { 455 return this.baseToolTipGenerator; 456 } 457 458 /** 459 * Sets the base tool tip generator and sends a {@link RendererChangeEvent} 460 * to all registered listeners. 461 * 462 * @param generator the generator (<code>null</code> permitted). 463 * 464 * @see #getBaseToolTipGenerator() 465 */ 466 @Override 467 public void setBaseToolTipGenerator(XYToolTipGenerator generator) { 468 this.baseToolTipGenerator = generator; 469 fireChangeEvent(); 470 } 471 472 // URL GENERATOR 473 474 /** 475 * Returns the URL generator for HTML image maps. 476 * 477 * @return The URL generator (possibly <code>null</code>). 478 */ 479 @Override 480 public XYURLGenerator getURLGenerator() { 481 return this.urlGenerator; 482 } 483 484 /** 485 * Sets the URL generator for HTML image maps and sends a 486 * {@link RendererChangeEvent} to all registered listeners. 487 * 488 * @param urlGenerator the URL generator (<code>null</code> permitted). 489 */ 490 @Override 491 public void setURLGenerator(XYURLGenerator urlGenerator) { 492 this.urlGenerator = urlGenerator; 493 fireChangeEvent(); 494 } 495 496 /** 497 * Adds an annotation and sends a {@link RendererChangeEvent} to all 498 * registered listeners. The annotation is added to the foreground 499 * layer. 500 * 501 * @param annotation the annotation (<code>null</code> not permitted). 502 */ 503 @Override 504 public void addAnnotation(XYAnnotation annotation) { 505 // defer argument checking 506 addAnnotation(annotation, Layer.FOREGROUND); 507 } 508 509 /** 510 * Adds an annotation to the specified layer and sends a 511 * {@link RendererChangeEvent} to all registered listeners. 512 * 513 * @param annotation the annotation (<code>null</code> not permitted). 514 * @param layer the layer (<code>null</code> not permitted). 515 */ 516 @Override 517 public void addAnnotation(XYAnnotation annotation, Layer layer) { 518 ParamChecks.nullNotPermitted(annotation, "annotation"); 519 if (layer.equals(Layer.FOREGROUND)) { 520 this.foregroundAnnotations.add(annotation); 521 annotation.addChangeListener(this); 522 fireChangeEvent(); 523 } 524 else if (layer.equals(Layer.BACKGROUND)) { 525 this.backgroundAnnotations.add(annotation); 526 annotation.addChangeListener(this); 527 fireChangeEvent(); 528 } 529 else { 530 // should never get here 531 throw new RuntimeException("Unknown layer."); 532 } 533 } 534 /** 535 * Removes the specified annotation and sends a {@link RendererChangeEvent} 536 * to all registered listeners. 537 * 538 * @param annotation the annotation to remove (<code>null</code> not 539 * permitted). 540 * 541 * @return A boolean to indicate whether or not the annotation was 542 * successfully removed. 543 */ 544 @Override 545 public boolean removeAnnotation(XYAnnotation annotation) { 546 boolean removed = this.foregroundAnnotations.remove(annotation); 547 removed = removed & this.backgroundAnnotations.remove(annotation); 548 annotation.removeChangeListener(this); 549 fireChangeEvent(); 550 return removed; 551 } 552 553 /** 554 * Removes all annotations and sends a {@link RendererChangeEvent} 555 * to all registered listeners. 556 */ 557 @Override 558 public void removeAnnotations() { 559 for(int i = 0; i < this.foregroundAnnotations.size(); i++){ 560 XYAnnotation annotation 561 = (XYAnnotation) this.foregroundAnnotations.get(i); 562 annotation.removeChangeListener(this); 563 } 564 for(int i = 0; i < this.backgroundAnnotations.size(); i++){ 565 XYAnnotation annotation 566 = (XYAnnotation) this.backgroundAnnotations.get(i); 567 annotation.removeChangeListener(this); 568 } 569 this.foregroundAnnotations.clear(); 570 this.backgroundAnnotations.clear(); 571 fireChangeEvent(); 572 } 573 574 575 /** 576 * Receives notification of a change to an {@link Annotation} added to 577 * this renderer. 578 * 579 * @param event information about the event (not used here). 580 * 581 * @since 1.0.14 582 */ 583 @Override 584 public void annotationChanged(AnnotationChangeEvent event) { 585 fireChangeEvent(); 586 } 587 588 /** 589 * Returns a collection of the annotations that are assigned to the 590 * renderer. 591 * 592 * @return A collection of annotations (possibly empty but never 593 * <code>null</code>). 594 * 595 * @since 1.0.13 596 */ 597 public Collection getAnnotations() { 598 List result = new java.util.ArrayList(this.foregroundAnnotations); 599 result.addAll(this.backgroundAnnotations); 600 return result; 601 } 602 603 /** 604 * Returns the legend item label generator. 605 * 606 * @return The label generator (never <code>null</code>). 607 * 608 * @see #setLegendItemLabelGenerator(XYSeriesLabelGenerator) 609 */ 610 @Override 611 public XYSeriesLabelGenerator getLegendItemLabelGenerator() { 612 return this.legendItemLabelGenerator; 613 } 614 615 /** 616 * Sets the legend item label generator and sends a 617 * {@link RendererChangeEvent} to all registered listeners. 618 * 619 * @param generator the generator (<code>null</code> not permitted). 620 * 621 * @see #getLegendItemLabelGenerator() 622 */ 623 @Override 624 public void setLegendItemLabelGenerator(XYSeriesLabelGenerator generator) { 625 ParamChecks.nullNotPermitted(generator, "generator"); 626 this.legendItemLabelGenerator = generator; 627 fireChangeEvent(); 628 } 629 630 /** 631 * Returns the legend item tool tip generator. 632 * 633 * @return The tool tip generator (possibly <code>null</code>). 634 * 635 * @see #setLegendItemToolTipGenerator(XYSeriesLabelGenerator) 636 */ 637 public XYSeriesLabelGenerator getLegendItemToolTipGenerator() { 638 return this.legendItemToolTipGenerator; 639 } 640 641 /** 642 * Sets the legend item tool tip generator and sends a 643 * {@link RendererChangeEvent} to all registered listeners. 644 * 645 * @param generator the generator (<code>null</code> permitted). 646 * 647 * @see #getLegendItemToolTipGenerator() 648 */ 649 public void setLegendItemToolTipGenerator( 650 XYSeriesLabelGenerator generator) { 651 this.legendItemToolTipGenerator = generator; 652 fireChangeEvent(); 653 } 654 655 /** 656 * Returns the legend item URL generator. 657 * 658 * @return The URL generator (possibly <code>null</code>). 659 * 660 * @see #setLegendItemURLGenerator(XYSeriesLabelGenerator) 661 */ 662 public XYSeriesLabelGenerator getLegendItemURLGenerator() { 663 return this.legendItemURLGenerator; 664 } 665 666 /** 667 * Sets the legend item URL generator and sends a 668 * {@link RendererChangeEvent} to all registered listeners. 669 * 670 * @param generator the generator (<code>null</code> permitted). 671 * 672 * @see #getLegendItemURLGenerator() 673 */ 674 public void setLegendItemURLGenerator(XYSeriesLabelGenerator generator) { 675 this.legendItemURLGenerator = generator; 676 fireChangeEvent(); 677 } 678 679 /** 680 * Returns the lower and upper bounds (range) of the x-values in the 681 * specified dataset. 682 * 683 * @param dataset the dataset (<code>null</code> permitted). 684 * 685 * @return The range (<code>null</code> if the dataset is <code>null</code> 686 * or empty). 687 * 688 * @see #findRangeBounds(XYDataset) 689 */ 690 @Override 691 public Range findDomainBounds(XYDataset dataset) { 692 return findDomainBounds(dataset, false); 693 } 694 695 /** 696 * Returns the lower and upper bounds (range) of the x-values in the 697 * specified dataset. 698 * 699 * @param dataset the dataset (<code>null</code> permitted). 700 * @param includeInterval include the interval (if any) for the dataset? 701 * 702 * @return The range (<code>null</code> if the dataset is <code>null</code> 703 * or empty). 704 * 705 * @since 1.0.13 706 */ 707 protected Range findDomainBounds(XYDataset dataset, 708 boolean includeInterval) { 709 if (dataset == null) { 710 return null; 711 } 712 if (getDataBoundsIncludesVisibleSeriesOnly()) { 713 List visibleSeriesKeys = new ArrayList(); 714 int seriesCount = dataset.getSeriesCount(); 715 for (int s = 0; s < seriesCount; s++) { 716 if (isSeriesVisible(s)) { 717 visibleSeriesKeys.add(dataset.getSeriesKey(s)); 718 } 719 } 720 return DatasetUtilities.findDomainBounds(dataset, 721 visibleSeriesKeys, includeInterval); 722 } 723 return DatasetUtilities.findDomainBounds(dataset, includeInterval); 724 } 725 726 /** 727 * Returns the range of values the renderer requires to display all the 728 * items from the specified dataset. 729 * 730 * @param dataset the dataset (<code>null</code> permitted). 731 * 732 * @return The range (<code>null</code> if the dataset is <code>null</code> 733 * or empty). 734 * 735 * @see #findDomainBounds(XYDataset) 736 */ 737 @Override 738 public Range findRangeBounds(XYDataset dataset) { 739 return findRangeBounds(dataset, false); 740 } 741 742 /** 743 * Returns the range of values the renderer requires to display all the 744 * items from the specified dataset. 745 * 746 * @param dataset the dataset (<code>null</code> permitted). 747 * @param includeInterval include the interval (if any) for the dataset? 748 * 749 * @return The range (<code>null</code> if the dataset is <code>null</code> 750 * or empty). 751 * 752 * @since 1.0.13 753 */ 754 protected Range findRangeBounds(XYDataset dataset, 755 boolean includeInterval) { 756 if (dataset == null) { 757 return null; 758 } 759 if (getDataBoundsIncludesVisibleSeriesOnly()) { 760 List visibleSeriesKeys = new ArrayList(); 761 int seriesCount = dataset.getSeriesCount(); 762 for (int s = 0; s < seriesCount; s++) { 763 if (isSeriesVisible(s)) { 764 visibleSeriesKeys.add(dataset.getSeriesKey(s)); 765 } 766 } 767 // the bounds should be calculated using just the items within 768 // the current range of the x-axis...if there is one 769 Range xRange = null; 770 XYPlot p = getPlot(); 771 if (p != null) { 772 ValueAxis xAxis = null; 773 int index = p.getIndexOf(this); 774 if (index >= 0) { 775 xAxis = this.plot.getDomainAxisForDataset(index); 776 } 777 if (xAxis != null) { 778 xRange = xAxis.getRange(); 779 } 780 } 781 if (xRange == null) { 782 xRange = new Range(Double.NEGATIVE_INFINITY, 783 Double.POSITIVE_INFINITY); 784 } 785 return DatasetUtilities.findRangeBounds(dataset, 786 visibleSeriesKeys, xRange, includeInterval); 787 } 788 return DatasetUtilities.findRangeBounds(dataset, includeInterval); 789 } 790 791 /** 792 * Returns a (possibly empty) collection of legend items for the series 793 * that this renderer is responsible for drawing. 794 * 795 * @return The legend item collection (never <code>null</code>). 796 */ 797 @Override 798 public LegendItemCollection getLegendItems() { 799 if (this.plot == null) { 800 return new LegendItemCollection(); 801 } 802 LegendItemCollection result = new LegendItemCollection(); 803 int index = this.plot.getIndexOf(this); 804 XYDataset dataset = this.plot.getDataset(index); 805 if (dataset != null) { 806 int seriesCount = dataset.getSeriesCount(); 807 for (int i = 0; i < seriesCount; i++) { 808 if (isSeriesVisibleInLegend(i)) { 809 LegendItem item = getLegendItem(index, i); 810 if (item != null) { 811 result.add(item); 812 } 813 } 814 } 815 816 } 817 return result; 818 } 819 820 /** 821 * Returns a default legend item for the specified series. Subclasses 822 * should override this method to generate customised items. 823 * 824 * @param datasetIndex the dataset index (zero-based). 825 * @param series the series index (zero-based). 826 * 827 * @return A legend item for the series. 828 */ 829 @Override 830 public LegendItem getLegendItem(int datasetIndex, int series) { 831 XYPlot xyplot = getPlot(); 832 if (xyplot == null) { 833 return null; 834 } 835 XYDataset dataset = xyplot.getDataset(datasetIndex); 836 if (dataset == null) { 837 return null; 838 } 839 String label = this.legendItemLabelGenerator.generateLabel(dataset, 840 series); 841 String description = label; 842 String toolTipText = null; 843 if (getLegendItemToolTipGenerator() != null) { 844 toolTipText = getLegendItemToolTipGenerator().generateLabel( 845 dataset, series); 846 } 847 String urlText = null; 848 if (getLegendItemURLGenerator() != null) { 849 urlText = getLegendItemURLGenerator().generateLabel(dataset, 850 series); 851 } 852 Shape shape = lookupLegendShape(series); 853 Paint paint = lookupSeriesPaint(series); 854 LegendItem item = new LegendItem(label, paint); 855 item.setToolTipText(toolTipText); 856 item.setURLText(urlText); 857 item.setLabelFont(lookupLegendTextFont(series)); 858 Paint labelPaint = lookupLegendTextPaint(series); 859 if (labelPaint != null) { 860 item.setLabelPaint(labelPaint); 861 } 862 item.setSeriesKey(dataset.getSeriesKey(series)); 863 item.setSeriesIndex(series); 864 item.setDataset(dataset); 865 item.setDatasetIndex(datasetIndex); 866 867 if (getTreatLegendShapeAsLine()) { 868 item.setLineVisible(true); 869 item.setLine(shape); 870 item.setLinePaint(paint); 871 item.setShapeVisible(false); 872 } 873 else { 874 Paint outlinePaint = lookupSeriesOutlinePaint(series); 875 Stroke outlineStroke = lookupSeriesOutlineStroke(series); 876 item.setOutlinePaint(outlinePaint); 877 item.setOutlineStroke(outlineStroke); 878 } 879 return item; 880 } 881 882 /** 883 * Fills a band between two values on the axis. This can be used to color 884 * bands between the grid lines. 885 * 886 * @param g2 the graphics device. 887 * @param plot the plot. 888 * @param axis the domain axis. 889 * @param dataArea the data area. 890 * @param start the start value. 891 * @param end the end value. 892 */ 893 @Override 894 public void fillDomainGridBand(Graphics2D g2, XYPlot plot, ValueAxis axis, 895 Rectangle2D dataArea, double start, double end) { 896 897 double x1 = axis.valueToJava2D(start, dataArea, 898 plot.getDomainAxisEdge()); 899 double x2 = axis.valueToJava2D(end, dataArea, 900 plot.getDomainAxisEdge()); 901 Rectangle2D band; 902 if (plot.getOrientation() == PlotOrientation.VERTICAL) { 903 band = new Rectangle2D.Double(Math.min(x1, x2), dataArea.getMinY(), 904 Math.abs(x2 - x1), dataArea.getHeight()); 905 } 906 else { 907 band = new Rectangle2D.Double(dataArea.getMinX(), Math.min(x1, x2), 908 dataArea.getWidth(), Math.abs(x2 - x1)); 909 } 910 Paint paint = plot.getDomainTickBandPaint(); 911 912 if (paint != null) { 913 g2.setPaint(paint); 914 g2.fill(band); 915 } 916 917 } 918 919 /** 920 * Fills a band between two values on the range axis. This can be used to 921 * color bands between the grid lines. 922 * 923 * @param g2 the graphics device. 924 * @param plot the plot. 925 * @param axis the range axis. 926 * @param dataArea the data area. 927 * @param start the start value. 928 * @param end the end value. 929 */ 930 @Override 931 public void fillRangeGridBand(Graphics2D g2, XYPlot plot, ValueAxis axis, 932 Rectangle2D dataArea, double start, double end) { 933 934 double y1 = axis.valueToJava2D(start, dataArea, 935 plot.getRangeAxisEdge()); 936 double y2 = axis.valueToJava2D(end, dataArea, plot.getRangeAxisEdge()); 937 Rectangle2D band; 938 if (plot.getOrientation() == PlotOrientation.VERTICAL) { 939 band = new Rectangle2D.Double(dataArea.getMinX(), Math.min(y1, y2), 940 dataArea.getWidth(), Math.abs(y2 - y1)); 941 } 942 else { 943 band = new Rectangle2D.Double(Math.min(y1, y2), dataArea.getMinY(), 944 Math.abs(y2 - y1), dataArea.getHeight()); 945 } 946 Paint paint = plot.getRangeTickBandPaint(); 947 948 if (paint != null) { 949 g2.setPaint(paint); 950 g2.fill(band); 951 } 952 953 } 954 955 /** 956 * Draws a grid line against the range axis. 957 * 958 * @param g2 the graphics device. 959 * @param plot the plot. 960 * @param axis the value axis. 961 * @param dataArea the area for plotting data (not yet adjusted for any 962 * 3D effect). 963 * @param value the value at which the grid line should be drawn. 964 */ 965 @Override 966 public void drawDomainGridLine(Graphics2D g2, XYPlot plot, ValueAxis axis, 967 Rectangle2D dataArea, double value) { 968 969 Range range = axis.getRange(); 970 if (!range.contains(value)) { 971 return; 972 } 973 974 PlotOrientation orientation = plot.getOrientation(); 975 double v = axis.valueToJava2D(value, dataArea, 976 plot.getDomainAxisEdge()); 977 Line2D line = null; 978 if (orientation == PlotOrientation.HORIZONTAL) { 979 line = new Line2D.Double(dataArea.getMinX(), v, 980 dataArea.getMaxX(), v); 981 } 982 else if (orientation == PlotOrientation.VERTICAL) { 983 line = new Line2D.Double(v, dataArea.getMinY(), v, 984 dataArea.getMaxY()); 985 } 986 987 Paint paint = plot.getDomainGridlinePaint(); 988 Stroke stroke = plot.getDomainGridlineStroke(); 989 g2.setPaint(paint != null ? paint : Plot.DEFAULT_OUTLINE_PAINT); 990 g2.setStroke(stroke != null ? stroke : Plot.DEFAULT_OUTLINE_STROKE); 991 Object saved = g2.getRenderingHint(RenderingHints.KEY_STROKE_CONTROL); 992 g2.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, 993 RenderingHints.VALUE_STROKE_NORMALIZE); 994 g2.draw(line); 995 g2.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, saved); 996 } 997 998 /** 999 * Draws a line perpendicular to the domain axis. 1000 * 1001 * @param g2 the graphics device. 1002 * @param plot the plot. 1003 * @param axis the value axis. 1004 * @param dataArea the area for plotting data (not yet adjusted for any 3D 1005 * effect). 1006 * @param value the value at which the grid line should be drawn. 1007 * @param paint the paint (<code>null</code> not permitted). 1008 * @param stroke the stroke (<code>null</code> not permitted). 1009 * 1010 * @since 1.0.5 1011 */ 1012 public void drawDomainLine(Graphics2D g2, XYPlot plot, ValueAxis axis, 1013 Rectangle2D dataArea, double value, Paint paint, Stroke stroke) { 1014 1015 Range range = axis.getRange(); 1016 if (!range.contains(value)) { 1017 return; 1018 } 1019 1020 PlotOrientation orientation = plot.getOrientation(); 1021 Line2D line = null; 1022 double v = axis.valueToJava2D(value, dataArea, 1023 plot.getDomainAxisEdge()); 1024 if (orientation.isHorizontal()) { 1025 line = new Line2D.Double(dataArea.getMinX(), v, dataArea.getMaxX(), 1026 v); 1027 } else if (orientation.isVertical()) { 1028 line = new Line2D.Double(v, dataArea.getMinY(), v, 1029 dataArea.getMaxY()); 1030 } 1031 1032 g2.setPaint(paint); 1033 g2.setStroke(stroke); 1034 Object saved = g2.getRenderingHint(RenderingHints.KEY_STROKE_CONTROL); 1035 g2.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, 1036 RenderingHints.VALUE_STROKE_NORMALIZE); 1037 g2.draw(line); 1038 g2.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, saved); 1039 } 1040 1041 /** 1042 * Draws a line perpendicular to the range axis. 1043 * 1044 * @param g2 the graphics device. 1045 * @param plot the plot. 1046 * @param axis the value axis. 1047 * @param dataArea the area for plotting data (not yet adjusted for any 3D 1048 * effect). 1049 * @param value the value at which the grid line should be drawn. 1050 * @param paint the paint. 1051 * @param stroke the stroke. 1052 */ 1053 @Override 1054 public void drawRangeLine(Graphics2D g2, XYPlot plot, ValueAxis axis, 1055 Rectangle2D dataArea, double value, Paint paint, Stroke stroke) { 1056 1057 Range range = axis.getRange(); 1058 if (!range.contains(value)) { 1059 return; 1060 } 1061 1062 PlotOrientation orientation = plot.getOrientation(); 1063 Line2D line = null; 1064 double v = axis.valueToJava2D(value, dataArea, plot.getRangeAxisEdge()); 1065 if (orientation == PlotOrientation.HORIZONTAL) { 1066 line = new Line2D.Double(v, dataArea.getMinY(), v, 1067 dataArea.getMaxY()); 1068 } else if (orientation == PlotOrientation.VERTICAL) { 1069 line = new Line2D.Double(dataArea.getMinX(), v, 1070 dataArea.getMaxX(), v); 1071 } 1072 1073 g2.setPaint(paint); 1074 g2.setStroke(stroke); 1075 Object saved = g2.getRenderingHint(RenderingHints.KEY_STROKE_CONTROL); 1076 g2.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, 1077 RenderingHints.VALUE_STROKE_NORMALIZE); 1078 g2.draw(line); 1079 g2.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, saved); 1080 } 1081 1082 /** 1083 * Draws a vertical line on the chart to represent a 'range marker'. 1084 * 1085 * @param g2 the graphics device. 1086 * @param plot the plot. 1087 * @param domainAxis the domain axis. 1088 * @param marker the marker line. 1089 * @param dataArea the axis data area. 1090 */ 1091 @Override 1092 public void drawDomainMarker(Graphics2D g2, XYPlot plot, 1093 ValueAxis domainAxis, Marker marker, Rectangle2D dataArea) { 1094 1095 if (marker instanceof ValueMarker) { 1096 ValueMarker vm = (ValueMarker) marker; 1097 double value = vm.getValue(); 1098 Range range = domainAxis.getRange(); 1099 if (!range.contains(value)) { 1100 return; 1101 } 1102 1103 double v = domainAxis.valueToJava2D(value, dataArea, 1104 plot.getDomainAxisEdge()); 1105 1106 PlotOrientation orientation = plot.getOrientation(); 1107 Line2D line = null; 1108 if (orientation == PlotOrientation.HORIZONTAL) { 1109 line = new Line2D.Double(dataArea.getMinX(), v, 1110 dataArea.getMaxX(), v); 1111 } 1112 else if (orientation == PlotOrientation.VERTICAL) { 1113 line = new Line2D.Double(v, dataArea.getMinY(), v, 1114 dataArea.getMaxY()); 1115 } else { 1116 throw new IllegalStateException(); 1117 } 1118 1119 final Composite originalComposite = g2.getComposite(); 1120 g2.setComposite(AlphaComposite.getInstance( 1121 AlphaComposite.SRC_OVER, marker.getAlpha())); 1122 g2.setPaint(marker.getPaint()); 1123 g2.setStroke(marker.getStroke()); 1124 g2.draw(line); 1125 1126 String label = marker.getLabel(); 1127 RectangleAnchor anchor = marker.getLabelAnchor(); 1128 if (label != null) { 1129 Font labelFont = marker.getLabelFont(); 1130 g2.setFont(labelFont); 1131 g2.setPaint(marker.getLabelPaint()); 1132 Point2D coordinates = calculateDomainMarkerTextAnchorPoint( 1133 g2, orientation, dataArea, line.getBounds2D(), 1134 marker.getLabelOffset(), 1135 LengthAdjustmentType.EXPAND, anchor); 1136 TextUtilities.drawAlignedString(label, g2, 1137 (float) coordinates.getX(), (float) coordinates.getY(), 1138 marker.getLabelTextAnchor()); 1139 } 1140 g2.setComposite(originalComposite); 1141 } 1142 else if (marker instanceof IntervalMarker) { 1143 IntervalMarker im = (IntervalMarker) marker; 1144 double start = im.getStartValue(); 1145 double end = im.getEndValue(); 1146 Range range = domainAxis.getRange(); 1147 if (!(range.intersects(start, end))) { 1148 return; 1149 } 1150 1151 double start2d = domainAxis.valueToJava2D(start, dataArea, 1152 plot.getDomainAxisEdge()); 1153 double end2d = domainAxis.valueToJava2D(end, dataArea, 1154 plot.getDomainAxisEdge()); 1155 double low = Math.min(start2d, end2d); 1156 double high = Math.max(start2d, end2d); 1157 1158 PlotOrientation orientation = plot.getOrientation(); 1159 Rectangle2D rect = null; 1160 if (orientation == PlotOrientation.HORIZONTAL) { 1161 // clip top and bottom bounds to data area 1162 low = Math.max(low, dataArea.getMinY()); 1163 high = Math.min(high, dataArea.getMaxY()); 1164 rect = new Rectangle2D.Double(dataArea.getMinX(), 1165 low, dataArea.getWidth(), 1166 high - low); 1167 } 1168 else if (orientation == PlotOrientation.VERTICAL) { 1169 // clip left and right bounds to data area 1170 low = Math.max(low, dataArea.getMinX()); 1171 high = Math.min(high, dataArea.getMaxX()); 1172 rect = new Rectangle2D.Double(low, 1173 dataArea.getMinY(), high - low, 1174 dataArea.getHeight()); 1175 } 1176 1177 final Composite originalComposite = g2.getComposite(); 1178 g2.setComposite(AlphaComposite.getInstance( 1179 AlphaComposite.SRC_OVER, marker.getAlpha())); 1180 Paint p = marker.getPaint(); 1181 if (p instanceof GradientPaint) { 1182 GradientPaint gp = (GradientPaint) p; 1183 GradientPaintTransformer t = im.getGradientPaintTransformer(); 1184 if (t != null) { 1185 gp = t.transform(gp, rect); 1186 } 1187 g2.setPaint(gp); 1188 } 1189 else { 1190 g2.setPaint(p); 1191 } 1192 g2.fill(rect); 1193 1194 // now draw the outlines, if visible... 1195 if (im.getOutlinePaint() != null && im.getOutlineStroke() != null) { 1196 if (orientation == PlotOrientation.VERTICAL) { 1197 Line2D line = new Line2D.Double(); 1198 double y0 = dataArea.getMinY(); 1199 double y1 = dataArea.getMaxY(); 1200 g2.setPaint(im.getOutlinePaint()); 1201 g2.setStroke(im.getOutlineStroke()); 1202 if (range.contains(start)) { 1203 line.setLine(start2d, y0, start2d, y1); 1204 g2.draw(line); 1205 } 1206 if (range.contains(end)) { 1207 line.setLine(end2d, y0, end2d, y1); 1208 g2.draw(line); 1209 } 1210 } 1211 else { // PlotOrientation.HORIZONTAL 1212 Line2D line = new Line2D.Double(); 1213 double x0 = dataArea.getMinX(); 1214 double x1 = dataArea.getMaxX(); 1215 g2.setPaint(im.getOutlinePaint()); 1216 g2.setStroke(im.getOutlineStroke()); 1217 if (range.contains(start)) { 1218 line.setLine(x0, start2d, x1, start2d); 1219 g2.draw(line); 1220 } 1221 if (range.contains(end)) { 1222 line.setLine(x0, end2d, x1, end2d); 1223 g2.draw(line); 1224 } 1225 } 1226 } 1227 1228 String label = marker.getLabel(); 1229 RectangleAnchor anchor = marker.getLabelAnchor(); 1230 if (label != null) { 1231 Font labelFont = marker.getLabelFont(); 1232 g2.setFont(labelFont); 1233 g2.setPaint(marker.getLabelPaint()); 1234 Point2D coordinates = calculateDomainMarkerTextAnchorPoint( 1235 g2, orientation, dataArea, rect, 1236 marker.getLabelOffset(), marker.getLabelOffsetType(), 1237 anchor); 1238 TextUtilities.drawAlignedString(label, g2, 1239 (float) coordinates.getX(), (float) coordinates.getY(), 1240 marker.getLabelTextAnchor()); 1241 } 1242 g2.setComposite(originalComposite); 1243 1244 } 1245 1246 } 1247 1248 /** 1249 * Calculates the (x, y) coordinates for drawing a marker label. 1250 * 1251 * @param g2 the graphics device. 1252 * @param orientation the plot orientation. 1253 * @param dataArea the data area. 1254 * @param markerArea the rectangle surrounding the marker area. 1255 * @param markerOffset the marker label offset. 1256 * @param labelOffsetType the label offset type. 1257 * @param anchor the label anchor. 1258 * 1259 * @return The coordinates for drawing the marker label. 1260 */ 1261 protected Point2D calculateDomainMarkerTextAnchorPoint(Graphics2D g2, 1262 PlotOrientation orientation, Rectangle2D dataArea, 1263 Rectangle2D markerArea, RectangleInsets markerOffset, 1264 LengthAdjustmentType labelOffsetType, RectangleAnchor anchor) { 1265 1266 Rectangle2D anchorRect = null; 1267 if (orientation == PlotOrientation.HORIZONTAL) { 1268 anchorRect = markerOffset.createAdjustedRectangle(markerArea, 1269 LengthAdjustmentType.CONTRACT, labelOffsetType); 1270 } 1271 else if (orientation == PlotOrientation.VERTICAL) { 1272 anchorRect = markerOffset.createAdjustedRectangle(markerArea, 1273 labelOffsetType, LengthAdjustmentType.CONTRACT); 1274 } 1275 return RectangleAnchor.coordinates(anchorRect, anchor); 1276 1277 } 1278 1279 /** 1280 * Draws a horizontal line across the chart to represent a 'range marker'. 1281 * 1282 * @param g2 the graphics device. 1283 * @param plot the plot. 1284 * @param rangeAxis the range axis. 1285 * @param marker the marker line. 1286 * @param dataArea the axis data area. 1287 */ 1288 @Override 1289 public void drawRangeMarker(Graphics2D g2, XYPlot plot, ValueAxis rangeAxis, 1290 Marker marker, Rectangle2D dataArea) { 1291 1292 if (marker instanceof ValueMarker) { 1293 ValueMarker vm = (ValueMarker) marker; 1294 double value = vm.getValue(); 1295 Range range = rangeAxis.getRange(); 1296 if (!range.contains(value)) { 1297 return; 1298 } 1299 1300 double v = rangeAxis.valueToJava2D(value, dataArea, 1301 plot.getRangeAxisEdge()); 1302 PlotOrientation orientation = plot.getOrientation(); 1303 Line2D line = null; 1304 if (orientation == PlotOrientation.HORIZONTAL) { 1305 line = new Line2D.Double(v, dataArea.getMinY(), v, 1306 dataArea.getMaxY()); 1307 } 1308 else if (orientation == PlotOrientation.VERTICAL) { 1309 line = new Line2D.Double(dataArea.getMinX(), v, 1310 dataArea.getMaxX(), v); 1311 } 1312 else { 1313 throw new IllegalStateException("Unknown orientation."); 1314 } 1315 1316 final Composite originalComposite = g2.getComposite(); 1317 g2.setComposite(AlphaComposite.getInstance( 1318 AlphaComposite.SRC_OVER, marker.getAlpha())); 1319 g2.setPaint(marker.getPaint()); 1320 g2.setStroke(marker.getStroke()); 1321 g2.draw(line); 1322 1323 String label = marker.getLabel(); 1324 RectangleAnchor anchor = marker.getLabelAnchor(); 1325 if (label != null) { 1326 Font labelFont = marker.getLabelFont(); 1327 g2.setFont(labelFont); 1328 g2.setPaint(marker.getLabelPaint()); 1329 Point2D coordinates = calculateRangeMarkerTextAnchorPoint( 1330 g2, orientation, dataArea, line.getBounds2D(), 1331 marker.getLabelOffset(), 1332 LengthAdjustmentType.EXPAND, anchor); 1333 TextUtilities.drawAlignedString(label, g2, 1334 (float) coordinates.getX(), (float) coordinates.getY(), 1335 marker.getLabelTextAnchor()); 1336 } 1337 g2.setComposite(originalComposite); 1338 } 1339 else if (marker instanceof IntervalMarker) { 1340 IntervalMarker im = (IntervalMarker) marker; 1341 double start = im.getStartValue(); 1342 double end = im.getEndValue(); 1343 Range range = rangeAxis.getRange(); 1344 if (!(range.intersects(start, end))) { 1345 return; 1346 } 1347 1348 double start2d = rangeAxis.valueToJava2D(start, dataArea, 1349 plot.getRangeAxisEdge()); 1350 double end2d = rangeAxis.valueToJava2D(end, dataArea, 1351 plot.getRangeAxisEdge()); 1352 double low = Math.min(start2d, end2d); 1353 double high = Math.max(start2d, end2d); 1354 1355 PlotOrientation orientation = plot.getOrientation(); 1356 Rectangle2D rect = null; 1357 if (orientation == PlotOrientation.HORIZONTAL) { 1358 // clip left and right bounds to data area 1359 low = Math.max(low, dataArea.getMinX()); 1360 high = Math.min(high, dataArea.getMaxX()); 1361 rect = new Rectangle2D.Double(low, 1362 dataArea.getMinY(), high - low, 1363 dataArea.getHeight()); 1364 } 1365 else if (orientation == PlotOrientation.VERTICAL) { 1366 // clip top and bottom bounds to data area 1367 low = Math.max(low, dataArea.getMinY()); 1368 high = Math.min(high, dataArea.getMaxY()); 1369 rect = new Rectangle2D.Double(dataArea.getMinX(), 1370 low, dataArea.getWidth(), 1371 high - low); 1372 } 1373 1374 final Composite originalComposite = g2.getComposite(); 1375 g2.setComposite(AlphaComposite.getInstance( 1376 AlphaComposite.SRC_OVER, marker.getAlpha())); 1377 Paint p = marker.getPaint(); 1378 if (p instanceof GradientPaint) { 1379 GradientPaint gp = (GradientPaint) p; 1380 GradientPaintTransformer t = im.getGradientPaintTransformer(); 1381 if (t != null) { 1382 gp = t.transform(gp, rect); 1383 } 1384 g2.setPaint(gp); 1385 } 1386 else { 1387 g2.setPaint(p); 1388 } 1389 g2.fill(rect); 1390 1391 // now draw the outlines, if visible... 1392 if (im.getOutlinePaint() != null && im.getOutlineStroke() != null) { 1393 if (orientation == PlotOrientation.VERTICAL) { 1394 Line2D line = new Line2D.Double(); 1395 double x0 = dataArea.getMinX(); 1396 double x1 = dataArea.getMaxX(); 1397 g2.setPaint(im.getOutlinePaint()); 1398 g2.setStroke(im.getOutlineStroke()); 1399 if (range.contains(start)) { 1400 line.setLine(x0, start2d, x1, start2d); 1401 g2.draw(line); 1402 } 1403 if (range.contains(end)) { 1404 line.setLine(x0, end2d, x1, end2d); 1405 g2.draw(line); 1406 } 1407 } 1408 else { // PlotOrientation.HORIZONTAL 1409 Line2D line = new Line2D.Double(); 1410 double y0 = dataArea.getMinY(); 1411 double y1 = dataArea.getMaxY(); 1412 g2.setPaint(im.getOutlinePaint()); 1413 g2.setStroke(im.getOutlineStroke()); 1414 if (range.contains(start)) { 1415 line.setLine(start2d, y0, start2d, y1); 1416 g2.draw(line); 1417 } 1418 if (range.contains(end)) { 1419 line.setLine(end2d, y0, end2d, y1); 1420 g2.draw(line); 1421 } 1422 } 1423 } 1424 1425 String label = marker.getLabel(); 1426 RectangleAnchor anchor = marker.getLabelAnchor(); 1427 if (label != null) { 1428 Font labelFont = marker.getLabelFont(); 1429 g2.setFont(labelFont); 1430 g2.setPaint(marker.getLabelPaint()); 1431 Point2D coordinates = calculateRangeMarkerTextAnchorPoint( 1432 g2, orientation, dataArea, rect, 1433 marker.getLabelOffset(), marker.getLabelOffsetType(), 1434 anchor); 1435 TextUtilities.drawAlignedString(label, g2, 1436 (float) coordinates.getX(), (float) coordinates.getY(), 1437 marker.getLabelTextAnchor()); 1438 } 1439 g2.setComposite(originalComposite); 1440 } 1441 } 1442 1443 /** 1444 * Calculates the (x, y) coordinates for drawing a marker label. 1445 * 1446 * @param g2 the graphics device. 1447 * @param orientation the plot orientation. 1448 * @param dataArea the data area. 1449 * @param markerArea the marker area. 1450 * @param markerOffset the marker offset. 1451 * @param labelOffsetForRange ?? 1452 * @param anchor the label anchor. 1453 * 1454 * @return The coordinates for drawing the marker label. 1455 */ 1456 private Point2D calculateRangeMarkerTextAnchorPoint(Graphics2D g2, 1457 PlotOrientation orientation, Rectangle2D dataArea, 1458 Rectangle2D markerArea, RectangleInsets markerOffset, 1459 LengthAdjustmentType labelOffsetForRange, RectangleAnchor anchor) { 1460 1461 Rectangle2D anchorRect = null; 1462 if (orientation == PlotOrientation.HORIZONTAL) { 1463 anchorRect = markerOffset.createAdjustedRectangle(markerArea, 1464 labelOffsetForRange, LengthAdjustmentType.CONTRACT); 1465 } 1466 else if (orientation == PlotOrientation.VERTICAL) { 1467 anchorRect = markerOffset.createAdjustedRectangle(markerArea, 1468 LengthAdjustmentType.CONTRACT, labelOffsetForRange); 1469 } 1470 return RectangleAnchor.coordinates(anchorRect, anchor); 1471 1472 } 1473 1474 /** 1475 * Returns a clone of the renderer. 1476 * 1477 * @return A clone. 1478 * 1479 * @throws CloneNotSupportedException if the renderer does not support 1480 * cloning. 1481 */ 1482 @Override 1483 protected Object clone() throws CloneNotSupportedException { 1484 AbstractXYItemRenderer clone = (AbstractXYItemRenderer) super.clone(); 1485 // 'plot' : just retain reference, not a deep copy 1486 1487 if (this.itemLabelGenerator != null 1488 && this.itemLabelGenerator instanceof PublicCloneable) { 1489 PublicCloneable pc = (PublicCloneable) this.itemLabelGenerator; 1490 clone.itemLabelGenerator = (XYItemLabelGenerator) pc.clone(); 1491 } 1492 clone.itemLabelGeneratorMap = CloneUtils.cloneMapValues( 1493 this.itemLabelGeneratorMap); 1494 if (this.baseItemLabelGenerator != null 1495 && this.baseItemLabelGenerator instanceof PublicCloneable) { 1496 PublicCloneable pc = (PublicCloneable) this.baseItemLabelGenerator; 1497 clone.baseItemLabelGenerator = (XYItemLabelGenerator) pc.clone(); 1498 } 1499 1500 if (this.toolTipGenerator != null 1501 && this.toolTipGenerator instanceof PublicCloneable) { 1502 PublicCloneable pc = (PublicCloneable) this.toolTipGenerator; 1503 clone.toolTipGenerator = (XYToolTipGenerator) pc.clone(); 1504 } 1505 clone.toolTipGeneratorMap = CloneUtils.cloneMapValues( 1506 this.toolTipGeneratorMap); 1507 if (this.baseToolTipGenerator != null 1508 && this.baseToolTipGenerator instanceof PublicCloneable) { 1509 PublicCloneable pc = (PublicCloneable) this.baseToolTipGenerator; 1510 clone.baseToolTipGenerator = (XYToolTipGenerator) pc.clone(); 1511 } 1512 1513 if (this.legendItemLabelGenerator instanceof PublicCloneable) { 1514 clone.legendItemLabelGenerator = (XYSeriesLabelGenerator) 1515 ObjectUtilities.clone(this.legendItemLabelGenerator); 1516 } 1517 if (this.legendItemToolTipGenerator instanceof PublicCloneable) { 1518 clone.legendItemToolTipGenerator = (XYSeriesLabelGenerator) 1519 ObjectUtilities.clone(this.legendItemToolTipGenerator); 1520 } 1521 if (this.legendItemURLGenerator instanceof PublicCloneable) { 1522 clone.legendItemURLGenerator = (XYSeriesLabelGenerator) 1523 ObjectUtilities.clone(this.legendItemURLGenerator); 1524 } 1525 1526 clone.foregroundAnnotations = (List) ObjectUtilities.deepClone( 1527 this.foregroundAnnotations); 1528 clone.backgroundAnnotations = (List) ObjectUtilities.deepClone( 1529 this.backgroundAnnotations); 1530 1531 return clone; 1532 } 1533 1534 /** 1535 * Tests this renderer for equality with another object. 1536 * 1537 * @param obj the object (<code>null</code> permitted). 1538 * 1539 * @return <code>true</code> or <code>false</code>. 1540 */ 1541 @Override 1542 public boolean equals(Object obj) { 1543 if (obj == this) { 1544 return true; 1545 } 1546 if (!(obj instanceof AbstractXYItemRenderer)) { 1547 return false; 1548 } 1549 AbstractXYItemRenderer that = (AbstractXYItemRenderer) obj; 1550 if (!ObjectUtilities.equal(this.itemLabelGenerator, 1551 that.itemLabelGenerator)) { 1552 return false; 1553 } 1554 if (!this.itemLabelGeneratorMap.equals(that.itemLabelGeneratorMap)) { 1555 return false; 1556 } 1557 if (!ObjectUtilities.equal(this.baseItemLabelGenerator, 1558 that.baseItemLabelGenerator)) { 1559 return false; 1560 } 1561 if (!ObjectUtilities.equal(this.toolTipGenerator, 1562 that.toolTipGenerator)) { 1563 return false; 1564 } 1565 if (!this.toolTipGeneratorMap.equals(that.toolTipGeneratorMap)) { 1566 return false; 1567 } 1568 if (!ObjectUtilities.equal(this.baseToolTipGenerator, 1569 that.baseToolTipGenerator)) { 1570 return false; 1571 } 1572 if (!ObjectUtilities.equal(this.urlGenerator, that.urlGenerator)) { 1573 return false; 1574 } 1575 if (!this.foregroundAnnotations.equals(that.foregroundAnnotations)) { 1576 return false; 1577 } 1578 if (!this.backgroundAnnotations.equals(that.backgroundAnnotations)) { 1579 return false; 1580 } 1581 if (!ObjectUtilities.equal(this.legendItemLabelGenerator, 1582 that.legendItemLabelGenerator)) { 1583 return false; 1584 } 1585 if (!ObjectUtilities.equal(this.legendItemToolTipGenerator, 1586 that.legendItemToolTipGenerator)) { 1587 return false; 1588 } 1589 if (!ObjectUtilities.equal(this.legendItemURLGenerator, 1590 that.legendItemURLGenerator)) { 1591 return false; 1592 } 1593 return super.equals(obj); 1594 } 1595 1596 /** 1597 * Returns the drawing supplier from the plot. 1598 * 1599 * @return The drawing supplier (possibly <code>null</code>). 1600 */ 1601 @Override 1602 public DrawingSupplier getDrawingSupplier() { 1603 DrawingSupplier result = null; 1604 XYPlot p = getPlot(); 1605 if (p != null) { 1606 result = p.getDrawingSupplier(); 1607 } 1608 return result; 1609 } 1610 1611 /** 1612 * Considers the current (x, y) coordinate and updates the crosshair point 1613 * if it meets the criteria (usually means the (x, y) coordinate is the 1614 * closest to the anchor point so far). 1615 * 1616 * @param crosshairState the crosshair state (<code>null</code> permitted, 1617 * but the method does nothing in that case). 1618 * @param x the x-value (in data space). 1619 * @param y the y-value (in data space). 1620 * @param domainAxisIndex the index of the domain axis for the point. 1621 * @param rangeAxisIndex the index of the range axis for the point. 1622 * @param transX the x-value translated to Java2D space. 1623 * @param transY the y-value translated to Java2D space. 1624 * @param orientation the plot orientation (<code>null</code> not 1625 * permitted). 1626 * 1627 * @since 1.0.4 1628 */ 1629 protected void updateCrosshairValues(CrosshairState crosshairState, 1630 double x, double y, int domainAxisIndex, int rangeAxisIndex, 1631 double transX, double transY, PlotOrientation orientation) { 1632 1633 ParamChecks.nullNotPermitted(orientation, "orientation"); 1634 if (crosshairState != null) { 1635 // do we need to update the crosshair values? 1636 if (this.plot.isDomainCrosshairLockedOnData()) { 1637 if (this.plot.isRangeCrosshairLockedOnData()) { 1638 // both axes 1639 crosshairState.updateCrosshairPoint(x, y, domainAxisIndex, 1640 rangeAxisIndex, transX, transY, orientation); 1641 } 1642 else { 1643 // just the domain axis... 1644 crosshairState.updateCrosshairX(x, domainAxisIndex); 1645 } 1646 } 1647 else { 1648 if (this.plot.isRangeCrosshairLockedOnData()) { 1649 // just the range axis... 1650 crosshairState.updateCrosshairY(y, rangeAxisIndex); 1651 } 1652 } 1653 } 1654 1655 } 1656 1657 /** 1658 * Draws an item label. 1659 * 1660 * @param g2 the graphics device. 1661 * @param orientation the orientation. 1662 * @param dataset the dataset. 1663 * @param series the series index (zero-based). 1664 * @param item the item index (zero-based). 1665 * @param x the x coordinate (in Java2D space). 1666 * @param y the y coordinate (in Java2D space). 1667 * @param negative indicates a negative value (which affects the item 1668 * label position). 1669 */ 1670 protected void drawItemLabel(Graphics2D g2, PlotOrientation orientation, 1671 XYDataset dataset, int series, int item, double x, double y, 1672 boolean negative) { 1673 1674 XYItemLabelGenerator generator = getItemLabelGenerator(series, item); 1675 if (generator != null) { 1676 Font labelFont = getItemLabelFont(series, item); 1677 Paint paint = getItemLabelPaint(series, item); 1678 g2.setFont(labelFont); 1679 g2.setPaint(paint); 1680 String label = generator.generateLabel(dataset, series, item); 1681 1682 // get the label position.. 1683 ItemLabelPosition position; 1684 if (!negative) { 1685 position = getPositiveItemLabelPosition(series, item); 1686 } 1687 else { 1688 position = getNegativeItemLabelPosition(series, item); 1689 } 1690 1691 // work out the label anchor point... 1692 Point2D anchorPoint = calculateLabelAnchorPoint( 1693 position.getItemLabelAnchor(), x, y, orientation); 1694 TextUtilities.drawRotatedString(label, g2, 1695 (float) anchorPoint.getX(), (float) anchorPoint.getY(), 1696 position.getTextAnchor(), position.getAngle(), 1697 position.getRotationAnchor()); 1698 } 1699 1700 } 1701 1702 /** 1703 * Draws all the annotations for the specified layer. 1704 * 1705 * @param g2 the graphics device. 1706 * @param dataArea the data area. 1707 * @param domainAxis the domain axis. 1708 * @param rangeAxis the range axis. 1709 * @param layer the layer. 1710 * @param info the plot rendering info. 1711 */ 1712 @Override 1713 public void drawAnnotations(Graphics2D g2, Rectangle2D dataArea, 1714 ValueAxis domainAxis, ValueAxis rangeAxis, Layer layer, 1715 PlotRenderingInfo info) { 1716 1717 Iterator iterator = null; 1718 if (layer.equals(Layer.FOREGROUND)) { 1719 iterator = this.foregroundAnnotations.iterator(); 1720 } 1721 else if (layer.equals(Layer.BACKGROUND)) { 1722 iterator = this.backgroundAnnotations.iterator(); 1723 } 1724 else { 1725 // should not get here 1726 throw new RuntimeException("Unknown layer."); 1727 } 1728 while (iterator.hasNext()) { 1729 XYAnnotation annotation = (XYAnnotation) iterator.next(); 1730 int index = this.plot.getIndexOf(this); 1731 annotation.draw(g2, this.plot, dataArea, domainAxis, rangeAxis, 1732 index, info); 1733 } 1734 1735 } 1736 1737 /** 1738 * Adds an entity to the collection. 1739 * 1740 * @param entities the entity collection being populated. 1741 * @param area the entity area (if <code>null</code> a default will be 1742 * used). 1743 * @param dataset the dataset. 1744 * @param series the series. 1745 * @param item the item. 1746 * @param entityX the entity's center x-coordinate in user space (only 1747 * used if <code>area</code> is <code>null</code>). 1748 * @param entityY the entity's center y-coordinate in user space (only 1749 * used if <code>area</code> is <code>null</code>). 1750 */ 1751 protected void addEntity(EntityCollection entities, Shape area, 1752 XYDataset dataset, int series, int item, 1753 double entityX, double entityY) { 1754 if (!getItemCreateEntity(series, item)) { 1755 return; 1756 } 1757 Shape hotspot = area; 1758 if (hotspot == null) { 1759 double r = getDefaultEntityRadius(); 1760 double w = r * 2; 1761 if (getPlot().getOrientation() == PlotOrientation.VERTICAL) { 1762 hotspot = new Ellipse2D.Double(entityX - r, entityY - r, w, w); 1763 } 1764 else { 1765 hotspot = new Ellipse2D.Double(entityY - r, entityX - r, w, w); 1766 } 1767 } 1768 String tip = null; 1769 XYToolTipGenerator generator = getToolTipGenerator(series, item); 1770 if (generator != null) { 1771 tip = generator.generateToolTip(dataset, series, item); 1772 } 1773 String url = null; 1774 if (getURLGenerator() != null) { 1775 url = getURLGenerator().generateURL(dataset, series, item); 1776 } 1777 XYItemEntity entity = new XYItemEntity(hotspot, dataset, series, item, 1778 tip, url); 1779 entities.add(entity); 1780 } 1781 1782 /** 1783 * Returns <code>true</code> if the specified point (x, y) falls within or 1784 * on the boundary of the specified rectangle. 1785 * 1786 * @param rect the rectangle (<code>null</code> not permitted). 1787 * @param x the x-coordinate. 1788 * @param y the y-coordinate. 1789 * 1790 * @return A boolean. 1791 * 1792 * @since 1.0.10 1793 */ 1794 public static boolean isPointInRect(Rectangle2D rect, double x, double y) { 1795 // TODO: For JFreeChart 1.2.0, this method should go in the 1796 // ShapeUtilities class 1797 return (x >= rect.getMinX() && x <= rect.getMaxX() 1798 && y >= rect.getMinY() && y <= rect.getMaxY()); 1799 } 1800 1801 /** 1802 * Utility method delegating to {@link GeneralPath#moveTo} taking double as 1803 * parameters. 1804 * 1805 * @param hotspot the region under construction (<code>null</code> not 1806 * permitted); 1807 * @param x the x coordinate; 1808 * @param y the y coordinate; 1809 * 1810 * @since 1.0.14 1811 */ 1812 protected static void moveTo(GeneralPath hotspot, double x, double y) { 1813 hotspot.moveTo((float) x, (float) y); 1814 } 1815 1816 /** 1817 * Utility method delegating to {@link GeneralPath#lineTo} taking double as 1818 * parameters. 1819 * 1820 * @param hotspot the region under construction (<code>null</code> not 1821 * permitted); 1822 * @param x the x coordinate; 1823 * @param y the y coordinate; 1824 * 1825 * @since 1.0.14 1826 */ 1827 protected static void lineTo(GeneralPath hotspot, double x, double y) { 1828 hotspot.lineTo((float) x, (float) y); 1829 } 1830 1831 // === DEPRECATED CODE === 1832 1833 /** 1834 * The item label generator for ALL series. 1835 * 1836 * @deprecated This field is redundant, use itemLabelGeneratorList and 1837 * baseItemLabelGenerator instead. Deprecated as of version 1.0.6. 1838 */ 1839 private XYItemLabelGenerator itemLabelGenerator; 1840 1841 /** 1842 * The tool tip generator for ALL series. 1843 * 1844 * @deprecated This field is redundant, use tooltipGeneratorList and 1845 * baseToolTipGenerator instead. Deprecated as of version 1.0.6. 1846 */ 1847 private XYToolTipGenerator toolTipGenerator; 1848 1849 /** 1850 * Returns the item label generator override. 1851 * 1852 * @return The generator (possibly <code>null</code>). 1853 * 1854 * @since 1.0.5 1855 * 1856 * @see #setItemLabelGenerator(XYItemLabelGenerator) 1857 * 1858 * @deprecated As of version 1.0.6, this override setting should not be 1859 * used. You can use the base setting instead 1860 * ({@link #getBaseItemLabelGenerator()}). 1861 */ 1862 public XYItemLabelGenerator getItemLabelGenerator() { 1863 return this.itemLabelGenerator; 1864 } 1865 1866 /** 1867 * Sets the item label generator for ALL series and sends a 1868 * {@link RendererChangeEvent} to all registered listeners. 1869 * 1870 * @param generator the generator (<code>null</code> permitted). 1871 * 1872 * @see #getItemLabelGenerator() 1873 * 1874 * @deprecated As of version 1.0.6, this override setting should not be 1875 * used. You can use the base setting instead 1876 * ({@link #setBaseItemLabelGenerator(XYItemLabelGenerator)}). 1877 */ 1878 @Override 1879 public void setItemLabelGenerator(XYItemLabelGenerator generator) { 1880 this.itemLabelGenerator = generator; 1881 fireChangeEvent(); 1882 } 1883 1884 /** 1885 * Returns the override tool tip generator. 1886 * 1887 * @return The tool tip generator (possible <code>null</code>). 1888 * 1889 * @since 1.0.5 1890 * 1891 * @see #setToolTipGenerator(XYToolTipGenerator) 1892 * 1893 * @deprecated As of version 1.0.6, this override setting should not be 1894 * used. You can use the base setting instead 1895 * ({@link #getBaseToolTipGenerator()}). 1896 */ 1897 public XYToolTipGenerator getToolTipGenerator() { 1898 return this.toolTipGenerator; 1899 } 1900 1901 /** 1902 * Sets the tool tip generator for ALL series and sends a 1903 * {@link RendererChangeEvent} to all registered listeners. 1904 * 1905 * @param generator the generator (<code>null</code> permitted). 1906 * 1907 * @see #getToolTipGenerator() 1908 * 1909 * @deprecated As of version 1.0.6, this override setting should not be 1910 * used. You can use the base setting instead 1911 * ({@link #setBaseToolTipGenerator(XYToolTipGenerator)}). 1912 */ 1913 @Override 1914 public void setToolTipGenerator(XYToolTipGenerator generator) { 1915 this.toolTipGenerator = generator; 1916 fireChangeEvent(); 1917 } 1918 1919 /** 1920 * Considers the current (x, y) coordinate and updates the crosshair point 1921 * if it meets the criteria (usually means the (x, y) coordinate is the 1922 * closest to the anchor point so far). 1923 * 1924 * @param crosshairState the crosshair state (<code>null</code> permitted, 1925 * but the method does nothing in that case). 1926 * @param x the x-value (in data space). 1927 * @param y the y-value (in data space). 1928 * @param transX the x-value translated to Java2D space. 1929 * @param transY the y-value translated to Java2D space. 1930 * @param orientation the plot orientation (<code>null</code> not 1931 * permitted). 1932 * 1933 * @deprecated Use {@link #updateCrosshairValues(CrosshairState, double, 1934 * double, int, int, double, double, PlotOrientation)} -- see bug 1935 * report 1086307. 1936 */ 1937 protected void updateCrosshairValues(CrosshairState crosshairState, 1938 double x, double y, double transX, double transY, 1939 PlotOrientation orientation) { 1940 updateCrosshairValues(crosshairState, x, y, 0, 0, transX, transY, 1941 orientation); 1942 } 1943 1944 1945}