Skip to content

Commit e25c9c9

Browse files
committed
add comments from upstream
1 parent a16f5e4 commit e25c9c9

File tree

1 file changed

+78
-62
lines changed

1 file changed

+78
-62
lines changed

app/utils/d3-flame-graphs-v4/d3-flame-graph.js

Lines changed: 78 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ let getClassAndMethodName = function(fqdn) {
1919
return tokens.slice(tokens.length - 2).join(".");
2020
};
2121

22+
// Return a vector (0.0 -> 1.0) that is a hash of the input string.
23+
// The hash is computed to favor early characters over later ones, so
24+
// that strings with similar starts have similar vectors. Only the first
25+
// 6 characters are considered.
2226
let hash = function(name) {
2327
let i, j, maxHash, mod, ref, ref1, result, weight;
2428
ref = [0, 0, 1, 10], result = ref[0], maxHash = ref[1], weight = ref[2], mod = ref[3];
@@ -36,10 +40,13 @@ let hash = function(name) {
3640
};
3741

3842
const FlameGraphUtils = {
43+
// augments each node in the tree with the maximum distance
44+
// it is from a terminal node, the list of parents linking
45+
// it to the root and filler nodes that balance the representation
3946
augment(node, location) {
40-
let childSum;
41-
let children;
42-
children = node.children;
47+
let children = node.children;
48+
// d3.partition adds the reverse (depth), here we store the distance
49+
// between a node and its furthest leaf
4350
if (node.augmented) {
4451
return node;
4552
}
@@ -51,7 +58,7 @@ const FlameGraphUtils = {
5158
node.augmented = true;
5259
return node;
5360
}
54-
childSum = children.reduce((function(sum, child) {
61+
let childSum = children.reduce((function(sum, child) {
5562
return sum + child.value;
5663
}), 0);
5764
if (childSum < node.value) {
@@ -72,41 +79,36 @@ const FlameGraphUtils = {
7279
.sum(d => d.data ? d.data.value : d.value)
7380
.sort((a, b) => {
7481
if (a.filler) {
75-
return 1;
82+
return 1; // move fillers to the right
7683
}
7784
if (b.filler) {
78-
return -1;
85+
return -1; // move fillers to the right
7986
}
8087
return a.data.name.localeCompare(b.data.name);
8188
});
8289
return d3partition(root).descendants();
8390
},
8491
hide(nodes, unhide) {
85-
let process;
86-
let processChildren;
87-
let processParents;
88-
let remove;
89-
let sum;
9092
if (unhide === null) {
9193
unhide = false;
9294
}
93-
sum = arr => arr.reduce(((acc, val) => acc + val), 0);
94-
remove = (arr, val) => {
95-
let pos;
96-
pos = arr.indexOf(val);
95+
let sum = arr => arr.reduce(((acc, val) => acc + val), 0);
96+
let remove = (arr, val) => {
97+
// we need to remove precisely one occurrence of initial value
98+
let pos = arr.indexOf(val);
9799
if (pos >= 0) {
98100
return arr.splice(pos, 1);
99101
}
100102
};
101-
process = (node, val) => {
103+
let process = (node, val) => {
102104
if (unhide) {
103105
remove(node.hidden, val);
104106
} else {
105107
node.hidden.push(val);
106108
}
107109
return node.value = Math.max(node.originalValue - sum(node.hidden), 0);
108110
};
109-
processChildren = (node, val) => {
111+
let processChildren = (node, val) => {
110112
if (!node.children) {
111113
return;
112114
}
@@ -115,18 +117,16 @@ const FlameGraphUtils = {
115117
return processChildren(child, val);
116118
});
117119
};
118-
processParents = (node, val) => {
119-
let results;
120-
results = [];
120+
let processParents = (node, val) => {
121+
let results = [];
121122
while (node.parent) {
122123
process(node.parent, val);
123124
results.push(node = node.parent);
124125
}
125126
return results;
126127
};
127128
return nodes.forEach(node => {
128-
let val;
129-
val = node.originalValue;
129+
let val = node.originalValue;
130130
processParents(node, val);
131131
process(node, val);
132132
return processChildren(node, val);
@@ -141,6 +141,8 @@ class FlameGraph {
141141
if (debug == null) {
142142
debug = false;
143143
}
144+
145+
// enable logging only if explicitly specified
144146
if (debug) {
145147
this.console = window.console;
146148
} else {
@@ -150,6 +152,8 @@ class FlameGraph {
150152
timeEnd() {}
151153
};
152154
}
155+
156+
// defaults
153157
this._size = [1200, 800];
154158
this._cellHeight = 20;
155159
this._margin = {
@@ -171,6 +175,8 @@ class FlameGraph {
171175
if (this._tooltipEnabled && d3Tip) {
172176
this._tooltipPlugin = d3Tip();
173177
}
178+
179+
// initial processing of data
174180
this.console.time('augment');
175181
this.original = FlameGraphUtils.augment(root, '0');
176182
this.console.timeEnd('augment');
@@ -256,45 +262,42 @@ class FlameGraph {
256262
if (onlyVisible) {
257263
return this.container.selectAll('.node').filter(predicate);
258264
} else {
265+
// re-partition the data prior to rendering
259266
result = FlameGraphUtils.partition(this.original).filter(predicate);
260267
return result;
261268
}
262269
}
263270

264271
render() {
265-
let data;
266-
let existingContainers;
267-
let maxLevels;
268-
let newContainers;
269-
let ref;
270-
let renderNode;
271-
let visibleCells;
272272
if (!this._selector) {
273273
throw new Error("No DOM element provided");
274274
}
275275
this.console.time('render');
276276
if (!this.container) {
277277
this._createContainer();
278278
}
279+
280+
// reset size and scales
279281
this.fontSize = (this.cellHeight() / 10) * 0.4;
280282

281283
this.x = scaleLinear().domain([0, max(this._data, d => d.x1)]).range([0, this.width()]);
282284

283-
visibleCells = Math.floor(this.height() / this.cellHeight());
284-
maxLevels = this._root.level;
285+
let visibleCells = Math.floor(this.height() / this.cellHeight());
286+
let maxLevels = this._root.level;
285287

286288
this.y = scaleQuantize().domain([min(this._data, d => d.y0), max(this._data, d => d.y0)]).range(range(maxLevels).map((function(_this) {
287289
return function(cell) {
288290
return (visibleCells - 1 - cell - _this._ancestors.length) * _this.cellHeight();
289291
};
290292
})(this)));
291293

292-
data = this._data.filter((function(_this) {
294+
// JOIN
295+
let data = this._data.filter((function(_this) {
293296
return function(d) {
294297
return _this.x(d.x1 - d.x0) > 0.4 && _this.y(d.y0) >= 0 && !d.data.filler;
295298
};
296299
})(this));
297-
renderNode = {
300+
let renderNode = {
298301
x: (function(_this) {
299302
return function(d) {
300303
return _this.x(d.x0);
@@ -324,10 +327,16 @@ class FlameGraph {
324327
};
325328
})(this)
326329
};
327-
existingContainers = this.container.selectAll('.node').data(data, d => d.data.location).attr('class', 'node');
330+
let existingContainers = this.container.selectAll('.node').data(data, d => d.data.location).attr('class', 'node');
331+
332+
// UPDATE
328333
this._renderNodes(existingContainers, renderNode, false, data);
329-
newContainers = existingContainers.enter().append('g').attr('class', 'node');
334+
335+
// ENTER
336+
let newContainers = existingContainers.enter().append('g').attr('class', 'node');
330337
this._renderNodes(newContainers, renderNode, true, data);
338+
339+
// EXIT
331340
existingContainers.exit().remove();
332341
if (this.zoomEnabled()) {
333342
this._renderAncestors()._enableNavigation();
@@ -341,13 +350,23 @@ class FlameGraph {
341350
}
342351

343352
_createContainer() {
344-
let offset;
345-
let svg;
353+
// remove any previously existing svg
346354
select(this._selector).select('svg').remove();
347-
svg = select(this._selector).append('svg').attr('class', 'flame-graph').attr('width', this._size[0]).attr('height', this._size[1]);
348-
offset = `translate(${this.margin().left}, ${this.margin().top})`;
355+
// create main svg container
356+
let svg = select(this._selector).append('svg').attr('class', 'flame-graph').attr('width', this._size[0]).attr('height', this._size[1]);
357+
// we set an offset based on the margin
358+
let offset = `translate(${this.margin().left}, ${this.margin().top})`;
359+
// this.container will hold all our nodes
349360
this.container = svg.append('g').attr('transform', offset);
350-
return svg.append('rect').attr('width', this._size[0] - (this._margin.left + this._margin.right)).attr('height', this._size[1] - (this._margin.top + this._margin.bottom)).attr('transform', offset).attr('class', 'border-rect');
361+
362+
// this rectangle draws the border around the flame graph
363+
// has to be appended after the container so that the border is visible
364+
// we also need to apply the same translation
365+
return svg.append('rect')
366+
.attr('width', this._size[0] - (this._margin.left + this._margin.right))
367+
.attr('height', this._size[1] - (this._margin.top + this._margin.bottom))
368+
.attr('transform', offset)
369+
.attr('class', 'border-rect');
351370
}
352371

353372
_renderNodes(containers, attrs, enter, data) {
@@ -403,12 +422,9 @@ class FlameGraph {
403422
}
404423
return 's';
405424
}))(this)).offset(((_this => d => {
406-
let x;
407-
let xOffset;
408-
let yOffset;
409-
x = _this.x(d.x0) + _this.x(d.x1 - d.x0) / 2;
410-
xOffset = Math.max(Math.ceil(_this.x(d.x1 - d.x0) / 2), 5);
411-
yOffset = Math.ceil(_this.cellHeight() / 2);
425+
let x = _this.x(d.x0) + _this.x(d.x1 - d.x0) / 2;
426+
let xOffset = Math.max(Math.ceil(_this.x(d.x1 - d.x0) / 2), 5);
427+
let yOffset = Math.ceil(_this.cellHeight() / 2);
412428
if (_this.width() - 100 < x) {
413429
return [0, -xOffset];
414430
}
@@ -431,33 +447,32 @@ class FlameGraph {
431447
}
432448

433449
_renderAncestors() {
434-
let ancestor;
435-
let ancestorData;
436-
let ancestors;
437-
let idx;
450+
let i;
438451
let j;
452+
let idx;
439453
let len;
440-
let newAncestors;
441-
let prev;
442-
let renderAncestor;
454+
let ancestor;
455+
let ancestors;
443456
if (!this._ancestors.length) {
444457
ancestors = this.container.selectAll('.ancestor').remove();
445458
return this;
446459
}
447-
ancestorData = this._ancestors.map((ancestor, idx) => ({
460+
let ancestorData = this._ancestors.map((ancestor, idx) => ({
448461
name: ancestor.name,
449462
value: idx + 1,
450463
location: ancestor.location,
451464
isAncestor: true
452465
}));
453466
for (idx = j = 0, len = ancestorData.length; j < len; idx = ++j) {
454467
ancestor = ancestorData[idx];
455-
prev = ancestorData[idx - 1];
468+
let prev = ancestorData[idx - 1];
456469
if (prev) {
457470
prev.children = [ancestor];
458471
}
459472
}
460-
renderAncestor = {
473+
474+
// FIXME: this is pretty ugly, but we need to add links between ancestors
475+
let renderAncestor = {
461476
x: (function(_this) {
462477
return function(d) {
463478
return 0;
@@ -477,20 +492,23 @@ class FlameGraph {
477492
})(this)
478493
};
479494

495+
// JOIN
480496
ancestors = this.container.selectAll('.ancestor').data(
481497
FlameGraphUtils.partition(ancestorData[0]), d => d.location
482498
);
483499

500+
// UPDATE
484501
this._renderNodes(ancestors, renderAncestor, false, ancestorData);
485-
newAncestors = ancestors.enter().append('g').attr('class', 'ancestor');
502+
// ENTER
503+
let newAncestors = ancestors.enter().append('g').attr('class', 'ancestor');
486504
this._renderNodes(newAncestors, renderAncestor, true, ancestorData);
505+
// EXIT
487506
ancestors.exit().remove();
488507
return this;
489508
}
490509

491510
_enableNavigation() {
492-
let clickable;
493-
clickable = ((_this => d => {
511+
let clickable = ((_this => d => {
494512
let ref;
495513
return Math.round(_this.width() - _this.x(d.x1 - d.x0)) > 0 && ((ref = d.children) != null ? ref.length : void 0);
496514
}))(this);
@@ -514,10 +532,8 @@ class FlameGraph {
514532

515533
_generateAccessors(accessors) {
516534
let accessor;
517-
let j;
518-
let len;
519535
let results = [];
520-
for (j = 0, len = accessors.length; j < len; j++) {
536+
for (let j = 0, len = accessors.length; j < len; j++) {
521537
accessor = accessors[j];
522538
results.push(this[accessor] = ((accessor => function(newValue) {
523539
if (!arguments.length) {

0 commit comments

Comments
 (0)