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

Save This Page
Home » jcommon-1.0.13 » org.jfree » chart » renderer » xy » [javadoc | source]