REGRESSION(r212853): Comparisons to baseline no longer shows up
[WebKit-https.git] / Websites / perf.webkit.org / public / v3 / models / time-series.js
1 'use strict';
2
3 // v3 UI still relies on RunsData for associating metrics with units.
4 // Use declartive syntax once that dependency has been removed.
5 var TimeSeries = class {
6     constructor()
7     {
8         this._data = [];
9     }
10
11     values() { return this._data.map((point) => point.value); }
12     length() { return this._data.length; }
13
14     append(item)
15     {
16         console.assert(item.series === undefined);
17         item.series = this;
18         item.seriesIndex = this._data.length;
19         this._data.push(item);
20     }
21
22     extendToFuture()
23     {
24         if (!this._data.length)
25             return;
26         var lastPoint = this._data[this._data.length - 1];
27         this._data.push({
28             series: this,
29             seriesIndex: this._data.length,
30             time: Date.now() + 365 * 24 * 3600 * 1000,
31             value: lastPoint.value,
32             interval: lastPoint.interval,
33         });
34     }
35
36     valuesBetweenRange(startingIndex, endingIndex)
37     {
38         startingIndex = Math.max(startingIndex, 0);
39         endingIndex = Math.min(endingIndex, this._data.length);
40         var length = endingIndex - startingIndex;
41         var values = new Array(length);
42         for (var i = 0; i < length; i++)
43             values[i] = this._data[startingIndex + i].value;
44         return values;
45     }
46
47     firstPoint() { return this._data.length ? this._data[0] : null; }
48     lastPoint() { return this._data.length ? this._data[this._data.length - 1] : null; }
49
50     previousPoint(point)
51     {
52         console.assert(point.series == this);
53         if (!point.seriesIndex)
54             return null;
55         return this._data[point.seriesIndex - 1];
56     }
57
58     nextPoint(point)
59     {
60         console.assert(point.series == this);
61         if (point.seriesIndex + 1 >= this._data.length)
62             return null;
63         return this._data[point.seriesIndex + 1];
64     }
65
66     findPointByIndex(index)
67     {
68         if (!this._data || index < 0 || index >= this._data.length)
69             return null;
70         return this._data[index];
71     }
72
73     findById(id) { return this._data.find(function (point) { return point.id == id }); }
74
75     findPointAfterTime(time) { return this._data.find(function (point) { return point.time >= time; }); }
76
77     viewBetweenPoints(firstPoint, lastPoint)
78     {
79         console.assert(firstPoint.series == this);
80         console.assert(lastPoint.series == this);
81         return new TimeSeriesView(this, firstPoint.seriesIndex, lastPoint.seriesIndex + 1);
82     }
83 };
84
85 class TimeSeriesView {
86     constructor(timeSeries, startingIndex, afterEndingIndex, filteredData = null)
87     {
88         console.assert(timeSeries instanceof TimeSeries);
89         console.assert(startingIndex <= afterEndingIndex);
90         console.assert(afterEndingIndex <= timeSeries._data.length);
91         this._timeSeries = timeSeries;
92         this._data = filteredData || timeSeries._data;
93         this._values = null;
94         this._length = afterEndingIndex - startingIndex;
95         this._startingIndex = startingIndex;
96         this._afterEndingIndex = afterEndingIndex;
97         this._pointIndexMap = null;
98
99         if (this._data != timeSeries._data) {
100             this._findIndexForPoint = (point) => {
101                 if (this._pointIndexMap == null)
102                     this._buildPointIndexMap();
103                 return this._pointIndexMap.get(point);
104             }
105         } else
106             this._findIndexForPoint = (point) => { return point.seriesIndex; }
107     }
108
109     _buildPointIndexMap()
110     {
111         this._pointIndexMap = new Map;
112         const data = this._data;
113         const length = data.length;
114         for (let i = 0; i < length; i++)
115             this._pointIndexMap.set(data[i], i);
116     }
117
118     length() { return this._length; }
119
120     firstPoint() { return this._length ? this._data[this._startingIndex] : null; }
121     lastPoint() { return this._length ? this._data[this._afterEndingIndex - 1] : null; }
122
123     nextPoint(point)
124     {
125         let index = this._findIndexForPoint(point);
126         index++;
127         if (index == this._afterEndingIndex)
128             return null;
129         return this._data[index];
130     }
131
132     previousPoint(point)
133     {
134         const index = this._findIndexForPoint(point);
135         if (index == this._startingIndex)
136             return null;
137         return this._data[index - 1];
138     }
139
140     findPointByIndex(index)
141     {
142         index += this._startingIndex;
143         if (index < 0 || index >= this._afterEndingIndex)
144             return null;
145         return this._data[index];
146     }
147
148     findById(id)
149     {
150         for (let point of this) {
151             if (point.id == id)
152                 return point;
153         }
154         return null;
155     }
156
157     values()
158     {
159         if (this._values == null) {
160             this._values = new Array(this._length);
161             let i = 0;
162             for (let point of this)
163                 this._values[i++] = point.value;
164         }
165         return this._values;
166     }
167
168     filter(callback)
169     {
170         const filteredData = [];
171         let i = 0;
172         for (let point of this) {
173             if (callback(point, i))
174                 filteredData.push(point);
175             i++;
176         }
177         return new TimeSeriesView(this._timeSeries, 0, filteredData.length, filteredData);
178     }
179
180     viewTimeRange(startTime, endTime)
181     {
182         const data = this._data;
183         let startingIndex = null;
184         let endingIndex = null;
185         for (let i = this._startingIndex; i < this._afterEndingIndex; i++) {
186             if (startingIndex == null && data[i].time >= startTime)
187                 startingIndex = i;
188             if (data[i].time <= endTime)
189                 endingIndex = i;
190         }
191         if (startingIndex == null || endingIndex == null)
192             return new TimeSeriesView(this._timeSeries, 0, 0, data);
193         return new TimeSeriesView(this._timeSeries, startingIndex, endingIndex + 1, data);
194     }
195
196     firstPointInTimeRange(startTime, endTime)
197     {
198         console.assert(startTime <= endTime);
199         for (let point of this) {
200             if (point.time > endTime)
201                 return null;
202             if (point.time >= startTime)
203                 return point;
204         }
205         return null;
206     }
207
208     lastPointInTimeRange(startTime, endTime)
209     {
210         console.assert(startTime <= endTime);
211         for (let point of this._reverse()) {
212             if (point.time < startTime)
213                 return null;
214             if (point.time <= endTime)
215                 return point;
216         }
217         return null;
218     }
219
220     [Symbol.iterator]()
221     {
222         const data = this._data;
223         const end = this._afterEndingIndex;
224         let i = this._startingIndex;
225         return {
226             next() {
227                 return {value: data[i], done: i++ == end};
228             }
229         };
230     }
231
232     _reverse()
233     {
234         return {
235             [Symbol.iterator]: () => {
236                 const data = this._data;
237                 const end = this._startingIndex;
238                 let i = this._afterEndingIndex;
239                 return {
240                     next() {
241                         return {done: i-- == end, value: data[i]};
242                     }
243                 };
244             }
245         }
246     }
247 }
248
249 if (typeof module != 'undefined')
250     module.exports.TimeSeries = TimeSeries;