Package com.positive.charts.axis

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

package com.positive.charts.axis;

import java.awt.Paint;

import org.eclipse.core.runtime.ListenerList;
import org.eclipse.swt.SWT;
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.widgets.Display;

import com.positive.charts.block.RectangleInsets;
import com.positive.charts.common.RectangleEdge;
import com.positive.charts.event.AxisChangeEvent;
import com.positive.charts.event.AxisChangeListener;
import com.positive.charts.plot.Plot;
import com.positive.charts.util.RectangleUtil;
import com.positive.charts.util.Stroke;
import com.positive.charts.util.TextAnchor;
import com.positive.charts.util.TextUtilities;
import com.positive.colorchecker.StaticColorChecker;

/**
* The base class for all axes in JFreeChart. Subclasses are divided into those
* that display values ({@link ValueAxis}) and those that display categories (
* {@link CategoryAxis}).
*/
public abstract class BaseAxis implements Axis {

  /** The default axis visibility. */
  public static final boolean DEFAULT_AXIS_VISIBLE = true;

  /** The default tick labels visibility. */
  public static final boolean DEFAULT_TICK_LABELS_VISIBLE = true;

  /** The default tick marks visible. */
  public static final boolean DEFAULT_TICK_MARKS_VISIBLE = true;

  /** The default tick mark inside length. */
  public static final float DEFAULT_TICK_MARK_INSIDE_LENGTH = 0.0f;

  /** The default tick mark outside length. */
  public static final float DEFAULT_TICK_MARK_OUTSIDE_LENGTH = 2.0f;

  /** A flag indicating whether or not the axis is visible. */
  private boolean visible;

  /** The label for the axis. */
  private String label;

  /** The font for displaying the axis label. */
  private Font labelFont;

  /** The insets for the axis label. */
  private RectangleInsets labelInsets = new RectangleInsets(2, 2, 2, 2);

  /** The label angle. */
  private double labelAngle;

  /** A flag that controls whether or not the axis line is visible. */
  private boolean axisLineVisible;

  /**
   * A flag that indicates whether or not tick labels are visible for the
   * axis.
   */
  private boolean tickLabelsVisible;

  /** The font used to display the tick labels. */
  private Font tickLabelFont;

  /** The blank space around each tick label. */
  private RectangleInsets tickLabelInsets = new RectangleInsets(1, 4, 1, 4);

  /**
   * A flag that indicates whether or not tick marks are visible for the axis.
   */
  private boolean tickMarksVisible;

  /** The length of the tick mark inside the data area (zero permitted). */
  private float tickMarkInsideLength;

  /** The length of the tick mark outside the data area (zero permitted). */
  private float tickMarkOutsideLength;

  /** The fixed (horizontal or vertical) dimension for the axis. */
  private int fixedDimension;

  /**
   * A reference back to the plot that the axis is assigned to (can be
   * <code>null</code>).
   */
  private transient Plot plot;

  /** Storage for registered listeners. */
  private transient final ListenerList listenerList;

  /**
   * Constructs an axis, using default values where necessary.
   *
   * @param label
   *            the axis label (<code>null</code> permitted).
   */
  protected BaseAxis(final String label) {
    this.label = label;
    this.visible = DEFAULT_AXIS_VISIBLE;
    this.labelAngle = 0.0;

    this.axisLineVisible = true;

    this.tickLabelsVisible = DEFAULT_TICK_LABELS_VISIBLE;

    this.tickMarksVisible = DEFAULT_TICK_MARKS_VISIBLE;
    this.tickMarkInsideLength = DEFAULT_TICK_MARK_INSIDE_LENGTH;
    this.tickMarkOutsideLength = DEFAULT_TICK_MARK_OUTSIDE_LENGTH;

    this.plot = null;

    this.listenerList = new ListenerList();
  }

  /**
   * Registers an object for notification of changes to the axis.
   *
   * @param listener
   *            the object that is being registered.
   *
   * @see #removeChangeListener(AxisChangeListener)
   */
  public void addChangeListener(final AxisChangeListener listener) {
    this.listenerList.add(listener);
  }

  /**
   * Configures the axis to work with the current plot. Override this method
   * to perform any special processing (such as auto-rescaling).
   */
  public abstract void configure();

