< prev index next >

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

Print this page




 155                 int nextClearBit = colorBits.nextClearBit(0);
 156                 colorBits.set(nextClearBit, true);
 157                 s.defaultColorStyleClass = DEFAULT_COLOR+(nextClearBit%8);
 158                 seriesColorMap.put(s, nextClearBit%8);
 159                 // inform sub-classes of series added
 160                 seriesAdded(s, i);
 161             }
 162             if (c.getFrom() < c.getTo()) updateLegend();
 163             seriesChanged(c);
 164 
 165         }
 166         // update axis ranges
 167         invalidateRange();
 168         // lay everything out
 169         requestChartLayout();
 170     };
 171 
 172     // -------------- PUBLIC PROPERTIES --------------------------------------------------------------------------------
 173 
 174     private final Axis<X> xAxis;
 175     /** Get the X axis, by default it is along the bottom of the plot */



 176     public Axis<X> getXAxis() { return xAxis; }
 177 
 178     private final Axis<Y> yAxis;
 179     /** Get the Y axis, by default it is along the left of the plot */



 180     public Axis<Y> getYAxis() { return yAxis; }
 181 
 182     /** XYCharts data */
 183     private ObjectProperty<ObservableList<Series<X,Y>>> data = new ObjectPropertyBase<ObservableList<Series<X,Y>>>() {
 184         private ObservableList<Series<X,Y>> old;
 185         @Override protected void invalidated() {
 186             final ObservableList<Series<X,Y>> current = getValue();
 187             if (current == old) return;
 188             int saveAnimationState = -1;
 189             // add remove listeners
 190             if(old != null) {
 191                 old.removeListener(seriesChanged);
 192                 // Set animated to false so we don't animate both remove and add
 193                 // at the same time. RT-14163
 194                 // RT-21295 - disable animated only when current is also not null.
 195                 if (current != null && old.size() > 0) {
 196                     saveAnimationState = (old.get(0).getChart().getAnimated()) ? 1 : 2;
 197                     old.get(0).getChart().setAnimated(false);
 198                 }
 199             }


 595     /**
 596      * A series has been added to the charts data model. This is where implementations of XYChart can create/add new
 597      * nodes to getPlotChildren to represent this series. Also you have to handle adding any data items that are
 598      * already in the series. You may simply call dataItemAdded() for each one or provide some different animation for
 599      * a whole series being added.
 600      *
 601      * @param series      The series that has been added
 602      * @param seriesIndex The index of the new series
 603      */
 604     protected abstract void seriesAdded(Series<X, Y> series, int seriesIndex);
 605 
 606     /**
 607      * A series has been removed from the data model but it is still visible on the chart. Its still visible
 608      * so that you can handle animation for removing it in this method. After you are done animating the data item you
 609      * must call removeSeriesFromDisplay() to remove the series from the display list.
 610      *
 611      * @param series The series that has been removed
 612      */
 613     protected abstract void seriesRemoved(Series<X,Y> series);
 614 
 615     /** Called when each atomic change is made to the list of series for this chart */



 616     protected void seriesChanged(Change<? extends Series> c) {}
 617 
 618     /**
 619      * This is called when a data change has happened that may cause the range to be invalid.
 620      */
 621     private void invalidateRange() {
 622         rangeValid = false;
 623     }
 624 
 625     /**
 626      * This is called when the range has been invalidated and we need to update it. If the axis are auto
 627      * ranging then we compile a list of all data that the given axis has to plot and call invalidateRange() on the
 628      * axis passing it that data.
 629      */
 630     protected void updateAxisRange() {
 631         final Axis<X> xa = getXAxis();
 632         final Axis<Y> ya = getYAxis();
 633         List<X> xData = null;
 634         List<Y> yData = null;
 635         if(xa.isAutoRanging()) xData = new ArrayList<X>();
 636         if(ya.isAutoRanging()) yData = new ArrayList<Y>();
 637         if(xData != null || yData != null) {
 638             for(Series<X,Y> series : getData()) {
 639                 for(Data<X,Y> data: series.getData()) {
 640                     if(xData != null) xData.add(data.getXValue());
 641                     if(yData != null) yData.add(data.getYValue());
 642                 }
 643             }
 644             if(xData != null) xa.invalidateRange(xData);
 645             if(yData != null) ya.invalidateRange(yData);
 646         }
 647     }
 648 
 649     /**
 650      * Called to update and layout the plot children. This should include all work to updates nodes representing
 651      * the plot on top of the axis and grid lines etc. The origin is the top left of the plot area, the plot area with
 652      * can be got by getting the width of the x axis and its height from the height of the y axis.
 653      */
 654     protected abstract void layoutPlotChildren();
 655 
 656     /** @inheritDoc */
 657     @Override protected final void layoutChartChildren(double top, double left, double width, double height) {
 658         if(getData() == null) return;
 659         if (!rangeValid) {
 660             rangeValid = true;
 661             if(getData() != null) updateAxisRange();
 662         }
 663         // snap top and left to pixels
 664         top = snapPositionY(top);
 665         left = snapPositionX(left);
 666         // get starting stuff
 667         final Axis<X> xa = getXAxis();
 668         final ObservableList<Axis.TickMark<X>> xaTickMarks = xa.getTickMarks();
 669         final Axis<Y> ya = getYAxis();
 670         final ObservableList<Axis.TickMark<Y>> yaTickMarks = ya.getTickMarks();
 671         // check we have 2 axises and know their sides
 672         if (xa == null || ya == null) return;
 673         // try and work out width and height of axises
 674         double xAxisWidth = 0;
 675         double xAxisHeight = 30; // guess x axis height to start with
 676         double yAxisWidth = 0;


 946         KeyValue[] startValues = new KeyValue[nodes.size()];
 947         KeyValue[] endValues = new KeyValue[nodes.size()];
 948         for (int j = 0; j < nodes.size(); j++) {
 949             startValues[j] = new KeyValue(nodes.get(j).opacityProperty(), 1);
 950             endValues[j] = new KeyValue(nodes.get(j).opacityProperty(), 0);
 951         }
 952         return new KeyFrame[] {
 953             new KeyFrame(Duration.ZERO, startValues),
 954             new KeyFrame(Duration.millis(fadeOutTime), actionEvent -> {
 955                 getPlotChildren().removeAll(nodes);
 956                 removeSeriesFromDisplay(series);
 957             }, endValues)
 958         };
 959     }
 960 
 961     /**
 962      * The current displayed data value plotted on the X axis. This may be the same as xValue or different. It is
 963      * used by XYChart to animate the xValue from the old value to the new value. This is what you should plot
 964      * in any custom XYChart implementations. Some XYChart chart implementations such as LineChart also use this
 965      * to animate when data is added or removed.


 966      */
 967     protected final X getCurrentDisplayedXValue(Data<X,Y> item) { return item.getCurrentX(); }
 968 
 969     /** Set the current displayed data value plotted on X axis.
 970      *
 971      * @param item The XYChart.Data item from which the current X axis data value is obtained.

 972      * @see #getCurrentDisplayedXValue
 973      */
 974     protected final void setCurrentDisplayedXValue(Data<X,Y> item, X value) { item.setCurrentX(value); }
 975 
 976     /** The current displayed data value property that is plotted on X axis.
 977      *
 978      * @param item The XYChart.Data item from which the current X axis data value property object is obtained.
 979      * @return The current displayed X data value ObjectProperty.
 980      * @see #getCurrentDisplayedXValue
 981      */
 982     protected final ObjectProperty<X> currentDisplayedXValueProperty(Data<X,Y> item) { return item.currentXProperty(); }
 983 
 984     /**
 985      * The current displayed data value plotted on the Y axis. This may be the same as yValue or different. It is
 986      * used by XYChart to animate the yValue from the old value to the new value. This is what you should plot
 987      * in any custom XYChart implementations. Some XYChart chart implementations such as LineChart also use this
 988      * to animate when data is added or removed.


 989      */
 990     protected final Y getCurrentDisplayedYValue(Data<X,Y> item) { return item.getCurrentY(); }
 991 
 992     /**
 993      * Set the current displayed data value plotted on Y axis.
 994      *
 995      * @param item The XYChart.Data item from which the current Y axis data value is obtained.

 996      * @see #getCurrentDisplayedYValue
 997      */
 998     protected final void setCurrentDisplayedYValue(Data<X,Y> item, Y value) { item.setCurrentY(value); }
 999 
1000     /** The current displayed data value property that is plotted on Y axis.
1001      *
1002      * @param item The XYChart.Data item from which the current Y axis data value property object is obtained.
1003      * @return The current displayed Y data value ObjectProperty.
1004      * @see #getCurrentDisplayedYValue
1005      */
1006     protected final ObjectProperty<Y> currentDisplayedYValueProperty(Data<X,Y> item) { return item.currentYProperty(); }
1007 
1008     /**
1009      * The current displayed data extra value. This may be the same as extraValue or different. It is
1010      * used by XYChart to animate the extraValue from the old value to the new value. This is what you should plot
1011      * in any custom XYChart implementations.


1012      */
1013     protected final Object getCurrentDisplayedExtraValue(Data<X,Y> item) { return item.getCurrentExtraValue(); }
1014 
1015     /**
1016      * Set the current displayed data extra value.
1017      *
1018      * @param item The XYChart.Data item from which the current extra value is obtained.

1019      * @see #getCurrentDisplayedExtraValue
1020      */
1021     protected final void setCurrentDisplayedExtraValue(Data<X,Y> item, Object value) { item.setCurrentExtraValue(value); }
1022 
1023     /**
1024      * The current displayed extra value property.
1025      *
1026      * @param item The XYChart.Data item from which the current extra value property object is obtained.
1027      * @return ObjectProperty<Object> The current extra value ObjectProperty
1028      * @see #getCurrentDisplayedExtraValue
1029      */
1030     protected final ObjectProperty<Object> currentDisplayedExtraValueProperty(Data<X,Y> item) { return item.currentExtraValueProperty(); }
1031 
1032     /**
1033      * XYChart maintains a list of all items currently displayed this includes all current data + any data items
1034      * recently deleted that are in the process of being faded out. This creates and returns a iterator over
1035      * that list. This is what implementations of XYChart should use when plotting data.
1036      *
1037      * @param series The series to get displayed data for
1038      * @return iterator over currently displayed items from this series
1039      */
1040     protected final Iterator<Data<X,Y>> getDisplayedDataIterator(final Series<X,Y> series) {
1041         return Collections.unmodifiableList(series.displayedData).iterator();
1042     }
1043 
1044     /**
1045      * This should be called from dataItemRemoved() when you are finished with any animation for deleting the item from the
1046      * chart. It will remove the data item from showing up in the Iterator returned by getDisplayedDataIterator().
1047      *




 155                 int nextClearBit = colorBits.nextClearBit(0);
 156                 colorBits.set(nextClearBit, true);
 157                 s.defaultColorStyleClass = DEFAULT_COLOR+(nextClearBit%8);
 158                 seriesColorMap.put(s, nextClearBit%8);
 159                 // inform sub-classes of series added
 160                 seriesAdded(s, i);
 161             }
 162             if (c.getFrom() < c.getTo()) updateLegend();
 163             seriesChanged(c);
 164 
 165         }
 166         // update axis ranges
 167         invalidateRange();
 168         // lay everything out
 169         requestChartLayout();
 170     };
 171 
 172     // -------------- PUBLIC PROPERTIES --------------------------------------------------------------------------------
 173 
 174     private final Axis<X> xAxis;
 175     /**
 176      * Get the X axis, by default it is along the bottom of the plot
 177      * @return the X axis of the chart
 178      */
 179     public Axis<X> getXAxis() { return xAxis; }
 180 
 181     private final Axis<Y> yAxis;
 182     /**
 183      * Get the Y axis, by default it is along the left of the plot
 184      * @return the Y axis of this chart
 185      */
 186     public Axis<Y> getYAxis() { return yAxis; }
 187 
 188     /** XYCharts data */
 189     private ObjectProperty<ObservableList<Series<X,Y>>> data = new ObjectPropertyBase<ObservableList<Series<X,Y>>>() {
 190         private ObservableList<Series<X,Y>> old;
 191         @Override protected void invalidated() {
 192             final ObservableList<Series<X,Y>> current = getValue();
 193             if (current == old) return;
 194             int saveAnimationState = -1;
 195             // add remove listeners
 196             if(old != null) {
 197                 old.removeListener(seriesChanged);
 198                 // Set animated to false so we don't animate both remove and add
 199                 // at the same time. RT-14163
 200                 // RT-21295 - disable animated only when current is also not null.
 201                 if (current != null && old.size() > 0) {
 202                     saveAnimationState = (old.get(0).getChart().getAnimated()) ? 1 : 2;
 203                     old.get(0).getChart().setAnimated(false);
 204                 }
 205             }


 601     /**
 602      * A series has been added to the charts data model. This is where implementations of XYChart can create/add new
 603      * nodes to getPlotChildren to represent this series. Also you have to handle adding any data items that are
 604      * already in the series. You may simply call dataItemAdded() for each one or provide some different animation for
 605      * a whole series being added.
 606      *
 607      * @param series      The series that has been added
 608      * @param seriesIndex The index of the new series
 609      */
 610     protected abstract void seriesAdded(Series<X, Y> series, int seriesIndex);
 611 
 612     /**
 613      * A series has been removed from the data model but it is still visible on the chart. Its still visible
 614      * so that you can handle animation for removing it in this method. After you are done animating the data item you
 615      * must call removeSeriesFromDisplay() to remove the series from the display list.
 616      *
 617      * @param series The series that has been removed
 618      */
 619     protected abstract void seriesRemoved(Series<X,Y> series);
 620 
 621     /**
 622      * Called when each atomic change is made to the list of series for this chart
 623      * @param c The series that has been changed
 624      */
 625     protected void seriesChanged(Change<? extends Series> c) {}
 626 
 627     /**
 628      * This is called when a data change has happened that may cause the range to be invalid.
 629      */
 630     private void invalidateRange() {
 631         rangeValid = false;
 632     }
 633 
 634     /**
 635      * This is called when the range has been invalidated and we need to update it. If the axis are auto
 636      * ranging then we compile a list of all data that the given axis has to plot and call invalidateRange() on the
 637      * axis passing it that data.
 638      */
 639     protected void updateAxisRange() {
 640         final Axis<X> xa = getXAxis();
 641         final Axis<Y> ya = getYAxis();
 642         List<X> xData = null;
 643         List<Y> yData = null;
 644         if(xa.isAutoRanging()) xData = new ArrayList<X>();
 645         if(ya.isAutoRanging()) yData = new ArrayList<Y>();
 646         if(xData != null || yData != null) {
 647             for(Series<X,Y> series : getData()) {
 648                 for(Data<X,Y> data: series.getData()) {
 649                     if(xData != null) xData.add(data.getXValue());
 650                     if(yData != null) yData.add(data.getYValue());
 651                 }
 652             }
 653             if(xData != null) xa.invalidateRange(xData);
 654             if(yData != null) ya.invalidateRange(yData);
 655         }
 656     }
 657 
 658     /**
 659      * Called to update and layout the plot children. This should include all work to updates nodes representing
 660      * the plot on top of the axis and grid lines etc. The origin is the top left of the plot area, the plot area with
 661      * can be got by getting the width of the x axis and its height from the height of the y axis.
 662      */
 663     protected abstract void layoutPlotChildren();
 664 
 665     /** {@inheritDoc} */
 666     @Override protected final void layoutChartChildren(double top, double left, double width, double height) {
 667         if(getData() == null) return;
 668         if (!rangeValid) {
 669             rangeValid = true;
 670             if(getData() != null) updateAxisRange();
 671         }
 672         // snap top and left to pixels
 673         top = snapPositionY(top);
 674         left = snapPositionX(left);
 675         // get starting stuff
 676         final Axis<X> xa = getXAxis();
 677         final ObservableList<Axis.TickMark<X>> xaTickMarks = xa.getTickMarks();
 678         final Axis<Y> ya = getYAxis();
 679         final ObservableList<Axis.TickMark<Y>> yaTickMarks = ya.getTickMarks();
 680         // check we have 2 axises and know their sides
 681         if (xa == null || ya == null) return;
 682         // try and work out width and height of axises
 683         double xAxisWidth = 0;
 684         double xAxisHeight = 30; // guess x axis height to start with
 685         double yAxisWidth = 0;


 955         KeyValue[] startValues = new KeyValue[nodes.size()];
 956         KeyValue[] endValues = new KeyValue[nodes.size()];
 957         for (int j = 0; j < nodes.size(); j++) {
 958             startValues[j] = new KeyValue(nodes.get(j).opacityProperty(), 1);
 959             endValues[j] = new KeyValue(nodes.get(j).opacityProperty(), 0);
 960         }
 961         return new KeyFrame[] {
 962             new KeyFrame(Duration.ZERO, startValues),
 963             new KeyFrame(Duration.millis(fadeOutTime), actionEvent -> {
 964                 getPlotChildren().removeAll(nodes);
 965                 removeSeriesFromDisplay(series);
 966             }, endValues)
 967         };
 968     }
 969 
 970     /**
 971      * The current displayed data value plotted on the X axis. This may be the same as xValue or different. It is
 972      * used by XYChart to animate the xValue from the old value to the new value. This is what you should plot
 973      * in any custom XYChart implementations. Some XYChart chart implementations such as LineChart also use this
 974      * to animate when data is added or removed.
 975      * @param item The XYChart.Data item from which the current X axis data value is obtained
 976      * @return The current displayed X data value
 977      */
 978     protected final X getCurrentDisplayedXValue(Data<X,Y> item) { return item.getCurrentX(); }
 979 
 980     /** Set the current displayed data value plotted on X axis.
 981      *
 982      * @param item The XYChart.Data item from which the current X axis data value is obtained.
 983      * @param value The X axis data value
 984      * @see #getCurrentDisplayedXValue
 985      */
 986     protected final void setCurrentDisplayedXValue(Data<X,Y> item, X value) { item.setCurrentX(value); }
 987 
 988     /** The current displayed data value property that is plotted on X axis.
 989      *
 990      * @param item The XYChart.Data item from which the current X axis data value property object is obtained.
 991      * @return The current displayed X data value ObjectProperty.
 992      * @see #getCurrentDisplayedXValue
 993      */
 994     protected final ObjectProperty<X> currentDisplayedXValueProperty(Data<X,Y> item) { return item.currentXProperty(); }
 995 
 996     /**
 997      * The current displayed data value plotted on the Y axis. This may be the same as yValue or different. It is
 998      * used by XYChart to animate the yValue from the old value to the new value. This is what you should plot
 999      * in any custom XYChart implementations. Some XYChart chart implementations such as LineChart also use this
1000      * to animate when data is added or removed.
1001      * @param item The XYChart.Data item from which the current Y axis data value is obtained
1002      * @return The current displayed Y data value
1003      */
1004     protected final Y getCurrentDisplayedYValue(Data<X,Y> item) { return item.getCurrentY(); }
1005 
1006     /**
1007      * Set the current displayed data value plotted on Y axis.
1008      *
1009      * @param item The XYChart.Data item from which the current Y axis data value is obtained.
1010      * @param value The Y axis data value
1011      * @see #getCurrentDisplayedYValue
1012      */
1013     protected final void setCurrentDisplayedYValue(Data<X,Y> item, Y value) { item.setCurrentY(value); }
1014 
1015     /** The current displayed data value property that is plotted on Y axis.
1016      *
1017      * @param item The XYChart.Data item from which the current Y axis data value property object is obtained.
1018      * @return The current displayed Y data value ObjectProperty.
1019      * @see #getCurrentDisplayedYValue
1020      */
1021     protected final ObjectProperty<Y> currentDisplayedYValueProperty(Data<X,Y> item) { return item.currentYProperty(); }
1022 
1023     /**
1024      * The current displayed data extra value. This may be the same as extraValue or different. It is
1025      * used by XYChart to animate the extraValue from the old value to the new value. This is what you should plot
1026      * in any custom XYChart implementations.
1027      * @param item The XYChart.Data item from which the current extra value is obtained
1028      * @return The current extra value
1029      */
1030     protected final Object getCurrentDisplayedExtraValue(Data<X,Y> item) { return item.getCurrentExtraValue(); }
1031 
1032     /**
1033      * Set the current displayed data extra value.
1034      *
1035      * @param item The XYChart.Data item from which the current extra value is obtained.
1036      * @param value The extra value
1037      * @see #getCurrentDisplayedExtraValue
1038      */
1039     protected final void setCurrentDisplayedExtraValue(Data<X,Y> item, Object value) { item.setCurrentExtraValue(value); }
1040 
1041     /**
1042      * The current displayed extra value property.
1043      *
1044      * @param item The XYChart.Data item from which the current extra value property object is obtained.
1045      * @return {@literal ObjectProperty<Object> The current extra value ObjectProperty}
1046      * @see #getCurrentDisplayedExtraValue
1047      */
1048     protected final ObjectProperty<Object> currentDisplayedExtraValueProperty(Data<X,Y> item) { return item.currentExtraValueProperty(); }
1049 
1050     /**
1051      * XYChart maintains a list of all items currently displayed this includes all current data + any data items
1052      * recently deleted that are in the process of being faded out. This creates and returns a iterator over
1053      * that list. This is what implementations of XYChart should use when plotting data.
1054      *
1055      * @param series The series to get displayed data for
1056      * @return iterator over currently displayed items from this series
1057      */
1058     protected final Iterator<Data<X,Y>> getDisplayedDataIterator(final Series<X,Y> series) {
1059         return Collections.unmodifiableList(series.displayedData).iterator();
1060     }
1061 
1062     /**
1063      * This should be called from dataItemRemoved() when you are finished with any animation for deleting the item from the
1064      * chart. It will remove the data item from showing up in the Iterator returned by getDisplayedDataIterator().
1065      *


< prev index next >