Spec-Zone .ru
спецификации, руководства, описания, API
001/*
002 * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation.  Oracle designates this
008 * particular file as subject to the "Classpath" exception as provided
009 * by Oracle in the LICENSE file that accompanied this code.
010 *
011 * This code is distributed in the hope that it will be useful, but WITHOUT
012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
014 * version 2 for more details (a copy is included in the LICENSE file that
015 * accompanied this code).
016 *
017 * You should have received a copy of the GNU General Public License version
018 * 2 along with this work; if not, write to the Free Software Foundation,
019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020 *
021 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
022 * or visit www.oracle.com if you need additional information or have any
023 * questions.
024 */
025
026package javafx.scene.chart;
027
028import javafx.animation.FadeTransition;
029import javafx.animation.ParallelTransition;
030import javafx.collections.FXCollections;
031import javafx.collections.ObservableList;
032import javafx.event.ActionEvent;
033import javafx.event.EventHandler;
034import javafx.scene.Node;
035import javafx.scene.layout.StackPane;
036import javafx.util.Duration;
037
038import com.sun.javafx.charts.Legend;
039import com.sun.javafx.charts.Legend.LegendItem;
040
041/**
042 * Chart type that plots symbols for the data points in a series.
043 */
044public class ScatterChart<X,Y> extends XYChart<X,Y> {
045
046    // -------------- PRIVATE FIELDS ------------------------------------------
047
048    private Legend legend = new Legend();
049
050    // -------------- CONSTRUCTORS ----------------------------------------------
051
052    /**
053     * Construct a new ScatterChart with the given axis and data.
054     *
055     * @param xAxis The x axis to use
056     * @param yAxis The y axis to use
057     */
058    public ScatterChart(Axis<X> xAxis, Axis<Y> yAxis) {
059        this(xAxis, yAxis, FXCollections.<Series<X, Y>>observableArrayList());
060    }
061
062    /**
063     * Construct a new ScatterChart with the given axis and data.
064     *
065     * @param xAxis The x axis to use
066     * @param yAxis The y axis to use
067     * @param data The data to use, this is the actual list used so any changes to it will be reflected in the chart
068     */
069    public ScatterChart(Axis<X> xAxis, Axis<Y> yAxis, ObservableList<Series<X,Y>> data) {
070        super(xAxis,yAxis);
071        setLegend(legend);
072        setData(data);
073    }
074
075    // -------------- METHODS ------------------------------------------------------------------------------------------
076
077    /** @inheritDoc */
078    @Override protected void dataItemAdded(Series<X,Y> series, int itemIndex, Data<X,Y> item) {
079        Node symbol = item.getNode();
080        // check if symbol has already been created
081        if (symbol == null) {
082            symbol = new StackPane();
083            item.setNode(symbol);
084        }
085        // set symbol styles
086        symbol.getStyleClass().setAll("chart-symbol", "series" + getData().indexOf(series), "data" + itemIndex,
087                series.defaultColorStyleClass);
088        // add and fade in new symbol if animated
089        if (shouldAnimate()) symbol.setOpacity(0);
090        getPlotChildren().add(symbol);
091        if (shouldAnimate()) {
092            FadeTransition ft = new FadeTransition(Duration.millis(500),symbol);
093            ft.setToValue(1);
094            ft.play();
095        }
096    }
097
098    /** @inheritDoc */
099    @Override protected  void dataItemRemoved(final Data<X,Y> item, final Series<X,Y> series) {
100        final Node symbol = item.getNode();
101        if (shouldAnimate()) {
102            // fade out old symbol
103            FadeTransition ft = new FadeTransition(Duration.millis(500),symbol);
104            ft.setToValue(0);
105            ft.setOnFinished(new EventHandler<ActionEvent>() {
106                @Override public void handle(ActionEvent actionEvent) {
107                    getPlotChildren().remove(symbol);
108                    removeDataItemFromDisplay(series, item);
109                }
110            });
111            ft.play();
112        } else {
113            getPlotChildren().remove(symbol);
114            removeDataItemFromDisplay(series, item);
115        }
116    }
117
118    /** @inheritDoc */
119    @Override protected void dataItemChanged(Data<X, Y> item) {
120    }
121    
122    /** @inheritDoc */
123    @Override protected  void seriesAdded(Series<X,Y> series, int seriesIndex) {
124        // handle any data already in series
125        for (int j=0; j<series.getData().size(); j++) {
126            dataItemAdded(series,j,series.getData().get(j));
127        }
128    }
129
130    /** @inheritDoc */
131    @Override protected  void seriesRemoved(final Series<X,Y> series) {
132        // remove all symbol nodes
133        if (shouldAnimate()) {
134            ParallelTransition pt = new ParallelTransition();
135            pt.setOnFinished(new EventHandler<ActionEvent>() {
136                public void handle(ActionEvent event) {
137                    removeSeriesFromDisplay(series);
138                }
139            });
140            for (final Data<X,Y> d : series.getData()) {
141                final Node symbol = d.getNode();
142                // fade out old symbol
143                FadeTransition ft = new FadeTransition(Duration.millis(500),symbol);
144                ft.setToValue(0);
145                ft.setOnFinished(new EventHandler<ActionEvent>() {
146                    @Override public void handle(ActionEvent actionEvent) {
147                        getPlotChildren().remove(symbol);
148                    }
149                });
150                pt.getChildren().add(ft);
151            }
152            pt.play();
153        } else {
154             for (final Data<X,Y> d : series.getData()) {
155                final Node symbol = d.getNode();
156                getPlotChildren().remove(symbol);
157            }
158             removeSeriesFromDisplay(series);
159        }
160    }
161
162    /** @inheritDoc */
163    @Override protected void layoutPlotChildren() {
164        // update symbol positions
165        for (int seriesIndex=0; seriesIndex < getDataSize(); seriesIndex++) {
166            Series<X,Y> series = getData().get(seriesIndex);
167            for (Data<X,Y> item = series.begin; item != null; item = item.next) {
168                double x = getXAxis().getDisplayPosition(item.getCurrentX());
169                double y = getYAxis().getDisplayPosition(item.getCurrentY());
170                Node symbol = item.getNode();
171                if (symbol != null) {
172                    final double w = symbol.prefWidth(-1);
173                    final double h = symbol.prefHeight(-1);
174                    symbol.resizeRelocate(x-(w/2), y-(h/2),w,h); 
175                }
176            }
177        }
178    }
179
180    /**
181     * This is called whenever a series is added or removed and the legend needs to be updated
182     */
183    @Override protected void updateLegend() {
184        legend.getItems().clear();
185        if (getData() != null) {
186            for (int seriesIndex=0; seriesIndex< getData().size(); seriesIndex++) {
187                Series<X,Y> series = getData().get(seriesIndex);
188                LegendItem legenditem = new LegendItem(series.getName());
189                if (!series.getData().isEmpty() && series.getData().get(0).getNode() != null) {
190                    legenditem.getSymbol().getStyleClass().addAll(series.getData().get(0).getNode().getStyleClass());
191                }
192                legend.getItems().add(legenditem);
193            }
194        }
195        if (legend.getItems().size() > 0) {
196            if (getLegend() == null) {
197                setLegend(legend);
198            }
199        } else {
200            setLegend(null);
201        }
202    }
203}