在JavaFX图表中添加一行

时间:2014-06-15 18:46:12

标签: java javafx-2 java-8 javafx-8

我在JavaFX中的定义位置添加一行时遇到问题。该行必须是一条恒定线,如下所示:How to add a value marker to JavaFX chart?

我的问题是,我的布局定义有点复杂。看看:

chart

重要的部分是顶部的那个。我希望在y = 60线上有这条线。 RadioBoxes的左侧部分是VBox。带有(Scatter-)图表的部分是StackPane(因为我希望它填充宽度的其余部分)。 StackPane内部是图表和组。该集团唯一的子女就是这条线。

我认为问题在于,StackPane将集团的中心放在图表上方。但我无法得到布局的组合 1.拉伸图表 2.将线设置在图表上方 3.不使线居中

我尝试了很多组合,但我不能按照我想要的方式得到它。有人有想法吗?!

2 个答案:

答案 0 :(得分:6)

不幸的是,XYCharts不支持ValueMarkers(可能在层次结构中应该这样做的地方)(Mis-)使用具有常量值的数据是可能(或不可)接受的黑客攻击/可能在某些情况下。

更清洁的出路是支持此类标记的自定义图表。 F.i.一个自定义的ScatterChart,如:

public class ScatterXChart<X, Y> extends ScatterChart<X, Y> {

    // data defining horizontal markers, xValues are ignored
    private ObservableList<Data<X, Y>> horizontalMarkers;

    public ScatterXChart(Axis<X> xAxis, Axis<Y> yAxis) {
        super(xAxis, yAxis);
        // a list that notifies on change of the yValue property
        horizontalMarkers = FXCollections.observableArrayList(d -> new Observable[] {d.YValueProperty()});
        // listen to list changes and re-plot
        horizontalMarkers.addListener((InvalidationListener)observable -> layoutPlotChildren());
    }

    /**
     * Add horizontal value marker. The marker's Y value is used to plot a
     * horizontal line across the plot area, its X value is ignored.
     * 
     * @param marker must not be null.
     */
    public void addHorizontalValueMarker(Data<X, Y> marker) {
        Objects.requireNonNull(marker, "the marker must not be null");
        if (horizontalMarkers.contains(marker)) return;
        Line line = new Line();
        marker.setNode(line );
        getPlotChildren().add(line);
        horizontalMarkers.add(marker);
    }

    /**
     * Remove horizontal value marker.
     * 
     * @param horizontalMarker must not be null
     */
    public void removeHorizontalValueMarker(Data<X, Y> marker) {
        Objects.requireNonNull(marker, "the marker must not be null");
        if (marker.getNode() != null) {
            getPlotChildren().remove(marker.getNode());
            marker.setNode(null);
        }
        horizontalMarkers.remove(marker);
    }

    /**
     * Overridden to layout the value markers.
     */
    @Override
    protected void layoutPlotChildren() {
        super.layoutPlotChildren();
        for (Data<X, Y> horizontalMarker : horizontalMarkers) {
            double lower = ((ValueAxis) getXAxis()).getLowerBound();
            X lowerX = getXAxis().toRealValue(lower);
            double upper = ((ValueAxis) getXAxis()).getUpperBound();
            X upperX = getXAxis().toRealValue(upper);
            Line line = (Line) horizontalMarker.getNode();
            line.setStartX(getXAxis().getDisplayPosition(lowerX));
            line.setEndX(getXAxis().getDisplayPosition(upperX));
            line.setStartY(getYAxis().getDisplayPosition(horizontalMarker.getYValue()));
            line.setEndY(line.getStartY());

        }
    }
}

测试图表的片段(f.i.插入oracle教程中的在线示例):

// instantiate chart
NumberAxis xAxis = new NumberAxis(0, 10, 1);
NumberAxis yAxis = new NumberAxis(-100, 500, 100);        
ScatterXChart<Number,Number> sc = new ScatterXChart<>(xAxis,yAxis);
// .. fill with some data
...
// ui to add/change/remove a value marker
Data<Number, Number> horizontalMarker = new Data<>(0, 110);
Button add = new Button("Add Marker");  
add.setOnAction(e -> sc.addHorizontalValueMarker(horizontalMarker));
Slider move = new Slider(yAxis.getLowerBound(), yAxis.getUpperBound(), 0);
move.setShowTickLabels(true);
move.valueProperty().bindBidirectional(horizontalMarker.YValueProperty());
Button remove = new Button("Remove Marker");
remove.setOnAction(e -> sc.removeHorizontalValueMarker(horizontalMarker));

附录:

虽然我不推荐approach in the related question(将标记线添加到图表的父级并在外部管理其位置/长度),但 可以使用它在可调整大小的容器中。让它发挥作用的关键因素是:

  • 聆听图表的尺寸/位置变化并适当更新线
  • 将标记的托管属性设置为false
代码中的

(updateShift是原始中计算yShift / lineX的部分):

Pane pane = new StackPane(chart);
chart.widthProperty().addListener(o -> updateShift(chart));
chart.heightProperty().addListener(o -> updateShift(chart));
valueMarker.setManaged(false);
pane.getChildren().add(valueMarker);

答案 1 :(得分:1)

为什么不在图表中添加该行?我有图表,我显示100,99,95和50百分位数,我解决这个问题的方法是为每个百分位数的正确y值添加一条线。

要做到这一点,只需添加一条有两个点的线,一个在y = 60 x = 70(最左边的x轴值),另一个在y = 60和x = 120(最右边) x轴值)。

这样做的好处是你不必亲自手动对齐水平线,缺点是这条水平线也将成为图例的一部分。但是,看到你没有一个应该没问题的传奇。

如果您决定添加图例,请务必正确命名水平线,l