Skip to content

Commit 21a69a0

Browse files
Port hierarchy display for tracevis waterfall view
In addition to porting the code from master, this change also includes some transition fixes and a more intuitive indicator of collapsed / expanded tasks.
1 parent 5bd9d00 commit 21a69a0

File tree

3 files changed

+120
-39
lines changed

3 files changed

+120
-39
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
v1.3.8
2+
------
3+
4+
* Improvements to tracevis tool
5+
16
v1.3.7
27
------
38

tools/tracevis/css/waterfall.css

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,31 @@
44
.waterfallview .trace rect.success { fill: #60D060; }
55
.waterfallview .trace rect.error { fill: #FF6F6F; }
66
.waterfallview .trace rect.early_finish { fill: #FFFD76; }
7-
.waterfallview .trace circle { fill: #FFFFFF; }
7+
8+
.waterfallview .trace circle {
9+
opacity: 0;
10+
fill: #FFFFFF;
11+
stroke: #333;
12+
stroke-width: 1px;
13+
}
14+
15+
.waterfallview .trace.composite circle,
16+
.waterfallview .trace.component circle {
17+
opacity: 1;
18+
}
19+
20+
.waterfallview .trace line {
21+
opacity: 0;
22+
stroke: #333;
23+
stroke-width: 1px;
24+
stroke-linecap: round;
25+
stroke-dasharray: 3;
26+
}
27+
28+
.waterfallview .trace.composite line,
29+
.waterfallview .trace.component line {
30+
opacity: 1;
31+
}
832

933
.waterfallview .trace text,
1034
.waterfallview .trace text tspan {

tools/tracevis/lib/render/waterfall.js

Lines changed: 90 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,12 @@ function redraw(svg, vis, data, ancestors, transitionTime, rootCoords) {
7979
.___domain([0, nodes.length])
8080
.range([0, height]);
8181

82+
nodes.forEach(function(d, i) {
83+
d.x = x(d.startMillis);
84+
d.y = y(i);
85+
d.deleted = false;
86+
});
87+
8288
// Dynamically determine height required to render all tasks and resize the
8389
// svg canvas if needed.
8490
var svgHeight = height + MARGIN.top + MARGIN.bottom;
@@ -96,16 +102,41 @@ function redraw(svg, vis, data, ancestors, transitionTime, rootCoords) {
96102
.enter()
97103
.append('g')
98104
.classed('trace', true)
99-
.classed('composite', function(d) {
100-
return d.children || d._children;
101-
})
102-
.classed('hidden', false)
105+
.classed('component', function(d) { return d.parent.id !== null; })
106+
.classed('composite', function(d) { return d.children || d._children; })
103107
.style('opacity', 1e-6)
104108
.on('mouseover', mouseover)
105109
.on('mouseout', mouseout);
106110

107111
bars.classed('collapsed', function(d) { return d._children; });
108112

113+
// Append hierarchy lines before we draw the bars
114+
barsEnter.each(function(d) {
115+
if (d.children || d._children) {
116+
d3.select(this).append('path')
117+
.attr('d', 'M10 5 L0 10 L0 0 Z');
118+
} else if (d.parent.id !== null) {
119+
d3.select(this).append('circle')
120+
.attr('r', 4)
121+
.attr('cx', -5)
122+
.attr('cy', BAR_HEIGHT / 2);
123+
}
124+
});
125+
126+
barsEnter.append('line')
127+
.classed('vertical', true)
128+
.attr('x1', -5)
129+
.attr('y1', BAR_HEIGHT / 2)
130+
.attr('x2', -5)
131+
.attr('y2', BAR_HEIGHT / 2);
132+
133+
barsEnter.append('line')
134+
.classed('horizontal', true)
135+
.attr('x1', -5)
136+
.attr('y1', BAR_HEIGHT / 2)
137+
.attr('x2', -5)
138+
.attr('y2', BAR_HEIGHT / 2);
139+
109140
barsEnter
110141
.attr('transform', 'translate(' + rootCoords.x + ',' + rootCoords.y + ')')
111142
.append('rect')
@@ -127,53 +158,76 @@ function redraw(svg, vis, data, ancestors, transitionTime, rootCoords) {
127158
var textEnter = barsEnter
128159
.append('text')
129160
.attr('dy', '1.3em')
130-
.attr('dx', '1em');
161+
.attr('dx', '0.5em');
131162

132163
textEnter
133164
.append('tspan')
134165
.classed('collapse-toggle', true)
135166
.style('font-family', 'monospace');
136167

137168
bars
138-
.on('click', toggleCollapse)
139-
.selectAll('text tspan.collapse-toggle')
140-
.text(function(d) {
141-
if (d.children) {
142-
return '[-] ';
143-
} else if (d._children) {
144-
return '[+] ';
145-
} else {
146-
return '';
147-
}
148-
});
169+
.on('click', toggleCollapse);
149170

150171
textEnter
151172
.append('tspan')
152173
.text(function(d) { return d.name + ' (' + util.alignMillis(d.totalMillis) + ' ms)'; });
153174

154175
bars
155-
.style('pointer-events', 'none')
156-
.transition()
157-
.duration(transitionTime)
158-
.attr('transform', function(d, i) {
159-
return 'translate(' + x(d.startMillis) + ',' + y(i) + ')';
160-
})
161-
.style('opacity', alpha)
162-
.each('end', function() {
163-
d3.select(this).style('opacity', alpha);
164-
d3.select(this).style('pointer-events', undefined);
176+
.exit()
177+
.each(function(d) {
178+
if (d.parent) {
179+
d.x = rootCoords.x;
180+
d.y = rootCoords.y;
181+
}
182+
d.deleted = true;
183+
});
184+
185+
createTransition(bars)
186+
.selectAll('path')
187+
.attr('transform', function(d) {
188+
return 'translate(' + (d.children ? 0 : -10) + ',' + (BAR_HEIGHT / 2 - 5) + ') ' +
189+
'rotate(' + (d.children ? 90 : 0) + ')';
165190
});
191+
createTransition(bars.exit())
192+
.each('end', function() {
193+
d3.select(this.remove());
194+
});
166195

167-
bars
168-
.exit()
196+
function createTransition(selection) {
197+
var transition = selection
169198
.style('pointer-events', 'none')
170-
.classed('hidden', true)
171199
.transition()
172200
.duration(transitionTime)
173-
.attr('transform', 'translate(' + rootCoords.x + ',' + rootCoords.y + ')')
174-
.style('opacity', 1e-6)
175-
.each('end', function() { d3.select(this).style('pointer-events', undefined); })
176-
.remove();
201+
.attr('transform', function(d) { return 'translate(' + d.x + ',' + d.y + ')'; })
202+
.style('opacity', alpha);
203+
204+
transition
205+
.each('end', function() {
206+
d3.select(this).style('opacity', alpha);
207+
d3.select(this).style('pointer-events', undefined);
208+
});
209+
210+
transition.selectAll('line.horizontal')
211+
.attr('x2', function(d) {
212+
var delta = 0;
213+
// Check for id is important since we have a fake node at the root
214+
if (d.parent.id !== null) {
215+
delta = d.parent.x - d.x;
216+
}
217+
return delta - 4;
218+
});
219+
220+
transition.selectAll('line.vertical')
221+
.attr('y2', function(d) {
222+
var delta = 0;
223+
if (d.children) {
224+
delta = Math.max.apply(Math, d.children.map(function(c) { return c.y; })) - d.y;
225+
}
226+
return delta + BAR_HEIGHT / 2;
227+
});
228+
229+
return transition;
230+
}
177231

178232
function mouseover(d) {
179233
if (d.children || d._children) {
@@ -187,10 +241,8 @@ function redraw(svg, vis, data, ancestors, transitionTime, rootCoords) {
187241
function mouseout() {
188242
vis.selectAll('g.trace')
189243
.filter(function(d) { return d.waterfallDimmed; })
190-
.style('opacity', function() {
191-
return d3.select(this).classed('hidden') ? 0 : 1;
192-
})
193-
.each(function(d) { delete d.waterfallDimmed; });
244+
.each(function(d) { delete d.waterfallDimmed; })
245+
.style('opacity', alpha);
194246
}
195247

196248
function toggleCollapse(d, i) {
@@ -226,7 +278,7 @@ function redraw(svg, vis, data, ancestors, transitionTime, rootCoords) {
226278
}
227279

228280
function alpha(d) {
229-
return d.waterfallDimmed ? DIMMED_ALPHA : 1;
281+
return d.deleted ? 1e-6 : (d.waterfallDimmed ? DIMMED_ALPHA : 1);
230282
}
231283

232284
function redrawGrid(svg, x, transitionTime, height) {

0 commit comments

Comments
 (0)