2 * Copyright (C) 2013 Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
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
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.
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.
33 * @extends {WebInspector.VBox}
34 * @param {!WebInspector.TimelineModel} model
35 * @param {!WebInspector.TimelineUIUtils} uiUtils
37 WebInspector.TimelineOverviewPane = function(model, uiUtils)
39 WebInspector.VBox.call(this);
40 this._uiUtils = uiUtils;
41 this.element.id = "timeline-overview-pane";
44 this._overviewCalculator = new WebInspector.TimelineOverviewCalculator();
46 this._overviewGrid = new WebInspector.OverviewGrid("timeline");
47 this.element.appendChild(this._overviewGrid.element);
49 model.addEventListener(WebInspector.TimelineModel.Events.RecordsCleared, this._reset, this);
50 this._overviewGrid.addEventListener(WebInspector.OverviewGrid.Events.WindowChanged, this._onWindowChanged, this);
51 this._overviewControls = [];
54 WebInspector.TimelineOverviewPane.Events = {
55 WindowChanged: "WindowChanged"
58 WebInspector.TimelineOverviewPane.prototype = {
70 * @param {!Array.<!WebInspector.TimelineOverview>} overviewControls
72 setOverviewControls: function(overviewControls)
74 for (var i = 0; i < this._overviewControls.length; ++i) {
75 var overviewControl = this._overviewControls[i];
76 overviewControl.detach();
77 overviewControl.dispose();
80 for (var i = 0; i < overviewControls.length; ++i) {
81 overviewControls[i].setOverviewGrid(this._overviewGrid);
82 overviewControls[i].show(this._overviewGrid.element);
84 this._overviewControls = overviewControls;
90 if (!this.isShowing())
93 if (this._model.isEmpty())
94 this._overviewCalculator._setWindow(0, 1000);
96 this._overviewCalculator._setWindow(this._model.minimumRecordTime(), this._model.maximumRecordTime());
98 this._overviewCalculator._setDisplayWindow(0, this._overviewGrid.clientWidth());
99 for (var i = 0; i < this._overviewControls.length; ++i)
100 this._overviewControls[i].update();
101 this._overviewGrid.updateDividers(this._overviewCalculator);
102 this._updateEventDividers();
103 this._updateWindow();
106 _updateEventDividers: function()
108 var records = this._model.eventDividerRecords();
109 this._overviewGrid.removeEventDividers();
111 for (var i = 0; i < records.length; ++i) {
112 var record = records[i];
113 var positions = this._overviewCalculator.computeBarGraphPercentages(record);
114 var dividerPosition = Math.round(positions.start * 10);
115 if (dividers[dividerPosition])
117 var title = this._uiUtils.titleForRecord(record);
118 var divider = this._uiUtils.createEventDivider(record.type(), title);
119 divider.style.left = positions.start + "%";
120 dividers[dividerPosition] = divider;
122 this._overviewGrid.addEventDividers(dividers);
127 this._overviewCalculator.reset();
128 this._overviewGrid.reset();
129 this._overviewGrid.setResizeEnabled(false);
130 this._overviewGrid.updateDividers(this._overviewCalculator);
131 for (var i = 0; i < this._overviewControls.length; ++i)
132 this._overviewControls[i].reset();
137 * @param {!WebInspector.Event} event
139 _onWindowChanged: function(event)
141 if (this._muteOnWindowChanged)
143 // Always use first control as a time converter.
144 if (!this._overviewControls.length)
146 var windowTimes = this._overviewControls[0].windowTimes(this._overviewGrid.windowLeft(), this._overviewGrid.windowRight());
147 this._windowStartTime = windowTimes.startTime;
148 this._windowEndTime = windowTimes.endTime;
149 this.dispatchEventToListeners(WebInspector.TimelineOverviewPane.Events.WindowChanged, windowTimes);
153 * @param {number} startTime
154 * @param {number} endTime
156 requestWindowTimes: function(startTime, endTime)
158 if (startTime === this._windowStartTime && endTime === this._windowEndTime)
160 this._windowStartTime = startTime;
161 this._windowEndTime = endTime;
162 this._updateWindow();
163 this.dispatchEventToListeners(WebInspector.TimelineOverviewPane.Events.WindowChanged, { startTime: startTime, endTime: endTime });
166 _updateWindow: function()
168 if (!this._overviewControls.length)
170 var windowBoundaries = this._overviewControls[0].windowBoundaries(this._windowStartTime, this._windowEndTime);
171 this._muteOnWindowChanged = true;
172 this._overviewGrid.setWindow(windowBoundaries.left, windowBoundaries.right);
173 this._overviewGrid.setResizeEnabled(!!this._model.records().length);
174 this._muteOnWindowChanged = false;
177 __proto__: WebInspector.VBox.prototype
182 * @implements {WebInspector.TimelineGrid.Calculator}
184 WebInspector.TimelineOverviewCalculator = function()
188 WebInspector.TimelineOverviewCalculator.prototype = {
192 paddingLeft: function()
194 return this._paddingLeft;
198 * @param {number} time
201 computePosition: function(time)
203 return (time - this._minimumBoundary) / this.boundarySpan() * this._workingArea + this._paddingLeft;
207 * @return {!{start: number, end: number}}
209 computeBarGraphPercentages: function(record)
211 var start = (record.startTime() - this._minimumBoundary) / this.boundarySpan() * 100;
212 var end = (record.endTime() - this._minimumBoundary) / this.boundarySpan() * 100;
213 return {start: start, end: end};
217 * @param {number=} minimumRecordTime
218 * @param {number=} maximumRecordTime
220 _setWindow: function(minimumRecordTime, maximumRecordTime)
222 this._minimumBoundary = minimumRecordTime;
223 this._maximumBoundary = maximumRecordTime;
227 * @param {number} paddingLeft
228 * @param {number} clientWidth
230 _setDisplayWindow: function(paddingLeft, clientWidth)
232 this._workingArea = clientWidth - paddingLeft;
233 this._paddingLeft = paddingLeft;
238 this._setWindow(0, 1000);
242 * @param {number} value
243 * @param {number=} precision
246 formatTime: function(value, precision)
248 return Number.preciseMillisToString(value - this.zeroTime(), precision);
254 maximumBoundary: function()
256 return this._maximumBoundary;
262 minimumBoundary: function()
264 return this._minimumBoundary;
272 return this._minimumBoundary;
278 boundarySpan: function()
280 return this._maximumBoundary - this._minimumBoundary;
287 WebInspector.TimelineOverview = function(model)
291 WebInspector.TimelineOverview.prototype = {
293 * @param {?Element} parentElement
294 * @param {!Element=} insertBefore
296 show: function(parentElement, insertBefore) { },
299 * @param {!WebInspector.OverviewGrid} grid
301 setOverviewGrid: function(grid) { },
303 update: function() { },
305 dispose: function() { },
307 reset: function() { },
310 * @param {number} windowLeft
311 * @param {number} windowRight
312 * @return {!{startTime: number, endTime: number}}
314 windowTimes: function(windowLeft, windowRight) { },
317 * @param {number} startTime
318 * @param {number} endTime
319 * @return {!{left: number, right: number}}
321 windowBoundaries: function(startTime, endTime) { },
326 * @extends {WebInspector.VBox}
327 * @implements {WebInspector.TimelineOverview}
328 * @param {!WebInspector.TimelineModel} model
330 WebInspector.TimelineOverviewBase = function(model)
332 WebInspector.VBox.call(this);
335 this._canvas = this.element.createChild("canvas", "fill");
336 this._context = this._canvas.getContext("2d");
339 WebInspector.TimelineOverviewBase.prototype = {
341 * @param {!WebInspector.OverviewGrid} grid
343 setOverviewGrid: function(grid)
360 timelineStarted: function()
364 timelineStopped: function()
369 * @param {number} windowLeft
370 * @param {number} windowRight
371 * @return {!{startTime: number, endTime: number}}
373 windowTimes: function(windowLeft, windowRight)
375 var absoluteMin = this._model.minimumRecordTime();
376 var timeSpan = this._model.maximumRecordTime() - absoluteMin;
378 startTime: absoluteMin + timeSpan * windowLeft,
379 endTime: absoluteMin + timeSpan * windowRight
384 * @param {number} startTime
385 * @param {number} endTime
386 * @return {!{left: number, right: number}}
388 windowBoundaries: function(startTime, endTime)
390 var absoluteMin = this._model.minimumRecordTime();
391 var timeSpan = this._model.maximumRecordTime() - absoluteMin;
392 var haveRecords = absoluteMin > 0;
394 left: haveRecords && startTime ? Math.min((startTime - absoluteMin) / timeSpan, 1) : 0,
395 right: haveRecords && endTime < Infinity ? (endTime - absoluteMin) / timeSpan : 1
399 resetCanvas: function()
401 this._canvas.width = this.element.clientWidth * window.devicePixelRatio;
402 this._canvas.height = this.element.clientHeight * window.devicePixelRatio;
405 __proto__: WebInspector.VBox.prototype