Example #1
0
  /**
   * Draws the visual representation of a single data item.
   *
   * @param g2 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 crosshairState crosshair information for the plot ({@code null} permitted).
   * @param pass the pass index.
   */
  @Override
  public void drawItem(
      Graphics2D g2,
      XYItemRendererState state,
      Rectangle2D dataArea,
      PlotRenderingInfo info,
      XYPlot plot,
      ValueAxis domainAxis,
      ValueAxis rangeAxis,
      XYDataset dataset,
      int series,
      int item,
      CrosshairState crosshairState,
      int pass) {

    if (!getItemVisible(series, item)) {
      return;
    }
    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;
    }
    if (value0 <= value1) {
      if (!rangeAxis.getRange().intersects(value0, value1)) {
        return;
      }
    } else {
      if (!rangeAxis.getRange().intersects(value1, value0)) {
        return;
      }
    }

    double translatedValue0 = rangeAxis.valueToJava2D(value0, dataArea, plot.getRangeAxisEdge());
    double translatedValue1 = rangeAxis.valueToJava2D(value1, dataArea, plot.getRangeAxisEdge());
    double bottom = Math.min(translatedValue0, translatedValue1);
    double top = Math.max(translatedValue0, translatedValue1);

    double startX = intervalDataset.getStartXValue(series, item);
    if (Double.isNaN(startX)) {
      return;
    }
    double endX = intervalDataset.getEndXValue(series, item);
    if (Double.isNaN(endX)) {
      return;
    }
    if (startX <= endX) {
      if (!domainAxis.getRange().intersects(startX, endX)) {
        return;
      }
    } else {
      if (!domainAxis.getRange().intersects(endX, startX)) {
        return;
      }
    }

    // is there an alignment adjustment to be made?
    if (this.barAlignmentFactor >= 0.0 && this.barAlignmentFactor <= 1.0) {
      double x = intervalDataset.getXValue(series, item);
      double interval = endX - startX;
      startX = x - interval * this.barAlignmentFactor;
      endX = startX + interval;
    }

    RectangleEdge location = plot.getDomainAxisEdge();
    double translatedStartX = domainAxis.valueToJava2D(startX, dataArea, location);
    double translatedEndX = domainAxis.valueToJava2D(endX, dataArea, location);

    double translatedWidth = Math.max(1, Math.abs(translatedEndX - translatedStartX));

    double left = Math.min(translatedStartX, translatedEndX);
    if (getMargin() > 0.0) {
      double cut = translatedWidth * getMargin();
      translatedWidth = translatedWidth - cut;
      left = left + cut / 2;
    }

    Rectangle2D bar = null;
    PlotOrientation orientation = plot.getOrientation();
    if (orientation.isHorizontal()) {
      // clip left and right bounds to data area
      bottom = Math.max(bottom, dataArea.getMinX());
      top = Math.min(top, dataArea.getMaxX());
      bar = new Rectangle2D.Double(bottom, left, top - bottom, translatedWidth);
    } else if (orientation.isVertical()) {
      // clip top and bottom bounds to data area
      bottom = Math.max(bottom, dataArea.getMinY());
      top = Math.min(top, dataArea.getMaxY());
      bar = new Rectangle2D.Double(left, bottom, translatedWidth, top - bottom);
    }

    boolean positive = (value1 > 0.0);
    boolean inverted = rangeAxis.isInverted();
    RectangleEdge barBase;
    if (orientation.isHorizontal()) {
      if (positive && inverted || !positive && !inverted) {
        barBase = RectangleEdge.RIGHT;
      } else {
        barBase = RectangleEdge.LEFT;
      }
    } else {
      if (positive && !inverted || !positive && inverted) {
        barBase = RectangleEdge.BOTTOM;
      } else {
        barBase = RectangleEdge.TOP;
      }
    }

    if (state.getElementHinting()) {
      beginElementGroup(g2, dataset.getSeriesKey(series), item);
    }
    if (getShadowsVisible()) {
      this.barPainter.paintBarShadow(g2, this, series, item, bar, barBase, !this.useYInterval);
    }
    this.barPainter.paintBar(g2, this, series, item, bar, barBase);
    if (state.getElementHinting()) {
      endElementGroup(g2);
    }

    if (isItemLabelVisible(series, item)) {
      XYItemLabelGenerator generator = getItemLabelGenerator(series, item);
      drawItemLabel(g2, 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());
    int domainAxisIndex = plot.getDomainAxisIndex(domainAxis);
    int rangeAxisIndex = plot.getRangeAxisIndex(rangeAxis);
    updateCrosshairValues(
        crosshairState,
        x1,
        y1,
        domainAxisIndex,
        rangeAxisIndex,
        transX1,
        transY1,
        plot.getOrientation());

    EntityCollection entities = state.getEntityCollection();
    if (entities != null) {
      addEntity(entities, bar, dataset, series, item, 0.0, 0.0);
    }
  }
  /**
   * Draws the visual representation of a single data item.
   *
   * @param g2 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 crosshairState crosshair information for the plot (<code>null</code> permitted).
   * @param pass the pass index.
   */
  public void drawItem(
      Graphics2D g2,
      XYItemRendererState state,
      Rectangle2D dataArea,
      PlotRenderingInfo info,
      XYPlot plot,
      ValueAxis domainAxis,
      ValueAxis rangeAxis,
      XYDataset dataset,
      int series,
      int item,
      CrosshairState crosshairState,
      int pass) {

    if (!(dataset instanceof IntervalXYDataset && dataset instanceof TableXYDataset)) {
      String message = "dataset (type " + dataset.getClass().getName() + ") has wrong type:";
      boolean and = false;
      if (!IntervalXYDataset.class.isAssignableFrom(dataset.getClass())) {
        message += " it is no IntervalXYDataset";
        and = true;
      }
      if (!TableXYDataset.class.isAssignableFrom(dataset.getClass())) {
        if (and) {
          message += " and";
        }
        message += " it is no TableXYDataset";
      }

      throw new IllegalArgumentException(message);
    }

    IntervalXYDataset intervalDataset = (IntervalXYDataset) dataset;
    double value = intervalDataset.getYValue(series, item);
    if (Double.isNaN(value)) {
      return;
    }

    // if we are rendering the values as percentages, we need to calculate
    // the total for the current item.  Unfortunately here we end up
    // repeating the calculation more times than is strictly necessary -
    // hopefully I'll come back to this and find a way to add the
    // total(s) to the renderer state.  The other problem is we implicitly
    // assume the dataset has no negative values...perhaps that can be
    // fixed too.
    double total = 0.0;
    if (this.renderAsPercentages) {
      total = DatasetUtilities.calculateStackTotal((TableXYDataset) dataset, item);
      value = value / total;
    }

    double positiveBase = 0.0;
    double negativeBase = 0.0;

    for (int i = 0; i < series; i++) {
      double v = dataset.getYValue(i, item);
      if (!Double.isNaN(v)) {
        if (this.renderAsPercentages) {
          v = v / total;
        }
        if (v > 0) {
          positiveBase = positiveBase + v;
        } else {
          negativeBase = negativeBase + v;
        }
      }
    }

    double translatedBase;
    double translatedValue;
    RectangleEdge edgeR = plot.getRangeAxisEdge();
    if (value > 0.0) {
      translatedBase = rangeAxis.valueToJava2D(positiveBase, dataArea, edgeR);
      translatedValue = rangeAxis.valueToJava2D(positiveBase + value, dataArea, edgeR);
    } else {
      translatedBase = rangeAxis.valueToJava2D(negativeBase, dataArea, edgeR);
      translatedValue = rangeAxis.valueToJava2D(negativeBase + value, dataArea, edgeR);
    }

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

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

    double translatedWidth = Math.max(1, Math.abs(translatedEndX - translatedStartX));
    double translatedHeight = Math.abs(translatedValue - translatedBase);
    if (getMargin() > 0.0) {
      double cut = translatedWidth * getMargin();
      translatedWidth = translatedWidth - cut;
      translatedStartX = translatedStartX + cut / 2;
    }

    Rectangle2D bar = null;
    PlotOrientation orientation = plot.getOrientation();
    if (orientation == PlotOrientation.HORIZONTAL) {
      bar =
          new Rectangle2D.Double(
              Math.min(translatedBase, translatedValue),
              Math.min(translatedEndX, translatedStartX),
              translatedHeight,
              translatedWidth);
    } else if (orientation == PlotOrientation.VERTICAL) {
      bar =
          new Rectangle2D.Double(
              Math.min(translatedStartX, translatedEndX),
              Math.min(translatedBase, translatedValue),
              translatedWidth,
              translatedHeight);
    }
    boolean positive = (value > 0.0);
    boolean inverted = rangeAxis.isInverted();
    RectangleEdge barBase;
    if (orientation == PlotOrientation.HORIZONTAL) {
      if (positive && inverted || !positive && !inverted) {
        barBase = RectangleEdge.RIGHT;
      } else {
        barBase = RectangleEdge.LEFT;
      }
    } else {
      if (positive && !inverted || !positive && inverted) {
        barBase = RectangleEdge.BOTTOM;
      } else {
        barBase = RectangleEdge.TOP;
      }
    }

    if (pass == 0) {
      if (getShadowsVisible()) {
        getBarPainter().paintBarShadow(g2, this, series, item, bar, barBase, false);
      }
    } else if (pass == 1) {
      getBarPainter().paintBar(g2, this, series, item, bar, barBase);

      // add an entity for the item...
      if (info != null) {
        EntityCollection entities = info.getOwner().getEntityCollection();
        if (entities != null) {
          addEntity(entities, bar, dataset, series, item, bar.getCenterX(), bar.getCenterY());
        }
      }
    } else if (pass == 2) {
      // handle item label drawing, now that we know all the bars have
      // been drawn...
      if (isItemLabelVisible(series, item)) {
        XYItemLabelGenerator generator = getItemLabelGenerator(series, item);
        drawItemLabel(g2, dataset, series, item, plot, generator, bar, value < 0.0);
      }
    }
  }
  /**
   * Draws the visual representation of a single data item.
   *
   * @param g2 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 crosshairState crosshair information for the plot (<code>null</code> permitted).
   * @param pass the pass index.
   */
  @Override
  public void drawItem(
      Graphics2D g2,
      XYItemRendererState state,
      Rectangle2D dataArea,
      PlotRenderingInfo info,
      XYPlot plot,
      ValueAxis domainAxis,
      ValueAxis rangeAxis,
      XYDataset dataset,
      int series,
      int item,
      CrosshairState crosshairState,
      int pass) {

    double x = dataset.getXValue(series, item);
    if (!domainAxis.getRange().contains(x)) {
      return; // the x value is not within the axis range
    }
    double xx = domainAxis.valueToJava2D(x, dataArea, plot.getDomainAxisEdge());

    // setup for collecting optional entity info...
    Shape entityArea = null;
    EntityCollection entities = null;
    if (info != null) {
      entities = info.getOwner().getEntityCollection();
    }

    PlotOrientation orientation = plot.getOrientation();
    RectangleEdge location = plot.getRangeAxisEdge();

    Paint itemPaint = getItemPaint(series, item);
    Stroke itemStroke = getItemStroke(series, item);
    g2.setPaint(itemPaint);
    g2.setStroke(itemStroke);

    if (dataset instanceof OHLCDataset) {
      OHLCDataset hld = (OHLCDataset) dataset;

      double yHigh = hld.getHighValue(series, item);
      double yLow = hld.getLowValue(series, item);
      if (!Double.isNaN(yHigh) && !Double.isNaN(yLow)) {
        double yyHigh = rangeAxis.valueToJava2D(yHigh, dataArea, location);
        double yyLow = rangeAxis.valueToJava2D(yLow, dataArea, location);
        if (orientation == PlotOrientation.HORIZONTAL) {
          g2.draw(new Line2D.Double(yyLow, xx, yyHigh, xx));
          entityArea =
              new Rectangle2D.Double(
                  Math.min(yyLow, yyHigh), xx - 1.0, Math.abs(yyHigh - yyLow), 2.0);
        } else if (orientation == PlotOrientation.VERTICAL) {
          g2.draw(new Line2D.Double(xx, yyLow, xx, yyHigh));
          entityArea =
              new Rectangle2D.Double(
                  xx - 1.0, Math.min(yyLow, yyHigh), 2.0, Math.abs(yyHigh - yyLow));
        }
      }

      double delta = getTickLength();
      if (domainAxis.isInverted()) {
        delta = -delta;
      }
      if (getDrawOpenTicks()) {
        double yOpen = hld.getOpenValue(series, item);
        if (!Double.isNaN(yOpen)) {
          double yyOpen = rangeAxis.valueToJava2D(yOpen, dataArea, location);
          if (this.openTickPaint != null) {
            g2.setPaint(this.openTickPaint);
          } else {
            g2.setPaint(itemPaint);
          }
          if (orientation == PlotOrientation.HORIZONTAL) {
            g2.draw(new Line2D.Double(yyOpen, xx + delta, yyOpen, xx));
          } else if (orientation == PlotOrientation.VERTICAL) {
            g2.draw(new Line2D.Double(xx - delta, yyOpen, xx, yyOpen));
          }
        }
      }

      if (getDrawCloseTicks()) {
        double yClose = hld.getCloseValue(series, item);
        if (!Double.isNaN(yClose)) {
          double yyClose = rangeAxis.valueToJava2D(yClose, dataArea, location);
          if (this.closeTickPaint != null) {
            g2.setPaint(this.closeTickPaint);
          } else {
            g2.setPaint(itemPaint);
          }
          if (orientation == PlotOrientation.HORIZONTAL) {
            g2.draw(new Line2D.Double(yyClose, xx, yyClose, xx - delta));
          } else if (orientation == PlotOrientation.VERTICAL) {
            g2.draw(new Line2D.Double(xx, yyClose, xx + delta, yyClose));
          }
        }
      }

    } else {
      // not a HighLowDataset, so just draw a line connecting this point
      // with the previous point...
      if (item > 0) {
        double x0 = dataset.getXValue(series, item - 1);
        double y0 = dataset.getYValue(series, item - 1);
        double y = dataset.getYValue(series, item);
        if (Double.isNaN(x0) || Double.isNaN(y0) || Double.isNaN(y)) {
          return;
        }
        double xx0 = domainAxis.valueToJava2D(x0, dataArea, plot.getDomainAxisEdge());
        double yy0 = rangeAxis.valueToJava2D(y0, dataArea, location);
        double yy = rangeAxis.valueToJava2D(y, dataArea, location);
        if (orientation == PlotOrientation.HORIZONTAL) {
          g2.draw(new Line2D.Double(yy0, xx0, yy, xx));
        } else if (orientation == PlotOrientation.VERTICAL) {
          g2.draw(new Line2D.Double(xx0, yy0, xx, yy));
        }
      }
    }

    if (entities != null) {
      addEntity(entities, entityArea, dataset, series, item, 0.0, 0.0);
    }
  }
    // copied and modified from jfreechart-1.0.14 org.jfree.chart.renderer.category.BarRenderer
    private void drawItemInternal(
        Graphics2D g2,
        CategoryItemRendererState state,
        Rectangle2D dataArea,
        CategoryPlot plot,
        CategoryAxis domainAxis,
        ValueAxis rangeAxis,
        CategoryDataset dataset,
        int row,
        int column,
        int pass) {

      // nothing is drawn if the row index is not included in the list with
      // the indices of the visible rows...
      int visibleRow = state.getVisibleSeriesIndex(row);
      if (visibleRow < 0) {
        return;
      }
      // nothing is drawn for null values...
      Number dataValue = dataset.getValue(row, column);
      if (dataValue == null) {
        return;
      }

      final double value = dataValue.doubleValue();
      PlotOrientation orientation = plot.getOrientation();
      double barW0 =
          calculateBarW0(plot, orientation, dataArea, domainAxis, state, visibleRow, column);
      double[] barL0L1 = calculateBarL0L1(value);
      if (barL0L1 == null) {
        return; // the bar is not visible
      }

      RectangleEdge edge = plot.getRangeAxisEdge();
      double transL0 = rangeAxis.valueToJava2D(barL0L1[0], dataArea, edge);
      double transL1 = rangeAxis.valueToJava2D(barL0L1[1], dataArea, edge);

      // in the following code, barL0 is (in Java2D coordinates) the LEFT
      // end of the bar for a horizontal bar chart, and the TOP end of the
      // bar for a vertical bar chart.  Whether this is the BASE of the bar
      // or not depends also on (a) whether the data value is 'negative'
      // relative to the base value and (b) whether or not the range axis is
      // inverted.  This only matters if/when we apply the minimumBarLength
      // attribute, because we should extend the non-base end of the bar
      boolean positive = (value >= this.getBase());
      boolean inverted = rangeAxis.isInverted();
      double barL0 = Math.min(transL0, transL1);
      double barLength = Math.abs(transL1 - transL0);
      double barLengthAdj = 0.0;
      if (barLength > 0.0 && barLength < getMinimumBarLength()) {
        barLengthAdj = getMinimumBarLength() - barLength;
      }
      double barL0Adj = 0.0;
      RectangleEdge barBase;
      if (orientation == PlotOrientation.HORIZONTAL) {
        if (positive && inverted || !positive && !inverted) {
          barL0Adj = barLengthAdj;
          barBase = RectangleEdge.RIGHT;
        } else {
          barBase = RectangleEdge.LEFT;
        }
      } else {
        if (positive && !inverted || !positive && inverted) {
          barL0Adj = barLengthAdj;
          barBase = RectangleEdge.BOTTOM;
        } else {
          barBase = RectangleEdge.TOP;
        }
      }

      // draw the bar...
      RectangularShape bar = null;
      if (orientation == PlotOrientation.HORIZONTAL) {
        bar =
            getBarShape(
                row, barL0 - barL0Adj, barW0, barLength + barLengthAdj, state.getBarWidth());
      } else {
        bar =
            getBarShape(
                row, barW0, barL0 - barL0Adj, state.getBarWidth(), barLength + barLengthAdj);
      }

      if (getShadowsVisible()) {
        this.getBarPainter().paintBarShadow(g2, this, row, column, bar, barBase, true);
      }
      this.getBarPainter().paintBar(g2, this, row, column, bar, barBase);

      //          FIXME
      //            CategoryItemLabelGenerator generator = getItemLabelGenerator(row,
      //                    column);
      //            if (generator != null && isItemLabelVisible(row, column)) {
      //                drawItemLabel(g2, dataset, row, column, plot, generator, bar,
      //                        (value < 0.0));
      //            }

      // submit the current data point as a crosshair candidate
      int datasetIndex = plot.indexOf(dataset);
      updateCrosshairValues(
          state.getCrosshairState(),
          dataset.getRowKey(row),
          dataset.getColumnKey(column),
          value,
          datasetIndex,
          barW0,
          barL0,
          orientation);

      // add an item entity, if this information is being collected
      EntityCollection entities = state.getEntityCollection();
      if (entities != null) {
        addItemEntity(entities, dataset, row, column, bar);
      }
    }