Commit 594b2d9a authored by timothy@apple.com's avatar timothy@apple.com

Implement basic versions of the TimelineOverview graphs.

https://bugs.webkit.org/show_bug.cgi?id=127184

Reviewed by Joseph Pecoraro.

* UserInterface/LayoutTimelineOverviewGraph.css: Added.
(.timeline-overview-graph.layout > .timeline-record-bar):
(.timeline-overview-graph.layout > .timeline-record-bar > .segment):

* UserInterface/LayoutTimelineOverviewGraph.js: Added.
(WebInspector.LayoutTimelineOverviewGraph.prototype.reset):
(WebInspector.LayoutTimelineOverviewGraph.prototype.updateLayout):
(WebInspector.LayoutTimelineOverviewGraph.prototype._layoutTimelineRecordAdded):

* UserInterface/Main.html: Added new files.

* UserInterface/NetworkTimelineOverviewGraph.css: Added.
(.timeline-overview-graph.network):
(.timeline-overview-graph.network > .graph-row):
(.timeline-overview-graph.network > .graph-row > .bar):
(.timeline-overview-graph.network > .graph-row > .bar.inactive):
(.timeline-overview-graph.network > .graph-row > .bar.unfinished):
(.timeline-overview-graph.network > .graph-row > .bar:not(.inactive)):
(.timeline-overview-graph.network:nth-child(even) > .graph-row > .bar:not(.inactive)):

* UserInterface/NetworkTimelineOverviewGraph.js: Added.
(WebInspector.NetworkTimelineOverviewGraph.prototype.reset):
(WebInspector.NetworkTimelineOverviewGraph.prototype.updateLayout.updateElementPosition):
(WebInspector.NetworkTimelineOverviewGraph.prototype.updateLayout.createBar):
(WebInspector.NetworkTimelineOverviewGraph.prototype.updateLayout):
(WebInspector.NetworkTimelineOverviewGraph.prototype._networkTimelineRecordAdded.compareByStartTime):
(WebInspector.NetworkTimelineOverviewGraph.prototype._networkTimelineRecordAdded.insertObjectIntoSortedArray):
(WebInspector.NetworkTimelineOverviewGraph.prototype._networkTimelineRecordAdded):

* UserInterface/ScriptTimelineOverviewGraph.css: Added.
(.timeline-overview-graph.script > .timeline-record-bar):
(.timeline-overview-graph.script > .timeline-record-bar > .segment):

* UserInterface/ScriptTimelineOverviewGraph.js: Added.
(WebInspector.ScriptTimelineOverviewGraph.prototype.reset):
(WebInspector.ScriptTimelineOverviewGraph.prototype.updateLayout):
(WebInspector.ScriptTimelineOverviewGraph.prototype._scriptTimelineRecordAdded):

* UserInterface/TimelineContentView.js:
(WebInspector.TimelineContentView.prototype._showTimelineView):
(WebInspector.TimelineContentView.prototype._update):
(WebInspector.TimelineContentView.prototype._recordingReset):
Create and keep the graphs informed.

* UserInterface/TimelineDataGridNode.js:
(WebInspector.TimelineDataGridNode):
(WebInspector.TimelineDataGridNode.prototype.refreshGraph):
Combine records that might overlap.

* UserInterface/TimelineOverview.css:
(.timeline-overview > .graphs-container):
(.timeline-overview > .graphs-container > .timeline-overview-graph):
(.timeline-overview > .graphs-container > .timeline-overview-graph:nth-child(even)):
(.timeline-overview > .graphs-container > .timeline-overview-graph:not(:first-child)):
Add the graph rows with alternating stripe.

* UserInterface/TimelineOverview.js:
(WebInspector.TimelineOverview):
(WebInspector.TimelineOverview.prototype.set startTime):
(WebInspector.TimelineOverview.prototype.get currentTime):
(WebInspector.TimelineOverview.prototype.set currentTime):
(WebInspector.TimelineOverview.prototype.updateLayout):
(WebInspector.TimelineOverview.prototype.updateLayoutIfNeeded):
Track currentTime in a member variable and let TimelineOverview manage the current time marker.

