具有值的 JavaFX 折线图

标签 java javafx charts linechart

我想在折线图的顶部显示值。我看过this answer这很有帮助,但它改变了折线图节点。我想要的是相同的想法,但不在节​​点上显示值,而是在它们附近(可能在它们的右侧和上方)显示值,例如:

     53
    O
   / \
  /   \
 /42   \ 21           21
O       O------------O

编辑:

我尝试在下面编写代码,但遗憾的是只出现了线条,没有显示节点。

for (int index = 0; index < value.getData().size(); index++) {
                XYChart.Data dataPoint = value.getData().get(index);
                Node lineSymbol = dataPoint.getNode().lookup(".chart-line-symbol");
                lineSymbol.setStyle("-fx-background-color: " + definedColor + " , white;");

                Label label = new Label(value.getName());
                label.toFront();
                Pane nodeWithText = new Pane();
                label.setStyle("-fx-font-size: 20; -fx-font-weight: bold;");
                StackPane stackPane = new StackPane();
                Group group = new Group(label);
                group.getChildren().add(lineSymbol);
                group.toFront();
                group.setLayoutX(-10);
                group.setLayoutY(-30);
                StackPane.setAlignment(group, Pos.TOP_RIGHT);
                StackPane.setMargin(group,new Insets(0,0,5,0));
                nodeWithText.getChildren().add(group);
                nodeWithText.getChildren().add(lineSymbol);
                dataPoint.setNode(nodeWithText);
}

最佳答案

一个选项是为图表中的每个Data 设置自定义Node。这是一个粗略的例子:

import javafx.application.Application;
import javafx.beans.binding.ObjectExpression;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.chart.LineChart;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart.Data;
import javafx.scene.chart.XYChart.Series;
import javafx.scene.control.Label;
import javafx.scene.layout.Pane;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;

public class Main extends Application {

    @Override
    public void start(Stage primaryStage) {
        var chart = new LineChart<>(new NumberAxis(), new NumberAxis());
        chart.getData().add(new Series<>(createData()));

        primaryStage.setScene(new Scene(chart, 600, 400));
        primaryStage.show();
    }

    private static ObservableList<Data<Number, Number>> createData() {
        var list = FXCollections.<Data<Number, Number>>observableArrayList();
        for (int x = 0; x < 10; x++) {
            var data = new Data<Number, Number>(x, Math.pow(x, 2));
            data.setNode(createDataNode(data.YValueProperty()));
            list.add(data);
        }
        return list;
    }

    private static Node createDataNode(ObjectExpression<Number> value) {
        var label = new Label();
        label.textProperty().bind(value.asString("%,.2f"));

        var pane = new Pane(label);
        pane.setShape(new Circle(6.0));
        pane.setScaleShape(false);

        label.translateYProperty().bind(label.heightProperty().divide(-1.5));

        return pane;
    }

}

在定位文本时,上面的代码并没有做任何复杂的事情。例如,它不会考虑线条的位置,也不会考虑某些文本是否被图表的剪辑截断。基本上,这是一个概念验证;结果看起来像:

image showing result of example

向图表添加文本的一些其他可能选项包括:

  1. LineChart 放在 GroupPane 中,其中图表是第一个子项。然后,对于图表中的每个 Data,您将向父级添加一个 LabelText 并将其定位到相对于Data 的节点(当它可用时)。您可以使用 Node#localToSceneNode#sceneToLocal 等方法计算这些位置。
  2. 子类 LineChart 并直接将 TextLabel 添加到图表中。由于我以前从未对图表进行子类化,因此我不确定如何实现此选项。
  3. 我没有想到的其他事情。

请注意,无论您做什么,如果您的图表中有很多数据点彼此非常接近,那么以视觉上令人愉悦的方式显示所有文本将很困难——如果不是不可能的话。

关于具有值的 JavaFX 折线图,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55946240/

相关文章:

java - 按键事件未触发

java - @FXML 自定义组件注入(inject)不会实例化 Controller 中的变量并导致 NullPointerException

javascript - 格式化饼图的工具提示

html - 我可以将图表从网页导出为 PDF 格式吗?

java - MySQL 中 SUM 结果的数据类型

java - 有没有一种方法可以使用嵌入式数据库来测试 Postgres Jsonb 查询以进行单元测试?

html - 是否可以在不使用 Javascript 的情况下检索 Web 引擎中的 HTML 元素?

javascript - 如何为nvd3.js图表​​绘制上限

java - Spring Boot 1.4 @DataJpaTest - 创建名称为 'dataSource' 的 bean 时出错

java - Android工具栏的文字大小和样式