Package com.positive.charts.renderer.xy

Source Code of com.positive.charts.renderer.xy.XYBarRenderer$XYBarRendererState

package com.positive.charts.renderer.xy;

import java.util.List;

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 com.positive.charts.axis.ValueAxis;
import com.positive.charts.common.RectangleEdge;
import com.positive.charts.data.Range;
import com.positive.charts.data.util.DatasetUtilities;
import com.positive.charts.data.xy.IntervalXYDataset;
import com.positive.charts.data.xy.XYDataset;
import com.positive.charts.event.RendererChangeEvent;
import com.positive.charts.labels.ItemLabelAnchor;
import com.positive.charts.labels.ItemLabelPosition;
import com.positive.charts.labels.XYItemLabelGenerator;
import com.positive.charts.plot.CrosshairState;
import com.positive.charts.plot.PlotOrientation;
import com.positive.charts.plot.PlotRenderingInfo;
import com.positive.charts.plot.xy.XYPlot;
import com.positive.charts.util.RectangleUtil;
import com.positive.charts.util.TextUtilities;

/**
* A renderer that draws bars on an {@link XYPlot} (requires an
* {@link IntervalXYDataset}).
*/
public class XYBarRenderer extends AbstractXYItemRenderer implements
    XYItemRenderer {

  /**
   * The state class used by this renderer.
   */
  protected class XYBarRendererState extends XYItemRendererState {

    /** Base for bars against the range axis, in Java 2D space. */
    private double g2Base;

    /**
     * Creates a new state object.
     *
     * @param info
     *            the plot rendering info.
     */
    public XYBarRendererState(final PlotRenderingInfo info) {
      super(info);
    }

    /**
     * Returns the base (range) value in Java 2D space.
     *
     * @return The base value.
     */
    public double getG2Base() {
      return this.g2Base;
    }

    /**
     * Sets the range axis base in Java2D space.
     *
     * @param value
     *            the value.
     */
    public void setG2Base(final double value) {
      this.g2Base = value;
    }
  }

  /** The default base value for the bars. */
  private double base;

  /**
   * A flag that controls whether the bars use the y-interval supplied by the
   * dataset.
   */
  private boolean useYInterval;

  /** Percentage margin (to reduce the width of bars). */
  private double margin;

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

  // /**
  // * An optional class used to transform gradient paint objects to fit each
  // * bar.
  // */
  // private GradientPaintTransformer gradientPaintTransformer;

  // /**
  // * The shape used to represent a bar in each legend item (this should
  // never
  // * be <code>null</code>).
  // */
  // private transient Shape legendBar;

  /**
   * 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 default constructor.
   */
  public XYBarRenderer() {
    this(0.0);
  }

  /**
   * Constructs a new renderer.
   *
   * @param margin
   *            the percentage amount to trim from the width of each bar.
   */
  public XYBarRenderer(final double margin) {
    super();
    this.margin = margin;
    this.base = 0.0;
    this.useYInterval = false;
    // this.gradientPaintTransformer = new
    // StandardGradientPaintTransformer();
    this.drawBarOutline = true;
    // this.legendBar = RectUtils.doubleRect(-3.0, -5.0, 6.0, 10.0);
  }

  /**
   * 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 bar, final PlotOrientation orientation) {

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

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

    if (anchor == ItemLabelAnchor.CENTER) {
      result = new Point(x3, y3);
    } else if (anchor == ItemLabelAnchor.INSIDE3) {
      result = new Point(x4, y3);
    } else if (anchor == ItemLabelAnchor.INSIDE6) {
      result = new Point(x3, y2);
    } else if (anchor == ItemLabelAnchor.INSIDE9) {
      result = new Point(x2, y3);
    } else if (anchor == ItemLabelAnchor.INSIDE12) {
      result = new Point(x3, y4);
    } else if (anchor == ItemLabelAnchor.OUTSIDE3) {
      result = new Point(x6, y3);
    } else if (anchor == ItemLabelAnchor.OUTSIDE6) {
      result = new Point(x3, y0);
    } else if (anchor == ItemLabelAnchor.OUTSIDE9) {
      result = new Point(x0, y3);
    } else if (anchor == ItemLabelAnchor.OUTSIDE12) {
      result = new Point(x3, y6);
    }

    return result;

  }

  /**
   * Draws the visual representation of a single data item.
   *
   * @param gc
   *            the graphics device.
   * @param state
   *            the renderer state.
   * @param dataArea
   *            the area within which the plot is being drawn.
   * @param info
   *            collects information about the drawing.
   * @param plot
   *            the plot (can be used to obtain standard color information
   *            etc).
   * @param domainAxis
   *            the domain axis.
   * @param rangeAxis
   *            the range axis.
   * @param dataset
   *            the dataset.
   * @param series
   *            the series index (zero-based).
   * @param item
   *            the item index (zero-based).
   * @param pass
   *            the pass index.
   */
  public void drawItem(final GC gc, final XYItemRendererState state,
      final Rectangle dataArea, final PlotRenderingInfo info,
      final XYPlot plot, final ValueAxis domainAxis,
      final ValueAxis rangeAxis, final XYDataset dataset,
      final int series, final int item, final CrosshairState cstate,
      final int pass) {

    if (!this.getItemVisible(series, item)) {
      return;
    }
    final IntervalXYDataset intervalDataset = (IntervalXYDataset) dataset;

    double value0;
    double value1;
    if (this.useYInterval) {
      value0 = intervalDataset.getStartYValue(series, item);
      value1 = intervalDataset.getEndYValue(series, item);
    } else {
      value0 = this.base;
      value1 = intervalDataset.getYValue(series, item);
    }
    if (Double.isNaN(value0) || Double.isNaN(value1)) {
      return;
    }

    final double translatedValue0 = rangeAxis.valueToJava2D(value0,
        dataArea, plot.getRangeAxisEdge());
    final double translatedValue1 = rangeAxis.valueToJava2D(value1,
        dataArea, plot.getRangeAxisEdge());

    final RectangleEdge location = plot.getDomainAxisEdge();
    final double startX = intervalDataset.getStartXValue(series, item);
    if (Double.isNaN(startX)) {
      return;
    }
    double translatedStartX = domainAxis.valueToJava2D(startX, dataArea,
        location);

    final double endX = intervalDataset.getEndXValue(series, item);
    if (Double.isNaN(endX)) {
      return;
    }
    final double translatedEndX = domainAxis.valueToJava2D(endX, dataArea,
        location);

    double translatedWidth = Math.max(1, Math.abs(translatedEndX
        - translatedStartX));
    final double translatedHeight = Math.abs(translatedValue1
        - translatedValue0);

    if (this.getMargin() > 0.0) {
      final double cut = translatedWidth * this.getMargin();
      translatedWidth = translatedWidth - cut;
      translatedStartX = translatedStartX + cut / 2;
    }

    Rectangle bar = null;
    final PlotOrientation orientation = plot.getOrientation();
    if (orientation == PlotOrientation.HORIZONTAL) {
      bar = new Rectangle((int) Math.min(translatedValue0,
          translatedValue1), (int) Math.min(translatedStartX,
          translatedEndX), (int) translatedHeight,
          (int) translatedWidth);
    } else if (orientation == PlotOrientation.VERTICAL) {
      bar = new Rectangle((int) Math
          .min(translatedStartX, translatedEndX), (int) Math.min(
          translatedValue0, translatedValue1), (int) translatedWidth,
          (int) translatedHeight);
    }

    final Color itemPaint = this.getItemColor(series, item);

    gc.setBackground(itemPaint);
    gc.fillRectangle(bar);
    // if (isDrawBarOutline() && Math.abs(translatedEndX - translatedStartX)
    // > 3) {
    // Stroke stroke = getItemOutlineStroke(series, item);
    // Color paint = getItemOutlinePaint(series, item);
    // if (stroke != null && paint != null) {
    // gc.setStroke(stroke);
    // gc.setPaint(paint);
    // gc.draw(bar);
    // }
    // }

    // TODO Draw item labels
    // if (isItemLabelVisible(series, item)) {
    // XYItemLabelGenerator generator = getItemLabelGenerator(series, item);
    // drawItemLabel(gc, dataset, series, item, plot, generator, bar, value1
    // < 0.0);
    // }

    // update the crosshair point
    // double x1 = (startX + endX) / 2.0;
    // double y1 = dataset.getYValue(series, item);
    // double transX1 = domainAxis.valueToJava2D(x1, dataArea, location);
    // double transY1 = rangeAxis.valueToJava2D(y1, dataArea,
    // plot.getRangeAxisEdge());
    // updateCrosshairValues(crosshairState, x1, y1, transX1, transY1,
    // plot.getOrientation());

  }

  /**
   * Draws an item label. This method is overridden so that the bar can be
   * used to calculate the label anchor point.
   *
   * @param g2
   *            the graphics device.
   * @param dataset
   *            the dataset.
   * @param series
   *            the series index.
   * @param item
   *            the item index.
   * @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 g2, final XYDataset dataset,
      final int series, final int item, final XYPlot plot,
      final XYItemLabelGenerator generator, final Rectangle bar,
      final boolean negative) {

    final String label = generator.generateLabel(dataset, series, item);
    if (label == null) {
      return; // nothing to do
    }

    final Font labelFont = this.getItemLabelFont(series, item);
    g2.setFont(labelFont);
    // Color paint = getItemLabelColor(series, item);
    // g2.setPaint(paint);

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

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

    // if (isInternalAnchor(position.getItemLabelAnchor())) {
    // Shape bounds = TextUtilities.calculateRotatedStringBounds(label, g2,
    // (float) anchorPoint.getX(), (float) anchorPoint.getY(), position
    // .getTextAnchor(), position.getAngle(), position.getRotationAnchor());
    //
    // if (bounds != null) {
    // if (!bar.contains(bounds.getBounds2D())) {
    // if (!negative) {
    // position = getPositiveItemLabelPositionFallback();
    // } else {
    // position = getNegativeItemLabelPositionFallback();
    // }
    // if (position != null) {
    // anchorPoint =
    // calculateLabelAnchorPoint(position.getItemLabelAnchor(), bar,
    // plot.getOrientation());
    // }
    // }
    // }
    // }

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

  public void drawSeriesItems(final GC gc, final Rectangle dataArea,
      final PlotRenderingInfo info, final XYPlot plot,
      final ValueAxis domainAxis, final ValueAxis rangeAxis,
      final XYDataset dataset, final int seriesIndex, final List series) {
    // TODO Auto-generated method stub

  }

  /**
   * Returns the lower and upper bounds (range) of the x-values in the
   * specified dataset. Since this renderer uses the x-interval in the
   * dataset, this is taken into account for the range.
   *
   * @param dataset
   *            the dataset (<code>null</code> permitted).
   *
   * @return The range (<code>null</code> if the dataset is <code>null</code>
   *         or empty).
   */
  public Range findDomainBounds(final XYDataset dataset) {
    if (dataset != null) {
      return DatasetUtilities.findDomainBounds(dataset, true);
    } else {
      return null;
    }
  }

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

  /**
   * Returns the margin which is a percentage amount by which the bars are
   * trimmed.
   *
   * @return The margin.
   */
  public double getMargin() {
    return this.margin;
  }

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

  // /**
  // * Returns the gradient paint transformer (an object used to transform
  // * gradient paint objects to fit each bar.
  // *
  // * @return A transformer (<code>null</code> possible).
  // */
  // public GradientPaintTransformer getGradientPaintTransformer() {
  // return this.gradientPaintTransformer;
  // }

  // /**
  // * Sets the gradient paint transformer and sends a
  // * {@link RendererChangeEvent} to all registered listeners.
  // *
  // * @param transformer
  // * the transformer (<code>null</code> permitted).
  // */
  // public void setGradientPaintTransformer(GradientPaintTransformer
  // transformer) {
  // this.gradientPaintTransformer = transformer;
  // notifyListeners(new RendererChangeEvent(this));
  // }

  // /**
  // * Returns the shape used to represent bars in each legend item.
  // *
  // * @return The shape used to represent bars in each legend item (never
  // * <code>null</code>).
  // */
  // public Shape getLegendBar() {
  // return this.legendBar;
  // }

  // /**
  // * Sets the shape used to represent bars in each legend item.
  // *
  // * @param bar
  // * the bar shape (<code>null</code> not permitted).
  // */
  // public void setLegendBar(Shape bar) {
  // if (bar == null) {
  // throw new IllegalArgumentException("Null 'bar' argument.");
  // }
  // this.legendBar = bar;
  // notifyListeners(new RendererChangeEvent(this));
  // }

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

  /**
   * Returns a flag that determines whether the y-interval from the dataset is
   * used to calculate the length of each bar.
   *
   * @return A boolean.
   */
  public boolean getUseYInterval() {
    return this.useYInterval;
  }

  /**
   * Initialises the renderer and returns a state object that should be passed
   * to all subsequent calls to the drawItem() method. Here we calculate the
   * Java2D y-coordinate for zero, since all the bars have their bases fixed
   * at zero.
   *
   * @param g2
   *            the graphics device.
   * @param dataArea
   *            the area inside the axes.
   * @param plot
   *            the plot.
   * @param dataset
   *            the data.
   * @param info
   *            an optional info collection object to return data back to the
   *            caller.
   *
   * @return A state object.
   */
  public XYItemRendererState initialise(final GC g2,
      final Rectangle dataArea, final XYPlot plot,
      final XYDataset dataset, final PlotRenderingInfo info) {

    final XYBarRendererState state = new XYBarRendererState(info);
    final ValueAxis rangeAxis = plot.getRangeAxisForDataset(plot
        .indexOf(dataset));
    state.setG2Base(rangeAxis.valueToJava2D(this.base, dataArea, plot
        .getRangeAxisEdge()));
    return state;

  }

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

  /**
   * Sets the base value for the bars and sends a {@link RendererChangeEvent}
   * to all registered listeners. The base value is not used if the dataset's
   * y-interval is being used to determine the bar length.
   *
   * @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 percentage amount by which the bars are trimmed and sends a
   * {@link RendererChangeEvent} to all registered listeners.
   *
   * @param margin
   *            the new margin.
   */
  public void setMargin(final double margin) {
    this.margin = margin;
    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).
   *
   * @since 1.0.2
   */
  public void setNegativeItemLabelPositionFallback(
      final ItemLabelPosition position) {
    this.negativeItemLabelPositionFallback = position;
    this.notifyListeners(new RendererChangeEvent(this));
  }

  // /**
  // * Returns <code>true</code> if the specified anchor point is inside a
  // * bar.
  // *
  // * @param anchor
  // * the anchor point.
  // *
  // * @return A boolean.
  // */
  // private boolean isInternalAnchor(ItemLabelAnchor anchor) {
  // return anchor.isInside();
  // }

  /**
   * 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).
   *
   * @since 1.0.2
   */
  public void setPositiveItemLabelPositionFallback(
      final ItemLabelPosition position) {
    this.positiveItemLabelPositionFallback = position;
    this.notifyListeners(new RendererChangeEvent(this));
  }

  /**
   * Sets the flag that determines whether the y-interval from the dataset is
   * used to calculate the length of each bar, and sends a
   * {@link RendererChangeEvent} to all registered listeners..
   *
   * @param use
   *            the flag.
   */
  public void setUseYInterval(final boolean use) {
    this.useYInterval = use;
    this.notifyListeners(new RendererChangeEvent(this));
  }

}
TOP

Related Classes of com.positive.charts.renderer.xy.XYBarRenderer$XYBarRendererState

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.