View Javadoc
1   /*
2    * Tethys: GUI Utilities
3    * Copyright 2012-2026. Tony Washer
4    *
5    * Licensed under the Apache License, Version 2.0 (the "License"); you may not
6    * use this file except in compliance with the License.  You may obtain a copy
7    * of the License at
8    *
9    *   http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
14   * License for the specific language governing permissions and limitations under
15   * the License.
16   */
17  package io.github.tonywasher.joceanus.tethys.core.chart;
18  
19  import io.github.tonywasher.joceanus.oceanus.date.OceanusDate;
20  import io.github.tonywasher.joceanus.oceanus.decimal.OceanusDecimalFormatter;
21  import io.github.tonywasher.joceanus.oceanus.decimal.OceanusDecimalParser;
22  import io.github.tonywasher.joceanus.oceanus.decimal.OceanusMoney;
23  import io.github.tonywasher.joceanus.oceanus.event.OceanusEventManager;
24  import io.github.tonywasher.joceanus.oceanus.event.OceanusEventRegistrar;
25  import io.github.tonywasher.joceanus.tethys.api.base.TethysUIEvent;
26  import io.github.tonywasher.joceanus.tethys.api.chart.TethysUIAreaChart;
27  import io.github.tonywasher.joceanus.tethys.core.base.TethysUICoreComponent;
28  import io.github.tonywasher.joceanus.tethys.core.factory.TethysUICoreFactory;
29  
30  import java.util.HashMap;
31  import java.util.Iterator;
32  import java.util.LinkedHashMap;
33  import java.util.Map;
34  
35  /**
36   * Area Chart.
37   * <p>
38   * The EventProvider fires the following events.
39   * <ul>
40   *    <li>TethysUIEvent.PRESSED is fired when a series is selected
41   * </ul>
42   */
43  public abstract class TethysUICoreAreaChart
44          extends TethysUICoreComponent
45          implements TethysUIAreaChart {
46      /**
47       * The angle for labels.
48       */
49      protected static final int LABEL_ANGLE = -45;
50  
51      /**
52       * The formatter.
53       */
54      private final OceanusDecimalFormatter theFormatter;
55  
56      /**
57       * The parser.
58       */
59      private final OceanusDecimalParser theParser;
60  
61      /**
62       * The id.
63       */
64      private final Integer theId;
65  
66      /**
67       * The Event Manager.
68       */
69      private final OceanusEventManager<TethysUIEvent> theEventManager;
70  
71      /**
72       * The sectionMap.
73       */
74      private final Map<String, TethysUIAreaChartSeries> theSeriesMap;
75  
76      /**
77       * Constructor.
78       *
79       * @param pFactory the Gui Factory
80       */
81      protected TethysUICoreAreaChart(final TethysUICoreFactory<?> pFactory) {
82          /* Build standard fields */
83          theId = pFactory.getNextId();
84          theEventManager = new OceanusEventManager<>();
85          theFormatter = pFactory.getDataFormatter().getDecimalFormatter();
86          theParser = pFactory.getDataFormatter().getDecimalParser();
87  
88          /* Create the section map */
89          theSeriesMap = new HashMap<>();
90      }
91  
92      @Override
93      public Integer getId() {
94          return theId;
95      }
96  
97      @Override
98      public OceanusEventRegistrar<TethysUIEvent> getEventRegistrar() {
99          return theEventManager.getEventRegistrar();
100     }
101 
102     /**
103      * Obtain the formatter.
104      *
105      * @return the formatter
106      */
107     protected OceanusDecimalFormatter getFormatter() {
108         return theFormatter;
109     }
110 
111     /**
112      * Obtain the parser.
113      *
114      * @return the parser
115      */
116     protected OceanusDecimalParser getParser() {
117         return theParser;
118     }
119 
120     @Override
121     public void updateAreaChart(final TethysUIAreaChartData pData) {
122         /* clear the data */
123         resetData();
124 
125         /* Iterate through the sections */
126         final Iterator<TethysUIAreaChartSeries> myIterator = pData.seriesIterator();
127         while (myIterator.hasNext()) {
128             final TethysUIAreaChartSeries myBase = myIterator.next();
129             final String myKey = myBase.getName();
130             theSeriesMap.put(myKey, myBase);
131 
132             /* Iterate through the sections */
133             final Iterator<TethysUIAreaChartDataPoint> myPointIterator = myBase.pointIterator();
134             while (myPointIterator.hasNext()) {
135                 final TethysUIAreaChartDataPoint myPoint = myPointIterator.next();
136 
137                 /* Add the section */
138                 createPoint(myKey, myPoint);
139             }
140         }
141     }
142 
143     /**
144      * Reset chart data.
145      */
146     protected void resetData() {
147         /* Clear existing data  */
148         theSeriesMap.clear();
149     }
150 
151     /**
152      * Add chart point.
153      *
154      * @param pName  the name of the series
155      * @param pPoint the point to add
156      */
157     protected abstract void createPoint(String pName,
158                                         TethysUIAreaChartDataPoint pPoint);
159 
160     /**
161      * Obtain tooltip for series.
162      *
163      * @param pName  the series name
164      * @param pValue the value
165      * @return the tooltip
166      */
167     protected String getToolTip(final String pName,
168                                 final OceanusMoney pValue) {
169         return pName + " = " + theFormatter.formatMoney(pValue);
170     }
171 
172     /**
173      * handle selection.
174      *
175      * @param pName the series name
176      */
177     protected void selectSeries(final String pName) {
178         final TethysUIAreaChartSeries mySeries = theSeriesMap.get(pName);
179         theEventManager.fireEvent(TethysUIEvent.PRESSED, mySeries);
180     }
181 
182     /**
183      * AreaChart Data.
184      */
185     public static final class TethysUICoreAreaChartData
186             implements TethysUIAreaChartData {
187         /**
188          * The XAxis default label.
189          */
190         static final String XAXIS_LABEL = "Date";
191 
192         /**
193          * The XAxis default label.
194          */
195         static final String YAXIS_LABEL = "Value";
196 
197         /**
198          * The SeriesMap.
199          */
200         private final Map<String, TethysUIAreaChartSeries> theSeriesMap;
201 
202         /**
203          * The Chart Title.
204          */
205         private final String theTitle;
206 
207         /**
208          * The Chart XAxisLabel.
209          */
210         private String theXAxisLabel;
211 
212         /**
213          * The Chart YAxisLabel.
214          */
215         private String theYAxisLabel;
216 
217         /**
218          * Constructor.
219          *
220          * @param pTitle the title
221          */
222         TethysUICoreAreaChartData(final String pTitle) {
223             this(pTitle, XAXIS_LABEL, YAXIS_LABEL);
224         }
225 
226         /**
227          * Constructor.
228          *
229          * @param pTitle      the title
230          * @param pXAxisLabel the XAxis label
231          * @param pYAxisLabel the YAxis label
232          */
233         private TethysUICoreAreaChartData(final String pTitle,
234                                           final String pXAxisLabel,
235                                           final String pYAxisLabel) {
236             /* Store parameters */
237             theTitle = pTitle;
238             theXAxisLabel = pXAxisLabel;
239             theYAxisLabel = pYAxisLabel;
240 
241             /* Create map */
242             theSeriesMap = new LinkedHashMap<>();
243         }
244 
245         @Override
246         public TethysUIAreaChartData setXAxisLabel(final String pLabel) {
247             theXAxisLabel = pLabel;
248             return this;
249         }
250 
251         @Override
252         public TethysUIAreaChartData setYAxisLabel(final String pLabel) {
253             theYAxisLabel = pLabel;
254             return this;
255         }
256 
257         @Override
258         public String getTitle() {
259             return theTitle;
260         }
261 
262         @Override
263         public String getXAxisLabel() {
264             return theXAxisLabel;
265         }
266 
267         @Override
268         public String getYAxisLabel() {
269             return theYAxisLabel;
270         }
271 
272         @Override
273         public Iterator<TethysUIAreaChartSeries> seriesIterator() {
274             return theSeriesMap.values().iterator();
275         }
276 
277         @Override
278         public TethysUIAreaChartSeries createSeries(final String pName,
279                                                     final Object pSource) {
280             final TethysUIAreaChartSeries mySeries = new TethysUICoreAreaChartSeries(pName, pSource);
281             theSeriesMap.put(pName, mySeries);
282             return mySeries;
283         }
284     }
285 
286     /**
287      * The Series definition.
288      */
289     public static final class TethysUICoreAreaChartSeries
290             implements TethysUIAreaChartSeries {
291         /**
292          * The name of the series.
293          */
294         private final String theName;
295 
296         /**
297          * The source of the series.
298          */
299         private final Object theSource;
300 
301         /**
302          * The pointMap of the series.
303          */
304         private final Map<OceanusDate, TethysUIAreaChartDataPoint> thePointMap;
305 
306         /**
307          * Constructor.
308          *
309          * @param pName   the name
310          * @param pSource the source
311          */
312         TethysUICoreAreaChartSeries(final String pName,
313                                     final Object pSource) {
314             theName = pName;
315             theSource = pSource;
316             thePointMap = new HashMap<>();
317         }
318 
319         @Override
320         public void addPoint(final OceanusDate pDate,
321                              final OceanusMoney pValue) {
322             thePointMap.put(pDate, new TethysUICoreAreaChartDataPoint(this, pDate, pValue));
323         }
324 
325         @Override
326         public String getName() {
327             return theName;
328         }
329 
330         @Override
331         public Iterator<TethysUIAreaChartDataPoint> pointIterator() {
332             return thePointMap.values().iterator();
333         }
334 
335         @Override
336         public Object getSource() {
337             return theSource;
338         }
339     }
340 
341     /**
342      * The Data Point definition.
343      */
344     public static final class TethysUICoreAreaChartDataPoint
345             implements TethysUIAreaChartDataPoint {
346         /**
347          * The series of the point.
348          */
349         private final TethysUIAreaChartSeries theSeries;
350 
351         /**
352          * The date of the point.
353          */
354         private final OceanusDate theDate;
355 
356         /**
357          * The value of the point.
358          */
359         private final OceanusMoney theValue;
360 
361         /**
362          * Constructor.
363          *
364          * @param pSeries the series
365          * @param pDate   the date
366          * @param pValue  the value
367          */
368         TethysUICoreAreaChartDataPoint(final TethysUIAreaChartSeries pSeries,
369                                        final OceanusDate pDate,
370                                        final OceanusMoney pValue) {
371             theSeries = pSeries;
372             theDate = pDate;
373             theValue = pValue;
374         }
375 
376         @Override
377         public TethysUIAreaChartSeries getSeries() {
378             return theSeries;
379         }
380 
381         @Override
382         public OceanusDate getDate() {
383             return theDate;
384         }
385 
386         @Override
387         public OceanusMoney getValue() {
388             return theValue;
389         }
390     }
391 }