OLD | NEW |
---|---|
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 /** | 5 /** |
6 * Plot a line graph of data versus time on a HTML canvas element. | 6 * Plot a line graph of data versus time on a HTML canvas element. |
7 * | 7 * |
8 * @param {HTMLCanvasElement} canvas The canvas on which the line graph is | 8 * @param {HTMLCanvasElement} plotCanvas The canvas on which the line graph is |
9 * drawn. | 9 * drawn. |
10 * @param {HTMLCanvasElement} legendCanvas The canvas on which the legend for | |
11 * the line graph is drawn. | |
10 * @param {Array.<number>} tData The time (in seconds) in the past when the | 12 * @param {Array.<number>} tData The time (in seconds) in the past when the |
11 * corresponding data in plots was sampled. | 13 * corresponding data in plots was sampled. |
12 * @param {Array.<{data: Array.<number>, color: string}>} plots An | 14 * @param {Array.<{data: Array.<number>, color: string}>} plots An |
13 * array of plots to plot on the canvas. The field 'data' of a plot is an | 15 * array of plots to plot on the canvas. The field 'data' of a plot is an |
14 * array of samples to be plotted as a line graph with color speficied by | 16 * array of samples to be plotted as a line graph with color speficied by |
15 * the field 'color'. The elements in the 'data' array are ordered | 17 * the field 'color'. The elements in the 'data' array are ordered |
16 * corresponding to their sampling time in the argument 'tData'. Also, the | 18 * corresponding to their sampling time in the argument 'tData'. Also, the |
17 * number of elements in the 'data' array should be the same as in the time | 19 * number of elements in the 'data' array should be the same as in the time |
18 * array 'tData' above. | 20 * array 'tData' above. |
19 * @param {number} yMin Minimum bound of y-axis | 21 * @param {number} yMin Minimum bound of y-axis |
20 * @param {number} yMax Maximum bound of y-axis. | 22 * @param {number} yMax Maximum bound of y-axis. |
21 * @param {integer} yPrecision An integer value representing the number of | 23 * @param {integer} yPrecision An integer value representing the number of |
22 * digits of precision the y-axis data should be printed with. | 24 * digits of precision the y-axis data should be printed with. |
23 */ | 25 */ |
24 function plotLineGraph(canvas, tData, plots, yMin, yMax, yPrecision) { | 26 function plotLineGraph( |
27 plotCanvas, legendCanvas, tData, plots, yMin, yMax, yPrecision) { | |
25 var textFont = '12px Arial'; | 28 var textFont = '12px Arial'; |
26 var textHeight = 12; | 29 var textHeight = 12; |
27 var padding = 5; // Pixels | 30 var padding = 5; // Pixels |
28 var errorOffsetPixels = 15; | 31 var errorOffsetPixels = 15; |
29 var gridColor = '#ccc'; | 32 var gridColor = '#ccc'; |
30 var ctx = canvas.getContext('2d'); | 33 var plotCtx = plotCanvas.getContext('2d'); |
31 var size = tData.length; | 34 var size = tData.length; |
32 | 35 |
33 function drawText(text, x, y) { | 36 function drawText(ctx, text, x, y) { |
34 ctx.font = textFont; | 37 ctx.font = textFont; |
35 ctx.fillStyle = '#000'; | 38 ctx.fillStyle = '#000'; |
36 ctx.fillText(text, x, y); | 39 ctx.fillText(text, x, y); |
37 } | 40 } |
38 | 41 |
39 function printErrorText(text) { | 42 function printErrorText(ctx, text) { |
40 ctx.clearRect(0, 0, canvas.width, canvas.height); | 43 ctx.clearRect(0, 0, plotCanvas.width, plotCanvas.height); |
41 drawText(text, errorOffsetPixels, errorOffsetPixels); | 44 drawText(ctx, text, errorOffsetPixels, errorOffsetPixels); |
42 } | 45 } |
43 | 46 |
44 if (size < 2) { | 47 if (size < 2) { |
45 printErrorText(loadTimeData.getString('notEnoughDataAvailableYet')); | 48 printErrorText(plotCtx, |
49 loadTimeData.getString('notEnoughDataAvailableYet')); | |
46 return; | 50 return; |
47 } | 51 } |
48 | 52 |
49 for (var count = 0; count < plots.length; count++) { | 53 for (var count = 0; count < plots.length; count++) { |
50 if (plots[count].data.length != size) { | 54 if (plots[count].data.length != size) { |
51 throw new Error('Mismatch in time and plot data.'); | 55 throw new Error('Mismatch in time and plot data.'); |
52 } | 56 } |
53 } | 57 } |
54 | 58 |
55 function valueToString(value) { | 59 function valueToString(value) { |
56 return Number(value).toPrecision(yPrecision); | 60 if (Math.abs(value) < 1) { |
61 return Number(value).toFixed(yPrecision - 1); | |
62 } else { | |
63 return Number(value).toPrecision(yPrecision); | |
64 } | |
57 } | 65 } |
58 | 66 |
59 function getTextWidth(text) { | 67 function getTextWidth(ctx, text) { |
60 ctx.font = textFont; | 68 ctx.font = textFont; |
61 // For now, all text is drawn to the left of vertical lines, or centered. | 69 // For now, all text is drawn to the left of vertical lines, or centered. |
62 // Add a 2 pixel padding so that there is some spacing between the text | 70 // Add a 2 pixel padding so that there is some spacing between the text |
63 // and the vertical line. | 71 // and the vertical line. |
64 return Math.round(ctx.measureText(text).width) + 2; | 72 return Math.round(ctx.measureText(text).width) + 2; |
65 } | 73 } |
66 | 74 |
67 function drawHighlightText(text, x, y, color) { | 75 function drawHighlightText(ctx, text, x, y, color) { |
68 ctx.strokeStyle = '#000'; | 76 ctx.strokeStyle = '#000'; |
69 ctx.strokeRect(x, y - textHeight, getTextWidth(text), textHeight); | 77 ctx.strokeRect(x, y - textHeight, getTextWidth(ctx, text), textHeight); |
70 ctx.fillStyle = color; | 78 ctx.fillStyle = color; |
71 ctx.fillRect(x, y - textHeight, getTextWidth(text), textHeight); | 79 ctx.fillRect(x, y - textHeight, getTextWidth(ctx, text), textHeight); |
72 ctx.fillStyle = '#fff'; | 80 ctx.fillStyle = '#fff'; |
73 ctx.fillText(text, x, y); | 81 ctx.fillText(text, x, y); |
74 } | 82 } |
75 | 83 |
76 function drawLine(x1, y1, x2, y2, color) { | 84 function drawLine(ctx, x1, y1, x2, y2, color) { |
77 ctx.save(); | 85 ctx.save(); |
78 ctx.beginPath(); | 86 ctx.beginPath(); |
79 ctx.moveTo(x1, y1); | 87 ctx.moveTo(x1, y1); |
80 ctx.lineTo(x2, y2); | 88 ctx.lineTo(x2, y2); |
81 ctx.strokeStyle = color; | 89 ctx.strokeStyle = color; |
82 ctx.stroke(); | 90 ctx.stroke(); |
83 ctx.restore(); | 91 ctx.restore(); |
84 } | 92 } |
85 | 93 |
86 // The strokeRect method of the 2d context of a canvas draws a bounding | 94 // The strokeRect method of the 2d context of a plotCanvas draws a bounding |
87 // rectangle with an offset origin and greater dimensions. Hence, use this | 95 // rectangle with an offset origin and greater dimensions. Hence, use this |
88 // function to draw a rect at the desired location with desired dimensions. | 96 // function to draw a rect at the desired location with desired dimensions. |
89 function drawRect(x, y, width, height, color) { | 97 function drawRect(ctx, x, y, width, height, color) { |
90 drawLine(x, y, x + width - 1, y, color); | 98 drawLine(ctx, x, y, x + width - 1, y, color); |
91 drawLine(x, y, x, y + height - 1, color); | 99 drawLine(ctx, x, y, x, y + height - 1, color); |
92 drawLine(x, y + height - 1, x + width - 1, y + height - 1, color); | 100 drawLine(ctx, x, y + height - 1, x + width - 1, y + height - 1, color); |
93 drawLine(x + width - 1, y, x + width - 1, y + height - 1, color); | 101 drawLine(ctx, x + width - 1, y, x + width - 1, y + height - 1, color); |
102 } | |
103 | |
104 function drawLegend() { | |
105 // Show a legend only if atleast one individual plot have a name. | |
arv (Not doing code reviews)
2014/03/10 17:00:46
at least
Siva Chandra
2014/03/10 18:46:09
Done.
| |
106 var valid = false; | |
107 for (var i = 0; i < plots.length; i++) { | |
108 if (plots[i].name != null) { | |
109 valid = true; | |
110 break; | |
111 } | |
112 } | |
113 if (!valid) { | |
114 legendCanvas.hidden = true; | |
115 return; | |
116 } | |
117 | |
118 var padding = 2; | |
119 var legendSquareSide = 12; | |
120 var legendCtx = legendCanvas.getContext('2d'); | |
121 var xLoc = padding; | |
122 var yLoc = padding; | |
123 // Adjust the height of the canvas before drawing on it. | |
124 for (var i = 0; i < plots.length; i++) { | |
125 if (plots[i].name == null) { | |
126 continue; | |
127 } | |
128 var legendText = ' - ' + plots[i].name; | |
129 xLoc += legendSquareSide + getTextWidth(legendCtx, legendText) + | |
130 2 * padding; | |
131 if (i < plots.length - 1) { | |
132 var xLocNext = xLoc + | |
133 getTextWidth(legendCtx, ' - ' + plots[i + 1].name) + | |
134 legendSquareSide; | |
135 if (xLocNext >= legendCanvas.width) { | |
136 xLoc = padding; | |
137 yLoc = yLoc + 2 * padding + textHeight; | |
138 } | |
139 } | |
140 } | |
141 | |
142 legendCanvas.height = yLoc + textHeight + padding; | |
143 | |
144 xLoc = padding; | |
145 yLoc = padding; | |
146 // Go over the plots again, this time drawing the legends. | |
147 for (var i = 0; i < plots.length; i++) { | |
148 legendCtx.fillStyle = plots[i].color; | |
149 legendCtx.fillRect(xLoc, yLoc, legendSquareSide, legendSquareSide); | |
150 xLoc += legendSquareSide; | |
151 | |
152 var legendText = ' - ' + plots[i].name; | |
153 drawText(legendCtx, legendText, xLoc, yLoc + textHeight - 1); | |
154 xLoc += getTextWidth(legendCtx, legendText) + 2 * padding; | |
155 | |
156 if (i < plots.length - 1) { | |
157 var xLocNext = xLoc + | |
158 getTextWidth(legendCtx, ' - ' + plots[i + 1].name) + | |
159 legendSquareSide; | |
160 if (xLocNext >= legendCanvas.width) { | |
161 xLoc = padding; | |
162 yLoc = yLoc + 2 * padding + textHeight; | |
163 } | |
164 } | |
165 } | |
94 } | 166 } |
95 | 167 |
96 var yMinStr = valueToString(yMin); | 168 var yMinStr = valueToString(yMin); |
97 var yMaxStr = valueToString(yMax); | 169 var yMaxStr = valueToString(yMax); |
98 var yHalfStr = valueToString((yMax + yMin) / 2); | 170 var yHalfStr = valueToString((yMax + yMin) / 2); |
99 var yMinWidth = getTextWidth(yMinStr); | 171 var yMinWidth = getTextWidth(plotCtx, yMinStr); |
100 var yMaxWidth = getTextWidth(yMaxStr); | 172 var yMaxWidth = getTextWidth(plotCtx, yMaxStr); |
101 var yHalfWidth = getTextWidth(yHalfStr); | 173 var yHalfWidth = getTextWidth(plotCtx, yHalfStr); |
102 | 174 |
103 var xMinStr = tData[0]; | 175 var xMinStr = tData[0]; |
104 var xMaxStr = tData[size - 1]; | 176 var xMaxStr = tData[size - 1]; |
105 var xMinWidth = getTextWidth(xMinStr); | 177 var xMinWidth = getTextWidth(plotCtx, xMinStr); |
106 var xMaxWidth = getTextWidth(xMaxStr); | 178 var xMaxWidth = getTextWidth(plotCtx, xMaxStr); |
107 | 179 |
108 var xOrigin = padding + Math.max(yMinWidth, | 180 var xOrigin = padding + Math.max(yMinWidth, |
109 yMaxWidth, | 181 yMaxWidth, |
110 Math.round(xMinWidth / 2)); | 182 Math.round(xMinWidth / 2)); |
111 var yOrigin = padding + textHeight; | 183 var yOrigin = padding + textHeight; |
112 var width = canvas.width - xOrigin - Math.floor(xMaxWidth / 2) - padding; | 184 var width = plotCanvas.width - xOrigin - Math.floor(xMaxWidth / 2) - padding; |
113 if (width < size) { | 185 if (width < size) { |
114 canvas.width += size - width; | 186 plotCanvas.width += size - width; |
115 width = size; | 187 width = size; |
116 } | 188 } |
117 var height = canvas.height - yOrigin - textHeight - padding; | 189 var height = plotCanvas.height - yOrigin - textHeight - padding; |
118 | 190 |
119 function drawPlots() { | 191 function drawPlots() { |
120 // Start fresh. | 192 // Start fresh. |
121 ctx.clearRect(0, 0, canvas.width, canvas.height); | 193 plotCtx.clearRect(0, 0, plotCanvas.width, plotCanvas.height); |
122 | 194 |
123 // Draw the bounding rectangle. | 195 // Draw the bounding rectangle. |
124 drawRect(xOrigin, yOrigin, width, height, gridColor); | 196 drawRect(plotCtx, xOrigin, yOrigin, width, height, gridColor); |
125 | 197 |
126 // Draw the x and y bound values. | 198 // Draw the x and y bound values. |
127 drawText(yMaxStr, xOrigin - yMaxWidth, yOrigin + textHeight); | 199 drawText(plotCtx, yMaxStr, xOrigin - yMaxWidth, yOrigin + textHeight); |
128 drawText(yMinStr, xOrigin - yMinWidth, yOrigin + height); | 200 drawText(plotCtx, yMinStr, xOrigin - yMinWidth, yOrigin + height); |
129 drawText(xMinStr, xOrigin - xMinWidth / 2, yOrigin + height + textHeight); | 201 drawText(plotCtx, |
130 drawText(xMaxStr, | 202 xMinStr, |
203 xOrigin - xMinWidth / 2, | |
204 yOrigin + height + textHeight); | |
205 drawText(plotCtx, | |
206 xMaxStr, | |
131 xOrigin + width - xMaxWidth / 2, | 207 xOrigin + width - xMaxWidth / 2, |
132 yOrigin + height + textHeight); | 208 yOrigin + height + textHeight); |
133 | 209 |
134 // Draw y-level (horizontal) lines. | 210 // Draw y-level (horizontal) lines. |
135 drawLine(xOrigin + 1, yOrigin + height / 4, | 211 drawLine(plotCtx, |
212 xOrigin + 1, yOrigin + height / 4, | |
136 xOrigin + width - 2, yOrigin + height / 4, | 213 xOrigin + width - 2, yOrigin + height / 4, |
137 gridColor); | 214 gridColor); |
138 drawLine(xOrigin + 1, yOrigin + height / 2, | 215 drawLine(plotCtx, |
216 xOrigin + 1, yOrigin + height / 2, | |
139 xOrigin + width - 2, yOrigin + height / 2, gridColor); | 217 xOrigin + width - 2, yOrigin + height / 2, gridColor); |
140 drawLine(xOrigin + 1, yOrigin + 3 * height / 4, | 218 drawLine(plotCtx, |
219 xOrigin + 1, yOrigin + 3 * height / 4, | |
141 xOrigin + width - 2, yOrigin + 3 * height / 4, | 220 xOrigin + width - 2, yOrigin + 3 * height / 4, |
142 gridColor); | 221 gridColor); |
143 | 222 |
144 // Draw half-level value. | 223 // Draw half-level value. |
145 drawText(yHalfStr, | 224 drawText(plotCtx, |
225 yHalfStr, | |
146 xOrigin - yHalfWidth, | 226 xOrigin - yHalfWidth, |
147 yOrigin + height / 2 + textHeight / 2); | 227 yOrigin + height / 2 + textHeight / 2); |
148 | 228 |
149 // Draw the plots. | 229 // Draw the plots. |
150 var yValRange = yMax - yMin; | 230 var yValRange = yMax - yMin; |
151 for (var count = 0; count < plots.length; count++) { | 231 for (var count = 0; count < plots.length; count++) { |
152 var plot = plots[count]; | 232 var plot = plots[count]; |
153 var yData = plot.data; | 233 var yData = plot.data; |
154 ctx.strokeStyle = plot.color; | 234 plotCtx.strokeStyle = plot.color; |
155 ctx.beginPath(); | 235 plotCtx.beginPath(); |
156 var beginPath = true; | 236 var beginPath = true; |
157 for (var i = 0; i < size; i++) { | 237 for (var i = 0; i < size; i++) { |
158 var val = yData[i]; | 238 var val = yData[i]; |
159 if (typeof val === 'string') { | 239 if (typeof val === 'string') { |
160 // Stroke the plot drawn so far and begin a fresh plot. | 240 // Stroke the plot drawn so far and begin a fresh plot. |
161 ctx.stroke(); | 241 plotCtx.stroke(); |
162 ctx.beginPath(); | 242 plotCtx.beginPath(); |
163 beginPath = true; | 243 beginPath = true; |
164 continue; | 244 continue; |
165 } | 245 } |
166 var xPos = xOrigin + Math.floor(i / (size - 1) * (width - 1)); | 246 var xPos = xOrigin + Math.floor(i / (size - 1) * (width - 1)); |
167 var yPos = yOrigin + height - 1 - | 247 var yPos = yOrigin + height - 1 - |
168 Math.round((val - yMin) / yValRange * (height - 1)); | 248 Math.round((val - yMin) / yValRange * (height - 1)); |
169 if (beginPath) { | 249 if (beginPath) { |
170 ctx.moveTo(xPos, yPos); | 250 plotCtx.moveTo(xPos, yPos); |
171 // A simple move to does not print anything. Hence, draw a little | 251 // A simple move to does not print anything. Hence, draw a little |
172 // square here to mark a beginning. | 252 // square here to mark a beginning. |
173 ctx.fillStyle = '#000'; | 253 plotCtx.fillStyle = '#000'; |
174 ctx.fillRect(xPos - 1, yPos - 1, 2, 2); | 254 plotCtx.fillRect(xPos - 1, yPos - 1, 2, 2); |
175 beginPath = false; | 255 beginPath = false; |
176 } else { | 256 } else { |
177 ctx.lineTo(xPos, yPos); | 257 plotCtx.lineTo(xPos, yPos); |
178 if (i === size - 1 || typeof yData[i + 1] === 'string') { | 258 if (i === size - 1 || typeof yData[i + 1] === 'string') { |
179 // Draw a little square to mark an end to go with the start | 259 // Draw a little square to mark an end to go with the start |
180 // markers from above. | 260 // markers from above. |
181 ctx.fillStyle = '#000'; | 261 plotCtx.fillStyle = '#000'; |
182 ctx.fillRect(xPos - 1, yPos - 1, 2, 2); | 262 plotCtx.fillRect(xPos - 1, yPos - 1, 2, 2); |
183 } | 263 } |
184 } | 264 } |
185 } | 265 } |
186 ctx.stroke(); | 266 plotCtx.stroke(); |
187 } | 267 } |
188 | 268 |
189 // Paint the missing time intervals with |gridColor|. | 269 // Paint the missing time intervals with |gridColor|. |
190 // Pick one of the plots to look for missing time intervals. | 270 // Pick one of the plots to look for missing time intervals. |
271 function drawMissingRect(start, end) { | |
272 var xLeft = xOrigin + Math.floor(start / (size - 1) * (width - 1)); | |
273 var xRight = xOrigin + Math.floor(end / (size - 1) * (width - 1)); | |
274 plotCtx.fillStyle = gridColor; | |
275 // The x offsets below are present so that the blank space starts | |
276 // and ends between two valid samples. | |
277 plotCtx.fillRect(xLeft + 1, yOrigin, xRight - xLeft - 2, height - 1); | |
278 } | |
191 var inMissingInterval = false; | 279 var inMissingInterval = false; |
192 var intervalStart; | 280 var intervalStart; |
193 for (var i = 0; i < size; i++) { | 281 for (var i = 0; i < size; i++) { |
194 if (typeof plots[0].data[i] === 'string') { | 282 if (typeof plots[0].data[i] === 'string') { |
195 if (!inMissingInterval) { | 283 if (!inMissingInterval) { |
196 inMissingInterval = true; | 284 inMissingInterval = true; |
197 // The missing interval should actually start from the previous | 285 // The missing interval should actually start from the previous |
198 // sample. | 286 // sample. |
199 intervalStart = Math.max(i - 1, 0); | 287 intervalStart = Math.max(i - 1, 0); |
200 } | 288 } |
289 | |
290 if (i == size - 1) { | |
291 // If this is the last sample, just draw missing rect. | |
292 drawMissingRect(intervalStart, i); | |
293 } | |
201 } else if (inMissingInterval) { | 294 } else if (inMissingInterval) { |
202 inMissingInterval = false; | 295 inMissingInterval = false; |
203 var xLeft = xOrigin + | 296 drawMissingRect(intervalStart, i); |
204 Math.floor(intervalStart / (size - 1) * (width - 1)); | |
205 var xRight = xOrigin + Math.floor(i / (size - 1) * (width - 1)); | |
206 ctx.fillStyle = gridColor; | |
207 // The x offsets below are present so that the blank space starts | |
208 // and ends between two valid samples. | |
209 ctx.fillRect(xLeft + 1, yOrigin, xRight - xLeft - 2, height - 1); | |
210 } | 297 } |
211 } | 298 } |
212 } | 299 } |
213 | 300 |
214 function drawTimeGuide(tDataIndex) { | 301 function drawTimeGuide(tDataIndex) { |
215 var x = xOrigin + tDataIndex / (size - 1) * (width - 1); | 302 var x = xOrigin + tDataIndex / (size - 1) * (width - 1); |
216 drawLine(x, yOrigin, x, yOrigin + height - 1, '#000'); | 303 drawLine(plotCtx, x, yOrigin, x, yOrigin + height - 1, '#000'); |
217 drawText(tData[tDataIndex], | 304 drawText(plotCtx, |
218 x - getTextWidth(tData[tDataIndex]) / 2, | 305 tData[tDataIndex], |
306 x - getTextWidth(plotCtx, tData[tDataIndex]) / 2, | |
219 yOrigin - 2); | 307 yOrigin - 2); |
220 | 308 |
221 for (var count = 0; count < plots.length; count++) { | 309 for (var count = 0; count < plots.length; count++) { |
222 var yData = plots[count].data; | 310 var yData = plots[count].data; |
223 | 311 |
224 // Draw small black square on the plot where the time guide intersects | 312 // Draw small black square on the plot where the time guide intersects |
225 // it. | 313 // it. |
226 var val = yData[tDataIndex]; | 314 var val = yData[tDataIndex]; |
227 var yPos, valStr; | 315 var yPos, valStr; |
228 if (typeof val === 'string') { | 316 if (typeof val === 'string') { |
229 yPos = yOrigin + Math.round(height / 2); | 317 yPos = yOrigin + Math.round(height / 2); |
230 valStr = val; | 318 valStr = val; |
231 } else { | 319 } else { |
232 yPos = yOrigin + height - 1 - | 320 yPos = yOrigin + height - 1 - |
233 Math.round((val - yMin) / (yMax - yMin) * (height - 1)); | 321 Math.round((val - yMin) / (yMax - yMin) * (height - 1)); |
234 valStr = valueToString(val); | 322 valStr = valueToString(val); |
235 } | 323 } |
236 ctx.fillStyle = '#000'; | 324 plotCtx.fillStyle = '#000'; |
237 ctx.fillRect(x - 2, yPos - 2, 4, 4); | 325 plotCtx.fillRect(x - 2, yPos - 2, 4, 4); |
238 | 326 |
239 // Draw the val to right of the intersection. | 327 // Draw the val to right of the intersection. |
240 var yLoc; | 328 var yLoc; |
241 if (yPos - textHeight / 2 < yOrigin) { | 329 if (yPos - textHeight / 2 < yOrigin) { |
242 yLoc = yOrigin + textHeight; | 330 yLoc = yOrigin + textHeight; |
243 } else if (yPos + textHeight / 2 >= yPos + height) { | 331 } else if (yPos + textHeight / 2 >= yPos + height) { |
244 yLoc = yOrigin + height - 1; | 332 yLoc = yOrigin + height - 1; |
245 } else { | 333 } else { |
246 yLoc = yPos + textHeight / 2; | 334 yLoc = yPos + textHeight / 2; |
247 } | 335 } |
248 drawHighlightText(valStr, x + 5, yLoc, plots[count].color); | 336 drawHighlightText(plotCtx, valStr, x + 5, yLoc, plots[count].color); |
249 } | 337 } |
250 } | 338 } |
251 | 339 |
252 function onMouseOverOrMove(event) { | 340 function onMouseOverOrMove(event) { |
253 drawPlots(); | 341 drawPlots(); |
254 | 342 |
255 var boundingRect = canvas.getBoundingClientRect(); | 343 var boundingRect = plotCanvas.getBoundingClientRect(); |
256 var x = event.clientX - boundingRect.left; | 344 var x = Math.round(event.clientX - boundingRect.left); |
257 var y = event.clientY - boundingRect.top; | 345 var y = Math.round(event.clientY - boundingRect.top); |
258 if (x < xOrigin || x >= xOrigin + width || | 346 if (x < xOrigin || x >= xOrigin + width || |
259 y < yOrigin || y >= yOrigin + height) { | 347 y < yOrigin || y >= yOrigin + height) { |
260 return; | 348 return; |
261 } | 349 } |
262 | 350 |
263 if (width == size) { | 351 if (width == size) { |
264 drawTimeGuide(x - xOrigin); | 352 drawTimeGuide(x - xOrigin); |
265 } else { | 353 } else { |
266 drawTimeGuide(Math.round((x - xOrigin) / (width - 1) * (size - 1))); | 354 drawTimeGuide(Math.round((x - xOrigin) / (width - 1) * (size - 1))); |
267 } | 355 } |
268 } | 356 } |
269 | 357 |
270 function onMouseOut(event) { | 358 function onMouseOut(event) { |
271 drawPlots(); | 359 drawPlots(); |
272 } | 360 } |
273 | 361 |
362 drawLegend(); | |
274 drawPlots(); | 363 drawPlots(); |
275 canvas.addEventListener('mouseover', onMouseOverOrMove); | 364 plotCanvas.addEventListener('mouseover', onMouseOverOrMove); |
276 canvas.addEventListener('mousemove', onMouseOverOrMove); | 365 plotCanvas.addEventListener('mousemove', onMouseOverOrMove); |
277 canvas.addEventListener('mouseout', onMouseOut); | 366 plotCanvas.addEventListener('mouseout', onMouseOut); |
278 } | 367 } |
279 | 368 |
280 var sleepSampleInterval = 30 * 1000; // in milliseconds. | 369 var sleepSampleInterval = 30 * 1000; // in milliseconds. |
281 var sleepText = loadTimeData.getString('systemSuspended'); | 370 var sleepText = loadTimeData.getString('systemSuspended'); |
371 var invalidDataText = loadTimeData.getString('invalidData'); | |
372 var offlineText = loadTimeData.getString('offlineText'); | |
373 | |
374 var plotColors = ['Red', 'Blue', 'Green', 'Gold', 'CadetBlue', 'LightCoral', | |
375 'LightSlateGray', 'Peru', 'DarkRed', 'LawnGreen', 'Tan']; | |
376 | |
377 /** | |
378 * Add canvases for plotting to |plotsDiv|. For every header in |headerArray|, | |
379 * one canvas for the plot and one for its legend are added. | |
380 * | |
381 * @param {Array.<string>} headerArray Headers for the different plots to be | |
382 * added to |plotsDiv|. | |
383 * @param {HTMLDivElement} plotsDiv The div element into which the canvases | |
384 * are added. | |
385 * @return {<string>: {plotCanvas: <HTMLCanvasElement>, | |
386 * legendCanvas: <HTMLCanvasElement>} Returns an object | |
387 * with the headers as 'keys'. Each element is an object containing the | |
388 * legend canvas and the plot canvas that have been added to |plotsDiv|. | |
389 */ | |
390 function addCanvases(headerArray, plotsDiv) { | |
391 // Remove the contents before adding new ones. | |
392 while (plotsDiv.firstChild != null) { | |
393 plotsDiv.removeChild(plotsDiv.firstChild); | |
394 } | |
395 var width = Math.floor(plotsDiv.getBoundingClientRect().width); | |
396 var canvases = {}; | |
397 for (var i = 0; i < headerArray.length; i++) { | |
398 var header = document.createElement('h4'); | |
399 header.textContent = headerArray[i]; | |
400 plotsDiv.appendChild(header); | |
401 | |
402 var legendCanvas = document.createElement('canvas'); | |
403 legendCanvas.width = width; | |
404 legendCanvas.height = 5; | |
405 plotsDiv.appendChild(legendCanvas); | |
406 | |
407 var br = document.createElement('br'); | |
arv (Not doing code reviews)
2014/03/10 17:00:46
I doubt this br is needed
Siva Chandra
2014/03/10 18:46:09
Done.
| |
408 plotsDiv.appendChild(br); | |
409 | |
410 var plotCanvasDiv = document.createElement('div'); | |
411 plotCanvasDiv.style.overflow = 'auto'; | |
412 plotCanvasDiv.style.maxWidth = String(width) + 'px'; | |
413 plotsDiv.appendChild(plotCanvasDiv); | |
414 | |
415 plotCanvas = document.createElement('canvas'); | |
416 plotCanvas.width = width; | |
417 plotCanvas.height = 200; | |
418 plotCanvasDiv.appendChild(plotCanvas); | |
419 | |
420 canvases[headerArray[i]] = {plot: plotCanvas, legend: legendCanvas}; | |
421 } | |
422 return canvases; | |
423 } | |
282 | 424 |
283 /** | 425 /** |
284 * Add samples in |sampleArray| to individual plots in |plots|. If the system | 426 * Add samples in |sampleArray| to individual plots in |plots|. If the system |
285 * resumed from a sleep/suspend, then "suspended" sleep samples are added to | 427 * resumed from a sleep/suspend, then "suspended" sleep samples are added to |
286 * the plot for the sleep duration. | 428 * the plot for the sleep duration. |
287 * | 429 * |
288 * @param {Array.<{data: Array.<number>, color: string}>} plots An | 430 * @param {Array.<{data: Array.<number>, color: string}>} plots An |
289 * array of plots to plot on the canvas. The field 'data' of a plot is an | 431 * array of plots to plot on the canvas. The field 'data' of a plot is an |
290 * array of samples to be plotted as a line graph with color speficied by | 432 * array of samples to be plotted as a line graph with color speficied by |
291 * the field 'color'. The elements in the 'data' array are ordered | 433 * the field 'color'. The elements in the 'data' array are ordered |
292 * corresponding to their sampling time in the argument 'tData'. Also, the | 434 * corresponding to their sampling time in the argument 'tData'. Also, the |
293 * number of elements in the 'data' array should be the same as in the time | 435 * number of elements in the 'data' array should be the same as in the time |
294 * array 'tData' below. | 436 * array 'tData' below. |
295 * @param {Array.<number>} tData The time (in seconds) in the past when the | 437 * @param {Array.<number>} tData The time (in seconds) in the past when the |
296 * corresponding data in plots was sampled. | 438 * corresponding data in plots was sampled. |
297 * @param {Array.<number>} sampleArray The array of samples wherein each | 439 * @param {Array.<number>} sampleArray The array of samples wherein each |
298 * element corresponds to the individual plot in |plots|. | 440 * element corresponds to the individual plot in |plots|. |
299 * @param {number} sampleTime Time in milliseconds since the epoch when the | 441 * @param {number} sampleTime Time in milliseconds since the epoch when the |
300 * samples in |sampleArray| were captured. | 442 * samples in |sampleArray| were captured. |
301 * @param {number} previousSampleTime Time in milliseconds since the epoch | 443 * @param {number} previousSampleTime Time in milliseconds since the epoch |
302 * when the sample prior to the current sample was captured. | 444 * when the sample prior to the current sample was captured. |
303 * @param {Array.<{time: number, sleepDuration: number}>} systemResumedArray An | 445 * @param {Array.<{time: number, sleepDuration: number}>} systemResumedArray An |
304 * array objects corresponding to system resume events. The 'time' field is | 446 * array objects corresponding to system resume events. The 'time' field is |
305 * for the time in milliseconds since the epoch when the system resumed. The | 447 * for the time in milliseconds since the epoch when the system resumed. The |
306 * 'sleepDuration' field is for the time in milliseconds the system spent | 448 * 'sleepDuration' field is for the time in milliseconds the system spent |
307 * in sleep/suspend state. | 449 * in sleep/suspend state. |
308 */ | 450 */ |
309 function addTimeDataSample(plots, tData, sampleArray, | 451 function addTimeDataSample(plots, tData, absTime, sampleArray, |
310 sampleTime, previousSampleTime, | 452 sampleTime, previousSampleTime, |
311 systemResumedArray) { | 453 systemResumedArray) { |
312 for (var i = 0; i < plots.length; i++) { | 454 for (var i = 0; i < plots.length; i++) { |
313 if (plots[i].data.length != tData.length) { | 455 if (plots[i].data.length != tData.length) { |
314 throw new Error('Mismatch in time and plot data.'); | 456 throw new Error('Mismatch in time and plot data.'); |
315 } | 457 } |
316 } | 458 } |
317 | 459 |
318 var time; | 460 var time; |
319 if (tData.length == 0) { | 461 if (tData.length == 0) { |
320 time = new Date(sampleTime); | 462 time = new Date(sampleTime); |
463 absTime[0] = sampleTime; | |
321 tData[0] = time.toLocaleTimeString(); | 464 tData[0] = time.toLocaleTimeString(); |
322 for (var i = 0; i < plots.length; i++) { | 465 for (var i = 0; i < plots.length; i++) { |
323 plots[i].data[0] = sampleArray[i]; | 466 plots[i].data[0] = sampleArray[i]; |
324 } | 467 } |
325 return; | 468 return; |
326 } | 469 } |
327 | 470 |
328 for (var i = 0; i < systemResumedArray.length; i++) { | 471 for (var i = 0; i < systemResumedArray.length; i++) { |
329 var resumeTime = systemResumedArray[i].time; | 472 var resumeTime = systemResumedArray[i].time; |
330 var sleepDuration = systemResumedArray[i].sleepDuration; | 473 var sleepDuration = systemResumedArray[i].sleepDuration; |
331 var sleepStartTime = resumeTime - sleepDuration; | 474 var sleepStartTime = resumeTime - sleepDuration; |
332 if (resumeTime < sampleTime && sleepStartTime > previousSampleTime) { | 475 if (resumeTime < sampleTime) { |
476 if (sleepStartTime < previousSampleTime) { | |
477 // This can happen if pending callbacks were handled before actually | |
478 // suspending. | |
479 sleepStartTime = previousSampleTime + 1000; | |
480 } | |
333 // Add sleep samples for every |sleepSampleInterval|. | 481 // Add sleep samples for every |sleepSampleInterval|. |
334 var sleepSampleTime = sleepStartTime; | 482 var sleepSampleTime = sleepStartTime; |
335 while (sleepSampleTime < resumeTime) { | 483 while (sleepSampleTime < resumeTime) { |
336 time = new Date(sleepSampleTime); | 484 time = new Date(sleepSampleTime); |
485 absTime.push(sleepSampleTime); | |
337 tData.push(time.toLocaleTimeString()); | 486 tData.push(time.toLocaleTimeString()); |
338 for (var j = 0; j < plots.length; j++) { | 487 for (var j = 0; j < plots.length; j++) { |
339 plots[j].data.push(sleepText); | 488 plots[j].data.push(sleepText); |
340 } | 489 } |
341 sleepSampleTime += sleepSampleInterval; | 490 sleepSampleTime += sleepSampleInterval; |
342 } | 491 } |
343 } | 492 } |
344 } | 493 } |
345 | 494 |
346 time = new Date(sampleTime); | 495 time = new Date(sampleTime); |
496 absTime.push(sampleTime); | |
347 tData.push(time.toLocaleTimeString()); | 497 tData.push(time.toLocaleTimeString()); |
348 for (var i = 0; i < plots.length; i++) { | 498 for (var i = 0; i < plots.length; i++) { |
349 plots[i].data.push(sampleArray[i]); | 499 plots[i].data.push(sampleArray[i]); |
350 } | 500 } |
351 } | 501 } |
352 | 502 |
353 /** | 503 /** |
354 * Display the battery charge vs time on a line graph. | 504 * Display the battery charge vs time on a line graph. |
355 * | 505 * |
356 * @param {Array.<{time: number, | 506 * @param {Array.<{time: number, |
357 * batteryPercent: number, | 507 * batteryPercent: number, |
358 * batteryDischargeRate: number, | 508 * batteryDischargeRate: number, |
359 * externalPower: number}>} powerSupplyArray An array of objects | 509 * externalPower: number}>} powerSupplyArray An array of objects |
360 * with fields representing the battery charge, time when the charge | 510 * with fields representing the battery charge, time when the charge |
361 * measurement was taken, and whether there was external power connected at | 511 * measurement was taken, and whether there was external power connected at |
362 * that time. | 512 * that time. |
363 * @param {Array.<{time: ?, sleepDuration: ?}>} systemResumedArray An array | 513 * @param {Array.<{time: ?, sleepDuration: ?}>} systemResumedArray An array |
364 * objects with fields 'time' and 'sleepDuration'. Each object corresponds | 514 * objects with fields 'time' and 'sleepDuration'. Each object corresponds |
365 * to a system resume event. The 'time' field is for the time in | 515 * to a system resume event. The 'time' field is for the time in |
366 * milliseconds since the epoch when the system resumed. The 'sleepDuration' | 516 * milliseconds since the epoch when the system resumed. The 'sleepDuration' |
367 * field is for the time in milliseconds the system spent in sleep/suspend | 517 * field is for the time in milliseconds the system spent in sleep/suspend |
368 * state. | 518 * state. |
369 */ | 519 */ |
370 function showBatteryChargeData(powerSupplyArray, systemResumedArray) { | 520 function showBatteryChargeData(powerSupplyArray, systemResumedArray) { |
371 var chargeTimeData = []; | 521 var chargeTimeData = []; |
522 var chargeAbsTime = []; | |
372 var chargePlot = [ | 523 var chargePlot = [ |
373 { | 524 { |
525 name: loadTimeData.getString('batteryChargePercentageHeader'), | |
374 color: '#0000FF', | 526 color: '#0000FF', |
375 data: [] | 527 data: [] |
376 } | 528 } |
377 ]; | 529 ]; |
378 var dischargeRateTimeData = []; | 530 var dischargeRateTimeData = []; |
531 var dischargeRateAbsTime = []; | |
379 var dischargeRatePlot = [ | 532 var dischargeRatePlot = [ |
380 { | 533 { |
534 name: loadTimeData.getString('dischargeRateLegendText'), | |
381 color: '#FF0000', | 535 color: '#FF0000', |
382 data: [] | 536 data: [] |
383 } | 537 } |
384 ]; | 538 ]; |
385 var minDischargeRate = 1000; // A high unrealistic number to begin with. | 539 var minDischargeRate = 1000; // A high unrealistic number to begin with. |
386 var maxDischargeRate = -1000; // A low unrealistic number to begin with. | 540 var maxDischargeRate = -1000; // A low unrealistic number to begin with. |
387 for (var i = 0; i < powerSupplyArray.length; i++) { | 541 for (var i = 0; i < powerSupplyArray.length; i++) { |
388 var j = Math.max(i - 1, 0); | 542 var j = Math.max(i - 1, 0); |
389 | 543 |
390 addTimeDataSample(chargePlot, chargeTimeData, | 544 addTimeDataSample(chargePlot, |
545 chargeTimeData, | |
546 chargeAbsTime, | |
391 [powerSupplyArray[i].batteryPercent], | 547 [powerSupplyArray[i].batteryPercent], |
392 powerSupplyArray[i].time, | 548 powerSupplyArray[i].time, |
393 powerSupplyArray[j].time, | 549 powerSupplyArray[j].time, |
394 systemResumedArray); | 550 systemResumedArray); |
395 | 551 |
396 var dischargeRate = powerSupplyArray[i].batteryDischargeRate; | 552 var dischargeRate = powerSupplyArray[i].batteryDischargeRate; |
397 minDischargeRate = Math.min(dischargeRate, minDischargeRate); | 553 minDischargeRate = Math.min(dischargeRate, minDischargeRate); |
398 maxDischargeRate = Math.max(dischargeRate, maxDischargeRate); | 554 maxDischargeRate = Math.max(dischargeRate, maxDischargeRate); |
399 addTimeDataSample(dischargeRatePlot, | 555 addTimeDataSample(dischargeRatePlot, |
400 dischargeRateTimeData, | 556 dischargeRateTimeData, |
557 dischargeRateAbsTime, | |
401 [dischargeRate], | 558 [dischargeRate], |
402 powerSupplyArray[i].time, | 559 powerSupplyArray[i].time, |
403 powerSupplyArray[j].time, | 560 powerSupplyArray[j].time, |
404 systemResumedArray); | 561 systemResumedArray); |
405 } | 562 } |
406 if (minDischargeRate == maxDischargeRate) { | 563 if (minDischargeRate == maxDischargeRate) { |
407 // This means that all the samples had the same value. Hence, offset the | 564 // This means that all the samples had the same value. Hence, offset the |
408 // extremes by a bit so that the plot looks good. | 565 // extremes by a bit so that the plot looks good. |
409 minDischargeRate -= 1; | 566 minDischargeRate -= 1; |
410 maxDischargeRate += 1; | 567 maxDischargeRate += 1; |
411 } | 568 } |
412 | 569 |
413 var chargeCanvas = $('battery-charge-percentage-canvas'); | 570 plotsDiv = $('battery-charge-plots-div'); |
414 var dischargeRateCanvas = $('battery-discharge-rate-canvas'); | 571 |
415 plotLineGraph(chargeCanvas, chargeTimeData, chargePlot, 0.00, 100.00, 3); | 572 canvases = addCanvases( |
416 plotLineGraph(dischargeRateCanvas, | 573 [loadTimeData.getString('batteryChargePercentageHeader'), |
417 dischargeRateTimeData, | 574 loadTimeData.getString('batteryDischargeRateHeader')], |
418 dischargeRatePlot, | 575 plotsDiv); |
419 minDischargeRate, | 576 |
420 maxDischargeRate, | 577 batteryChargeCanvases = canvases[ |
421 3); | 578 loadTimeData.getString('batteryChargePercentageHeader')]; |
579 plotLineGraph( | |
580 batteryChargeCanvases['plot'], | |
581 batteryChargeCanvases['legend'], | |
582 chargeTimeData, | |
583 chargePlot, | |
584 0.00, | |
585 100.00, | |
586 3); | |
587 | |
588 dischargeRateCanvases = canvases[ | |
589 loadTimeData.getString('batteryDischargeRateHeader')]; | |
590 plotLineGraph( | |
591 dischargeRateCanvases['plot'], | |
592 dischargeRateCanvases['legend'], | |
593 dischargeRateTimeData, | |
594 dischargeRatePlot, | |
595 minDischargeRate, | |
596 maxDischargeRate, | |
597 3); | |
598 } | |
599 | |
600 /** | |
601 * Shows state occupancy data (CPU idle or CPU freq state occupancy) on a set of | |
602 * plots on the about:power UI. | |
603 * | |
604 * @param {Array.<{Array.<{ | |
605 * time: number, | |
606 * cpuOnline:boolean, | |
607 * timeInState: {<string>: number}>}>} timeInStateData Array of arrays | |
608 * where each array corresponds to a CPU on the system. The elements of the | |
609 * individual arrays contain state occupancy samples. | |
610 * @param {Array.<{time: ?, sleepDuration: ?}>} systemResumedArray An array | |
611 * objects with fields 'time' and 'sleepDuration'. Each object corresponds | |
612 * to a system resume event. The 'time' field is for the time in | |
613 * milliseconds since the epoch when the system resumed. The 'sleepDuration' | |
614 * field is for the time in milliseconds the system spent in sleep/suspend | |
615 * state. | |
616 * @param {string} i18nHeaderString The header string to be displayed with each | |
617 * plot. For example, CPU idle data will have its own header format, and CPU | |
618 * freq data will have its header format. | |
619 * @param {string} unitString This is the string capturing the unit, if any, | |
620 * for the different states. Note that this is not the unit of the data | |
621 * being plotted. | |
622 * @param {HTMLDivElement} plotsDivId The div element in which the plots should | |
623 * be added. | |
624 */ | |
625 function showStateOccupancyData(timeInStateData, | |
626 systemResumedArray, | |
627 i18nHeaderString, | |
628 unitString, | |
629 plotsDivId) { | |
630 var cpuPlots = []; | |
631 for (var cpu = 0; cpu < timeInStateData.length; cpu++) { | |
632 var cpuData = timeInStateData[cpu]; | |
633 if (cpuData.length == 0) { | |
634 cpuPlots[cpu] = {plots: [], tData: []}; | |
635 continue; | |
636 } | |
637 tData = []; | |
638 absTime = []; | |
639 // Each element of |plots| is an array of samples, one for each of the CPU | |
640 // states. The number of states is dicovered by looking at the first | |
641 // sample for which the CPU is online. | |
642 var plots = []; | |
643 var stateIndexMap = []; | |
644 var stateCount = 0; | |
645 for (var i = 0; i < cpuData.length; i++) { | |
646 if (cpuData[i].cpuOnline) { | |
647 for (var state in cpuData[i].timeInState) { | |
648 var stateName = state; | |
649 if (unitString != null) { | |
650 stateName += ' ' + unitString; | |
651 } | |
652 plots.push({ | |
653 name: stateName, | |
654 data: [], | |
655 color: plotColors[stateCount] | |
656 }); | |
657 stateIndexMap.push(state); | |
658 stateCount += 1; | |
659 } | |
660 break; | |
661 } | |
662 } | |
663 // If stateCount is 0, then it means the CPU has been offline | |
664 // throughout. Just add a single plot for such a case. | |
665 if (stateCount == 0) { | |
666 plots.push({ | |
667 name: null, | |
668 data: [], | |
669 color: null | |
670 }); | |
671 stateCount = 1; // Some invalid state! | |
672 } | |
673 | |
674 // Pass the samples through the function addTimeDataSample to add 'sleep' | |
675 // samples. | |
676 for (var i = 0; i < cpuData.length; i++) { | |
677 var sample = cpuData[i]; | |
678 var valArray = []; | |
679 for (var j = 0; j < stateCount; j++) { | |
680 if (sample.cpuOnline) { | |
681 valArray[j] = sample.timeInState[stateIndexMap[j]]; | |
682 } else { | |
683 valArray[j] = offlineText; | |
684 } | |
685 } | |
686 | |
687 var k = Math.max(i - 1, 0); | |
688 addTimeDataSample(plots, | |
689 tData, | |
690 absTime, | |
691 valArray, | |
692 sample.time, | |
693 cpuData[k].time, | |
694 systemResumedArray); | |
695 } | |
696 | |
697 // Calculate the percentage occupancy of each state. A valid number is | |
698 // possible only if two consecutive samples are valid/numbers. | |
699 for (var k = 0; k < stateCount; k++) { | |
700 var stateData = plots[k].data; | |
701 // Skip the first sample as there is no previous sample. | |
702 for (var i = stateData.length - 1; i > 0; i--) { | |
703 if (typeof stateData[i] === 'number') { | |
704 if (typeof stateData[i - 1] === 'number') { | |
705 stateData[i] = (stateData[i] - stateData[i - 1]) / | |
706 (absTime[i] - absTime[i - 1]) * 100; | |
707 } else { | |
708 stateData[i] = invalidDataText; | |
709 } | |
710 } | |
711 } | |
712 } | |
713 | |
714 // Remove the first sample from the time and data arrays. | |
715 tData.shift(); | |
716 for (var k = 0; k < stateCount; k++) { | |
717 plots[k].data.shift(); | |
718 } | |
719 cpuPlots[cpu] = {plots: plots, tData: tData}; | |
720 } | |
721 | |
722 headers = []; | |
723 for (var cpu = 0; cpu < timeInStateData.length; cpu++) { | |
724 headers[cpu] = | |
725 'CPU ' + cpu + ' ' + loadTimeData.getString(i18nHeaderString); | |
726 } | |
727 | |
728 canvases = addCanvases(headers, $(plotsDivId)); | |
729 for (var cpu = 0; cpu < timeInStateData.length; cpu++) { | |
730 cpuCanvases = canvases[headers[cpu]]; | |
731 plotLineGraph(cpuCanvases['plot'], | |
732 cpuCanvases['legend'], | |
733 cpuPlots[cpu]['tData'], | |
734 cpuPlots[cpu]['plots'], | |
735 0, | |
736 100, | |
737 3); | |
738 } | |
739 } | |
740 | |
741 function showCpuIdleData(idleStateData, systemResumedArray) { | |
742 showStateOccupancyData(idleStateData, | |
743 systemResumedArray, | |
744 'idleStateOccupancyPercentageHeader', | |
745 null, | |
746 'cpu-idle-plots-div'); | |
747 } | |
748 | |
749 function showCpuFreqData(freqStateData, systemResumedArray) { | |
750 showStateOccupancyData(freqStateData, | |
751 systemResumedArray, | |
752 'frequencyStateOccupancyPercentageHeader', | |
753 'MHz', | |
754 'cpu-freq-plots-div'); | |
422 } | 755 } |
423 | 756 |
424 function requestBatteryChargeData() { | 757 function requestBatteryChargeData() { |
425 chrome.send('requestBatteryChargeData'); | 758 chrome.send('requestBatteryChargeData'); |
426 } | 759 } |
427 | 760 |
761 function requestCpuIdleData() { | |
762 chrome.send('requestCpuIdleData'); | |
763 } | |
764 | |
765 function requestCpuFreqData() { | |
766 chrome.send('requestCpuFreqData'); | |
767 } | |
768 | |
769 /** | |
770 * Return a callback for the 'Show'/'Hide' buttons for each section of the | |
771 * about:power page. | |
772 * | |
773 * @param {string} sectionId The ID of the section which is to be shown or | |
774 * hidden. | |
775 * @param {string} buttonId The ID of the 'Show'/'Hide' button. | |
776 * @param {function} requestFunction The function which should be invoked on | |
777 * 'Show' to request for data from chrome. | |
778 * @return {function} The button callback function. | |
779 */ | |
780 function showHideCallback(sectionId, buttonId, requestFunction) { | |
781 return function() { | |
782 if ($(sectionId).hidden) { | |
783 $(sectionId).hidden = false; | |
784 $(buttonId).textContent = loadTimeData.getString('hideButton'); | |
785 requestFunction(); | |
786 } else { | |
787 $(sectionId).hidden = true; | |
788 $(buttonId).textContent = loadTimeData.getString('showButton'); | |
789 } | |
790 } | |
791 } | |
792 | |
428 var powerUI = { | 793 var powerUI = { |
429 showBatteryChargeData: showBatteryChargeData | 794 showBatteryChargeData: showBatteryChargeData, |
795 showCpuIdleData: showCpuIdleData, | |
796 showCpuFreqData: showCpuFreqData | |
430 }; | 797 }; |
431 | 798 |
432 document.addEventListener('DOMContentLoaded', function() { | 799 document.addEventListener('DOMContentLoaded', function() { |
433 requestBatteryChargeData(); | 800 $('battery-charge-section').hidden = true; |
801 $('battery-charge-show-button').onclick = showHideCallback( | |
802 'battery-charge-section', | |
803 'battery-charge-show-button', | |
804 requestBatteryChargeData); | |
434 $('battery-charge-reload-button').onclick = requestBatteryChargeData; | 805 $('battery-charge-reload-button').onclick = requestBatteryChargeData; |
806 | |
807 $('cpu-idle-section').hidden = true; | |
808 $('cpu-idle-show-button').onclick = showHideCallback( | |
809 'cpu-idle-section', 'cpu-idle-show-button', requestCpuIdleData); | |
810 $('cpu-idle-reload-button').onclick = requestCpuIdleData; | |
811 | |
arv (Not doing code reviews)
2014/03/10 17:00:46
remove empty line
Siva Chandra
2014/03/10 18:46:09
Done.
| |
812 | |
813 $('cpu-freq-section').hidden = true; | |
814 $('cpu-freq-show-button').onclick = showHideCallback( | |
815 'cpu-freq-section', 'cpu-freq-show-button', requestCpuFreqData); | |
816 $('cpu-freq-reload-button').onclick = requestCpuFreqData; | |
435 }); | 817 }); |
OLD | NEW |