Files
pinpoint/src/main/webapp/scripts/directives/distributedCallFlow.js
T
2014-02-19 06:53:29 +00:00

234 lines
10 KiB
JavaScript

'use strict';
pinpointApp.directive('distributedCallFlow', [ '$filter',
function ($filter) {
return {
restrict: 'E',
replace: true,
templateUrl: 'views/distributedCallFlow.html',
scope : {
namespace : '@' // string value
},
link: function postLink(scope, element, attrs) {
// initialize variables
var grid, columns, dataView, lastAgent;
// initialize variables of methods
var initialize, treeFormatter, treeFilter, parseData, execTimeFormatter,
getColorByString, progressBarFormatter;
// bootstrap
window.callStacks = [];
getColorByString = function(str) {
// str to hash
for (var i = 0, hash = 0; i < str.length; hash = str.charCodeAt(i++) + ((hash << 5) - hash));
// int/hash to hex
for (var i = 0, colour = "#"; i < 3; colour += ("00" + ((hash >> i++ * 8) & 0xFF).toString(16)).slice(-2));
return colour;
};
treeFormatter = function (row, cell, value, columnDef, dataContext) {
var html = [];
value = value.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;");
var item = dataView.getItemById(dataContext.id);
lastAgent = item.agent ? item.agent : lastAgent;
var leftBarColor = getColorByString(lastAgent),
idx = dataView.getIdxById(dataContext.id);
html.push("<div style='position:absolute;top:0;left:0;bottom:0;width:5px;background-color:"+leftBarColor+"'></div>");
html.push("<span style='display:inline-block;height:1px;width:" + (15 * dataContext["indent"]) + "px'></span>");
if (window.callStacks[idx + 1] && window.callStacks[idx + 1].indent > window.callStacks[idx].indent) {
if (dataContext._collapsed) {
html.push(" <span class='toggle expand'></span>&nbsp;");
} else {
html.push(" <span class='toggle collapse'></span>&nbsp;");
}
} else {
html.push(" <span class='toggle'></span>&nbsp;");
}
if (item.hasException) {
html.push('<span style="color:rgb(214, 39, 39);">');
html.push('<span class="glyphicon glyphicon-fire"></span>&nbsp;');
} else if (!item.isMethod) {
html.push('<span style="color:rgb(79, 79, 107);">');
html.push('<span class="glyphicon glyphicon-info-sign"></span>&nbsp;');
} else {
html.push('<span>');
}
html.push(value);
html.push('</span>');
return html.join('');
};
treeFilter = function (item) {
var result = true;
if (item.parent != null) {
var parent = window.callStacks[item.parent];
while (parent) {
if (parent._collapsed) {
result = false;
}
parent = window.callStacks[parent.parent];
}
}
return result;
};
execTimeFormatter = function (row, cell, value, columnDef, dataContext) {
return $filter('date')(value, 'HH:mm:ss sss');
};
progressBarFormatter = function (row, cell, value, columnDef, dataContext) {
if (value == null || value === "" || value == 0) {
return "";
}
var color;
if (value < 30) {
color = "#5bc0de";
} else if (value < 70) {
color = "#5bc0de";
} else {
color = "#5bc0de";
}
return "<span class='percent-complete-bar' style='background:" + color + ";width:" + value + "%'></span>";
};
columns = [
{id: "method", name: "Method", field: "method", width: 400, formatter: treeFormatter},
{id: "argument", name: "Argument", field: "argument", width: 300},
{id: "exec-time", name: "Exec Time", field: "execTime", width: 90, formatter: execTimeFormatter},
{id: "gap-ms", name: "Gap(ms)", field: "gapMs", width: 60, cssClass: "right-align"},
{id: "time-ms", name: "Time(ms)", field: "timeMs", width: 60, cssClass: "right-align"},
{id: "time-per", name: "Time(%)", field: "timePer", width: 100, formatter: progressBarFormatter},
{id: "class", name: "Class", field: "class", width: 120},
{id: "api-type", name: "Api Type", field: "apiType", width: 90},
{id: "agent", name: "Agent", field: "agent", width: 130},
{id: "application-name", name: "Application Name", field: "applicationName", width: 150}
];
parseData = function(index, callStacks) {
var result = [],
barRatio = 100 / (callStacks[0][index.end] - callStacks[0][index.begin]);
angular.forEach(callStacks, function (val, key) {
result.push({
id: 'id_' + key,
parent: val[index['parentId']] ? val[index['parentId']] - 1 : null,
indent: val[index['tab']],
method: val[index['title']],
argument: val[index['arguments']],
execTime: val[index['begin']] > 0 ? val[index['begin']] : null,
gapMs: val[index['gap']],
timeMs: val[index['elapsedTime']],
timePer: val[index['elapsedTime']] ? ((val[index['end']] - val[index['begin']]) * barRatio) + 0.9 : null,
class: val[index['simpleClassName']],
apiType: val[index['apiType']],
agent: val[index['agent']],
applicationName: val[index['applicationName']],
hasException: val[index['hasException']],
isMethod: val[index['isMethod']]
});
});
return result;
};
/**
* initialize
* @param t transactionDetail
*/
initialize = function (t) {
window.callStacks = parseData(t.callStackIndex, t.callStack);
// initialize the model
var options = {
enableCellNavigation: true,
enableColumnReorder: true,
// autoHeight: true,
topPanelHeight: 30,
rowHeight: 25
};
dataView = new Slick.Data.DataView({ inlineFilters: true });
dataView.beginUpdate();
dataView.setItems(window.callStacks);
dataView.setFilter(treeFilter);
// dataView.getItemMetadata = function (row) {
// var item = dataView.getItemByIdx(row);
// if (!item.execTime) {
// return {
// "columns": {
// 2: {
// "colspan": "*"
// }
// }
// };
// }
// };
dataView.endUpdate();
grid = new Slick.Grid(element.get(0), dataView, columns, options);
grid.onClick.subscribe(function (e, args) {
if ($(e.target).hasClass("toggle")) {
var item = dataView.getItem(args.row);
if (item) {
if (!item._collapsed) {
item._collapsed = true;
} else {
item._collapsed = false;
}
dataView.updateItem(item.id, item);
}
e.stopImmediatePropagation();
}
});
grid.onCellChange.subscribe(function (e, args) {
dataView.updateItem(args.item.id, args.item);
});
grid.onActiveCellChanged.subscribe(function (e, args) {
scope.$emit('distributedCallFlow.rowSelected.' + scope.namespace, args.grid.getDataItem(args.row));
});
// wire up model events to drive the grid
dataView.onRowCountChanged.subscribe(function (e, args) {
grid.updateRowCount();
grid.render();
});
dataView.onRowsChanged.subscribe(function (e, args) {
grid.invalidateRows(args.rows);
grid.render();
});
};
/**
* scope event on distributedCallFlow.initialize
*/
scope.$on('distributedCallFlow.initialize.' + scope.namespace, function (event, transactionDetail) {
initialize(transactionDetail);
});
/**
* scope event on distributedCallFlow.resize
*/
scope.$on('distributedCallFlow.resize.' + scope.namespace, function (event) {
grid.resizeCanvas();
});
}
};
}
]);