如何在JavaFX图表中添加值标记?

时间:2013-03-25 13:14:15

标签: java charts javafx-2 javafx

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

每次插入新值时,我想检查这是否是目前为止的最高值,如果是,我想绘制一条水平线以显示这是最大值。

在JFree图表中,我会使用ValueMarker,但我也尝试使用JavaFX。

我尝试使用Line对象,但它绝对不一样,因为我无法提供Chart值,它需要窗口中的相对像素位置。

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

http://postimg.org/image/s5fkupsuz/

有什么建议吗? 谢谢。

1 个答案:

答案 0 :(得分:15)

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

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

Node chartArea = chart.lookup(".chart-plot-background");
Bounds chartAreaBounds = chartArea.localToScene(chartArea.getBoundsInLocal());

注意localToScene()方法,它允许您将任何坐标转换为场景坐标。因此,您可以使用它们来更新值标记坐标。确保在场景播放后进行localToScene调用。

请参阅下面的示例程序,该程序将生成下一个图表:

enter image description here

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();
    }
}