force-graph 1.42.3
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/LICENSE +21 -0
- package/README.md +228 -0
- package/dist/force-graph.common.js +1754 -0
- package/dist/force-graph.d.ts +195 -0
- package/dist/force-graph.js +12168 -0
- package/dist/force-graph.js.map +1 -0
- package/dist/force-graph.min.js +5 -0
- package/dist/force-graph.module.js +1743 -0
- package/example/auto-colored/index.html +34 -0
- package/example/basic/index.html +29 -0
- package/example/build-a-graph/index.html +108 -0
- package/example/click-to-focus/index.html +28 -0
- package/example/collision-detection/index.html +50 -0
- package/example/curved-links/index.html +37 -0
- package/example/curved-links-computed-curvature/index.html +76 -0
- package/example/custom-node-shape/index.html +44 -0
- package/example/dag-yarn/index.html +96 -0
- package/example/dagre/index.html +119 -0
- package/example/dash-odd-links/index.html +47 -0
- package/example/datasets/blocks.json +1 -0
- package/example/datasets/d3-dependencies.csv +464 -0
- package/example/datasets/miserables.json +337 -0
- package/example/datasets/mplate.mtx +74090 -0
- package/example/directional-links-arrows/index.html +29 -0
- package/example/directional-links-particles/index.html +22 -0
- package/example/dynamic/index.html +42 -0
- package/example/emit-particles/index.html +50 -0
- package/example/expandable-nodes/index.html +66 -0
- package/example/expandable-tree/index.html +85 -0
- package/example/fit-to-canvas/index.html +34 -0
- package/example/fix-dragged-nodes/index.html +24 -0
- package/example/highlight/index.html +84 -0
- package/example/huge-1M/index.html +37 -0
- package/example/img-nodes/imgs/cat.jpg +0 -0
- package/example/img-nodes/imgs/dog.jpg +0 -0
- package/example/img-nodes/imgs/eagle.jpg +0 -0
- package/example/img-nodes/imgs/elephant.jpg +0 -0
- package/example/img-nodes/imgs/grasshopper.jpg +0 -0
- package/example/img-nodes/imgs/octopus.jpg +0 -0
- package/example/img-nodes/imgs/owl.jpg +0 -0
- package/example/img-nodes/imgs/panda.jpg +0 -0
- package/example/img-nodes/imgs/squirrel.jpg +0 -0
- package/example/img-nodes/imgs/tiger.jpg +0 -0
- package/example/img-nodes/imgs/whale.jpg +0 -0
- package/example/img-nodes/index.html +43 -0
- package/example/large-graph/index.html +41 -0
- package/example/load-json/index.html +24 -0
- package/example/medium-graph/index.html +26 -0
- package/example/medium-graph/preview.png +0 -0
- package/example/move-viewport/index.html +42 -0
- package/example/multi-selection/index.html +57 -0
- package/example/responsive/index.html +37 -0
- package/example/text-links/index.html +69 -0
- package/example/text-nodes/index.html +42 -0
- package/example/tree/index.html +71 -0
- package/package.json +72 -0
- package/src/canvas-force-graph.js +544 -0
- package/src/color-utils.js +17 -0
- package/src/dagDepths.js +51 -0
- package/src/force-graph.css +35 -0
- package/src/force-graph.js +644 -0
- package/src/index.d.ts +195 -0
- package/src/index.js +3 -0
- package/src/kapsule-link.js +34 -0
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
<head>
|
|
2
|
+
<style> body { margin: 0; } </style>
|
|
3
|
+
|
|
4
|
+
<script src="//unpkg.com/force-graph"></script>
|
|
5
|
+
<!--<script src="../../dist/force-graph.js"></script>-->
|
|
6
|
+
</head>
|
|
7
|
+
|
|
8
|
+
<body>
|
|
9
|
+
<div id="graph"></div>
|
|
10
|
+
|
|
11
|
+
<script>
|
|
12
|
+
// Random tree
|
|
13
|
+
const N = 40;
|
|
14
|
+
const gData = {
|
|
15
|
+
nodes: [...Array(N).keys()].map(i => ({ id: i })),
|
|
16
|
+
links: [...Array(N).keys()]
|
|
17
|
+
.filter(id => id)
|
|
18
|
+
.map(id => ({
|
|
19
|
+
source: id,
|
|
20
|
+
target: Math.round(Math.random() * (id-1))
|
|
21
|
+
}))
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
const Graph = ForceGraph()
|
|
25
|
+
(document.getElementById('graph'))
|
|
26
|
+
.graphData(gData)
|
|
27
|
+
.linkDirectionalArrowLength(6);
|
|
28
|
+
</script>
|
|
29
|
+
</body>
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
<head>
|
|
2
|
+
<style> body { margin: 0; } </style>
|
|
3
|
+
|
|
4
|
+
<script src="//unpkg.com/force-graph"></script>
|
|
5
|
+
<!--<script src="../../dist/force-graph.js"></script>-->
|
|
6
|
+
</head>
|
|
7
|
+
|
|
8
|
+
<body>
|
|
9
|
+
<div id="graph"></div>
|
|
10
|
+
|
|
11
|
+
<script>
|
|
12
|
+
fetch('../datasets/miserables.json').then(res => res.json()).then(data => {
|
|
13
|
+
const Graph = ForceGraph()
|
|
14
|
+
(document.getElementById('graph'))
|
|
15
|
+
.graphData(data)
|
|
16
|
+
.nodeLabel('id')
|
|
17
|
+
.nodeAutoColorBy('group')
|
|
18
|
+
.linkDirectionalParticles("value")
|
|
19
|
+
.linkDirectionalParticleSpeed(d => d.value * 0.001);
|
|
20
|
+
});
|
|
21
|
+
</script>
|
|
22
|
+
</body>
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
<head>
|
|
2
|
+
<style> body { margin: 0; } </style>
|
|
3
|
+
|
|
4
|
+
<script src="//unpkg.com/force-graph"></script>
|
|
5
|
+
<!--<script src="../../dist/force-graph.js"></script>-->
|
|
6
|
+
</head>
|
|
7
|
+
|
|
8
|
+
<body>
|
|
9
|
+
<div id="graph"></div>
|
|
10
|
+
|
|
11
|
+
<script>
|
|
12
|
+
const initData = {
|
|
13
|
+
nodes: [ {id: 0 } ],
|
|
14
|
+
links: []
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
const elem = document.getElementById("graph");
|
|
18
|
+
|
|
19
|
+
const Graph = ForceGraph()(elem)
|
|
20
|
+
.onNodeClick(removeNode)
|
|
21
|
+
.graphData(initData);
|
|
22
|
+
|
|
23
|
+
setInterval(() => {
|
|
24
|
+
const { nodes, links } = Graph.graphData();
|
|
25
|
+
const id = nodes.length;
|
|
26
|
+
Graph.graphData({
|
|
27
|
+
nodes: [...nodes, { id }],
|
|
28
|
+
links: [...links, { source: id, target: Math.round(Math.random() * (id-1)) }]
|
|
29
|
+
});
|
|
30
|
+
}, 1000);
|
|
31
|
+
|
|
32
|
+
//
|
|
33
|
+
|
|
34
|
+
function removeNode(node) {
|
|
35
|
+
let { nodes, links } = Graph.graphData();
|
|
36
|
+
links = links.filter(l => l.source !== node && l.target !== node); // Remove links attached to node
|
|
37
|
+
nodes.splice(node.id, 1); // Remove node
|
|
38
|
+
nodes.forEach((n, idx) => { n.id = idx; }); // Reset node ids to array index
|
|
39
|
+
Graph.graphData({ nodes, links });
|
|
40
|
+
}
|
|
41
|
+
</script>
|
|
42
|
+
</body>
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
<head>
|
|
2
|
+
<style>
|
|
3
|
+
body { margin: 0; }
|
|
4
|
+
|
|
5
|
+
#emit-particles-btn {
|
|
6
|
+
position: absolute;
|
|
7
|
+
top: 10px;
|
|
8
|
+
right: 10px;
|
|
9
|
+
font-size: 13px;
|
|
10
|
+
}
|
|
11
|
+
</style>
|
|
12
|
+
|
|
13
|
+
<script src="//unpkg.com/force-graph"></script>
|
|
14
|
+
<!--<script src="../../dist/force-graph.js"></script>-->
|
|
15
|
+
</head>
|
|
16
|
+
|
|
17
|
+
<body>
|
|
18
|
+
<div id="graph"></div>
|
|
19
|
+
<button id="emit-particles-btn">Emit 10 Random Particles</button>
|
|
20
|
+
|
|
21
|
+
<script>
|
|
22
|
+
// Random tree
|
|
23
|
+
const N = 50;
|
|
24
|
+
const links = [...Array(N).keys()]
|
|
25
|
+
.filter(id => id)
|
|
26
|
+
.map(id => ({
|
|
27
|
+
source: id,
|
|
28
|
+
target: Math.round(Math.random() * (id-1))
|
|
29
|
+
}));
|
|
30
|
+
const gData = {
|
|
31
|
+
nodes: [...Array(N).keys()].map(i => ({ id: i })),
|
|
32
|
+
links
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
const Graph = ForceGraph()
|
|
36
|
+
(document.getElementById('graph'))
|
|
37
|
+
.linkDirectionalParticleColor(() => 'red')
|
|
38
|
+
.linkHoverPrecision(10)
|
|
39
|
+
.graphData(gData);
|
|
40
|
+
|
|
41
|
+
Graph.onLinkClick(Graph.emitParticle); // emit particles on link click
|
|
42
|
+
|
|
43
|
+
document.getElementById('emit-particles-btn').addEventListener('click', () => {
|
|
44
|
+
[...Array(10).keys()].forEach(() => {
|
|
45
|
+
const link = links[Math.floor(Math.random() * links.length)];
|
|
46
|
+
Graph.emitParticle(link);
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
</script>
|
|
50
|
+
</body>
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
<head>
|
|
2
|
+
<style> body { margin: 0; } </style>
|
|
3
|
+
|
|
4
|
+
<script src="//unpkg.com/force-graph"></script>
|
|
5
|
+
<!-- <script src="../../dist/force-graph.js"></script>-->
|
|
6
|
+
|
|
7
|
+
<style>
|
|
8
|
+
.clickable { cursor: unset !important }
|
|
9
|
+
</style>
|
|
10
|
+
</head>
|
|
11
|
+
|
|
12
|
+
<body>
|
|
13
|
+
<div id="graph"></div>
|
|
14
|
+
|
|
15
|
+
<script>
|
|
16
|
+
const rootId = 0;
|
|
17
|
+
|
|
18
|
+
// Random tree
|
|
19
|
+
const N = 300;
|
|
20
|
+
const gData = {
|
|
21
|
+
nodes: [...Array(N).keys()].map(i => ({ id: i, collapsed: i !== rootId, childLinks: [] })),
|
|
22
|
+
links: [...Array(N).keys()]
|
|
23
|
+
.filter(id => id)
|
|
24
|
+
.map(id => ({
|
|
25
|
+
source: Math.round(Math.random() * (id - 1)),
|
|
26
|
+
target: id
|
|
27
|
+
}))
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
// link parent/children
|
|
31
|
+
const nodesById = Object.fromEntries(gData.nodes.map(node => [node.id, node]));
|
|
32
|
+
gData.links.forEach(link => {
|
|
33
|
+
nodesById[link.source].childLinks.push(link);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
const getPrunedTree = () => {
|
|
37
|
+
const visibleNodes = [];
|
|
38
|
+
const visibleLinks = [];
|
|
39
|
+
|
|
40
|
+
(function traverseTree(node = nodesById[rootId]) {
|
|
41
|
+
visibleNodes.push(node);
|
|
42
|
+
if (node.collapsed) return;
|
|
43
|
+
visibleLinks.push(...node.childLinks);
|
|
44
|
+
node.childLinks
|
|
45
|
+
.map(link => ((typeof link.target) === 'object') ? link.target : nodesById[link.target]) // get child node
|
|
46
|
+
.forEach(traverseTree);
|
|
47
|
+
})(); // IIFE
|
|
48
|
+
|
|
49
|
+
return { nodes: visibleNodes, links: visibleLinks };
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
const elem = document.getElementById('graph');
|
|
53
|
+
const Graph = ForceGraph()(elem)
|
|
54
|
+
.graphData(getPrunedTree())
|
|
55
|
+
.onNodeHover(node => elem.style.cursor = node && node.childLinks.length ? 'pointer' : null)
|
|
56
|
+
.onNodeClick(node => {
|
|
57
|
+
if (node.childLinks.length) {
|
|
58
|
+
node.collapsed = !node.collapsed; // toggle collapse state
|
|
59
|
+
Graph.graphData(getPrunedTree());
|
|
60
|
+
}
|
|
61
|
+
})
|
|
62
|
+
.linkDirectionalParticles(1)
|
|
63
|
+
.linkDirectionalParticleWidth(2.5)
|
|
64
|
+
.nodeColor(node => !node.childLinks.length ? 'green' : node.collapsed ? 'red' : 'yellow');
|
|
65
|
+
</script>
|
|
66
|
+
</body>
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
<head>
|
|
2
|
+
<style> body { margin: 0; } </style>
|
|
3
|
+
|
|
4
|
+
<script src="//unpkg.com/d3-dsv"></script>
|
|
5
|
+
<script src="//unpkg.com/d3-quadtree"></script>
|
|
6
|
+
<script src="//unpkg.com/d3-force"></script>
|
|
7
|
+
|
|
8
|
+
<script src="//unpkg.com/force-graph"></script>
|
|
9
|
+
<!--<script src="../../dist/force-graph.js"></script>-->
|
|
10
|
+
|
|
11
|
+
<style>
|
|
12
|
+
.clickable { cursor: unset !important }
|
|
13
|
+
</style>
|
|
14
|
+
</head>
|
|
15
|
+
|
|
16
|
+
<body>
|
|
17
|
+
<div id="graph"></div>
|
|
18
|
+
|
|
19
|
+
<script>
|
|
20
|
+
fetch('../datasets/d3-dependencies.csv').then(r => r.text()).then(d3.csvParse).then(data => {
|
|
21
|
+
const nodes = [], links = [];
|
|
22
|
+
data.forEach(({ size, path }) => {
|
|
23
|
+
const levels = path.split('/'),
|
|
24
|
+
level = levels.length - 1,
|
|
25
|
+
module = level > 0 ? levels[1] : null,
|
|
26
|
+
leaf = levels.pop(),
|
|
27
|
+
parent = levels.join('/');
|
|
28
|
+
|
|
29
|
+
const node = {
|
|
30
|
+
id: path,
|
|
31
|
+
leaf,
|
|
32
|
+
module,
|
|
33
|
+
collapsed: level > 0,
|
|
34
|
+
childLinks: []
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
nodes.push(node);
|
|
38
|
+
|
|
39
|
+
if (parent) {
|
|
40
|
+
links.push({ source: parent, target: path });
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
const rootId = 'd3';
|
|
45
|
+
|
|
46
|
+
// link parent/children
|
|
47
|
+
const nodesById = Object.fromEntries(nodes.map(node => [node.id, node]));
|
|
48
|
+
links.forEach(link => {
|
|
49
|
+
nodesById[link.source].childLinks.push(link);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
const getPrunedTree = () => {
|
|
53
|
+
const visibleNodes = [];
|
|
54
|
+
const visibleLinks = [];
|
|
55
|
+
|
|
56
|
+
(function traverseTree(node = nodesById[rootId]) {
|
|
57
|
+
visibleNodes.push(node);
|
|
58
|
+
if (node.collapsed) return;
|
|
59
|
+
visibleLinks.push(...node.childLinks);
|
|
60
|
+
node.childLinks
|
|
61
|
+
.map(link => ((typeof link.target) === 'object') ? link.target : nodesById[link.target]) // get child node
|
|
62
|
+
.forEach(traverseTree);
|
|
63
|
+
})(); // IIFE
|
|
64
|
+
|
|
65
|
+
return { nodes: visibleNodes, links: visibleLinks };
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
const elem = document.getElementById('graph');
|
|
69
|
+
const Graph = ForceGraph()
|
|
70
|
+
(elem)
|
|
71
|
+
.graphData(getPrunedTree())
|
|
72
|
+
.nodeLabel('id')
|
|
73
|
+
.nodeColor(node => !node.childLinks.length ? 'green' : node.collapsed ? 'red' : 'yellow')
|
|
74
|
+
.onNodeHover(node => elem.style.cursor = node && node.childLinks.length ? 'pointer' : null)
|
|
75
|
+
.onNodeClick(node => {
|
|
76
|
+
node.collapsed = !node.collapsed; // toggle collapse state
|
|
77
|
+
Graph.graphData(getPrunedTree());
|
|
78
|
+
})
|
|
79
|
+
.dagMode('td')
|
|
80
|
+
.dagLevelDistance(90)
|
|
81
|
+
.d3Force('collision', d3.forceCollide(node => Graph.nodeRelSize()))
|
|
82
|
+
.warmupTicks(250);
|
|
83
|
+
});
|
|
84
|
+
</script>
|
|
85
|
+
</body>
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
<head>
|
|
2
|
+
<style> body { margin: 0; } </style>
|
|
3
|
+
|
|
4
|
+
<script src="//unpkg.com/force-graph"></script>
|
|
5
|
+
<!-- <script src="../../dist/force-graph.js"></script>-->
|
|
6
|
+
</head>
|
|
7
|
+
|
|
8
|
+
<body>
|
|
9
|
+
<div id="graph"></div>
|
|
10
|
+
|
|
11
|
+
<script>
|
|
12
|
+
// Random tree
|
|
13
|
+
const N = 100;
|
|
14
|
+
const gData = {
|
|
15
|
+
nodes: [...Array(N).keys()].map(i => ({ id: i })),
|
|
16
|
+
links: [...Array(N).keys()]
|
|
17
|
+
.filter(id => id)
|
|
18
|
+
.map(id => ({
|
|
19
|
+
source: id,
|
|
20
|
+
target: Math.round(Math.random() * (id-1))
|
|
21
|
+
}))
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
const Graph = ForceGraph()
|
|
25
|
+
(document.getElementById('graph'))
|
|
26
|
+
.cooldownTicks(100)
|
|
27
|
+
.graphData(gData);
|
|
28
|
+
|
|
29
|
+
Graph.d3Force('center', null);
|
|
30
|
+
|
|
31
|
+
// fit to canvas when engine stops
|
|
32
|
+
Graph.onEngineStop(() => Graph.zoomToFit(400));
|
|
33
|
+
</script>
|
|
34
|
+
</body>
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
<head>
|
|
2
|
+
<style> body { margin: 0; } </style>
|
|
3
|
+
|
|
4
|
+
<script src="//unpkg.com/force-graph"></script>
|
|
5
|
+
<!--<script src="../../dist/force-graph.js"></script>-->
|
|
6
|
+
</head>
|
|
7
|
+
|
|
8
|
+
<body>
|
|
9
|
+
<div id="graph"></div>
|
|
10
|
+
|
|
11
|
+
<script>
|
|
12
|
+
fetch('../datasets/miserables.json').then(res => res.json()).then(data => {
|
|
13
|
+
const Graph = ForceGraph()
|
|
14
|
+
(document.getElementById('graph'))
|
|
15
|
+
.graphData(data)
|
|
16
|
+
.nodeLabel('id')
|
|
17
|
+
.nodeAutoColorBy('group')
|
|
18
|
+
.onNodeDragEnd(node => {
|
|
19
|
+
node.fx = node.x;
|
|
20
|
+
node.fy = node.y;
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
</script>
|
|
24
|
+
</body>
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
<head>
|
|
2
|
+
<style> body { margin: 0; } </style>
|
|
3
|
+
|
|
4
|
+
<script src="//unpkg.com/force-graph"></script>
|
|
5
|
+
<!--<script src="../../dist/force-graph.js"></script>-->
|
|
6
|
+
</head>
|
|
7
|
+
|
|
8
|
+
<body>
|
|
9
|
+
<div id="graph"></div>
|
|
10
|
+
|
|
11
|
+
<script>
|
|
12
|
+
// Random tree
|
|
13
|
+
const N = 80;
|
|
14
|
+
const gData = {
|
|
15
|
+
nodes: [...Array(N).keys()].map(i => ({ id: i })),
|
|
16
|
+
links: [...Array(N).keys()]
|
|
17
|
+
.filter(id => id)
|
|
18
|
+
.map(id => ({
|
|
19
|
+
source: id,
|
|
20
|
+
target: Math.round(Math.random() * (id-1))
|
|
21
|
+
}))
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
// cross-link node objects
|
|
25
|
+
gData.links.forEach(link => {
|
|
26
|
+
const a = gData.nodes[link.source];
|
|
27
|
+
const b = gData.nodes[link.target];
|
|
28
|
+
!a.neighbors && (a.neighbors = []);
|
|
29
|
+
!b.neighbors && (b.neighbors = []);
|
|
30
|
+
a.neighbors.push(b);
|
|
31
|
+
b.neighbors.push(a);
|
|
32
|
+
|
|
33
|
+
!a.links && (a.links = []);
|
|
34
|
+
!b.links && (b.links = []);
|
|
35
|
+
a.links.push(link);
|
|
36
|
+
b.links.push(link);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
const NODE_R = 8;
|
|
40
|
+
|
|
41
|
+
const highlightNodes = new Set();
|
|
42
|
+
const highlightLinks = new Set();
|
|
43
|
+
let hoverNode = null;
|
|
44
|
+
|
|
45
|
+
const elem = document.getElementById('graph');
|
|
46
|
+
|
|
47
|
+
ForceGraph()(elem)
|
|
48
|
+
.graphData(gData)
|
|
49
|
+
.nodeRelSize(NODE_R)
|
|
50
|
+
.onNodeHover(node => {
|
|
51
|
+
highlightNodes.clear();
|
|
52
|
+
highlightLinks.clear();
|
|
53
|
+
if (node) {
|
|
54
|
+
highlightNodes.add(node);
|
|
55
|
+
node.neighbors.forEach(neighbor => highlightNodes.add(neighbor));
|
|
56
|
+
node.links.forEach(link => highlightLinks.add(link));
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
hoverNode = node || null;
|
|
60
|
+
})
|
|
61
|
+
.onLinkHover(link => {
|
|
62
|
+
highlightNodes.clear();
|
|
63
|
+
highlightLinks.clear();
|
|
64
|
+
|
|
65
|
+
if (link) {
|
|
66
|
+
highlightLinks.add(link);
|
|
67
|
+
highlightNodes.add(link.source);
|
|
68
|
+
highlightNodes.add(link.target);
|
|
69
|
+
}
|
|
70
|
+
})
|
|
71
|
+
.autoPauseRedraw(false) // keep redrawing after engine has stopped
|
|
72
|
+
.linkWidth(link => highlightLinks.has(link) ? 5 : 1)
|
|
73
|
+
.linkDirectionalParticles(4)
|
|
74
|
+
.linkDirectionalParticleWidth(link => highlightLinks.has(link) ? 4 : 0)
|
|
75
|
+
.nodeCanvasObjectMode(node => highlightNodes.has(node) ? 'before' : undefined)
|
|
76
|
+
.nodeCanvasObject((node, ctx) => {
|
|
77
|
+
// add ring just for highlighted nodes
|
|
78
|
+
ctx.beginPath();
|
|
79
|
+
ctx.arc(node.x, node.y, NODE_R * 1.4, 0, 2 * Math.PI, false);
|
|
80
|
+
ctx.fillStyle = node === hoverNode ? 'red' : 'orange';
|
|
81
|
+
ctx.fill();
|
|
82
|
+
});
|
|
83
|
+
</script>
|
|
84
|
+
</body>
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
<head>
|
|
2
|
+
<style> body { margin: 0; } </style>
|
|
3
|
+
|
|
4
|
+
<script src="//unpkg.com/force-graph"></script>
|
|
5
|
+
<!--<script src="../../dist/force-graph.js"></script>-->
|
|
6
|
+
</head>
|
|
7
|
+
|
|
8
|
+
<body>
|
|
9
|
+
<div id="graph"></div>
|
|
10
|
+
|
|
11
|
+
<script>
|
|
12
|
+
window.devicePixelRatio = 1; // use standard resolution in retina displays
|
|
13
|
+
|
|
14
|
+
// Random tree
|
|
15
|
+
const N = 500000;
|
|
16
|
+
const gData = {
|
|
17
|
+
nodes: [...Array(N).keys()].map(i => ({ id: i })),
|
|
18
|
+
links: [...Array(N).keys()]
|
|
19
|
+
.filter(id => id)
|
|
20
|
+
.map(id => ({
|
|
21
|
+
source: id,
|
|
22
|
+
target: Math.round(Math.random() * (id-1))
|
|
23
|
+
}))
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
const Graph = ForceGraph()
|
|
27
|
+
(document.getElementById('graph'))
|
|
28
|
+
.linkColor(() => 'rgba(0,0,0,0.04)')
|
|
29
|
+
.enablePointerInteraction(false)
|
|
30
|
+
.d3AlphaDecay(0)
|
|
31
|
+
.d3VelocityDecay(0.08)
|
|
32
|
+
.warmupTicks(20)
|
|
33
|
+
.cooldownTicks(0)
|
|
34
|
+
.zoom(0.01)
|
|
35
|
+
.graphData(gData);
|
|
36
|
+
</script>
|
|
37
|
+
</body>
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
<head>
|
|
2
|
+
<style> body { margin: 0; } </style>
|
|
3
|
+
|
|
4
|
+
<script src="//unpkg.com/force-graph"></script>
|
|
5
|
+
<!--<script src="../../dist/force-graph.js"></script>-->
|
|
6
|
+
</head>
|
|
7
|
+
|
|
8
|
+
<body>
|
|
9
|
+
<div id="graph"></div>
|
|
10
|
+
|
|
11
|
+
<script>
|
|
12
|
+
const imgs = ['cat.jpg', 'dog.jpg', 'eagle.jpg', 'elephant.jpg', 'grasshopper.jpg', 'octopus.jpg', 'owl.jpg', 'panda.jpg', 'squirrel.jpg', 'tiger.jpg', 'whale.jpg']
|
|
13
|
+
.map(src => {
|
|
14
|
+
const img = new Image();
|
|
15
|
+
img.src = `./imgs/${src}`;
|
|
16
|
+
return img;
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
// Random connected graph
|
|
20
|
+
const gData = {
|
|
21
|
+
nodes: imgs.map((img, id) => ({ id, img })),
|
|
22
|
+
links: [...Array(imgs.length).keys()]
|
|
23
|
+
.filter(id => id)
|
|
24
|
+
.map(id => ({
|
|
25
|
+
source: id,
|
|
26
|
+
target: Math.round(Math.random() * (id-1))
|
|
27
|
+
}))
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
const Graph = ForceGraph()
|
|
31
|
+
(document.getElementById('graph'))
|
|
32
|
+
.nodeCanvasObject(({ img, x, y }, ctx) => {
|
|
33
|
+
const size = 12;
|
|
34
|
+
ctx.drawImage(img, x - size / 2, y - size / 2, size, size);
|
|
35
|
+
})
|
|
36
|
+
.nodePointerAreaPaint((node, color, ctx) => {
|
|
37
|
+
const size = 12;
|
|
38
|
+
ctx.fillStyle = color;
|
|
39
|
+
ctx.fillRect(node.x - size / 2, node.y - size / 2, size, size); // draw square as pointer trap
|
|
40
|
+
})
|
|
41
|
+
.graphData(gData);
|
|
42
|
+
</script>
|
|
43
|
+
</body>
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
<head>
|
|
2
|
+
<style> body { margin: 0; } </style>
|
|
3
|
+
|
|
4
|
+
<script src="//unpkg.com/force-graph"></script>
|
|
5
|
+
<!--<script src="../../dist/force-graph.js"></script>-->
|
|
6
|
+
</head>
|
|
7
|
+
|
|
8
|
+
<body>
|
|
9
|
+
<div id="graph"></div>
|
|
10
|
+
|
|
11
|
+
<script>
|
|
12
|
+
window.devicePixelRatio = 1; // use standard resolution in retina displays
|
|
13
|
+
|
|
14
|
+
fetch('../datasets/mplate.mtx').then(res => res.text()).then(mtxData => {
|
|
15
|
+
let nodeSet = new Set();
|
|
16
|
+
|
|
17
|
+
const pairs = mtxData.split('\n')
|
|
18
|
+
.slice(14, -1)
|
|
19
|
+
.map(d => d.split(' '));
|
|
20
|
+
|
|
21
|
+
pairs.forEach(d => {
|
|
22
|
+
nodeSet.add(d[0]);
|
|
23
|
+
nodeSet.add(d[1]);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
const nodes = Array.from(nodeSet).map(d => ({ id: d }));
|
|
27
|
+
const links = pairs.filter(d => d[0] !== d[1])
|
|
28
|
+
.map(d => ({ source: d[0], target: d[1] }));
|
|
29
|
+
|
|
30
|
+
const Graph = ForceGraph()
|
|
31
|
+
(document.getElementById('graph'))
|
|
32
|
+
.graphData({ nodes, links })
|
|
33
|
+
.d3AlphaDecay(0)
|
|
34
|
+
.d3VelocityDecay(0.08)
|
|
35
|
+
.cooldownTime(60000)
|
|
36
|
+
.linkColor(() => 'rgba(0,0,0,0.05)')
|
|
37
|
+
.zoom(0.05)
|
|
38
|
+
.enablePointerInteraction(false);
|
|
39
|
+
});
|
|
40
|
+
</script>
|
|
41
|
+
</body>
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
<head>
|
|
2
|
+
<style> body { margin: 0; } </style>
|
|
3
|
+
|
|
4
|
+
<script src="//unpkg.com/force-graph"></script>
|
|
5
|
+
<!--<script src="../../dist/force-graph.js"></script>-->
|
|
6
|
+
</head>
|
|
7
|
+
|
|
8
|
+
<body>
|
|
9
|
+
<div id="graph"></div>
|
|
10
|
+
|
|
11
|
+
<script>
|
|
12
|
+
fetch('../datasets/miserables.json').then(res => res.json()).then(data => {
|
|
13
|
+
const Graph = ForceGraph()
|
|
14
|
+
(document.getElementById('graph'))
|
|
15
|
+
.graphData(data)
|
|
16
|
+
.nodeId('id')
|
|
17
|
+
.nodeVal('val')
|
|
18
|
+
.nodeLabel('id')
|
|
19
|
+
.nodeAutoColorBy('group')
|
|
20
|
+
.linkSource('source')
|
|
21
|
+
.linkTarget('target')
|
|
22
|
+
});
|
|
23
|
+
</script>
|
|
24
|
+
</body>
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
<head>
|
|
2
|
+
<style> body { margin: 0; } </style>
|
|
3
|
+
|
|
4
|
+
<script src="//unpkg.com/force-graph"></script>
|
|
5
|
+
<!--<script src="../../dist/force-graph.js"></script>-->
|
|
6
|
+
</head>
|
|
7
|
+
|
|
8
|
+
<body>
|
|
9
|
+
<div id="graph"></div>
|
|
10
|
+
|
|
11
|
+
<script>
|
|
12
|
+
fetch('../datasets/blocks.json').then(res => res.json()).then(data => {
|
|
13
|
+
const elem = document.getElementById('graph');
|
|
14
|
+
|
|
15
|
+
const Graph = ForceGraph()(elem)
|
|
16
|
+
.backgroundColor('#101020')
|
|
17
|
+
.nodeRelSize(6)
|
|
18
|
+
.nodeAutoColorBy('user')
|
|
19
|
+
.nodeLabel(node => `${node.user}: ${node.description}`)
|
|
20
|
+
.linkColor(() => 'rgba(255,255,255,0.2)')
|
|
21
|
+
.linkDirectionalParticles(1)
|
|
22
|
+
.onNodeClick(node => window.open(`https://bl.ocks.org/${node.user}/${node.id}`, '_blank'))
|
|
23
|
+
.graphData(data);
|
|
24
|
+
});
|
|
25
|
+
</script>
|
|
26
|
+
</body>
|
|
Binary file
|