Source Code Cross Referenced for DynamicTimeSeriesCollection.java in  » Chart » jfreechart » org » jfree » data » time » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Chart » jfreechart » org.jfree.data.time 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /* ===========================================================
002:         * JFreeChart : a free chart library for the Java(tm) platform
003:         * ===========================================================
004:         *
005:         * (C) Copyright 2000-2007, by Object Refinery Limited and Contributors.
006:         *
007:         * Project Info:  http://www.jfree.org/jfreechart/index.html
008:         *
009:         * This library is free software; you can redistribute it and/or modify it 
010:         * under the terms of the GNU Lesser General Public License as published by 
011:         * the Free Software Foundation; either version 2.1 of the License, or 
012:         * (at your option) any later version.
013:         *
014:         * This library is distributed in the hope that it will be useful, but 
015:         * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
016:         * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 
017:         * License for more details.
018:         *
019:         * You should have received a copy of the GNU Lesser General Public
020:         * License along with this library; if not, write to the Free Software
021:         * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, 
022:         * USA.  
023:         *
024:         * [Java is a trademark or registered trademark of Sun Microsystems, Inc. 
025:         * in the United States and other countries.]
026:         *
027:         * --------------------------------
028:         * DynamicTimeSeriesCollection.java
029:         * --------------------------------
030:         * (C) Copyright 2002-2007, by I. H. Thomae and Contributors.
031:         *
032:         * Original Author:  I. H. Thomae (ithomae@ists.dartmouth.edu);
033:         * Contributor(s):   David Gilbert (for Object Refinery Limited);
034:         *
035:         * $Id: DynamicTimeSeriesCollection.java,v 1.11.2.2 2007/02/02 15:15:09 mungady Exp $
036:         *
037:         * Changes
038:         * -------
039:         * 22-Nov-2002 : Initial version completed
040:         *    Jan 2003 : Optimized advanceTime(), added implemnt'n of RangeInfo intfc
041:         *               (using cached values for min, max, and range); also added
042:         *               getOldestIndex() and getNewestIndex() ftns so client classes
043:         *               can use this class as the master "index authority".
044:         * 22-Jan-2003 : Made this class stand on its own, rather than extending
045:         *               class FastTimeSeriesCollection
046:         * 31-Jan-2003 : Changed TimePeriod --> RegularTimePeriod (DG);
047:         * 13-Mar-2003 : Moved to com.jrefinery.data.time package (DG);
048:         * 29-Apr-2003 : Added small change to appendData method, from Irv Thomae (DG);
049:         * 19-Sep-2003 : Added new appendData method, from Irv Thomae (DG);
050:         * 05-May-2004 : Now extends AbstractIntervalXYDataset.  This also required a
051:         *               change to the return type of the getY() method - I'm slightly
052:         *               unsure of the implications of this, so it might require some
053:         *               further amendment (DG);
054:         * 15-Jul-2004 : Switched getX() with getXValue() and getY() with 
055:         *               getYValue() (DG);
056:         * 11-Jan-2004 : Removed deprecated code in preparation for the 1.0.0 
057:         *               release (DG);
058:         * 02-Feb-2007 : Removed author tags all over JFreeChart sources (DG);
059:         * 
060:         */
061:
062:        package org.jfree.data.time;
063:
064:        import java.util.Calendar;
065:        import java.util.TimeZone;
066:
067:        import org.jfree.data.DomainInfo;
068:        import org.jfree.data.Range;
069:        import org.jfree.data.RangeInfo;
070:        import org.jfree.data.general.SeriesChangeEvent;
071:        import org.jfree.data.xy.AbstractIntervalXYDataset;
072:        import org.jfree.data.xy.IntervalXYDataset;
073:
074:        /**
075:         * A dynamic dataset.
076:         * <p>
077:         * Like FastTimeSeriesCollection, this class is a functional replacement
078:         * for JFreeChart's TimeSeriesCollection _and_ TimeSeries classes.
079:         * FastTimeSeriesCollection is appropriate for a fixed time range; for
080:         * real-time applications this subclass adds the ability to append new
081:         * data and discard the oldest.
082:         * In this class, the arrays used in FastTimeSeriesCollection become FIFO's.
083:         * NOTE:As presented here, all data is assumed >= 0, an assumption which is
084:         * embodied only in methods associated with interface RangeInfo.
085:         */
086:        public class DynamicTimeSeriesCollection extends
087:                AbstractIntervalXYDataset implements  IntervalXYDataset,
088:                DomainInfo, RangeInfo {
089:
090:            /** 
091:             * Useful constant for controlling the x-value returned for a time 
092:             * period. 
093:             */
094:            public static final int START = 0;
095:
096:            /** 
097:             * Useful constant for controlling the x-value returned for a time period. 
098:             */
099:            public static final int MIDDLE = 1;
100:
101:            /** 
102:             * Useful constant for controlling the x-value returned for a time period. 
103:             */
104:            public static final int END = 2;
105:
106:            /** The maximum number of items for each series (can be overridden). */
107:            private int maximumItemCount = 2000; // an arbitrary safe default value
108:
109:            /** The history count. */
110:            protected int historyCount;
111:
112:            /** Storage for the series keys. */
113:            private Comparable[] seriesKeys;
114:
115:            /** The time period class - barely used, and could be removed (DG). */
116:            private Class timePeriodClass = Minute.class; // default value;
117:
118:            /** Storage for the x-values. */
119:            protected RegularTimePeriod[] pointsInTime;
120:
121:            /** The number of series. */
122:            private int seriesCount;
123:
124:            /**
125:             * A wrapper for a fixed array of float values.
126:             */
127:            protected class ValueSequence {
128:
129:                /** Storage for the float values. */
130:                float[] dataPoints;
131:
132:                /**
133:                 * Default constructor:
134:                 */
135:                public ValueSequence() {
136:                    this (DynamicTimeSeriesCollection.this .maximumItemCount);
137:                }
138:
139:                /**
140:                 * Creates a sequence with the specified length.
141:                 *
142:                 * @param length  the length.
143:                 */
144:                public ValueSequence(int length) {
145:                    this .dataPoints = new float[length];
146:                    for (int i = 0; i < length; i++) {
147:                        this .dataPoints[i] = 0.0f;
148:                    }
149:                }
150:
151:                /**
152:                 * Enters data into the storage array.
153:                 *
154:                 * @param index  the index.
155:                 * @param value  the value.
156:                 */
157:                public void enterData(int index, float value) {
158:                    this .dataPoints[index] = value;
159:                }
160:
161:                /**
162:                 * Returns a value from the storage array.
163:                 *
164:                 * @param index  the index.
165:                 *
166:                 * @return The value.
167:                 */
168:                public float getData(int index) {
169:                    return this .dataPoints[index];
170:                }
171:            }
172:
173:            /** An array for storing the objects that represent each series. */
174:            protected ValueSequence[] valueHistory;
175:
176:            /** A working calendar (to recycle) */
177:            protected Calendar workingCalendar;
178:
179:            /** 
180:             * The position within a time period to return as the x-value (START, 
181:             * MIDDLE or END). 
182:             */
183:            private int position;
184:
185:            /**
186:             * A flag that indicates that the domain is 'points in time'.  If this flag 
187:             * is true, only the x-value is used to determine the range of values in 
188:             * the domain, the start and end x-values are ignored.
189:             */
190:            private boolean domainIsPointsInTime;
191:
192:            /** index for mapping: points to the oldest valid time & data. */
193:            private int oldestAt; // as a class variable, initializes == 0
194:
195:            /** Index of the newest data item. */
196:            private int newestAt;
197:
198:            // cached values used for interface DomainInfo:
199:
200:            /** the # of msec by which time advances. */
201:            private long deltaTime;
202:
203:            /** Cached domain start (for use by DomainInfo). */
204:            private Long domainStart;
205:
206:            /** Cached domain end (for use by DomainInfo). */
207:            private Long domainEnd;
208:
209:            /** Cached domain range (for use by DomainInfo). */
210:            private Range domainRange;
211:
212:            // Cached values used for interface RangeInfo: (note minValue pinned at 0)
213:            //   A single set of extrema covers the entire SeriesCollection
214:
215:            /** The minimum value. */
216:            private Float minValue = new Float(0.0f);
217:
218:            /** The maximum value. */
219:            private Float maxValue = null;
220:
221:            /** The value range. */
222:            private Range valueRange; // autoinit's to null.
223:
224:            /**
225:             * Constructs a dataset with capacity for N series, tied to default 
226:             * timezone.
227:             *
228:             * @param nSeries the number of series to be accommodated.
229:             * @param nMoments the number of TimePeriods to be spanned.
230:             */
231:            public DynamicTimeSeriesCollection(int nSeries, int nMoments) {
232:
233:                this (nSeries, nMoments, new Millisecond(), TimeZone
234:                        .getDefault());
235:                this .newestAt = nMoments - 1;
236:
237:            }
238:
239:            /**
240:             * Constructs an empty dataset, tied to a specific timezone.
241:             *
242:             * @param nSeries the number of series to be accommodated
243:             * @param nMoments the number of TimePeriods to be spanned
244:             * @param zone the timezone.
245:             */
246:            public DynamicTimeSeriesCollection(int nSeries, int nMoments,
247:                    TimeZone zone) {
248:                this (nSeries, nMoments, new Millisecond(), zone);
249:                this .newestAt = nMoments - 1;
250:            }
251:
252:            /**
253:             * Creates a new dataset.
254:             *
255:             * @param nSeries  the number of series.
256:             * @param nMoments  the number of items per series.
257:             * @param timeSample  a time period sample.
258:             */
259:            public DynamicTimeSeriesCollection(int nSeries, int nMoments,
260:                    RegularTimePeriod timeSample) {
261:                this (nSeries, nMoments, timeSample, TimeZone.getDefault());
262:            }
263:
264:            /**
265:             * Creates a new dataset.
266:             *
267:             * @param nSeries  the number of series.
268:             * @param nMoments  the number of items per series.
269:             * @param timeSample  a time period sample.
270:             * @param zone  the time zone.
271:             */
272:            public DynamicTimeSeriesCollection(int nSeries, int nMoments,
273:                    RegularTimePeriod timeSample, TimeZone zone) {
274:
275:                // the first initialization must precede creation of the ValueSet array:
276:                this .maximumItemCount = nMoments; // establishes length of each array
277:                this .historyCount = nMoments;
278:                this .seriesKeys = new Comparable[nSeries];
279:                // initialize the members of "seriesNames" array so they won't be null:
280:                for (int i = 0; i < nSeries; i++) {
281:                    this .seriesKeys[i] = "";
282:                }
283:                this .newestAt = nMoments - 1;
284:                this .valueHistory = new ValueSequence[nSeries];
285:                this .timePeriodClass = timeSample.getClass();
286:
287:                /// Expand the following for all defined TimePeriods:
288:                if (this .timePeriodClass == Second.class) {
289:                    this .pointsInTime = new Second[nMoments];
290:                } else if (this .timePeriodClass == Minute.class) {
291:                    this .pointsInTime = new Minute[nMoments];
292:                } else if (this .timePeriodClass == Hour.class) {
293:                    this .pointsInTime = new Hour[nMoments];
294:                }
295:                ///  .. etc....
296:                this .workingCalendar = Calendar.getInstance(zone);
297:                this .position = START;
298:                this .domainIsPointsInTime = true;
299:            }
300:
301:            /**
302:             * Fill the pointsInTime with times using TimePeriod.next():
303:             * Will silently return if the time array was already populated.
304:             *
305:             * Also computes the data cached for later use by
306:             * methods implementing the DomainInfo interface:
307:             *
308:             * @param start  the start.
309:             *
310:             * @return ??.
311:             */
312:            public synchronized long setTimeBase(RegularTimePeriod start) {
313:
314:                if (this .pointsInTime[0] == null) {
315:                    this .pointsInTime[0] = start;
316:                    for (int i = 1; i < this .historyCount; i++) {
317:                        this .pointsInTime[i] = this .pointsInTime[i - 1].next();
318:                    }
319:                }
320:                long oldestL = this .pointsInTime[0]
321:                        .getFirstMillisecond(this .workingCalendar);
322:                long nextL = this .pointsInTime[1]
323:                        .getFirstMillisecond(this .workingCalendar);
324:                this .deltaTime = nextL - oldestL;
325:                this .oldestAt = 0;
326:                this .newestAt = this .historyCount - 1;
327:                findDomainLimits();
328:                return this .deltaTime;
329:
330:            }
331:
332:            /**
333:             * Finds the domain limits.  Note: this doesn't need to be synchronized 
334:             * because it's called from within another method that already is.
335:             */
336:            protected void findDomainLimits() {
337:
338:                long startL = getOldestTime().getFirstMillisecond(
339:                        this .workingCalendar);
340:                long endL;
341:                if (this .domainIsPointsInTime) {
342:                    endL = getNewestTime().getFirstMillisecond(
343:                            this .workingCalendar);
344:                } else {
345:                    endL = getNewestTime().getLastMillisecond(
346:                            this .workingCalendar);
347:                }
348:                this .domainStart = new Long(startL);
349:                this .domainEnd = new Long(endL);
350:                this .domainRange = new Range(startL, endL);
351:
352:            }
353:
354:            /**
355:             * Returns the x position type (START, MIDDLE or END).
356:             *
357:             * @return The x position type.
358:             */
359:            public int getPosition() {
360:                return this .position;
361:            }
362:
363:            /**
364:             * Sets the x position type (START, MIDDLE or END).
365:             *
366:             * @param position The x position type.
367:             */
368:            public void setPosition(int position) {
369:                this .position = position;
370:            }
371:
372:            /**
373:             * Adds a series to the dataset.  Only the y-values are supplied, the 
374:             * x-values are specified elsewhere.
375:             *
376:             * @param values  the y-values.
377:             * @param seriesNumber  the series index (zero-based).
378:             * @param seriesKey  the series key.
379:             *
380:             * Use this as-is during setup only, or add the synchronized keyword around 
381:             * the copy loop.
382:             */
383:            public void addSeries(float[] values, int seriesNumber,
384:                    Comparable seriesKey) {
385:
386:                invalidateRangeInfo();
387:                int i;
388:                if (values == null) {
389:                    throw new IllegalArgumentException(
390:                            "TimeSeriesDataset.addSeries(): "
391:                                    + "cannot add null array of values.");
392:                }
393:                if (seriesNumber >= this .valueHistory.length) {
394:                    throw new IllegalArgumentException(
395:                            "TimeSeriesDataset.addSeries(): "
396:                                    + "cannot add more series than specified in c'tor");
397:                }
398:                if (this .valueHistory[seriesNumber] == null) {
399:                    this .valueHistory[seriesNumber] = new ValueSequence(
400:                            this .historyCount);
401:                    this .seriesCount++;
402:                }
403:                // But if that series array already exists, just overwrite its contents
404:
405:                // Avoid IndexOutOfBoundsException:
406:                int srcLength = values.length;
407:                int copyLength = this .historyCount;
408:                boolean fillNeeded = false;
409:                if (srcLength < this .historyCount) {
410:                    fillNeeded = true;
411:                    copyLength = srcLength;
412:                }
413:                //{
414:                for (i = 0; i < copyLength; i++) { // deep copy from values[], caller 
415:                    // can safely discard that array
416:                    this .valueHistory[seriesNumber].enterData(i, values[i]);
417:                }
418:                if (fillNeeded) {
419:                    for (i = copyLength; i < this .historyCount; i++) {
420:                        this .valueHistory[seriesNumber].enterData(i, 0.0f);
421:                    }
422:                }
423:                //}
424:                if (seriesKey != null) {
425:                    this .seriesKeys[seriesNumber] = seriesKey;
426:                }
427:                fireSeriesChanged();
428:
429:            }
430:
431:            /**
432:             * Sets the name of a series.  If planning to add values individually.
433:             *
434:             * @param seriesNumber  the series.
435:             * @param key  the new key.
436:             */
437:            public void setSeriesKey(int seriesNumber, Comparable key) {
438:                this .seriesKeys[seriesNumber] = key;
439:            }
440:
441:            /**
442:             * Adds a value to a series.
443:             *
444:             * @param seriesNumber  the series index.
445:             * @param index  ??.
446:             * @param value  the value.
447:             */
448:            public void addValue(int seriesNumber, int index, float value) {
449:
450:                invalidateRangeInfo();
451:                if (seriesNumber >= this .valueHistory.length) {
452:                    throw new IllegalArgumentException(
453:                            "TimeSeriesDataset.addValue(): series #"
454:                                    + seriesNumber + "unspecified in c'tor");
455:                }
456:                if (this .valueHistory[seriesNumber] == null) {
457:                    this .valueHistory[seriesNumber] = new ValueSequence(
458:                            this .historyCount);
459:                    this .seriesCount++;
460:                }
461:                // But if that series array already exists, just overwrite its contents
462:                //synchronized(this)
463:                //{
464:                this .valueHistory[seriesNumber].enterData(index, value);
465:                //}
466:                fireSeriesChanged();
467:            }
468:
469:            /**
470:             * Returns the number of series in the collection.
471:             *
472:             * @return The series count.
473:             */
474:            public int getSeriesCount() {
475:                return this .seriesCount;
476:            }
477:
478:            /**
479:             * Returns the number of items in a series.
480:             * <p>
481:             * For this implementation, all series have the same number of items.
482:             *
483:             * @param series  the series index (zero-based).
484:             *
485:             * @return The item count.
486:             */
487:            public int getItemCount(int series) { // all arrays equal length, 
488:                // so ignore argument:
489:                return this .historyCount;
490:            }
491:
492:            // Methods for managing the FIFO's:
493:
494:            /**
495:             * Re-map an index, for use in retrieving data.
496:             *
497:             * @param toFetch  the index.
498:             *
499:             * @return The translated index.
500:             */
501:            protected int translateGet(int toFetch) {
502:                if (this .oldestAt == 0) {
503:                    return toFetch; // no translation needed
504:                }
505:                // else  [implicit here]
506:                int newIndex = toFetch + this .oldestAt;
507:                if (newIndex >= this .historyCount) {
508:                    newIndex -= this .historyCount;
509:                }
510:                return newIndex;
511:            }
512:
513:            /**
514:             * Returns the actual index to a time offset by "delta" from newestAt.
515:             *
516:             * @param delta  the delta.
517:             *
518:             * @return The offset.
519:             */
520:            public int offsetFromNewest(int delta) {
521:                return wrapOffset(this .newestAt + delta);
522:            }
523:
524:            /**
525:             * ??
526:             *
527:             * @param delta ??
528:             *
529:             * @return The offset.
530:             */
531:            public int offsetFromOldest(int delta) {
532:                return wrapOffset(this .oldestAt + delta);
533:            }
534:
535:            /**
536:             * ??
537:             *
538:             * @param protoIndex  the index.
539:             *
540:             * @return The offset.
541:             */
542:            protected int wrapOffset(int protoIndex) {
543:                int tmp = protoIndex;
544:                if (tmp >= this .historyCount) {
545:                    tmp -= this .historyCount;
546:                } else if (tmp < 0) {
547:                    tmp += this .historyCount;
548:                }
549:                return tmp;
550:            }
551:
552:            /**
553:             * Adjust the array offset as needed when a new time-period is added:
554:             * Increments the indices "oldestAt" and "newestAt", mod(array length),
555:             * zeroes the series values at newestAt, returns the new TimePeriod.
556:             *
557:             * @return The new time period.
558:             */
559:            public synchronized RegularTimePeriod advanceTime() {
560:                RegularTimePeriod nextInstant = this .pointsInTime[this .newestAt]
561:                        .next();
562:                this .newestAt = this .oldestAt; // newestAt takes value previously held 
563:                // by oldestAT
564:                /*** 
565:                 * The next 10 lines or so should be expanded if data can be negative 
566:                 ***/
567:                // if the oldest data contained a maximum Y-value, invalidate the stored
568:                //   Y-max and Y-range data:
569:                boolean extremaChanged = false;
570:                float oldMax = 0.0f;
571:                if (this .maxValue != null) {
572:                    oldMax = this .maxValue.floatValue();
573:                }
574:                for (int s = 0; s < getSeriesCount(); s++) {
575:                    if (this .valueHistory[s].getData(this .oldestAt) == oldMax) {
576:                        extremaChanged = true;
577:                    }
578:                    if (extremaChanged) {
579:                        break;
580:                    }
581:                }
582:                /*** If data can be < 0, add code here to check the minimum    **/
583:                if (extremaChanged) {
584:                    invalidateRangeInfo();
585:                }
586:                //  wipe the next (about to be used) set of data slots
587:                float wiper = (float) 0.0;
588:                for (int s = 0; s < getSeriesCount(); s++) {
589:                    this .valueHistory[s].enterData(this .newestAt, wiper);
590:                }
591:                // Update the array of TimePeriods:
592:                this .pointsInTime[this .newestAt] = nextInstant;
593:                // Now advance "oldestAt", wrapping at end of the array
594:                this .oldestAt++;
595:                if (this .oldestAt >= this .historyCount) {
596:                    this .oldestAt = 0;
597:                }
598:                // Update the domain limits:
599:                long startL = this .domainStart.longValue(); //(time is kept in msec)
600:                this .domainStart = new Long(startL + this .deltaTime);
601:                long endL = this .domainEnd.longValue();
602:                this .domainEnd = new Long(endL + this .deltaTime);
603:                this .domainRange = new Range(startL, endL);
604:                fireSeriesChanged();
605:                return nextInstant;
606:            }
607:
608:            //  If data can be < 0, the next 2 methods should be modified
609:
610:            /**
611:             * Invalidates the range info.
612:             */
613:            public void invalidateRangeInfo() {
614:                this .maxValue = null;
615:                this .valueRange = null;
616:            }
617:
618:            /**
619:             * Returns the maximum value.
620:             *
621:             * @return The maximum value.
622:             */
623:            protected double findMaxValue() {
624:                double max = 0.0f;
625:                for (int s = 0; s < getSeriesCount(); s++) {
626:                    for (int i = 0; i < this .historyCount; i++) {
627:                        double tmp = getYValue(s, i);
628:                        if (tmp > max) {
629:                            max = tmp;
630:                        }
631:                    }
632:                }
633:                return max;
634:            }
635:
636:            /** End, positive-data-only code  **/
637:
638:            /**
639:             * Returns the index of the oldest data item.
640:             *
641:             * @return The index.
642:             */
643:            public int getOldestIndex() {
644:                return this .oldestAt;
645:            }
646:
647:            /**
648:             * Returns the index of the newest data item.
649:             *
650:             * @return The index.
651:             */
652:            public int getNewestIndex() {
653:                return this .newestAt;
654:            }
655:
656:            // appendData() writes new data at the index position given by newestAt/
657:            // When adding new data dynamically, use advanceTime(), followed by this:
658:            /**
659:             * Appends new data.
660:             *
661:             * @param newData  the data.
662:             */
663:            public void appendData(float[] newData) {
664:                int nDataPoints = newData.length;
665:                if (nDataPoints > this .valueHistory.length) {
666:                    throw new IllegalArgumentException(
667:                            "More data than series to put them in");
668:                }
669:                int s; // index to select the "series"
670:                for (s = 0; s < nDataPoints; s++) {
671:                    // check whether the "valueHistory" array member exists; if not, 
672:                    // create them:
673:                    if (this .valueHistory[s] == null) {
674:                        this .valueHistory[s] = new ValueSequence(
675:                                this .historyCount);
676:                    }
677:                    this .valueHistory[s].enterData(this .newestAt, newData[s]);
678:                }
679:                fireSeriesChanged();
680:            }
681:
682:            /**
683:             * Appends data at specified index, for loading up with data from file(s).
684:             *
685:             * @param  newData  the data
686:             * @param  insertionIndex  the index value at which to put it
687:             * @param  refresh  value of n in "refresh the display on every nth call"
688:             *                 (ignored if <= 0 )
689:             */
690:            public void appendData(float[] newData, int insertionIndex,
691:                    int refresh) {
692:                int nDataPoints = newData.length;
693:                if (nDataPoints > this .valueHistory.length) {
694:                    throw new IllegalArgumentException(
695:                            "More data than series to put them " + "in");
696:                }
697:                for (int s = 0; s < nDataPoints; s++) {
698:                    if (this .valueHistory[s] == null) {
699:                        this .valueHistory[s] = new ValueSequence(
700:                                this .historyCount);
701:                    }
702:                    this .valueHistory[s].enterData(insertionIndex, newData[s]);
703:                }
704:                if (refresh > 0) {
705:                    insertionIndex++;
706:                    if (insertionIndex % refresh == 0) {
707:                        fireSeriesChanged();
708:                    }
709:                }
710:            }
711:
712:            /**
713:             * Returns the newest time.
714:             *
715:             * @return The newest time.
716:             */
717:            public RegularTimePeriod getNewestTime() {
718:                return this .pointsInTime[this .newestAt];
719:            }
720:
721:            /**
722:             * Returns the oldest time.
723:             *
724:             * @return The oldest time.
725:             */
726:            public RegularTimePeriod getOldestTime() {
727:                return this .pointsInTime[this .oldestAt];
728:            }
729:
730:            /**
731:             * Returns the x-value.
732:             *
733:             * @param series  the series index (zero-based).
734:             * @param item  the item index (zero-based).
735:             *
736:             * @return The value.
737:             */
738:            // getXxx() ftns can ignore the "series" argument:
739:            // Don't synchronize this!! Instead, synchronize the loop that calls it.
740:            public Number getX(int series, int item) {
741:                RegularTimePeriod tp = this .pointsInTime[translateGet(item)];
742:                return new Long(getX(tp));
743:            }
744:
745:            /**
746:             * Returns the y-value.
747:             *
748:             * @param series  the series index (zero-based).
749:             * @param item  the item index (zero-based).
750:             *
751:             * @return The value.
752:             */
753:            public double getYValue(int series, int item) {
754:                // Don't synchronize this!!
755:                // Instead, synchronize the loop that calls it.
756:                ValueSequence values = this .valueHistory[series];
757:                return values.getData(translateGet(item));
758:            }
759:
760:            /**
761:             * Returns the y-value.
762:             *
763:             * @param series  the series index (zero-based).
764:             * @param item  the item index (zero-based).
765:             *
766:             * @return The value.
767:             */
768:            public Number getY(int series, int item) {
769:                return new Float(getYValue(series, item));
770:            }
771:
772:            /**
773:             * Returns the start x-value.
774:             *
775:             * @param series  the series index (zero-based).
776:             * @param item  the item index (zero-based).
777:             *
778:             * @return The value.
779:             */
780:            public Number getStartX(int series, int item) {
781:                RegularTimePeriod tp = this .pointsInTime[translateGet(item)];
782:                return new Long(tp.getFirstMillisecond(this .workingCalendar));
783:            }
784:
785:            /**
786:             * Returns the end x-value.
787:             *
788:             * @param series  the series index (zero-based).
789:             * @param item  the item index (zero-based).
790:             *
791:             * @return The value.
792:             */
793:            public Number getEndX(int series, int item) {
794:                RegularTimePeriod tp = this .pointsInTime[translateGet(item)];
795:                return new Long(tp.getLastMillisecond(this .workingCalendar));
796:            }
797:
798:            /**
799:             * Returns the start y-value.
800:             *
801:             * @param series  the series index (zero-based).
802:             * @param item  the item index (zero-based).
803:             *
804:             * @return The value.
805:             */
806:            public Number getStartY(int series, int item) {
807:                return getY(series, item);
808:            }
809:
810:            /**
811:             * Returns the end y-value.
812:             *
813:             * @param series  the series index (zero-based).
814:             * @param item  the item index (zero-based).
815:             *
816:             * @return The value.
817:             */
818:            public Number getEndY(int series, int item) {
819:                return getY(series, item);
820:            }
821:
822:            /* // "Extras" found useful when analyzing/verifying class behavior:
823:            public Number getUntranslatedXValue(int series, int item)
824:            {
825:              return super.getXValue(series, item);
826:            }
827:
828:            public float getUntranslatedY(int series, int item)
829:            {
830:              return super.getY(series, item);
831:            }  */
832:
833:            /**
834:             * Returns the key for a series.
835:             *
836:             * @param series  the series index (zero-based).
837:             *
838:             * @return The key.
839:             */
840:            public Comparable getSeriesKey(int series) {
841:                return this .seriesKeys[series];
842:            }
843:
844:            /**
845:             * Sends a {@link SeriesChangeEvent} to all registered listeners.
846:             */
847:            protected void fireSeriesChanged() {
848:                seriesChanged(new SeriesChangeEvent(this ));
849:            }
850:
851:            // The next 3 functions override the base-class implementation of
852:            // the DomainInfo interface.  Using saved limits (updated by
853:            // each updateTime() call), improves performance.
854:            //
855:
856:            /**
857:             * Returns the minimum x-value in the dataset.
858:             *
859:             * @param includeInterval  a flag that determines whether or not the
860:             *                         x-interval is taken into account.
861:             * 
862:             * @return The minimum value.
863:             */
864:            public double getDomainLowerBound(boolean includeInterval) {
865:                return this .domainStart.doubleValue();
866:                // a Long kept updated by advanceTime()        
867:            }
868:
869:            /**
870:             * Returns the maximum x-value in the dataset.
871:             *
872:             * @param includeInterval  a flag that determines whether or not the
873:             *                         x-interval is taken into account.
874:             * 
875:             * @return The maximum value.
876:             */
877:            public double getDomainUpperBound(boolean includeInterval) {
878:                return this .domainEnd.doubleValue();
879:                // a Long kept updated by advanceTime()
880:            }
881:
882:            /**
883:             * Returns the range of the values in this dataset's domain.
884:             *
885:             * @param includeInterval  a flag that determines whether or not the
886:             *                         x-interval is taken into account.
887:             * 
888:             * @return The range.
889:             */
890:            public Range getDomainBounds(boolean includeInterval) {
891:                if (this .domainRange == null) {
892:                    findDomainLimits();
893:                }
894:                return this .domainRange;
895:            }
896:
897:            /**
898:             * Returns the x-value for a time period.
899:             *
900:             * @param period  the period.
901:             *
902:             * @return The x-value.
903:             */
904:            private long getX(RegularTimePeriod period) {
905:                switch (this .position) {
906:                case (START):
907:                    return period.getFirstMillisecond(this .workingCalendar);
908:                case (MIDDLE):
909:                    return period.getMiddleMillisecond(this .workingCalendar);
910:                case (END):
911:                    return period.getLastMillisecond(this .workingCalendar);
912:                default:
913:                    return period.getMiddleMillisecond(this .workingCalendar);
914:                }
915:            }
916:
917:            // The next 3 functions implement the RangeInfo interface.
918:            // Using saved limits (updated by each updateTime() call) significantly
919:            // improves performance.  WARNING: this code makes the simplifying 
920:            // assumption that data is never negative.  Expand as needed for the 
921:            // general case.
922:
923:            /**
924:             * Returns the minimum range value.
925:             *
926:             * @param includeInterval  a flag that determines whether or not the
927:             *                         y-interval is taken into account.
928:             * 
929:             * @return The minimum range value.
930:             */
931:            public double getRangeLowerBound(boolean includeInterval) {
932:                double result = Double.NaN;
933:                if (this .minValue != null) {
934:                    result = this .minValue.doubleValue();
935:                }
936:                return result;
937:            }
938:
939:            /**
940:             * Returns the maximum range value.
941:             *
942:             * @param includeInterval  a flag that determines whether or not the
943:             *                         y-interval is taken into account.
944:             * 
945:             * @return The maximum range value.
946:             */
947:            public double getRangeUpperBound(boolean includeInterval) {
948:                double result = Double.NaN;
949:                if (this .maxValue != null) {
950:                    result = this .maxValue.doubleValue();
951:                }
952:                return result;
953:            }
954:
955:            /**
956:             * Returns the value range.
957:             *
958:             * @param includeInterval  a flag that determines whether or not the
959:             *                         y-interval is taken into account.
960:             * 
961:             * @return The range.
962:             */
963:            public Range getRangeBounds(boolean includeInterval) {
964:                if (this .valueRange == null) {
965:                    double max = getRangeUpperBound(includeInterval);
966:                    this .valueRange = new Range(0.0, max);
967:                }
968:                return this.valueRange;
969:            }
970:
971:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.