Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1574)

Side by Side Diff: Source/devtools/front_end/MemoryStatistics.js

Issue 210053002: DevTools: merge MemoryStatistics.js and CountersGraph.js, extract DOMCountersGraph.js (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Created 6 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 /*
2 * Copyright (C) 2012 Google Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 *
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
13 * distribution.
14 * * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 /**
32 * @constructor
33 * @extends {WebInspector.SplitView}
34 * @param {!WebInspector.TimelineModeViewDelegate} delegate
35 * @param {!WebInspector.TimelineModel} model
36 */
37 WebInspector.MemoryStatistics = function(delegate, model)
38 {
39 WebInspector.SplitView.call(this, true, false);
40
41 this.element.id = "memory-graphs-container";
42
43 this._delegate = delegate;
44 this._model = model;
45 this._calculator = new WebInspector.TimelineCalculator(this._model);
46
47 this._graphsContainer = this.mainElement();
48 this._createCurrentValuesBar();
49 this._canvasView = new WebInspector.VBoxWithResizeCallback(this._resize.bind (this));
50 this._canvasView.show(this._graphsContainer);
51 this._canvasContainer = this._canvasView.element;
52 this._canvasContainer.id = "memory-graphs-canvas-container";
53 this._canvas = this._canvasContainer.createChild("canvas");
54 this._canvas.id = "memory-counters-graph";
55
56 this._canvasContainer.addEventListener("mouseover", this._onMouseMove.bind(t his), true);
57 this._canvasContainer.addEventListener("mousemove", this._onMouseMove.bind(t his), true);
58 this._canvasContainer.addEventListener("mouseout", this._onMouseOut.bind(thi s), true);
59 this._canvasContainer.addEventListener("click", this._onClick.bind(this), tr ue);
60 // We create extra timeline grid here to reuse its event dividers.
61 this._timelineGrid = new WebInspector.TimelineGrid();
62 this._canvasContainer.appendChild(this._timelineGrid.dividersElement);
63
64 // Populate sidebar
65 this.sidebarElement().createChild("div", "sidebar-tree sidebar-tree-section" ).textContent = WebInspector.UIString("COUNTERS");
66 this.createAllCounters();
67 }
68
69 /**
70 * @constructor
71 * @param {string} counterName
72 */
73 WebInspector.MemoryStatistics.Counter = function(counterName)
74 {
75 this.counterName = counterName;
76 this.times = [];
77 this.values = [];
78 }
79
80 WebInspector.MemoryStatistics.Counter.prototype = {
81 /**
82 * @param {number} time
83 * @param {!TimelineAgent.Counters} counters
84 */
85 appendSample: function(time, counters)
86 {
87 var value = counters[this.counterName];
88 if (value === undefined)
89 return;
90 if (this.values.length && this.values.peekLast() === value)
91 return;
92 this.times.push(time);
93 this.values.push(value);
94 },
95
96 reset: function()
97 {
98 this.times = [];
99 this.values = [];
100 },
101
102 /**
103 * @param {!WebInspector.TimelineCalculator} calculator
104 */
105 _calculateVisibleIndexes: function(calculator)
106 {
107 var start = calculator.minimumBoundary();
108 var end = calculator.maximumBoundary();
109
110 // Maximum index of element whose time <= start.
111 this._minimumIndex = Number.constrain(this.times.upperBound(start) - 1, 0, this.times.length - 1);
112
113 // Minimum index of element whose time >= end.
114 this._maximumIndex = Number.constrain(this.times.lowerBound(end), 0, thi s.times.length - 1);
115
116 // Current window bounds.
117 this._minTime = start;
118 this._maxTime = end;
119 },
120
121 /**
122 * @param {number} width
123 */
124 _calculateXValues: function(width)
125 {
126 if (!this.values.length)
127 return;
128
129 var xFactor = width / (this._maxTime - this._minTime);
130
131 this.x = new Array(this.values.length);
132 this.x[this._minimumIndex] = 0;
133 for (var i = this._minimumIndex + 1; i < this._maximumIndex; i++)
134 this.x[i] = xFactor * (this.times[i] - this._minTime);
135 this.x[this._maximumIndex] = width;
136 }
137 }
138
139 /**
140 * @constructor
141 * @extends {WebInspector.Object}
142 */
143 WebInspector.SwatchCheckbox = function(title, color)
144 {
145 this.element = document.createElement("div");
146 this._swatch = this.element.createChild("div", "swatch");
147 this.element.createChild("span", "title").textContent = title;
148 this._color = color;
149 this.checked = true;
150
151 this.element.addEventListener("click", this._toggleCheckbox.bind(this), true );
152 }
153
154 WebInspector.SwatchCheckbox.Events = {
155 Changed: "Changed"
156 }
157
158 WebInspector.SwatchCheckbox.prototype = {
159 get checked()
160 {
161 return this._checked;
162 },
163
164 set checked(v)
165 {
166 this._checked = v;
167 if (this._checked)
168 this._swatch.style.backgroundColor = this._color;
169 else
170 this._swatch.style.backgroundColor = "";
171 },
172
173 _toggleCheckbox: function(event)
174 {
175 this.checked = !this.checked;
176 this.dispatchEventToListeners(WebInspector.SwatchCheckbox.Events.Changed );
177 },
178
179 __proto__: WebInspector.Object.prototype
180 }
181
182 /**
183 * @constructor
184 * @param {!WebInspector.MemoryStatistics} memoryCountersPane
185 * @param {string} title
186 * @param {string} graphColor
187 * @param {!WebInspector.MemoryStatistics.Counter} counter
188 */
189 WebInspector.CounterUIBase = function(memoryCountersPane, title, graphColor, cou nter)
190 {
191 this._memoryCountersPane = memoryCountersPane;
192 this.counter = counter;
193 var container = memoryCountersPane.sidebarElement().createChild("div", "memo ry-counter-sidebar-info");
194 var swatchColor = graphColor;
195 this._swatch = new WebInspector.SwatchCheckbox(WebInspector.UIString(title), swatchColor);
196 this._swatch.addEventListener(WebInspector.SwatchCheckbox.Events.Changed, th is._toggleCounterGraph.bind(this));
197 container.appendChild(this._swatch.element);
198
199 this._value = null;
200 this.graphColor = graphColor;
201 this.strokeColor = graphColor;
202 this.graphYValues = [];
203 }
204
205 WebInspector.CounterUIBase.prototype = {
206 _toggleCounterGraph: function(event)
207 {
208 this._value.classList.toggle("hidden", !this._swatch.checked);
209 this._memoryCountersPane.refresh();
210 },
211
212 /**
213 * @param {number} x
214 * @return {number}
215 */
216 _recordIndexAt: function(x)
217 {
218 return this.counter.x.upperBound(x, null, this.counter._minimumIndex + 1 , this.counter._maximumIndex + 1) - 1;
219 },
220
221 /**
222 * @param {number} x
223 */
224 updateCurrentValue: function(x)
225 {
226 if (!this.visible || !this.counter.values.length)
227 return;
228 var index = this._recordIndexAt(x);
229 this._value.textContent = WebInspector.UIString(this._currentValueLabel, this.counter.values[index]);
230 var y = this.graphYValues[index];
231 this._marker.style.left = x + "px";
232 this._marker.style.top = y + "px";
233 this._marker.classList.remove("hidden");
234 },
235
236 clearCurrentValueAndMarker: function()
237 {
238 this._value.textContent = "";
239 this._marker.classList.add("hidden");
240 },
241
242 get visible()
243 {
244 return this._swatch.checked;
245 },
246 }
247
248 WebInspector.MemoryStatistics.prototype = {
249 _createCurrentValuesBar: function()
250 {
251 throw new Error("Not implemented");
252 },
253
254 createAllCounters: function()
255 {
256 throw new Error("Not implemented");
257 },
258
259 /**
260 * @param {!WebInspector.TimelineModel.Record} record
261 */
262 addRecord: function(record)
263 {
264 throw new Error("Not implemented");
265 },
266
267 reset: function()
268 {
269 for (var i = 0; i < this._counters.length; ++i)
270 this._counters[i].reset();
271
272 for (var i = 0; i < this._counterUI.length; ++i)
273 this._counterUI[i].reset();
274
275 this.refresh();
276 },
277
278 _resize: function()
279 {
280 var parentElement = this._canvas.parentElement;
281 this._canvas.width = parentElement.clientWidth;
282 this._canvas.height = parentElement.clientHeight;
283 var timelinePaddingLeft = 15;
284 this._calculator.setDisplayWindow(timelinePaddingLeft, this._canvas.widt h);
285 this.refresh();
286 },
287
288 /**
289 * @param {number} startTime
290 * @param {number} endTime
291 */
292 setWindowTimes: function(startTime, endTime)
293 {
294 this._calculator.setWindow(startTime, endTime);
295 this.scheduleRefresh();
296 },
297
298 scheduleRefresh: function()
299 {
300 if (this._refreshTimer)
301 return;
302 this._refreshTimer = setTimeout(this.refresh.bind(this), 300);
303 },
304
305 draw: function()
306 {
307 for (var i = 0; i < this._counters.length; ++i) {
308 this._counters[i]._calculateVisibleIndexes(this._calculator);
309 this._counters[i]._calculateXValues(this._canvas.width);
310 }
311 this._clear();
312 this._setVerticalClip(10, this._canvas.height - 20);
313 },
314
315 /**
316 * @param {?Event} event
317 */
318 _onClick: function(event)
319 {
320 var x = event.x - this._canvasContainer.totalOffsetLeft();
321 var minDistance = Infinity;
322 var bestTime;
323 for (var i = 0; i < this._counterUI.length; ++i) {
324 var counterUI = this._counterUI[i];
325 if (!counterUI.counter.times.length)
326 continue;
327 var index = counterUI._recordIndexAt(x);
328 var distance = Math.abs(x - counterUI.counter.x[index]);
329 if (distance < minDistance) {
330 minDistance = distance;
331 bestTime = counterUI.counter.times[index];
332 }
333 }
334 if (bestTime !== undefined)
335 this._revealRecordAt(bestTime);
336 },
337
338 /**
339 * @param {number} time
340 */
341 _revealRecordAt: function(time)
342 {
343 var recordToReveal;
344 function findRecordToReveal(record)
345 {
346 if (record.startTime <= time && time <= record.endTime) {
347 recordToReveal = record;
348 return true;
349 }
350 // If there is no record containing the time than use the latest one before that time.
351 if (!recordToReveal || record.endTime < time && recordToReveal.endTi me < record.endTime)
352 recordToReveal = record;
353 return false;
354 }
355 this._model.forAllRecords(null, findRecordToReveal);
356 this._delegate.selectRecord(recordToReveal);
357 },
358
359 /**
360 * @param {?Event} event
361 */
362 _onMouseOut: function(event)
363 {
364 delete this._markerXPosition;
365 this._clearCurrentValueAndMarker();
366 },
367
368 _clearCurrentValueAndMarker: function()
369 {
370 for (var i = 0; i < this._counterUI.length; i++)
371 this._counterUI[i].clearCurrentValueAndMarker();
372 },
373
374 /**
375 * @param {?Event} event
376 */
377 _onMouseMove: function(event)
378 {
379 var x = event.x - this._canvasContainer.totalOffsetLeft();
380 this._markerXPosition = x;
381 this._refreshCurrentValues();
382 },
383
384 _refreshCurrentValues: function()
385 {
386 if (this._markerXPosition === undefined)
387 return;
388 for (var i = 0; i < this._counterUI.length; ++i)
389 this._counterUI[i].updateCurrentValue(this._markerXPosition);
390 },
391
392 refresh: function()
393 {
394 delete this._refreshTimer;
395 this._timelineGrid.updateDividers(this._calculator);
396 this.draw();
397 this._refreshCurrentValues();
398 },
399
400 refreshRecords: function()
401 {
402 this.reset();
403 var records = this._model.records();
404 for (var i = 0; i < records.length; ++i)
405 this.addRecord(records[i]);
406 },
407
408 /**
409 * @param {number} originY
410 * @param {number} height
411 */
412 _setVerticalClip: function(originY, height)
413 {
414 this._originY = originY;
415 this._clippedHeight = height;
416 },
417
418 _clear: function()
419 {
420 var ctx = this._canvas.getContext("2d");
421 ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
422 },
423
424 /**
425 * @param {?WebInspector.TimelineModel.Record} record
426 * @param {string=} regex
427 * @param {boolean=} selectRecord
428 */
429 highlightSearchResult: function(record, regex, selectRecord)
430 {
431 },
432
433 /**
434 * @param {?WebInspector.TimelineModel.Record} record
435 */
436 setSelectedRecord: function(record)
437 {
438 },
439
440 __proto__: WebInspector.SplitView.prototype
441 }
OLDNEW
« no previous file with comments | « Source/devtools/front_end/DOMCountersGraph.js ('k') | Source/devtools/front_end/TimelineOverviewPane.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698