Package com.positive.charts.renderer.category

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

/* ===========================================================
* 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.]
*
* -----------------------
* StackedBarRenderer.java
* -----------------------
* (C) Copyright 2000-2006, by Object Refinery Limited and Contributors.
*
* Original Author:  David Gilbert (for Object Refinery Limited);
* Contributor(s):   Richard Atkinson;
*                   Thierry Saura;
*                   Christian W. Zuckschwerdt;
*
* $Id: StackedBarRenderer.java,v 1.1 2007/08/24 12:43:41 slapukhov Exp $
*
* Changes
* -------
* 19-Oct-2001 : Version 1 (DG);
* 22-Oct-2001 : Renamed DataSource.java --> Dataset.java etc. (DG);
* 23-Oct-2001 : Changed intro and trail gaps on bar plots to use percentage of
*               available space rather than a fixed number of units (DG);
* 15-Nov-2001 : Modified to allow for null data values (DG);
* 22-Nov-2001 : Modified to allow for negative data values (DG);
* 13-Dec-2001 : Added tooltips (DG);
* 16-Jan-2002 : Fixed bug for single category datasets (DG);
* 15-Feb-2002 : Added isStacked() method (DG);
* 14-Mar-2002 : Modified to implement the CategoryItemRenderer interface (DG);
* 24-May-2002 : Incorporated tooltips into chart entities (DG);
* 11-Jun-2002 : Added check for (permitted) null info object, bug and fix
*               reported by David Basten.  Also updated Javadocs. (DG);
* 25-Jun-2002 : Removed redundant import (DG);
* 26-Jun-2002 : Small change to entity (DG);
* 05-Aug-2002 : Small modification to drawCategoryItem method to support URLs
*               for HTML image maps (RA);
* 08-Aug-2002 : Added optional linking lines, contributed by Thierry
*               Saura (DG);
* 26-Sep-2002 : Fixed errors reported by Checkstyle (DG);
* 24-Oct-2002 : Amendments for changes in CategoryDataset interface and
*               CategoryToolTipGenerator interface (DG);
* 05-Nov-2002 : Replaced references to CategoryDataset with TableDataset (DG);
* 26-Nov-2002 : Replaced isStacked() method with getRangeType() method (DG);
* 17-Jan-2003 : Moved plot classes to a separate package (DG);
* 25-Mar-2003 : Implemented Serializable (DG);
* 12-May-2003 : Merged horizontal and vertical stacked bar renderers (DG);
* 30-Jul-2003 : Modified entity constructor (CZ);
* 08-Sep-2003 : Fixed bug 799668 (isBarOutlineDrawn() ignored) (DG);
* 16-Sep-2003 : Changed ChartRenderingInfo --> PlotRenderingInfo (DG);
* 21-Oct-2003 : Moved bar width into renderer state (DG);
* 26-Nov-2003 : Added code to respect maxBarWidth attribute (DG);
* 05-Nov-2004 : Changed to a two-pass renderer so that item labels are not
*               overwritten by other bars (DG);
* 07-Jan-2005 : Renamed getRangeExtent() --> findRangeBounds() (DG);
* 29-Mar-2005 : Modified drawItem() method so that a zero value is handled
*               within the code for positive rather than negative values (DG);
* 20-Apr-2005 : Renamed CategoryLabelGenerator
*               --> CategoryItemLabelGenerator (DG);
* 17-May-2005 : Added flag to allow rendering values as percentages - inspired
*               by patch 1200886 submitted by John Xiao (DG);
* 09-Jun-2005 : Added accessor methods for the renderAsPercentages flag,
*               provided equals() method, and use addItemEntity from
*               superclass (DG);
* 09-Jun-2005 : Added support for GradientPaint - see bug report 1215670 (DG);
* 22-Sep-2005 : Renamed getMaxBarWidth() --> getMaximumBarWidth() (DG);
* 29-Sep-2005 : Use outline stroke in drawItem method - see bug report
*               1304139 (DG);
* ------------- JFREECHART 1.0.x ---------------------------------------------
* 11-Oct-2006 : Source reformatting (DG);
*
*/