* UserInterface/TimelineOverviewGraph.js: Added.
(WebInspector.TimelineOverviewGraph):
(WebInspector.TimelineOverviewGraph.prototype.get zeroTime):
(WebInspector.TimelineOverviewGraph.prototype.set zeroTime):
(WebInspector.TimelineOverviewGraph.prototype.get startTime):
(WebInspector.TimelineOverviewGraph.prototype.set startTime):
(WebInspector.TimelineOverviewGraph.prototype.get endTime):
(WebInspector.TimelineOverviewGraph.prototype.set endTime):
(WebInspector.TimelineOverviewGraph.prototype.get currentTime):
(WebInspector.TimelineOverviewGraph.prototype.set currentTime):
(WebInspector.TimelineOverviewGraph.prototype.reset):
(WebInspector.TimelineOverviewGraph.prototype.updateLayout):
(WebInspector.TimelineOverviewGraph.prototype.updateLayoutIfNeeded):
(WebInspector.TimelineOverviewGraph.prototype.needsLayout):

* UserInterface/TimelineRecordBar.css:
(.timeline-record-bar > .segment):
(.timeline-record-bar.unfinished > .segment):
(.timeline-record-bar > .segment.inactive + .segment):
(.timeline-record-bar.timeline-record-type-network > .segment.inactive):

* UserInterface/TimelineRecordBar.js:
(WebInspector.TimelineRecordBar):
(WebInspector.TimelineRecordBar.recordsCannotBeCombined):
(WebInspector.TimelineRecordBar.prototype.get records):
(WebInspector.TimelineRecordBar.prototype.set records):
(WebInspector.TimelineRecordBar.prototype.refresh):
Make TimelineRecordBar support multiple records.

