Skip to content

Commit

Permalink
Update TimelineGraph.tsx
Browse files Browse the repository at this point in the history
  • Loading branch information
LPeter1997 committed Sep 21, 2023
1 parent 2e78c1b commit bd3983c
Showing 1 changed file with 86 additions and 67 deletions.
153 changes: 86 additions & 67 deletions src/Draco.Trace.Visualizer/src/TimelineGraph.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,80 +19,99 @@ const TimelineGraph = (props: Props) => {
const [width, setWidth] = React.useState(props.width);
const [height, setHeight] = React.useState(props.height);

React.useEffect(() => {
const svg = d3
.select(domRef.current)
.attr('width', width)
.attr('height', height);

const messageHierarchy = d3.hierarchy(toTimelineMessage(data.rootMessage), getTimelineChildren);
messageHierarchy.sum(node => node.children && node.children.length > 0 ? 0 : getTimeSpan(node));

const partitionLayout = d3
.partition<TimelineMessageModel>()
.size([width, height])
.padding(2);

let laidOutMessages = partitionLayout(messageHierarchy);

const colorScale = d3.interpolateHsl('green', 'red');

const allNodes = svg
.selectAll('g')
.data(laidOutMessages.descendants())
.enter()
.append('g');

allNodes
.append('rect')
.attr('x', node => node.x0)
.attr('y', node => height - node.y1)
.attr('width', node => node.x1 - node.x0)
.attr('height', node => node.y1 - node.y0)
.attr('fill', node => {
if (node.data.isPlaceholder) return 'transparent';
const fillPercentage = node.parent
? getTimeSpan(node.data) / getTimeSpan(node.parent.data)
: 1;
return colorScale(fillPercentage);
});

const wideNodes = allNodes
.filter(node => !node.data.isPlaceholder)
.filter(node => node.x1 - node.x0 > 5);

wideNodes
.append('text')
.text(node => node.data.name)
.attr('color', 'black')
.attr('dominant-baseline', 'middle')
.attr('text-anchor', 'middle')
.attr('x', node => node.x0 + (node.x1 - node.x0) / 2)
.attr('y', node => height - node.y1 + (node.y1 - node.y0) / 2);

allNodes.on('click', function (svg, node) {
d3
.select(this)
.select('rect')
.transition()
.duration(500)
.attr('width', (d: any) => width)
.attr('x', (d: any) => 0);
d3
.select(this)
.select('text')
.transition()
.duration(500)
.attr('x', (d: any) => width / 2);
});
}, [data, width, height]);
React.useEffect(() => buildGraph(domRef, props), [data, width, height]);

return (
<svg ref={domRef}>
</svg>
);
};

function buildGraph(domRef: React.MutableRefObject<null>, props: Props) {
const svg = d3
.select(domRef.current)
.attr('width', props.width)
.attr('height', props.height);

const messageHierarchy = d3.hierarchy(toTimelineMessage(props.data.rootMessage), getTimelineChildren);
messageHierarchy.sum(node => node.children && node.children.length > 0 ? 0 : getTimeSpan(node));

const partitionLayout = d3
.partition<TimelineMessageModel>()
.size([props.width, props.height])
.padding(2);

let laidOutMessages = partitionLayout(messageHierarchy);

const colorScale = d3.interpolateHsl('green', 'red');

// Groups of rect and text
const allGroups = svg
.selectAll('g')
.data(laidOutMessages.descendants())
.enter()
.append('g');

// Rects
const allRects = allGroups
.append('rect')
.attr('x', node => node.x0)
.attr('y', node => props.height - node.y1)
.attr('width', node => node.x1 - node.x0)
.attr('height', node => node.y1 - node.y0)
.attr('fill', node => {
if (node.data.isPlaceholder) return 'transparent';
const fillPercentage = node.parent
? getTimeSpan(node.data) / getTimeSpan(node.parent.data)
: 1;
return colorScale(fillPercentage);
});

// Texts
const allTexts = allGroups
.append('text')
.text(node => node.data.name)
.attr('color', 'black')
.attr('dominant-baseline', 'middle')
.attr('text-anchor', 'middle')
.attr('x', node => node.x0 + (node.x1 - node.x0) / 2)
.attr('y', node => props.height - node.y1 + (node.y1 - node.y0) / 2);

allRects.on('click', function (svg, node) {
focus(node);

const transition = d3
.transition()
.duration(500);
allRects
.transition(transition)
.attr('x', (node: any) => node.target ? node.target.x0 : node.x0)
.attr('width', (node: any) => node.target ? (node.target.x1 - node.target.x0) : (node.x1 - node.x0));
});
}

function focus(node: d3.HierarchyRectangularNode<TimelineMessageModel>) {
function resize(node: d3.HierarchyRectangularNode<TimelineMessageModel>, x0: number, x1: number) {
(node as any).target = {
x0,
y0: node.y0,
x1,
y1: node.y1,
};
}

// Find root
let root = node;
while (root.parent) root = root.parent;

// Walk up the ancestry chain, expand
let current = node;
while (current.parent) {
resize(current, root.x0, root.x1);
current = current.parent;
}
}

function getTimeSpan(msg: MessageModel): number {
return msg.endTime - msg.startTime;
}
Expand Down

0 comments on commit bd3983c

Please sign in to comment.