فهرست منبع

Brand new timeline graph

Gaël Métais 10 سال پیش
والد
کامیت
2d00ac81ea
3فایلهای تغییر یافته به همراه138 افزوده شده و 0 حذف شده
  1. 27 0
      app/node_views/results.html
  2. 50 0
      app/public/scripts/resultsCtrl.js
  3. 61 0
      app/public/styles/results.css

+ 27 - 0
app/node_views/results.html

@@ -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 - 0
app/public/scripts/resultsCtrl.js

@@ -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 - 0
app/public/styles/results.css

@@ -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;