< 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 >