  /**
   * Draws an axis line at the current cursor position and edge.
   *
   * @param gc
   *            the graphics device.
   * @param cursor
   *            the cursor position.
   * @param dataArea
   *            the data area.
   * @param edge
   *            the edge.
   */
  protected void drawAxisLine(final GC gc, final int cursor,
      final Rectangle dataArea, final RectangleEdge edge) {
    if (edge == RectangleEdge.TOP) {
      gc.drawLine(dataArea.x, cursor, RectangleUtil.getMaxX(dataArea),
          cursor);
    } else if (edge == RectangleEdge.BOTTOM) {
      gc.drawLine(dataArea.x, cursor, RectangleUtil.getMaxX(dataArea),
          cursor);
    } else if (edge == RectangleEdge.LEFT) {
      gc.drawLine(cursor, dataArea.y, cursor, RectangleUtil
          .getMaxY(dataArea)); // dataArea.x was replaced with
      // dataArea.y - it was a BUG
    } else if (edge == RectangleEdge.RIGHT) {
      gc.drawLine(cursor, dataArea.y, cursor, RectangleUtil
          .getMaxY(dataArea)); // dataArea.x was replaced with
      // dataArea.y - it was a BUG
    }
  }

  /**
   * Draws the axis label.
   *
   * @param label
   *            the label text.
   * @param g2
   *            the graphics device.
   * @param plotArea
   *            the plot area.
   * @param dataArea
   *            the area inside the axes.
   * @param edge
   *            the location of the axis.
   * @param state
   *            the axis state (<code>null</code> not permitted).
   *
   * @return Information about the axis.
   */
  protected AxisState drawLabel(final String label, final GC g2,
      final Rectangle plotArea, final Rectangle dataArea,
      final RectangleEdge edge, final AxisState state) {

    // it is unlikely that 'state' will be null, but check anyway...
    if (state == null) {
      throw new IllegalArgumentException("Null 'state' argument.");
    }

    if ((label == null) || (label.length() == 0)) {
      return state;
    }

    // Font font = getLabelFont();
    // g2.setFont(font);
    // g2.setPaint(getLabelPaint());
    final RectangleInsets insets = this.getLabelInsets();
    final Rectangle labelBounds = TextUtilities.getTextBounds(label, g2);

    double labelx, labely;

    if (edge == RectangleEdge.TOP) {
      labelx = RectangleUtil.getCenterX(dataArea);
      labely = state.getCursor() - insets.getBottom()
          - labelBounds.height / 2.0;
      TextUtilities.drawRotatedString(label, g2, (float) labelx,
          (float) labely, TextAnchor.CENTER, this.getLabelAngle(),
          TextAnchor.CENTER);
      state.cursorUp(insets.getTop() + labelBounds.height
          + insets.getBottom());
    } else if (edge == RectangleEdge.BOTTOM) {
      labelx = RectangleUtil.getCenterX(dataArea);
      labely = state.getCursor() + insets.getTop() + labelBounds.height
          / 2.0;
      TextUtilities.drawRotatedString(label, g2, (float) labelx,
          (float) labely, TextAnchor.CENTER, this.getLabelAngle(),
          TextAnchor.CENTER);
      state.cursorDown(insets.getTop() + labelBounds.height
          + insets.getBottom());
    } else if (edge == RectangleEdge.LEFT) {
      this.swapWidthAndHeight(labelBounds);

      labelx = state.getCursor() - insets.getRight() - labelBounds.width
          / 2.0;
      labely = RectangleUtil.getCenterY(dataArea);
      TextUtilities.drawRotatedString(label, g2, (float) labelx,
          (float) labely, TextAnchor.CENTER, this.getLabelAngle()
              - Math.PI / 2.0, TextAnchor.BOTTOM_CENTER);
      state.cursorLeft(insets.getLeft() + labelBounds.width
          + insets.getRight());
    } else if (edge == RectangleEdge.RIGHT) {
      this.swapWidthAndHeight(labelBounds);

      labelx = state.getCursor() + insets.getLeft() + labelBounds.width
          / 2.0;
      labely = RectangleUtil.getCenterY(dataArea);
      TextUtilities.drawRotatedString(label, g2, (float) labelx,
          (float) labely, TextAnchor.CENTER, this.getLabelAngle()
              + Math.PI / 2.0, TextAnchor.BOTTOM_CENTER);
      state.cursorRight(insets.getLeft() + labelBounds.width
          + insets.getRight());
    }

    return state;
  }

  /**
   * Returns the fixed dimension for the axis.
   *
   * @return The fixed dimension.
   *
   * @see #setFixedDimension(double)
   */
  public int getFixedDimension() {
    return this.fixedDimension;
  }

  /**
   * Returns the label for the axis.
   *
   * @return The label for the axis (<code>null</code> possible).
   *
   * @see #getLabelFont()
   * @see #getLabelPaint()
   * @see #setLabel(String)
   */
  public String getLabel() {
    return this.label;
  }

