如何向JavaFX图表添加值标记?

如何向JavaFX图表添加值标记?,java,charts,javafx-2,javafx,Java,Charts,Javafx 2,Javafx,我正在尝试使用JavaFX构建一个系列图表,其中数据是动态插入的 每次插入一个新值时,我想检查这是否是迄今为止的最高值,如果是,我想画一条水平线来显示这是最大值 在JFree图表中,我会使用ValueMarker,但我正试图用JavaFX做同样的事情 我尝试使用Line对象,但它肯定不一样,因为我无法提供图表值,它在窗口中采用相对像素位置 下面是我想要实现的图表截图: 有什么建议吗? 谢谢。要将图表值转换为像素,可以使用返回图表节点实际坐标的方法NumberAxis#getDisplayPos

我正在尝试使用JavaFX构建一个系列图表,其中数据是动态插入的

每次插入一个新值时,我想检查这是否是迄今为止的最高值,如果是,我想画一条水平线来显示这是最大值

在JFree图表中,我会使用ValueMarker,但我正试图用JavaFX做同样的事情

我尝试使用Line对象,但它肯定不一样,因为我无法提供图表值,它在窗口中采用相对像素位置

下面是我想要实现的图表截图:

有什么建议吗?
谢谢。

要将图表值转换为像素,可以使用返回图表节点实际坐标的方法
NumberAxis#getDisplayPosition()

虽然这些坐标是相对于图表区域的,但您可以通过下面的代码找到:

Node chartArea = chart.lookup(".chart-plot-background");
Bounds chartAreaBounds = chartArea.localToScene(chartArea.getBoundsInLocal());
注意
localToScene()
方法,该方法允许您将任何坐标转换为场景坐标。因此,您可以使用它们来更新值标记坐标。确保在场景显示后进行
localToScene
调用

请参阅下面生成下一张图表的示例程序:

public class LineChartValueMarker extends Application {

    private Line valueMarker = new Line();
    private XYChart.Series<Number, Number> series = new XYChart.Series<>();
    private NumberAxis yAxis;
    private double yShift;

    private void updateMarker() {
        // find maximal y value
        double max = 0;
        for (Data<Number, Number> value : series.getData()) {
            double y = value.getYValue().doubleValue();
            if (y > max) {
                max = y;
            }
        }
        // find pixel position of that value
        double displayPosition = yAxis.getDisplayPosition(max);
        // update marker
        valueMarker.setStartY(yShift + displayPosition);
        valueMarker.setEndY(yShift + displayPosition);
    }

    @Override
    public void start(Stage stage) {
        LineChart<Number, Number> chart = new LineChart<>(new NumberAxis(0, 100, 10), yAxis = new NumberAxis(0, 100, 10));

        series.getData().add(new XYChart.Data(0, 0));
        series.getData().add(new XYChart.Data(10, 20));

        chart.getData().addAll(series);
        Pane pane = new Pane();
        pane.getChildren().addAll(chart, valueMarker);
        Scene scene = new Scene(pane);

        // add new value on mouseclick for testing
        chart.setOnMouseClicked(new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent t) {
                series.getData().add(new XYChart.Data(series.getData().size() * 10, 30 + 50 * new Random().nextDouble()));
                updateMarker();
            }
        });

        stage.setScene(scene);
        stage.show();

        // find chart area Node
        Node chartArea = chart.lookup(".chart-plot-background");
        Bounds chartAreaBounds = chartArea.localToScene(chartArea.getBoundsInLocal());
        // remember scene position of chart area
        yShift = chartAreaBounds.getMinY();
        // set x parameters of the valueMarker to chart area bounds
        valueMarker.setStartX(chartAreaBounds.getMinX());
        valueMarker.setEndX(chartAreaBounds.getMaxX());
        updateMarker();
    }

    public static void main(String[] args) {
        launch();
    }
}

公共类LineChartValueMarker扩展应用程序{
专用行valueMarker=新行();
私有XYChart.Series系列=新的XYChart.Series();
私人号码xis yAxis;
私人双Y档;
私有void updateMarker(){
//求最大y值
双最大值=0;
for(数据值:series.getData()){
双y=value.getYValue().doubleValue();
如果(y>最大值){
max=y;
}
}
//查找该值的像素位置
双显示位置=yAxis.getDisplayPosition(最大值);
//更新标记
valueMarker.setStartY(YSShift+显示位置);
valueMarker.setEndY(YSShift+显示位置);
}
@凌驾
公众假期开始(阶段){
线形图=新线形图(新编号轴(0,100,10),yAxis=新编号轴(0,100,10));
series.getData().add(新的XYChart.Data(0,0));
series.getData().add(新的XYChart.Data(10,20));
chart.getData().addAll(系列);
窗格=新窗格();
pane.getChildren().addAll(图表、valueMarker);
场景=新场景(窗格);
//在鼠标上添加新值单击以进行测试
setOnMouseClicked(新的EventHandler(){
@凌驾
公共无效句柄(MouseEvent t){
series.getData().add(新的XYChart.Data(series.getData().size()*10,30+50*新的Random().nextDouble());
updateMarker();
}
});
舞台场景;
stage.show();
//查找图表区域节点
节点chartArea=chart.lookup(“.chart-plot-background”);
Bounds chartAreaBounds=chartArea.localToScene(chartArea.getBoundsInLocal());
//记住图表区域的场景位置
yShift=chartAreaBounds.getMinY();
//将valueMarker的x参数设置为图表区域边界
valueMarker.setStartX(chartAreaBounds.getMinX());
valueMarker.setEndX(chartAreaBounds.getMaxX());
updateMarker();
}
公共静态void main(字符串[]args){
发射();
}
}

btw,对代码进行了一些修改,以应对可调整大小的父级,因为此类支持应由图表本身处理:)在所有环境更改中更新标记可能会很麻烦(除了大小/位置更改,请考虑禁用f.i.)哦,但您不能期望软件支持所有功能。我要说的是,这张图表很容易用新功能进行扩展。