Effectively updating lines / markers on top of a JavaFX chart

I am using JavaFX LineChart, which takes almost a second second, and I want to move the vertical marker (cursor position) along this chart, which is updated very often.

I tested the following solutions:

However, these solutions are not intended for frequent marker updates on large charts. Whenever a marker changes, the entire chart is redrawn.

How can I prevent Java from redrawing the entire chart when updating a marker? I thought of a wrapper component that can be placed around a chart, and caches the chart image until the contents of the chart and the borders of the chart change. Does something like this exist or how can this be implemented?

0
source share
2 answers

It turned out that the solution is much simpler than I thought. Each JavaFX ( Node ) component has a cache property that can be set to true to cache the displayed node as a bitmap. This is exactly what I was looking for.

Thus, an effective solution is to put the chart and all marker lines in the StackPane and enable caching for the chart. The rest is already explained in Adding a row in a JavaFX diagram and How do I add a value marker to a JavaFX diagram? (how to create a StackPane and how to calculate and update marker lines).

0
source

As mentioned in Stefan, the best way is to set the cache property for true nodes that you do not want to update. I want to add that StackPane does not require special attention, it can be Pane or another region (in fact, StackPane has its own way of adding new children that make you manipulate). Here is a piece of code that I used to implement LineMarker, which moves along LineChart (in my example, I had a video, and LineMarker is the time on the chart)

Basic 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(); } 
0
source

All Articles