Skip to content

Commit a01d644

Browse files
committed
moved text fromtool tip hover into history nodes
1 parent f8eaed7 commit a01d644

File tree

1 file changed

+35
-88
lines changed

1 file changed

+35
-88
lines changed

src/app/components/StateRoute/History.tsx

Lines changed: 35 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,15 @@ import { changeView, changeSlider, setCurrentTabInApp } from '../../slices/mainS
1414
*/
1515

1616
const defaultMargin: DefaultMargin = {
17-
top: 30,
17+
top: 60,
1818
left: 30,
1919
right: 55,
2020
bottom: 70,
2121
};
2222

2323
// Fixed node separation distances
24-
const FIXED_NODE_HEIGHT = 100; // Vertical distance between nodes
25-
const FIXED_NODE_WIDTH = 180; // Horizontal distance between nodes
24+
const FIXED_NODE_HEIGHT = 120; // Vertical distance between nodes
25+
const FIXED_NODE_WIDTH = 220; // Horizontal distance between nodes
2626

2727
// main function exported to StateRoute
2828
// below we destructure the props
@@ -117,6 +117,8 @@ function History(props: Record<string, unknown>): JSX.Element {
117117
return changedState; // return the changedState array with any and all stateful delta objects.
118118
}
119119

120+
if (index === 0) return ''; // Return empty string for initial state
121+
120122
const delta = diff(
121123
// 'diff' function from 'jsondiffpatch' returns the difference in state between the (snapshot that occurred before the indexed snapshot) and the (indexed snapshot).
122124
statelessCleaning(snapshots[index - 1]),
@@ -135,13 +137,9 @@ function History(props: Record<string, unknown>): JSX.Element {
135137
const svg = d3.select(svgRef.current);
136138
svg.selectAll('*').remove();
137139

138-
// Create tree layout with fixed node separation
139-
const treeLayout = d3.tree().nodeSize([FIXED_NODE_WIDTH, FIXED_NODE_HEIGHT]); // Set fixed sizes between nodes
140-
141-
// Calculate the tree structure
140+
const treeLayout = d3.tree().nodeSize([FIXED_NODE_WIDTH, FIXED_NODE_HEIGHT]);
142141
const d3root = treeLayout(d3.hierarchy(root));
143142

144-
// Calculate total required height and width
145143
let minX = Infinity;
146144
let maxX = -Infinity;
147145
let minY = Infinity;
@@ -157,16 +155,14 @@ function History(props: Record<string, unknown>): JSX.Element {
157155
const actualWidth = maxX - minX + FIXED_NODE_WIDTH;
158156
const actualHeight = maxY - minY + FIXED_NODE_HEIGHT;
159157

160-
// Set SVG size to accommodate the entire tree
161158
svg
162159
.attr('width', Math.max(actualWidth + margin.left + margin.right, totalWidth))
163160
.attr('height', Math.max(actualHeight + margin.top + margin.bottom, totalHeight));
164161

165-
// Center the root node horizontally
166162
const centerOffset = totalWidth / 2 - (maxX - minX) / 2;
167-
168163
const g = svg.append('g').attr('transform', `translate(${centerOffset},${margin.top})`);
169164

165+
// Draw links
170166
const link = g
171167
.selectAll('.link')
172168
.data(d3root.descendants().slice(1))
@@ -183,6 +179,7 @@ function History(props: Record<string, unknown>): JSX.Element {
183179
} ${d.parent.x},${d.parent.y}`,
184180
);
185181

182+
// Create node groups
186183
const node = g
187184
.selectAll('.node')
188185
.data(d3root.descendants())
@@ -194,92 +191,42 @@ function History(props: Record<string, unknown>): JSX.Element {
194191
const activeClass = d.data.index === currLocation.index ? ' active' : '';
195192
return baseClass + internalClass + activeClass;
196193
})
197-
.attr('transform', (d) => `translate(${d.x},${d.y})`);
194+
.attr('transform', (d) => `translate(${d.x},${d.y})`)
195+
.on('click', (event, d) => {
196+
dispatch(changeView(d.data.index));
197+
dispatch(changeSlider(d.data.index));
198+
});
198199

200+
// Add rectangles for nodes
199201
node
200202
.append('rect')
201-
.attr('width', 100) // Width of rectangle
202-
.attr('height', 40) // Height of rectangle
203-
.attr('x', -50) // Center the rectangle horizontally
204-
.attr('y', -20) // Center the rectangle vertically
205-
.attr('rx', 8) // Rounded corners
206-
.attr('ry', 8); // Rounded corners
207-
208-
// Add text with "Snapshot" prefix
203+
.attr('width', 180)
204+
.attr('height', 80)
205+
.attr('x', -90)
206+
.attr('y', -40)
207+
.attr('rx', 8)
208+
.attr('ry', 8);
209+
210+
// Add snapshot title
209211
node
210212
.append('text')
211-
.attr('dy', '0.31em')
213+
.attr('dy', '-25')
212214
.attr('text-anchor', 'middle')
215+
.attr('class', 'snapshot-title')
213216
.text((d) => `Snapshot ${d.data.index + 1}`);
214217

215-
// Add click handler for nodes
218+
// Add state changes text
216219
node
217-
.on('click', (event, d) => {
218-
dispatch(changeView(d.data.index));
219-
dispatch(changeSlider(d.data.index));
220-
221-
function renderToolTip() {
222-
const [x, y] = d3.pointer(event);
223-
const div = d3
224-
.select('.display:first-child')
225-
.append('div')
226-
.attr('class', `tooltip`)
227-
.attr('id', `tt-${d.data.index}`)
228-
.style('left', `${event.clientX - 10}px`)
229-
.style('top', `${event.clientY - 10}px`)
230-
.style('max-height', `25%`)
231-
.style('overflow', `scroll`);
232-
d3.selectAll('.tooltip').html(findDiff(d.data.index));
233-
}
234-
235-
if (d3.selectAll('.tooltip')._groups['0'].length === 0) {
236-
renderToolTip(); //if there are no tooltips left in the doc, we call the function to create a new tooltip
237-
} else {
238-
if (d3.selectAll(`#tt-${d.data.index}`)._groups['0'].length === 0) {
239-
// if there is no tooltip with the specific id
240-
d3.selectAll('.tooltip').remove(); //remove any existing tooltips
241-
renderToolTip(); //call the function again to create a new tooltip
242-
}
243-
}
244-
})
245-
.on('mouseenter', function (event, d) {
246-
if (d.data.index === 0) return;
247-
d3.selectAll('.tooltip').remove();
248-
const [x, y] = d3.pointer(event);
249-
if (d3.selectAll('.tooltip')._groups['0'].length === 0) {
250-
const div = d3
251-
.select('.display:first-child')
252-
.append('div')
253-
.attr('class', `tooltip`)
254-
.attr('id', `tt-${d.data.index}`)
255-
.style('left', `${event.clientX + 30}px`)
256-
.style('top', `${event.clientY - 75}px`)
257-
.style('max-height', `25%`)
258-
.style('overflow', `auto`)
259-
.on('mouseenter', function (event, d) {
260-
d3.select(this).interrupt(); // Interrupt any ongoing transitions
261-
})
262-
.on('mouseleave', function (event, d) {
263-
d3.selectAll('.tooltip').remove().style('display', 'hidden');
264-
});
265-
266-
d3.selectAll('.tooltip').html(findDiff(d.data.index));
267-
}
268-
})
269-
.on('mouseleave', function (event, d) {
270-
if (event.relatedTarget.id !== `tt-${d.data.index}`) {
271-
d3.selectAll('.tooltip').transition().delay(0).remove();
272-
}
273-
});
274-
275-
const tooltip = d3
276-
.select('.tooltip')
277-
.on('mousemove', function (event, d) {
278-
d3.select('.tooltip').style('opacity', '1');
279-
})
280-
.on('mouseleave', function (event, d) {
281-
d3.selectAll('.tooltip').remove();
282-
});
220+
.append('foreignObject')
221+
.attr('x', -85)
222+
.attr('y', -15)
223+
.attr('width', 170)
224+
.attr('height', 65)
225+
.append('xhtml:div')
226+
.style('font-size', '12px')
227+
.style('overflow', 'hidden')
228+
.style('text-align', 'center')
229+
.html((d) => findDiff(d.data.index));
283230

284231
return svg.node();
285232
};

0 commit comments

Comments
 (0)