As mentioned by Stefan the best way is to set the cache
property to true
of the nodes that you do not want to update. What I want to add is that the StackPane
is not strickly necessary, it could be a Pane
or another region (actually a StackPane has its own way to add new children which make you dificult to manipulate).
Here is a snippet of the code I used to implement a LineMarker that moves along the LineChart
(in my example I had a video and the LineMarker followed the time in the chart)
Main Example
Pane pane;
LineChart chart;
MediaPlayer mediaPlayer;
// Create pane, chart (and mediaplayer for this example)
pane.getChildren.add(chart);
List<XYChart.Data<Number, Number> dataList;
XYChart.Series series = new XYChart.Series();
// Fill the data
ObservableList<XYChart.Data<Number, Number>> list;
list = FXCollections.observableList(dataList);
series.setData(list);
chart.getData().add(series);
chart.setCache(true);
LineMarker lineMarker = new LineMarker(pane, (ValueAxis) chart.getXAxis(), 0, (ValueAxis) chart.getYAxis());
mediaPlayer.currentTimeProperty().addListener((v, oldValue, newValue) -> lineMarker.updateMarker(newValue.doubleValue()));
LineMarker.java
public class LineMarker extends Line{
private final DoubleProperty value = new SimpleDoubleProperty();
private Pane pane;
private ValueAxis xAxis;
private ValueAxis yAxis;
public LineMarker(Pane pane, ValueAxis xAxis, double value, ValueAxis yAxis){
this.pane = pane;
this.xAxis = xAxis;
this.yAxis = yAxis;
Number lowerY = yAxis.toRealValue(yAxis.getLowerBound());
double minY = yAxis.getDisplayPosition(lowerY);
setStartY(getYPositionParent(minY, pane));
Number upperY = yAxis.toRealValue(yAxis.getUpperBound());
double maxY = yAxis.getDisplayPosition(upperY);
setEndY(getYPositionParent(maxY, pane));
double xPosInAxis = xAxis.getDisplayPosition(value);
setStartX(getXPositionParent(xPosInAxis, pane));
setEndX(getStartX());
pane.getChildren().add(this);
}
private double getXPositionParent(double xPosInAxis, Node parent){
double xPosInParent = xPosInAxis - xAxis.getBoundsInLocal().getMinX();
Node node = xAxis;
while(!node.equals(parent)){
xPosInParent = xPosInParent + node.getBoundsInParent().getMinX();
node = node.getParent();
}
return xPosInParent;
}
private double getYPositionParent(double yPosInAxis, Node parent){
double yPosInParent = yPosInAxis - yAxis.getBoundsInLocal().getMinY();
Node node = yAxis;
while(!node.equals(parent)){
yPosInParent = yPosInParent + node.getBoundsInParent().getMinY();
node = node.getParent();
}
return yPosInParent;
}
public void updateMarker(double value){
pane.getChildren().remove(this);
double xPosInAxis = xAxis.getDisplayPosition(value);
setStartX(getXPositionParent(xPosInAxis, pane));
setEndX(getStartX());
pane.getChildren().add(this);
pane.requestLayout();
}