9

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

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

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

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

这是我想要实现的图表截图:

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

有什么建议么?谢谢你。

4

1 回答 1

15

要将图表值转换为像素,您可以使用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();
    }
}
于 2013-03-28T13:55:31.320 回答