  /**
   * Returns the angle of the axis label.
   *
   * @return The angle (in radians).
   *
   * @see #setLabelAngle(double)
   */
  public double getLabelAngle() {
    return this.labelAngle;
  }

  /**
   * Returns a rectangle that encloses the axis label. This is typically used
   * for layout purposes (it gives the maximum dimensions of the label).
   *
   * @param g2
   *            the graphics device.
   * @param edge
   *            the edge of the plot area along which the axis is measuring.
   *
   * @return The enclosing rectangle.
   */
  protected Rectangle getLabelEnclosure(final GC g2, final RectangleEdge edge) {
    Rectangle result = new Rectangle(0, 0, 0, 0);
    final String axisLabel = this.getLabel();
    if ((axisLabel != null) && (axisLabel.length() != 0)) {
      g2.setFont(this.getLabelFont());
      final Point textExtent = g2.textExtent(axisLabel);
      Rectangle bounds = new Rectangle(0, 0, textExtent.x, textExtent.y);
      final RectangleInsets insets = this.getLabelInsets();
      bounds = insets.createOutsetRectangle(bounds);

      final Rectangle labelBounds = bounds;
      if (edge.isLeftOrRight()) {
        // Rotated 90 degrees, so swap width and height.
        this.swapWidthAndHeight(labelBounds);
      }

      result = labelBounds;
    }

    return result;

  }

  /**
   * Returns the font for the axis label.
   *
   * @return The font (never <code>null</code>).
   *
   * @see #setLabelFont(Font)
   */
  public Font getLabelFont() {
    return this.labelFont;
  }

  /**
   * Returns the insets for the label (that is, the amount of blank space that
   * should be left around the label).
   *
   * @return The label insets (never <code>null</code>).
   *
   * @see #setLabelInsets(RectangleInsets)
   */
  public RectangleInsets getLabelInsets() {
    return this.labelInsets;
  }

  /**
   * Returns the plot that the axis is assigned to. This method will return
   * <code>null</code> if the axis is not currently assigned to a plot.
   *
   * @return The plot that the axis is assigned to (possibly <code>null</code>
   *         ).
   *
   * @see #setPlot(Plot)
   */
  public Plot getPlot() {
    return this.plot;
  }

  /**
   * Returns the font used for the tick labels (if showing).
   *
   * @return The font (never <code>null</code>).
   *
   * @see #setTickLabelFont(Font)
   */
  public Font getTickLabelFont() {
    if (this.tickLabelFont == null) {
      return Display.getCurrent().getSystemFont();
    }
    return this.tickLabelFont;
  }

  /**
   * Returns the insets for the tick labels.
   *
   * @return The insets (never <code>null</code>).
   *
   * @see #setTickLabelInsets(RectangleInsets)
   */
  public RectangleInsets getTickLabelInsets() {
    return this.tickLabelInsets;
  }

  /**
   * Returns the color/shade used for the tick labels.
   *
   * @return The paint used for the tick labels.
   *
   * @see #setTickLabelPaint(Paint)
   */
  public Color getTickLabelPaint() {
    final Color color = this.getPlot().getDrawingAssets().getColor(
        Plot.COLOR_TICK_LABEL);
    if (color == null) {
      return  StaticColorChecker.dublicateColor(SWT.COLOR_BLACK); //Display.getCurrent().getSystemColor(SWT.COLOR_BLACK);
    }
    return color;
  }

  /**
   * Returns the inside length of the tick marks.
   *
   * @return The length.
   *
   * @see #getTickMarkOutsideLength()
   * @see #setTickMarkInsideLength(float)
   */
  public float getTickMarkInsideLength() {
    return this.tickMarkInsideLength;
  }

  /**
   * Returns the outside length of the tick marks.
   *
   * @return The length.
   *
   * @see #getTickMarkInsideLength()
   * @see #setTickMarkOutsideLength(float)
   */
  public float getTickMarkOutsideLength() {
    return this.tickMarkOutsideLength;
  }

  /**
   * Returns <code>true</code> if the specified object is registered with the
   * dataset as a listener. Most applications won't need to call this method,
   * it exists mainly for use by unit testing code.
   *
   * @param listener
   *            the listener.
   *
   * @return A boolean.
   */
  public boolean hasListener(final AxisChangeListener listener) {
    // return listenerList.contains(listener);
    // FIXME Implement some kind of ListenerList#contains()
    return false;
  }

  /**
   * A flag that controls whether or not the axis line is drawn.
   *
   * @return A boolean.
   *
   * @see #getAxisLinePaint()
   * @see #getAxisLineStroke()
   * @see #setAxisLineVisible(boolean)
   */
  public boolean isAxisLineVisible() {
    return this.axisLineVisible;
  }