* UserInterface/TimelineRuler.css:
(.timeline-ruler > .markers):
(.timeline-ruler > .selection-handle):
(.timeline-ruler > .shaded-area):
Add some z-index values to stay above graph elements.

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@162419 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 387f50ed
2014-01-19 Timothy Hatcher <timothy@apple.com>
Implement basic versions of the TimelineOverview graphs.
https://bugs.webkit.org/show_bug.cgi?id=127184
Reviewed by Joseph Pecoraro.
* UserInterface/LayoutTimelineOverviewGraph.css: Added.
(.timeline-overview-graph.layout > .timeline-record-bar):
(.timeline-overview-graph.layout > .timeline-record-bar > .segment):
* UserInterface/LayoutTimelineOverviewGraph.js: Added.
(WebInspector.LayoutTimelineOverviewGraph.prototype.reset):
(WebInspector.LayoutTimelineOverviewGraph.prototype.updateLayout):
(WebInspector.LayoutTimelineOverviewGraph.prototype._layoutTimelineRecordAdded):
* UserInterface/Main.html: Added new files.
* UserInterface/NetworkTimelineOverviewGraph.css: Added.
(.timeline-overview-graph.network):
(.timeline-overview-graph.network > .graph-row):
(.timeline-overview-graph.network > .graph-row > .bar):
(.timeline-overview-graph.network > .graph-row > .bar.inactive):
(.timeline-overview-graph.network > .graph-row > .bar.unfinished):
(.timeline-overview-graph.network > .graph-row > .bar:not(.inactive)):
(.timeline-overview-graph.network:nth-child(even) > .graph-row > .bar:not(.inactive)):
* UserInterface/NetworkTimelineOverviewGraph.js: Added.
(WebInspector.NetworkTimelineOverviewGraph.prototype.reset):
(WebInspector.NetworkTimelineOverviewGraph.prototype.updateLayout.updateElementPosition):
(WebInspector.NetworkTimelineOverviewGraph.prototype.updateLayout.createBar):
(WebInspector.NetworkTimelineOverviewGraph.prototype.updateLayout):
(WebInspector.NetworkTimelineOverviewGraph.prototype._networkTimelineRecordAdded.compareByStartTime):
(WebInspector.NetworkTimelineOverviewGraph.prototype._networkTimelineRecordAdded.insertObjectIntoSortedArray):
(WebInspector.NetworkTimelineOverviewGraph.prototype._networkTimelineRecordAdded):
* UserInterface/ScriptTimelineOverviewGraph.css: Added.
(.timeline-overview-graph.script > .timeline-record-bar):
(.timeline-overview-graph.script > .timeline-record-bar > .segment):
* UserInterface/ScriptTimelineOverviewGraph.js: Added.
(WebInspector.ScriptTimelineOverviewGraph.prototype.reset):
(WebInspector.ScriptTimelineOverviewGraph.prototype.updateLayout):
(WebInspector.ScriptTimelineOverviewGraph.prototype._scriptTimelineRecordAdded):
* UserInterface/TimelineContentView.js:
(WebInspector.TimelineContentView.prototype._showTimelineView):
(WebInspector.TimelineContentView.prototype._update):
(WebInspector.TimelineContentView.prototype._recordingReset):
Create and keep the graphs informed.
* UserInterface/TimelineDataGridNode.js:
(WebInspector.TimelineDataGridNode):
(WebInspector.TimelineDataGridNode.prototype.refreshGraph):
Combine records that might overlap.
* UserInterface/TimelineOverview.css:
(.timeline-overview > .graphs-container):
(.timeline-overview > .graphs-container > .timeline-overview-graph):
(.timeline-overview > .graphs-container > .timeline-overview-graph:nth-child(even)):
(.timeline-overview > .graphs-container > .timeline-overview-graph:not(:first-child)):
Add the graph rows with alternating stripe.
* UserInterface/TimelineOverview.js:
(WebInspector.TimelineOverview):
(WebInspector.TimelineOverview.prototype.set startTime):
(WebInspector.TimelineOverview.prototype.get currentTime):
(WebInspector.TimelineOverview.prototype.set currentTime):
(WebInspector.TimelineOverview.prototype.updateLayout):
(WebInspector.TimelineOverview.prototype.updateLayoutIfNeeded):
Track currentTime in a member variable and let TimelineOverview manage the current time marker.
* UserInterface/TimelineOverviewGraph.js: Added.
(WebInspector.TimelineOverviewGraph):
(WebInspector.TimelineOverviewGraph.prototype.get zeroTime):
(WebInspector.TimelineOverviewGraph.prototype.set zeroTime):
(WebInspector.TimelineOverviewGraph.prototype.get startTime):
(WebInspector.TimelineOverviewGraph.prototype.set startTime):
(WebInspector.TimelineOverviewGraph.prototype.get endTime):
(WebInspector.TimelineOverviewGraph.prototype.set endTime):
(WebInspector.TimelineOverviewGraph.prototype.get currentTime):
(WebInspector.TimelineOverviewGraph.prototype.set currentTime):
(WebInspector.TimelineOverviewGraph.prototype.reset):
(WebInspector.TimelineOverviewGraph.prototype.updateLayout):
(WebInspector.TimelineOverviewGraph.prototype.updateLayoutIfNeeded):
(WebInspector.TimelineOverviewGraph.prototype.needsLayout):
* UserInterface/TimelineRecordBar.css:
(.timeline-record-bar > .segment):
(.timeline-record-bar.unfinished > .segment):
(.timeline-record-bar > .segment.inactive + .segment):
(.timeline-record-bar.timeline-record-type-network > .segment.inactive):
* UserInterface/TimelineRecordBar.js:
(WebInspector.TimelineRecordBar):
(WebInspector.TimelineRecordBar.recordsCannotBeCombined):
(WebInspector.TimelineRecordBar.prototype.get records):
(WebInspector.TimelineRecordBar.prototype.set records):
(WebInspector.TimelineRecordBar.prototype.refresh):
Make TimelineRecordBar support multiple records.
* UserInterface/TimelineRuler.css:
(.timeline-ruler > .markers):
(.timeline-ruler > .selection-handle):
(.timeline-ruler > .shaded-area):
Add some z-index values to stay above graph elements.
2014-01-16 Timothy Hatcher <timothy@apple.com>
Clean up Timelines code by using ES6 features and less global access of TimelineRecording.
......
......@@ -78,3 +78,8 @@ function insertionIndexForObjectInListSortedByFunction(anObject, aList, aFunctio
return index;
}
}
function insertObjectIntoSortedArray(value, array, compareFunction)
{
array.splice(insertionIndexForObjectInListSortedByFunction(value, array, compareFunction), 0, value);
}
/*
* Copyright (C) 2014 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
.timeline-overview-graph.layout > .timeline-record-bar {
margin-top: 8px;
height: 20px;
}
.timeline-overview-graph.layout > .timeline-record-bar > .segment {
border-radius: 2px;
}
/*
* Copyright (C) 2014 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
WebInspector.LayoutTimelineOverviewGraph = function(recording)
{
WebInspector.TimelineOverviewGraph.call(this, recording);
this.element.classList.add(WebInspector.LayoutTimelineOverviewGraph.StyleClassName);
this._layoutTimeline = recording.timelines.get(WebInspector.TimelineRecord.Type.Layout);
this._layoutTimeline.addEventListener(WebInspector.Timeline.Event.RecordAdded, this._layoutTimelineRecordAdded, this);
this._timelineRecordBars = [];
this.reset();
};
WebInspector.LayoutTimelineOverviewGraph.StyleClassName = "layout";
WebInspector.LayoutTimelineOverviewGraph.prototype = {
constructor: WebInspector.LayoutTimelineOverviewGraph,
__proto__: WebInspector.TimelineOverviewGraph.prototype,
// Public
reset: function()
{
WebInspector.TimelineOverviewGraph.prototype.reset.call(this);
this._timelineRecordBarMap = new Map;
this.element.removeChildren();
},
updateLayout: function()
{
WebInspector.TimelineOverviewGraph.prototype.updateLayout.call(this);
var startTime = this.startTime;
var currentTime = this.currentTime;
var endTime = this.endTime;
var duration = (endTime - startTime);
var visibleWidth = this.element.offsetWidth;
var secondsPerPixel = duration / visibleWidth;
var recordBarIndex = 0;
var barRecords = [];
function createBar(barRecords)
{
var timelineRecordBar = this._timelineRecordBars[recordBarIndex];
if (!timelineRecordBar)
timelineRecordBar = this._timelineRecordBars[recordBarIndex] = new WebInspector.TimelineRecordBar;
timelineRecordBar.records = barRecords;
timelineRecordBar.refresh(this);
if (!timelineRecordBar.element.parentNode)
this.element.appendChild(timelineRecordBar.element);
++recordBarIndex;
}
for (var record of this._layoutTimeline.records) {
// If this bar is completely before the bounds of the graph, skip this record.
if (record.endTime < startTime)
continue;
// If this record is completely after the current time or end time, break out now.
// Records are sorted, so all records after this will be beyond the current or end time too.
if (record.startTime > currentTime || record.startTime > endTime)
break;
// Check if the previous record is a different type or far enough away to create the bar.
if (barRecords.length && WebInspector.TimelineRecordBar.recordsCannotBeCombined(barRecords, record, secondsPerPixel)) {
createBar.call(this, barRecords);
barRecords = [];
}
barRecords.push(record);
}
// Create the bar for the last record if needed.
if (barRecords.length)
createBar.call(this, barRecords);
// Remove the remaining unused TimelineRecordBars.
for (; recordBarIndex < this._timelineRecordBars.length; ++recordBarIndex) {
this._timelineRecordBars[recordBarIndex].records = null;
this._timelineRecordBars[recordBarIndex].element.remove();
}
},
// Private
_layoutTimelineRecordAdded: function(event)
{
this.needsLayout();
}
};
......@@ -92,6 +92,9 @@
<link rel="stylesheet" href="TimelineDataGrid.css">
<link rel="stylesheet" href="TimelineRecordBar.css">
<link rel="stylesheet" href="TimelineOverview.css">
<link rel="stylesheet" href="NetworkTimelineOverviewGraph.css">
<link rel="stylesheet" href="LayoutTimelineOverviewGraph.css">
<link rel="stylesheet" href="ScriptTimelineOverviewGraph.css">
<link rel="stylesheet" href="ProfileView.css">
<link rel="stylesheet" href="JavaScriptProfileView.css">
<link rel="stylesheet" href="CSSStyleDetailsSidebarPanel.css">
......@@ -367,6 +370,10 @@
<script src="SourceCodeTimelineTimelineDataGridNode.js"></script>
<script src="TreeOutlineDataGridSynchronizer.js"></script>
<script src="TimelineOverview.js"></script>
<script src="TimelineOverviewGraph.js"></script>
<script src="NetworkTimelineOverviewGraph.js"></script>
<script src="LayoutTimelineOverviewGraph.js"></script>
<script src="ScriptTimelineOverviewGraph.js"></script>
<script src="ProfileManager.js"></script>
<script src="ProfileType.js"></script>
<script src="ProfileView.js"></script>
......
/*
* Copyright (C) 2014 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
.timeline-overview-graph.network {
padding-top: 2px
}
.timeline-overview-graph.network > .graph-row {
position: relative;
height: 5px;
}
.timeline-overview-graph.network > .graph-row > .bar {
position: absolute;
height: 4px;
background-color: rgb(120, 176, 225);
border: 1px solid rgb(61, 147, 200);
border-radius: 2px;
margin-top: 1px;
min-width: 3px;
}
.timeline-overview-graph.network > .graph-row > .bar.inactive {
background-color: rgb(167, 204, 237);
border-color: rgb(127, 185, 220);
}
.timeline-overview-graph.network > .graph-row > .bar.inactive,
.timeline-overview-graph.network > .graph-row > .bar.unfinished {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
border-right: none;
}
.timeline-overview-graph.network > .graph-row > .bar:not(.inactive) {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
z-index: 1;
box-shadow: white 1px 0 0;
}
.timeline-overview-graph.network:nth-child(even) > .graph-row > .bar:not(.inactive) {
box-shadow: rgb(247, 247, 247) 1px 0 0;
}
/*
* Copyright (C) 2014 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
.timeline-overview-graph.script > .timeline-record-bar {
margin-top: 8px;
height: 20px;
}
.timeline-overview-graph.script > .timeline-record-bar > .segment {
border-radius: 2px;
}
/*
* Copyright (C) 2014 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
WebInspector.ScriptTimelineOverviewGraph = function(recording)
{
WebInspector.TimelineOverviewGraph.call(this, recording);
this.element.classList.add(WebInspector.ScriptTimelineOverviewGraph.StyleClassName);
this._scriptTimeline = recording.timelines.get(WebInspector.TimelineRecord.Type.Script);
this._scriptTimeline.addEventListener(WebInspector.Timeline.Event.RecordAdded, this._scriptTimelineRecordAdded, this);
this._timelineRecordBars = [];
this.reset();
};
WebInspector.ScriptTimelineOverviewGraph.StyleClassName = "script";
WebInspector.ScriptTimelineOverviewGraph.prototype = {
constructor: WebInspector.ScriptTimelineOverviewGraph,
__proto__: WebInspector.TimelineOverviewGraph.prototype,
// Public
reset: function()
{
WebInspector.TimelineOverviewGraph.prototype.reset.call(this);
this._timelineRecordBarMap = new Map;
this.element.removeChildren();
},
updateLayout: function()
{
WebInspector.TimelineOverviewGraph.prototype.updateLayout.call(this);
var startTime = this.startTime;
var currentTime = this.currentTime;
var endTime = this.endTime;
var duration = (endTime - startTime);
var visibleWidth = this.element.offsetWidth;
var secondsPerPixel = duration / visibleWidth;
var recordBarIndex = 0;
var barRecords = [];
function createBar(barRecords)
{
var timelineRecordBar = this._timelineRecordBars[recordBarIndex];
if (!timelineRecordBar)
timelineRecordBar = this._timelineRecordBars[recordBarIndex] = new WebInspector.TimelineRecordBar;
timelineRecordBar.records = barRecords;
timelineRecordBar.refresh(this);
if (!timelineRecordBar.element.parentNode)
this.element.appendChild(timelineRecordBar.element);
++recordBarIndex;
}
for (var record of this._scriptTimeline.records) {
// If this bar is completely before the bounds of the graph, skip this record.
if (record.endTime < startTime)
continue;
// If this record is completely after the current time or end time, break out now.
// Records are sorted, so all records after this will be beyond the current or end time too.
if (record.startTime > currentTime || record.startTime > endTime)
break;
// Check if the previous record is a different type or far enough away to create the bar.
if (barRecords.length && WebInspector.TimelineRecordBar.recordsCannotBeCombined(barRecords, record, secondsPerPixel)) {
createBar.call(this, barRecords);
barRecords = [];
}
barRecords.push(record);
}
// Create the bar for the last record if needed.
if (barRecords.length)
createBar.call(this, barRecords);
// Remove the remaining unused TimelineRecordBars.
for (; recordBarIndex < this._timelineRecordBars.length; ++recordBarIndex) {
this._timelineRecordBars[recordBarIndex].records = null;
this._timelineRecordBars[recordBarIndex].element.remove();
}
},
// Private
_scriptTimelineRecordAdded: function(event)
{
this.needsLayout();
}
};
......@@ -31,13 +31,15 @@ WebInspector.TimelineContentView = function(recording)
this.element.classList.add(WebInspector.TimelineContentView.StyleClassName);
this._timelineOverview = new WebInspector.TimelineOverview;
this._discreteTimelineOverviewGraphMap = new Map;
this._discreteTimelineOverviewGraphMap.set(WebInspector.TimelineRecord.Type.Network, new WebInspector.NetworkTimelineOverviewGraph(recording));
this._discreteTimelineOverviewGraphMap.set(WebInspector.TimelineRecord.Type.Layout, new WebInspector.LayoutTimelineOverviewGraph(recording));
this._discreteTimelineOverviewGraphMap.set(WebInspector.TimelineRecord.Type.Script, new WebInspector.ScriptTimelineOverviewGraph(recording));
this._timelineOverview = new WebInspector.TimelineOverview(this._discreteTimelineOverviewGraphMap);
this._timelineOverview.addEventListener(WebInspector.TimelineOverview.Event.TimeRangeSelectionChanged, this._timeRangeSelectionChanged, this);
this.element.appendChild(this._timelineOverview.element);
this._currentTimeMarker = new WebInspector.TimelineMarker(0, WebInspector.TimelineMarker.Type.CurrentTime);
this._timelineOverview.addMarker(this._currentTimeMarker);
this._viewContainer = document.createElement("div");
this._viewContainer.classList.add(WebInspector.TimelineContentView.ViewContainerStyleClassName);
this.element.appendChild(this._viewContainer);
......@@ -159,7 +161,7 @@ WebInspector.TimelineContentView.prototype = {
var startTime = this._timelineOverview.selectionStartTime;
var endTime = this._timelineOverview.selectionStartTime + this._timelineOverview.selectionDuration;
var currentTime = this._currentTimeMarker.time || this._recording.startTime;
var currentTime = this._currentTime || this._recording.startTime;
function checkTimeBounds(itemStartTime, itemEndTime)
{
......@@ -228,7 +230,7 @@ WebInspector.TimelineContentView.prototype = {
this._currentTimelineView.startTime = this._timelineOverview.selectionStartTime;
this._currentTimelineView.endTime = this._timelineOverview.selectionStartTime + this._timelineOverview.selectionDuration;
this._currentTimelineView.currentTime = this._currentTimeMarker.time;
this._currentTimelineView.currentTime = this._currentTime;
this._currentTimelineView.shown();
this._currentTimelineView.updateLayout();
......@@ -240,7 +242,7 @@ WebInspector.TimelineContentView.prototype = {
_update: function(timestamp)
{
var startTime = this._recording.startTime;
var currentTime = this._currentTimeMarker.time || startTime;
var currentTime = this._currentTime || startTime;
var endTime = this._recording.endTime;
var timespanSinceLastUpdate = (timestamp - this._lastUpdateTimestamp) / 1000 || 0;
......@@ -261,11 +263,10 @@ WebInspector.TimelineContentView.prototype = {
this._timelineOverview.endTime = Math.max(endTime, currentTime);
this._currentTimeMarker.time = currentTime;
this._currentTime = currentTime;
this._timelineOverview.currentTime = currentTime;
this._currentTimelineView.currentTime = currentTime;
this._timelineOverview.revealMarker(this._currentTimeMarker);
// Force a layout now since we are already in an animation frame and don't need to delay it until the next.
this._timelineOverview.updateLayoutIfNeeded();
this._currentTimelineView.updateLayoutIfNeeded();
......@@ -314,11 +315,14 @@ WebInspector.TimelineContentView.prototype = {
_recordingReset: function(event)
{
this._startTimeNeedsReset = true;
this._currentTimeMarker.time = 0;
this._currentTime = NaN;
this._overviewTimelineView.reset();
for (var timelineView of this._discreteTimelineViewMap.values())
timelineView.reset();
for (var timelineOverviewGraph of this._discreteTimelineOverviewGraphMap.values())
timelineOverviewGraph.reset();
},
_timeRangeSelectionChanged: function(event)
......
......@@ -32,7 +32,7 @@ WebInspector.TimelineDataGridNode = function(graphOnly, graphDataSource)
if (graphDataSource) {
this._graphContainerElement = document.createElement("div");
this._timelineRecordBarMap = new Map;
this._timelineRecordBars = [];
}
};
......@@ -198,20 +198,89 @@ WebInspector.TimelineDataGridNode.prototype = {
delete this._scheduledGraphRefreshIdentifier;
}
var records = this.records || [];
for (var record of records) {
var timelineRecordBar = this._timelineRecordBarMap.get(record);
if (!timelineRecordBar) {
timelineRecordBar = new WebInspector.TimelineRecordBar(record);
this._timelineRecordBarMap.set(record, timelineRecordBar);
var records = this.records;
if (!records || !records.length)
return;
// Fast path for single records.
if (records.length === 1) {
var record = records[0];
var timelineRecordBar = this._timelineRecordBars[0];
if (timelineRecordBar && timelineRecordBar.record !== record) {
timelineRecordBar.element.remove();
timelineRecordBar = null;
}
if (!timelineRecordBar)
timelineRecordBar = this._timelineRecordBars[0] = new WebInspector.TimelineRecordBar(record);
if (timelineRecordBar.refresh(this._graphDataSource)) {
if (!timelineRecordBar.element.parentNode)
this._graphContainerElement.appendChild(timelineRecordBar.element);
} else {
} else
timelineRecordBar.element.remove();
return;
}
// Multiple records attempt to share a bar if their time is close to prevent overlapping bars.
var startTime = this._graphDataSource.startTime;
var currentTime = this._graphDataSource.currentTime;
var endTime = this._graphDataSource.endTime;
var duration = endTime - startTime;
var visibleWidth = this._graphContainerElement.offsetWidth;
var secondsPerPixel = duration / visibleWidth;
var recordBarIndex = 0;
var barRecords = [];
function createBar(barRecords)
{
var timelineRecordBar = this._timelineRecordBars[recordBarIndex];
if (!timelineRecordBar)
timelineRecordBar = this._timelineRecordBars[recordBarIndex] = new WebInspector.TimelineRecordBar;
timelineRecordBar.records = barRecords;
timelineRecordBar.refresh(this._graphDataSource);
if (!timelineRecordBar.element.parentNode)
this._graphContainerElement.appendChild(timelineRecordBar.element);
++recordBarIndex;
}
for (var record of records) {
// Combining multiple record bars is not supported with records that have inactive time.
// ResourceTimelineRecord is the only one right, and it is always a single record handled above.
console.assert(!record.usesActiveStartTime);
if (isNaN(record.startTime))
continue;
// If this bar is completely before the bounds of the graph, skip this record.
if (record.endTime < startTime)
continue;
// If this record is completely after the current time or end time, break out now.
// Records are sorted, so all records after this will be beyond the current or end time too.
if (record.startTime > currentTime || record.startTime > endTime)
break;
// Check if the previous record can be combined with the current record, if not make a new bar.
if (barRecords.length && WebInspector.TimelineRecordBar.recordsCannotBeCombined(barRecords, record, secondsPerPixel)) {
createBar.call(this, barRecords);
barRecords = [];
}
barRecords.push<