blob: c87533d77643be9f2d49af14e610bc32b8494375 [file] [log] [blame]
class FrameManager {
constructor(chartComponent, canvasComponent) {
// Function callback bindings
this.togglePause = this.togglePause.bind(this);
this.drawChart = this.drawChart.bind(this);
this.draw = this.draw.bind(this);
this.processInput = this.processInput.bind(this);
this.selectHandler = this.selectHandler.bind(this);
// Draw params
this.chartComponent = chartComponent;
this.pause = false;
this.redraw = false;
this.frameNumber = 0;
this.maxCount = 250;
this.frame_tree_canvas = canvasComponent;
this.ctx = this.frame_tree_canvas.getContext("2d");
// Data params
this.frameData = [];
this.allFrames = [];
google.charts.load('current', { 'packages': ['bar'] });
google.charts.setOnLoadCallback(this.drawChart);
}
togglePause() {
this.pause = !this.pause;
}
setMaxFrames(val) {
this.maxCount = val;
}
drawChart() {
this.chart = new google.charts.Bar(this.chartComponent);
google.visualization.events.addListener(this.chart, 'select', this.selectHandler);
}
selectHandler(element) {
if (this.chart.getSelection().length > 0) {
this.renderTree();
}
}
buildName(type, name) {
var char = "";
if (type == "PaintImmediatelyMethodStat") {
char = "[I]";
} else if (type == "PaintComponentMethodStat") {
char = "[P]";
} else if (type == "PaintChildrenMethodStat") {
char = "[C]";
}
return char + name;
}
buildTree(output, node, indent) {
node.callee.forEach(child => {
var time = ((child.endTime - child.startTime) / 100000.0);
output.push({
"name": child.owner,
"duration": time,
"indent": indent,
"type": child.classType,
});
this.buildTree(output, child, indent + 1);
});
}
renderTree() {
var frameData = this.allFrames[this.chart.getSelection()[0].row];
this.ctx.font = "12px Arial";
this.ctx.clearRect(0, 0, frame_tree_canvas.width, frame_tree_canvas.height);
this.ctx.fillStyle = 'rgb(0,0,0)';
var offset = 0;
var rows = 1;
frameData.forEach(data => {
rows++;
rows += data.children.length;
});
this.ctx.canvas.height = rows * 15;
frameData.forEach(data => {
this.ctx.fillText(data.duration, offset, 15);
this.ctx.fillText(this.buildName(data.type, data.name), offset + 75, 15);
var row = 2;
var maxIndent = 0;
data.children.forEach(child => {
if (child.indent > maxIndent) {
maxIndent = child.indent;
}
this.ctx.fillText(child.duration, offset, row * 15);
this.ctx.fillText(this.buildName(child.type, child.name), 75 + offset + child.indent * 10, row * 15);
row++;
});
offset += maxIndent * 10 + 100;
});
}
draw() {
if (this.frameData.length == 0 || this.chart == null || !this.redraw || this.pause) {
return;
}
while (this.allFrames.length > this.maxCount) {
this.allFrames.shift();
}
this.redraw = false;
this.allFrames.push(this.frameData.slice());
var maxSize = this.allFrames[0].length;
var maxElement = this.allFrames[0];
// Find any root nodes that may have more than one child.
this.allFrames.forEach(val => {
if (maxSize < val.length) {
maxSize = val.length;
maxElement = val;
}
});
// Build our chart data.
var data = new google.visualization.DataTable();
data.addColumn('number', "Count");
maxElement.forEach(val => {
data.addColumn('number', val.name);
})
this.allFrames.forEach(val => {
var frameData = []
frameData.push(this.frameNumber);
frameData.push(val[0].duration);
while (frameData.length < this.maxSize) {
frameData.push(0);
}
data.addRow(frameData);
});
var options = {
title: 'Frame Performance',
legend: { position: 'bottom' }
};
this.chart.draw(data, options);
}
// Process each complete JSON tree, and split up ThreadStats individually for processing.
processInput(rootNode) {
//var rootFilter = rootFilterElement.value;
var output = [];
this.frameNumber++;
rootNode.forEach(val => {
if (val.events.length > 0) {
var time = ((val.events[0].endTime - val.events[0].startTime) / 100000.0);
var children = [];
this.buildTree(children, val.events[0], 1);
output.push({
"name": val.threadName.substring(0, Math.min(val.threadName.length, 25)),
"duration": time,
"time": this.frameNumber,
"children": children,
"type": val.events[0].classType,
});
}
})
if (output.length > 0) {
this.redraw = true;
this.frameData = output;
}
}
}