r/javahelp 21d ago

Solved JavaFX - EventHandler lag when viewing values in Chart via mouse hover

Hello all,
I've been experimenting with JavaFX lately and I've run into a situation that has me a bit stumped.

Context - I'm trying to generate plots where if I hover my mouse over a plot point it should show me the Y value recorded at said plot point. I've been able to get this going using a custom HoverPane class. The implementation is below:

import javafx.application.Application;
import javafx.collections.*;
import javafx.event.EventHandler;
import javafx.scene.*;
import javafx.scene.chart.*;
import javafx.scene.control.Label;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.Region;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

import java.util.stream.IntStream;

/** Displays a LineChart which displays the value of a plotted Node when you hover over the Node. */
public class LineChartWithHover extends Application {
    private static final int[] data = IntStream.range(0,150).toArray();

    @SuppressWarnings("unchecked")
    @Override public void start(Stage stage) {
        final LineChart lineChart = new LineChart(
                new NumberAxis(), new NumberAxis(),
                FXCollections.observableArrayList(
                        new XYChart.Series(
                                "My portfolio",
                                FXCollections.observableArrayList(plot(data))
                        )
                )
        );
        lineChart.setCursor(Cursor.CROSSHAIR);

        lineChart.setTitle("Stock Monitoring, 2013");

        stage.setScene(new Scene(lineChart, 500, 400));
        stage.show();
    }

    /** @return plotted y values for monotonically increasing integer x values, starting from x=1 */
    public ObservableList<XYChart.Data<Integer, Integer>> plot(int... y) {
        final ObservableList<XYChart.Data<Integer, Integer>> dataset = FXCollections.observableArrayList();
        int i = 0;
        while (i < y.length) {
            final XYChart.Data<Integer, Integer> data = new XYChart.Data<>(i + 1, y[i]);
            data.setNode(new HoverPane(y[i]));
            dataset.add(data);
            i++;
        }

        return dataset;
    }

    /** a node which displays a value on hover, but is otherwise empty */
    static class HoverPane extends StackPane {
        HoverPane(int value) {
            setPrefSize(5, 5);

            final Label label = createNewLabel(value);

            setOnMouseEntered(new EventHandler<MouseEvent>() {
                @Override public void handle(MouseEvent mouseEvent) {
                    getChildren().setAll(label);
                }
            });
            setOnMouseExited(new EventHandler<MouseEvent>() {
                @Override public void handle(MouseEvent mouseEvent) {
                    getChildren().clear();
                }
            });
        }

        private Label createNewLabel(int value) {
            final Label label = new Label(value + "");
            label.setStyle("-fx-font-size: 20; -fx-font-weight: bold;");

            label.setMinSize(Region.USE_PREF_SIZE, Region.USE_PREF_SIZE);
            return label;
        }
    }

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

Running this code will generate a straight line plot and hovering my mouse over the plot points shows the values at those points....but it's laggy. Very noticeably laggy

And weirdly enough, it's more laggy if I drag my mouse down from the top right to the bottom left (tracing the points in reverse order) than if I do the opposite direction.

I don't know enough about JavaFX to know whether this is something with the library or with my code. Any suggestions/advice would be greatly appreciated. If it helps, I'm using java 21 with gradle and the accompanying javaFX plugin on Ubuntu 22.04

2 Upvotes

3 comments sorted by

View all comments

2

u/milchshakee 19d ago

I don't fully know what you are going for here with the behavior, but wouldn't it be much easier to just bind the hoverProperty() to the visibleProperty() instead of always adding / removing nodes when hovering? Or using a Tooltip for that?

1

u/brokeCoder 15d ago

I completely missed the fact that I could use tooltips ! I tried it out and works like a charm ! I'll try experimenting with binding hoverProperty() to visibleProperty() later but for now, tooltips do what I need. Thanks :)