< prev index next >

modules/controls/src/main/java/javafx/scene/chart/StackedBarChart.java

Print this page
rev 9950 : 8152418: Memory Leak in StackedBarChart when series are removed

*** 62,83 **** * @since JavaFX 2.1 */ public class StackedBarChart<X, Y> extends XYChart<X, Y> { // -------------- PRIVATE FIELDS ------------------------------------------- ! private Map<Series, Map<String, List<Data<X, Y>>>> seriesCategoryMap = ! new HashMap<Series, Map<String, List<Data<X, Y>>>>(); private Legend legend = new Legend(); private final Orientation orientation; private CategoryAxis categoryAxis; private ValueAxis valueAxis; // RT-23125 handling data removal when a category is removed. private ListChangeListener<String> categoriesListener = new ListChangeListener<String>() { @Override public void onChanged(ListChangeListener.Change<? extends String> c) { while (c.next()) { for(String cat : c.getRemoved()) { ! for (Series<X,Y> series : getData()) { for (Data<X, Y> data : series.getData()) { if ((cat).equals((orientation == orientation.VERTICAL) ? data.getXValue() : data.getYValue())) { boolean animatedOn = getAnimated(); setAnimated(false); --- 62,83 ---- * @since JavaFX 2.1 */ public class StackedBarChart<X, Y> extends XYChart<X, Y> { // -------------- PRIVATE FIELDS ------------------------------------------- ! private Map<Series<X, Y>, Map<String, List<Data<X, Y>>>> seriesCategoryMap = ! new HashMap<>(); private Legend legend = new Legend(); private final Orientation orientation; private CategoryAxis categoryAxis; private ValueAxis valueAxis; // RT-23125 handling data removal when a category is removed. private ListChangeListener<String> categoriesListener = new ListChangeListener<String>() { @Override public void onChanged(ListChangeListener.Change<? extends String> c) { while (c.next()) { for(String cat : c.getRemoved()) { ! for (Series<X, Y> series : getData()) { for (Data<X, Y> data : series.getData()) { if ((cat).equals((orientation == orientation.VERTICAL) ? data.getXValue() : data.getYValue())) { boolean animatedOn = getAnimated(); setAnimated(false);
*** 228,238 **** t.setOnFinished(event -> { removeDataItemFromDisplay(series, item); }); t.play(); } else { ! getPlotChildren().remove(bar); removeDataItemFromDisplay(series, item); } } /** @inheritDoc */ --- 228,238 ---- t.setOnFinished(event -> { removeDataItemFromDisplay(series, item); }); t.play(); } else { ! processDataRemove(series, item); removeDataItemFromDisplay(series, item); } } /** @inheritDoc */
*** 253,293 **** // remove style class negative item.getNode().getStyleClass().remove("negative"); } } - private void animateDataAdd(Data<X, Y> item, Node bar) { - double barVal; - if (orientation == Orientation.VERTICAL) { - barVal = ((Number) item.getYValue()).doubleValue(); - if (barVal < 0) { - bar.getStyleClass().add("negative"); - } - item.setYValue(getYAxis().toRealValue(getYAxis().getZeroPosition())); - setCurrentDisplayedYValue(item, getYAxis().toRealValue(getYAxis().getZeroPosition())); - getPlotChildren().add(bar); - item.setYValue(getYAxis().toRealValue(barVal)); - animate(new Timeline( - new KeyFrame(Duration.ZERO, new KeyValue(currentDisplayedYValueProperty(item), getCurrentDisplayedYValue(item))), - new KeyFrame(Duration.millis(700), new KeyValue(currentDisplayedYValueProperty(item), item.getYValue(), Interpolator.EASE_BOTH))) - ); - } else { - barVal = ((Number) item.getXValue()).doubleValue(); - if (barVal < 0) { - bar.getStyleClass().add("negative"); - } - item.setXValue(getXAxis().toRealValue(getXAxis().getZeroPosition())); - setCurrentDisplayedXValue(item, getXAxis().toRealValue(getXAxis().getZeroPosition())); - getPlotChildren().add(bar); - item.setXValue(getXAxis().toRealValue(barVal)); - animate(new Timeline( - new KeyFrame(Duration.ZERO, new KeyValue(currentDisplayedXValueProperty(item), getCurrentDisplayedXValue(item))), - new KeyFrame(Duration.millis(700), new KeyValue(currentDisplayedXValueProperty(item), item.getXValue(), Interpolator.EASE_BOTH))) - ); - } - } - @Override protected void seriesChanged(ListChangeListener.Change<? extends Series> c) { // Update style classes for all series lines and symbols // Note: is there a more efficient way of doing this? for (int i = 0; i < getDataSize(); i++) { final Series<X,Y> series = getData().get(i); --- 253,262 ----
*** 331,364 **** if (categoryMap.size() > 0) { seriesCategoryMap.put(series, categoryMap); } } - private Timeline createDataRemoveTimeline(Data<X, Y> item, final Node bar, final Series<X, Y> series) { - Timeline t = new Timeline(); - if (orientation == Orientation.VERTICAL) { - item.setYValue(getYAxis().toRealValue(getYAxis().getZeroPosition())); - t.getKeyFrames().addAll( - new KeyFrame(Duration.ZERO, new KeyValue(currentDisplayedYValueProperty(item), - getCurrentDisplayedYValue(item))), - new KeyFrame(Duration.millis(700), actionEvent -> { - getPlotChildren().remove(bar); - }, - new KeyValue(currentDisplayedYValueProperty(item), item.getYValue(), Interpolator.EASE_BOTH))); - } else { - item.setXValue(getXAxis().toRealValue(getXAxis().getZeroPosition())); - t.getKeyFrames().addAll( - new KeyFrame(Duration.ZERO, new KeyValue(currentDisplayedXValueProperty(item), - getCurrentDisplayedXValue(item))), - new KeyFrame(Duration.millis(700), actionEvent -> { - getPlotChildren().remove(bar); - }, - new KeyValue(currentDisplayedXValueProperty(item), item.getXValue(), Interpolator.EASE_BOTH))); - } - return t; - } - @Override protected void seriesRemoved(final Series<X, Y> series) { // remove all symbol nodes if (shouldAnimate()) { ParallelTransition pt = new ParallelTransition(); pt.setOnFinished(event -> { --- 300,309 ----
*** 378,398 **** // fade out last series FadeTransition ft = new FadeTransition(Duration.millis(700), bar); ft.setFromValue(1); ft.setToValue(0); ft.setOnFinished(actionEvent -> { ! getPlotChildren().remove(bar); bar.setOpacity(1.0); }); pt.getChildren().add(ft); } } pt.play(); } else { for (Data<X, Y> d : series.getData()) { ! final Node bar = d.getNode(); ! getPlotChildren().remove(bar); } removeSeriesFromDisplay(series); requestChartLayout(); } } --- 323,342 ---- // fade out last series FadeTransition ft = new FadeTransition(Duration.millis(700), bar); ft.setFromValue(1); ft.setToValue(0); ft.setOnFinished(actionEvent -> { ! processDataRemove(series, d); bar.setOpacity(1.0); }); pt.getChildren().add(ft); } } pt.play(); } else { for (Data<X, Y> d : series.getData()) { ! processDataRemove(series, d); } removeSeriesFromDisplay(series); requestChartLayout(); } }
*** 443,454 **** double catSpace = categoryAxis.getCategorySpacing(); // calculate bar spacing final double availableBarSpace = catSpace - getCategoryGap(); final double barWidth = availableBarSpace; final double barOffset = -((catSpace - getCategoryGap()) / 2); - final double lowerBoundValue = valueAxis.getLowerBound(); - final double upperBoundValue = valueAxis.getUpperBound(); // update bar positions and sizes for (String category : categoryAxis.getCategories()) { double currentPositiveValue = 0; double currentNegativeValue = 0; Iterator<Series<X, Y>> seriesIterator = getDisplayedSeriesIterator(); --- 387,396 ----
*** 530,540 **** } else { setLegend(null); } } ! private Node createBar(Series series, int seriesIndex, final Data item, int itemIndex) { Node bar = item.getNode(); if (bar == null) { bar = new StackPane(); bar.setAccessibleRole(AccessibleRole.TEXT); bar.setAccessibleRoleDescription("Bar"); --- 472,568 ---- } else { setLegend(null); } } ! private void updateMap(Series<X,Y> series, Data<X,Y> item) { ! final String category = (orientation == Orientation.VERTICAL) ? (String)item.getXValue() : ! (String)item.getYValue(); ! Map<String, List<Data<X, Y>>> categoryMap = seriesCategoryMap.get(series); ! if (categoryMap != null) { ! categoryMap.remove(category); ! if (categoryMap.isEmpty()) seriesCategoryMap.remove(series); ! } ! if (seriesCategoryMap.isEmpty() && categoryAxis.isAutoRanging()) categoryAxis.getCategories().clear(); ! } ! ! private void processDataRemove(final Series<X,Y> series, final Data<X,Y> item) { ! Node bar = item.getNode(); ! getPlotChildren().remove(bar); ! updateMap(series, item); ! } ! ! private void animateDataAdd(Data<X, Y> item, Node bar) { ! double barVal; ! if (orientation == Orientation.VERTICAL) { ! barVal = ((Number) item.getYValue()).doubleValue(); ! if (barVal < 0) { ! bar.getStyleClass().add("negative"); ! } ! item.setYValue(getYAxis().toRealValue(getYAxis().getZeroPosition())); ! setCurrentDisplayedYValue(item, getYAxis().toRealValue(getYAxis().getZeroPosition())); ! getPlotChildren().add(bar); ! item.setYValue(getYAxis().toRealValue(barVal)); ! animate( ! new KeyFrame(Duration.ZERO, new KeyValue( ! currentDisplayedYValueProperty(item), ! getCurrentDisplayedYValue(item))), ! new KeyFrame(Duration.millis(700), new KeyValue( ! currentDisplayedYValueProperty(item), ! item.getYValue(), Interpolator.EASE_BOTH)) ! ); ! } else { ! barVal = ((Number) item.getXValue()).doubleValue(); ! if (barVal < 0) { ! bar.getStyleClass().add("negative"); ! } ! item.setXValue(getXAxis().toRealValue(getXAxis().getZeroPosition())); ! setCurrentDisplayedXValue(item, getXAxis().toRealValue(getXAxis().getZeroPosition())); ! getPlotChildren().add(bar); ! item.setXValue(getXAxis().toRealValue(barVal)); ! animate( ! new KeyFrame(Duration.ZERO, new KeyValue( ! currentDisplayedXValueProperty(item), ! getCurrentDisplayedXValue(item))), ! new KeyFrame(Duration.millis(700), new KeyValue( ! currentDisplayedXValueProperty(item), ! item.getXValue(), Interpolator.EASE_BOTH)) ! ); ! } ! } ! ! private Timeline createDataRemoveTimeline(Data<X, Y> item, final Node bar, final Series<X, Y> series) { ! Timeline t = new Timeline(); ! if (orientation == Orientation.VERTICAL) { ! item.setYValue(getYAxis().toRealValue(getYAxis().getZeroPosition())); ! t.getKeyFrames().addAll( ! new KeyFrame(Duration.ZERO, new KeyValue( ! currentDisplayedYValueProperty(item), ! getCurrentDisplayedYValue(item))), ! new KeyFrame(Duration.millis(700), actionEvent -> { ! processDataRemove(series, item); ! }, new KeyValue( ! currentDisplayedYValueProperty(item), ! item.getYValue(), Interpolator.EASE_BOTH)) ! ); ! } else { ! item.setXValue(getXAxis().toRealValue(getXAxis().getZeroPosition())); ! t.getKeyFrames().addAll( ! new KeyFrame(Duration.ZERO, new KeyValue( ! currentDisplayedXValueProperty(item), ! getCurrentDisplayedXValue(item))), ! new KeyFrame(Duration.millis(700), actionEvent -> { ! processDataRemove(series, item); ! }, new KeyValue( ! currentDisplayedXValueProperty(item), ! item.getXValue(), Interpolator.EASE_BOTH)) ! ); ! } ! return t; ! } ! ! private Node createBar(Series<X, Y> series, int seriesIndex, final Data<X, Y> item, int itemIndex) { Node bar = item.getNode(); if (bar == null) { bar = new StackPane(); bar.setAccessibleRole(AccessibleRole.TEXT); bar.setAccessibleRoleDescription("Bar");
*** 575,585 **** private static final List<CssMetaData<? extends Styleable, ?>> STYLEABLES; static { final List<CssMetaData<? extends Styleable, ?>> styleables = ! new ArrayList<CssMetaData<? extends Styleable, ?>>(XYChart.getClassCssMetaData()); styleables.add(CATEGORY_GAP); STYLEABLES = Collections.unmodifiableList(styleables); } } --- 603,613 ---- private static final List<CssMetaData<? extends Styleable, ?>> STYLEABLES; static { final List<CssMetaData<? extends Styleable, ?>> styleables = ! new ArrayList<>(XYChart.getClassCssMetaData()); styleables.add(CATEGORY_GAP); STYLEABLES = Collections.unmodifiableList(styleables); } }
*** 602,611 **** --- 630,640 ---- } /** Pseudoclass indicating this is a vertical chart. */ private static final PseudoClass VERTICAL_PSEUDOCLASS_STATE = PseudoClass.getPseudoClass("vertical"); + /** Pseudoclass indicating this is a horizontal chart. */ private static final PseudoClass HORIZONTAL_PSEUDOCLASS_STATE = PseudoClass.getPseudoClass("horizontal"); }
< prev index next >