0

This is the code for interface:

@Override
public void start(Stage primaryStage){

    NumberAxis xAxis = new NumberAxis();
    xAxis.setLabel("XX");

    NumberAxis yAxis = new NumberAxis();
    yAxis.setLabel("YY");

    LineChart<Number, Number> lineChart = new LineChart<>(xAxis, yAxis);
    lineChart.setLegendVisible(false);

    XYChart.Series<Number, Number> series1 = new XYChart.Series<>();
    series1.setName("Line1");
    series1.getData().add(new XYChart.Data<>(1, 1));
    series1.getData().add(new XYChart.Data<>(2, 2));
    series1.getData().add(new XYChart.Data<>(3, 2));
    series1.getData().add(new XYChart.Data<>(4, 1));

    XYChart.Series<Number, Number> series2 = new XYChart.Series<>();
    series2.setName("Line2");
    series2.getData().add(new XYChart.Data<>(2, 2));
    series2.getData().add(new XYChart.Data<>(3, 2));
    series2.getData().add(new XYChart.Data<>(4, 2));

    XYChart.Series<Number, Number> series3 = new XYChart.Series<>();
    series3.setName("Line3");
    series3.getData().add(new XYChart.Data<>(1, 3));
    series3.getData().add(new XYChart.Data<>(2, 2));
    series3.getData().add(new XYChart.Data<>(3, 1));
    series3.getData().add(new XYChart.Data<>(3, 2));

    List<XYChart.Series<Number, Number>> seriesList = Arrays.asList(series1, series2, series3);

    lineChart.getData().addAll(seriesList);

    HBox legendBox = new HBox();
    legendBox.setStyle("-fx-alignment: center; -fx-padding: 10;");

    Insets insets = new Insets(0, 10, 0, 10);

    for(Node legend : lineChart.lookupAll(".chart-legend-item")){

        Label label = (Label)legend;

        label.setOnMouseClicked(e -> {

            XYChart.Series<Number, Number> toFront = seriesList.stream()
                                                                .filter(e1 -> e1.getName().equals(label.getText()))
                                                                .findFirst().get();

            System.out.println(toFront);


            //put series toFront over all other series
            //i don't know how//

            /*I have tried this
            Platform.runLater(() -> {

                lineChart.getData().remove(toFront);
                lineChart.getData().add(toFront); //first time click: Duplicate, after only NullPointer

            });*/

        });

        legendBox.getChildren().add(label);
        HBox.setMargin(label, insets);

    }

    BorderPane borderPane = new BorderPane();
    borderPane.setCenter(lineChart);
    borderPane.setBottom(legendBox);

    primaryStage.setScene(new Scene(borderPane));
    primaryStage.sizeToScene();
    primaryStage.centerOnScreen();

    primaryStage.show();

}

This is how interface looks:

As you can see in image, you can't know the exact path of Line1 and Line2.

I want to put an EventHandler on legends. When you click on one of the legends, place the line of legend in front of chart, over all others lines.

The code with EventHandler, as you can see, is writen. After the series is identified I don't know what do to. I have tried to remove from chart and add again:

Platform.runLater(() -> {

    lineChart.getData().remove(toFront);
    lineChart.getData().add(toFront);

});

Which only remove line and result errors:

1. First click: "Duplicate series added" //at line with add
2. Next clicks: "NullPointerException" //at line with add
KunLun
  • 3,109
  • 3
  • 18
  • 65
  • I believe the lines/points are all drawn in the same parent, which means you could try setting the [view order](https://openjfx.io/javadoc/12/javafx.graphics/javafx/scene/Node.html#viewOrderProperty) of the node for the series and the node of each data in said series. – Slaw Aug 10 '19 at 19:29
  • But how I find parent node? – KunLun Aug 10 '19 at 20:47
  • `Node` has a `parent` property. However, you shouldn't need the parent node. The view order should be set on the `Node` in the `Series#node` property and each `Data#node` property (in said `Series`). Note I haven't tried this, so if you find it doesn't work please let me know. – Slaw Aug 10 '19 at 20:51
  • @Slaw `toFront.getNode().setViewOrder(10);` - `toFront.getData().forEach(e1 -> e1.getNode().setViewOrder(10));` - something happened, but it's not what I want and I don't really understand what happend, because sometimes put it in back and sometimes happened nothing. Can you help me with code? If you have time. – KunLun Aug 11 '19 at 10:28
  • @Slaw I found it. There is a method `toFront()` which `Node` has it. Thank you for your time. Also in first place I understand wrong `setViewOrder` use. I thought it set `z-coord`. Actually it work like using like an index in an array(lower value mean first element). – KunLun Aug 11 '19 at 12:03

1 Answers1

0

I had got it.

My code is good:

 Platform.runLater(() -> {

    lineChart.getData().remove(toFront);
    lineChart.getData().add(toFront);

});

The problem is from animation when remove.

To fix that I set: lineChart.setAnimated(false);

UPDATE

I found a better solution which don't compromise setAnimated

Instread of removing series and add it again you can simply can use method toFront() which Node class has it.

Here is the code which replace above code.

toFront.getNode().toFront();
toFront.getData().forEach(e1 -> e1.getNode().toFront());

This code is also better if you change the color of series. In case remove-add you need to recolor the line which was moved in front, but in case Node#toFront you don't need.

KunLun
  • 3,109
  • 3
  • 18
  • 65
  • @Sedrick Maybe this info can help you. – KunLun Aug 10 '19 at 16:52
  • 1
    I'm glad you found a solution in the form of `toFront()`, but note that method causes the children list to be structurally modified. If that's not a problem then feel free to continue using `toFront()`; that said, the reason I suggested `viewOrder` is because that property can modify the z-order _without_ structurally modifying the child list. Of course, you'd need to "reset" the `viewOrder` of the "old" series. – Slaw Aug 12 '19 at 00:07
  • `structurally modified`? Can you explain me this? – KunLun Aug 12 '19 at 07:00
  • 1
    The method `toFront()` literally changes the order of the children list. If you look at the implementation you'll see it removes the `Node` and then re-adds it to the end of the list (and `toBack()` re-adds it to the start of the list). It does this because [the z-order is solely determined by the order of the children list](https://stackoverflow.com/questions/2988196/z-order-in-javafx)—that is, until they added the `viewOrder` property in JavaFX 9 (but read the documentation of the property, it doesn't do _exactly_ the same thing as structurally modifying the children list). – Slaw Aug 13 '19 at 21:09
  • @Slaw thanks! Where can I found implementation of all methods from Java? – KunLun Aug 14 '19 at 09:42
  • 1
    The sources are included in the distributions (both OpenJDK and OpenJFX). If you include JavaFX via a build tool, such as Maven or Gradle, then the sources can be downloaded by your IDE. Then you just navigate the code with your IDE (you may have to "link" the sources). For instance, in IntelliJ, just hover over a method you're interested in and Ctrl+Click on it; if the IDE is aware of the appropriate source file it will take you to it. – Slaw Aug 14 '19 at 15:13