plebeiangraphlibrary 2.1.2 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Build/Drawing/GraphDrawer.d.ts +19 -0
- package/Build/Drawing/InteractionLayer.d.ts +76 -0
- package/Build/index.d.ts +2 -0
- package/Build/pgl.js +170 -170
- package/Build/pgl.js.map +1 -1
- package/Build/pgl_module.js +2493 -2311
- package/Build/pgl_module.js.map +1 -1
- package/Examples/14_Interaction_click.html +82 -0
- package/Examples/15_Interaction_hover.html +93 -0
- package/Examples/16_Interaction_details.html +92 -0
- package/Examples/17_Interaction_drag.html +66 -0
- package/Examples/examples.html +20 -0
- package/README.md +69 -2
- package/package.json +1 -1
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
|
|
4
|
+
<head>
|
|
5
|
+
<meta charset="UTF-8" />
|
|
6
|
+
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
|
7
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
8
|
+
<link rel="stylesheet" href="MasterStyle.css">
|
|
9
|
+
<title>Example 14 – Interaction (click)</title>
|
|
10
|
+
<style>
|
|
11
|
+
.info-panel {
|
|
12
|
+
position: absolute;
|
|
13
|
+
top: 1rem;
|
|
14
|
+
right: 1rem;
|
|
15
|
+
width: 220px;
|
|
16
|
+
padding: 0.75rem;
|
|
17
|
+
background: rgba(26, 26, 26, 0.9);
|
|
18
|
+
border: 1px solid var(--border);
|
|
19
|
+
border-radius: 8px;
|
|
20
|
+
font-size: 0.85rem;
|
|
21
|
+
font-family: monospace;
|
|
22
|
+
}
|
|
23
|
+
.info-panel h3 { margin: 0 0 0.5rem; font-size: 0.9rem; color: var(--teal); }
|
|
24
|
+
.info-panel p { margin: 0.25rem 0; }
|
|
25
|
+
.canvas-wrap { position: relative; }
|
|
26
|
+
</style>
|
|
27
|
+
</head>
|
|
28
|
+
|
|
29
|
+
<body class="example-page">
|
|
30
|
+
<header class="example-header">
|
|
31
|
+
<a href="examples.html" class="back-link">← All examples</a>
|
|
32
|
+
<h1>Example 14 – Interaction (click)</h1>
|
|
33
|
+
<p class="example-desc">Opt-in interaction: click nodes or edges to see graph details in the panel. Uses enableInteraction() with onNodeClick and onEdgeClick.</p>
|
|
34
|
+
<a href="https://github.com/range-et/PGL/blob/main/Examples/14_Interaction_click.html" class="code-link" target="_blank" rel="noopener">View code</a>
|
|
35
|
+
</header>
|
|
36
|
+
<div class="canvas-wrap">
|
|
37
|
+
<div id="infoPanel" class="info-panel">
|
|
38
|
+
<h3>Click a node or edge</h3>
|
|
39
|
+
<p id="infoText">Details will appear here.</p>
|
|
40
|
+
</div>
|
|
41
|
+
<canvas id="displayCanvas" class="displayCanvas"></canvas>
|
|
42
|
+
<script type="module">
|
|
43
|
+
// Opt-in interaction layer: call enableInteraction() to add click/hover support.
|
|
44
|
+
// Callbacks receive graph details (nodeId, neighbours, position, edge start/end, etc.).
|
|
45
|
+
import * as PGL from "../Build/pgl_module.js";
|
|
46
|
+
|
|
47
|
+
const G = await PGL.SampleData.LoadZKCSimulated();
|
|
48
|
+
const width = 800;
|
|
49
|
+
const height = 700;
|
|
50
|
+
const canvas = document.getElementById("displayCanvas");
|
|
51
|
+
const infoText = document.getElementById("infoText");
|
|
52
|
+
|
|
53
|
+
const graph3d = new PGL.GraphDrawer.GraphDrawer3d({ graph: G, width, height, canvas });
|
|
54
|
+
await graph3d.init();
|
|
55
|
+
|
|
56
|
+
const bounds = 1;
|
|
57
|
+
const nodeVisualElements = PGL.ThreeWrapper.DrawTHREEBoxBasedVertices(G, bounds, 0xffffff, 5);
|
|
58
|
+
const edgeVisualElements = PGL.ThreeWrapper.DrawTHREEGraphEdgesThick(G, bounds, 0xffafcc, 10);
|
|
59
|
+
graph3d.addVisElement(nodeVisualElements);
|
|
60
|
+
graph3d.addVisElement(edgeVisualElements);
|
|
61
|
+
|
|
62
|
+
// Enable opt-in interaction — pass graph and callbacks
|
|
63
|
+
graph3d.enableInteraction({
|
|
64
|
+
graph: G,
|
|
65
|
+
onNodeClick: (d) => {
|
|
66
|
+
infoText.innerHTML = `Node <b>${d.nodeId}</b><br>Neighbours: ${d.neighbours.length}<br>Position: (${d.position?.x?.toFixed(2) ?? "?"}, ${d.position?.y?.toFixed(2) ?? "?"}, ${d.position?.z?.toFixed(2) ?? "?"})`;
|
|
67
|
+
},
|
|
68
|
+
onEdgeClick: (d) => {
|
|
69
|
+
infoText.innerHTML = `Edge <b>${d.edgeId}</b><br>Connects: ${d.start} → ${d.end}`;
|
|
70
|
+
},
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
function animate() {
|
|
74
|
+
requestAnimationFrame(animate);
|
|
75
|
+
graph3d.rendercall();
|
|
76
|
+
}
|
|
77
|
+
animate();
|
|
78
|
+
</script>
|
|
79
|
+
</div>
|
|
80
|
+
</body>
|
|
81
|
+
|
|
82
|
+
</html>
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
|
|
4
|
+
<head>
|
|
5
|
+
<meta charset="UTF-8" />
|
|
6
|
+
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
|
7
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
8
|
+
<link rel="stylesheet" href="MasterStyle.css">
|
|
9
|
+
<title>Example 15 – Interaction (hover)</title>
|
|
10
|
+
<style>
|
|
11
|
+
.info-panel {
|
|
12
|
+
position: absolute;
|
|
13
|
+
top: 1rem;
|
|
14
|
+
right: 1rem;
|
|
15
|
+
width: 220px;
|
|
16
|
+
padding: 0.75rem;
|
|
17
|
+
background: rgba(26, 26, 26, 0.9);
|
|
18
|
+
border: 1px solid var(--border);
|
|
19
|
+
border-radius: 8px;
|
|
20
|
+
font-size: 0.85rem;
|
|
21
|
+
font-family: monospace;
|
|
22
|
+
}
|
|
23
|
+
.info-panel h3 { margin: 0 0 0.5rem; font-size: 0.9rem; color: var(--teal); }
|
|
24
|
+
.info-panel p { margin: 0.25rem 0; }
|
|
25
|
+
.canvas-wrap { position: relative; }
|
|
26
|
+
</style>
|
|
27
|
+
</head>
|
|
28
|
+
|
|
29
|
+
<body class="example-page">
|
|
30
|
+
<header class="example-header">
|
|
31
|
+
<a href="examples.html" class="back-link">← All examples</a>
|
|
32
|
+
<h1>Example 15 – Interaction (hover)</h1>
|
|
33
|
+
<p class="example-desc">Hover over nodes or edges to see details in the panel. Uses onNodeHover and onEdgeHover callbacks. Auto-rotate disabled for easier hovering.</p>
|
|
34
|
+
<a href="https://github.com/range-et/PGL/blob/main/Examples/15_Interaction_hover.html" class="code-link" target="_blank" rel="noopener">View code</a>
|
|
35
|
+
</header>
|
|
36
|
+
<div class="canvas-wrap">
|
|
37
|
+
<div id="infoPanel" class="info-panel">
|
|
38
|
+
<h3>Hover a node or edge</h3>
|
|
39
|
+
<p id="infoText">Details appear here when you hover.</p>
|
|
40
|
+
</div>
|
|
41
|
+
<canvas id="displayCanvas" class="displayCanvas"></canvas>
|
|
42
|
+
<script type="module">
|
|
43
|
+
// Hover callbacks: onNodeHover(details) and onEdgeHover(details) fire when pointer moves.
|
|
44
|
+
// Pass null when pointer leaves a node/edge.
|
|
45
|
+
import * as PGL from "../Build/pgl_module.js";
|
|
46
|
+
|
|
47
|
+
const G = await PGL.SampleData.LoadZKCSimulated();
|
|
48
|
+
const width = 800;
|
|
49
|
+
const height = 700;
|
|
50
|
+
const canvas = document.getElementById("displayCanvas");
|
|
51
|
+
const infoText = document.getElementById("infoText");
|
|
52
|
+
|
|
53
|
+
const graph3d = new PGL.GraphDrawer.GraphDrawer3d({ graph: G, width, height, canvas });
|
|
54
|
+
await graph3d.init();
|
|
55
|
+
|
|
56
|
+
// Disable auto-rotate so the graph stays still for easier hovering
|
|
57
|
+
graph3d.controls.autoRotate = false;
|
|
58
|
+
|
|
59
|
+
const bounds = 1;
|
|
60
|
+
const nodeVisualElements = PGL.ThreeWrapper.DrawTHREEBoxBasedVertices(G, bounds, 0xffffff, 8);
|
|
61
|
+
const edgeVisualElements = PGL.ThreeWrapper.DrawTHREEGraphEdgesThick(G, bounds, 0xffafcc, 10);
|
|
62
|
+
graph3d.addVisElement(nodeVisualElements);
|
|
63
|
+
graph3d.addVisElement(edgeVisualElements);
|
|
64
|
+
|
|
65
|
+
graph3d.enableInteraction({
|
|
66
|
+
graph: G,
|
|
67
|
+
hoverEnabled: true,
|
|
68
|
+
onNodeHover: (d) => {
|
|
69
|
+
if (d) {
|
|
70
|
+
infoText.innerHTML = `Node <b>${d.nodeId}</b><br>Neighbours: ${d.neighbours.length}<br>Position: (${d.position?.x?.toFixed(2) ?? "?"}, ${d.position?.y?.toFixed(2) ?? "?"}, ${d.position?.z?.toFixed(2) ?? "?"})`;
|
|
71
|
+
} else {
|
|
72
|
+
infoText.innerHTML = "Hover a node or edge";
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
|
+
onEdgeHover: (d) => {
|
|
76
|
+
if (d) {
|
|
77
|
+
infoText.innerHTML = `Edge <b>${d.edgeId}</b><br>Connects: ${d.start} → ${d.end}`;
|
|
78
|
+
} else {
|
|
79
|
+
infoText.innerHTML = "Hover a node or edge";
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
function animate() {
|
|
85
|
+
requestAnimationFrame(animate);
|
|
86
|
+
graph3d.rendercall();
|
|
87
|
+
}
|
|
88
|
+
animate();
|
|
89
|
+
</script>
|
|
90
|
+
</div>
|
|
91
|
+
</body>
|
|
92
|
+
|
|
93
|
+
</html>
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
|
|
4
|
+
<head>
|
|
5
|
+
<meta charset="UTF-8" />
|
|
6
|
+
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
|
7
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
8
|
+
<link rel="stylesheet" href="MasterStyle.css">
|
|
9
|
+
<title>Example 16 – Interaction (highlight neighbours)</title>
|
|
10
|
+
<style>
|
|
11
|
+
.info-panel {
|
|
12
|
+
position: absolute;
|
|
13
|
+
top: 1rem;
|
|
14
|
+
right: 1rem;
|
|
15
|
+
width: 240px;
|
|
16
|
+
padding: 0.75rem;
|
|
17
|
+
background: rgba(26, 26, 26, 0.9);
|
|
18
|
+
border: 1px solid var(--border);
|
|
19
|
+
border-radius: 8px;
|
|
20
|
+
font-size: 0.85rem;
|
|
21
|
+
font-family: monospace;
|
|
22
|
+
}
|
|
23
|
+
.info-panel h3 { margin: 0 0 0.5rem; font-size: 0.9rem; color: var(--teal); }
|
|
24
|
+
.info-panel p { margin: 0.25rem 0; }
|
|
25
|
+
.canvas-wrap { position: relative; }
|
|
26
|
+
</style>
|
|
27
|
+
</head>
|
|
28
|
+
|
|
29
|
+
<body class="example-page">
|
|
30
|
+
<header class="example-header">
|
|
31
|
+
<a href="examples.html" class="back-link">← All examples</a>
|
|
32
|
+
<h1>Example 16 – Interaction (highlight neighbours)</h1>
|
|
33
|
+
<p class="example-desc">Hover a node to highlight its neighbours. Combines enableInteraction with ChangeTheVertexColours.</p>
|
|
34
|
+
<a href="https://github.com/range-et/PGL/blob/main/Examples/16_Interaction_details.html" class="code-link" target="_blank" rel="noopener">View code</a>
|
|
35
|
+
</header>
|
|
36
|
+
<div class="canvas-wrap">
|
|
37
|
+
<div id="infoPanel" class="info-panel">
|
|
38
|
+
<h3>Hover a node</h3>
|
|
39
|
+
<p id="infoText">Its neighbours will be highlighted in red.</p>
|
|
40
|
+
</div>
|
|
41
|
+
<canvas id="displayCanvas" class="displayCanvas"></canvas>
|
|
42
|
+
<script type="module">
|
|
43
|
+
// Rich interaction: use NodePickDetails to drive visual feedback.
|
|
44
|
+
// ChangeTheVertexColours highlights neighbour nodes by node ID.
|
|
45
|
+
import * as PGL from "../Build/pgl_module.js";
|
|
46
|
+
|
|
47
|
+
const G = await PGL.SampleData.LoadZKCSimulated();
|
|
48
|
+
const width = 800;
|
|
49
|
+
const height = 700;
|
|
50
|
+
const canvas = document.getElementById("displayCanvas");
|
|
51
|
+
const infoText = document.getElementById("infoText");
|
|
52
|
+
|
|
53
|
+
const graph3d = new PGL.GraphDrawer.GraphDrawer3d({ graph: G, width, height, canvas });
|
|
54
|
+
await graph3d.init();
|
|
55
|
+
|
|
56
|
+
graph3d.controls.autoRotate = false;
|
|
57
|
+
|
|
58
|
+
const bounds = 1;
|
|
59
|
+
const nodeVisualElements = PGL.ThreeWrapper.DrawTHREEGraphVertices(G, bounds, 8, 0xffffff, 1);
|
|
60
|
+
const edgeMap = G.get_edge_map();
|
|
61
|
+
const edgeVisualElements = PGL.ThreeWrapper.DrawThinEdgesFromEdgeMap(edgeMap, bounds, 0x5fa8d3);
|
|
62
|
+
graph3d.addVisElement(nodeVisualElements);
|
|
63
|
+
graph3d.addVisElement(edgeVisualElements);
|
|
64
|
+
|
|
65
|
+
const HIGHLIGHT_COLOR = 0xff4444;
|
|
66
|
+
|
|
67
|
+
graph3d.enableInteraction({
|
|
68
|
+
graph: G,
|
|
69
|
+
hoverEnabled: true,
|
|
70
|
+
onNodeHover: (d) => {
|
|
71
|
+
PGL.ThreeWrapper.ResetVertexColors(nodeVisualElements.children[0]);
|
|
72
|
+
if (d) {
|
|
73
|
+
if (d.neighbours.length > 0) {
|
|
74
|
+
PGL.ThreeWrapper.ChangeTheVertexColours(nodeVisualElements.children[0], d.neighbours, HIGHLIGHT_COLOR);
|
|
75
|
+
}
|
|
76
|
+
infoText.innerHTML = `Node <b>${d.nodeId}</b><br>Degree: ${d.neighbours.length}<br>Neighbours highlighted in red`;
|
|
77
|
+
} else {
|
|
78
|
+
infoText.innerHTML = "Hover a node";
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
function animate() {
|
|
84
|
+
requestAnimationFrame(animate);
|
|
85
|
+
graph3d.rendercall();
|
|
86
|
+
}
|
|
87
|
+
animate();
|
|
88
|
+
</script>
|
|
89
|
+
</div>
|
|
90
|
+
</body>
|
|
91
|
+
|
|
92
|
+
</html>
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
|
|
4
|
+
<head>
|
|
5
|
+
<meta charset="UTF-8" />
|
|
6
|
+
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
|
7
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
8
|
+
<link rel="stylesheet" href="MasterStyle.css">
|
|
9
|
+
<title>Example 17 – Interaction (drag nodes)</title>
|
|
10
|
+
</head>
|
|
11
|
+
|
|
12
|
+
<body class="example-page">
|
|
13
|
+
<header class="example-header">
|
|
14
|
+
<a href="examples.html" class="back-link">← All examples</a>
|
|
15
|
+
<h1>Example 17 – Interaction (drag nodes)</h1>
|
|
16
|
+
<p class="example-desc">Drag cubes to reposition nodes. Uses enableNodeDrag and onNodeDrag with mutable box vertices and edges.</p>
|
|
17
|
+
<a href="https://github.com/range-et/PGL/blob/main/Examples/17_Interaction_drag.html" class="code-link" target="_blank" rel="noopener">View code</a>
|
|
18
|
+
</header>
|
|
19
|
+
<div class="canvas-wrap">
|
|
20
|
+
<canvas id="displayCanvas" class="displayCanvas"></canvas>
|
|
21
|
+
<script type="module">
|
|
22
|
+
import * as PGL from "../Build/pgl_module.js";
|
|
23
|
+
|
|
24
|
+
const G = await PGL.SampleData.LoadZKCSimulated();
|
|
25
|
+
const width = 800;
|
|
26
|
+
const height = 700;
|
|
27
|
+
const canvas = document.getElementById("displayCanvas");
|
|
28
|
+
|
|
29
|
+
const graph3d = new PGL.GraphDrawer.GraphDrawer3d({ graph: G, width, height, canvas });
|
|
30
|
+
await graph3d.init();
|
|
31
|
+
|
|
32
|
+
graph3d.controls.autoRotate = false;
|
|
33
|
+
|
|
34
|
+
const bounds = 1;
|
|
35
|
+
const { group: nodeGroup, updatePositions } = PGL.ThreeWrapper.DrawTHREEBoxBasedVerticesMutable(G, bounds, 0xffffff, 5);
|
|
36
|
+
const { group: edgeGroup, updateEdges } = PGL.ThreeWrapper.DrawTHREEGraphEdgesThinMutable(G, bounds, 0xffafcc);
|
|
37
|
+
graph3d.addVisElement(nodeGroup);
|
|
38
|
+
graph3d.addVisElement(edgeGroup);
|
|
39
|
+
|
|
40
|
+
graph3d.enableInteraction({
|
|
41
|
+
graph: G,
|
|
42
|
+
enableNodeDrag: true,
|
|
43
|
+
onNodeDrag: (nodeId, newPos) => {
|
|
44
|
+
const node = G.nodes.get(nodeId);
|
|
45
|
+
if (node?.data?.pos) {
|
|
46
|
+
node.data.pos.x = newPos.x;
|
|
47
|
+
node.data.pos.y = newPos.y;
|
|
48
|
+
node.data.pos.z = newPos.z;
|
|
49
|
+
}
|
|
50
|
+
const lmap = PGL.Drawing.DrawEdgeLinesDivisions(G, 1);
|
|
51
|
+
G.apply_edge_pos_maps(lmap);
|
|
52
|
+
updatePositions(G.get_position_map());
|
|
53
|
+
updateEdges();
|
|
54
|
+
},
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
function animate() {
|
|
58
|
+
requestAnimationFrame(animate);
|
|
59
|
+
graph3d.rendercall();
|
|
60
|
+
}
|
|
61
|
+
animate();
|
|
62
|
+
</script>
|
|
63
|
+
</div>
|
|
64
|
+
</body>
|
|
65
|
+
|
|
66
|
+
</html>
|
package/Examples/examples.html
CHANGED
|
@@ -79,6 +79,26 @@
|
|
|
79
79
|
<div class="title">Stress SGD 3D (Stanford Bunny mesh)</div>
|
|
80
80
|
<p class="desc">3D stress layout from a mesh: OBJ → graph (vertices + edges), initial positions = mesh. Layout refines in 3D so the shape stays bunny-like.</p>
|
|
81
81
|
</a>
|
|
82
|
+
<a href="14_Interaction_click.html" class="example-card">
|
|
83
|
+
<div class="num">Example 14</div>
|
|
84
|
+
<div class="title">Interaction (click)</div>
|
|
85
|
+
<p class="desc">Opt-in interaction: click nodes or edges to see graph details. Uses enableInteraction() with onNodeClick and onEdgeClick callbacks.</p>
|
|
86
|
+
</a>
|
|
87
|
+
<a href="15_Interaction_hover.html" class="example-card">
|
|
88
|
+
<div class="num">Example 15</div>
|
|
89
|
+
<div class="title">Interaction (hover)</div>
|
|
90
|
+
<p class="desc">Hover over nodes or edges to see details in a tooltip. Demonstrates onNodeHover and onEdgeHover.</p>
|
|
91
|
+
</a>
|
|
92
|
+
<a href="16_Interaction_details.html" class="example-card">
|
|
93
|
+
<div class="num">Example 16</div>
|
|
94
|
+
<div class="title">Interaction (highlight neighbours)</div>
|
|
95
|
+
<p class="desc">Click a node to highlight its neighbours. Combines enableInteraction with ChangeTheVertexColours.</p>
|
|
96
|
+
</a>
|
|
97
|
+
<a href="17_Interaction_drag.html" class="example-card">
|
|
98
|
+
<div class="num">Example 17</div>
|
|
99
|
+
<div class="title">Interaction (drag nodes)</div>
|
|
100
|
+
<p class="desc">Drag cubes to reposition nodes. Uses enableNodeDrag and onNodeDrag with mutable vertices and edges.</p>
|
|
101
|
+
</a>
|
|
82
102
|
</section>
|
|
83
103
|
</main>
|
|
84
104
|
</body>
|
package/README.md
CHANGED
|
@@ -22,7 +22,7 @@ The documentation for the package is available at [documentation](https://www.pl
|
|
|
22
22
|
npm run document
|
|
23
23
|
```
|
|
24
24
|
|
|
25
|
-
This writes TypeDoc output to the `docs/` folder. **API overview:** the library exposes the following namespaces: `Graph`, `GraphMethods` (BFS, Dijkstra, GraphDiameter, SelectSubgraph — note: `Dijkstra` returns hop-count distances via BFS for unweighted graphs), `SampleData` (LoadZKC, LoadZKCSimulated, LoadGraphFromEdgeListText for (sgd)²-style edge lists, LoadGraphFromObjText for OBJ meshes → graph + positions), `Constructors` (ConstructGraphNodeEdgesList), `Drawing` (SimulateKamadaKawai, DrawEdgeLines, DrawEdgeBundling, DisplaceEdgeInY, etc.), `Geometry`, `Utilities`, `ThreeWrapper`, `GraphDrawer`, `Models` (Erdos–Renyi), `Hierarchy` (clusterByDistance, clusterByStrategy for flow-map style clustering), **Simulation** (createKamadaKawai3D, createStressSGD3D — stress layout methods from (sgd)², Imperial), **MatrixHelpers** (matrixVectorMultiply, normalizeVector), and **glMatrix** (re-exported [gl-matrix](https://github.com/toji/gl-matrix) for vector/matrix math in the browser).
|
|
25
|
+
This writes TypeDoc output to the `docs/` folder. **API overview:** the library exposes the following namespaces: `Graph`, `GraphMethods` (BFS, Dijkstra, GraphDiameter, SelectSubgraph — note: `Dijkstra` returns hop-count distances via BFS for unweighted graphs), `SampleData` (LoadZKC, LoadZKCSimulated, LoadGraphFromEdgeListText for (sgd)²-style edge lists, LoadGraphFromObjText for OBJ meshes → graph + positions), `Constructors` (ConstructGraphNodeEdgesList), `Drawing` (SimulateKamadaKawai, DrawEdgeLines, DrawEdgeBundling, DisplaceEdgeInY, etc.), `Geometry`, `Utilities`, `ThreeWrapper`, `GraphDrawer`, **Interaction** (opt-in: `enableInteraction`, `disableInteraction`; types `NodePickDetails`, `EdgePickDetails`, `InteractionOptions` for click/hover/drag callbacks), `Models` (Erdos–Renyi), `Hierarchy` (clusterByDistance, clusterByStrategy for flow-map style clustering), **Simulation** (createKamadaKawai3D, createStressSGD3D — stress layout methods from (sgd)², Imperial), **MatrixHelpers** (matrixVectorMultiply, normalizeVector), and **glMatrix** (re-exported [gl-matrix](https://github.com/toji/gl-matrix) for vector/matrix math in the browser).
|
|
26
26
|
|
|
27
27
|
### Graph simulations
|
|
28
28
|
|
|
@@ -37,6 +37,67 @@ The library exports **Point** (class with `x`, `y`, `z` and `translate()`) and *
|
|
|
37
37
|
- **Static** (one-shot layout): `DrawTHREEGraphVertices`, `DrawTHREEGraphEdgesThin` — create geometry once from the graph.
|
|
38
38
|
- **Mutable** (animation loops): `DrawTHREEGraphVerticesMutable` (and `updatePositions()`), `DrawTHREEGraphEdgesThinMutable` (and `updateEdges()`) — update geometry each frame for time-based simulation.
|
|
39
39
|
|
|
40
|
+
### Interaction (opt-in)
|
|
41
|
+
|
|
42
|
+
Interaction is **100% opt-in**. Call `graph3d.enableInteraction(options)` after adding visual elements. No interaction occurs unless you call it.
|
|
43
|
+
|
|
44
|
+
**Options:**
|
|
45
|
+
|
|
46
|
+
| Option | Type | Description |
|
|
47
|
+
|--------|------|-------------|
|
|
48
|
+
| `graph` | `Graph` | Required. Used to look up node/edge details for callbacks. |
|
|
49
|
+
| `onNodeClick` | `(details: NodePickDetails) => void` | Fired when a node is clicked. |
|
|
50
|
+
| `onEdgeClick` | `(details: EdgePickDetails) => void` | Fired when an edge is clicked. |
|
|
51
|
+
| `onNodeHover` | `(details: NodePickDetails \| null) => void` | Fired when pointer enters/leaves a node. `null` when leaving. |
|
|
52
|
+
| `onEdgeHover` | `(details: EdgePickDetails \| null) => void` | Fired when pointer enters/leaves an edge. `null` when leaving. |
|
|
53
|
+
| `hoverEnabled` | `boolean` | Default `true`. Set `false` to disable hover callbacks. |
|
|
54
|
+
| `enableNodeDrag` | `boolean` | Enable drag-to-reposition. Requires `onNodeDrag`. |
|
|
55
|
+
| `onNodeDrag` | `(nodeId: number, newPosition: PointLike) => void` | Called each pointer move while dragging. Update graph and call `updatePositions()` / `updateEdges()`. |
|
|
56
|
+
| `controls` | `OrbitControls` | Optional. Pass `graph3d.controls` to disable camera orbit during drag. Auto-passed by GraphDrawer. |
|
|
57
|
+
|
|
58
|
+
**Callback payloads:**
|
|
59
|
+
|
|
60
|
+
- **NodePickDetails**: `nodeId`, `data`, `neighbours`, `position`
|
|
61
|
+
- **EdgePickDetails**: `edgeId`, `start`, `end`, `data`
|
|
62
|
+
|
|
63
|
+
**Example — click and hover:**
|
|
64
|
+
|
|
65
|
+
```javascript
|
|
66
|
+
graph3d.enableInteraction({
|
|
67
|
+
graph: G,
|
|
68
|
+
onNodeClick: (d) => console.log("Node", d.nodeId, "neighbours:", d.neighbours),
|
|
69
|
+
onNodeHover: (d) => { if (d) showTooltip(d); else hideTooltip(); },
|
|
70
|
+
});
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
**Example — drag to reposition (use mutable vertices and edges):**
|
|
74
|
+
|
|
75
|
+
```javascript
|
|
76
|
+
const { group, updatePositions } = PGL.ThreeWrapper.DrawTHREEBoxBasedVerticesMutable(G, 1, 0xffffff, 5);
|
|
77
|
+
const { group: edgeGroup, updateEdges } = PGL.ThreeWrapper.DrawTHREEGraphEdgesThinMutable(G, 1, 0xffafcc);
|
|
78
|
+
graph3d.addVisElement(group);
|
|
79
|
+
graph3d.addVisElement(edgeGroup);
|
|
80
|
+
|
|
81
|
+
graph3d.enableInteraction({
|
|
82
|
+
graph: G,
|
|
83
|
+
enableNodeDrag: true,
|
|
84
|
+
onNodeDrag: (nodeId, newPos) => {
|
|
85
|
+
const node = G.nodes.get(nodeId);
|
|
86
|
+
if (node?.data?.pos) {
|
|
87
|
+
node.data.pos.x = newPos.x;
|
|
88
|
+
node.data.pos.y = newPos.y;
|
|
89
|
+
node.data.pos.z = newPos.z;
|
|
90
|
+
}
|
|
91
|
+
const lmap = PGL.Drawing.DrawEdgeLinesDivisions(G, 1);
|
|
92
|
+
G.apply_edge_pos_maps(lmap);
|
|
93
|
+
updatePositions(G.get_position_map());
|
|
94
|
+
updateEdges();
|
|
95
|
+
},
|
|
96
|
+
});
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
**Tips:** Thick edges are easier to pick than thin lines. Use `bounds: 1` or `5` for better picking. Set `graph3d.controls.autoRotate = false` for interactive demos. See Examples 14 (click), 15 (hover), 16 (highlight neighbours), 17 (drag).
|
|
100
|
+
|
|
40
101
|
### LOD and flow-map style
|
|
41
102
|
|
|
42
103
|
**Hierarchy** (clusterByDistance, clusterByStrategy) and Example 6 provide FlowmapBlue-style level-of-detail: cluster nodes by distance (e.g. KD-tree), merge nearby nodes into super-nodes, and simplify the graph for zoom-dependent detail. See Examples 5 (Hierarchy) and 6 (Flow map).
|
|
@@ -137,7 +198,7 @@ Or head over to the GitHub, download the pgl_module.js [Builds](https://github.c
|
|
|
137
198
|
|
|
138
199
|
## More examples
|
|
139
200
|
|
|
140
|
-
More examples are available at [Examples](https://www.plebeiangraphlibrary.com/examples.html)
|
|
201
|
+
More examples are available at [Examples](https://www.plebeiangraphlibrary.com/examples.html). They cover layout (Kamada–Kawai, Stress SGD), edge bundling, flow maps, and **interaction** (Examples 14–17: click, hover, neighbour highlight, drag-to-reposition).
|
|
141
202
|
|
|
142
203
|
## Integrations
|
|
143
204
|
|
|
@@ -171,6 +232,12 @@ Remember to follow our Code of Conduct to ensure a welcoming and inclusive envir
|
|
|
171
232
|
|
|
172
233
|
## References and acknowledgements
|
|
173
234
|
|
|
235
|
+
**PGL:** If you use this library in your research, please cite:
|
|
236
|
+
|
|
237
|
+
> Haldar, I. (2024). The plebeian Graph Library: A WebGL based network visualisation and diagnostics package. *Journal of Open Source Software*, 9(96), 5887. https://doi.org/10.21105/joss.05887
|
|
238
|
+
|
|
239
|
+
BibTeX entry is available in `paper.bib` as `Haldar2024`.
|
|
240
|
+
|
|
174
241
|
**Stress-based layout (createStressSGD3D):** The stress-minimization-by-SGD algorithm and schedule used in PGL are taken from the **(sgd)²** reference implementation ([jxz12/s_gd2](https://github.com/jxz12/s_gd2)) from Imperial College London. The underlying method is from the paper: J. X. Zheng, S. Pawar, D. F. M. Goodman, *Graph Drawing by Stochastic Gradient Descent*, IEEE Transactions on Visualization and Computer Graphics, [arXiv:1710.04626](https://arxiv.org/abs/1710.04626). Example graph data (e.g. football.txt) in the Stress SGD demo are from the same s_gd2 repository.
|
|
175
242
|
|
|
176
243
|
**PGL:** This library was sponsored by the Geometry Lab under the Laboratory for Design Technologies at the Graduate School of Design, Harvard University. Many thanks to Andrew Witt for guiding this project. This project was developed by [Indrajeet Haldar](https://www.indrajeethaldar.com/).
|