Package com.positive.charts.renderer.category

Source Code of com.positive.charts.renderer.category.BarRenderer

/* ===========================================================
* JFreeChart : a free chart library for the Java(tm) platform
* ===========================================================
*
* (C) Copyright 2000-2006, by Object Refinery Limited and Contributors.
*
* Project Info:  http://www.jfree.org/jfreechart/index.html
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
* USA. 
*
* [Java is a trademark or registered trademark of Sun Microsystems, Inc.
* in the United States and other countries.]
*
* ----------------
* BarRenderer.java
* ----------------
* (C) Copyright 2002-2006, by Object Refinery Limited.
*
* Original Author:  David Gilbert (for Object Refinery Limited);
* Contributor(s):   Christian W. Zuckschwerdt;
*
* $Id: BarRenderer.java,v 1.1 2007/08/24 12:43:41 slapukhov Exp $
*
* Changes
* -------
* 14-Mar-2002 : Version 1 (DG);
* 23-May-2002 : Added tooltip generator to renderer (DG);
* 29-May-2002 : Moved tooltip generator to abstract super-class (DG);
* 25-Jun-2002 : Changed constructor to protected and removed redundant
*               code (DG);
* 26-Jun-2002 : Added axis to initialise method, and record upper and lower
*               clip values (DG);
* 24-Sep-2002 : Added getLegendItem() method (DG);
* 09-Oct-2002 : Modified constructor to include URL generator (DG);
* 05-Nov-2002 : Base dataset is now TableDataset not CategoryDataset (DG);
* 10-Jan-2003 : Moved get/setItemMargin() method up from subclasses (DG);
* 17-Jan-2003 : Moved plot classes into a separate package (DG);
* 25-Mar-2003 : Implemented Serializable (DG);
* 01-May-2003 : Modified clipping to allow for dual axes and datasets (DG);
* 12-May-2003 : Merged horizontal and vertical bar renderers (DG);
* 12-Jun-2003 : Updates for item labels (DG);
* 30-Jul-2003 : Modified entity constructor (CZ);
* 02-Sep-2003 : Changed initialise method to fix bug 790407 (DG);
* 16-Sep-2003 : Changed ChartRenderingInfo --> PlotRenderingInfo (DG);
* 07-Oct-2003 : Added renderer state (DG);
* 27-Oct-2003 : Merged drawHorizontalItem() and drawVerticalItem()
*               methods (DG);
* 28-Oct-2003 : Added support for gradient paint on bars (DG);
* 14-Nov-2003 : Added 'maxBarWidth' attribute (DG);
* 10-Feb-2004 : Small changes inside drawItem() method to ease cut-and-paste
*               overriding (DG);
* 19-Mar-2004 : Fixed bug introduced with separation of tool tip and item
*               label generators.  Fixed equals() method (DG);
* 11-May-2004 : Fix for null pointer exception (bug id 951127) (DG);
* 05-Nov-2004 : Modified drawItem() signature (DG);
* 26-Jan-2005 : Provided override for getLegendItem() method (DG);
* 20-Apr-2005 : Generate legend labels, tooltips and URLs (DG);
* 18-May-2005 : Added configurable base value (DG);
* 09-Jun-2005 : Use addItemEntity() method from superclass (DG);
* 01-Dec-2005 : Update legend item to use/not use outline (DG);
* ------------: JFreeChart 1.0.0 ---------------------------------------------
* 06-Dec-2005 : Fixed bug 1374222 (JDK 1.4 specific code) (DG);
* 11-Jan-2006 : Fixed bug 1401856 (bad rendering for non-zero base) (DG);
* 04-Aug-2006 : Fixed bug 1467706 (missing item labels for zero value
*               bars) (DG);
*
*/

package com.positive.charts.renderer.category;

import java.io.Serializable;

import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.graphics.Region;

