2015-05-27 3 views
0

Я использую JavaFX LineChart, который занимает почти вторую секунду, и я хочу переместить вертикальный маркер (положение курсора) по этой диаграмме, который обновляется очень часто.Эффективное обновление линий/маркеров поверх диаграммы JavaFX

Я тестировал следующие решения:

Однако эти решения не сделаны для частых обновлений маркеров на больших картах. Всякий раз, когда маркер изменяется, весь график перерисовывается.

Как я могу запретить Java перерисовывать всю диаграмму при обновлении маркера? Я подумал о компоненте-обертки, который можно поместить вокруг диаграммы и кэширует изображение диаграммы, пока содержимое диаграммы и границы графика не меняются. Что-то вроде этого существует или как можно реализовать это?

ответ

0

Оказалось, что решение намного проще, чем я думал. Каждый компонент JavaFX (Node) имеет свойство cache, которое может быть установлено на true, чтобы кэшировать обработанный узел в виде растрового изображения. Это именно то, что я искал.

Таким образом, эффективным решением является привязка диаграммы и всех маркерных линий к StackPane и включение кеширования для диаграммы. Остальное уже объяснено в Adding a line in a JavaFX chart и How to add a value marker to JavaFX chart? (как создать StackPane и как рассчитать и обновить линии маркера).

0

Как упомянуто Stefan, наилучшим способом является присвоение cache объектов true узлов, которые вы не хотите обновлять. Я хочу добавить, что StackPane не требует особого внимания, это может быть Pane или другой регион (на самом деле StackPane имеет свой собственный способ добавления новых детей, которые заставляют вас манипулировать). Вот фрагмент кода, который я использовал для реализации LineMarker, которая двигается вдоль LineChart (в моем примере я имел видео и LineMarker следовало время на графике)

Главного Пример

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(); 
} 
Смежные вопросы