plebeiangraphlibrary 2.0.1 → 2.1.2
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/Core/Edge.d.ts +20 -0
- package/Build/Core/Graph.d.ts +114 -0
- package/Build/Core/_Node.d.ts +20 -0
- package/Build/Core/index.d.ts +3 -0
- package/Build/Drawing/Drawing.d.ts +129 -0
- package/Build/Drawing/GraphDrawer.d.ts +70 -0
- package/Build/Drawing/MeshLineGeometry.d.ts +11 -0
- package/Build/Drawing/MeshLineMaterial.d.ts +16 -0
- package/Build/Drawing/ThickLine.d.ts +21 -0
- package/Build/Drawing/ThreeJSDrawer.d.ts +197 -0
- package/Build/Drawing/index.d.ts +3 -0
- package/Build/GraphAlgorithms/GraphMethods.d.ts +47 -0
- package/Build/GraphAlgorithms/index.d.ts +1 -0
- package/Build/HelperClasses/ColorHelper.d.ts +21 -0
- package/Build/HelperClasses/GeometryHelpers.d.ts +31 -0
- package/Build/HelperClasses/GraphConstructors.d.ts +12 -0
- package/Build/HelperClasses/Line.d.ts +12 -0
- package/Build/HelperClasses/Point.d.ts +26 -0
- package/Build/HelperClasses/Utilities.d.ts +45 -0
- package/Build/HelperClasses/index.d.ts +3 -0
- package/Build/Hierarchy/KDDistanceStrategy.d.ts +8 -0
- package/Build/Hierarchy/KDTree.d.ts +10 -0
- package/Build/Hierarchy/buildSimplifiedGraph.d.ts +7 -0
- package/Build/Hierarchy/index.d.ts +29 -0
- package/Build/Hierarchy/types.d.ts +33 -0
- package/Build/MatrixHelpers.d.ts +12 -0
- package/Build/Models/ErdosRenyiModel.d.ts +13 -0
- package/Build/Models/index.d.ts +1 -0
- package/Build/SampleData/DataLoader.d.ts +49 -0
- package/Build/SampleData/ZKC.d.ts +5 -0
- package/Build/SampleData/ZKC_simulated.d.ts +10 -0
- package/Build/SampleData/dwt_1005.d.ts +1008 -0
- package/Build/SampleData/index.d.ts +2 -0
- package/Build/Shaders/fragmentShader.glsl.d.ts +2 -0
- package/Build/Shaders/vertexShader.glsl.d.ts +2 -0
- package/Build/Simulation/KamadaKawai3D.d.ts +30 -0
- package/Build/Simulation/Octree.d.ts +34 -0
- package/Build/Simulation/StressSGD3D.d.ts +45 -0
- package/Build/Simulation/index.d.ts +4 -0
- package/Build/index.d.ts +40 -0
- package/Build/pgl.js +3824 -3389
- package/Build/pgl.js.map +1 -1
- package/Build/pgl_module.js +20827 -35564
- package/Build/pgl_module.js.map +1 -1
- package/Examples/10_Adjacency_matrix.html +74 -0
- package/Examples/11_Custom_layout.html +89 -0
- package/Examples/12_StressSGD_simulation_live.html +80 -0
- package/Examples/13_StressSGD_bunny_3d.html +104 -0
- package/Examples/4_ToggleActivation.html +1 -1
- package/Examples/5_Hierarchy_simple.html +5 -2
- package/Examples/9_Simulation_live.html +74 -0
- package/Examples/data/bunny.obj +7474 -0
- package/Examples/examples.html +27 -2
- package/README.md +42 -10
- package/package.json +15 -23
- package/Build/Textures/Square.png +0 -0
- package/Build/pgl.d.ts +0 -703
- package/Build/pgl.d.ts.map +0 -1
|
@@ -0,0 +1,74 @@
|
|
|
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 10 – Adjacency matrix and power iteration</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 10 – Adjacency matrix and power iteration</h1>
|
|
16
|
+
<p class="example-desc">get_adjacency_matrix() + power iteration in the browser. Node size reflects leading eigenvector (larger = higher value).</p>
|
|
17
|
+
<a href="https://github.com/range-et/PGL/blob/main/Examples/10_Adjacency_matrix.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.Models.GenerateErdosReyni_n_p(150, 0.04);
|
|
25
|
+
await G.initialize();
|
|
26
|
+
G.printData();
|
|
27
|
+
|
|
28
|
+
const { matrix, nodeIds } = G.get_adjacency_matrix();
|
|
29
|
+
const n = nodeIds.length;
|
|
30
|
+
const x = new Float32Array(n);
|
|
31
|
+
for (let i = 0; i < n; i++) x[i] = Math.random();
|
|
32
|
+
PGL.normalizeVector(x);
|
|
33
|
+
|
|
34
|
+
const out = new Float32Array(n);
|
|
35
|
+
for (let iter = 0; iter < 20; iter++) {
|
|
36
|
+
PGL.matrixVectorMultiply(matrix, n, x, out);
|
|
37
|
+
x.set(out);
|
|
38
|
+
PGL.normalizeVector(x);
|
|
39
|
+
}
|
|
40
|
+
let min = Infinity, max = -Infinity;
|
|
41
|
+
for (let i = 0; i < n; i++) {
|
|
42
|
+
if (x[i] < min) min = x[i];
|
|
43
|
+
if (x[i] > max) max = x[i];
|
|
44
|
+
}
|
|
45
|
+
const range = max - min || 1;
|
|
46
|
+
const sizes = nodeIds.map((_, i) => 0.3 + 0.7 * (x[i] - min) / range);
|
|
47
|
+
|
|
48
|
+
const simulatedPosMap = await PGL.Drawing.SimulateKamadaKawai(G, 3, 2000, 1, 1.2);
|
|
49
|
+
G.apply_position_map(simulatedPosMap);
|
|
50
|
+
const lmap = PGL.Drawing.DrawEdgeLinesDivisions(G, 1);
|
|
51
|
+
G.apply_edge_pos_maps(lmap);
|
|
52
|
+
|
|
53
|
+
const width = 800;
|
|
54
|
+
const height = 700;
|
|
55
|
+
const canvas = document.getElementById("displayCanvas");
|
|
56
|
+
const graph3d = new PGL.GraphDrawer.GraphDrawer3d({ graph: G, width, height, canvas });
|
|
57
|
+
await graph3d.init();
|
|
58
|
+
|
|
59
|
+
const bounds = 0.08;
|
|
60
|
+
const nodeVisualElements = PGL.ThreeWrapper.DrawTHREEGraphVertices(G, bounds, sizes, 0xffffff, 1);
|
|
61
|
+
graph3d.addVisElement(nodeVisualElements);
|
|
62
|
+
const edgeVisualElements = PGL.ThreeWrapper.DrawTHREEGraphEdgesThin(G, bounds, 0x444444);
|
|
63
|
+
graph3d.addVisElement(edgeVisualElements);
|
|
64
|
+
|
|
65
|
+
function animate() {
|
|
66
|
+
requestAnimationFrame(animate);
|
|
67
|
+
graph3d.rendercall();
|
|
68
|
+
}
|
|
69
|
+
animate();
|
|
70
|
+
</script>
|
|
71
|
+
</div>
|
|
72
|
+
</body>
|
|
73
|
+
|
|
74
|
+
</html>
|
|
@@ -0,0 +1,89 @@
|
|
|
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 11 – Custom layout from matrix math</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 11 – Custom layout from matrix math</h1>
|
|
16
|
+
<p class="example-desc">Adjacency matrix → power iteration for two vectors → use as X/Z coordinates. Full pipeline: get_adjacency_matrix(), matrixVectorMultiply, apply_position_map.</p>
|
|
17
|
+
<a href="https://github.com/range-et/PGL/blob/main/Examples/11_Custom_layout.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.Models.GenerateErdosReyni_n_p(120, 0.05);
|
|
25
|
+
await G.initialize();
|
|
26
|
+
G.printData();
|
|
27
|
+
|
|
28
|
+
const { matrix, nodeIds } = G.get_adjacency_matrix();
|
|
29
|
+
const n = nodeIds.length;
|
|
30
|
+
const out = new Float32Array(n);
|
|
31
|
+
|
|
32
|
+
function powerIteration(seed) {
|
|
33
|
+
const x = new Float32Array(n);
|
|
34
|
+
for (let i = 0; i < n; i++) x[i] = seed(i);
|
|
35
|
+
PGL.normalizeVector(x);
|
|
36
|
+
for (let iter = 0; iter < 15; iter++) {
|
|
37
|
+
PGL.matrixVectorMultiply(matrix, n, x, out);
|
|
38
|
+
x.set(out);
|
|
39
|
+
PGL.normalizeVector(x);
|
|
40
|
+
}
|
|
41
|
+
return x;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const xCoord = powerIteration(() => Math.random());
|
|
45
|
+
const zCoord = powerIteration((i) => (i % 2 === 0 ? 1 : -1));
|
|
46
|
+
|
|
47
|
+
let minX = Infinity, maxX = -Infinity, minZ = Infinity, maxZ = -Infinity;
|
|
48
|
+
for (let i = 0; i < n; i++) {
|
|
49
|
+
if (xCoord[i] < minX) minX = xCoord[i];
|
|
50
|
+
if (xCoord[i] > maxX) maxX = xCoord[i];
|
|
51
|
+
if (zCoord[i] < minZ) minZ = zCoord[i];
|
|
52
|
+
if (zCoord[i] > maxZ) maxZ = zCoord[i];
|
|
53
|
+
}
|
|
54
|
+
const scale = 80;
|
|
55
|
+
const rx = maxX - minX || 1;
|
|
56
|
+
const rz = maxZ - minZ || 1;
|
|
57
|
+
const posMap = new Map();
|
|
58
|
+
nodeIds.forEach((id, i) => {
|
|
59
|
+
posMap.set(id, {
|
|
60
|
+
x: scale * (xCoord[i] - minX) / rx,
|
|
61
|
+
y: 0,
|
|
62
|
+
z: scale * (zCoord[i] - minZ) / rz,
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
G.apply_position_map(posMap);
|
|
66
|
+
|
|
67
|
+
const lmap = PGL.Drawing.DrawEdgeLinesDivisions(G, 1);
|
|
68
|
+
G.apply_edge_pos_maps(lmap);
|
|
69
|
+
|
|
70
|
+
const width = 800;
|
|
71
|
+
const height = 700;
|
|
72
|
+
const canvas = document.getElementById("displayCanvas");
|
|
73
|
+
const graph3d = new PGL.GraphDrawer.GraphDrawer3d({ graph: G, width, height, canvas });
|
|
74
|
+
await graph3d.init();
|
|
75
|
+
|
|
76
|
+
const bounds = 0.1;
|
|
77
|
+
graph3d.addVisElement(PGL.ThreeWrapper.DrawTHREEGraphVertices(G, bounds, 1, 0xffffff, 1));
|
|
78
|
+
graph3d.addVisElement(PGL.ThreeWrapper.DrawTHREEGraphEdgesThin(G, bounds, 0xffafcc));
|
|
79
|
+
|
|
80
|
+
function animate() {
|
|
81
|
+
requestAnimationFrame(animate);
|
|
82
|
+
graph3d.rendercall();
|
|
83
|
+
}
|
|
84
|
+
animate();
|
|
85
|
+
</script>
|
|
86
|
+
</div>
|
|
87
|
+
</body>
|
|
88
|
+
|
|
89
|
+
</html>
|
|
@@ -0,0 +1,80 @@
|
|
|
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 12 – Stress SGD live simulation</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 12 – Stress SGD live simulation</h1>
|
|
16
|
+
<p class="example-desc">Time-based 3D stress layout by stochastic gradient descent (arXiv:1710.04626). Uses createStressSGD3D, step(dt), and mutable vertices.</p>
|
|
17
|
+
<a href="https://github.com/range-et/PGL/blob/main/Examples/12_StressSGD_simulation_live.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
|
+
// DWT 1005 graph from the paper (1005 nodes). dimensions: 3 = full 3D layout (like Example 9).
|
|
25
|
+
const G = await PGL.SampleData.LoadDwt1005();
|
|
26
|
+
G.printData();
|
|
27
|
+
|
|
28
|
+
// Faithful s_gd2 port: epoch-based, Fisher-Yates shuffle, [0,1] init
|
|
29
|
+
const simulation = await PGL.createStressSGD3D(G, {
|
|
30
|
+
dimensions: 2,
|
|
31
|
+
simulationBound: 1,
|
|
32
|
+
epochsPerStep: 1,
|
|
33
|
+
tMax: 80,
|
|
34
|
+
eps: 0.01,
|
|
35
|
+
scaleBound: 1200, // scale output for visibility (not in reference)
|
|
36
|
+
});
|
|
37
|
+
// Keep graph and simulation in sync: apply positions then rebuild edge geometry from graph
|
|
38
|
+
G.apply_position_map(simulation.getPositionMap());
|
|
39
|
+
const lmap = PGL.Drawing.DrawEdgeLinesDivisions(G, 1);
|
|
40
|
+
G.apply_edge_pos_maps(lmap);
|
|
41
|
+
|
|
42
|
+
const width = 800;
|
|
43
|
+
const height = 700;
|
|
44
|
+
const canvas = document.getElementById("displayCanvas");
|
|
45
|
+
const graph3d = new PGL.GraphDrawer.GraphDrawer3d({
|
|
46
|
+
graph: G,
|
|
47
|
+
width,
|
|
48
|
+
height,
|
|
49
|
+
canvas,
|
|
50
|
+
});
|
|
51
|
+
await graph3d.init();
|
|
52
|
+
|
|
53
|
+
const bounds = 0.1;
|
|
54
|
+
const { group, updatePositions } = PGL.ThreeWrapper.DrawTHREEGraphVerticesMutable(G, bounds, 1, 0xffffff, 1);
|
|
55
|
+
graph3d.addVisElement(group);
|
|
56
|
+
const { group: edgeGroup, updateEdges } = PGL.ThreeWrapper.DrawTHREEGraphEdgesThinMutable(G, bounds, 0xffafcc);
|
|
57
|
+
graph3d.addVisElement(edgeGroup);
|
|
58
|
+
|
|
59
|
+
let lastTime = performance.now();
|
|
60
|
+
function animate() {
|
|
61
|
+
requestAnimationFrame(animate);
|
|
62
|
+
const now = performance.now();
|
|
63
|
+
const dt = (now - lastTime) / 1000;
|
|
64
|
+
lastTime = now;
|
|
65
|
+
simulation.step(dt);
|
|
66
|
+
// 1) Push simulation positions into graph so edge geometry uses same positions
|
|
67
|
+
G.apply_position_map(simulation.getPositionMap());
|
|
68
|
+
const lmap = PGL.Drawing.DrawEdgeLinesDivisions(G, 1);
|
|
69
|
+
G.apply_edge_pos_maps(lmap);
|
|
70
|
+
// 2) Update Three.js vertex and edge geometry from same data
|
|
71
|
+
updatePositions(simulation.getPositions());
|
|
72
|
+
updateEdges();
|
|
73
|
+
graph3d.rendercall();
|
|
74
|
+
}
|
|
75
|
+
animate();
|
|
76
|
+
</script>
|
|
77
|
+
</div>
|
|
78
|
+
</body>
|
|
79
|
+
|
|
80
|
+
</html>
|
|
@@ -0,0 +1,104 @@
|
|
|
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 13 – Stress SGD 3D (Stanford Bunny mesh)</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 13 – Stress SGD 3D (Stanford Bunny mesh)</h1>
|
|
16
|
+
<p class="example-desc">3D stress layout from a mesh: graph = mesh vertices + edges, initial positions = mesh positions. Layout refines in 3D so the shape stays bunny-like (no collapse to a line). Based on IEEE TVCG “Graph Drawing by Stochastic Gradient Descent” and Stanford Bunny OBJ.</p>
|
|
17
|
+
<a href="https://github.com/range-et/PGL/blob/main/Examples/13_StressSGD_bunny_3d.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
|
+
<p id="status" style="position:absolute;left:12px;top:60px;color:#fff;font-size:12px;pointer-events:none;"></p>
|
|
22
|
+
<script type="module">
|
|
23
|
+
import * as PGL from "../Build/pgl_module.js";
|
|
24
|
+
|
|
25
|
+
const status = document.getElementById("status");
|
|
26
|
+
function setStatus(msg) {
|
|
27
|
+
if (status) status.textContent = msg;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Stanford Bunny OBJ: load from local copy (no CORS). Mesh → graph: vertices = nodes, face edges = graph edges.
|
|
31
|
+
setStatus("Loading bunny.obj…");
|
|
32
|
+
let objText;
|
|
33
|
+
try {
|
|
34
|
+
// Prefer local copy (Examples/data/bunny.obj) so it works without CORS
|
|
35
|
+
const response = await fetch("data/bunny.obj");
|
|
36
|
+
if (!response.ok) throw new Error(response.statusText);
|
|
37
|
+
objText = await response.text();
|
|
38
|
+
} catch (e) {
|
|
39
|
+
setStatus("Could not load data/bunny.obj. Serve Examples from a local server (e.g. from repo root: npx serve ., then open Examples/13_StressSGD_bunny_3d.html). " + (e && e.message ? e.message : ""));
|
|
40
|
+
throw e;
|
|
41
|
+
}
|
|
42
|
+
setStatus("Building graph from mesh…");
|
|
43
|
+
const { graph: G, positions: meshPositions } = await PGL.SampleData.LoadGraphFromObjText(objText);
|
|
44
|
+
await G.initialize();
|
|
45
|
+
G.printData();
|
|
46
|
+
|
|
47
|
+
// Scale mesh positions into a comfortable range (bunny is ~0.1 units); then we'll use scaleBound to hold size
|
|
48
|
+
const scale = 4000;
|
|
49
|
+
const initialPositions = new Float32Array(meshPositions.length);
|
|
50
|
+
for (let i = 0; i < meshPositions.length; i++) initialPositions[i] = meshPositions[i] * scale;
|
|
51
|
+
|
|
52
|
+
setStatus("Computing all-pairs distances (one-time, may take a few seconds)…");
|
|
53
|
+
const simulation = await PGL.createStressSGD3D(G, {
|
|
54
|
+
dimensions: 3,
|
|
55
|
+
initialPositions,
|
|
56
|
+
epochsPerStep: 1,
|
|
57
|
+
tMax: 100,
|
|
58
|
+
eps: 0.01,
|
|
59
|
+
scaleBound: 1200,
|
|
60
|
+
initialPreservation: 0.15, // blend toward mesh shape so bunny stays 3D
|
|
61
|
+
});
|
|
62
|
+
setStatus("");
|
|
63
|
+
|
|
64
|
+
G.apply_position_map(simulation.getPositionMap());
|
|
65
|
+
const lmap = PGL.Drawing.DrawEdgeLinesDivisions(G, 1);
|
|
66
|
+
G.apply_edge_pos_maps(lmap);
|
|
67
|
+
|
|
68
|
+
const width = 800;
|
|
69
|
+
const height = 700;
|
|
70
|
+
const canvas = document.getElementById("displayCanvas");
|
|
71
|
+
const graph3d = new PGL.GraphDrawer.GraphDrawer3d({
|
|
72
|
+
graph: G,
|
|
73
|
+
width,
|
|
74
|
+
height,
|
|
75
|
+
canvas,
|
|
76
|
+
});
|
|
77
|
+
await graph3d.init();
|
|
78
|
+
|
|
79
|
+
const bounds = 0.1;
|
|
80
|
+
const { group, updatePositions } = PGL.ThreeWrapper.DrawTHREEGraphVerticesMutable(G, bounds, 0.8, 0xffffff, 1);
|
|
81
|
+
graph3d.addVisElement(group);
|
|
82
|
+
const { group: edgeGroup, updateEdges } = PGL.ThreeWrapper.DrawTHREEGraphEdgesThinMutable(G, bounds, 0x88aacc);
|
|
83
|
+
graph3d.addVisElement(edgeGroup);
|
|
84
|
+
|
|
85
|
+
let lastTime = performance.now();
|
|
86
|
+
function animate() {
|
|
87
|
+
requestAnimationFrame(animate);
|
|
88
|
+
const now = performance.now();
|
|
89
|
+
const dt = (now - lastTime) / 1000;
|
|
90
|
+
lastTime = now;
|
|
91
|
+
simulation.step(dt);
|
|
92
|
+
G.apply_position_map(simulation.getPositionMap());
|
|
93
|
+
const lmap = PGL.Drawing.DrawEdgeLinesDivisions(G, 1);
|
|
94
|
+
G.apply_edge_pos_maps(lmap);
|
|
95
|
+
updatePositions(simulation.getPositions());
|
|
96
|
+
updateEdges();
|
|
97
|
+
graph3d.rendercall();
|
|
98
|
+
}
|
|
99
|
+
animate();
|
|
100
|
+
</script>
|
|
101
|
+
</div>
|
|
102
|
+
</body>
|
|
103
|
+
|
|
104
|
+
</html>
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
|
|
33
33
|
// now in this case we shall use the Kamada Kawai algorithm to initilaize all the positions
|
|
34
34
|
// this essentially spreads them out a little
|
|
35
|
-
const simulatedPosMap = await PGL.Drawing.SimulateKamadaKawai(G, 3,
|
|
35
|
+
const simulatedPosMap = await PGL.Drawing.SimulateKamadaKawai(G, 3, 5000, 1, 1.5);
|
|
36
36
|
G.apply_position_map(simulatedPosMap);
|
|
37
37
|
// get the line map associated
|
|
38
38
|
const lmap = PGL.Drawing.DrawEdgeLinesDivisions(G, 1);
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
<header class="example-header">
|
|
14
14
|
<a href="examples.html" class="back-link">← All examples</a>
|
|
15
15
|
<h1>Example 5 – Hierarchy</h1>
|
|
16
|
-
<p class="example-desc">
|
|
16
|
+
<p class="example-desc">Simplify a graph by merging nearby nodes into super-nodes. Nodes within 25 units in 3D are grouped; each group becomes one node at its center (centroid), and edges between groups are merged. You get fewer nodes and edges while keeping the overall structure — useful for LOD or flow-map style “zoomed out” views.</p>
|
|
17
17
|
<a href="https://github.com/range-et/PGL/blob/main/Examples/5_Hierarchy_simple.html" class="code-link" target="_blank" rel="noopener">View code</a>
|
|
18
18
|
</header>
|
|
19
19
|
<div class="canvas-wrap">
|
|
@@ -21,12 +21,15 @@
|
|
|
21
21
|
<script type="module">
|
|
22
22
|
import * as PGL from "../Build/pgl_module.js";
|
|
23
23
|
|
|
24
|
+
// 1) Load original graph (many nodes)
|
|
24
25
|
const original = await PGL.SampleData.LoadZKCSimulated();
|
|
25
26
|
original.printData();
|
|
26
27
|
|
|
28
|
+
// 2) Cluster by 3D distance: nodes within distanceThreshold are merged into one super-node per cluster (at centroid). Edges between clusters are aggregated.
|
|
27
29
|
const simplified = await PGL.Hierarchy.clusterByDistance(original, { distanceThreshold: 25 });
|
|
28
|
-
simplified.printData();
|
|
30
|
+
simplified.printData(); // fewer nodes than original
|
|
29
31
|
|
|
32
|
+
// 3) Draw the simplified graph (boxes at cluster centers, thick edges between clusters)
|
|
30
33
|
const lmap = PGL.Drawing.DrawEdgeLinesDivisions(simplified, 1);
|
|
31
34
|
simplified.apply_edge_pos_maps(lmap);
|
|
32
35
|
|
|
@@ -0,0 +1,74 @@
|
|
|
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 9 – Live 3D simulation</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 9 – Live 3D simulation</h1>
|
|
16
|
+
<p class="example-desc">Time-based 3D Kamada–Kawai: layout evolves in real time. Uses createKamadaKawai3D, step(dt), and mutable vertices.</p>
|
|
17
|
+
<a href="https://github.com/range-et/PGL/blob/main/Examples/9_Simulation_live.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
|
+
// DWT 1005 graph from the paper (same as Example 12's 2D stress dataset)
|
|
25
|
+
const G = await PGL.SampleData.LoadDwt1005();
|
|
26
|
+
G.printData();
|
|
27
|
+
|
|
28
|
+
const simulation = PGL.createKamadaKawai3D(G, {
|
|
29
|
+
simulationBound: 800,
|
|
30
|
+
cohesionValue: 1,
|
|
31
|
+
repulsionValue: 1,
|
|
32
|
+
iterationsPerStep: 1,
|
|
33
|
+
});
|
|
34
|
+
G.apply_position_map(simulation.getPositionMap());
|
|
35
|
+
const lmap = PGL.Drawing.DrawEdgeLinesDivisions(G, 1);
|
|
36
|
+
G.apply_edge_pos_maps(lmap);
|
|
37
|
+
|
|
38
|
+
const width = 800;
|
|
39
|
+
const height = 700;
|
|
40
|
+
const canvas = document.getElementById("displayCanvas");
|
|
41
|
+
const graph3d = new PGL.GraphDrawer.GraphDrawer3d({
|
|
42
|
+
graph: G,
|
|
43
|
+
width,
|
|
44
|
+
height,
|
|
45
|
+
canvas,
|
|
46
|
+
});
|
|
47
|
+
await graph3d.init();
|
|
48
|
+
|
|
49
|
+
const bounds = 0.1;
|
|
50
|
+
const { group, updatePositions } = PGL.ThreeWrapper.DrawTHREEGraphVerticesMutable(G, bounds, 1, 0xffffff, 1);
|
|
51
|
+
graph3d.addVisElement(group);
|
|
52
|
+
const { group: edgeGroup, updateEdges } = PGL.ThreeWrapper.DrawTHREEGraphEdgesThinMutable(G, bounds, 0xffafcc);
|
|
53
|
+
graph3d.addVisElement(edgeGroup);
|
|
54
|
+
|
|
55
|
+
let lastTime = performance.now();
|
|
56
|
+
function animate() {
|
|
57
|
+
requestAnimationFrame(animate);
|
|
58
|
+
const now = performance.now();
|
|
59
|
+
const dt = (now - lastTime) / 1000;
|
|
60
|
+
lastTime = now;
|
|
61
|
+
simulation.step(dt);
|
|
62
|
+
G.apply_position_map(simulation.getPositionMap());
|
|
63
|
+
const lmap = PGL.Drawing.DrawEdgeLinesDivisions(G, 1);
|
|
64
|
+
G.apply_edge_pos_maps(lmap);
|
|
65
|
+
updatePositions(simulation.getPositions());
|
|
66
|
+
updateEdges();
|
|
67
|
+
graph3d.rendercall();
|
|
68
|
+
}
|
|
69
|
+
animate();
|
|
70
|
+
</script>
|
|
71
|
+
</div>
|
|
72
|
+
</body>
|
|
73
|
+
|
|
74
|
+
</html>
|