LineChart FX - Delete solid line

守給你的承諾、 提交于 2019-12-02 07:34:57

This is an old question with an accepted answer but I came across it and was curious. I wanted to know if it was possible to put a gap in a LineChart (at least without having to create a custom chart implementation). It turns out that there is. The solution is kind of hacky and brittle. It involves getting the Path by using XYChart.Series.getNode() and manipulating the list of PathElements. The following code gives an example:

import javafx.application.Application;
import javafx.application.Platform;
import javafx.scene.Scene;
import javafx.scene.chart.LineChart;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart;
import javafx.scene.layout.StackPane;
import javafx.scene.shape.LineTo;
import javafx.scene.shape.MoveTo;
import javafx.scene.shape.Path;
import javafx.stage.Stage;

public class Main extends Application {

    @Override
    public void start(Stage primaryStage) {
        LineChart<Number, Number> chart = new LineChart<>(new NumberAxis(), new NumberAxis());
        chart.getXAxis().setLabel("X");
        chart.getYAxis().setLabel("Y");
        chart.setLegendVisible(false);
        chart.getData().add(new XYChart.Series<>());

        for (int x = 0; x <= 10; x++) {
            chart.getData().get(0).getData().add(new XYChart.Data<>(x, Math.pow(x, 2)));
        }

        /*
         * Had to wrap the call in a Platform.runLater otherwise the Path was
         * redrawn after the modifications are made.
         */
        primaryStage.setOnShown(we -> Platform.runLater(() -> {
            Path path = (Path) chart.getData().get(0).getNode();
            LineTo lineTo = (LineTo) path.getElements().get(8);
            path.getElements().set(8, new MoveTo(lineTo.getX(), lineTo.getY()));
        }));

        primaryStage.setScene(new Scene(new StackPane(chart), 500, 300));
        primaryStage.setTitle("LineChart Gap");
        primaryStage.show();
    }

}

This code results in the following:

This is possible because the ObservableList of PathElements seems to be a MoveTo followed by a bunch of LineTos. I simply picked a LineTo and replaced it with a MoveTo to the same coordinates. I haven't quite figured out which index of LineTo matches with which XYChart.Data, however, and picked 8 for the example randomly.

There are a couple of issues with this solution. The first and obvious one is that this relies on the internal implementation of LineChart. The second is where the real brittleness comes from though. Any change to the data, either axes' value ranges, the chart's width or height, or pretty much anything that causes the chart to redraw itself will cause the Path to be recomputed and redrawn. This means if you use this solution you'll have to reapply the modification every time the chart redraws itself.

I made a GapLineChart that automatically sets a MoveTo like Slaw pointed it whenever it sees a Double.NaN. You can find it here https://gist.github.com/sirolf2009/ae8a7897b57dcf902b4ed747b05641f9. Check the first comment for an example

I checked it. It is not possible to change only one part of this line. Because this is one long Path and you can't change one element of Path.

I think the only way is add each "jump" in different series.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!