  /**
   * Returns a flag indicating whether or not the tick labels are visible.
   *
   * @return The flag.
   *
   * @see #getTickLabelFont()
   * @see #getTickLabelPaint()
   * @see #setTickLabelsVisible(boolean)
   */
  public boolean isTickLabelsVisible() {
    return this.tickLabelsVisible;
  }

  /**
   * Returns the flag that indicates whether or not the tick marks are
   * showing.
   *
   * @return The flag that indicates whether or not the tick marks are
   *         showing.
   *
   * @see #setTickMarksVisible(boolean)
   */
  public boolean isTickMarksVisible() {
    return this.tickMarksVisible;
  }

  /**
   * Returns <code>true</code> if the axis is visible, and <code>false</code>
   * otherwise.
   *
   * @return A boolean.
   *
   * @see #setVisible(boolean)
   */
  public boolean isVisible() {
    return this.visible;
  }

  /**
   * Notifies all registered listeners that the axis has changed. The
   * AxisChangeEvent provides information about the change.
   *
   * @param event
   *            information about the change to the axis.
   */
  protected void notifyListeners(final AxisChangeEvent event) {
    final Object[] listeners = this.listenerList.getListeners();
    for (int i = 0; i < listeners.length; i++) {
      final AxisChangeListener listener = (AxisChangeListener) listeners[i];
      listener.axisChanged(event);
    }
  }

  /**
   * Deregisters an object for notification of changes to the axis.
   *
   * @param listener
   *            the object to deregister.
   *
   * @see #addChangeListener(AxisChangeListener)
   */
  public void removeChangeListener(final AxisChangeListener listener) {
    this.listenerList.remove(listener);
  }

  /**
   * Sets a flag that controls whether or not the axis line is visible and
   * sends an {@link AxisChangeEvent} to all registered listeners.
   *
   * @param visible
   *            the flag.
   *
   * @see #isAxisLineVisible()
   * @see #setAxisLinePaint(Paint)
   * @see #setAxisLineStroke(Stroke)
   */
  public void setAxisLineVisible(final boolean visible) {
    this.axisLineVisible = visible;
    this.notifyListeners(new AxisChangeEvent(this));
  }

  /**
   * Sets the fixed dimension for the axis.
   * <P>
   * This is used when combining more than one plot on a chart. In this case,
   * there may be several axes that need to have the same height or width so
   * that they are aligned. This method is used to fix a dimension for the
   * axis (the context determines whether the dimension is horizontal or
   * vertical).
   *
   * @param dimension
   *            the fixed dimension.
   *
   * @see #getFixedDimension()
   */
  public void setFixedDimension(final int dimension) {
    this.fixedDimension = dimension;
  }

  /**
   * Sets the label for the axis and sends an {@link AxisChangeEvent} to all
   * registered listeners.
   *
   * @param label
   *            the new label (<code>null</code> permitted).
   *
   * @see #getLabel()
   * @see #setLabelFont(Font)
   * @see #setLabelPaint(Paint)
   */
  public void setLabel(final String label) {
    final String existing = this.label;
    if (existing != null) {
      if (!existing.equals(label)) {
        this.label = label;
        this.notifyListeners(new AxisChangeEvent(this));
      }
    } else {
      if (label != null) {
        this.label = label;
        this.notifyListeners(new AxisChangeEvent(this));
      }
    }
  }

  /**
   * Sets the angle for the label and sends an {@link AxisChangeEvent} to all
   * registered listeners.
   *
   * @param angle
   *            the angle (in radians).
   *
   * @see #getLabelAngle()
   */
  public void setLabelAngle(final double angle) {
    this.labelAngle = angle;
    this.notifyListeners(new AxisChangeEvent(this));
  }

  /**
   * Sets the font for the axis label and sends an {@link AxisChangeEvent} to
   * all registered listeners.
   *
   * @param font
   *            the font (<code>null</code> not permitted).
   *
   * @see #getLabelFont()
   */
  public void setLabelFont(final Font font) {
    if (font == null) {
      throw new IllegalArgumentException("Null 'font' argument.");
    }
    if (!font.equals(this.labelFont)) {
      this.labelFont = font;
      this.notifyListeners(new AxisChangeEvent(this));
    }
  }

  /**
   * Sets the insets for the axis label, and sends an {@link AxisChangeEvent}
   * to all registered listeners.
   *
   * @param insets
   *            the insets (<code>null</code> not permitted).
   *
   * @see #getLabelInsets()
   */
  public void setLabelInsets(final RectangleInsets insets) {
    if (insets == null) {
      throw new IllegalArgumentException("Null 'insets' argument.");
    }
    if (!insets.equals(this.labelInsets)) {
      this.labelInsets = insets;
      this.notifyListeners(new AxisChangeEvent(this));
    }
  }

