7

使用 JavaFX 图表,我需要反转堆积面积图的 y 轴,以便正零位于顶部,正数在 y 轴上向下工作。下面是我想要实现的目标的模型。

带正数的倒 Y 轴

在 JavaFX 中实现这一目标的最佳方式是什么(阅读:最短的开发时间和高代码重用)?

更新

将数据转换为负数不是一种选择。我正在寻找适用于“未触及”的正数的答案。

4

4 回答 4

3

您可以使用带有负值的常规轴,但添加TickLabelFormatter会去除减号的轴。

    final NumberAxis yAxis = new NumberAxis(-25, 0, 5);

    yAxis.setTickLabelFormatter(new NumberAxis.DefaultFormatter(yAxis) {
        @Override
        public String toString(Number value) {
            // note we are printing minus value
            return String.format("%7.1f", -value.doubleValue());
        }
    });

    series1.getData().add(new XYChart.Data("Jan", -1));
    series1.getData().add(new XYChart.Data("Feb", -5));
    series1.getData().add(new XYChart.Data("Mar", -20));
于 2013-08-06T13:36:12.087 回答
1

容易的选择是启用inverse()轴上的操作。如果不修补 JRE 类,它会非常复杂。

关于如何解决这个问题的一些提示:

1)扩展ValueAxis或Axis(不幸的是NumberAxis是最终的)

2)将布尔字段和inverse()方法添加到您的轴类

public void inverse() {
    inversed = !inversed; // boolean property
    invalidateRange();
    requestAxisLayout();
}

3)如果您扩展 ValueAxis - 您将需要补偿超类应用的偏移量(并截取轴大小发生变化的代码)

@Override
public Long getValueForDisplay(double displayPosition) {
    if (inversed)
        return super.getValueForDisplay(offset - displayPosition);
    else
        return super.getValueForDisplay(displayPosition);
}

@Override
public double getDisplayPosition(Long value) {
    if (inversed)
        return offset - super.getDisplayPosition(value);
    else
        return super.getDisplayPosition(value);
}

4)(最丑陋的部分)取消隐藏 Axis 类抑制的标签刻度 - 原始实现取决于默认的刻度顺序。除了通过反射解锁它之外,我没有找到任何其他方法。所以这是非常脆弱的。

@Override
protected void layoutChildren() {
    final Side side = getSide();
    boolean isHorisontal = null == side || side.isHorizontal();
    this.offset = isHorisontal ? getWidth() : getHeight();
    super.layoutChildren();
    if (inversed) {
        double prevEnd = isHorisontal ? offset + getTickLabelGap() : 0;
        for (TickMark m : getTickMarks()) {
            double position = m.getPosition();
            try {
                final Text textNode = (Text) textNodeField.get(m);
                final Bounds bounds = textNode.getLayoutBounds();
                if (0 <= position && position <= offset)
                    if (isHorisontal) {
                        textNode.setVisible(position < prevEnd);
                        prevEnd = position - (bounds.getWidth() + getTickLabelGap());
                    } else {
                        textNode.setVisible(position > prevEnd);
                        prevEnd = position + (bounds.getHeight() + getTickLabelGap());
                    }
            } catch (IllegalAccessException ignored) {
            }
        }
    }
}

在这个例子中 Y 轴是倒置的 这就是它的样子

于 2015-08-16T18:07:09.303 回答
0

@harshtuna 的回答略有更新,以避免反射部分。以下代码使用 OpenJFX 16 为我工作

@Override
protected void layoutChildren() {
    final Side side = getSide();
    boolean isHorizontal = null == side || side.isHorizontal();
    double offSetting = isHorizontal ? getWidth() : getHeight();

    super.layoutChildren();
    if (inversed) {
        double prevEnd = isHorizontal ? offSetting + getTickLabelGap() : 0;
        for (TickMark m : getTickMarks()) {
            double position = m.getPosition();
            try {
                if (0 <= position && position <= offSetting)
                    if (isHorizontal) {
                        m.setTextVisible(position < prevEnd);
                        prevEnd = position - (2 + getTickLabelGap());
                    } else {
                        m.setTextVisible(position > prevEnd);
                        prevEnd = position + (2 + getTickLabelGap());
                    }
            } catch (Exception ignored) {
                System.out.println("illegal...?");
            }
        }
    }
}   
于 2021-06-21T16:58:19.773 回答
-1

使用轴的属性lowerBoundupperBound。下界必须高于上界。以下是使用 fxml 的方法:

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>

<HBox         
    prefHeight="600.0" 
    prefWidth="800.0" 
    xmlns:fx="http://javafx.com/fxml/1">    

    <javafx.scene.chart.LineChart 
        fx:id="chart" >
        <xAxis >
            <javafx.scene.chart.NumberAxis 
                label="X Axis"
                lowerBound="0.01"
                upperBound="100"
                tickUnit="10"
                autoRanging="false" /> 
        </xAxis>
        <yAxis> 
            <javafx.scene.chart.NumberAxis 
                    label="Y Axis"
                    lowerBound="100"
                    upperBound="0.001"
                    tickUnit="10"
                    autoRanging="false"
                />
        </yAxis>
    </javafx.scene.chart.LineChart>            
</Hbox>
于 2016-09-04T07:10:37.300 回答