1 2/* 3 * Copyright (C) 2014 Apple Inc. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' 15 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 16 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS 18 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 19 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 20 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 21 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 22 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 24 * THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27WebInspector.NetworkTimelineOverviewGraph = function(recording) 28{ 29 WebInspector.TimelineOverviewGraph.call(this, recording); 30 31 this.element.classList.add(WebInspector.NetworkTimelineOverviewGraph.StyleClassName); 32 33 var networkTimeline = recording.timelines.get(WebInspector.TimelineRecord.Type.Network); 34 networkTimeline.addEventListener(WebInspector.Timeline.Event.RecordAdded, this._networkTimelineRecordAdded, this); 35 networkTimeline.addEventListener(WebInspector.Timeline.Event.TimesUpdated, this.needsLayout, this); 36 37 this.reset(); 38}; 39 40WebInspector.NetworkTimelineOverviewGraph.StyleClassName = "network"; 41WebInspector.NetworkTimelineOverviewGraph.GraphRowStyleClassName = "graph-row"; 42WebInspector.NetworkTimelineOverviewGraph.BarStyleClassName = "bar"; 43WebInspector.NetworkTimelineOverviewGraph.InactiveBarStyleClassName = "inactive"; 44WebInspector.NetworkTimelineOverviewGraph.UnfinishedStyleClassName = "unfinished"; 45WebInspector.NetworkTimelineOverviewGraph.MaximumRowCount = 6; 46 47WebInspector.NetworkTimelineOverviewGraph.prototype = { 48 constructor: WebInspector.NetworkTimelineOverviewGraph, 49 __proto__: WebInspector.TimelineOverviewGraph.prototype, 50 51 // Public 52 53 reset: function() 54 { 55 WebInspector.TimelineOverviewGraph.prototype.reset.call(this); 56 57 this._nextDumpRow = 0; 58 this._timelineRecordGridRows = []; 59 60 for (var i = 0; i < WebInspector.NetworkTimelineOverviewGraph.MaximumRowCount; ++i) 61 this._timelineRecordGridRows.push([]); 62 63 this.element.removeChildren(); 64 65 for (var rowRecords of this._timelineRecordGridRows) { 66 rowRecords.__element = document.createElement("div"); 67 rowRecords.__element.className = WebInspector.NetworkTimelineOverviewGraph.GraphRowStyleClassName; 68 this.element.appendChild(rowRecords.__element); 69 70 rowRecords.__recordBars = []; 71 } 72 }, 73 74 updateLayout: function() 75 { 76 WebInspector.TimelineOverviewGraph.prototype.updateLayout.call(this); 77 78 var secondsPerPixel = this.timelineOverview.secondsPerPixel; 79 80 var recordBarIndex = 0; 81 82 function createBar(rowElement, rowRecordBars, records, renderMode) 83 { 84 var timelineRecordBar = rowRecordBars[recordBarIndex]; 85 if (!timelineRecordBar) 86 timelineRecordBar = rowRecordBars[recordBarIndex] = new WebInspector.TimelineRecordBar(records, renderMode); 87 else { 88 timelineRecordBar.renderMode = renderMode; 89 timelineRecordBar.records = records; 90 } 91 timelineRecordBar.refresh(this); 92 if (!timelineRecordBar.element.parentNode) 93 rowElement.appendChild(timelineRecordBar.element); 94 ++recordBarIndex; 95 } 96 97 for (var rowRecords of this._timelineRecordGridRows) { 98 var rowElement = rowRecords.__element; 99 var rowRecordBars = rowRecords.__recordBars; 100 101 recordBarIndex = 0; 102 103 WebInspector.TimelineRecordBar.createCombinedBars(rowRecords, secondsPerPixel, this, createBar.bind(this, rowElement, rowRecordBars)); 104 105 // Remove the remaining unused TimelineRecordBars. 106 for (; recordBarIndex < rowRecordBars.length; ++recordBarIndex) { 107 rowRecordBars[recordBarIndex].records = null; 108 rowRecordBars[recordBarIndex].element.remove(); 109 } 110 } 111 }, 112 113 // Private 114 115 _networkTimelineRecordAdded: function(event) 116 { 117 var resourceTimelineRecord = event.data.record; 118 console.assert(resourceTimelineRecord instanceof WebInspector.ResourceTimelineRecord); 119 120 function compareByStartTime(a, b) 121 { 122 return a.startTime - b.startTime; 123 } 124 125 // Try to find a row that has room and does not overlap a previous record. 126 var foundRowForRecord = false; 127 for (var i = 0; i < this._timelineRecordGridRows.length; ++i) { 128 var rowRecords = this._timelineRecordGridRows[i]; 129 var lastRecord = rowRecords.lastValue; 130 131 if (!lastRecord || lastRecord.endTime + WebInspector.NetworkTimelineOverviewGraph.MinimumBarPaddingTime <= resourceTimelineRecord.startTime) { 132 insertObjectIntoSortedArray(resourceTimelineRecord, rowRecords, compareByStartTime); 133 this._nextDumpRow = i + 1; 134 foundRowForRecord = true; 135 break; 136 } 137 } 138 139 if (!foundRowForRecord) { 140 // Try to find a row that does not overlap a previous record's active time, but it can overlap the inactive time. 141 for (var i = 0; i < this._timelineRecordGridRows.length; ++i) { 142 var rowRecords = this._timelineRecordGridRows[i]; 143 var lastRecord = rowRecords.lastValue; 144 console.assert(lastRecord); 145 146 if (lastRecord.activeStartTime + WebInspector.NetworkTimelineOverviewGraph.MinimumBarPaddingTime <= resourceTimelineRecord.startTime) { 147 insertObjectIntoSortedArray(resourceTimelineRecord, rowRecords, compareByStartTime); 148 this._nextDumpRow = i + 1; 149 foundRowForRecord = true; 150 break; 151 } 152 } 153 } 154 155 // We didn't find a empty spot, so dump into the designated dump row. 156 if (!foundRowForRecord) { 157 if (this._nextDumpRow >= WebInspector.NetworkTimelineOverviewGraph.MaximumRowCount) 158 this._nextDumpRow = 0; 159 insertObjectIntoSortedArray(resourceTimelineRecord, this._timelineRecordGridRows[this._nextDumpRow++], compareByStartTime); 160 } 161 162 this.needsLayout(); 163 } 164}; 165