1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
|
// Copyright Epic Games, Inc. All Rights Reserved.
// Sortable stats table view.
const US_PER_MS = 1000;
function escapeHtml(s) {
return String(s).replace(/[&<>"']/g, (c) => ({
"&": "&",
"<": "<",
">": ">",
"\"": """,
"'": "'",
}[c]));
}
export class StatsView {
constructor(tbody, headerRow, model, onSelect) {
this.tbody = tbody;
this.headerRow = headerRow;
this.stats = model.scopeStats.slice();
this.onSelect = onSelect;
this.sortKey = "count";
this.sortAsc = false;
this.selectedName = null;
for (const th of headerRow.querySelectorAll("th[data-sort]")) {
th.addEventListener("click", () => this.handleSort(th.dataset.sort));
}
this.render();
}
handleSort(key) {
if (this.sortKey === key) {
this.sortAsc = !this.sortAsc;
} else {
this.sortKey = key;
this.sortAsc = key === "name";
}
this.render();
}
selectByName(name) {
this.selectedName = name;
for (const tr of this.tbody.querySelectorAll("tr")) {
tr.classList.toggle("selected", tr.dataset.name === name);
if (tr.dataset.name === name) {
tr.scrollIntoView({ block: "nearest" });
}
}
}
render() {
const key = this.sortKey;
const asc = this.sortAsc;
this.stats.sort((a, b) => {
const av = a[key];
const bv = b[key];
if (typeof av === "string") {
return asc ? av.localeCompare(bv) : bv.localeCompare(av);
}
return asc ? av - bv : bv - av;
});
for (const th of this.headerRow.querySelectorAll("th[data-sort]")) {
th.classList.toggle("sorted", th.dataset.sort === key);
th.classList.toggle("asc", th.dataset.sort === key && asc);
}
const rows = [];
for (const stat of this.stats) {
const selected = stat.name === this.selectedName ? " class=\"selected\"" : "";
rows.push(
`<tr data-name="${escapeHtml(stat.name)}"${selected}>` +
`<td>${escapeHtml(stat.name)}</td>` +
`<td class="num">${stat.count.toLocaleString()}</td>` +
`<td class="num">${(stat.min_us / US_PER_MS).toFixed(3)}</td>` +
`<td class="num">${(stat.mean_us / US_PER_MS).toFixed(3)}</td>` +
`<td class="num">${(stat.max_us / US_PER_MS).toFixed(3)}</td>` +
`<td class="num">${(stat.stdev_us / US_PER_MS).toFixed(3)}</td>` +
`</tr>`,
);
}
this.tbody.innerHTML = rows.join("");
for (const tr of this.tbody.querySelectorAll("tr")) {
tr.addEventListener("click", () => {
const name = tr.dataset.name;
this.selectByName(name);
if (this.onSelect) {
this.onSelect(name);
}
});
}
}
}
|