Bonjour,

Je suis plutôt novice en java et encore plus avec javafx, donc la solution est sans doute toute bête mais elle m'échappe.

En suivant les modèles disponibles dans la documentation Oracle et sur le net, j'ai construit un un chart personnalisé appelé "HisTChart".
Ce HisTChart fonctionne avec un DateAxis en xAxis et un CategoryAxis en yAxis.

Les datas traités contiennent une date de début, une catégorie, une date de fin et un titre. La date de fin et le titre sont contenus dans une extraValue personnalisée.

Ces datas sont affichés sur le HisTChart par un Node personnalisé appelé "TimeRegion" qui se présente comme une Region "tRegion" (couvrant la zone entre la date de début et la date de fin en abscisse, un pourcentage de l'espacement entre catégories en ordonnée) et un Text "tText" pour afficher un texte au dessus.

J'ai implémenté toutes les méthodes abstraites nécessaires pour faire un chart héritant de XYChart.

Le TimeRegion s'affiche correctement mais le tRegion qu'il contient ne s'affiche pas. Le tText, lui, s'affiche correctement.

Si vous pouviez m'aider à saisir où est l'erreur avec la Region contenue dans mon Node, ça soulagerait mon cuir chevelu. Merci d'avance !

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
package histime;
 
import java.util.Date;
import java.util.Iterator;
import javafx.animation.FadeTransition;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.chart.Axis;
import javafx.scene.chart.CategoryAxis;
import javafx.scene.chart.XYChart;
import javafx.scene.layout.Region;
import javafx.scene.text.Text;
import javafx.util.Duration;
 
/**
 *
 * @author benoi_000
 */
public class HisTChart extends XYChart <Date, String> {
 
    public HisTChart(Axis<Date> xAxis, Axis<String> yAxis) {
        super(xAxis, yAxis);
 
    }
 
    @Override
    protected void dataItemAdded(Series<Date, String> series, int itemIndex, Data<Date, String> item) {
       Node timeRegion = createTimeRegion(getData().indexOf(series), item, itemIndex);
        if (shouldAnimate()) {
            timeRegion.setOpacity(0);
            getPlotChildren().add(timeRegion);
            // Effet de transition en fade in
            FadeTransition ft = new FadeTransition(Duration.millis(500), timeRegion);
            ft.setToValue(1);
            ft.play();
        } else {
            getPlotChildren().add(timeRegion);
        }
        //always draw average line on top
        //if (series.getNode() != null) series.getNode().toFront();
    }
 
    @Override
    protected void dataItemRemoved(Data<Date, String> item, Series<Date, String> series) {
        final Node timeRegion = item.getNode();
        if (shouldAnimate()) {
            // suppression en fade out
            FadeTransition ft = new FadeTransition(Duration.millis(500), timeRegion);
            ft.setToValue(0);
            ft.setOnFinished(new EventHandler<ActionEvent>() {
                @Override public void handle(ActionEvent actionEvent) {
                    getPlotChildren().remove(timeRegion);
                }
            });
            ft.play();
        } else {
            // suppression barbare !
            getPlotChildren().remove(timeRegion);
        }
    }
 
    @Override
    protected void dataItemChanged(Data<Date, String> data) {
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
    }
 
    @Override
    protected void seriesAdded(Series<Date, String> series, int seriesIndex) {
        for (int j=0; j<series.getData().size(); j++) {
            Data item = series.getData().get(j);
            Node timeRegion = createTimeRegion(seriesIndex, item, j);
            if (shouldAnimate()) {
                timeRegion.setOpacity(0);
                getPlotChildren().add(timeRegion);
                //effet animé fade in du nouveau timeRegion
                FadeTransition ft = new FadeTransition(Duration.millis(500),timeRegion);
                ft.setToValue(1);
                ft.play();
            } else {
                getPlotChildren().add(timeRegion);
            }
        }
    }
 
    @Override
    protected void seriesRemoved(Series<Date, String> series) {
        for (XYChart.Data<Date, String> d : series.getData()) {
            final Node timeRegion = d.getNode();
            if (shouldAnimate()) {
                // fade out encore
                FadeTransition ft = new FadeTransition(Duration.millis(500),timeRegion);
                ft.setToValue(0);
                ft.setOnFinished(new EventHandler<ActionEvent>() {
                    @Override public void handle(ActionEvent actionEvent) {
                        getPlotChildren().remove(timeRegion);
                    }
                });
                ft.play();
            } else {
                getPlotChildren().remove(timeRegion);
            }
        }
    }
 
    @Override
    protected void layoutPlotChildren() {
        // si pas de data, pas de layout
        if(getData() == null) return;
 
        // sinon, update des timeRegions
        for (int seriesIndex=0; seriesIndex < getData().size(); seriesIndex++) {
            Series<Date,String> series = getData().get(seriesIndex);
            Iterator<Data<Date,String>> iter = getDisplayedDataIterator(series);
 
            while(iter.hasNext()) {
                // récupération de l'item
                Data<Date, String> item = iter.next();
 
                // récupération de ses valeurs x, y et extravalue
                double x = getXAxis().getDisplayPosition(getCurrentDisplayedXValue(item));
                System.out.println("display Position x = " + x);
                double y = getYAxis().getDisplayPosition(getCurrentDisplayedYValue(item));
                System.out.println("display position y = " + y);
                TimeRegionExtraValues extra = (TimeRegionExtraValues)item.getExtraValue();
 
                //récupération de son Node associé
                Node itemNode = item.getNode();
 
                //si l'item a déjà un Node de type TimeRegion, on met à jour ce TimeRegion
                if (itemNode instanceof TimeRegion && extra != null) {
                    TimeRegion timeRegion = (TimeRegion) itemNode;
 
                    double dateEnd = getXAxis().getDisplayPosition(extra.getDateEnd());
                    System.out.println("display position dateEnd = " + dateEnd);
 
                    // détermination de la hauteur d'un timeRegion
                    CategoryAxis yAxis = (CategoryAxis)getYAxis();
                    double timeRegionHeight = yAxis.getCategorySpacing() * 0.90; // 90% de l'écart entre catégories
                    System.out.println("timeRegionHeight = " + timeRegionHeight);
 
                    // màj de la timeRegion
                    timeRegion.update((dateEnd-x), timeRegionHeight);
 
                    // positionnement de la timeRegion
                    timeRegion.setLayoutX(x);
                    timeRegion.setLayoutY(y-(timeRegionHeight/2));
 
                }
 
            }
        }
    }
 
    /**
     * Créer un nouveau Node TimeRegion pour un item
     *
     * @param seriesIndex index de la série dans laquelle se trouve l'item
     * @param item        item pour lequel créer la TimeRegion
     * @param itemIndex   index de l'item dans la série
     * @return Nouveau Node pour représenter l'item
     */
    private Node createTimeRegion(int seriesIndex, final Data item, int itemIndex) {
 
        Node timeRegion = item.getNode();
 
        // Vérifier si timeRegion n'est pas déjà créée
        if (timeRegion instanceof TimeRegion) {
 
            ((TimeRegion) timeRegion).setSeriesAndDataStyleClasses("series" + seriesIndex, "data" + itemIndex);
 
        } else {
 
            timeRegion = new TimeRegion("series" + seriesIndex, "data" + itemIndex);
            item.setNode(timeRegion);
 
        }
        return timeRegion;
    }
 
    private static class TimeRegion extends Group {
        private String seriesStyleClass;
        private String dataStyleClass;
        private Region tRegion = new Region();
        private Text tText = new Text();
 
        public TimeRegion(String seriesStyleClass, String dataStyleClass) {
            setAutoSizeChildren(false);
            getChildren().addAll(tRegion, tText);
            this.seriesStyleClass = seriesStyleClass;
            this.dataStyleClass = dataStyleClass;
            updateStyleClasses();
                    }
 
        public void update(double tRegionWidth, double tRegionHeight) {
 
            updateStyleClasses();
            tRegion.resizeRelocate(tRegionWidth/2, tRegionHeight/2, tRegionWidth, tRegionHeight);
            tText.setText("Test !!!");
 
        }
 
        public void setSeriesAndDataStyleClasses(String seriesStyleClass , String dataStyleClass) {
            this.seriesStyleClass = seriesStyleClass;
            this.dataStyleClass = dataStyleClass;
            updateStyleClasses();
        }
 
        private void updateStyleClasses() {
            getStyleClass().setAll("TimeRegion-timeRegion",seriesStyleClass,dataStyleClass);
            tText.getStyleClass().setAll("TimeRegion-tText",seriesStyleClass,dataStyleClass);
            tRegion.getStyleClass().setAll("IimeRegion-tRegion",seriesStyleClass,dataStyleClass);
        }
 
    }
 
    public static class TimeRegionExtraValues {
        private Date dateEnd;
        private String title;
 
        public TimeRegionExtraValues(Date dateEnd, String title) {
            this.dateEnd = dateEnd;
            this.title = title;
        }
 
        public Date getDateEnd() {
            return dateEnd;
        }
 
        public String getTitle() {
            return title;
        }
    }
 
}