/**
   * Draws the background to the specified graphics device. If the dial frame specifies a window,
   * the clipping region will already have been set to this window before this method is called.
   *
   * @param g2 the graphics device (<code>null</code> not permitted).
   * @param plot the plot (ignored here).
   * @param frame the dial frame (ignored here).
   * @param view the view rectangle (<code>null</code> not permitted).
   */
  @Override
  public void draw(Graphics2D g2, DialPlot plot, Rectangle2D frame, Rectangle2D view) {

    // work out the anchor point
    Rectangle2D f = DialPlot.rectangleByRadius(frame, this.radius, this.radius);
    Arc2D arc = new Arc2D.Double(f, this.angle, 0.0, Arc2D.OPEN);
    Point2D pt = arc.getStartPoint();

    // the indicator bounds is calculated from the templateValue (which
    // determines the minimum size), the maxTemplateValue (which, if
    // specified, provides a maximum size) and the actual value
    FontMetrics fm = g2.getFontMetrics(this.font);
    double value = plot.getValue(this.datasetIndex);
    String valueStr = this.formatter.format(value);
    Rectangle2D valueBounds = TextUtilities.getTextBounds(valueStr, g2, fm);

    // calculate the bounds of the template value
    String s = this.formatter.format(this.templateValue);
    Rectangle2D tb = TextUtilities.getTextBounds(s, g2, fm);
    double minW = tb.getWidth();
    double minH = tb.getHeight();

    double maxW = Double.MAX_VALUE;
    double maxH = Double.MAX_VALUE;
    if (this.maxTemplateValue != null) {
      s = this.formatter.format(this.maxTemplateValue);
      tb = TextUtilities.getTextBounds(s, g2, fm);
      maxW = Math.max(tb.getWidth(), minW);
      maxH = Math.max(tb.getHeight(), minH);
    }
    double w = fixToRange(valueBounds.getWidth(), minW, maxW);
    double h = fixToRange(valueBounds.getHeight(), minH, maxH);

    // align this rectangle to the frameAnchor
    Rectangle2D bounds =
        RectangleAnchor.createRectangle(new Size2D(w, h), pt.getX(), pt.getY(), this.frameAnchor);

    // add the insets
    Rectangle2D fb = this.insets.createOutsetRectangle(bounds);

    // draw the background
    g2.setPaint(this.backgroundPaint);
    g2.fill(fb);

    // draw the border
    g2.setStroke(this.outlineStroke);
    g2.setPaint(this.outlinePaint);
    g2.draw(fb);

    // now find the text anchor point
    Shape savedClip = g2.getClip();
    g2.clip(fb);

    Point2D pt2 = RectangleAnchor.coordinates(bounds, this.valueAnchor);
    g2.setPaint(this.paint);
    g2.setFont(this.font);
    TextUtilities.drawAlignedString(
        valueStr, g2, (float) pt2.getX(), (float) pt2.getY(), this.textAnchor);
    g2.setClip(savedClip);
  }
  /**
   * Reserve some space on each axis side because we draw a centered label at each extremity.
   *
   * @param g2 the graphics device.
   * @param plot the plot.
   * @param plotArea the plot area.
   * @param edge the edge.
   * @param space the space already reserved.
   * @return The reserved space.
   */
  public AxisSpace reserveSpace(
      Graphics2D g2, Plot plot, Rectangle2D plotArea, RectangleEdge edge, AxisSpace space) {

    this.internalMarkerCycleBoundTick = null;
    AxisSpace ret = super.reserveSpace(g2, plot, plotArea, edge, space);
    if (this.internalMarkerCycleBoundTick == null) {
      return ret;
    }

    FontMetrics fm = g2.getFontMetrics(getTickLabelFont());
    Rectangle2D r =
        TextUtilities.getTextBounds(this.internalMarkerCycleBoundTick.getText(), g2, fm);

    if (RectangleEdge.isTopOrBottom(edge)) {
      if (isVerticalTickLabels()) {
        space.add(r.getHeight() / 2, RectangleEdge.RIGHT);
      } else {
        space.add(r.getWidth() / 2, RectangleEdge.RIGHT);
      }
    } else if (RectangleEdge.isLeftOrRight(edge)) {
      if (isVerticalTickLabels()) {
        space.add(r.getWidth() / 2, RectangleEdge.TOP);
      } else {
        space.add(r.getHeight() / 2, RectangleEdge.TOP);
      }
    }

    return ret;
  }
