OLD | NEW |
| (Empty) |
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 /** | |
6 * Factory function to create a View for "peak hours". | |
7 * | |
8 * This display of the data shows tree closure/open totals during peak hours in | |
9 * various time zones. | |
10 */ | |
11 var CreatePeakHoursView; | |
12 | |
13 // ----------------------------------------------------------------------------- | |
14 // Private implementation | |
15 // ----------------------------------------------------------------------------- | |
16 | |
17 (function() { | |
18 | |
19 CreatePeakHoursView = function(timeRange, entries) { | |
20 return new PeakHoursView(timeRange, entries); | |
21 } | |
22 | |
23 function PeakHoursView(timeRange, entries) { | |
24 Draw(entries, timeRange); | |
25 } | |
26 | |
27 PeakHoursView.prototype.Show = function(visible) { | |
28 gViewerApp.ShowViewContentAndTabArea("peak", visible); | |
29 } | |
30 | |
31 /** | |
32 * Draws the peak hours chart for all days in |timeRange|. | |
33 * @param {array<Entry>} entries | |
34 * @param {TimeRange} timeRange | |
35 */ | |
36 function Draw(entries, timeRange) { | |
37 var utcOffsetsMillis = { | |
38 // Please keep this ordered by UTC offset. | |
39 // If you extend this list, you need to adjust column widths in | |
40 // AddPeakColumn() and on the status_viewer.html page. | |
41 MTV: -7 * DateUtil.MILLIS_PER_HOUR, // UTC-7 -- Mountain View | |
42 NYC: -4 * DateUtil.MILLIS_PER_HOUR, // UTC-4 -- New York | |
43 CET: 1 * DateUtil.MILLIS_PER_HOUR, // UTC+1 -- Denmark | |
44 TOK: 9 * DateUtil.MILLIS_PER_HOUR // UTC+9 -- Tokyo | |
45 }; | |
46 var graphCSV = []; | |
47 | |
48 // Find which is the minimum and maximum. | |
49 var minUTCOffsetMillis = utcOffsetsMillis.MTV; | |
50 var maxUTCOffsetMillis = utcOffsetsMillis.MTV; | |
51 | |
52 for (var timezone in utcOffsetsMillis) { | |
53 var offset = utcOffsetsMillis[timezone]; | |
54 minUTCOffsetMillis = Math.min(minUTCOffsetMillis, offset); | |
55 maxUTCOffsetMillis = Math.max(maxUTCOffsetMillis, offset); | |
56 } | |
57 | |
58 // Set the graph csv header: "Date,MTV,NYC,CET,TOK\n". | |
59 graphCSV.push("Date"); | |
60 for (var timezone in utcOffsetsMillis) { | |
61 graphCSV.push(","); | |
62 graphCSV.push(timezone); | |
63 } | |
64 graphCSV.push("\n"); | |
65 | |
66 // Figure out what days we touch. | |
67 // | |
68 // Note that we have to extend the time range by the max and | |
69 // minimum offsets, since those timezones may be on the next/previous | |
70 // day! | |
71 var days = DateUtil.GetUTCDaysInRange( | |
72 new TimeRange(timeRange.startTime + maxUTCOffsetMillis, | |
73 timeRange.endTime + minUTCOffsetMillis)); | |
74 | |
75 var tbody = document.getElementById("peak_tbody"); | |
76 // Clear anything already present in the output table. | |
77 tbody.innerHTML = ""; | |
78 | |
79 // Draw the rows for each day worth of data. | |
80 for (var i = 0; i < days.length; ++i) { | |
81 var day = days[i]; | |
82 DrawDay(tbody, entries, day, utcOffsetsMillis, graphCSV); | |
83 } | |
84 | |
85 // Draw a graph with the csv data across all dates. | |
86 // Dygraph docs at http://danvk.org/dygraphs/ | |
87 var peakGraph = | |
88 new Dygraph(document.getElementById("peak_dygraph"), | |
89 graphCSV.join(""), | |
90 { | |
91 rollPeriod: 1, | |
92 showRoller: true, | |
93 axisLabelFontSize: 11, | |
94 includeZero: true, | |
95 colors: ["red", "orange", "blue", "LightSkyBlue"], | |
96 strokeWidth: 3, | |
97 labelsDiv: document.getElementById("peak_dygraph_legend"), | |
98 labelsSeparateLines: true, | |
99 }); | |
100 } | |
101 | |
102 /** | |
103 * Draws a specific day's row in the peak hours chart. | |
104 * @parm {DOMNode} tbody | |
105 * @param {array<Entry>} entries | |
106 * @param {TimeRange} day | |
107 * @param {dict} utcOffsetsMillis | |
108 * @param {array} graphCSV | |
109 */ | |
110 function DrawDay(tbody, entries, utcDay, utcOffsetsMillis, graphCSV) { | |
111 var tr = DomUtil.AddNode(tbody, "tr"); | |
112 | |
113 | |
114 var tdForDayName = DomUtil.AddNode(tr, "td"); | |
115 | |
116 DrawUTCDayNameColumn(utcDay, tdForDayName); | |
117 // Start each graphCSV row with a date like "2010/08/01". | |
118 graphCSV.push(tdForDayName.innerText); | |
119 | |
120 var tableTd = DomUtil.AddNode(tr, "td"); | |
121 | |
122 tableTd.width = "100%"; | |
123 | |
124 var table = DomUtil.AddNode(tableTd, "table"); | |
125 table.cellSpacing = 0; | |
126 table.cellPadding = 0; | |
127 table.width = "100%"; | |
128 | |
129 var tr = DomUtil.AddNode(table, "tr"); | |
130 | |
131 for (var timezone in utcOffsetsMillis) { | |
132 AddPeakColumn(tr, | |
133 entries, | |
134 utcDay, | |
135 utcOffsetsMillis[timezone], | |
136 graphCSV); | |
137 } | |
138 graphCSV.push("\n"); | |
139 } | |
140 | |
141 /** | |
142 * @returns {StatusTotals} | |
143 */ | |
144 function GetStateCountsInRange(runs, timeRange) { | |
145 var statusTotalsSeconds = new StatusTotals(); | |
146 | |
147 var y1 = timeRange.startTime; | |
148 var y2 = timeRange.endTime; | |
149 | |
150 for (var i = 0; i < runs.length; ++i) { | |
151 var run = runs[i]; | |
152 | |
153 // Basically we have two boxes (x and y), and need to find the overlap. | |
154 var x1 = run.startTime; | |
155 var x2 = run.startTime - run.duration; | |
156 | |
157 if (x1 > y2 && x2 < y1) { | |
158 var leftEdge = Math.min(x1, y1); | |
159 var rightEdge = Math.max(y2, x2); | |
160 | |
161 var dt = leftEdge - rightEdge; | |
162 | |
163 statusTotalsSeconds.Increment(run.entry.GetTreeState(), | |
164 DateUtil.MillisToSeconds(dt)); | |
165 } | |
166 } | |
167 | |
168 return statusTotalsSeconds; | |
169 } | |
170 | |
171 function AddPeakColumn(tr, entries, utcDay, utcOffsetMillis, graphCSV) { | |
172 var td = DomUtil.AddNode(tr, "td"); | |
173 | |
174 // Width is (100/[items in utcMillisOffsets])%. | |
175 td.width = "25%"; | |
176 td.align = "center"; | |
177 | |
178 // Get a day range for the timezone. | |
179 var day = new TimeRange(utcDay.startTime - utcOffsetMillis, | |
180 utcDay.endTime - utcOffsetMillis); | |
181 | |
182 // Extract the data from |entries| that apply to |day|, and break it | |
183 // into (start,duration) runs. | |
184 var runs = MakeRuns(entries, day); | |
185 | |
186 // 9 - 5 in the local timezone. | |
187 var localPeakHours = new TimeRange( | |
188 day.endTime + 17 * DateUtil.MILLIS_PER_HOUR, | |
189 day.endTime + 9 * DateUtil.MILLIS_PER_HOUR); | |
190 | |
191 var statusTotalsSeconds = GetStateCountsInRange(runs, localPeakHours); | |
192 | |
193 var total = statusTotalsSeconds.GetTotalKnown(); | |
194 | |
195 var percentOpenText = ""; | |
196 var color = ""; | |
197 var className = ""; | |
198 | |
199 var percentOpenNumber = "0.0"; | |
200 if (total == 0) { | |
201 // This can happen if the day is in the future (edge day of slow timezone). | |
202 percentOpenText = "N/A"; | |
203 } else { | |
204 var fraction = statusTotalsSeconds.GetOpen() / total; | |
205 percentOpenNumber = (100 * fraction).toFixed(2); | |
206 percentOpenText = percentOpenNumber + "%"; | |
207 | |
208 // If we didn't fetch all the data necessary, our percentage won't be | |
209 // accurate as it is missing zones. | |
210 if (total != DateUtil.MillisToSeconds( | |
211 localPeakHours.startTime - localPeakHours.endTime)) { | |
212 percentOpenText += " [incomplete]"; | |
213 } | |
214 | |
215 // Choose a style based on how bad things are. | |
216 var badnessBuckets = [0.50, 0.75, 1.1]; | |
217 for (var i = 0; i < badnessBuckets.length; ++i) { | |
218 if (fraction < badnessBuckets[i]) { | |
219 className = "open_badness" + i; | |
220 break; | |
221 } | |
222 } | |
223 } | |
224 graphCSV.push("," + percentOpenNumber); | |
225 | |
226 var span = DomUtil.AddNode(td, "span"); | |
227 span.className = className; | |
228 DomUtil.AddText(span, percentOpenText); | |
229 } | |
230 | |
231 /** | |
232 * Draws a specific day's name column in the peak hours charts. | |
233 * @param {TimeRange} utcDay | |
234 * @param {DOMNode} td The column to print name into. | |
235 */ | |
236 function DrawUTCDayNameColumn(utcDay, td) { | |
237 var d = new Date(); | |
238 d.setTime(utcDay.endTime); | |
239 | |
240 // Display the day as for example "2009/8/38". | |
241 var dateText = | |
242 d.getUTCFullYear() + "/" + | |
243 PadWithZero(d.getUTCMonth() + 1, 2) + "/" + | |
244 PadWithZero(d.getUTCDate(), 2); | |
245 | |
246 // Color saturday and sunday differently. | |
247 if (d.getUTCDay() == 0) { | |
248 td.className = "sundayName"; | |
249 } else if (d.getUTCDay() == 6) { | |
250 td.className = "saturdayName"; | |
251 } | |
252 | |
253 td.innerHTML = dateText; | |
254 } | |
255 | |
256 })(); // Private implementation. | |
OLD | NEW |