package com.positive.charts.renderer.category;

import java.io.Serializable;

import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.GC;
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.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.plot.CategoryPlot;
import com.positive.charts.plot.PlotOrientation;
import com.positive.charts.util.DataUtilities;
import com.positive.charts.util.RectangleUtil;
import com.positive.charts.util.TextAnchor;

/**
* A stacked bar renderer for use with the
* {@link org.jfree.chart.plot.CategoryPlot} class.
*/
public class StackedBarRenderer extends BarRenderer implements Cloneable,
    PublicCloneable, Serializable {

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

  /** A flag that controls whether the bars display values or percentages. */
  private boolean renderAsPercentages;

  /**
   * Creates a new renderer. By default, the renderer has no tool tip
   * generator and no URL generator. These defaults have been chosen to
   * minimise the processing required to generate a default chart. If you
   * require tool tips or URLs, then you can easily add the required
   * generators.
   */
  public StackedBarRenderer() {
    this(false);
  }

  /**
   * Creates a new renderer.
   *
   * @param renderAsPercentages
   *            a flag that controls whether the data values are rendered as
   *            percentages.
   */
  public StackedBarRenderer(final boolean renderAsPercentages) {
    super();
    this.renderAsPercentages = renderAsPercentages;

    // set the default item label positions, which will only be used if
    // the user requests visible item labels...
    final ItemLabelPosition p = new ItemLabelPosition(
        ItemLabelAnchor.CENTER, TextAnchor.CENTER);
    this.setBasePositiveItemLabelPosition(p);
    this.setBaseNegativeItemLabelPosition(p);
    this.setPositiveItemLabelPositionFallback(null);
    this.setNegativeItemLabelPositionFallback(null);
  }

  /**
   * 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) {

    // calculate the bar width
    final CategoryAxis xAxis = plot.getDomainAxisForDataset(rendererIndex);
    final CategoryDataset data = plot.getDataset(rendererIndex);
    if (data != null) {
      final PlotOrientation orientation = plot.getOrientation();
      double space = 0.0;
      if (orientation == PlotOrientation.HORIZONTAL) {
        space = dataArea.height;
      } else if (orientation == PlotOrientation.VERTICAL) {
        space = dataArea.width;
      }
      final double maxWidth = space * this.getMaximumBarWidth();
      final int columns = data.getColumnCount();
      double categoryMargin = 0.0;
      if (columns > 1) {
        categoryMargin = xAxis.getCategoryMargin();
      }

      final double used = space
          * (1 - xAxis.getLowerMargin() - xAxis.getUpperMargin() - categoryMargin);
      if (columns > 0) {
        state.setBarWidth(Math.min(used / columns, maxWidth));
      } else {
        state.setBarWidth(Math.min(used, maxWidth));
      }
    }

  }

  /**
   * Draws a stacked bar for a specific item.
   *
   * @param g2
   *            the graphics device.
   * @param state
   *            the renderer state.
   * @param dataArea
   *            the plot area.
   * @param plot
   *            the plot.
   * @param domainAxis
   *            the domain (category) axis.
   * @param rangeAxis
   *            the range (value) axis.
   * @param dataset
   *            the data.
   * @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;
    }

    double value = dataValue.doubleValue();
    double total = 0.0; // only needed if calculating percentages
    if (this.renderAsPercentages) {
      total = DataUtilities.calculateColumnTotal(dataset, column);
      value = value / total;
    }

    final PlotOrientation orientation = plot.getOrientation();
    final double barW0 = domainAxis.getCategoryMiddle(column, this
        .getColumnCount(), dataArea, plot.getDomainAxisEdge())
        - state.getBarWidth() / 2.0;

    double positiveBase = this.getBase();
    double negativeBase = positiveBase;

    for (int i = 0; i < row; i++) {
      final Number v = dataset.getValue(i, column);
      if (v != null) {
        double d = v.doubleValue();
        if (this.renderAsPercentages) {
          d = d / total;
        }
        if (d > 0) {
          positiveBase = positiveBase + d;
        } else {
          negativeBase = negativeBase + d;
        }
      }
    }

    double translatedBase;
    double translatedValue;
    final RectangleEdge location = plot.getRangeAxisEdge();
    if (value >= 0.0) {
      translatedBase = rangeAxis.valueToJava2D(positiveBase, dataArea,
          location);
      translatedValue = rangeAxis.valueToJava2D(positiveBase + value,
          dataArea, location);
    } else {
      translatedBase = rangeAxis.valueToJava2D(negativeBase, dataArea,
          location);
      translatedValue = rangeAxis.valueToJava2D(negativeBase + value,
          dataArea, location);
    }
    final double barL0 = Math.min(translatedBase, translatedValue);
    final double barLength = Math.max(Math.abs(translatedValue
        - translatedBase), this.getMinimumBarLength());

    Rectangle bar = null;
    if (orientation == PlotOrientation.HORIZONTAL) {
      bar = RectangleUtil.Double(barL0, barW0, barLength, state
          .getBarWidth());
    } else {
      bar = RectangleUtil.Double(barW0, barL0, state.getBarWidth(),
          barLength);
    }
    if (pass == 0) {
      final Color itemPaint = this.getItemPaint(row, column);
      gc.setForeground(itemPaint);
      gc.fillRectangle(bar);
      if (this.isDrawBarOutline()
          && (state.getBarWidth() > BAR_OUTLINE_WIDTH_THRESHOLD)) {
        this.getItemOutlineStroke(row, column).set(gc);
        gc.setForeground(this.getItemOutlinePaint(row, column));
        gc.drawRectangle(bar);
      }

      // 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);
      }
    } else if (pass == 1) {
      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));
      }
    }
  }

  /**
   * Tests this renderer 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 StackedBarRenderer)) {
      return false;
    }
    if (!super.equals(obj)) {
      return false;
    }
    final StackedBarRenderer that = (StackedBarRenderer) obj;
    if (this.renderAsPercentages != that.renderAsPercentages) {
      return false;
    }
    return true;
  }

  /**
   * Returns the range of values the renderer requires to display all the
   * items from the specified dataset.
   *
   * @param dataset
   *            the dataset (<code>null</code> permitted).
   *
   * @return The range (or <code>null</code> if the dataset is empty).
   */
  public Range findRangeBounds(final CategoryDataset dataset) {
    if (this.renderAsPercentages) {
      return new Range(0.0, 1.0);
    } else {
      return DatasetUtilities.findStackedRangeBounds(dataset, this
          .getBase());
    }
  }

  /**
   * Returns the number of passes (<code>2</code>) required by this renderer.
   * The first pass is used to draw the bars, the second pass is used to draw
   * the item labels (if visible).
   *
   * @return The number of passes required by the renderer.
   */
  public int getPassCount() {
    return 2;
  }

  /**
   * Returns <code>true</code> if the renderer displays each item value as a
   * percentage (so that the stacked bars add to 100%), and <code>false</code>
   * otherwise.
   *
   * @return A boolean.
   */
  public boolean getRenderAsPercentages() {
    return this.renderAsPercentages;
  }

  /**
   * Sets the flag that controls whether the renderer displays each item value
   * as a percentage (so that the stacked bars add to 100%), and sends a
   * {@link RendererChangeEvent} to all registered listeners.
   *
   * @param asPercentages
   *            the flag.
   */
  public void setRenderAsPercentages(final boolean asPercentages) {
    this.renderAsPercentages = asPercentages;
    this.notifyListeners(new RendererChangeEvent(this));
  }

}
TOP

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

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.