Skip to content

Commit 7eba67e

Browse files
committed
improved zoom and drag
1 parent 9d2c59e commit 7eba67e

File tree

3 files changed

+88
-63
lines changed

3 files changed

+88
-63
lines changed

src/app/components/Map.tsx

Lines changed: 83 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -9,32 +9,37 @@ import * as d3 from 'd3';
99

1010

1111
const Map = (props) => {
12-
const { snapshot, snapshots } = props;
13-
const lastSnap = snapshots.length - 1;
14-
15-
const width = 2000;
16-
const height = 600;
17-
const margin = { top: 10, right: 120, bottom: 10, left: 120 };
18-
const dy = 100;
19-
const dx = 76;
20-
const data = snapshots[lastSnap];
21-
const tree = d3.tree().nodeSize([dx, dy]);
22-
const diagonal = d3
23-
.linkHorizontal()
24-
.x((d) => d.y)
25-
.y((d) => d.x);
26-
27-
12+
const { viewIndex, snapshots } = props;
13+
14+
let lastSnap: number | null = null;
15+
if (viewIndex < 0) lastSnap = snapshots.length - 1;
16+
else lastSnap = viewIndex;
17+
18+
19+
const width: number = 900;
20+
const height: number = 600;
21+
let data = snapshots[lastSnap];
22+
2823

2924
useEffect(() => {
30-
document.getElementById('canvas').innerHTML = '_';
31-
return makeChart();
25+
document.getElementById('canvas').innerHTML = '_';
26+
return makeChart(data);
3227
});
3328

34-
const makeChart = () => {
35-
29+
const makeChart = React.useCallback ( (data) => {
30+
31+
// Establish Constants
32+
const margin = { top: 10, right: 120, bottom: 10, left: 120 };
33+
const dy = 100;
34+
const dx = 100;
35+
const tree = d3.tree().nodeSize([dx, dy]);
36+
const diagonal = d3
37+
.linkHorizontal()
38+
.x((d) => d.y)
39+
.y((d) => d.x);
3640
const root = d3.hierarchy(data);
3741

42+
// Determine descendants of root node use d.depth conditional to how many levels deep to display on first render
3843
root.x0 = dy / 2;
3944
root.y0 = 0;
4045
root.descendants().forEach((d, i) => {
@@ -43,46 +48,50 @@ const Map = (props) => {
4348
if (d.depth === 9) d.children = null;
4449
});
4550

46-
console.log("root", root)
47-
48-
const svg = d3
51+
52+
// Create Container for D3 Visualizations
53+
const svgContainer = d3
4954
.select('#canvas')
5055
.attr('width', width)
5156
.attr('height', height)
52-
// .attr('viewBox', [-margin.left, -margin.top, width, dx])
53-
// .style('font', '10px sans-serif')
54-
// .style('user-select', 'none');
5557

58+
// create inner container to help with drag and zoom
59+
const svg: any = svgContainer
60+
.append('g')
61+
62+
// create links
5663
const gLink = svg
5764
.append('g')
5865
.attr('fill', 'none')
5966
.attr('stroke', '#555')
6067
.attr('stroke-opacity', 0.9)
6168
.attr('stroke-width', 1.5);
6269

70+
// create nodes
6371
const gNode = svg
6472
.append('g')
6573
.attr('cursor', 'pointer')
6674
.attr('pointer-events', 'all');
6775

76+
// declare re render funciton to handle collapse and expansion of nodes
6877
function update(source) {
6978
const duration = d3.event && d3.event.altKey ? 2500 : 250;
7079
const nodes = root.descendants().reverse();
7180
const links = root.links();
7281

7382
// Compute the new tree layout.
7483
tree(root);
75-
76-
console.log("tree",tree(root))
7784
let left = root;
7885
let right = root;
7986
root.eachBefore((node) => {
8087
if (node.x < left.x) left = node;
8188
if (node.x > right.x) right = node;
8289
});
8390

84-
const height = right.x - left.x + margin.top + margin.bottom;
91+
//use nodes to detrmine height
92+
const height = right.x - left.x + margin.top + margin.bottom;
8593

94+
// transition between past and present
8695
const transition = svg
8796
.transition()
8897
.duration(duration)
@@ -98,37 +107,59 @@ const Map = (props) => {
98107
.append('g')
99108
.attr('transform', (d) => `translate(${source.y0},${source.x0})`)
100109
.attr('fill-opacity', 0)
101-
// .attr('stroke-linejoin', 'round')
102110
.attr('stroke-opacity', 1)
103111
.on('click', (d) => {
104112
d.children = d.children ? null : d._children;
105113
update(d);
106114
});
107-
115+
116+
// paint circles, color based on children
108117
nodeEnter
109118
.append('circle')
110119
.attr('r', 10)
111120
.attr('fill', (d) => (d._children ? '#46edf2': '#95B6B7' ))
112-
//.attr('stroke-linejoin', 'round')
113121
.attr('stroke-width', 10)
114122
.attr('stroke-opacity', 1);
115-
116-
123+
124+
// append node names
117125
nodeEnter
118126
.append('text')
119127
.attr('dy', '.31em')
120-
.attr('x', (d: any) => (d.children ? -50 : 50))
121-
.attr('text-anchor', (d: any) => (d.children ? 'end' : 'start'))
122-
.text((d: any) => d.data.name)
123-
.style('font-size', `.8rem`)
128+
.attr('x', '-10')
129+
.attr('y', '-5')
130+
.attr('text-anchor','end' )
131+
.text((d: any) => d.data.name.slice(0,14))
132+
.style('font-size', `.6rem`)
124133
.style('fill', 'white')
125134
.clone(true)
126135
.lower()
127136
.attr("stroke-linejoin", "round")
128137
.attr('stroke', '#646464')
129-
.attr('stroke-width', 2);
138+
.attr('stroke-width', 1);
139+
140+
// display the data in the node on hover
141+
142+
nodeEnter.on('mouseover', function (d: any, i: number): any {
143+
if (!d.children) {
144+
d3.select(this)
145+
.append('text')
146+
.text(()=>{
147+
console.log(d)
148+
return JSON.stringify(d.data)})
149+
.style('fill', 'white')
150+
.attr('x',0)
151+
.attr('y', 0)
152+
.style('font-size', '.6rem')
153+
.style('text-align', 'center')
154+
.attr('stroke', '#646464')
155+
.attr('id', `popup${i}`);
156+
}
157+
});
158+
159+
nodeEnter.on('mouseout', function (d: any, i: number): any {
160+
d3.select(`#popup${i}`).remove();
161+
});
130162

131-
132163
// Transition nodes to their new position.
133164
const nodeUpdate = node
134165
.merge(nodeEnter)
@@ -153,7 +184,6 @@ const Map = (props) => {
153184
const linkEnter = link
154185
.enter()
155186
.append('path')
156-
//.selectAll('path')
157187
.attr('d', (d) => {
158188
const o = { x: source.x0, y: source.y0 };
159189
return diagonal({ source: o, target: o });
@@ -182,17 +212,16 @@ const Map = (props) => {
182212

183213
//______________ZOOM______________\\
184214

185-
// Sets starting zoom but breaks keeping currents zoom on state change
186-
187-
// let zoom = d3.zoom().on('zoom', zoomed);
188-
// svgContainer.call(
189-
// zoom.transform,
190-
// // Changes the initial view, (left, top)
191-
// d3.zoomIdentity.translate(150, 250).scale(0.2)
192-
// );
215+
// Sets starting zoom
216+
let zoom = d3.zoom().on('zoom', zoomed);
217+
svgContainer.call(
218+
zoom.transform,
219+
// Changes the initial view, (left, top)
220+
d3.zoomIdentity.translate(150, 250).scale(0.6)
221+
);
193222

194-
// allows the canvas to be zoom-able
195-
svg.call(
223+
// allows the canvas to be zoom-able
224+
svgContainer.call(
196225
d3
197226
.zoom()
198227
.scaleExtent([0.15, 1.5]) // [zoomOut, zoomIn]
@@ -210,7 +239,6 @@ const Map = (props) => {
210239
.on('drag', dragged)
211240
.on('end', dragEnded)
212241
);
213-
214242
function dragStarted(): any {
215243
d3.select(this).raise();
216244
svg.attr('cursor', 'grabbing');
@@ -223,11 +251,10 @@ const Map = (props) => {
223251
function dragEnded(): any {
224252
svg.attr('cursor', 'grab');
225253
}
226-
227-
228-
254+
255+
// call update on node click
229256
update(root);
230-
};
257+
}, [data]);
231258
// // set the heights and width of the tree to be passed into treeMap function
232259
// const width: number = 900;
233260
// const height: number = 600;

src/app/components/PerfView.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,8 @@ const PerfView = (props: PerfViewProps) => {
4545
if (viewIndex < 0) indexToDisplay = snapshots.length - 1;
4646
else indexToDisplay = viewIndex;
4747

48-
console.log('SNAPSHOTS IN PERF VIEW', snapshots);
49-
console.log('VIEW INDEX', indexToDisplay);
48+
//console.log('SNAPSHOTS IN PERF VIEW', snapshots);
49+
//console.log('VIEW INDEX', indexToDisplay);
5050

5151
// Set up color scaling function
5252
const colorScale = d3

src/app/components/StateRoute.tsx

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ const StateRoute = (props: StateRouteProps) => {
4343
//Test Map
4444
const renderMap = () => {
4545
if (hierarchy) {
46-
return <Map snapshot={snapshot} snapshots={snapshots} />;
46+
return <Map viewIndex={viewIndex} snapshots={snapshots} />;
4747
}
4848
return <div className="noState">{NO_STATE_MSG}</div>;
4949
};
@@ -67,12 +67,10 @@ const StateRoute = (props: StateRouteProps) => {
6767
}
6868
return <div className="noState">{NO_STATE_MSG}</div>;
6969
};
70-
console.log('NORENDER DATA', noRenderData);
70+
7171
let perfChart;
7272
if (true) {
73-
console.log('ViewINDex', viewIndex);
74-
console.log('snapshots', snapshots);
75-
console.log('setnorenderdata', setNoRenderData);
73+
7674
perfChart = (
7775
<PerfView
7876
viewIndex={viewIndex}

0 commit comments

Comments
 (0)