在JavaFx BarChart中显示垂直线

时间:2018-10-25 22:01:38

标签: javafx bar-chart

我正在使用JavaFx BarChart显示直方图,xAxis是CategoryAxis,我想显示两条与平均值和中位数相对应的垂直线,如this picture

谢谢

1 个答案:

答案 0 :(得分:0)

您必须将图表放入Pane内,并将Lines添加为同一Pane的更多子元素。然后,诀窍是如何找到在何处绘制Lines:为此,您必须使用CSS查找(.lookup(".chart-plot-background");)查找图表区域,并向图表轴询问特定值将在哪里绘制(Axis().getDisplayPosition())。 这是一个完整的示例:

package so_52998721;

import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.geometry.Bounds;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.chart.BarChart;
import javafx.scene.chart.CategoryAxis;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart;
import javafx.scene.layout.Pane;
import javafx.scene.shape.Line;
import javafx.stage.Stage;

/**
 *
 * @author ced04u
 */
public class SO_52998721 extends Application {

    private XYChart<String, Number> barChart;
    final private Line horizontalLine = new Line();
    final private Line verticalLine = new Line();

    @Override
    public void start(Stage primaryStage) {

        Pane root = new Pane();
        barChart = new BarChart<>(
                new CategoryAxis(),
                new NumberAxis(0, 100, 5));

        root.getChildren().addAll(barChart, horizontalLine, verticalLine);

        barChart.setMaxWidth(Double.MAX_VALUE);
        barChart.prefWidthProperty().bind(root.widthProperty());
        barChart.prefHeightProperty().bind(root.heightProperty());

        //populate barchart with some data
        barChart.getData().add(new XYChart.Series(
                FXCollections.observableArrayList(new XYChart.Data("pizza", 80.0),
                        new XYChart.Data("spaghetti", 50.0),
                        new XYChart.Data("mozzarella", 30.0)
                )
        ));

        //lines have to be updated every time the chart size changes
        barChart.boundsInLocalProperty().addListener(new ChangeListener<Bounds>() {
            @Override
            public void changed(ObservableValue<? extends Bounds> observable, Bounds oldValue, Bounds newValue) {
                Platform.runLater(() -> {
                    updateLines();
                });
            }
        });

        updateLines();

        Scene scene = new Scene(root, 1024, 768);

        primaryStage.setScene(scene);
        primaryStage.show();
    }

    private void updateLines() {

        // find chart area Node
        Node chartArea = barChart.lookup(".chart-plot-background");
        // remember scene position of chart area
        Bounds chartAreaBounds = chartArea.localToParent(chartArea.getBoundsInLocal());

        //******** horizontal line ******************
        horizontalLine.setStartX(chartAreaBounds.getMinX());
        horizontalLine.setEndX(chartAreaBounds.getMaxX());
        final double averageValue = (80 + 50 + 30) / 3;
        double yShift = chartAreaBounds.getMinY();
        // find pixel position of the specified value
        final double medianPosition = barChart.getYAxis().getDisplayPosition(averageValue);
        horizontalLine.setStartY(yShift + medianPosition);
        horizontalLine.setEndY(yShift + medianPosition);

        //******** vertical line ******************
        verticalLine.setStartY(chartAreaBounds.getMinY());
        verticalLine.setEndY(chartAreaBounds.getMaxY());
        double xShift = chartAreaBounds.getMinX();
        // find pixel position of the specified value
        final double mozzarellaPosition = barChart.getXAxis().getDisplayPosition("mozzarella");
        verticalLine.setStartX(xShift + mozzarellaPosition);
        verticalLine.setEndX(xShift + mozzarellaPosition);

    }

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        launch(args);
    }

}