Package com.positive.charts.axis

Source Code of com.positive.charts.axis.SubCategoryAxis

package com.positive.charts.axis;

import java.io.Serializable;
import java.util.Iterator;
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.Rectangle;

import com.positive.charts.common.RectangleEdge;
import com.positive.charts.data.category.CategoryDataset;
import com.positive.charts.event.AxisChangeEvent;
import com.positive.charts.plot.CategoryPlot;
import com.positive.charts.plot.Plot;
import com.positive.charts.plot.PlotRenderingInfo;
import com.positive.charts.util.RectangleUtil;
import com.positive.charts.util.TextAnchor;
import com.positive.charts.util.TextUtilities;

/**
* A specialised category axis that can display sub-categories.
*/
public class SubCategoryAxis extends CategoryAxis implements Cloneable,
    Serializable {

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

  /** Storage for the sub-categories (these need to be set manually). */
  private final List subCategories;

  /** The font for the sub-category labels. */
  private Font subLabelFont = null;

  /**
   * Creates a new axis.
   *
   * @param label
   *            the axis label.
   */
  public SubCategoryAxis(final String label) {
    super(label);
    this.subCategories = new java.util.ArrayList();
  }

  /**
   * Adds a sub-category to the axis.
   *
   * @param subCategory
   *            the sub-category.
   */
  public void addSubCategory(final Comparable subCategory) {
    this.subCategories.add(subCategory);
  }

  /**
   * Draws the axis on a Java 2D graphics device (such as the screen or a
   * printer).
   *
   * @param g2
   *            the graphics device (<code>null</code> not permitted).
   * @param cursor
   *            the cursor location.
   * @param plotArea
   *            the area within which the axis should be drawn (
   *            <code>null</code> not permitted).
   * @param dataArea
   *            the area within which the plot is being drawn (
   *            <code>null</code> not permitted).
   * @param edge
   *            the location of the axis (<code>null</code> not permitted).
   * @param plotState
   *            collects information about the plot (<code>null</code>
   *            permitted).
   *
   * @return The axis state (never <code>null</code>).
   */
  public AxisState draw(final GC g2, final double cursor,
      final Rectangle plotArea, final Rectangle dataArea,
      final RectangleEdge edge, final PlotRenderingInfo plotState) {

    // if the axis is not visible, don't draw it...
    if (!this.isVisible()) {
      return new AxisState(cursor);
    }

    if (this.isAxisLineVisible()) {
      this.drawAxisLine(g2, (int) (cursor - 1.5), dataArea, edge);
    }

    // draw the category labels and axis label
    AxisState state = new AxisState(cursor);
    state = this.drawSubCategoryLabels(g2, plotArea, dataArea, edge, state,
        plotState);
    state = this.drawCategoryLabels(g2, plotArea, dataArea, edge, state,
        plotState);
    state = this.drawLabel(this.getLabel(), g2, plotArea, dataArea, edge,
        state);

    return state;

  }

  /**
   * Draws the category labels and returns the updated axis state.
   *
   * @param g2
   *            the graphics device (<code>null</code> not permitted).
   * @param plotArea
   *            the plot area (<code>null</code> not permitted).
   * @param dataArea
   *            the area inside the axes (<code>null</code> not permitted).
   * @param edge
   *            the axis location (<code>null</code> not permitted).
   * @param state
   *            the axis state (<code>null</code> not permitted).
   * @param plotState
   *            collects information about the plot (<code>null</code>
   *            permitted).
   *
   * @return The updated axis state (never <code>null</code>).
   */
  protected AxisState drawSubCategoryLabels(final GC g2,
      final Rectangle plotArea, final Rectangle dataArea,
      final RectangleEdge edge, final AxisState state,
      final PlotRenderingInfo plotState) {

    if (state == null) {
      throw new IllegalArgumentException("Null 'state' argument.");
    }

    g2.setFont(this.subLabelFont);
    g2.setForeground(this.getSubLabelPaint());
    final CategoryPlot plot = (CategoryPlot) this.getPlot();
    final CategoryDataset dataset = plot.getDataset();
    final int categoryCount = dataset.getColumnCount();

    final double maxdim = this.getMaxDim(g2, edge);
    for (int categoryIndex = 0; categoryIndex < categoryCount; categoryIndex++) {

      double x0 = 0.0;
      double x1 = 0.0;
      double y0 = 0.0;
      double y1 = 0.0;
      if (edge == RectangleEdge.TOP) {
        x0 = this.getCategoryStart(categoryIndex, categoryCount,
            dataArea, edge);
        x1 = this.getCategoryEnd(categoryIndex, categoryCount,
            dataArea, edge);
        y1 = state.getCursor();
        y0 = y1 - maxdim;
      } else if (edge == RectangleEdge.BOTTOM) {
        x0 = this.getCategoryStart(categoryIndex, categoryCount,
            dataArea, edge);
        x1 = this.getCategoryEnd(categoryIndex, categoryCount,
            dataArea, edge);
        y0 = state.getCursor();
        y1 = y0 + maxdim;
      } else if (edge == RectangleEdge.LEFT) {
        y0 = this.getCategoryStart(categoryIndex, categoryCount,
            dataArea, edge);
        y1 = this.getCategoryEnd(categoryIndex, categoryCount,
            dataArea, edge);
        x1 = state.getCursor();
        x0 = x1 - maxdim;
      } else if (edge == RectangleEdge.RIGHT) {
        y0 = this.getCategoryStart(categoryIndex, categoryCount,
            dataArea, edge);
        y1 = this.getCategoryEnd(categoryIndex, categoryCount,
            dataArea, edge);
        x0 = state.getCursor();
        x1 = x0 + maxdim;
      }
      final Rectangle area = RectangleUtil.Double(x0, y0, (x1 - x0),
          (y1 - y0));
      final int subCategoryCount = this.subCategories.size();
      final float width = (float) ((x1 - x0) / subCategoryCount);
      final float height = (float) ((y1 - y0) / subCategoryCount);
      float xx = 0.0f;
      float yy = 0.0f;
      for (int i = 0; i < subCategoryCount; i++) {
        if (RectangleEdge.isTopOrBottom(edge)) {
          xx = (float) (x0 + (i + 0.5) * width);
          yy = RectangleUtil.getCenterY(area);
        } else {
          xx = RectangleUtil.getCenterX(area);
          yy = (float) (y0 + (i + 0.5) * height);
        }
        final String label = this.subCategories.get(i).toString();
        TextUtilities.drawRotatedString(label, g2, xx, yy,
            TextAnchor.TOP_CENTER, 0.0, TextAnchor.TOP_CENTER);
      }
    }

    if (edge.equals(RectangleEdge.TOP)) {
      final double h = maxdim;
      state.cursorUp(h);
    } else if (edge.equals(RectangleEdge.BOTTOM)) {
      final double h = maxdim;
      state.cursorDown(h);
    } else if (edge == RectangleEdge.LEFT) {
      final double w = maxdim;
      state.cursorLeft(w);
    } else if (edge == RectangleEdge.RIGHT) {
      final double w = maxdim;
      state.cursorRight(w);
    }
    return state;
  }

  /**
   * Tests the axis 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 SubCategoryAxis) && super.equals(obj)) {
      final SubCategoryAxis axis = (SubCategoryAxis) obj;
      if (!this.subCategories.equals(axis.subCategories)) {
        return false;
      }
      if (!this.subLabelFont.equals(axis.subLabelFont)) {
        return false;
      }
      return true;
    }
    return false;
  }

  /**
   * Returns the maximum of the relevant dimension (height or width) of the
   * subcategory labels.
   *
   * @param g2
   *            the graphics device.
   * @param edge
   *            the edge.
   *
   * @return The maximum dimension.
   */
  private double getMaxDim(final GC g2, final RectangleEdge edge) {
    double result = 0.0;
    g2.setFont(this.subLabelFont);
    final Iterator iterator = this.subCategories.iterator();
    while (iterator.hasNext()) {
      final Comparable subcategory = (Comparable) iterator.next();
      final String label = subcategory.toString();
      final Rectangle bounds = TextUtilities.getTextBounds(label, g2);
      double dim = 0.0;
      if (RectangleEdge.isLeftOrRight(edge)) {
        dim = bounds.width;
      } else { // must be top or bottom
        dim = bounds.height;
      }
      result = Math.max(result, dim);
    }
    return result;
  }

  public int getSubCategoryCount() {
    return this.subCategories.size();
  }

  /**
   * Returns the font used to display the sub-category labels.
   *
   * @return The font (never <code>null</code>).
   */
  public Font getSubLabelFont() {
    return this.subLabelFont;
  }

  /**
   * Returns the paint used to display the sub-category labels.
   *
   * @return The paint (never <code>null</code>).
   */
  public Color getSubLabelPaint() {
    return this.getPlot().getDrawingAssets().getColor(Plot.COLOR_SUB_LABEL);
  }

  public void removeSubcategories() {
    this.subCategories.clear();
  }

  /**
   * Estimates the space required for the axis, given a specific drawing area.
   *
   * @param g2
   *            the graphics device (used to obtain font information).
   * @param plot
   *            the plot that the axis belongs to.
   * @param plotArea
   *            the area within which the axis should be drawn.
   * @param edge
   *            the axis location (top or bottom).
   * @param space
   *            the space already reserved.
   *
   * @return The space required to draw the axis.
   */
  public AxisSpace reserveSpace(final GC gc, final Plot plot,
      final Rectangle plotArea, final RectangleEdge edge, AxisSpace space) {

    // create a new space object if one wasn't supplied...
    if (space == null) {
      space = new AxisSpace();
    }

    // if the axis is not visible, no additional space is required...
    if (!this.isVisible()) {
      return space;
    }

    space = super.reserveSpace(gc, plot, plotArea, edge, space);
    final double maxdim = this.getMaxDim(gc, edge);
    if (RectangleEdge.isTopOrBottom(edge)) {
      space.add((int) (maxdim + 0.5), edge);
    } else if (RectangleEdge.isLeftOrRight(edge)) {
      space.add((int) (maxdim + 0.5), edge);
    }
    return space;
  }

  /**
   * Sets the font used to display the sub-category labels and sends an
   * {@link AxisChangeEvent} to all registered listeners.
   *
   * @param font
   *            the font (<code>null</code> not permitted).
   */
  public void setSubLabelFont(final Font font) {
    if (font == null) {
      throw new IllegalArgumentException("Null 'font' argument.");
    }
    this.subLabelFont = font;
    this.notifyListeners(new AxisChangeEvent(this));
  }

  /**
   * Sets the paint used to display the sub-category labels and sends an
   * {@link AxisChangeEvent} to all registered listeners.
   *
   * @param paint
   *            the paint (<code>null</code> not permitted).
   */
  public void setSubLabelPaint(final Color paint) {
    if (paint == null) {
      throw new IllegalArgumentException("Null 'paint' argument.");
    }

    this.getPlot().getDrawingAssets().setColor(Plot.COLOR_SUB_LABEL, paint);
    this.notifyListeners(new AxisChangeEvent(this));
  }
}
TOP

Related Classes of com.positive.charts.axis.SubCategoryAxis

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.