java - 带值的 JavaFX 折线图
问题描述
我想在折线图顶部显示值。我已经看到这个答案非常有帮助,但它改变了折线图节点。我想要的是相同的想法,但不是在节点上显示值,而是在它们附近(可能在它们的右侧和上方)显示值,例如:
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);
}
解决方案
一种选择是为图表中Node
的每个设置自定义。Data
这是一个粗略的例子:
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;
}
}
在定位文本时,上述内容并没有做任何复杂的事情。例如,它不会考虑线条在哪里,也不会考虑某些文本是否被图表的剪辑截断。基本上,这是一个概念验证;结果如下:
向图表添加文本的其他一些可能选项包括:
- 将
LineChart
aGroup
或Pane
图表中的第一个孩子放在其中。然后,对于Data
图表中的每个,您将添加一个Label
orText
到父节点,并将其相对于Data
's 节点的位置(当它可用时)定位。Node#localToScene
您可以使用和等方法计算这些位置Node#sceneToLocal
。 - 子类
LineChart
化并将Text
orLabel
直接添加到图表中。由于我以前从未对图表进行子类化,因此我不确定如何实现此选项。 - 还有一些我没有想到的。
请注意,无论您做什么,如果您的图表有很多彼此非常接近的数据点,那么以视觉上令人愉悦的方式显示所有文本将是困难的——如果不是不可能的话。
推荐阅读
- ios - TextInput 在 multiline={false} 上对齐文本(带高度)
- python - 自定义标题栏图标 Windows 10
- php - Nginx try_files 提示下载 PHP
- ios - 在 CPU 上计算矩阵占用了大部分帧时间
- powershell - Set-PnPDefaultColumnValues 是否支持 SharePoint Online 文档库中的 DateTime 字段
- excel - Excel Worksheet_Change 未通过单元格值更新触发
- kotlin - 从字符串实例化 Kotlin 类
- typescript - TypeScript:创建一个没有可选属性的新界面
- python - 单击Selenium python中的按钮没有ID
- bash - configMap 的文件名在 Pod 中显示为 env