Exemple #3
0
  public Point textExtent(String text) {

    String[] lines = text.split(Const.CR);
    int maxWidth = 0;
    for (String line : lines) {
      Rectangle2D bounds = TextUtilities.getTextBounds(line, gc, gc.getFontMetrics());
      if (bounds.getWidth() > maxWidth) maxWidth = (int) bounds.getWidth();
    }
    int height = gc.getFontMetrics().getHeight() * lines.length;

    return new Point((int) maxWidth, (int) height);
  }
Exemple #4
0
  /**
   * A utility method that draws a string inside a rectangle.
   *
   * @param g2 the graphics device.
   * @param bounds the rectangle.
   * @param font the font.
   * @param text the text.
   */
  private void drawStringInRect(Graphics2D g2, Rectangle2D bounds, Font font, String text) {

    g2.setFont(font);
    FontMetrics fm = g2.getFontMetrics(font);
    Rectangle2D r = TextUtilities.getTextBounds(text, g2, fm);
    double x = bounds.getX();
    if (r.getWidth() < bounds.getWidth()) {
      x = x + (bounds.getWidth() - r.getWidth()) / 2;
    }
    LineMetrics metrics = font.getLineMetrics(text, g2.getFontRenderContext());
    g2.drawString(
        text, (float) x, (float) (bounds.getMaxY() - this.bottomInnerGap - metrics.getDescent()));
  }
Exemple #5
0
  /**
   * Draws a tick on the dial.
   *
   * @param g2 the graphics device.
   * @param meterArea the meter area.
   * @param value the tick value.
   * @param label a flag that controls whether or not a value label is drawn.
   */
  protected void drawTick(Graphics2D g2, Rectangle2D meterArea, double value, boolean label) {

    double valueAngle = valueToAngle(value);

    double meterMiddleX = meterArea.getCenterX();
    double meterMiddleY = meterArea.getCenterY();

    g2.setPaint(this.tickPaint);
    g2.setStroke(new BasicStroke(2.0f));

    double valueP2X = 0;
    double valueP2Y = 0;

    double radius = (meterArea.getWidth() / 2) + DEFAULT_BORDER_SIZE;
    double radius1 = radius - 15;

    double valueP1X = meterMiddleX + (radius * Math.cos(Math.PI * (valueAngle / 180)));
    double valueP1Y = meterMiddleY - (radius * Math.sin(Math.PI * (valueAngle / 180)));

    valueP2X = meterMiddleX + (radius1 * Math.cos(Math.PI * (valueAngle / 180)));
    valueP2Y = meterMiddleY - (radius1 * Math.sin(Math.PI * (valueAngle / 180)));

    Line2D.Double line = new Line2D.Double(valueP1X, valueP1Y, valueP2X, valueP2Y);
    g2.draw(line);

    if (this.tickLabelsVisible && label) {

      String tickLabel = this.tickLabelFormat.format(value);
      g2.setFont(this.tickLabelFont);
      g2.setPaint(this.tickLabelPaint);

      FontMetrics fm = g2.getFontMetrics();
      Rectangle2D tickLabelBounds = TextUtilities.getTextBounds(tickLabel, g2, fm);

      double x = valueP2X;
      double y = valueP2Y;
      if (valueAngle == 90 || valueAngle == 270) {
        x = x - tickLabelBounds.getWidth() / 2;
      } else if (valueAngle < 90 || valueAngle > 270) {
        x = x - tickLabelBounds.getWidth();
      }
      if ((valueAngle > 135 && valueAngle < 225) || valueAngle > 315 || valueAngle < 45) {
        y = y - tickLabelBounds.getHeight() / 2;
      } else {
        y = y + tickLabelBounds.getHeight() / 2;
      }
      g2.drawString(tickLabel, (float) x, (float) y);
    }
  }
