cros: Update SAML flow.
[chromium-blink-merge.git] / chrome / browser / resources / chromeos / power.js
blob2d2f2df2b2a3978823fc4dd1894188e81f0e663d
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
3 // found in the LICENSE file.
5 /**
6 * Plot a line graph of data versus time on a HTML canvas element.
8 * @param {HTMLCanvasElement} canvas The canvas on which the line graph is
9 * drawn.
10 * @param {Array.<number>} tData The time (in seconds) in the past when the
11 * corresponding data in plots was sampled.
12 * @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
14 * 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
16 * 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
18 * array 'tData' above.
19 * @param {number} yMin Minimum bound of y-axis
20 * @param {number} yMax Maximum bound of y-axis.
21 * @param {integer} yPrecision An integer value representing the number of
22 * digits of precision the y-axis data should be printed with.
24 function plotLineGraph(canvas, tData, plots, yMin, yMax, yPrecision) {
25 var textFont = '12px Arial';
26 var textHeight = 12;
27 var padding = 5; // Pixels
28 var errorOffsetPixels = 15;
29 var gridColor = '#ccc';
30 var ctx = canvas.getContext('2d');
31 var size = tData.length;
33 function drawText(text, x, y) {
34 ctx.font = textFont;
35 ctx.fillStyle = '#000';
36 ctx.fillText(text, x, y);
39 function printErrorText(text) {
40 ctx.clearRect(0, 0, canvas.width, canvas.height);
41 drawText(text, errorOffsetPixels, errorOffsetPixels);
44 if (size < 2) {
45 printErrorText(loadTimeData.getString('notEnoughDataAvailableYet'));
46 return;
49 for (var count = 0; count < plots.length; count++) {
50 if (plots[count].data.length != size) {
51 throw new Error('Mismatch in time and plot data.');
55 function valueToString(value) {
56 return Number(value).toPrecision(yPrecision);
59 function getTextWidth(text) {
60 ctx.font = textFont;
61 // 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
63 // and the vertical line.
64 return Math.round(ctx.measureText(text).width) + 2;
67 function drawHighlightText(text, x, y, color) {
68 ctx.strokeStyle = '#000';
69 ctx.strokeRect(x, y - textHeight, getTextWidth(text), textHeight);
70 ctx.fillStyle = color;
71 ctx.fillRect(x, y - textHeight, getTextWidth(text), textHeight);
72 ctx.fillStyle = '#fff';
73 ctx.fillText(text, x, y);
76 function drawLine(x1, y1, x2, y2, color) {
77 ctx.save();
78 ctx.beginPath();
79 ctx.moveTo(x1, y1);
80 ctx.lineTo(x2, y2);
81 ctx.strokeStyle = color;
82 ctx.stroke();
83 ctx.restore();
86 // The strokeRect method of the 2d context of a canvas draws a bounding
87 // rectangle with an offset origin and greater dimensions. Hence, use this
88 // function to draw a rect at the desired location with desired dimensions.
89 function drawRect(x, y, width, height, color) {
90 drawLine(x, y, x + width - 1, y, color);
91 drawLine(x, y, x, y + height - 1, color);
92 drawLine(x, y + height - 1, x + width - 1, y + height - 1, color);
93 drawLine(x + width - 1, y, x + width - 1, y + height - 1, color);
96 var yMinStr = valueToString(yMin);
97 var yMaxStr = valueToString(yMax);
98 var yHalfStr = valueToString((yMax + yMin) / 2);
99 var yMinWidth = getTextWidth(yMinStr);
100 var yMaxWidth = getTextWidth(yMaxStr);
101 var yHalfWidth = getTextWidth(yHalfStr);
103 var xMinStr = tData[0];
104 var xMaxStr = tData[size - 1];
105 var xMinWidth = getTextWidth(xMinStr);
106 var xMaxWidth = getTextWidth(xMaxStr);
108 var xOrigin = padding + Math.max(yMinWidth,
109 yMaxWidth,
110 Math.round(xMinWidth / 2));
111 var yOrigin = padding + textHeight;
112 var width = canvas.width - xOrigin - Math.floor(xMaxWidth / 2) - padding;
113 if (width < size) {
114 canvas.width += size - width;
115 width = size;
117 var height = canvas.height - yOrigin - textHeight - padding;
119 function drawPlots() {
120 // Start fresh.
121 ctx.clearRect(0, 0, canvas.width, canvas.height);
123 // Draw the bounding rectangle.
124 drawRect(xOrigin, yOrigin, width, height, gridColor);
126 // Draw the x and y bound values.
127 drawText(yMaxStr, xOrigin - yMaxWidth, yOrigin + textHeight);
128 drawText(yMinStr, xOrigin - yMinWidth, yOrigin + height);
129 drawText(xMinStr, xOrigin - xMinWidth / 2, yOrigin + height + textHeight);
130 drawText(xMaxStr,
131 xOrigin + width - xMaxWidth / 2,
132 yOrigin + height + textHeight);
134 // Draw y-level (horizontal) lines.
135 drawLine(xOrigin + 1, yOrigin + height / 4,
136 xOrigin + width - 2, yOrigin + height / 4,
137 gridColor);
138 drawLine(xOrigin + 1, yOrigin + height / 2,
139 xOrigin + width - 2, yOrigin + height / 2, gridColor);
140 drawLine(xOrigin + 1, yOrigin + 3 * height / 4,
141 xOrigin + width - 2, yOrigin + 3 * height / 4,
142 gridColor);
144 // Draw half-level value.
145 drawText(yHalfStr,
146 xOrigin - yHalfWidth,
147 yOrigin + height / 2 + textHeight / 2);
149 // Draw the plots.
150 var yValRange = yMax - yMin;
151 for (var count = 0; count < plots.length; count++) {
152 var plot = plots[count];
153 var yData = plot.data;
154 ctx.strokeStyle = plot.color;
155 ctx.beginPath();
156 var beginPath = true;
157 for (var i = 0; i < size; i++) {
158 var val = yData[i];
159 if (typeof val === 'string') {
160 // Stroke the plot drawn so far and begin a fresh plot.
161 ctx.stroke();
162 ctx.beginPath();
163 beginPath = true;
164 continue;
166 var xPos = xOrigin + Math.floor(i / (size - 1) * (width - 1));
167 var yPos = yOrigin + height - 1 -
168 Math.round((val - yMin) / yValRange * (height - 1));
169 if (beginPath) {
170 ctx.moveTo(xPos, yPos);
171 // A simple move to does not print anything. Hence, draw a little
172 // square here to mark a beginning.
173 ctx.fillStyle = '#000';
174 ctx.fillRect(xPos - 1, yPos - 1, 2, 2);
175 beginPath = false;
176 } else {
177 ctx.lineTo(xPos, yPos);
178 if (i === size - 1 || typeof yData[i + 1] === 'string') {
179 // Draw a little square to mark an end to go with the start
180 // markers from above.
181 ctx.fillStyle = '#000';
182 ctx.fillRect(xPos - 1, yPos - 1, 2, 2);
186 ctx.stroke();
189 // Paint the missing time intervals with |gridColor|.
190 // Pick one of the plots to look for missing time intervals.
191 var inMissingInterval = false;
192 var intervalStart;
193 for (var i = 0; i < size; i++) {
194 if (typeof plots[0].data[i] === 'string') {
195 if (!inMissingInterval) {
196 inMissingInterval = true;
197 // The missing interval should actually start from the previous
198 // sample.
199 intervalStart = Math.max(i - 1, 0);
201 } else if (inMissingInterval) {
202 inMissingInterval = false;
203 var xLeft = xOrigin +
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);
214 function drawTimeGuide(tDataIndex) {
215 var x = xOrigin + tDataIndex / (size - 1) * (width - 1);
216 drawLine(x, yOrigin, x, yOrigin + height - 1, '#000');
217 drawText(tData[tDataIndex],
218 x - getTextWidth(tData[tDataIndex]) / 2,
219 yOrigin - 2);
221 for (var count = 0; count < plots.length; count++) {
222 var yData = plots[count].data;
224 // Draw small black square on the plot where the time guide intersects
225 // it.
226 var val = yData[tDataIndex];
227 var yPos, valStr;
228 if (typeof val === 'string') {
229 yPos = yOrigin + Math.round(height / 2);
230 valStr = val;
231 } else {
232 yPos = yOrigin + height - 1 -
233 Math.round((val - yMin) / (yMax - yMin) * (height - 1));
234 valStr = valueToString(val);
236 ctx.fillStyle = '#000';
237 ctx.fillRect(x - 2, yPos - 2, 4, 4);
239 // Draw the val to right of the intersection.
240 var yLoc;
241 if (yPos - textHeight / 2 < yOrigin) {
242 yLoc = yOrigin + textHeight;
243 } else if (yPos + textHeight / 2 >= yPos + height) {
244 yLoc = yOrigin + height - 1;
245 } else {
246 yLoc = yPos + textHeight / 2;
248 drawHighlightText(valStr, x + 5, yLoc, plots[count].color);
252 function onMouseOverOrMove(event) {
253 drawPlots();
255 var boundingRect = canvas.getBoundingClientRect();
256 var x = event.clientX - boundingRect.left;
257 var y = event.clientY - boundingRect.top;
258 if (x < xOrigin || x >= xOrigin + width ||
259 y < yOrigin || y >= yOrigin + height) {
260 return;
263 if (width == size) {
264 drawTimeGuide(x - xOrigin);
265 } else {
266 drawTimeGuide(Math.round((x - xOrigin) / (width - 1) * (size - 1)));
270 function onMouseOut(event) {
271 drawPlots();
274 drawPlots();
275 canvas.addEventListener('mouseover', onMouseOverOrMove);
276 canvas.addEventListener('mousemove', onMouseOverOrMove);
277 canvas.addEventListener('mouseout', onMouseOut);
280 var sleepSampleInterval = 30 * 1000; // in milliseconds.
281 var sleepText = loadTimeData.getString('systemSuspended');
284 * 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
286 * the plot for the sleep duration.
288 * @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
290 * 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
292 * 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
294 * array 'tData' below.
295 * @param {Array.<number>} tData The time (in seconds) in the past when the
296 * corresponding data in plots was sampled.
297 * @param {Array.<number>} sampleArray The array of samples wherein each
298 * element corresponds to the individual plot in |plots|.
299 * @param {number} sampleTime Time in milliseconds since the epoch when the
300 * samples in |sampleArray| were captured.
301 * @param {number} previousSampleTime Time in milliseconds since the epoch
302 * when the sample prior to the current sample was captured.
303 * @param {Array.<{time: number, sleepDuration: number}>} systemResumedArray An
304 * 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
306 * 'sleepDuration' field is for the time in milliseconds the system spent
307 * in sleep/suspend state.
309 function addTimeDataSample(plots, tData, sampleArray,
310 sampleTime, previousSampleTime,
311 systemResumedArray) {
312 for (var i = 0; i < plots.length; i++) {
313 if (plots[i].data.length != tData.length) {
314 throw new Error('Mismatch in time and plot data.');
318 var time;
319 if (tData.length == 0) {
320 time = new Date(sampleTime);
321 tData[0] = time.toLocaleTimeString();
322 for (var i = 0; i < plots.length; i++) {
323 plots[i].data[0] = sampleArray[i];
325 return;
328 for (var i = 0; i < systemResumedArray.length; i++) {
329 var resumeTime = systemResumedArray[i].time;
330 var sleepDuration = systemResumedArray[i].sleepDuration;
331 var sleepStartTime = resumeTime - sleepDuration;
332 if (resumeTime < sampleTime && sleepStartTime > previousSampleTime) {
333 // Add sleep samples for every |sleepSampleInterval|.
334 var sleepSampleTime = sleepStartTime;
335 while (sleepSampleTime < resumeTime) {
336 time = new Date(sleepSampleTime);
337 tData.push(time.toLocaleTimeString());
338 for (var j = 0; j < plots.length; j++) {
339 plots[j].data.push(sleepText);
341 sleepSampleTime += sleepSampleInterval;
346 time = new Date(sampleTime);
347 tData.push(time.toLocaleTimeString());
348 for (var i = 0; i < plots.length; i++) {
349 plots[i].data.push(sampleArray[i]);
354 * Display the battery charge vs time on a line graph.
356 * @param {Array.<{time: number,
357 * batteryPercent: number,
358 * batteryDischargeRate: number,
359 * externalPower: number}>} powerSupplyArray An array of objects
360 * with fields representing the battery charge, time when the charge
361 * measurement was taken, and whether there was external power connected at
362 * that time.
363 * @param {Array.<{time: ?, sleepDuration: ?}>} systemResumedArray An array
364 * objects with fields 'time' and 'sleepDuration'. Each object corresponds
365 * to a system resume event. The 'time' field is for the time in
366 * milliseconds since the epoch when the system resumed. The 'sleepDuration'
367 * field is for the time in milliseconds the system spent in sleep/suspend
368 * state.
370 function showBatteryChargeData(powerSupplyArray, systemResumedArray) {
371 var chargeTimeData = [];
372 var chargePlot = [
374 color: '#0000FF',
375 data: []
378 var dischargeRateTimeData = [];
379 var dischargeRatePlot = [
381 color: '#FF0000',
382 data: []
385 var minDischargeRate = 1000; // A high unrealistic number to begin with.
386 var maxDischargeRate = -1000; // A low unrealistic number to begin with.
387 for (var i = 0; i < powerSupplyArray.length; i++) {
388 var j = Math.max(i - 1, 0);
390 addTimeDataSample(chargePlot, chargeTimeData,
391 [powerSupplyArray[i].batteryPercent],
392 powerSupplyArray[i].time,
393 powerSupplyArray[j].time,
394 systemResumedArray);
396 var dischargeRate = powerSupplyArray[i].batteryDischargeRate;
397 minDischargeRate = Math.min(dischargeRate, minDischargeRate);
398 maxDischargeRate = Math.max(dischargeRate, maxDischargeRate);
399 addTimeDataSample(dischargeRatePlot,
400 dischargeRateTimeData,
401 [dischargeRate],
402 powerSupplyArray[i].time,
403 powerSupplyArray[j].time,
404 systemResumedArray);
406 if (minDischargeRate == maxDischargeRate) {
407 // This means that all the samples had the same value. Hence, offset the
408 // extremes by a bit so that the plot looks good.
409 minDischargeRate -= 1;
410 maxDischargeRate += 1;
413 var chargeCanvas = $('battery-charge-percentage-canvas');
414 var dischargeRateCanvas = $('battery-discharge-rate-canvas');
415 plotLineGraph(chargeCanvas, chargeTimeData, chargePlot, 0.00, 100.00, 3);
416 plotLineGraph(dischargeRateCanvas,
417 dischargeRateTimeData,
418 dischargeRatePlot,
419 minDischargeRate,
420 maxDischargeRate,
424 function requestBatteryChargeData() {
425 chrome.send('requestBatteryChargeData');
428 var powerUI = {
429 showBatteryChargeData: showBatteryChargeData
432 document.addEventListener('DOMContentLoaded', function() {
433 requestBatteryChargeData();
434 $('battery-charge-reload-button').onclick = requestBatteryChargeData;