Brand new timeline graph

This commit is contained in:
Gaël Métais
2014-09-08 19:30:57 +02:00
parent bf752790f2
commit 2d00ac81ea
3 changed files with 138 additions and 0 deletions
+27
View File
@@ -116,6 +116,33 @@
</div>
<div ng-show="view == 'execution' && !phantomasResults.error" class="execution">
<h2>Javascript Spaghetti Timeline</h2>
<p>
This graph gives a quick view of when the Javascript interactions with the DOM occur during the loading of the page.
</p>
<div class="timeline">
<div class="chart">
<div ng-repeat="duration in timeline track by $index"
class="interval"
ng-class="{
domCreation: $index * timelineIntervalDuration < phantomasResults.metrics.domInteractive,
domContentLoaded: $index * timelineIntervalDuration >= phantomasResults.metrics.domContentLoaded
&& $index * timelineIntervalDuration < phantomasResults.metrics.domContentLoadedEnd,
domContentLoadedEnd: $index * timelineIntervalDuration >= phantomasResults.metrics.domContentLoadedEnd
&& $index * timelineIntervalDuration < phantomasResults.metrics.domComplete,
domComplete: $index * timelineIntervalDuration >= phantomasResults.metrics.domComplete
}">
<div style="height: {{100 * duration / timelineMax | number: 0}}px" class="color"></div>
</div>
</div>
<div class="legend">
<div class="domCreation"><div class="color"></div>DOM creation</div>
<div class="domContentLoaded"><div class="color"></div>DOM content loaded event</div>
<div class="domContentLoadedEnd"><div class="color"></div>Page completion</div>
<div class="domComplete"><div class="color"></div>Page completed</div>
</div>
</div>
<h2>Javascript Spaghetti Profiler</h2>
<p>
The table below shows the interactions between Javascript and the DOM. It is usefull to understand what's going on when the page loads.
+50
View File
@@ -215,6 +215,56 @@ app.controller('ResultsCtrl', function ($scope) {
function initExecutionView() {
$scope.slowRequestsOn = false;
$scope.slowRequestsLimit = 5;
// Now read the tree and display it on a timeline
// Split the timeline into 200 intervals
var numberOfIntervals = 200;
var lastEvent = $scope.javascript.children[$scope.javascript.children.length - 1];
var endTime = lastEvent.data.timestamp + (lastEvent.data.time || 0);
$scope.timelineIntervalDuration = endTime / numberOfIntervals;
// Pre-filled array of 100 elements
$scope.timeline = Array.apply(null, new Array(numberOfIntervals)).map(Number.prototype.valueOf,0);
treeRunner($scope.javascript, function(node) {
if (node.data.time) {
// If a node is between two intervals, split it. That's the meaning of the following dirty algorithm.
var startInterval = Math.floor(node.data.timestamp / $scope.timelineIntervalDuration);
var endInterval = Math.floor((node.data.timestamp + node.data.time) / $scope.timelineIntervalDuration);
if (startInterval === endInterval) {
$scope.timeline[startInterval] += node.data.time;
} else {
var timeToDispatch = node.data.time;
var startIntervalPart = ((startInterval + 1) * $scope.timelineIntervalDuration) - node.data.timestamp;
$scope.timeline[startInterval] += startIntervalPart;
timeToDispatch -= startIntervalPart;
var currentInterval = startInterval;
while(currentInterval < endInterval && currentInterval + 1 < numberOfIntervals) {
currentInterval ++;
var currentIntervalPart = Math.min(timeToDispatch, $scope.timelineIntervalDuration);
$scope.timeline[currentInterval] = currentIntervalPart;
timeToDispatch -= currentIntervalPart;
}
}
}
if (node.data.type !== 'main') {
// Don't check the children
return false;
}
});
$scope.timelineMax = Math.max.apply(Math, $scope.timeline);
}
function initMetricsView() {
+61
View File
@@ -115,6 +115,67 @@ h4 {
background: #CCC;
}
.timeline {
margin: 2em 0 5em;
}
.timeline .chart {
height: 100px;
width: 100%;
border-bottom: 1px solid #000;
}
.timeline .interval {
position: relative;
display: inline-block;
height: 100px;
width: 0.5%;
}
.timeline .interval > div {
position: absolute;
bottom: 0;
width: 100%;
}
.timeline .domCreation.interval {
background: #FFE0CC;
}
.timeline .domCreation .color {
background: #FF6600;
}
.timeline .domContentLoaded.interval {
background: #E0FFD1;
}
.timeline .domContentLoaded .color {
background: #99FF66;
}
.timeline .domContentLoadedEnd.interval {
background: #D8F0F0;
}
.timeline .domContentLoadedEnd .color {
background: #7ECCCC;
}
.timeline .domComplete.interval {
background: #EDE3FF;
}
.timeline .domComplete .color {
background: #C2A3FF;
}
.timeline .legend {
display: table;
width: 100%;
}
.timeline .legend > div {
display: table-cell;
margin-top: 1em;
}
.timeline .legend .color {
display: inline-block;
position: relative;
top: 0.4em;
height: 1.5em;
width: 1.5em;
border-radius: 0.5em;
margin: 0 0.2em 0 1em;
}
.metrics h4 {
padding-left: 2em;