  /**
   * Sets a reference to the plot that the axis is assigned to.
   * <P>
   * This method is used internally, you shouldn't need to call it yourself.
   *
   * @param plot
   *            the plot.
   *
   * @see #getPlot()
   */
  public void setPlot(final Plot plot) {
    this.plot = plot;
    this.configure();
  }

  /**
   * Sets the font for the tick labels and sends an {@link AxisChangeEvent} to
   * all registered listeners.
   *
   * @param font
   *            the font (<code>null</code> not allowed).
   *
   * @see #getTickLabelFont()
   */
  public void setTickLabelFont(final Font font) {
    if (font == null) {
      throw new IllegalArgumentException("Null 'font' argument.");
    }

    if (!font.equals(this.tickLabelFont)) {
      this.tickLabelFont = font;
      this.notifyListeners(new AxisChangeEvent(this));
    }
  }

  /**
   * Sets the insets for the tick labels and sends an {@link AxisChangeEvent}
   * to all registered listeners.
   *
   * @param insets
   *            the insets (<code>null</code> not permitted).
   *
   * @see #getTickLabelInsets()
   */
  public void setTickLabelInsets(final RectangleInsets insets) {
    if (insets == null) {
      throw new IllegalArgumentException("Null 'insets' argument.");
    }
    if (!this.tickLabelInsets.equals(insets)) {
      this.tickLabelInsets = insets;
      this.notifyListeners(new AxisChangeEvent(this));
    }
  }

  /**
   * Sets the paint used to draw tick labels (if they are showing) and sends
   * an {@link AxisChangeEvent} to all registered listeners.
   *
   * @param paint
   *            the paint (<code>null</code> not permitted).
   *
   * @see #getTickLabelPaint()
   */
  public void setTickLabelPaint(final Color paint) {
    if (paint == null) {
      throw new IllegalArgumentException("Null 'paint' argument.");
    }
    this.notifyListeners(new AxisChangeEvent(this));
  }

  /**
   * Sets the flag that determines whether or not the tick labels are visible
   * and sends an {@link AxisChangeEvent} to all registered listeners.
   *
   * @param flag
   *            the flag.
   *
   * @see #isTickLabelsVisible()
   * @see #setTickLabelFont(Font)
   * @see #setTickLabelPaint(Paint)
   */
  public void setTickLabelsVisible(final boolean flag) {
    if (flag != this.tickLabelsVisible) {
      this.tickLabelsVisible = flag;
      this.notifyListeners(new AxisChangeEvent(this));
    }
  }

  /**
   * Sets the inside length of the tick marks and sends an
   * {@link AxisChangeEvent} to all registered listeners.
   *
   * @param length
   *            the new length.
   *
   * @see #getTickMarkInsideLength()
   */
  public void setTickMarkInsideLength(final float length) {
    this.tickMarkInsideLength = length;
    this.notifyListeners(new AxisChangeEvent(this));
  }

  /**
   * Sets the outside length of the tick marks and sends an
   * {@link AxisChangeEvent} to all registered listeners.
   *
   * @param length
   *            the new length.
   *
   * @see #getTickMarkInsideLength()
   */
  public void setTickMarkOutsideLength(final float length) {
    this.tickMarkOutsideLength = length;
    this.notifyListeners(new AxisChangeEvent(this));
  }

  /**
   * Sets the flag that indicates whether or not the tick marks are showing
   * and sends an {@link AxisChangeEvent} to all registered listeners.
   *
   * @param flag
   *            the flag.
   *
   * @see #isTickMarksVisible()
   */
  public void setTickMarksVisible(final boolean flag) {
    if (flag != this.tickMarksVisible) {
      this.tickMarksVisible = flag;
      this.notifyListeners(new AxisChangeEvent(this));
    }
  }

  /**
   * Sets a flag that controls whether or not the axis is visible and sends an
   * {@link AxisChangeEvent} to all registered listeners.
   *
   * @param flag
   *            the flag.
   *
   * @see #isVisible()
   */
  public void setVisible(final boolean flag) {
    if (flag != this.visible) {
      this.visible = flag;
      this.notifyListeners(new AxisChangeEvent(this));
    }
  }

  private void swapWidthAndHeight(final Rectangle rect) {
    final int temp = rect.width;
    rect.width = rect.height;
    rect.height = temp;
  }

}
TOP

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

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.