var timelineCtrl = angular.module('timelineCtrl', []); timelineCtrl.controller('TimelineCtrl', ['$scope', '$rootScope', '$routeParams', '$location', '$timeout', 'Menu', 'Results', 'API', function($scope, $rootScope, $routeParams, $location, $timeout, Menu, Results, API) { $scope.runId = $routeParams.runId; $scope.Menu = Menu.setCurrentPage('timeline', $scope.runId); function loadResults() { // Load result if needed if (!$rootScope.loadedResult || $rootScope.loadedResult.runId !== $routeParams.runId) { Results.get({runId: $routeParams.runId}, function(result) { $rootScope.loadedResult = result; $scope.result = result; render(); }); } else { $scope.result = $rootScope.loadedResult; render(); } } function render() { initExecutionTree(); initTimeline(); $timeout(initProfiler, 100); } function initExecutionTree() { var originalExecutions = $scope.result.javascriptExecutionTree.children || []; $scope.executionTree = []; originalExecutions.forEach(function(node) { // Prepare a faster angular search by creating a kind of search index node.searchIndex = (node.data.callDetails) ? [node.data.type].concat(node.data.callDetails.arguments).join('°°') : node.data.type; $scope.executionTree.push(node); }); } function initTimeline() { // Split the timeline into 200 intervals var numberOfIntervals = 199; var lastEvent = $scope.executionTree[$scope.executionTree.length - 1]; $scope.endTime = lastEvent.data.timestamp + (lastEvent.data.time || 0); $scope.timelineIntervalDuration = $scope.endTime / numberOfIntervals; // Pre-fill array of as many elements as there are milleseconds var millisecondsArray = Array.apply(null, new Array($scope.endTime + 1)).map(Number.prototype.valueOf,0); // Create the milliseconds array from the execution tree $scope.executionTree.forEach(function(node) { if (node.data.time !== undefined) { // Ignore artefacts (durations > 100ms) var time = Math.min(node.data.time, 100) || 1; for (var i=node.data.timestamp, max=node.data.timestamp + time ; i