Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tooltips on Data Points #123

Open
bgmf opened this issue Aug 26, 2021 · 1 comment
Open

Tooltips on Data Points #123

bgmf opened this issue Aug 26, 2021 · 1 comment

Comments

@bgmf
Copy link

bgmf commented Aug 26, 2021

Hi Gerrit

If you create a Tile with a XYChart in it (Line or Area, doesn't matter) you can use JavaFX's XYChart.Data class to add items to the graph. In its documentation it is stated, that the node for each data point is required to be set manually either before you add it to the series it belongs to, or it will be automatically created.
But in the library that seems not to be the case, therefore we are not able to set a tooltip on a point.

Here's a simple example to test it (tested against version 16.0.3):

import eu.hansolo.tilesfx.Tile;
import eu.hansolo.tilesfx.TileBuilder;
import eu.hansolo.tilesfx.chart.TilesFXSeries;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.chart.XYChart;
import javafx.scene.control.Label;
import javafx.scene.control.Tooltip;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.text.TextAlignment;
import javafx.stage.Stage;

import java.util.Optional;
import java.util.Random;

public class ChartTest extends Application {

    @Override
    public void start(Stage stage) throws Exception {

        var tile = TileBuilder.create().skinType(Tile.SkinType.SMOOTHED_CHART).chartType(Tile.ChartType.LINE).backgroundColor(Color.TRANSPARENT)
                .unitColor(Color.GRAY).valueColor(Color.GRAY).tickLabelColor(Color.GRAY).minSize(150.0, 250.0).prefSize(150.0, 250.0).build();
        tile.getXAxis().setLabel("X Axis");
        tile.getYAxis().setLabel("Y Axis");

        Optional.ofNullable(tile.getXAxis().lookup(".axis-label")).ifPresent(it -> {
            if (it instanceof Label l)
                l.setTextAlignment(TextAlignment.CENTER);
        });
        Optional.ofNullable(tile.getYAxis().lookup(".axis-label")).ifPresent(it -> {
            if (it instanceof Label l)
                l.setTextAlignment(TextAlignment.CENTER);
        });

        var seriesA = new XYChart.Series<String, Number>();
        seriesA.setName("A");

        var seriesB = new XYChart.Series<String, Number>();
        seriesB.setName("B");

        tile.setTilesFXSeries(new TilesFXSeries<>(seriesA, Color.RED), new TilesFXSeries<>(seriesB, Color.GREEN));

        seriesA.getData().add(new XYChart.Data("", 0));
        seriesB.getData().add(new XYChart.Data("", 0));

        var r = new Random();
        for (int i = 1; i < 10; i++) {
            seriesA.getData().add(new XYChart.Data("" + i, r.nextInt(100)));
            seriesB.getData().add(new XYChart.Data("" + i, r.nextInt(100)));
        }

        for (var data : seriesA.getData()) {
            System.err.println(data.getNode());
            // from the documentation you can either set a node, before adding the data to the series
            // OR: it should be provided by the implementation (like a bullet or something)
            
            // Tooltip installation will fail silently, since data.getNode() returns null
            // Tooltip.install(data.getNode(), new Tooltip(data.getXValue() + ": " + data.getYValue()));
        }
        for (var data : seriesB.getData()) {
            System.err.println(data.getNode());
        }

        var box = new VBox(10.0);
        box.getChildren().add(tile);

        var scene = new Scene(box, 500.0, 250.0);
        stage.setScene(scene);
        stage.setMinWidth(500.0);
        stage.setMinHeight(250.0);

        stage.show();
    }

    public static void main(String[] args) {
        Application.launch(ChartTest.class, args);
    }
}

Thanks in advance for any tips, hacks or workarounds... 😉

Cheers, Daniel

@HanSolo
Copy link
Owner

HanSolo commented Aug 26, 2021

Ok, I think I've found the problem, I've pushed the fix with commit: 8a40e08
Could you give it a try and let me know if it works? With this version it should be possible to add a tooltip to a data point as follows:

public void start(Stage stage) throws Exception {
        var tile = TileBuilder.create()
                              .skinType(Tile.SkinType.SMOOTHED_CHART)
                              .chartType(Tile.ChartType.LINE)
                              .backgroundColor(Color.TRANSPARENT)
                              .unitColor(Color.GRAY)
                              .valueColor(Color.GRAY)
                              .tickLabelColor(Color.GRAY)
                              .minSize(150.0, 250.0)
                              .prefSize(150.0, 250.0)
                              .build();
        tile.getXAxis().setLabel("X Axis");
        tile.getYAxis().setLabel("Y Axis");

        Optional.ofNullable(tile.getXAxis().lookup(".axis-label")).ifPresent(it -> {
            if (it instanceof Label l) { l.setTextAlignment(TextAlignment.CENTER); }
        });
        Optional.ofNullable(tile.getYAxis().lookup(".axis-label")).ifPresent(it -> {
            if (it instanceof Label l) { l.setTextAlignment(TextAlignment.CENTER); }
        });

        var seriesA = new XYChart.Series<String, Number>();
        seriesA.setName("A");

        var seriesB = new XYChart.Series<String, Number>();
        seriesB.setName("B");

        var tilesFXSeriesA = new TilesFXSeries<>(seriesA, Color.RED);
        var tilesFXSeriesB = new TilesFXSeries<>(seriesB, Color.LIME);

        tile.setTilesFXSeries(tilesFXSeriesA, tilesFXSeriesB);

        seriesA.getData().add(new XYChart.Data("", 0));
        seriesB.getData().add(new XYChart.Data("", 0));

        var r = new Random();
        for (int i = 1; i < 10; i++) {
            XYChart.Data dataA = new Data("" + i, r.nextInt(100));
            dataA.setNode(new Circle(5, tilesFXSeriesA.getFill()));
            Tooltip.install(dataA.getNode(), new Tooltip("Tooltip A: " + i));
            seriesA.getData().add(dataA);

            XYChart.Data dataB = new Data("" + i, r.nextInt(100));
            dataB.setNode(new Rectangle(10, 10, tilesFXSeriesB.getFill()));
            Tooltip.install(dataB.getNode(), new Tooltip("Tooltip B: " + i));
            seriesB.getData().add(dataB);

            //seriesA.getData().add(new XYChart.Data("" + i, r.nextInt(100)));
            //seriesB.getData().add(new XYChart.Data("" + i, r.nextInt(100)));
        }

        for (var data : seriesA.getData()) {
            System.err.println(data.getNode());
            // from the documentation you can either set a node, before adding the data to the series
            // OR: it should be provided by the implementation (like a bullet or something)

            // Tooltip installation will fail silently, since data.getNode() returns null
            // Tooltip.install(data.getNode(), new Tooltip(data.getXValue() + ": " + data.getYValue()));
        }
        for (var data : seriesB.getData()) {
            System.err.println(data.getNode());
        }

        var box = new VBox(10.0);
        box.setBackground(new Background(new BackgroundFill(Tile.BACKGROUND, CornerRadii.EMPTY, Insets.EMPTY)));
        box.getChildren().add(tile);

        var scene = new Scene(box, 500.0, 250.0);
        stage.setScene(scene);
        stage.setMinWidth(500.0);
        stage.setMinHeight(250.0);

        stage.show();
    }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants