My desktop application has a timer for starting and stopping a test. On the graph, I want to create two vertical lines to indicate the start and stop time. \"Adding vertical
I'm not sure which question you are referring to. You can basically do all this with some binding magic: the trick is to map the x value of the line to coordinates relative to the xAxis using xAxis.getDisplayPosition(...). Then you need to transform that coordinate to the coordinate relative to the container holding the chart and the line: the easiest way to do this is to first transform to Scene coordinates using xAxis.localToScene(...) and then to the coordinates of the container, using container.sceneToLocal(...).
Then you just need to let the binding observe everything that it needs to watch for changes: these will be the (numerical) bounds of the axes, the (graphical) bounds of the chart, and, if the line is going to move, a property representing its x-value.
Here is an SSCCE. In this example, I use a Slider to move the line around. I also make the line visible only if it's in range, and bind the y-coordinates so it spans the yAxis.
import java.util.Random;
import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.beans.value.ObservableDoubleValue;
import javafx.geometry.Insets;
import javafx.geometry.Point2D;
import javafx.scene.Scene;
import javafx.scene.chart.LineChart;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart;
import javafx.scene.chart.XYChart.Data;
import javafx.scene.chart.XYChart.Series;
import javafx.scene.control.Slider;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Pane;
import javafx.scene.shape.Line;
import javafx.stage.Stage;
public class LineChartWithVerticalLine extends Application {
@Override
public void start(Stage primaryStage) {
NumberAxis xAxis = new NumberAxis();
NumberAxis yAxis = new NumberAxis();
LineChart chart = new LineChart<>(xAxis, yAxis);
chart.getData().add(createSeries());
Pane chartHolder = new Pane();
chartHolder.getChildren().add(chart);
DoubleProperty lineX = new SimpleDoubleProperty();
Slider slider = new Slider();
slider.minProperty().bind(xAxis.lowerBoundProperty());
slider.maxProperty().bind(xAxis.upperBoundProperty());
slider.setPadding(new Insets(20));
lineX.bind(slider.valueProperty());
chartHolder.getChildren().add(createVerticalLine(chart, xAxis, yAxis, chartHolder, lineX));
BorderPane root = new BorderPane(chartHolder, null, null, slider, null);
Scene scene = new Scene(root, 800, 600);
primaryStage.setScene(scene);
primaryStage.show();
}
private Line createVerticalLine(XYChart chart, NumberAxis xAxis, NumberAxis yAxis, Pane container, ObservableDoubleValue x) {
Line line = new Line();
line.startXProperty().bind(Bindings.createDoubleBinding(() -> {
double xInAxis = xAxis.getDisplayPosition(x.get());
Point2D pointInScene = xAxis.localToScene(xInAxis, 0);
double xInContainer = container.sceneToLocal(pointInScene).getX();
return xInContainer ;
},
x,
chart.boundsInParentProperty(),
xAxis.lowerBoundProperty(),
xAxis.upperBoundProperty()));
line.endXProperty().bind(line.startXProperty());
line.startYProperty().bind(Bindings.createDoubleBinding(() -> {
double lowerY = yAxis.getDisplayPosition(yAxis.getLowerBound());
Point2D pointInScene = yAxis.localToScene(0, lowerY);
double yInContainer = container.sceneToLocal(pointInScene).getY();
return yInContainer ;
},
chart.boundsInParentProperty(),
yAxis.lowerBoundProperty()));
line.endYProperty().bind(Bindings.createDoubleBinding(() -> {
double upperY = yAxis.getDisplayPosition(yAxis.getUpperBound());
Point2D pointInScene = yAxis.localToScene(0, upperY);
double yInContainer = container.sceneToLocal(pointInScene).getY();
return yInContainer ;
},
chart.boundsInParentProperty(),
yAxis.lowerBoundProperty()));
line.visibleProperty().bind(
Bindings.lessThan(x, xAxis.lowerBoundProperty())
.and(Bindings.greaterThan(x, xAxis.upperBoundProperty())).not());
return line ;
}
private Series createSeries() {
Series series = new Series<>();
series.setName("Data");
Random rng = new Random();
for (int i=0; i<=20; i++) {
series.getData().add(new Data<>(i, rng.nextInt(101)));
}
return series ;
}
public static void main(String[] args) {
launch(args);
}
}