JavaFX 面积图并在光标后添加动态标签

Posted

技术标签:

【中文标题】JavaFX 面积图并在光标后添加动态标签【英文标题】:JavaFX Area Charts and adding dynamic labels following cursor 【发布时间】:2015-03-20 17:51:58 【问题描述】:

我希望能够在光标后的图表中添加标签。我已经在堆栈溢出中看到了几个这样的例子,它们将标签附加到一系列的值/节点,但我希望能够对整个区域图执行此操作。当我想添加一个标签(最终是一个浮动的值框)时,我的问题就来了。我正在努力弄清楚如何做到这一点并保持场景的布局。当我将图表作为专用项目添加到场景中时,图表会按预期呈现。但是当我向场景添加标签时,它会被共享并且图表不再填满整个画布

Group root = new Group();
root.getChildren().addAll(sac,myLabel);
Scene scene = new Scene(root, 800, 600); // Now the Chart shares the scene with the label

我想添加标签,以便在鼠标移动到图表上时使用它,然后简单地将其转换到光标位置。我对鼠标事件没有任何问题,只是我似乎无法与瞬态对象共享场景。我认为这是由于对如何管理这种特殊情况缺乏了解。这个问题的解决方案很可能是动态生成这个标签,而不是将它作为静态场景对象。感谢您提供任何帮助。

下面的完整测试用例(Java 8)

import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.StackedAreaChart;
import javafx.scene.chart.XYChart;
import javafx.scene.control.Label;
import javafx.scene.input.MouseEvent;
import javafx.stage.Stage;

public class AreaChartTestCase extends Application 

    final NumberAxis xAxis = new NumberAxis(1, 31, 1);
    final NumberAxis yAxis = new NumberAxis();
    final StackedAreaChart<Number, Number> sac
            = new StackedAreaChart<Number, Number>(xAxis, yAxis);
    Label myLabel = new Label();

    @Override
    public void start(Stage stage) 
        stage.setTitle("Area Chart Sample");
        sac.setTitle("Temperature Monitoring (in Degrees C)");
        XYChart.Series<Number, Number> seriesApril
                = new XYChart.Series<Number, Number>();
        seriesApril.setName("April");
        seriesApril.getData().add(new XYChart.Data(1, 4));
        seriesApril.getData().add(new XYChart.Data(3, 10));
        seriesApril.getData().add(new XYChart.Data(6, 15));
        seriesApril.getData().add(new XYChart.Data(9, 8));
        seriesApril.getData().add(new XYChart.Data(12, 5));
        seriesApril.getData().add(new XYChart.Data(15, 18));
        seriesApril.getData().add(new XYChart.Data(18, 15));
        seriesApril.getData().add(new XYChart.Data(21, 13));
        seriesApril.getData().add(new XYChart.Data(24, 19));
        seriesApril.getData().add(new XYChart.Data(27, 21));
        seriesApril.getData().add(new XYChart.Data(30, 21));
        XYChart.Series<Number, Number> seriesMay
                = new XYChart.Series<Number, Number>();
        seriesMay.setName("May");
        seriesMay.getData().add(new XYChart.Data(1, 20));
        seriesMay.getData().add(new XYChart.Data(3, 15));
        seriesMay.getData().add(new XYChart.Data(6, 13));
        seriesMay.getData().add(new XYChart.Data(9, 12));
        seriesMay.getData().add(new XYChart.Data(12, 14));
        seriesMay.getData().add(new XYChart.Data(15, 18));
        seriesMay.getData().add(new XYChart.Data(18, 25));
        seriesMay.getData().add(new XYChart.Data(21, 25));
        seriesMay.getData().add(new XYChart.Data(24, 23));
        seriesMay.getData().add(new XYChart.Data(27, 26));
        seriesMay.getData().add(new XYChart.Data(31, 26));

        final Node chartPlotBackground = sac.lookup(".chart-plot-background");
        chartPlotBackground.setOnMouseEntered((MouseEvent mouseEvent) -> 
            myLabel.setVisible(true);
        );

        chartPlotBackground.setOnMouseExited((MouseEvent mouseEvent) -> 
            myLabel.setVisible(false);
        );

        chartPlotBackground.setOnMouseMoved((MouseEvent mouseEvent) -> 
            myLabel.setText("Location : X = " + mouseEvent.getSceneX() + " : Y = "+ mouseEvent.getSceneY());
            myLabel.setTranslateX(mouseEvent.getSceneX());
            myLabel.setTranslateY(mouseEvent.getSceneY());
        );

        Group root = new Group();
        root.getChildren().addAll(sac, myLabel);
        Scene scene = new Scene(root, 800, 600); // Now the Chart shares the scene with the label
        sac.getData().addAll(seriesApril, seriesMay);
        stage.setScene(scene);
        stage.show();

    

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

【问题讨论】:

在示例中,您的标签取决于mouseEvent.getSceneX/Y 值,这似乎不是特别有用。这是你真正想要的吗?还是您希望标签依赖于某些图表特定值?如果是这样,它与鼠标悬停的区域或鼠标所在的确切点有关? 感谢您的回复。老实说,鼠标的跟踪只是为了展示我正在尝试做的事情。我相当肯定我可以做得那么优雅。真正的问题是我不明白如何将标签添加到场景然后应用布局,以便图表在窗口/画布中最大化并且标签没有绑定到特定的布局区域。基本上我的问题比这更根本......一个小组使我能够做到这一点,但似乎我不能最大化图表。 【参考方案1】:

所以我想我已经解决了。至少达到我要求的水平。

    Group root = new Group();
    root.setManaged(false);
    root.getChildren().add(ac);
    root.getChildren().add(myLabel);
    Scene scene = new Scene(root);

    scene.widthProperty().addListener(new ChangeListener<Number>() 
        @Override
        public void changed(ObservableValue<? extends Number> observableValue, Number oldSceneWidth, Number newSceneWidth) 
            ac.setPrefWidth((double) newSceneWidth);
        
    );
    scene.heightProperty().addListener(new ChangeListener<Number>() 
        @Override
        public void changed(ObservableValue<? extends Number> observableValue, Number oldSceneHeight, Number newSceneHeight) 
            ac.setPrefHeight((double) newSceneHeight);
        
    );

通过监听宽度和高度属性的变化并手动管理图表和标签的布局,我能够获得所需的布局和功能。我不能 100% 确定这是否是最佳方法,但它有效.

【讨论】:

以上是关于JavaFX 面积图并在光标后添加动态标签的主要内容,如果未能解决你的问题,请参考以下文章

python使用matplotlib绘制水平条形图并在条形图上添加实际数值标签实战

Python使用matplotlib可视化面积图(Area Chart)通过给坐标轴和曲线之间的区域着色可视化面积图在面积图的指定区域添加箭头和数值标签

R语言ggplot2可视化绘制分组水平条形图并在条形图的各种位置添加数值标签实战

python使用matplotlib可视化时间序列图并在时间序列可视化图像中的不同区域添加动态阈值动态阈值上限动态阈值下限

坐标计算与面积重叠比较

R语言编写自定义分组统计函数(customize statistics function)可视化分组箱图并在X轴标签下方添加分组对应的统计值(样本数N中位数median四分位数的间距iqr)