Changeset 203843 in webkit


Ignore:
Timestamp:
Jul 28, 2016 2:38:50 PM (8 years ago)
Author:
commit-queue@webkit.org
Message:

Web Inspector: Waterfall view should be visible in Network tab and Network Timeline
https://bugs.webkit.org/show_bug.cgi?id=160061

Patch by Johan K. Jensen <johan_jensen@apple.com> on 2016-07-28
Reviewed by Joseph Pecoraro.

Adds a Timeline-column (waterfall) to the Network tab and Network Timeline.

  • Localizations/en.lproj/localizedStrings.js:

Add "Timeline" localized string.

  • UserInterface/Views/NetworkGridContentView.js:

(WebInspector.NetworkGridContentView):
Add the Timeline-column with a TimelineRuler as the headerview,
and properties for updating current time.

(WebInspector.NetworkGridContentView.prototype.get secondsPerPixel):
(WebInspector.NetworkGridContentView.prototype.get startTime):
(WebInspector.NetworkGridContentView.prototype.get currentTime):
(WebInspector.NetworkGridContentView.prototype.get endTime):
Acting as a graphDataSource used by TimelineDataGridNode.

(WebInspector.NetworkGridContentView.prototype.shown):
(WebInspector.NetworkGridContentView.prototype.reset):
(WebInspector.NetworkGridContentView.prototype.layout):
Refresh graphs and update the TimelineRuler on layout changes.

(WebInspector.NetworkGridContentView.prototype._networkTimelineRecordAdded):
Add listeners for when resources are finished to stop the timer.

(WebInspector.NetworkGridContentView.prototype._update):
(WebInspector.NetworkGridContentView.prototype._startUpdatingCurrentTime):
(WebInspector.NetworkGridContentView.prototype._stopUpdatingCurrentTime):
Adding a timer which updates the TimelineRuler and the layout
if any non-finished requests are running.

  • UserInterface/Views/NetworkTimelineView.js:

(WebInspector.NetworkTimelineView):
Add the Timeline-column with a TimelineRuler as the headerview.

(WebInspector.NetworkTimelineView.prototype.get secondsPerPixel):
(WebInspector.NetworkTimelineView.prototype.layout):
Refresh graphs on layout changes.

  • UserInterface/Views/TimelineDataGrid.css:

(.tree-outline.timeline-data-grid .item:hover .subtitle):
(.data-grid.timeline th):
(.data-grid.timeline th.graph-column > .timeline-ruler):
(.data-grid.timeline td.graph-column):
(.data-grid.timeline td.graph-column > .cell-content):
(.data-grid.timeline td.graph-column .timeline-record-bar):

