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

Side by Side Diff: third_party/WebKit/Source/devtools/front_end/timeline/TimelineNetworkFlameChart.js

Issue 2785533002: DevTools: Show event initiator on Flame Chart for selected entries (Closed)
Patch Set: sort experiments Created 3 years, 8 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 // Copyright 2016 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 * @implements {PerfUI.FlameChartDataProvider}
7 * @unrestricted
8 */
9 Timeline.TimelineFlameChartNetworkDataProvider = class {
10 constructor() {
11 this._font = '11px ' + Host.fontFamily();
12 this.setModel(null);
13 this._style = {
14 padding: 4,
15 height: 17,
16 collapsible: true,
17 color: UI.themeSupport.patchColor('#222', UI.ThemeSupport.ColorUsage.Foreg round),
18 font: this._font,
19 backgroundColor: UI.themeSupport.patchColor('white', UI.ThemeSupport.Color Usage.Background),
20 nestingLevel: 0,
21 useFirstLineForOverview: false,
22 useDecoratorsForOverview: true,
23 shareHeaderLine: false
24 };
25 this._group = {startLevel: 0, name: Common.UIString('Network'), expanded: fa lse, style: this._style};
26 }
27
28 /**
29 * @param {?Timeline.PerformanceModel} performanceModel
30 */
31 setModel(performanceModel) {
32 this._model = performanceModel && performanceModel.timelineModel();
33 this._maxLevel = 0;
34 this._timelineData = null;
35 /** @type {!Array<!TimelineModel.TimelineModel.NetworkRequest>} */
36 this._requests = [];
37 }
38
39 /**
40 * @return {boolean}
41 */
42 isEmpty() {
43 this.timelineData();
44 return !this._requests.length;
45 }
46
47 /**
48 * @override
49 * @return {number}
50 */
51 maxStackDepth() {
52 return this._maxLevel;
53 }
54
55 /**
56 * @override
57 * @return {!PerfUI.FlameChart.TimelineData}
58 */
59 timelineData() {
60 if (this._timelineData)
61 return this._timelineData;
62 /** @type {!Array<!TimelineModel.TimelineModel.NetworkRequest>} */
63 this._requests = [];
64 this._timelineData = new PerfUI.FlameChart.TimelineData([], [], [], []);
65 if (this._model)
66 this._appendTimelineData(this._model.mainThreadEvents());
67 return this._timelineData;
68 }
69
70 /**
71 * @override
72 * @return {number}
73 */
74 minimumBoundary() {
75 return this._minimumBoundary;
76 }
77
78 /**
79 * @override
80 * @return {number}
81 */
82 totalTime() {
83 return this._timeSpan;
84 }
85
86 /**
87 * @param {number} startTime
88 * @param {number} endTime
89 */
90 setWindowTimes(startTime, endTime) {
91 this._startTime = startTime;
92 this._endTime = endTime;
93 this._updateTimelineData();
94 }
95
96 /**
97 * @param {number} index
98 * @return {?Timeline.TimelineSelection}
99 */
100 createSelection(index) {
101 if (index === -1)
102 return null;
103 var request = this._requests[index];
104 this._lastSelection =
105 new Timeline.TimelineFlameChartView.Selection(Timeline.TimelineSelection .fromNetworkRequest(request), index);
106 return this._lastSelection.timelineSelection;
107 }
108
109 /**
110 * @param {?Timeline.TimelineSelection} selection
111 * @return {number}
112 */
113 entryIndexForSelection(selection) {
114 if (!selection)
115 return -1;
116
117 if (this._lastSelection && this._lastSelection.timelineSelection.object() == = selection.object())
118 return this._lastSelection.entryIndex;
119
120 if (selection.type() !== Timeline.TimelineSelection.Type.NetworkRequest)
121 return -1;
122 var request = /** @type{!TimelineModel.TimelineModel.NetworkRequest} */ (sel ection.object());
123 var index = this._requests.indexOf(request);
124 if (index !== -1) {
125 this._lastSelection =
126 new Timeline.TimelineFlameChartView.Selection(Timeline.TimelineSelecti on.fromNetworkRequest(request), index);
127 }
128 return index;
129 }
130
131 /**
132 * @override
133 * @param {number} index
134 * @return {string}
135 */
136 entryColor(index) {
137 var request = /** @type {!TimelineModel.TimelineModel.NetworkRequest} */ (th is._requests[index]);
138 var category = Timeline.TimelineUIUtils.networkRequestCategory(request);
139 return Timeline.TimelineUIUtils.networkCategoryColor(category);
140 }
141
142 /**
143 * @override
144 * @param {number} index
145 * @return {string}
146 */
147 textColor(index) {
148 return Timeline.FlameChartStyle.textColor;
149 }
150
151 /**
152 * @override
153 * @param {number} index
154 * @return {?string}
155 */
156 entryTitle(index) {
157 var request = /** @type {!TimelineModel.TimelineModel.NetworkRequest} */ (th is._requests[index]);
158 var parsedURL = new Common.ParsedURL(request.url || '');
159 return parsedURL.isValid ? `${parsedURL.displayName} (${parsedURL.host})` : request.url || null;
160 }
161
162 /**
163 * @override
164 * @param {number} index
165 * @return {?string}
166 */
167 entryFont(index) {
168 return this._font;
169 }
170
171 /**
172 * @override
173 * @param {number} index
174 * @param {!CanvasRenderingContext2D} context
175 * @param {?string} text
176 * @param {number} barX
177 * @param {number} barY
178 * @param {number} barWidth
179 * @param {number} barHeight
180 * @param {number} unclippedBarX
181 * @param {number} timeToPixelRatio
182 * @return {boolean}
183 */
184 decorateEntry(index, context, text, barX, barY, barWidth, barHeight, unclipped BarX, timeToPixelRatio) {
185 var request = /** @type {!TimelineModel.TimelineModel.NetworkRequest} */ (th is._requests[index]);
186 if (!request.timing)
187 return false;
188
189 /**
190 * @param {number} time
191 * @return {number}
192 */
193 function timeToPixel(time) {
194 return Math.floor(unclippedBarX + (time - startTime) * timeToPixelRatio);
195 }
196
197 var /** @const */ minBarWidthPx = 2;
198 var startTime = request.startTime;
199 var endTime = request.endTime;
200 var requestTime = request.timing.requestTime * 1000;
201 var sendStart = Math.max(timeToPixel(requestTime + request.timing.sendStart) , unclippedBarX);
202 var headersEnd = Math.max(timeToPixel(requestTime + request.timing.receiveHe adersEnd), sendStart);
203 var finish = Math.max(timeToPixel(request.finishTime || endTime), headersEnd + minBarWidthPx);
204 var end = Math.max(timeToPixel(endTime), finish);
205
206 context.fillStyle = 'hsla(0, 100%, 100%, 0.8)';
207 context.fillRect(sendStart + 0.5, barY + 0.5, headersEnd - sendStart - 0.5, barHeight - 2);
208 context.fillStyle = UI.themeSupport.patchColor('white', UI.ThemeSupport.Colo rUsage.Background);
209 context.fillRect(barX, barY - 0.5, sendStart - barX, barHeight);
210 context.fillRect(finish, barY - 0.5, barX + barWidth - finish, barHeight);
211
212 /**
213 * @param {number} begin
214 * @param {number} end
215 * @param {number} y
216 */
217 function drawTick(begin, end, y) {
218 var /** @const */ tickHeightPx = 6;
219 context.moveTo(begin, y - tickHeightPx / 2);
220 context.lineTo(begin, y + tickHeightPx / 2);
221 context.moveTo(begin, y);
222 context.lineTo(end, y);
223 }
224
225 context.lineWidth = 1;
226 context.strokeStyle = '#ccc';
227 var lineY = Math.floor(barY + barHeight / 2) + 0.5;
228 var leftTick = Math.floor(unclippedBarX) + 0.5;
229 var rightTick = end - 0.5;
230 drawTick(leftTick, sendStart, lineY);
231 drawTick(rightTick, finish, lineY);
232 context.stroke();
233
234 if (typeof request.priority === 'string') {
235 var color = this._colorForPriority(request.priority);
236 if (color) {
237 context.fillStyle = color;
238 context.fillRect(sendStart + 0.5, barY + 0.5, 3.5, 3.5);
239 }
240 }
241
242 var textStart = Math.max(sendStart, 0);
243 var textWidth = finish - textStart;
244 var /** @const */ minTextWidthPx = 20;
245 if (textWidth >= minTextWidthPx) {
246 text = this.entryTitle(index) || '';
247 if (request.fromServiceWorker)
248 text = '⚙ ' + text;
249 if (text) {
250 var /** @const */ textPadding = 4;
251 var /** @const */ textBaseline = 5;
252 var textBaseHeight = barHeight - textBaseline;
253 var trimmedText = UI.trimTextEnd(context, text, textWidth - 2 * textPadd ing);
254 context.fillStyle = '#333';
255 context.fillText(trimmedText, textStart + textPadding, barY + textBaseHe ight);
256 }
257 }
258
259 return true;
260 }
261
262 /**
263 * @override
264 * @param {number} index
265 * @return {boolean}
266 */
267 forceDecoration(index) {
268 return true;
269 }
270
271 /**
272 * @override
273 * @param {number} index
274 * @return {?Element}
275 */
276 prepareHighlightedEntryInfo(index) {
277 var /** @const */ maxURLChars = 80;
278 var request = /** @type {!TimelineModel.TimelineModel.NetworkRequest} */ (th is._requests[index]);
279 if (!request.url)
280 return null;
281 var element = createElement('div');
282 var root = UI.createShadowRootWithCoreStyles(element, 'timeline/timelineFlam echartPopover.css');
283 var contents = root.createChild('div', 'timeline-flamechart-popover');
284 var duration = request.endTime - request.startTime;
285 if (request.startTime && isFinite(duration))
286 contents.createChild('span', 'timeline-info-network-time').textContent = N umber.millisToString(duration);
287 if (typeof request.priority === 'string') {
288 var div = contents.createChild('span');
289 div.textContent =
290 NetworkConditions.uiLabelForPriority(/** @type {!Protocol.Network.Reso urcePriority} */ (request.priority));
291 div.style.color = this._colorForPriority(request.priority) || 'black';
292 }
293 contents.createChild('span').textContent = request.url.trimMiddle(maxURLChar s);
294 return element;
295 }
296
297 /**
298 * @override
299 * @param {number} entryIndex
300 */
301 highlightEntry(entryIndex) {
302 }
303
304 /**
305 * @param {string} priority
306 * @return {?string}
307 */
308 _colorForPriority(priority) {
309 if (!this._priorityToValue) {
310 var priorities = Protocol.Network.ResourcePriority;
311 this._priorityToValue = new Map([
312 [priorities.VeryLow, 1], [priorities.Low, 2], [priorities.Medium, 3], [p riorities.High, 4],
313 [priorities.VeryHigh, 5]
314 ]);
315 }
316 var value = this._priorityToValue.get(priority);
317 return value ? `hsla(214, 80%, 50%, ${value / 5})` : null;
318 }
319
320 /**
321 * @param {!Array.<!SDK.TracingModel.Event>} events
322 */
323 _appendTimelineData(events) {
324 this._minimumBoundary = this._model.minimumRecordTime();
325 this._maximumBoundary = this._model.maximumRecordTime();
326 this._timeSpan = this._model.isEmpty() ? 1000 : this._maximumBoundary - this ._minimumBoundary;
327 this._model.networkRequests().forEach(this._appendEntry.bind(this));
328 this._updateTimelineData();
329 }
330
331 _updateTimelineData() {
332 if (!this._timelineData)
333 return;
334 var lastTimeByLevel = [];
335 var maxLevel = 0;
336 for (var i = 0; i < this._requests.length; ++i) {
337 var r = this._requests[i];
338 var visible = r.startTime < this._endTime && r.endTime > this._startTime;
339 if (!visible) {
340 this._timelineData.entryLevels[i] = -1;
341 continue;
342 }
343 while (lastTimeByLevel.length && lastTimeByLevel.peekLast() <= r.startTime )
344 lastTimeByLevel.pop();
345 this._timelineData.entryLevels[i] = lastTimeByLevel.length;
346 lastTimeByLevel.push(r.endTime);
347 maxLevel = Math.max(maxLevel, lastTimeByLevel.length);
348 }
349 for (var i = 0; i < this._requests.length; ++i) {
350 if (this._timelineData.entryLevels[i] === -1)
351 this._timelineData.entryLevels[i] = maxLevel;
352 }
353 this._timelineData = new PerfUI.FlameChart.TimelineData(
354 this._timelineData.entryLevels, this._timelineData.entryTotalTimes, this ._timelineData.entryStartTimes,
355 [this._group]);
356 this._maxLevel = maxLevel;
357 }
358
359
360 /**
361 * @param {!TimelineModel.TimelineModel.NetworkRequest} request
362 */
363 _appendEntry(request) {
364 this._requests.push(request);
365 this._timelineData.entryStartTimes.push(request.startTime);
366 this._timelineData.entryTotalTimes.push(request.endTime - request.startTime) ;
367 this._timelineData.entryLevels.push(this._requests.length - 1);
368 }
369
370 /**
371 * @return {number}
372 */
373 preferredHeight() {
374 return this._style.height * (this._group.expanded ? Number.constrain(this._m axLevel + 1, 4, 8.5) : 1);
375 }
376
377 /**
378 * @return {boolean}
379 */
380 isExpanded() {
381 return this._group.expanded;
382 }
383
384 /**
385 * @override
386 * @param {number} value
387 * @param {number=} precision
388 * @return {string}
389 */
390 formatValue(value, precision) {
391 return Number.preciseMillisToString(value, precision);
392 }
393
394 /**
395 * @override
396 * @param {number} entryIndex
397 * @return {boolean}
398 */
399 canJumpToEntry(entryIndex) {
400 return false;
401 }
402 };
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698