@Override
 public ChartView.Element getElementAt(int x, int y) {
   ChartView.Element element = new ChartView.Element(0, 0);
   ChartEntity chartEntity = getChartEntityAt(x, y);
   if (chartEntity instanceof CategoryItemEntity) {
     CategoryItemEntity categoryItemEntity = (CategoryItemEntity) chartEntity;
     CategoryDataset dataset = categoryItemEntity.getDataset();
     String columnKey = (String) categoryItemEntity.getColumnKey();
     int columnIndex = dataset.getColumnIndex(columnKey);
     String rowKey = (String) categoryItemEntity.getRowKey();
     int rowIndex = dataset.getRowIndex(rowKey);
     element = new ChartView.Element(rowIndex, columnIndex);
   } else if (chartEntity instanceof XYItemEntity) {
     XYItemEntity xyItemEntity = (XYItemEntity) chartEntity;
     element = new ChartView.Element(xyItemEntity.getSeriesIndex(), xyItemEntity.getItem());
   }
   return element;
 }
  /**
   * Returns the middle coordinate (in Java2D space) for a series within a category.
   *
   * @param category the category (<code>null</code> not permitted).
   * @param seriesKey the series key (<code>null</code> not permitted).
   * @param dataset the dataset (<code>null</code> not permitted).
   * @param itemMargin the item margin (0.0 <= itemMargin < 1.0);
   * @param area the area (<code>null</code> not permitted).
   * @param edge the edge (<code>null</code> not permitted).
   * @return The coordinate in Java2D space.
   * @since 1.0.7
   */
  public double getCategorySeriesMiddle(
      Comparable category,
      Comparable seriesKey,
      CategoryDataset dataset,
      double itemMargin,
      Rectangle2D area,
      RectangleEdge edge) {

    int categoryIndex = dataset.getColumnIndex(category);
    int categoryCount = dataset.getColumnCount();
    int seriesIndex = dataset.getRowIndex(seriesKey);
    int seriesCount = dataset.getRowCount();
    double start = getCategoryStart(categoryIndex, categoryCount, area, edge);
    double end = getCategoryEnd(categoryIndex, categoryCount, area, edge);
    double width = end - start;
    if (seriesCount == 1) {
      return start + width / 2.0;
    }
    double gap = (width * itemMargin) / (seriesCount - 1);
    double ww = (width * (1 - itemMargin)) / seriesCount;
    return start + (seriesIndex * (ww + gap)) + ww / 2.0;
  }
  /**
   * Draws a marker for the domain axis.
   *
   * @param g2 the graphics device (not <code>null</code>).
   * @param plot the plot (not <code>null</code>).
   * @param axis the range axis (not <code>null</code>).
   * @param marker the marker to be drawn (not <code>null</code>).
   * @param dataArea the area inside the axes (not <code>null</code>).
   */
  public void drawDomainMarker(
      Graphics2D g2,
      CategoryPlot plot,
      CategoryAxis axis,
      CategoryMarker marker,
      Rectangle2D dataArea) {

    Comparable category = marker.getKey();
    CategoryDataset dataset = plot.getDataset(plot.getIndexOf(this));
    int columnIndex = dataset.getColumnIndex(category);
    if (columnIndex < 0) {
      return;
    }
    PlotOrientation orientation = plot.getOrientation();
    Rectangle2D bounds = null;
    if (marker.getDrawAsLine()) {
      double v =
          axis.getCategoryMiddle(
              columnIndex, dataset.getColumnCount(),
              dataArea, plot.getDomainAxisEdge());
      Line2D line = null;
      if (orientation == PlotOrientation.HORIZONTAL) {
        line = new Line2D.Double(dataArea.getMinX(), v, dataArea.getMaxX(), v);
      } else if (orientation == PlotOrientation.VERTICAL) {
        line = new Line2D.Double(v, dataArea.getMinY(), v, dataArea.getMaxY());
      }

      g2.setPaint(marker.getPaint());
      g2.setStroke(marker.getStroke());
      g2.draw(line);
      bounds = line.getBounds2D();
    } else {
      double v0 =
          axis.getCategoryStart(
              columnIndex, dataset.getColumnCount(),
              dataArea, plot.getDomainAxisEdge());
      double v1 =
          axis.getCategoryEnd(
              columnIndex, dataset.getColumnCount(),
              dataArea, plot.getDomainAxisEdge());
      Rectangle2D area = null;
      if (orientation == PlotOrientation.HORIZONTAL) {
        area = new Rectangle2D.Double(dataArea.getMinX(), v0, dataArea.getWidth(), (v1 - v0));
      } else if (orientation == PlotOrientation.VERTICAL) {
        area = new Rectangle2D.Double(v0, dataArea.getMinY(), (v1 - v0), dataArea.getHeight());
      }
      g2.setPaint(marker.getPaint());
      g2.fill(area);
      bounds = area;
    }

    String label = marker.getLabel();
    RectangleAnchor anchor = marker.getLabelAnchor();
    if (label != null) {
      Font labelFont = marker.getLabelFont();
      g2.setFont(labelFont);
      g2.setPaint(marker.getLabelPaint());
      Point2D coordinates =
          calculateDomainMarkerTextAnchorPoint(
              g2,
              orientation,
              dataArea,
              bounds,
              marker.getLabelOffset(),
              marker.getLabelOffsetType(),
              anchor);
      TextUtilities.drawAlignedString(
          label,
          g2,
          (float) coordinates.getX(),
          (float) coordinates.getY(),
          marker.getLabelTextAnchor());
    }
  }