检测重叠的滴答标签

时间:2012-01-31 15:12:50

标签: java label jfreechart

Overlapping labels

正如您所看到的,当范围轴跨越大面积并且刻度标签太靠近时,它们开始重叠。我想实现某种逻辑来检测它们是否重叠,如果是,只显示一个首选(或适合的数量)。但是,我有点不确定如何实现这一目标。

逻辑将是这样的:

  1. 重要性后优先处理每个标签
  2. 掌握每个刻度标签(x,y,宽度,高度)的Java2d坐标
  3. 如果标签的区域与另一个区域重叠,则只显示最重要的区域
  4. 但是有哪些方法可以做到这一点?从我买的API文档中我找到了这个方法

    public double valueToJava2D(double value, Rectangle2D area, RectangleEdge edge);
    

    但是我需要提供这个功能的区域和边缘是什么?如果是一个勾选标签,我怎么能得到宽度和高度?这是正确的方法吗,还是有更好的方法可以带来成功?

1 个答案:

答案 0 :(得分:0)

我在JFree论坛上发布了这个问题(找到了trashgod)并得到了一些不错的提示there。我在那里发布的最终代码解决了我的问题如下:

@SuppressWarnings({"RawUseOfParameterizedType", "serial"})
private static class CustomTickMarkNumberAxis extends NumberAxis {
    private double[] customTicksSortedOnImportance;

    /**
     * A list ticks sorted after importance. In case of overlapping,
     * a higher ranked tick will trump a lower ranked tick, thus <i>not showing</i>
     * the lower ranked (overlapping) tick.
     * Other lower ranked ticks might still be shown, if they are not overlapping
     */
    public CustomTickMarkNumberAxis(double[] customTicksSortedOnImportance) {
        this.customTicksSortedOnImportance = customTicksSortedOnImportance;
    }

    protected List<NumberTick> refreshTicksVertical(Graphics2D g2, Rectangle2D dataArea, RectangleEdge edge) {
        List<NumberTick> result = new java.util.ArrayList<NumberTick>();

        //(... snip ...)

        Area tickLabelArea = new Area(); /** Used for overlap detection */
        for (int i = 0; i < customTicksSortedOnImportance.length; i++) {
            // The next lines of code are different from NumberAxis
            double currentTickValue = customTicksSortedOnImportance[i];
            currentTickValue = NumberUtil.round(currentTickValue, precision);

            //(... snip ...)

            /* Overlapping logic here */
            NumberTick numberTick = new NumberTick(currentTickValue, tickLabel, anchor, rotationAnchor, angle);
            Rectangle2D labelBounds = getTickBounds(numberTick, g2);
            double java2dValue = valueToJava2D(currentTickValue, g2.getClipBounds(), edge);
            labelBounds.setRect(labelBounds.getX(), java2dValue, labelBounds.getWidth(), labelBounds.getHeight());

            if (!tickLabelIsOverlapping(tickLabelArea, labelBounds)) {
                result.add(numberTick);
                tickLabelArea.add(new Area(labelBounds));
            }

            //(... snip ...)
        }
        return result;
    }

    private boolean tickLabelIsOverlapping(Area area, Rectangle2D rectangle) {
        return area.intersects(rectangle);
    }

    private Rectangle2D getTickBounds(NumberTick numberTick, Graphics2D g2) {
        FontMetrics fm = g2.getFontMetrics(getTickLabelFont());
        return TextUtilities.getTextBounds(numberTick.getText(), g2, fm);
    }
}