Save This Page
Home » jcommon-1.0.13 » org.jfree » chart » renderer » category » [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    * CategoryStepRenderer.java
   29    * -------------------------
   30    *
   31    * (C) Copyright 2004-2008, by Brian Cole and Contributors.
   32    *
   33    * Original Author:  Brian Cole;
   34    * Contributor(s):   David Gilbert (for Object Refinery Limited);
   35    *
   36    * Changes
   37    * -------
   38    * 21-Apr-2004 : Version 1, contributed by Brian Cole (DG);
   39    * 22-Apr-2004 : Fixed Checkstyle complaints (DG);
   40    * 05-Nov-2004 : Modified drawItem() signature (DG);
   41    * 08-Mar-2005 : Added equals() method (DG);
   42    * ------------- JFREECHART 1.0.x ---------------------------------------------
   43    * 30-Nov-2006 : Added checks for series visibility (DG);
   44    * 22-Feb-2007 : Use new state object for reusable line, enable chart entities
   45    *               (for tooltips, URLs), added new getLegendItem() override (DG);
   46    * 20-Apr-2007 : Updated getLegendItem() for renderer change (DG);
   47    * 18-May-2007 : Set dataset and seriesKey for LegendItem (DG);
   48    *
   49    */
   50   
   51   package org.jfree.chart.renderer.category;
   52   
   53   import java.awt.Graphics2D;
   54   import java.awt.Paint;
   55   import java.awt.Shape;
   56   import java.awt.geom.Line2D;
   57   import java.awt.geom.Rectangle2D;
   58   import java.io.Serializable;
   59   
   60   import org.jfree.chart.LegendItem;
   61   import org.jfree.chart.axis.CategoryAxis;
   62   import org.jfree.chart.axis.ValueAxis;
   63   import org.jfree.chart.entity.EntityCollection;
   64   import org.jfree.chart.event.RendererChangeEvent;
   65   import org.jfree.chart.plot.CategoryPlot;
   66   import org.jfree.chart.plot.PlotOrientation;
   67   import org.jfree.chart.plot.PlotRenderingInfo;
   68   import org.jfree.chart.renderer.xy.XYStepRenderer;
   69   import org.jfree.data.category.CategoryDataset;
   70   import org.jfree.util.PublicCloneable;
   71   
   72   /**
   73    * A "step" renderer similar to {@link XYStepRenderer} but
   74    * that can be used with the {@link CategoryPlot} class.
   75    */
   76   public class CategoryStepRenderer extends AbstractCategoryItemRenderer
   77           implements Cloneable, PublicCloneable, Serializable {
   78   
   79       /**
   80        * State information for the renderer.
   81        */
   82       protected static class State extends CategoryItemRendererState {
   83   
   84           /**
   85            * A working line for re-use to avoid creating large numbers of
   86            * objects.
   87            */
   88           public Line2D line;
   89   
   90           /**
   91            * Creates a new state instance.
   92            *
   93            * @param info  collects plot rendering information (<code>null</code>
   94            *              permitted).
   95            */
   96           public State(PlotRenderingInfo info) {
   97               super(info);
   98               this.line = new Line2D.Double();
   99           }
  100   
  101       }
  102   
  103       /** For serialization. */
  104       private static final long serialVersionUID = -5121079703118261470L;
  105   
  106       /** The stagger width. */
  107       public static final int STAGGER_WIDTH = 5; // could make this configurable
  108   
  109       /**
  110        * A flag that controls whether or not the steps for multiple series are
  111        * staggered.
  112        */
  113       private boolean stagger = false;
  114   
  115       /**
  116        * Creates a new renderer (stagger defaults to <code>false</code>).
  117        */
  118       public CategoryStepRenderer() {
  119           this(false);
  120       }
  121   
  122       /**
  123        * Creates a new renderer.
  124        *
  125        * @param stagger  should the horizontal part of the step be staggered by
  126        *                 series?
  127        */
  128       public CategoryStepRenderer(boolean stagger) {
  129           this.stagger = stagger;
  130       }
  131   
  132       /**
  133        * Returns the flag that controls whether the series steps are staggered.
  134        *
  135        * @return A boolean.
  136        */
  137       public boolean getStagger() {
  138           return this.stagger;
  139       }
  140   
  141       /**
  142        * Sets the flag that controls whether or not the series steps are
  143        * staggered and sends a {@link RendererChangeEvent} to all registered
  144        * listeners.
  145        *
  146        * @param shouldStagger  a boolean.
  147        */
  148       public void setStagger(boolean shouldStagger) {
  149           this.stagger = shouldStagger;
  150           fireChangeEvent();
  151       }
  152   
  153       /**
  154        * Returns a legend item for a series.
  155        *
  156        * @param datasetIndex  the dataset index (zero-based).
  157        * @param series  the series index (zero-based).
  158        *
  159        * @return The legend item.
  160        */
  161       public LegendItem getLegendItem(int datasetIndex, int series) {
  162   
  163           CategoryPlot p = getPlot();
  164           if (p == null) {
  165               return null;
  166           }
  167   
  168           // check that a legend item needs to be displayed...
  169           if (!isSeriesVisible(series) || !isSeriesVisibleInLegend(series)) {
  170               return null;
  171           }
  172   
  173           CategoryDataset dataset = p.getDataset(datasetIndex);
  174           String label = getLegendItemLabelGenerator().generateLabel(dataset,
  175                   series);
  176           String description = label;
  177           String toolTipText = null;
  178           if (getLegendItemToolTipGenerator() != null) {
  179               toolTipText = getLegendItemToolTipGenerator().generateLabel(
  180                       dataset, series);
  181           }
  182           String urlText = null;
  183           if (getLegendItemURLGenerator() != null) {
  184               urlText = getLegendItemURLGenerator().generateLabel(dataset,
  185                       series);
  186           }
  187           Shape shape = new Rectangle2D.Double(-4.0, -3.0, 8.0, 6.0);
  188           Paint paint = lookupSeriesPaint(series);
  189   
  190           LegendItem item = new LegendItem(label, description, toolTipText,
  191                   urlText, shape, paint);
  192           item.setSeriesKey(dataset.getRowKey(series));
  193           item.setSeriesIndex(series);
  194           item.setDataset(dataset);
  195           item.setDatasetIndex(datasetIndex);
  196           return item;
  197       }
  198   
  199       /**
  200        * Creates a new state instance.  This method is called from
  201        * {@link #initialise(Graphics2D, Rectangle2D, CategoryPlot, int,
  202        * PlotRenderingInfo)}, and we override it to ensure that the state
  203        * contains a working Line2D instance.
  204        *
  205        * @param info  the plot rendering info (<code>null</code> is permitted).
  206        *
  207        * @return A new state instance.
  208        */
  209       protected CategoryItemRendererState createState(PlotRenderingInfo info) {
  210           return new State(info);
  211       }
  212   
  213       /**
  214        * Draws a line taking into account the specified orientation.
  215        * <p>
  216        * In version 1.0.5, the signature of this method was changed by the
  217        * addition of the 'state' parameter.  This is an incompatible change, but
  218        * is considered a low risk because it is unlikely that anyone has
  219        * subclassed this renderer.  If this *does* cause trouble for you, please
  220        * report it as a bug.
  221        *
  222        * @param g2  the graphics device.
  223        * @param state  the renderer state.
  224        * @param orientation  the plot orientation.
  225        * @param x0  the x-coordinate for the start of the line.
  226        * @param y0  the y-coordinate for the start of the line.
  227        * @param x1  the x-coordinate for the end of the line.
  228        * @param y1  the y-coordinate for the end of the line.
  229        */
  230       protected void drawLine(Graphics2D g2, State state,
  231               PlotOrientation orientation, double x0, double y0, double x1,
  232               double y1) {
  233   
  234           if (orientation == PlotOrientation.VERTICAL) {
  235               state.line.setLine(x0, y0, x1, y1);
  236               g2.draw(state.line);
  237           }
  238           else if (orientation == PlotOrientation.HORIZONTAL) {
  239               state.line.setLine(y0, x0, y1, x1); // switch x and y
  240               g2.draw(state.line);
  241           }
  242   
  243       }
  244   
  245       /**
  246        * Draw a single data item.
  247        *
  248        * @param g2  the graphics device.
  249        * @param state  the renderer state.
  250        * @param dataArea  the area in which the data is drawn.
  251        * @param plot  the plot.
  252        * @param domainAxis  the domain axis.
  253        * @param rangeAxis  the range axis.
  254        * @param dataset  the dataset.
  255        * @param row  the row index (zero-based).
  256        * @param column  the column index (zero-based).
  257        * @param pass  the pass index.
  258        */
  259       public void drawItem(Graphics2D g2,
  260                            CategoryItemRendererState state,
  261                            Rectangle2D dataArea,
  262                            CategoryPlot plot,
  263                            CategoryAxis domainAxis,
  264                            ValueAxis rangeAxis,
  265                            CategoryDataset dataset,
  266                            int row,
  267                            int column,
  268                            int pass) {
  269   
  270           // do nothing if item is not visible
  271           if (!getItemVisible(row, column)) {
  272               return;
  273           }
  274   
  275           Number value = dataset.getValue(row, column);
  276           if (value == null) {
  277               return;
  278           }
  279           PlotOrientation orientation = plot.getOrientation();
  280   
  281           // current data point...
  282           double x1s = domainAxis.getCategoryStart(column, getColumnCount(),
  283                   dataArea, plot.getDomainAxisEdge());
  284           double x1 = domainAxis.getCategoryMiddle(column, getColumnCount(),
  285                   dataArea, plot.getDomainAxisEdge());
  286           double x1e = 2 * x1 - x1s; // or: x1s + 2*(x1-x1s)
  287           double y1 = rangeAxis.valueToJava2D(value.doubleValue(), dataArea,
  288                   plot.getRangeAxisEdge());
  289           g2.setPaint(getItemPaint(row, column));
  290           g2.setStroke(getItemStroke(row, column));
  291   
  292           if (column != 0) {
  293               Number previousValue = dataset.getValue(row, column - 1);
  294               if (previousValue != null) {
  295                   // previous data point...
  296                   double previous = previousValue.doubleValue();
  297                   double x0s = domainAxis.getCategoryStart(column - 1,
  298                           getColumnCount(), dataArea, plot.getDomainAxisEdge());
  299                   double x0 = domainAxis.getCategoryMiddle(column - 1,
  300                           getColumnCount(), dataArea, plot.getDomainAxisEdge());
  301                   double x0e = 2 * x0 - x0s; // or: x0s + 2*(x0-x0s)
  302                   double y0 = rangeAxis.valueToJava2D(previous, dataArea,
  303                           plot.getRangeAxisEdge());
  304                   if (getStagger()) {
  305                       int xStagger = row * STAGGER_WIDTH;
  306                       if (xStagger > (x1s - x0e)) {
  307                           xStagger = (int) (x1s - x0e);
  308                       }
  309                       x1s = x0e + xStagger;
  310                   }
  311                   drawLine(g2, (State) state, orientation, x0e, y0, x1s, y0);
  312                   // extend x0's flat bar
  313   
  314                   drawLine(g2, (State) state, orientation, x1s, y0, x1s, y1);
  315                   // upright bar
  316              }
  317          }
  318          drawLine(g2, (State) state, orientation, x1s, y1, x1e, y1);
  319          // x1's flat bar
  320   
  321          // draw the item labels if there are any...
  322          if (isItemLabelVisible(row, column)) {
  323               drawItemLabel(g2, orientation, dataset, row, column, x1, y1,
  324                       (value.doubleValue() < 0.0));
  325          }
  326   
  327          // add an item entity, if this information is being collected
  328          EntityCollection entities = state.getEntityCollection();
  329          if (entities != null) {
  330              Rectangle2D hotspot = new Rectangle2D.Double();
  331              if (orientation == PlotOrientation.VERTICAL) {
  332                  hotspot.setRect(x1s, y1, x1e - x1s, 4.0);
  333              }
  334              else {
  335                  hotspot.setRect(y1 - 2.0, x1s, 4.0, x1e - x1s);
  336              }
  337              addItemEntity(entities, dataset, row, column, hotspot);
  338          }
  339   
  340       }
  341   
  342       /**
  343        * Tests this renderer for equality with an arbitrary object.
  344        *
  345        * @param obj  the object (<code>null</code> permitted).
  346        *
  347        * @return A boolean.
  348        */
  349       public boolean equals(Object obj) {
  350           if (obj == this) {
  351               return true;
  352           }
  353           if (!(obj instanceof CategoryStepRenderer)) {
  354               return false;
  355           }
  356           CategoryStepRenderer that = (CategoryStepRenderer) obj;
  357           if (this.stagger != that.stagger) {
  358               return false;
  359           }
  360           return super.equals(obj);
  361       }
  362   
  363   }

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