Display additional values in Pie chart

2019-04-02 00:56发布

I have this example of Pie chart data:

import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.concurrent.Task;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.chart.PieChart;
import javafx.scene.chart.PieChart.Data;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.Label;
import javafx.scene.control.MenuItem;
import javafx.scene.effect.Glow;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
import javafx.scene.paint.Color;
import javafx.stage.Stage;

public class MainApp extends Application
{

    Stage stage;

    PieChart chart;
    ObservableList<Data> pieChartData = FXCollections.observableArrayList();
    Label caption;

    @Override
    public void start(Stage stage)
    {

        this.stage = stage;

        setUserAgentStylesheet(STYLESHEET_CASPIAN);
        Scene scene = new Scene(new Group());
        stage.setTitle("Imported Fruits");
        stage.setWidth(500);
        stage.setHeight(500);

        chart = new PieChart(pieChartData);
        chart.setTitle("Imported Fruits");

        // Add some data
        addPieChartData("Grapefruit", 13);
        addPieChartData("Oranges", 25);
        addPieChartData("Plums", 10);
        addPieChartData("Pears", 22);
        addPieChartData("Apples", 30);

        // Some task which updates the Pie Chart
        final Task task;
        task = new Task<Void>()
        {
            @Override
            protected Void call() throws Exception
            {
                int max = 50;
                int l = 0;
                for (int i = 1; i <= max; i++)
                {

                    updatePieChartData("Grapefruit", l++);
                    updatePieChartData("Oranges", l++);

                    Thread.sleep(600);
                }
                return null;
            }
        };

        new Thread(task).start();

        ((Group) scene.getRoot()).getChildren().addAll(chart, caption);
        stage.setScene(scene);
        stage.show();
    }

    public void addPieChartData(String name, double value)
    {
        pieChartData.add(new Data(name, value));

        caption = new Label();
        caption.setTextFill(Color.DARKORANGE);
        caption.setStyle("-fx-font: 24 arial;");

        for (final Data data : chart.getData())
        {

            Node node = data.getNode();

            node.addEventHandler(MouseEvent.MOUSE_MOVED, new EventHandler<MouseEvent>()
            {
                @Override
                public void handle(MouseEvent e)
                {
                    caption.setTranslateX(e.getSceneX() + 15);
                    caption.setTranslateY(e.getSceneY());
                    caption.setText(String.valueOf(data.getPieValue()) + "%");
                    caption.setVisible(true);
                    node.setEffect(new Glow());
                    //String styleString = "-fx-border-color: white; -fx-border-width: 1; -fx-border-style: dashed;";
                    //node.setStyle(styleString);
                }
            });

            node.addEventHandler(MouseEvent.MOUSE_EXITED, new EventHandler<MouseEvent>()
            {
                @Override
                public void handle(MouseEvent e)
                {
                    caption.setVisible(false);
                    node.setEffect(null);
                    //node.setStyle("");
                }
            });

            final MenuItem resizeItem = new MenuItem("Resize");
            resizeItem.setOnAction(new EventHandler<ActionEvent>()
            {
                @Override
                public void handle(ActionEvent event)
                {
                    System.out.println("Resize requested");
                }
            });

            final MenuItem aboutItem = new MenuItem("About");
            aboutItem.setOnAction(new EventHandler<ActionEvent>()
            {
                @Override
                public void handle(ActionEvent event)
                {
                    System.out.println("About requested");
                }
            });

            final MenuItem changeColorItem = new MenuItem("Change Color");
            changeColorItem.setOnAction(new EventHandler<ActionEvent>()
            {
                @Override
                public void handle(ActionEvent event)
                {
                    System.out.println("change Color Item requested");

                }
            });

            final ContextMenu menu = new ContextMenu(resizeItem, aboutItem, changeColorItem);

            node.setOnMouseClicked(new EventHandler<MouseEvent>()
            {
                @Override
                public void handle(MouseEvent event)
                {
                    if (MouseButton.SECONDARY.equals(event.getButton()))
                    {
                        menu.show(stage, event.getScreenX(), event.getScreenY());
                    }
                }
            });

        }
    }

    // updates existing Data-Object if name matches
    public void updatePieChartData(String name, double value)
    {
        for (Data d : pieChartData)
        {
            if (d.getName().equals(name))
            {
                d.setPieValue(value);
                return;
            }
        }
        addPieChartData(name, value);
    }

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

Is there any way similar to tickLabelFormatter in Line chart to display additional values in Pie chart names?

I want to display each Pie slice with names and number.

2条回答
地球回转人心会变
2楼-- · 2019-04-02 01:31

If you have changing values (like in the example code) and/or want to avoid displaying the values in the chart legend, you could modify the text label instead of changing the data names.

Each data item has a text node that holds the string which is shown as the pie chart label. This string can be updated before the chart children are drawn by overriding PieChart#layoutChartChildren:

chart = new PieChart(pieChartData) {
  @Override
  protected void layoutChartChildren(double top, double left, double contentWidth, double contentHeight) {
    if (getLabelsVisible()) {
      getData().forEach(d -> {
        Optional<Node> opTextNode = chart.lookupAll(".chart-pie-label").stream().filter(n -> n instanceof Text && ((Text) n).getText().contains(d.getName())).findAny();
        if (opTextNode.isPresent()) {
          ((Text) opTextNode.get()).setText(d.getName() + " " + d.getPieValue() + " Tons");
        }
      });
    }
    super.layoutChartChildren(top, left, contentWidth, contentHeight);
  }
};

animated chart with changing value in label

查看更多
我欲成王,谁敢阻挡
3楼-- · 2019-04-02 01:34

Just bind the pie chart data name to the required value.

pieChartData.forEach(data ->
        data.nameProperty().bind(
                Bindings.concat(
                        data.getName(), " ", data.pieValueProperty(), " Tons"
                )
        )
);

add info

import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.collections.*;
import javafx.scene.Scene;
import javafx.stage.Stage;
import javafx.scene.chart.*;
import javafx.scene.Group;

public class PieChartSample extends Application {

    @Override public void start(Stage stage) {
        Scene scene = new Scene(new Group());
        stage.setTitle("Imported Fruits");
        stage.setWidth(500);
        stage.setHeight(500);

        ObservableList<PieChart.Data> pieChartData =
                FXCollections.observableArrayList(
                new PieChart.Data("Grapefruit", 13),
                new PieChart.Data("Oranges", 25),
                new PieChart.Data("Plums", 10),
                new PieChart.Data("Pears", 22),
                new PieChart.Data("Apples", 30));
        final PieChart chart = new PieChart(pieChartData);
        chart.setTitle("Imported Fruits");

        pieChartData.forEach(data ->
                data.nameProperty().bind(
                        Bindings.concat(
                                data.getName(), " ", data.pieValueProperty(), " Tons"
                        )
                )
        );

        ((Group) scene.getRoot()).getChildren().add(chart);
        stage.setScene(scene);
        stage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}
查看更多
登录 后发表回答