import com.positive.charts.axis.CategoryAxis;
import com.positive.charts.axis.ValueAxis;
import com.positive.charts.common.RectangleEdge;
import com.positive.charts.data.Range;
import com.positive.charts.data.category.CategoryDataset;
import com.positive.charts.data.util.DatasetUtilities;
import com.positive.charts.data.util.ObjectUtilities;
import com.positive.charts.data.util.PublicCloneable;
import com.positive.charts.entity.EntityCollection;
import com.positive.charts.event.RendererChangeEvent;
import com.positive.charts.labels.CategoryItemLabelGenerator;
import com.positive.charts.labels.ItemLabelAnchor;
import com.positive.charts.labels.ItemLabelPosition;
import com.positive.charts.legend.LegendItem;
import com.positive.charts.plot.CategoryPlot;
import com.positive.charts.plot.Plot;
import com.positive.charts.plot.PlotOrientation;
import com.positive.charts.plot.PlotRenderingInfo;
import com.positive.charts.util.DrawingAssets;
import com.positive.charts.util.RectangleAdapter;
import com.positive.charts.util.RectangleUtil;
import com.positive.charts.util.Stroke;
import com.positive.charts.util.TextUtilities;

/**
* A {@link CategoryItemRenderer} that draws individual data items as bars.
*/
public class BarRenderer extends AbstractCategoryItemRenderer implements
    Cloneable, PublicCloneable, Serializable {

  /** For serialization. */
  private static final long serialVersionUID = 6000649414965887481L;

  /** The default item margin percentage. */
  public static final double DEFAULT_ITEM_MARGIN = 0.20;

  /**
   * Constant that controls the minimum width before a bar has an outline
   * drawn.
   */
  public static final double BAR_OUTLINE_WIDTH_THRESHOLD = 3.0;

  /** The margin between items (bars) within a category. */
  private double itemMargin;

  /** A flag that controls whether or not bar outlines are drawn. */
  private boolean drawBarOutline;

  /** The maximum bar width as a percentage of the available space. */
  private double maximumBarWidth;

  /** The minimum bar length (in Java2D units). */
  private double minimumBarLength;

  /**
   * The fallback position if a positive item label doesn't fit inside the
   * bar.
   */
  private ItemLabelPosition positiveItemLabelPositionFallback;

  /**
   * The fallback position if a negative item label doesn't fit inside the
   * bar.
   */
  private ItemLabelPosition negativeItemLabelPositionFallback;

  /** The upper clip (axis) value for the axis. */
  private double upperClip;
  // TODO: this needs to move into the renderer state

  /** The lower clip (axis) value for the axis. */
  private double lowerClip;
  // TODO: this needs to move into the renderer state

  /** The base value for the bars (defaults to 0.0). */
  private double base;

  /**
   * A flag that controls whether the base value is included in the range
   * returned by the findRangeBounds() method.
   */
  private boolean includeBaseInRange;

  /**
   * Creates a new bar renderer with default settings.
   */
  public BarRenderer() {
    super();
    this.base = 0.0;
    this.includeBaseInRange = true;
    this.itemMargin = DEFAULT_ITEM_MARGIN;
    this.drawBarOutline = true;
    this.maximumBarWidth = 1.0;
    // 100 percent, so it will not apply unless changed
    this.positiveItemLabelPositionFallback = null;
    this.negativeItemLabelPositionFallback = null;
    this.minimumBarLength = 0.0;
  }

  /**
   * Calculates the coordinates for the length of a single bar.
   *
   * @param value
   *            the value represented by the bar.
   *
   * @return The coordinates for each end of the bar (or <code>null</code> if
   *         the bar is not visible for the current axis range).
   */
  protected double[] calculateBarL0L1(final double value) {
    final double lclip = this.getLowerClip();
    final double uclip = this.getUpperClip();
    double barLow = Math.min(this.base, value);
    double barHigh = Math.max(this.base, value);
    if (barHigh < lclip) { // bar is not visible
      return null;
    }
    if (barLow > uclip) { // bar is not visible
      return null;
    }
    barLow = Math.max(barLow, lclip);
    barHigh = Math.min(barHigh, uclip);
    return new double[] { barLow, barHigh };
  }

  /**
   * Calculates the coordinate of the first "side" of a bar. This will be the
   * minimum x-coordinate for a vertical bar, and the minimum y-coordinate for
   * a horizontal bar.
   *
   * @param plot
   *            the plot.
   * @param orientation
   *            the plot orientation.
   * @param dataArea
   *            the data area.
   * @param domainAxis
   *            the domain axis.
   * @param state
   *            the renderer state (has the bar width precalculated).
   * @param row
   *            the row index.
   * @param column
   *            the column index.
   *
   * @return The coordinate.
   */
  protected double calculateBarW0(final CategoryPlot plot,
      final PlotOrientation orientation, final Rectangle dataArea,
      final CategoryAxis domainAxis,
      final CategoryItemRendererState state, final int row,
      final int column) {
    // calculate bar width...
    double space = 0.0;
    if (orientation == PlotOrientation.HORIZONTAL) {
      space = dataArea.height;
    } else {
      space = dataArea.width;
    }
    double barW0 = domainAxis.getCategoryStart(column, this
        .getColumnCount(), dataArea, plot.getDomainAxisEdge());
    final int seriesCount = this.getRowCount();
    final int categoryCount = this.getColumnCount();
    if (seriesCount > 1) {
      final double seriesGap = space * this.getItemMargin()
          / (categoryCount * (seriesCount - 1));
      final double seriesW = this.calculateSeriesWidth(space, domainAxis,
          categoryCount, seriesCount);
      barW0 = barW0 + row * (seriesW + seriesGap) + (seriesW / 2.0)
          - (state.getBarWidth() / 2.0);
    } else {
      barW0 = domainAxis.getCategoryMiddle(column, this.getColumnCount(),
          dataArea, plot.getDomainAxisEdge())
          - state.getBarWidth() / 2.0;
    }
    return barW0;
  }

  /**
   * Calculates the bar width and stores it in the renderer state.
   *
   * @param plot
   *            the plot.
   * @param dataArea
   *            the data area.
   * @param rendererIndex
   *            the renderer index.
   * @param state
   *            the renderer state.
   */
  protected void calculateBarWidth(final CategoryPlot plot,
      final Rectangle dataArea, final int rendererIndex,
      final CategoryItemRendererState state) {

    final CategoryAxis domainAxis = this.getDomainAxis(plot, rendererIndex);
    final CategoryDataset dataset = plot.getDataset(rendererIndex);
    if (dataset != null) {
      final int columns = dataset.getColumnCount();
      final int rows = dataset.getRowCount();
      double space = 0.0;
      final PlotOrientation orientation = plot.getOrientation();
      if (orientation == PlotOrientation.HORIZONTAL) {
        space = dataArea.height;
      } else if (orientation == PlotOrientation.VERTICAL) {
        space = dataArea.width;
      }
      final double maxWidth = space * this.getMaximumBarWidth();
      double categoryMargin = 0.0;
      double currentItemMargin = 0.0;
      if (columns > 1) {
        categoryMargin = domainAxis.getCategoryMargin();
      }
      if (rows > 1) {
        currentItemMargin = this.getItemMargin();
      }
      final double used = space
          * (1 - domainAxis.getLowerMargin()
              - domainAxis.getUpperMargin() - categoryMargin - currentItemMargin);
      if ((rows * columns) > 0) {
        state.setBarWidth(Math.min(used / (rows * columns), maxWidth));
      } else {
        state.setBarWidth(Math.min(used, maxWidth));
      }
    }
  }

  /**
   * Calculates the item label anchor point.
   *
   * @param anchor
   *            the anchor.
   * @param bar
   *            the bar.
   * @param orientation
   *            the plot orientation.
   *
   * @return The anchor point.
   */
  private Point calculateLabelAnchorPoint(final ItemLabelAnchor anchor,
      final Rectangle barRect, final PlotOrientation orientation) {

    final RectangleAdapter bar = new RectangleAdapter(barRect);

    Point result = null;
    final int offset = this.getItemLabelAnchorOffset();
    final int x0 = bar.getX() - offset;
    final int x1 = bar.getX();
    final int x2 = bar.getX() + offset;
    final int x3 = bar.getCenterX();
    final int x4 = bar.getMaxX() - offset;
    final int x5 = bar.getMaxX();
    final int x6 = bar.getMaxX() + offset;

    final int y0 = bar.getMaxY() + offset;
    final int y1 = bar.getMaxY();
    final int y2 = bar.getMaxY() - offset;
    final int y3 = bar.getCenterY();
    final int y4 = bar.getMinY() + offset;
    final int y5 = bar.getMinY();
    final int y6 = bar.getMinY() - offset;

    if (anchor == ItemLabelAnchor.CENTER) {
      result = new Point(x3, y3);
    } else if (anchor == ItemLabelAnchor.INSIDE1) {
      result = new Point(x4, y4);
    } else if (anchor == ItemLabelAnchor.INSIDE2) {
      result = new Point(x4, y4);
    } else if (anchor == ItemLabelAnchor.INSIDE3) {
      result = new Point(x4, y3);
    } else if (anchor == ItemLabelAnchor.INSIDE4) {
      result = new Point(x4, y2);
    } else if (anchor == ItemLabelAnchor.INSIDE5) {
      result = new Point(x4, y2);
    } else if (anchor == ItemLabelAnchor.INSIDE6) {
      result = new Point(x3, y2);
    } else if (anchor == ItemLabelAnchor.INSIDE7) {
      result = new Point(x2, y2);
    } else if (anchor == ItemLabelAnchor.INSIDE8) {
      result = new Point(x2, y2);
    } else if (anchor == ItemLabelAnchor.INSIDE9) {
      result = new Point(x2, y3);
    } else if (anchor == ItemLabelAnchor.INSIDE10) {
      result = new Point(x2, y4);
    } else if (anchor == ItemLabelAnchor.INSIDE11) {
      result = new Point(x2, y4);
    } else if (anchor == ItemLabelAnchor.INSIDE12) {
      result = new Point(x3, y4);
    } else if (anchor == ItemLabelAnchor.OUTSIDE1) {
      result = new Point(x5, y6);
    } else if (anchor == ItemLabelAnchor.OUTSIDE2) {
      result = new Point(x6, y5);
    } else if (anchor == ItemLabelAnchor.OUTSIDE3) {
      result = new Point(x6, y3);
    } else if (anchor == ItemLabelAnchor.OUTSIDE4) {
      result = new Point(x6, y1);
    } else if (anchor == ItemLabelAnchor.OUTSIDE5) {
      result = new Point(x5, y0);
    } else if (anchor == ItemLabelAnchor.OUTSIDE6) {
      result = new Point(x3, y0);
    } else if (anchor == ItemLabelAnchor.OUTSIDE7) {
      result = new Point(x1, y0);
    } else if (anchor == ItemLabelAnchor.OUTSIDE8) {
      result = new Point(x0, y1);
    } else if (anchor == ItemLabelAnchor.OUTSIDE9) {
      result = new Point(x0, y3);
    } else if (anchor == ItemLabelAnchor.OUTSIDE10) {
      result = new Point(x0, y5);
    } else if (anchor == ItemLabelAnchor.OUTSIDE11) {
      result = new Point(x1, y6);
    } else if (anchor == ItemLabelAnchor.OUTSIDE12) {
      result = new Point(x3, y6);
    }

    return result;

  }

  /**
   * Calculates the available space for each series.
   *
   * @param space
   *            the space along the entire axis (in Java2D units).
   * @param axis
   *            the category axis.
   * @param categories
   *            the number of categories.
   * @param series
   *            the number of series.
   *
   * @return The width of one series.
   */
  protected double calculateSeriesWidth(final double space,
      final CategoryAxis axis, final int categories, final int series) {
    double factor = 1.0 - this.getItemMargin() - axis.getLowerMargin()
        - axis.getUpperMargin();
    if (categories > 1) {
      factor = factor - axis.getCategoryMargin();
    }
    return (space * factor) / (categories * series);
  }

  /**
   * Draws the bar for a single (series, category) data item.
   *
   * @param gc
   *            the graphics device.
   * @param state
   *            the renderer state.
   * @param dataArea
   *            the data area.
   * @param plot
   *            the plot.
   * @param domainAxis
   *            the domain axis.
   * @param rangeAxis
   *            the range axis.
   * @param dataset
   *            the dataset.
   * @param row
   *            the row index (zero-based).
   * @param column
   *            the column index (zero-based).
   * @param pass
   *            the pass index.
   */
  public void drawItem(final GC gc, final CategoryItemRendererState state,
      final Rectangle dataArea, final CategoryPlot plot,
      final CategoryAxis domainAxis, final ValueAxis rangeAxis,
      final CategoryDataset dataset, final int row, final int column,
      final int pass) {

    // nothing is drawn for null values...
    final Number dataValue = dataset.getValue(row, column);
    if (dataValue == null) {
      return;
    }

    final double value = dataValue.doubleValue();

    final PlotOrientation orientation = plot.getOrientation();
    final double barW0 = this.calculateBarW0(plot, orientation, dataArea,
        domainAxis, state, row, column);
    final double[] barL0L1 = this.calculateBarL0L1(value);
    if (barL0L1 == null) {
      return; // the bar is not visible
    }

    final RectangleEdge edge = plot.getRangeAxisEdge();
    final double transL0 = rangeAxis.valueToJava2D(barL0L1[0], dataArea,
        edge);
    final double transL1 = rangeAxis.valueToJava2D(barL0L1[1], dataArea,
        edge);
    final double barL0 = Math.min(transL0, transL1);
    final double barLength = Math.max(Math.abs(transL1 - transL0), this
        .getMinimumBarLength());

    // draw the bar...
    Rectangle bar = null;
    if (orientation == PlotOrientation.HORIZONTAL) {
      bar = RectangleUtil.Double(barL0, barW0, barLength, state
          .getBarWidth());
    } else {
      bar = RectangleUtil.Double(barW0, barL0, state.getBarWidth(),
          barLength);
    }
    final Color itemPaint = this.getItemPaint(row, column);
    gc.setBackground(itemPaint);
    gc.fillRectangle(bar);

    // draw the outline...
    if (this.isDrawBarOutline()
        && (state.getBarWidth() > BAR_OUTLINE_WIDTH_THRESHOLD)) {
      final Stroke stroke = this.getItemOutlineStroke(row, column);
      final Color paint = this.getItemOutlinePaint(row, column);
      if ((stroke != null) && (paint != null)) {
        stroke.set(gc);
        gc.setBackground(paint);
        gc.drawRectangle(bar);
      }
    }

    final CategoryItemLabelGenerator generator = this
        .getItemLabelGenerator(row, column);
    if ((generator != null) && this.isItemLabelVisible(row, column)) {
      this.drawItemLabel(gc, dataset, row, column, plot, generator, bar,
          (value < 0.0));
    }

    // add an item entity, if this information is being collected
    final EntityCollection entities = state.getEntityCollection();
    if (entities != null) {
      final Region region = new Region();
      region.add(bar);
      this.addItemEntity(entities, dataset, row, column, region);
    }

  }

  /**
   * Draws an item label. This method is overridden so that the bar can be
   * used to calculate the label anchor point.
   *
   * @param gc
   *            the graphics device.
   * @param data
   *            the dataset.
   * @param row
   *            the row.
   * @param column
   *            the column.
   * @param plot
   *            the plot.
   * @param generator
   *            the label generator.
   * @param bar
   *            the bar.
   * @param negative
   *            a flag indicating a negative value.
   */
  protected void drawItemLabel(final GC gc, final CategoryDataset data,
      final int row, final int column, final CategoryPlot plot,
      final CategoryItemLabelGenerator generator, final Rectangle bar,
      final boolean negative) {

    final String label = generator.generateLabel(data, row, column);
    if (label == null) {
      return; // nothing to do
    }

    final Font labelFont = this.getItemLabelFont(row, column);
    gc.setFont(labelFont);
    final Color paint = this.getItemLabelPaint(row, column);
    gc.setForeground(paint);

    // find out where to place the label...
    ItemLabelPosition position = null;
    if (!negative) {
      position = this.getPositiveItemLabelPosition(row, column);
    } else {
      position = this.getNegativeItemLabelPosition(row, column);
    }

    // work out the label anchor point...
    Point anchorPoint = this.calculateLabelAnchorPoint(position
        .getItemLabelAnchor(), bar, plot.getOrientation());

    if (this.isInternalAnchor(position.getItemLabelAnchor())) {
      // TODO : correct rotation code
      // Rectangle bounds =
      // TextUtilities.calculateRotatedStringBounds(label,
      // gc, (float) anchorPoint.x, (float) anchorPoint.y,
      // position.getTextAnchor(), position.getAngle(),
      // position.getRotationAnchor());

      final RectangleAdapter bounds = new RectangleAdapter(TextUtilities
          .getTextBounds(label, gc));

      if (bounds != null) {
        if (!RectangleUtil.contains(bar, bounds.getBounds())) {
          if (!negative) {
            position = this.getPositiveItemLabelPositionFallback();
          } else {
            position = this.getNegativeItemLabelPositionFallback();
          }
          if (position != null) {
            anchorPoint = this.calculateLabelAnchorPoint(position
                .getItemLabelAnchor(), bar, plot
                .getOrientation());
          }
        }
      }

    }

    if (position != null) {
      TextUtilities.drawRotatedString(label, gc, anchorPoint.x,
          anchorPoint.y, position.getTextAnchor(), position
              .getAngle(), position.getRotationAnchor());
    }
  }

  /**
   * Tests this instance for equality with an arbitrary object.
   *
   * @param obj
   *            the object (<code>null</code> permitted).
   *
   * @return A boolean.
   */
  public boolean equals(final Object obj) {

    if (obj == this) {
      return true;
    }
    if (!(obj instanceof BarRenderer)) {
      return false;
    }
    if (!super.equals(obj)) {
      return false;
    }
    final BarRenderer that = (BarRenderer) obj;
    if (this.base != that.base) {
      return false;
    }
    if (this.itemMargin != that.itemMargin) {
      return false;
    }
    if (this.drawBarOutline != that.drawBarOutline) {
      return false;
    }
    if (this.maximumBarWidth != that.maximumBarWidth) {
      return false;
    }
    if (this.minimumBarLength != that.minimumBarLength) {
      return false;
    }
    if (!ObjectUtilities.equal(this.positiveItemLabelPositionFallback,
        that.positiveItemLabelPositionFallback)) {
      return false;
    }
    if (!ObjectUtilities.equal(this.negativeItemLabelPositionFallback,
        that.negativeItemLabelPositionFallback)) {
      return false;
    }
    return true;
  }

  /**
   * Returns the range of values the renderer requires to display all the
   * items from the specified dataset. This takes into account the range of
   * values in the dataset, plus the flag that determines whether or not the
   * base value for the bars should be included in the range.
   *
   * @param dataset
   *            the dataset (<code>null</code> permitted).
   *
   * @return The range (or <code>null</code> if the dataset is
   *         <code>null</code> or empty).
   */
  public Range findRangeBounds(final CategoryDataset dataset) {
    Range result = DatasetUtilities.findRangeBounds(dataset);
    if (result != null) {
      if (this.includeBaseInRange) {
        result = Range.expandToInclude(result, this.base);
      }
    }
    return result;
  }

  /**
   * Returns the base value for the bars.
   *
   * @return The base value for the bars.
   */
  public double getBase() {
    return this.base;
  }

  public DrawingAssets getDrawingAssets() {
    return this.getPlot().getDrawingAssets();
  }

  /**
   * Returns the flag that controls whether or not the base value for the bars
   * is included in the range calculated by
   * {@link #findRangeBounds(CategoryDataset)}.
   *
   * @return <code>true</code> if the base is included in the range, and
   *         <code>false</code> otherwise.
   *
   * @since 1.0.1
   */
  public boolean getIncludeBaseInRange() {
    return this.includeBaseInRange;
  }

  /**
   * Returns the item margin as a percentage of the available space for all
   * bars.
   *
   * @return The margin percentage (where 0.10 is ten percent).
   */
  public double getItemMargin() {
    return this.itemMargin;
  }

  /**
   * Returns a legend item for a series.
   *
   * @param datasetIndex
   *            the dataset index (zero-based).
   * @param series
   *            the series index (zero-based).
   *
   * @return The legend item.
   */
  public LegendItem getLegendItem(final int datasetIndex, final int series) {

    final CategoryPlot cp = this.getPlot();
    if (cp == null) {
      return null;
    }

    CategoryDataset dataset;
    dataset = cp.getDataset(datasetIndex);
    final String label = this.getLegendItemLabelGenerator().generateLabel(
        dataset, series);
    final String description = label;
    String toolTipText = null;
    if (this.getLegendItemToolTipGenerator() != null) {
      toolTipText = this.getLegendItemToolTipGenerator().generateLabel(
          dataset, series);
    }
    String urlText = null;
    if (this.getLegendItemURLGenerator() != null) {
      urlText = this.getLegendItemURLGenerator().generateLabel(dataset,
          series);
    }
    final Rectangle shape = new Rectangle(-4, -4, 8, 8);
    final Color paint = this.getSeriesPaint(series);
    final Color outlinePaint = this.getSeriesOutlinePaint(series);
    final Stroke outlineStroke = this.getSeriesOutlineStroke(series);

    final Color legendItemLineColor = this.getPlot().getColor(
        Plot.DEFAULT_LEGEND_ITEM_LINE_COLOR);

    return new LegendItem(label, description, toolTipText, urlText, true,
        shape, true, paint, this.isDrawBarOutline(), outlinePaint,
        outlineStroke, false, new Rectangle(0, 0, 0, 0), new Stroke(1),
        legendItemLineColor);
  }

  /**
   * Returns the lower clip value. This value is recalculated in the
   * initialise() method.
   *
   * @return The value.
   */
  public double getLowerClip() {
    // TODO: this attribute should be transferred to the renderer state.
    return this.lowerClip;
  }

  /**
   * Returns the maximum bar width, as a percentage of the available drawing
   * space.
   *
   * @return The maximum bar width.
   */
  public double getMaximumBarWidth() {
    return this.maximumBarWidth;
  }

  /**
   * Returns the minimum bar length (in Java2D units).
   *
   * @return The minimum bar length.
   */
  public double getMinimumBarLength() {
    return this.minimumBarLength;
  }

  /**
   * Returns the fallback position for negative item labels that don't fit
   * within a bar.
   *
   * @return The fallback position (<code>null</code> possible).
   */
  public ItemLabelPosition getNegativeItemLabelPositionFallback() {
    return this.negativeItemLabelPositionFallback;
  }

  /**
   * Returns the fallback position for positive item labels that don't fit
   * within a bar.
   *
   * @return The fallback position (<code>null</code> possible).
   */
  public ItemLabelPosition getPositiveItemLabelPositionFallback() {
    return this.positiveItemLabelPositionFallback;
  }

  /**
   * Returns the upper clip value. This value is recalculated in the
   * initialise() method.
   *
   * @return The value.
   */
  public double getUpperClip() {
    // TODO: this attribute should be transferred to the renderer state.
    return this.upperClip;
  }

  /**
   * Initialises the renderer and returns a state object that will be passed
   * to subsequent calls to the drawItem method. This method gets called once
   * at the start of the process of drawing a chart.
   *
   * @param g2
   *            the graphics device.
   * @param dataArea
   *            the area in which the data is to be plotted.
   * @param plot
   *            the plot.
   * @param rendererIndex
   *            the renderer index.
   * @param info
   *            collects chart rendering information for return to caller.
   *
   * @return The renderer state.
   */
  public CategoryItemRendererState initialise(final GC g2,
      final Rectangle dataArea, final CategoryPlot plot,
      final int rendererIndex, final PlotRenderingInfo info) {

    final CategoryItemRendererState state = super.initialise(g2, dataArea,
        plot, rendererIndex, info);

    // get the clipping values...
    final ValueAxis rangeAxis = this.getRangeAxis(plot, rendererIndex);
    this.lowerClip = rangeAxis.getRange().getLowerBound();
    this.upperClip = rangeAxis.getRange().getUpperBound();

    // calculate the bar width
    this.calculateBarWidth(plot, dataArea, rendererIndex, state);

    return state;

  }

  /**
   * Returns a flag that controls whether or not bar outlines are drawn.
   *
   * @return A boolean.
   */
  public boolean isDrawBarOutline() {
    return this.drawBarOutline;
  }

  /**
   * Returns <code>true</code> if the specified anchor point is inside a bar.
   *
   * @param anchor
   *            the anchor point.
   *
   * @return A boolean.
   */
  private boolean isInternalAnchor(final ItemLabelAnchor anchor) {
    return (anchor == ItemLabelAnchor.CENTER)
        || (anchor == ItemLabelAnchor.INSIDE1)
        || (anchor == ItemLabelAnchor.INSIDE2)
        || (anchor == ItemLabelAnchor.INSIDE3)
        || (anchor == ItemLabelAnchor.INSIDE4)
        || (anchor == ItemLabelAnchor.INSIDE5)
        || (anchor == ItemLabelAnchor.INSIDE6)
        || (anchor == ItemLabelAnchor.INSIDE7)
        || (anchor == ItemLabelAnchor.INSIDE8)
        || (anchor == ItemLabelAnchor.INSIDE9)
        || (anchor == ItemLabelAnchor.INSIDE10)
        || (anchor == ItemLabelAnchor.INSIDE11)
        || (anchor == ItemLabelAnchor.INSIDE12);
  }

  /**
   * Sets the base value for the bars and sends a {@link RendererChangeEvent}
   * to all registered listeners.
   *
   * @param base
   *            the new base value.
   */
  public void setBase(final double base) {
    this.base = base;
    this.notifyListeners(new RendererChangeEvent(this));
  }

  /**
   * Sets the flag that controls whether or not bar outlines are drawn and
   * sends a {@link RendererChangeEvent} to all registered listeners.
   *
   * @param draw
   *            the flag.
   */
  public void setDrawBarOutline(final boolean draw) {
    this.drawBarOutline = draw;
    this.notifyListeners(new RendererChangeEvent(this));
  }

  /**
   * Sets the flag that controls whether or not the base value for the bars is
   * included in the range calculated by
   * {@link #findRangeBounds(CategoryDataset)}. If the flag is changed, a
   * {@link RendererChangeEvent} is sent to all registered listeners.
   *
   * @param include
   *            the new value for the flag.
   *
   * @since 1.0.1
   */
  public void setIncludeBaseInRange(final boolean include) {
    if (this.includeBaseInRange != include) {
      this.includeBaseInRange = include;
      this.notifyListeners(new RendererChangeEvent(this));
    }
  }

  /**
   * Sets the item margin and sends a {@link RendererChangeEvent} to all
   * registered listeners. The value is expressed as a percentage of the
   * available width for plotting all the bars, with the resulting amount to
   * be distributed between all the bars evenly.
   *
   * @param percent
   *            the margin (where 0.10 is ten percent).
   */
  public void setItemMargin(final double percent) {
    this.itemMargin = percent;
    this.notifyListeners(new RendererChangeEvent(this));
  }

  /**
   * Sets the maximum bar width, which is specified as a percentage of the
   * available space for all bars, and sends a {@link RendererChangeEvent} to
   * all registered listeners.
   *
   * @param percent
   *            the percent (where 0.05 is five percent).
   */
  public void setMaximumBarWidth(final double percent) {
    this.maximumBarWidth = percent;
    this.notifyListeners(new RendererChangeEvent(this));
  }

  /**
   * Sets the minimum bar length and sends a {@link RendererChangeEvent} to
   * all registered listeners. The minimum bar length is specified in Java2D
   * units, and can be used to prevent bars that represent very small data
   * values from disappearing when drawn on the screen.
   *
   * @param min
   *            the minimum bar length (in Java2D units).
   */
  public void setMinimumBarLength(final double min) {
    this.minimumBarLength = min;
    this.notifyListeners(new RendererChangeEvent(this));
  }

  /**
   * Sets the fallback position for negative item labels that don't fit within
   * a bar, and sends a {@link RendererChangeEvent} to all registered
   * listeners.
   *
   * @param position
   *            the position (<code>null</code> permitted).
   */
  public void setNegativeItemLabelPositionFallback(
      final ItemLabelPosition position) {
    this.negativeItemLabelPositionFallback = position;
    this.notifyListeners(new RendererChangeEvent(this));
  }

  /**
   * Sets the fallback position for positive item labels that don't fit within
   * a bar, and sends a {@link RendererChangeEvent} to all registered
   * listeners.
   *
   * @param position
   *            the position (<code>null</code> permitted).
   */
  public void setPositiveItemLabelPositionFallback(
      final ItemLabelPosition position) {
    this.positiveItemLabelPositionFallback = position;
    this.notifyListeners(new RendererChangeEvent(this));
  }

}
TOP

Related Classes of com.positive.charts.renderer.category.BarRenderer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.