Exemple #6
0
 /**
  * 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(Graphics2D g2, RectangleEdge edge) {
   double result = 0.0;
   g2.setFont(this.subLabelFont);
   FontMetrics fm = g2.getFontMetrics();
   Iterator iterator = this.subCategories.iterator();
   while (iterator.hasNext()) {
     Comparable subcategory = (Comparable) iterator.next();
     String label = subcategory.toString();
     Rectangle2D bounds = TextUtilities.getTextBounds(label, g2, fm);
     double dim = 0.0;
     if (RectangleEdge.isLeftOrRight(edge)) {
       dim = bounds.getWidth();
     } else { // must be top or bottom
       dim = bounds.getHeight();
     }
     result = Math.max(result, dim);
   }
   return result;
 }
  /**
   * 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 Rectangle2D getLabelEnclosure(Graphics2D g2, RectangleEdge edge) {

    Rectangle2D result = new Rectangle2D.Double();
    String axisLabel = getLabel();
    if (axisLabel != null && !axisLabel.equals("")) {
      FontMetrics fm = g2.getFontMetrics(getLabelFont());
      Rectangle2D bounds = TextUtilities.getTextBounds(axisLabel, g2, fm);
      RectangleInsets insets = getLabelInsets();
      bounds = insets.createOutsetRectangle(bounds);
      double angle = getLabelAngle();
      if (edge == RectangleEdge.LEFT || edge == RectangleEdge.RIGHT) {
        angle = angle - Math.PI / 2.0;
      }
      double x = bounds.getCenterX();
      double y = bounds.getCenterY();
      AffineTransform transformer = AffineTransform.getRotateInstance(angle, x, y);
      Shape labelBounds = transformer.createTransformedShape(bounds);
      result = labelBounds.getBounds2D();
    }

    return result;
  }
  /**
   * 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(
      String label,
      Graphics2D g2,
      Rectangle2D plotArea,
      Rectangle2D dataArea,
      RectangleEdge edge,
      AxisState state) {

    // it is unlikely that 'state' will be null, but check anyway...
    ParamChecks.nullNotPermitted(state, "state");

    if ((label == null) || (label.equals(""))) {
      return state;
    }

    Font font = getLabelFont();
    RectangleInsets insets = getLabelInsets();
    g2.setFont(font);
    g2.setPaint(getLabelPaint());
    FontMetrics fm = g2.getFontMetrics();
    Rectangle2D labelBounds = TextUtilities.getTextBounds(label, g2, fm);

    if (edge == RectangleEdge.TOP) {
      AffineTransform t =
          AffineTransform.getRotateInstance(
              getLabelAngle(), labelBounds.getCenterX(), labelBounds.getCenterY());
      Shape rotatedLabelBounds = t.createTransformedShape(labelBounds);
      labelBounds = rotatedLabelBounds.getBounds2D();
      double labelx = dataArea.getCenterX();
      double labely = state.getCursor() - insets.getBottom() - labelBounds.getHeight() / 2.0;
      TextUtilities.drawRotatedString(
          label,
          g2,
          (float) labelx,
          (float) labely,
          TextAnchor.CENTER,
          getLabelAngle(),
          TextAnchor.CENTER);
      state.cursorUp(insets.getTop() + labelBounds.getHeight() + insets.getBottom());
    } else if (edge == RectangleEdge.BOTTOM) {
      AffineTransform t =
          AffineTransform.getRotateInstance(
              getLabelAngle(), labelBounds.getCenterX(), labelBounds.getCenterY());
      Shape rotatedLabelBounds = t.createTransformedShape(labelBounds);
      labelBounds = rotatedLabelBounds.getBounds2D();
      double labelx = dataArea.getCenterX();
      double labely = state.getCursor() + insets.getTop() + labelBounds.getHeight() / 2.0;
      TextUtilities.drawRotatedString(
          label,
          g2,
          (float) labelx,
          (float) labely,
          TextAnchor.CENTER,
          getLabelAngle(),
          TextAnchor.CENTER);
      state.cursorDown(insets.getTop() + labelBounds.getHeight() + insets.getBottom());
    } else if (edge == RectangleEdge.LEFT) {
      AffineTransform t =
          AffineTransform.getRotateInstance(
              getLabelAngle() - Math.PI / 2.0, labelBounds.getCenterX(), labelBounds.getCenterY());
      Shape rotatedLabelBounds = t.createTransformedShape(labelBounds);
      labelBounds = rotatedLabelBounds.getBounds2D();
      double labelx = state.getCursor() - insets.getRight() - labelBounds.getWidth() / 2.0;
      double labely = dataArea.getCenterY();
      TextUtilities.drawRotatedString(
          label,
          g2,
          (float) labelx,
          (float) labely,
          TextAnchor.CENTER,
          getLabelAngle() - Math.PI / 2.0,
          TextAnchor.CENTER);
      state.cursorLeft(insets.getLeft() + labelBounds.getWidth() + insets.getRight());
    } else if (edge == RectangleEdge.RIGHT) {

      AffineTransform t =
          AffineTransform.getRotateInstance(
              getLabelAngle() + Math.PI / 2.0, labelBounds.getCenterX(), labelBounds.getCenterY());
      Shape rotatedLabelBounds = t.createTransformedShape(labelBounds);
      labelBounds = rotatedLabelBounds.getBounds2D();
      double labelx = state.getCursor() + insets.getLeft() + labelBounds.getWidth() / 2.0;
      double labely = dataArea.getY() + dataArea.getHeight() / 2.0;
      TextUtilities.drawRotatedString(
          label,
          g2,
          (float) labelx,
          (float) labely,
          TextAnchor.CENTER,
          getLabelAngle() + Math.PI / 2.0,
          TextAnchor.CENTER);
      state.cursorRight(insets.getLeft() + labelBounds.getWidth() + insets.getRight());
    }

    return state;
  }
  /**
   * Draws the tick labels for one "band" of time periods.
   *
   * @param band the band index (zero-based).
   * @param g2 the graphics device.
   * @param state the axis state.
   * @param dataArea the data area.
   * @param edge the edge where the axis is located.
   * @return The updated axis state.
   */
  protected AxisState drawTickLabels(
      int band, Graphics2D g2, AxisState state, Rectangle2D dataArea, RectangleEdge edge) {

    // work out the initial gap
    double delta1 = 0.0;
    FontMetrics fm = g2.getFontMetrics(this.labelInfo[band].getLabelFont());
    if (edge == RectangleEdge.BOTTOM) {
      delta1 = this.labelInfo[band].getPadding().calculateTopOutset(fm.getHeight());
    } else if (edge == RectangleEdge.TOP) {
      delta1 = this.labelInfo[band].getPadding().calculateBottomOutset(fm.getHeight());
    }
    state.moveCursor(delta1, edge);
    long axisMin = this.first.getFirstMillisecond();
    long axisMax = this.last.getLastMillisecond();
    g2.setFont(this.labelInfo[band].getLabelFont());
    g2.setPaint(this.labelInfo[band].getLabelPaint());

    // work out the number of periods to skip for labelling
    RegularTimePeriod p1 =
        this.labelInfo[band].createInstance(new Date(axisMin), this.timeZone, this.locale);
    RegularTimePeriod p2 =
        this.labelInfo[band].createInstance(new Date(axisMax), this.timeZone, this.locale);
    String label1 =
        this.labelInfo[band].getDateFormat().format(new Date(p1.getMiddleMillisecond()));
    String label2 =
        this.labelInfo[band].getDateFormat().format(new Date(p2.getMiddleMillisecond()));
    Rectangle2D b1 = TextUtilities.getTextBounds(label1, g2, g2.getFontMetrics());
    Rectangle2D b2 = TextUtilities.getTextBounds(label2, g2, g2.getFontMetrics());
    double w = Math.max(b1.getWidth(), b2.getWidth());
    long ww = Math.round(java2DToValue(dataArea.getX() + w + 5.0, dataArea, edge));
    if (isInverted()) {
      ww = axisMax - ww;
    } else {
      ww = ww - axisMin;
    }
    long length = p1.getLastMillisecond() - p1.getFirstMillisecond();
    int periods = (int) (ww / length) + 1;

    RegularTimePeriod p =
        this.labelInfo[band].createInstance(new Date(axisMin), this.timeZone, this.locale);
    Rectangle2D b = null;
    long lastXX = 0L;
    float y = (float) (state.getCursor());
    TextAnchor anchor = TextAnchor.TOP_CENTER;
    float yDelta = (float) b1.getHeight();
    if (edge == RectangleEdge.TOP) {
      anchor = TextAnchor.BOTTOM_CENTER;
      yDelta = -yDelta;
    }
    while (p.getFirstMillisecond() <= axisMax) {
      float x = (float) valueToJava2D(p.getMiddleMillisecond(), dataArea, edge);
      DateFormat df = this.labelInfo[band].getDateFormat();
      String label = df.format(new Date(p.getMiddleMillisecond()));
      long first = p.getFirstMillisecond();
      long last = p.getLastMillisecond();
      if (last > axisMax) {
        // this is the last period, but it is only partially visible
        // so check that the label will fit before displaying it...
        Rectangle2D bb = TextUtilities.getTextBounds(label, g2, g2.getFontMetrics());
        if ((x + bb.getWidth() / 2) > dataArea.getMaxX()) {
          float xstart = (float) valueToJava2D(Math.max(first, axisMin), dataArea, edge);
          if (bb.getWidth() < (dataArea.getMaxX() - xstart)) {
            x = ((float) dataArea.getMaxX() + xstart) / 2.0f;
          } else {
            label = null;
          }
        }
      }
      if (first < axisMin) {
        // this is the first period, but it is only partially visible
        // so check that the label will fit before displaying it...
        Rectangle2D bb = TextUtilities.getTextBounds(label, g2, g2.getFontMetrics());
        if ((x - bb.getWidth() / 2) < dataArea.getX()) {
          float xlast = (float) valueToJava2D(Math.min(last, axisMax), dataArea, edge);
          if (bb.getWidth() < (xlast - dataArea.getX())) {
            x = (xlast + (float) dataArea.getX()) / 2.0f;
          } else {
            label = null;
          }
        }
      }
      if (label != null) {
        g2.setPaint(this.labelInfo[band].getLabelPaint());
        b = TextUtilities.drawAlignedString(label, g2, x, y, anchor);
      }
      if (lastXX > 0L) {
        if (this.labelInfo[band].getDrawDividers()) {
          long nextXX = p.getFirstMillisecond();
          long mid = (lastXX + nextXX) / 2;
          float mid2d = (float) valueToJava2D(mid, dataArea, edge);
          g2.setStroke(this.labelInfo[band].getDividerStroke());
          g2.setPaint(this.labelInfo[band].getDividerPaint());
          g2.draw(new Line2D.Float(mid2d, y, mid2d, y + yDelta));
        }
      }
      lastXX = last;
      for (int i = 0; i < periods; i++) {
        p = p.next();
      }
      p.peg(this.calendar);
    }
    double used = 0.0;
    if (b != null) {
      used = b.getHeight();
      // work out the trailing gap
      if (edge == RectangleEdge.BOTTOM) {
        used += this.labelInfo[band].getPadding().calculateBottomOutset(fm.getHeight());
      } else if (edge == RectangleEdge.TOP) {
        used += this.labelInfo[band].getPadding().calculateTopOutset(fm.getHeight());
      }
    }
    state.moveCursor(used, edge);
    return state;
  }