Location:
trunk/Source/WebInspectorUI
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebInspectorUI/ChangeLog

    r203840 r203843  
     12016-07-28  Johan K. Jensen  <johan_jensen@apple.com>
     2
     3        Web Inspector: Waterfall view should be visible in Network tab and Network Timeline
     4        https://bugs.webkit.org/show_bug.cgi?id=160061
     5
     6        Reviewed by Joseph Pecoraro.
     7
     8        Adds a Timeline-column (waterfall) to the Network tab and Network Timeline.
     9
     10        * Localizations/en.lproj/localizedStrings.js:
     11        Add "Timeline" localized string.
     12
     13        * UserInterface/Views/NetworkGridContentView.js:
     14        (WebInspector.NetworkGridContentView):
     15        Add the Timeline-column with a TimelineRuler as the headerview,
     16        and properties for updating current time.
     17
     18        (WebInspector.NetworkGridContentView.prototype.get secondsPerPixel):
     19        (WebInspector.NetworkGridContentView.prototype.get startTime):
     20        (WebInspector.NetworkGridContentView.prototype.get currentTime):
     21        (WebInspector.NetworkGridContentView.prototype.get endTime):
     22        Acting as a graphDataSource used by TimelineDataGridNode.
     23
     24        (WebInspector.NetworkGridContentView.prototype.shown):
     25        (WebInspector.NetworkGridContentView.prototype.reset):
     26        (WebInspector.NetworkGridContentView.prototype.layout):
     27        Refresh graphs and update the TimelineRuler on layout changes.
     28
     29        (WebInspector.NetworkGridContentView.prototype._networkTimelineRecordAdded):
     30        Add listeners for when resources are finished to stop the timer.
     31
     32        (WebInspector.NetworkGridContentView.prototype._update):
     33        (WebInspector.NetworkGridContentView.prototype._startUpdatingCurrentTime):
     34        (WebInspector.NetworkGridContentView.prototype._stopUpdatingCurrentTime):
     35        Adding a timer which updates the TimelineRuler and the layout
     36        if any non-finished requests are running.
     37
     38        * UserInterface/Views/NetworkTimelineView.js:
     39        (WebInspector.NetworkTimelineView):
     40        Add the Timeline-column with a TimelineRuler as the headerview.
     41
     42        (WebInspector.NetworkTimelineView.prototype.get secondsPerPixel):
     43        (WebInspector.NetworkTimelineView.prototype.layout):
     44        Refresh graphs on layout changes.
     45
     46        * UserInterface/Views/TimelineDataGrid.css:
     47        (.tree-outline.timeline-data-grid .item:hover .subtitle):
     48        (.data-grid.timeline th):
     49        (.data-grid.timeline th.graph-column > .timeline-ruler):
     50        (.data-grid.timeline td.graph-column):
     51        (.data-grid.timeline td.graph-column > .cell-content):
     52        (.data-grid.timeline td.graph-column .timeline-record-bar):
     53
    1542016-07-28  Chris Dumez  <cdumez@apple.com>
    255
  • trunk/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js

    r203132 r203843  
    707707localizedStrings["Time"] = "Time";
    708708localizedStrings["Time until the load event fired, click to show the Network Requests timeline"] = "Time until the load event fired, click to show the Network Requests timeline";
     709localizedStrings["Timeline"] = "Timeline";
    709710localizedStrings["Timeline Recording %d"] = "Timeline Recording %d";
    710711localizedStrings["Timelines"] = "Timelines";
  • trunk/Source/WebInspectorUI/UserInterface/Views/NetworkGridContentView.js

    r202133 r203843  
    3838        this._contentTreeOutline.addEventListener(WebInspector.TreeOutline.Event.SelectionDidChange, this._treeSelectionDidChange, this);
    3939
    40         var columns = {domain: {}, type: {}, method: {}, scheme: {}, statusCode: {}, cached: {}, size: {}, transferSize: {}, requestSent: {}, latency: {}, duration: {}};
     40        var columns = {domain: {}, type: {}, method: {}, scheme: {}, statusCode: {}, cached: {}, size: {}, transferSize: {}, requestSent: {}, latency: {}, duration: {}, graph: {}};
    4141
    4242        columns.domain.title = WebInspector.UIString("Domain");
     
    8080        for (var column in columns)
    8181            columns[column].sortable = true;
     82
     83        this._timelineRuler = new WebInspector.TimelineRuler;
     84        this._timelineRuler.allowsClippedLabels = true;
     85
     86        columns.graph.title = WebInspector.UIString("Timeline");
     87        columns.graph.width = "15%";
     88        columns.graph.headerView = this._timelineRuler;
     89        columns.graph.sortable = false;
    8290
    8391        this._dataGrid = new WebInspector.TimelineDataGrid(columns, this._contentTreeOutline);
     
    98106
    99107        this._pendingRecords = [];
     108        this._loadingResourceCount = 0;
     109        this._lastUpdateTimestamp = NaN;
     110        this._scheduledCurrentTimeUpdateIdentifier = undefined;
    100111    }
    101112
    102113    // Public
     114
     115    get secondsPerPixel() { return this._timelineRuler.secondsPerPixel; }
     116    get startTime() { return this._timelineRuler.startTime; }
     117    get currentTime() { return this.endTime || this.startTime; }
     118    get endTime() { return this._timelineRuler.endTime; }
    103119
    104120    get selectionPathComponents()
     
    127143
    128144        this._dataGrid.shown();
     145
     146        if (this._loadingResourceCount && !this._scheduledCurrentTimeUpdateIdentifier)
     147            this._startUpdatingCurrentTime();
    129148    }
    130149
     
    145164        this._contentTreeOutline.removeChildren();
    146165        this._dataGrid.reset();
     166
     167        if (this._scheduledCurrentTimeUpdateIdentifier)
     168            this._stopUpdatingCurrentTime();
     169
     170        this._loadingResourceCount = 0;
     171        this._lastUpdateTimestamp = NaN;
     172
     173        this._timelineRuler.startTime = 0;
     174        this._timelineRuler.endTime = 0;
    147175    }
    148176
     
    151179    layout()
    152180    {
     181        this._timelineRuler.zeroTime = this.zeroTime;
     182        this._timelineRuler.startTime = this.zeroTime;
     183
     184        for (let dataGridNode of this._dataGrid.children)
     185            dataGridNode.refreshGraph();
     186
    153187        this._processPendingRecords();
    154188    }
     
    186220        console.assert(resourceTimelineRecord instanceof WebInspector.ResourceTimelineRecord);
    187221
     222        let update = (event) => {
     223            if (event.target[WebInspector.NetworkGridContentView.ResourceDidFinishOrFail])
     224                return;
     225
     226            event.target.removeEventListener(null, null, this);
     227            event.target[WebInspector.NetworkGridContentView.ResourceDidFinishOrFail] = true;
     228
     229            this._loadingResourceCount--;
     230            if (this._loadingResourceCount)
     231                return;
     232
     233            this.debounce(250)._stopUpdatingCurrentTime();
     234        };
     235
    188236        this._pendingRecords.push(resourceTimelineRecord);
    189237
    190238        this.needsLayout();
     239
     240        let resource = resourceTimelineRecord.resource;
     241        if (resource.finished || resource.failed || resource.canceled)
     242            return;
     243
     244        resource[WebInspector.NetworkGridContentView.ResourceDidFinishOrFail] = false;
     245        resource.addEventListener(WebInspector.Resource.Event.LoadingDidFinish, update, this);
     246        resource.addEventListener(WebInspector.Resource.Event.LoadingDidFail, update, this);
     247
     248        this._loadingResourceCount++;
     249        if (this._loadingResourceCount && !this._scheduledCurrentTimeUpdateIdentifier)
     250            this._startUpdatingCurrentTime();
    191251    }
    192252
     
    223283        this.reset();
    224284    }
     285
     286    _update(timestamp)
     287    {
     288        console.assert(this._scheduledCurrentTimeUpdateIdentifier);
     289
     290        let startTime = this.startTime;
     291        let currentTime = this.currentTime;
     292        let endTime = this.endTime;
     293        let timespanSinceLastUpdate = (timestamp - this._lastUpdateTimestamp) / 1000 || 0;
     294
     295        currentTime += timespanSinceLastUpdate;
     296
     297        this._timelineRuler.endTime = currentTime;
     298        this._lastUpdateTimestamp = timestamp;
     299        this.updateLayout();
     300
     301        this._scheduledCurrentTimeUpdateIdentifier = requestAnimationFrame(this._updateCallback);
     302    }
     303
     304    _startUpdatingCurrentTime()
     305    {
     306        console.assert(!this._scheduledCurrentTimeUpdateIdentifier);
     307        if (this._scheduledCurrentTimeUpdateIdentifier)
     308            return;
     309
     310        // Don't update the current time if the Inspector is not visible, as the requestAnimationFrames won't work.
     311        if (!WebInspector.visible)
     312            return;
     313
     314        if (!this._updateCallback)
     315            this._updateCallback = this._update.bind(this);
     316
     317        this._scheduledCurrentTimeUpdateIdentifier = requestAnimationFrame(this._updateCallback);
     318    }
     319
     320    _stopUpdatingCurrentTime()
     321    {
     322        console.assert(this._scheduledCurrentTimeUpdateIdentifier);
     323        if (!this._scheduledCurrentTimeUpdateIdentifier)
     324            return;
     325
     326        cancelAnimationFrame(this._scheduledCurrentTimeUpdateIdentifier);
     327        this._scheduledCurrentTimeUpdateIdentifier = undefined;
     328    }
    225329};
     330
     331WebInspector.NetworkGridContentView.ResourceDidFinishOrFail = Symbol("ResourceDidFinishOrFail");
  • trunk/Source/WebInspectorUI/UserInterface/Views/NetworkTimelineView.js

    r202133 r203843  
    3232        console.assert(timeline.type === WebInspector.TimelineRecord.Type.Network);
    3333
    34         let columns = {name: {}, domain: {}, type: {}, method: {}, scheme: {}, statusCode: {}, cached: {}, size: {}, transferSize: {}, requestSent: {}, latency: {}, duration: {}};
     34        let columns = {name: {}, domain: {}, type: {}, method: {}, scheme: {}, statusCode: {}, cached: {}, size: {}, transferSize: {}, requestSent: {}, latency: {}, duration: {}, graph: {}};
    3535
    3636        columns.name.title = WebInspector.UIString("Name");
     
    4040
    4141        columns.domain.title = WebInspector.UIString("Domain");
    42         columns.domain.width = "10%";
     42        columns.domain.width = "8%";
    4343
    4444        columns.type.title = WebInspector.UIString("Type");
    45         columns.type.width = "8%";
     45        columns.type.width = "7%";
    4646
    4747        var typeToLabelMap = new Map;
     
    5555
    5656        columns.method.title = WebInspector.UIString("Method");
    57         columns.method.width = "6%";
     57        columns.method.width = "4%";
    5858
    5959        columns.scheme.title = WebInspector.UIString("Scheme");
    60         columns.scheme.width = "6%";
     60        columns.scheme.width = "4%";
    6161
    6262        columns.statusCode.title = WebInspector.UIString("Status");
    63         columns.statusCode.width = "6%";
     63        columns.statusCode.width = "4%";
    6464
    6565        columns.cached.title = WebInspector.UIString("Cached");
    66         columns.cached.width = "6%";
     66        columns.cached.width = "4%";
    6767
    6868        columns.size.title = WebInspector.UIString("Size");
     
    8888        for (var column in columns)
    8989            columns[column].sortable = true;
     90
     91        this._timelineRuler = new WebInspector.TimelineRuler;
     92        this._timelineRuler.allowsClippedLabels = true;
     93
     94        columns.graph.title = WebInspector.UIString("Timeline");
     95        columns.graph.width = "15%";
     96        columns.graph.headerView = this._timelineRuler;
     97        columns.graph.sortable = false;
    9098
    9199        this._dataGrid = new WebInspector.TimelineDataGrid(columns);
     
    108116    // Public
    109117
     118    get secondsPerPixel() { return this._timelineRuler.secondsPerPixel; }
     119
    110120    get selectionPathComponents()
    111121    {
     
    198208    layout()
    199209    {
     210        this.endTime = Math.min(this.endTime, this.currentTime);
     211
     212        this._timelineRuler.zeroTime = this.zeroTime;
     213        this._timelineRuler.startTime = this.startTime;
     214        this._timelineRuler.endTime = this.endTime;
     215
     216        for (let dataGridNode of this._resourceDataGridNodeMap.values())
     217            dataGridNode.refreshGraph();
     218
    200219        this._processPendingRecords();
    201220    }
  • trunk/Source/WebInspectorUI/UserInterface/Views/TimelineDataGrid.css

    r201538 r203843  
    3737    color: white;
    3838}
     39
     40.data-grid.timeline th {
     41    border-top: none;
     42}
     43
     44.data-grid.timeline th.graph-column > .timeline-ruler {
     45    position: absolute;
     46    top: 0;
     47    bottom: 0;
     48}
     49
     50.data-grid.timeline td.graph-column {
     51    padding: 2px 0;
     52}
     53
     54.data-grid.timeline td.graph-column > .cell-content {
     55    position: relative;
     56}
     57
     58.data-grid.timeline td.graph-column .timeline-record-bar {
     59    top: 2px;
     60}
Note: See TracChangeset for help on using the changeset viewer.