高效地更新JavaFX图表顶部的线条/标记
我使用一个JavaFX折线图,它需要将近一秒钟的时间来渲染,我想在这个经常更新的图表上移动一个垂直标记(光标位置) 我测试了以下解决方案:高效地更新JavaFX图表顶部的线条/标记,java,javafx-2,javafx-8,Java,Javafx 2,Javafx 8,我使用一个JavaFX折线图,它需要将近一秒钟的时间来渲染,我想在这个经常更新的图表上移动一个垂直标记(光标位置) 我测试了以下解决方案: 然而,这些解决方案并不适用于大型图表上频繁的标记更新。每当标记改变时,整个图表都会重新绘制 如何防止Java在标记更新时重新绘制整个图表? 我想到了一个包装器组件,只要图表内容和图表边界不变,它就可以放在图表周围并缓存图表图像。类似的东西是否存在,或者如何实现这一点?事实证明,解决方案比我想象的要简单得多。 每个JavaFX组件(节点)都有一个缓存属
我想到了一个包装器组件,只要图表内容和图表边界不变,它就可以放在图表周围并缓存图表图像。类似的东西是否存在,或者如何实现这一点?事实证明,解决方案比我想象的要简单得多。 每个JavaFX组件(
节点
)都有一个缓存
属性,可以将该属性设置为true
,以便将渲染节点缓存为位图。这正是我要找的
因此,一个有效的解决方案是将图表和所有标记行放入
堆栈窗格
,并为图表启用缓存。其余部分已在和(如何创建StackPane以及如何计算和更新标记线)中进行了说明。正如Stefan所述,最好的方法是将不想更新的节点的缓存属性设置为true
。我想补充的是,StackPane
并不是绝对必要的,它可以是一个Pane
或另一个区域(实际上,StackPane有自己的方式来添加新的子项,这使您难以操作)。
下面是我用来实现沿着折线图移动的线标记的代码片段(在我的示例中,我有一个视频,线标记跟随图表中的时间)
主要例子
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()));
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();
}