/*
* Copyright (c) 2010, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javafx.scene.chart;
import javafx.animation.FadeTransition;
import javafx.animation.ParallelTransition;
import javafx.application.Platform;
import javafx.beans.NamedArg;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.AccessibleRole;
import javafx.scene.Node;
import javafx.scene.layout.StackPane;
import javafx.util.Duration;
import com.sun.javafx.charts.Legend.LegendItem;
import java.util.Iterator;
Chart type that plots symbols for the data points in a series.
Since: JavaFX 2.0
/**
* Chart type that plots symbols for the data points in a series.
* @since JavaFX 2.0
*/
public class ScatterChart<X,Y> extends XYChart<X,Y> {
// -------------- CONSTRUCTORS ----------------------------------------------
Construct a new ScatterChart with the given axis and data.
Params: - xAxis – The x axis to use
- yAxis – The y axis to use
/**
* Construct a new ScatterChart with the given axis and data.
*
* @param xAxis The x axis to use
* @param yAxis The y axis to use
*/
public ScatterChart(@NamedArg("xAxis") Axis<X> xAxis, @NamedArg("yAxis") Axis<Y> yAxis) {
this(xAxis, yAxis, FXCollections.<Series<X, Y>>observableArrayList());
}
Construct a new ScatterChart with the given axis and data.
Params: - xAxis – The x axis to use
- yAxis – The y axis to use
- data – The data to use, this is the actual list used so any changes to it will be reflected in the chart
/**
* Construct a new ScatterChart with the given axis and data.
*
* @param xAxis The x axis to use
* @param yAxis The y axis to use
* @param data The data to use, this is the actual list used so any changes to it will be reflected in the chart
*/
public ScatterChart(@NamedArg("xAxis") Axis<X> xAxis, @NamedArg("yAxis") Axis<Y> yAxis, @NamedArg("data") ObservableList<Series<X,Y>> data) {
super(xAxis,yAxis);
setData(data);
}
// -------------- METHODS ------------------------------------------------------------------------------------------
{@inheritDoc} /** {@inheritDoc} */
@Override protected void dataItemAdded(Series<X,Y> series, int itemIndex, Data<X,Y> item) {
Node symbol = item.getNode();
// check if symbol has already been created
if (symbol == null) {
symbol = new StackPane();
symbol.setAccessibleRole(AccessibleRole.TEXT);
symbol.setAccessibleRoleDescription("Point");
symbol.focusTraversableProperty().bind(Platform.accessibilityActiveProperty());
item.setNode(symbol);
}
// set symbol styles
symbol.getStyleClass().setAll("chart-symbol", "series" + getData().indexOf(series), "data" + itemIndex,
series.defaultColorStyleClass);
// add and fade in new symbol if animated
if (shouldAnimate()) {
symbol.setOpacity(0);
getPlotChildren().add(symbol);
FadeTransition ft = new FadeTransition(Duration.millis(500),symbol);
ft.setToValue(1);
ft.play();
} else {
getPlotChildren().add(symbol);
}
}
{@inheritDoc} /** {@inheritDoc} */
@Override protected void dataItemRemoved(final Data<X,Y> item, final Series<X,Y> series) {
final Node symbol = item.getNode();
if (symbol != null) {
symbol.focusTraversableProperty().unbind();
}
if (shouldAnimate()) {
// fade out old symbol
FadeTransition ft = new FadeTransition(Duration.millis(500),symbol);
ft.setToValue(0);
ft.setOnFinished(actionEvent -> {
getPlotChildren().remove(symbol);
removeDataItemFromDisplay(series, item);
symbol.setOpacity(1.0);
});
ft.play();
} else {
getPlotChildren().remove(symbol);
removeDataItemFromDisplay(series, item);
}
}
{@inheritDoc} /** {@inheritDoc} */
@Override protected void dataItemChanged(Data<X, Y> item) {
}
{@inheritDoc} /** {@inheritDoc} */
@Override protected void seriesAdded(Series<X,Y> series, int seriesIndex) {
// handle any data already in series
for (int j=0; j<series.getData().size(); j++) {
dataItemAdded(series,j,series.getData().get(j));
}
}
{@inheritDoc} /** {@inheritDoc} */
@Override protected void seriesRemoved(final Series<X,Y> series) {
// remove all symbol nodes
if (shouldAnimate()) {
ParallelTransition pt = new ParallelTransition();
pt.setOnFinished(event -> {
removeSeriesFromDisplay(series);
});
for (final Data<X,Y> d : series.getData()) {
final Node symbol = d.getNode();
// fade out old symbol
FadeTransition ft = new FadeTransition(Duration.millis(500),symbol);
ft.setToValue(0);
ft.setOnFinished(actionEvent -> {
getPlotChildren().remove(symbol);
symbol.setOpacity(1.0);
});
pt.getChildren().add(ft);
}
pt.play();
} else {
for (final Data<X,Y> d : series.getData()) {
final Node symbol = d.getNode();
getPlotChildren().remove(symbol);
}
removeSeriesFromDisplay(series);
}
}
{@inheritDoc} /** {@inheritDoc} */
@Override protected void layoutPlotChildren() {
// update symbol positions
for (int seriesIndex=0; seriesIndex < getDataSize(); seriesIndex++) {
Series<X,Y> series = getData().get(seriesIndex);
for (Iterator<Data<X, Y>> it = getDisplayedDataIterator(series); it.hasNext(); ) {
Data<X, Y> item = it.next();
double x = getXAxis().getDisplayPosition(item.getCurrentX());
double y = getYAxis().getDisplayPosition(item.getCurrentY());
if (Double.isNaN(x) || Double.isNaN(y)) {
continue;
}
Node symbol = item.getNode();
if (symbol != null) {
final double w = symbol.prefWidth(-1);
final double h = symbol.prefHeight(-1);
symbol.resizeRelocate(x-(w/2), y-(h/2),w,h);
}
}
}
}
@Override
LegendItem createLegendItemForSeries(Series<X, Y> series, int seriesIndex) {
LegendItem legendItem = new LegendItem(series.getName());
Node node = series.getData().isEmpty() ? null : series.getData().get(0).getNode();
if (node != null) {
legendItem.getSymbol().getStyleClass().addAll(node.getStyleClass());
}
return legendItem;
}
}