@react-fabric/graph 1.0.0-beta.58

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.
Files changed (208) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +10 -0
  3. package/css/styles.css +56 -0
  4. package/dist/cjs/_virtual/_commonjs-dynamic-modules.js +7 -0
  5. package/dist/cjs/_virtual/_commonjsHelpers.js +7 -0
  6. package/dist/cjs/_virtual/_rollup-plugin-web-worker-loader__helper__auto__createBase64WorkerFactory.js +14 -0
  7. package/dist/cjs/_virtual/_rollup-plugin-web-worker-loader__helper__auto__isNodeJS.js +9 -0
  8. package/dist/cjs/_virtual/_rollup-plugin-web-worker-loader__helper__browser__createBase64WorkerFactory.js +35 -0
  9. package/dist/cjs/_virtual/_rollup-plugin-web-worker-loader__helper__node__WorkerClass.js +11 -0
  10. package/dist/cjs/_virtual/_rollup-plugin-web-worker-loader__helper__node__createBase64WorkerFactory.js +20 -0
  11. package/dist/cjs/_virtual/elk-worker.js +8 -0
  12. package/dist/cjs/_virtual/elk.bundled.js +5 -0
  13. package/dist/cjs/node_modules/elkjs/lib/elk.bundled.js +6667 -0
  14. package/dist/cjs/packages/graph/src/components/Context.js +108 -0
  15. package/dist/cjs/packages/graph/src/components/ContextMenu.js +134 -0
  16. package/dist/cjs/packages/graph/src/components/Tools.js +127 -0
  17. package/dist/cjs/packages/graph/src/components/Viewer.js +57 -0
  18. package/dist/cjs/packages/graph/src/constants/index.js +16 -0
  19. package/dist/cjs/packages/graph/src/graph/index.js +425 -0
  20. package/dist/cjs/packages/graph/src/hooks/sigmaDragSelect.js +169 -0
  21. package/dist/cjs/packages/graph/src/hooks/sigmaHilighter.js +83 -0
  22. package/dist/cjs/packages/graph/src/hooks/sigmaMouseActions.js +145 -0
  23. package/dist/cjs/packages/graph/src/hooks/useGraphology.js +41 -0
  24. package/dist/cjs/packages/graph/src/hooks/useSigma.js +112 -0
  25. package/dist/cjs/packages/graph/src/index.js +33 -0
  26. package/dist/cjs/packages/graph/src/programs/arrow-head/frag.glsl.js +8 -0
  27. package/dist/cjs/packages/graph/src/programs/arrow-head/index.js +142 -0
  28. package/dist/cjs/packages/graph/src/programs/arrow-head/vert.glsl.js +8 -0
  29. package/dist/cjs/packages/graph/src/programs/edge-curve/drawLabel.js +136 -0
  30. package/dist/cjs/packages/graph/src/programs/edge-curve/frag.glsl.js +8 -0
  31. package/dist/cjs/packages/graph/src/programs/edge-curve/index.js +157 -0
  32. package/dist/cjs/packages/graph/src/programs/edge-curve/vert.glsl.js +8 -0
  33. package/dist/cjs/packages/graph/src/programs/edge-line/drawLabel.js +70 -0
  34. package/dist/cjs/packages/graph/src/programs/edge-line/frag.glsl.js +8 -0
  35. package/dist/cjs/packages/graph/src/programs/edge-line/index.js +166 -0
  36. package/dist/cjs/packages/graph/src/programs/edge-line/vert.glsl.js +8 -0
  37. package/dist/cjs/packages/graph/src/programs/node-badge/factory.js +249 -0
  38. package/dist/cjs/packages/graph/src/programs/node-badge/frag.glsl.js +8 -0
  39. package/dist/cjs/packages/graph/src/programs/node-badge/index.js +33 -0
  40. package/dist/cjs/packages/graph/src/programs/node-badge/texture.js +455 -0
  41. package/dist/cjs/packages/graph/src/programs/node-badge/vert.glsl.js +19 -0
  42. package/dist/cjs/packages/graph/src/programs/node-circle/base/drawHover.js +70 -0
  43. package/dist/cjs/packages/graph/src/programs/node-circle/base/drawLabel.js +112 -0
  44. package/dist/cjs/packages/graph/src/programs/node-circle/base/frag.glsl.js +8 -0
  45. package/dist/cjs/packages/graph/src/programs/node-circle/base/index.js +136 -0
  46. package/dist/cjs/packages/graph/src/programs/node-circle/base/vert.glsl.js +8 -0
  47. package/dist/cjs/packages/graph/src/programs/node-circle/index.js +15 -0
  48. package/dist/cjs/packages/graph/src/programs/node-image/factory.js +223 -0
  49. package/dist/cjs/packages/graph/src/programs/node-image/frag.glsl.js +8 -0
  50. package/dist/cjs/packages/graph/src/programs/node-image/index.js +14 -0
  51. package/dist/cjs/packages/graph/src/programs/node-image/texture.js +472 -0
  52. package/dist/cjs/packages/graph/src/programs/node-image/vert.glsl.js +8 -0
  53. package/dist/cjs/packages/graph/src/programs/node-rect/base/drawHover.js +67 -0
  54. package/dist/cjs/packages/graph/src/programs/node-rect/base/drawLabel.js +106 -0
  55. package/dist/cjs/packages/graph/src/programs/node-rect/base/frag.glsl.js +8 -0
  56. package/dist/cjs/packages/graph/src/programs/node-rect/base/index.js +135 -0
  57. package/dist/cjs/packages/graph/src/programs/node-rect/base/vert.glsl.js +8 -0
  58. package/dist/cjs/packages/graph/src/programs/node-rect/index.js +15 -0
  59. package/dist/esm/_virtual/_commonjs-dynamic-modules.js +7 -0
  60. package/dist/esm/_virtual/_commonjsHelpers.js +7 -0
  61. package/dist/esm/_virtual/_rollup-plugin-web-worker-loader__helper__auto__createBase64WorkerFactory.js +14 -0
  62. package/dist/esm/_virtual/_rollup-plugin-web-worker-loader__helper__auto__isNodeJS.js +9 -0
  63. package/dist/esm/_virtual/_rollup-plugin-web-worker-loader__helper__browser__createBase64WorkerFactory.js +34 -0
  64. package/dist/esm/_virtual/_rollup-plugin-web-worker-loader__helper__node__WorkerClass.js +13 -0
  65. package/dist/esm/_virtual/_rollup-plugin-web-worker-loader__helper__node__createBase64WorkerFactory.js +20 -0
  66. package/dist/esm/_virtual/elk-worker.js +8 -0
  67. package/dist/esm/_virtual/elk.bundled.js +5 -0
  68. package/dist/esm/node_modules/elkjs/lib/elk.bundled.js +6667 -0
  69. package/dist/esm/packages/graph/src/components/Context.js +107 -0
  70. package/dist/esm/packages/graph/src/components/ContextMenu.js +134 -0
  71. package/dist/esm/packages/graph/src/components/Tools.js +127 -0
  72. package/dist/esm/packages/graph/src/components/Viewer.js +57 -0
  73. package/dist/esm/packages/graph/src/constants/index.js +16 -0
  74. package/dist/esm/packages/graph/src/graph/index.js +425 -0
  75. package/dist/esm/packages/graph/src/hooks/sigmaDragSelect.js +169 -0
  76. package/dist/esm/packages/graph/src/hooks/sigmaHilighter.js +83 -0
  77. package/dist/esm/packages/graph/src/hooks/sigmaMouseActions.js +145 -0
  78. package/dist/esm/packages/graph/src/hooks/useGraphology.js +41 -0
  79. package/dist/esm/packages/graph/src/hooks/useSigma.js +112 -0
  80. package/dist/esm/packages/graph/src/index.js +30 -0
  81. package/dist/esm/packages/graph/src/programs/arrow-head/frag.glsl.js +8 -0
  82. package/dist/esm/packages/graph/src/programs/arrow-head/index.js +141 -0
  83. package/dist/esm/packages/graph/src/programs/arrow-head/vert.glsl.js +8 -0
  84. package/dist/esm/packages/graph/src/programs/edge-curve/drawLabel.js +136 -0
  85. package/dist/esm/packages/graph/src/programs/edge-curve/frag.glsl.js +8 -0
  86. package/dist/esm/packages/graph/src/programs/edge-curve/index.js +156 -0
  87. package/dist/esm/packages/graph/src/programs/edge-curve/vert.glsl.js +8 -0
  88. package/dist/esm/packages/graph/src/programs/edge-line/drawLabel.js +70 -0
  89. package/dist/esm/packages/graph/src/programs/edge-line/frag.glsl.js +8 -0
  90. package/dist/esm/packages/graph/src/programs/edge-line/index.js +166 -0
  91. package/dist/esm/packages/graph/src/programs/edge-line/vert.glsl.js +8 -0
  92. package/dist/esm/packages/graph/src/programs/node-badge/factory.js +249 -0
  93. package/dist/esm/packages/graph/src/programs/node-badge/frag.glsl.js +8 -0
  94. package/dist/esm/packages/graph/src/programs/node-badge/index.js +32 -0
  95. package/dist/esm/packages/graph/src/programs/node-badge/texture.js +445 -0
  96. package/dist/esm/packages/graph/src/programs/node-badge/vert.glsl.js +19 -0
  97. package/dist/esm/packages/graph/src/programs/node-circle/base/drawHover.js +70 -0
  98. package/dist/esm/packages/graph/src/programs/node-circle/base/drawLabel.js +112 -0
  99. package/dist/esm/packages/graph/src/programs/node-circle/base/frag.glsl.js +8 -0
  100. package/dist/esm/packages/graph/src/programs/node-circle/base/index.js +136 -0
  101. package/dist/esm/packages/graph/src/programs/node-circle/base/vert.glsl.js +8 -0
  102. package/dist/esm/packages/graph/src/programs/node-circle/index.js +15 -0
  103. package/dist/esm/packages/graph/src/programs/node-image/factory.js +223 -0
  104. package/dist/esm/packages/graph/src/programs/node-image/frag.glsl.js +8 -0
  105. package/dist/esm/packages/graph/src/programs/node-image/index.js +13 -0
  106. package/dist/esm/packages/graph/src/programs/node-image/texture.js +462 -0
  107. package/dist/esm/packages/graph/src/programs/node-image/vert.glsl.js +8 -0
  108. package/dist/esm/packages/graph/src/programs/node-rect/base/drawHover.js +67 -0
  109. package/dist/esm/packages/graph/src/programs/node-rect/base/drawLabel.js +106 -0
  110. package/dist/esm/packages/graph/src/programs/node-rect/base/frag.glsl.js +8 -0
  111. package/dist/esm/packages/graph/src/programs/node-rect/base/index.js +135 -0
  112. package/dist/esm/packages/graph/src/programs/node-rect/base/vert.glsl.js +8 -0
  113. package/dist/esm/packages/graph/src/programs/node-rect/index.js +15 -0
  114. package/dist/types/components/Context.d.ts +18 -0
  115. package/dist/types/components/ContextMenu.d.ts +1 -0
  116. package/dist/types/components/Tools.d.ts +1 -0
  117. package/dist/types/components/Viewer.d.ts +2 -0
  118. package/dist/types/constants/index.d.ts +12 -0
  119. package/dist/types/graph/index.d.ts +30 -0
  120. package/dist/types/graph/layout.worker.d.ts +1 -0
  121. package/dist/types/hooks/sigmaDragSelect.d.ts +8 -0
  122. package/dist/types/hooks/sigmaHilighter.d.ts +3 -0
  123. package/dist/types/hooks/sigmaMouseActions.d.ts +3 -0
  124. package/dist/types/hooks/useGraphology.d.ts +6 -0
  125. package/dist/types/hooks/useSigma.d.ts +8 -0
  126. package/dist/types/index.d.ts +3 -0
  127. package/dist/types/programs/arrow-head/frag.glsl.d.ts +2 -0
  128. package/dist/types/programs/arrow-head/index.d.ts +9 -0
  129. package/dist/types/programs/arrow-head/vert.glsl.d.ts +2 -0
  130. package/dist/types/programs/edge-curve/drawLabel.d.ts +6 -0
  131. package/dist/types/programs/edge-curve/frag.glsl.d.ts +2 -0
  132. package/dist/types/programs/edge-curve/index.d.ts +43 -0
  133. package/dist/types/programs/edge-curve/vert.glsl.d.ts +2 -0
  134. package/dist/types/programs/edge-line/drawLabel.d.ts +5 -0
  135. package/dist/types/programs/edge-line/frag.glsl.d.ts +2 -0
  136. package/dist/types/programs/edge-line/index.d.ts +11 -0
  137. package/dist/types/programs/edge-line/vert.glsl.d.ts +2 -0
  138. package/dist/types/programs/node-badge/factory.d.ts +27 -0
  139. package/dist/types/programs/node-badge/frag.glsl.d.ts +2 -0
  140. package/dist/types/programs/node-badge/index.d.ts +5 -0
  141. package/dist/types/programs/node-badge/texture.d.ts +102 -0
  142. package/dist/types/programs/node-badge/vert.glsl.d.ts +2 -0
  143. package/dist/types/programs/node-circle/base/drawHover.d.ts +8 -0
  144. package/dist/types/programs/node-circle/base/drawLabel.d.ts +8 -0
  145. package/dist/types/programs/node-circle/base/frag.glsl.d.ts +2 -0
  146. package/dist/types/programs/node-circle/base/index.d.ts +37 -0
  147. package/dist/types/programs/node-circle/base/vert.glsl.d.ts +2 -0
  148. package/dist/types/programs/node-circle/index.d.ts +11 -0
  149. package/dist/types/programs/node-image/factory.d.ts +25 -0
  150. package/dist/types/programs/node-image/frag.glsl.d.ts +2 -0
  151. package/dist/types/programs/node-image/index.d.ts +5 -0
  152. package/dist/types/programs/node-image/texture.d.ts +102 -0
  153. package/dist/types/programs/node-image/vert.glsl.d.ts +2 -0
  154. package/dist/types/programs/node-rect/base/drawHover.d.ts +8 -0
  155. package/dist/types/programs/node-rect/base/drawLabel.d.ts +8 -0
  156. package/dist/types/programs/node-rect/base/frag.glsl.d.ts +2 -0
  157. package/dist/types/programs/node-rect/base/index.d.ts +34 -0
  158. package/dist/types/programs/node-rect/base/vert.glsl.d.ts +2 -0
  159. package/dist/types/programs/node-rect/index.d.ts +11 -0
  160. package/dist/types/types/index.d.ts +189 -0
  161. package/package.json +69 -0
  162. package/src/components/Context.tsx +135 -0
  163. package/src/components/ContextMenu.tsx +156 -0
  164. package/src/components/Tools.tsx +107 -0
  165. package/src/components/Viewer.tsx +75 -0
  166. package/src/constants/index.ts +22 -0
  167. package/src/graph/index.ts +428 -0
  168. package/src/graph/layout.worker.ts +42 -0
  169. package/src/hooks/sigmaDragSelect.ts +219 -0
  170. package/src/hooks/sigmaHilighter.ts +107 -0
  171. package/src/hooks/sigmaMouseActions.ts +153 -0
  172. package/src/hooks/useGraphology.ts +31 -0
  173. package/src/hooks/useSigma.ts +118 -0
  174. package/src/index.ts +34 -0
  175. package/src/programs/arrow-head/frag.glsl.ts +18 -0
  176. package/src/programs/arrow-head/index.ts +148 -0
  177. package/src/programs/arrow-head/vert.glsl.ts +75 -0
  178. package/src/programs/edge-curve/drawLabel.ts +166 -0
  179. package/src/programs/edge-curve/frag.glsl.ts +86 -0
  180. package/src/programs/edge-curve/index.ts +158 -0
  181. package/src/programs/edge-curve/vert.glsl.ts +110 -0
  182. package/src/programs/edge-line/drawLabel.ts +113 -0
  183. package/src/programs/edge-line/frag.glsl.ts +34 -0
  184. package/src/programs/edge-line/index.ts +165 -0
  185. package/src/programs/edge-line/vert.glsl.ts +104 -0
  186. package/src/programs/node-badge/factory.ts +327 -0
  187. package/src/programs/node-badge/frag.glsl.ts +79 -0
  188. package/src/programs/node-badge/index.ts +35 -0
  189. package/src/programs/node-badge/texture.ts +425 -0
  190. package/src/programs/node-badge/vert.glsl.ts +99 -0
  191. package/src/programs/node-circle/base/drawHover.ts +80 -0
  192. package/src/programs/node-circle/base/drawLabel.ts +145 -0
  193. package/src/programs/node-circle/base/frag.glsl.ts +72 -0
  194. package/src/programs/node-circle/base/index.ts +102 -0
  195. package/src/programs/node-circle/base/vert.glsl.ts +83 -0
  196. package/src/programs/node-circle/index.ts +19 -0
  197. package/src/programs/node-image/factory.ts +301 -0
  198. package/src/programs/node-image/frag.glsl.ts +97 -0
  199. package/src/programs/node-image/index.ts +7 -0
  200. package/src/programs/node-image/texture.ts +435 -0
  201. package/src/programs/node-image/vert.glsl.ts +60 -0
  202. package/src/programs/node-rect/base/drawHover.ts +77 -0
  203. package/src/programs/node-rect/base/drawLabel.ts +149 -0
  204. package/src/programs/node-rect/base/frag.glsl.ts +67 -0
  205. package/src/programs/node-rect/base/index.ts +109 -0
  206. package/src/programs/node-rect/base/vert.glsl.ts +87 -0
  207. package/src/programs/node-rect/index.ts +19 -0
  208. package/src/types/index.ts +210 -0
@@ -0,0 +1,107 @@
1
+ import { debounce } from "@react-fabric/utilities";
2
+ import type Graph from "graphology";
3
+ import type Sigma from "sigma";
4
+ import { SigmaEdgeEventPayload, SigmaNodeEventPayload } from "sigma/types";
5
+ import { EdgeAttributes, NodeAttributes } from "../types";
6
+
7
+ export const attachHighlighter = (
8
+ renderer: Sigma<NodeAttributes<any>, EdgeAttributes<any>>,
9
+ ) => {
10
+ const handleEnterNode = (id: string, graph: Graph) => {
11
+ try {
12
+ const neighbors = graph.neighbors(id);
13
+ graph.forEachNode((node) => {
14
+ graph.setNodeAttribute(
15
+ node,
16
+ "opacity",
17
+ node !== id && !neighbors.includes(node) ? 0.1 : 1,
18
+ );
19
+ });
20
+ graph.forEachEdge((edge) => {
21
+ graph.setEdgeAttribute(
22
+ edge,
23
+ "opacity",
24
+ !graph.hasExtremity(edge, id) ? 0.1 : 1,
25
+ );
26
+ });
27
+ } catch {
28
+ //
29
+ }
30
+ };
31
+
32
+ const handleLeaveNode = (graph: Graph) => {
33
+ graph.forEachNode((node) => {
34
+ graph.setNodeAttribute(node, "opacity", 1);
35
+ });
36
+ graph.forEachEdge((edge) => {
37
+ graph.setEdgeAttribute(edge, "opacity", 1);
38
+ });
39
+ };
40
+
41
+ const handleEnterEdge = (id: string, graph: Graph) => {
42
+ try {
43
+ const source = graph.source(id);
44
+ const target = graph.target(id);
45
+
46
+ graph.setEdgeAttribute(id, "zIndex", 2);
47
+ graph.setNodeAttribute(source, "zIndex", 2);
48
+ graph.setNodeAttribute(target, "zIndex", 2);
49
+
50
+ graph.setEdgeAttribute(id, "highlight", true);
51
+ graph.setNodeAttribute(source, "highlight", true);
52
+ graph.setNodeAttribute(target, "highlight", true);
53
+
54
+ graph.forEachNode((node) => {
55
+ graph.setNodeAttribute(
56
+ node,
57
+ "opacity",
58
+ node !== source && node !== target ? 0.1 : 1,
59
+ );
60
+ });
61
+ graph.forEachEdge((edge) => {
62
+ graph.setEdgeAttribute(edge, "opacity", edge !== id ? 0.1 : 1);
63
+ });
64
+ } catch {
65
+ //
66
+ }
67
+ };
68
+
69
+ const handleLeaveEdge = (id: string, graph: Graph) => {
70
+ const source = graph.source(id);
71
+ const target = graph.target(id);
72
+
73
+ graph.setEdgeAttribute(id, "zIndex", 0);
74
+ graph.setNodeAttribute(source, "zIndex", 0);
75
+ graph.setNodeAttribute(target, "zIndex", 0);
76
+
77
+ graph.setEdgeAttribute(id, "highlight", false);
78
+ graph.setNodeAttribute(source, "highlight", false);
79
+ graph.setNodeAttribute(target, "highlight", false);
80
+
81
+ graph.forEachNode((node) => {
82
+ graph.setNodeAttribute(node, "opacity", 1);
83
+ graph.setNodeAttribute(node, "highlight", false);
84
+ });
85
+ graph.forEachEdge((edge) => {
86
+ graph.setEdgeAttribute(edge, "opacity", 1);
87
+ graph.setEdgeAttribute(edge, "highlight", false);
88
+ });
89
+ };
90
+
91
+ const debouceNodeEnter = debounce((e: SigmaNodeEventPayload) => {
92
+ handleEnterNode(e.node, renderer.getGraph());
93
+ });
94
+ const debouceEdgeEnter = debounce((e: SigmaEdgeEventPayload) => {
95
+ handleEnterEdge(e.edge, renderer.getGraph());
96
+ }, 100);
97
+ renderer.on("enterNode", debouceNodeEnter);
98
+ renderer.on("leaveNode", (e) => {
99
+ debouceNodeEnter.cancel();
100
+ handleLeaveNode(renderer.getGraph());
101
+ });
102
+ renderer.on("enterEdge", debouceEdgeEnter);
103
+ renderer.on("leaveEdge", (e) => {
104
+ debouceEdgeEnter.cancel();
105
+ handleLeaveEdge(e.edge, renderer.getGraph());
106
+ });
107
+ };
@@ -0,0 +1,153 @@
1
+ import type Graph from "graphology";
2
+ import type Sigma from "sigma";
3
+ import { type MouseCoords } from "sigma/types";
4
+ import { EdgeAttributes, NodeAttributes } from "../types";
5
+
6
+ export const attachMouseActions = (
7
+ renderer: Sigma<NodeAttributes<any>, EdgeAttributes<any>>,
8
+ ) => {
9
+ let isDragging = false;
10
+ let isDragged = false;
11
+ let startPos = { x: 0, y: 0 };
12
+ let draggedNode: AnyObject;
13
+
14
+ const handleDrag =
15
+ (renderer: Sigma<NodeAttributes<any>, EdgeAttributes<any>>) =>
16
+ (e: MouseCoords) => {
17
+ if (!isDragging || !draggedNode) return;
18
+
19
+ isDragged = true;
20
+ // Get new position of node
21
+ const pos = renderer.viewportToGraph(e);
22
+ const diff = { x: pos.x - startPos.x, y: pos.y - startPos.y };
23
+
24
+ const graph = renderer.getGraph();
25
+ Object.entries<KeyValue>(draggedNode).forEach(([node, xy]) => {
26
+ graph.setNodeAttribute(node, "x", xy.x + diff.x);
27
+ graph.setNodeAttribute(node, "y", xy.y + diff.y);
28
+ });
29
+
30
+ // Prevent sigma to move camera:
31
+ e.preventSigmaDefault();
32
+ e.original.preventDefault();
33
+ e.original.stopPropagation();
34
+ };
35
+
36
+ const stopDragging = (graph: Graph) => {
37
+ // if (draggedNode) {
38
+ // Object.entries<KeyValue>(draggedNode).forEach(([node, xy]) => {
39
+ // const atts = graph.getNodeAttributes(node);
40
+ // if (atts.isGroup) {
41
+ // const diff = { x: atts.x - xy.x, y: atts.y - xy.y };
42
+ // atts.nodes?.forEach((id: string) => {
43
+ // try {
44
+ // const { x, y } = graph.getNodeAttributes(id);
45
+ // graph.setNodeAttribute(id, "x", x + diff.x);
46
+ // graph.setNodeAttribute(id, "y", y + diff.y);
47
+ // } catch {
48
+ // //
49
+ // }
50
+ // });
51
+ // }
52
+ // });
53
+ // }
54
+ isDragging = false;
55
+ draggedNode = undefined;
56
+ };
57
+
58
+ const enableDragging = (
59
+ renderer: Sigma<NodeAttributes<any>, EdgeAttributes<any>>,
60
+ ) => {
61
+ renderer.on("downNode", (e) => {
62
+ if ("button" in e.event.original && e.event.original.button === 0) {
63
+ const graph = renderer.getGraph();
64
+ isDragging = true;
65
+ draggedNode = {};
66
+ const { x = 0, y = 0 } = graph.getNodeAttributes(e.node);
67
+ draggedNode[e.node] = { x, y };
68
+ startPos = { x, y };
69
+ graph.forEachNode((node, atts) => {
70
+ if (atts.selected) {
71
+ draggedNode[node] = { x: atts.x, y: atts.y };
72
+ }
73
+ });
74
+ }
75
+ });
76
+
77
+ // On mouse move, if the drag mode is enabled, we change the position of the draggedNode
78
+ renderer.getMouseCaptor().on("mousemovebody", handleDrag(renderer));
79
+
80
+ // On mouse up, we reset the autoscale and the dragging mode
81
+ renderer.getMouseCaptor().on("mouseup", (e) => {
82
+ if (isDragging) {
83
+ stopDragging(renderer.getGraph());
84
+ e.original.preventDefault();
85
+ e.preventSigmaDefault();
86
+ }
87
+ });
88
+
89
+ // Disable the autoscale at the first down interaction
90
+ renderer.getMouseCaptor().on("mousedown", () => {
91
+ if (!renderer.getCustomBBox()) renderer.setCustomBBox(renderer.getBBox());
92
+ });
93
+ };
94
+
95
+ const resetSelection = (graph: Graph) => {
96
+ graph.forEachNode(
97
+ (node, atts) =>
98
+ atts.selected && graph.setNodeAttribute(node, "selected", false),
99
+ );
100
+ graph.forEachEdge(
101
+ (node, atts) =>
102
+ atts.selected && graph.setEdgeAttribute(node, "selected", false),
103
+ );
104
+ };
105
+
106
+ const enableSelection = (
107
+ renderer: Sigma<NodeAttributes<any>, EdgeAttributes<any>>,
108
+ ) => {
109
+ renderer.on("downNode", (e) => {
110
+ if ("button" in e.event.original && e.event.original.button === 2) {
111
+ const isSelected = renderer
112
+ .getGraph()
113
+ .getNodeAttribute(e.node, "selected");
114
+
115
+ !isSelected && resetSelection(renderer.getGraph());
116
+ !isSelected &&
117
+ renderer.getGraph().setNodeAttribute(e.node, "selected", true);
118
+ }
119
+ });
120
+ renderer.on("downEdge", (e) => {
121
+ if ("button" in e.event.original && e.event.original.button === 2) {
122
+ const isSelected = renderer
123
+ .getGraph()
124
+ .getEdgeAttribute(e.edge, "selected");
125
+
126
+ !isSelected && resetSelection(renderer.getGraph());
127
+ !isSelected &&
128
+ renderer.getGraph().setEdgeAttribute(e.edge, "selected", true);
129
+ }
130
+ });
131
+ renderer.on("clickNode", (e) => {
132
+ if (
133
+ !isDragged &&
134
+ "button" in e.event.original &&
135
+ e.event.original.button === 0
136
+ ) {
137
+ const isSelected = renderer
138
+ .getGraph()
139
+ .getNodeAttribute(e.node, "selected");
140
+
141
+ !e.event.original.shiftKey && resetSelection(renderer.getGraph());
142
+ renderer.getGraph().setNodeAttribute(e.node, "selected", !isSelected);
143
+ }
144
+ isDragged = false;
145
+ });
146
+ renderer.on("downStage", (e) => {
147
+ resetSelection(renderer.getGraph());
148
+ });
149
+ };
150
+
151
+ enableSelection(renderer);
152
+ enableDragging(renderer);
153
+ };
@@ -0,0 +1,31 @@
1
+ import { useEffect, useState } from "react";
2
+ import { Graph } from "../graph";
3
+ import { GraphProps } from "../types";
4
+
5
+ export const useGraphology = <N, E>(data: GraphProps<N, E>["data"]) => {
6
+ const [graph, setGraph] = useState(new Graph<N, E>({ multi: true }));
7
+
8
+ const [selected, setSelected] = useState<string[]>([]);
9
+
10
+ useEffect(() => {
11
+ if (data instanceof Graph) {
12
+ setGraph(data);
13
+ return;
14
+ }
15
+ graph.clear();
16
+ data && graph.import(data, false);
17
+ }, [data]);
18
+
19
+ useEffect(() => {
20
+ const handler = (nodes: string[]) => {
21
+ setSelected(nodes);
22
+ };
23
+ graph.on("nodesSelected", handler);
24
+
25
+ return () => {
26
+ graph.off("nodesSelected", handler);
27
+ };
28
+ }, [graph]);
29
+
30
+ return { graph, selected };
31
+ };
@@ -0,0 +1,118 @@
1
+ import { useIsDark } from "@react-fabric/core";
2
+ import { useEffect, useState } from "react";
3
+ import Sigma from "sigma";
4
+ import { Graph } from "../graph";
5
+ import { EdgeCurveProgram } from "../programs/edge-curve";
6
+ import { EdgeLineProgram } from "../programs/edge-line";
7
+ import { NodeCircleProgram } from "../programs/node-circle";
8
+ import { NodeRectProgram } from "../programs/node-rect";
9
+ import {
10
+ EdgeAttributes,
11
+ InternalEdgeAttributes,
12
+ InternalNodeAttributes,
13
+ NodeAttributes,
14
+ } from "../types";
15
+ import { attachHighlighter } from "./sigmaHilighter";
16
+ import { attachMouseActions } from "./sigmaMouseActions";
17
+
18
+ export const useSigma = <N, E>(
19
+ graph: Graph<N, E>,
20
+ nodeReducer?: (node: NodeAttributes<N>) => NodeAttributes<N>,
21
+ edgeReducer?: (edge: EdgeAttributes<E>) => EdgeAttributes<E>,
22
+ ) => {
23
+ const [containerRef, setContainerRef] = useState<HTMLDivElement | null>(null);
24
+ const [componentsRef, setComponentsRef] = useState<HTMLDivElement | null>(
25
+ null,
26
+ );
27
+ const isDark = useIsDark();
28
+
29
+ const [sigma, updateSigma] =
30
+ useState<Sigma<NodeAttributes<N>, EdgeAttributes<E>>>();
31
+
32
+ useEffect(() => {
33
+ if (containerRef) {
34
+ const renderer = new Sigma<
35
+ InternalNodeAttributes<N>,
36
+ InternalEdgeAttributes<E>
37
+ >(graph as any, containerRef, {
38
+ allowInvalidContainer: true,
39
+ enableEdgeEvents: true,
40
+ renderEdgeLabels: true,
41
+ renderLabels: true,
42
+ labelSize: 14,
43
+ defaultEdgeType: "line",
44
+ defaultNodeType: "circle",
45
+ edgeProgramClasses: {
46
+ line: EdgeLineProgram,
47
+ curved: EdgeCurveProgram,
48
+ },
49
+ // for some reason max ratio is min zoom and min ratio is max zoom
50
+ maxCameraRatio: 10,
51
+ minCameraRatio: 0.01,
52
+ nodeProgramClasses: {
53
+ rect: NodeRectProgram,
54
+ circle: NodeCircleProgram,
55
+ },
56
+ nodeReducer(key, data) {
57
+ const nodeData: InternalNodeAttributes<N> =
58
+ nodeReducer?.(data) || data;
59
+ // Ensure node size is at least 16 for visibility
60
+ if (!nodeData.size && nodeData.weight) {
61
+ nodeData.size = Math.max(16, nodeData.weight * 3);
62
+ }
63
+ if ((nodeData.size ?? 0) < 16) {
64
+ nodeData.size = 16;
65
+ }
66
+
67
+ // ensure node label renderer is called in order to render selected border
68
+ nodeData.label = nodeData.label || "";
69
+ nodeData.id = key;
70
+ return nodeData;
71
+ },
72
+ edgeReducer(key, data) {
73
+ const edgeData: InternalEdgeAttributes<E> =
74
+ edgeReducer?.(data) || data;
75
+ // Ensure edge size is at least 0.5 for visibility
76
+ if (!edgeData.size && edgeData.weight) {
77
+ edgeData.size = Math.max(0.5, edgeData.weight * 6);
78
+ }
79
+ if ((edgeData.size ?? 0) < 0.5) {
80
+ edgeData.size = 0.5;
81
+ }
82
+ edgeData.id = key;
83
+ return edgeData;
84
+ },
85
+ });
86
+
87
+ attachMouseActions(renderer);
88
+ attachHighlighter(renderer);
89
+
90
+ // containerRef?.insertBefore(
91
+ // componentsRef,
92
+ // renderer.getCanvases().mouse,
93
+ // );
94
+
95
+ // @ts-expect-error ignore
96
+ window.sigma = renderer;
97
+ updateSigma(renderer);
98
+
99
+ return () => {
100
+ renderer.kill();
101
+ };
102
+ }
103
+ }, [graph, containerRef, componentsRef]);
104
+
105
+ useEffect(() => {
106
+ sigma?.setSettings({
107
+ defaultNodeColor: isDark ? "#000" : "#fff",
108
+ defaultEdgeColor: isDark ? "#fff" : "#000",
109
+ labelColor: { color: isDark ? "#fff" : "#000", attribute: "labelColor" },
110
+ });
111
+ }, [isDark, sigma]);
112
+
113
+ return {
114
+ instance: sigma,
115
+ containerRef: setContainerRef,
116
+ componentsRef: setComponentsRef,
117
+ };
118
+ };
package/src/index.ts ADDED
@@ -0,0 +1,34 @@
1
+ /*
2
+ * React Fabric
3
+ * @version: 1.0.0
4
+ *
5
+ *
6
+ * The MIT License (MIT)
7
+ * Copyright (c) 2024 Adarsh Pastakia
8
+ *
9
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
10
+ * and associated documentation files (the "Software"), to deal in the Software without restriction,
11
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
12
+ * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
13
+ * subject to the following conditions:
14
+ *
15
+ * The above copyright notice and this permission notice shall be included in all copies or substantial
16
+ * portions of the Software.
17
+ *
18
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
19
+ * TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+ */
23
+
24
+ export { SigmaGraph } from "./components/Viewer";
25
+ export { Graph } from "./graph";
26
+ export type {
27
+ EdgeAttributes,
28
+ GraphRef,
29
+ NodeAttributes,
30
+ RawGraph,
31
+ } from "./types";
32
+
33
+ // @ts-expect-error ignore
34
+ window.__GRAPH_LAYOUT_DURATION_MULTIPLIER__ = 10;
@@ -0,0 +1,18 @@
1
+ /* istanbul ignore file */
2
+
3
+ // language=GLSL
4
+ const SHADER_SOURCE = /*glsl*/ `
5
+ precision mediump float;
6
+
7
+ varying vec4 v_color;
8
+ varying float v_opacity;
9
+
10
+ const vec4 transparent = vec4(0.0, 0.0, 0.0, 0.0);
11
+
12
+ void main(void) {
13
+ gl_FragColor = v_color;
14
+ gl_FragColor = mix(transparent, gl_FragColor, v_opacity);
15
+ }
16
+ `;
17
+
18
+ export default SHADER_SOURCE;
@@ -0,0 +1,148 @@
1
+ import { Attributes } from "graphology-types";
2
+
3
+ import { EdgeProgram, EdgeProgramType, ProgramInfo } from "sigma/rendering";
4
+ import { EdgeDisplayData, NodeDisplayData, RenderParams } from "sigma/types";
5
+ import { floatColor } from "sigma/utils";
6
+ import { InternalEdgeAttributes } from "../../types";
7
+ import FRAGMENT_SHADER_SOURCE from "./frag.glsl";
8
+ import VERTEX_SHADER_SOURCE from "./vert.glsl";
9
+
10
+ const { UNSIGNED_BYTE, FLOAT } = WebGLRenderingContext;
11
+
12
+ const UNIFORMS = [
13
+ "u_matrix",
14
+ "u_sizeRatio",
15
+ "u_correctionRatio",
16
+ "u_minEdgeThickness",
17
+ "u_lengthToThicknessRatio",
18
+ "u_widenessToThicknessRatio",
19
+ ] as const;
20
+
21
+ export type CreateEdgeArrowHeadProgramOptions = {
22
+ extremity: "source" | "target";
23
+ lengthToThicknessRatio: number;
24
+ widenessToThicknessRatio: number;
25
+ };
26
+
27
+ export const DEFAULT_EDGE_ARROW_HEAD_PROGRAM_OPTIONS: CreateEdgeArrowHeadProgramOptions =
28
+ {
29
+ extremity: "target",
30
+ lengthToThicknessRatio: 2.5,
31
+ widenessToThicknessRatio: 2,
32
+ };
33
+
34
+ export function createEdgeArrowHeadProgram<
35
+ N extends Attributes = Attributes,
36
+ E extends Attributes = Attributes,
37
+ G extends Attributes = Attributes,
38
+ >(
39
+ inputOptions?: Partial<CreateEdgeArrowHeadProgramOptions>,
40
+ ): EdgeProgramType<N, E, G> {
41
+ const options = {
42
+ ...DEFAULT_EDGE_ARROW_HEAD_PROGRAM_OPTIONS,
43
+ ...(inputOptions || {}),
44
+ };
45
+
46
+ return class EdgeArrowHeadProgram<
47
+ N extends Attributes = Attributes,
48
+ E extends Attributes = Attributes,
49
+ G extends Attributes = Attributes,
50
+ > extends EdgeProgram<(typeof UNIFORMS)[number], N, E, G> {
51
+ getDefinition() {
52
+ return {
53
+ VERTICES: 3,
54
+ VERTEX_SHADER_SOURCE,
55
+ FRAGMENT_SHADER_SOURCE,
56
+ METHOD: WebGLRenderingContext.TRIANGLES,
57
+ UNIFORMS,
58
+ ATTRIBUTES: [
59
+ { name: "a_position", size: 2, type: FLOAT },
60
+ { name: "a_normal", size: 2, type: FLOAT },
61
+ { name: "a_radius", size: 1, type: FLOAT },
62
+ { name: "a_color", size: 4, type: UNSIGNED_BYTE, normalized: true },
63
+ { name: "a_opacity", size: 1, type: FLOAT },
64
+ { name: "a_id", size: 4, type: UNSIGNED_BYTE, normalized: true },
65
+ ],
66
+ CONSTANT_ATTRIBUTES: [{ name: "a_barycentric", size: 3, type: FLOAT }],
67
+ CONSTANT_DATA: [
68
+ [1, 0, 0],
69
+ [0, 1, 0],
70
+ [0, 0, 1],
71
+ ],
72
+ };
73
+ }
74
+
75
+ processVisibleItem(
76
+ edgeIndex: number,
77
+ startIndex: number,
78
+ sourceData: NodeDisplayData,
79
+ targetData: NodeDisplayData,
80
+ data: EdgeDisplayData & InternalEdgeAttributes,
81
+ ) {
82
+ if (options.extremity === "source") {
83
+ [sourceData, targetData] = [targetData, sourceData];
84
+ }
85
+
86
+ const thickness = Math.min(data.size || 1, 0.5) * 8;
87
+ const radius = targetData.size || 1;
88
+ const x1 = sourceData.x;
89
+ const y1 = sourceData.y;
90
+ const x2 = targetData.x;
91
+ const y2 = targetData.y;
92
+ let color = data.color;
93
+ if (data.selected) color = "#f00";
94
+ if (data.highlight) color = "#F54A4A";
95
+
96
+ // Computing normals
97
+ const dx = x2 - x1;
98
+ const dy = y2 - y1;
99
+
100
+ let len = dx * dx + dy * dy;
101
+ let n1 = 0;
102
+ let n2 = 0;
103
+
104
+ if (len) {
105
+ len = 1 / Math.sqrt(len);
106
+
107
+ n1 = -dy * len * thickness;
108
+ n2 = dx * len * thickness;
109
+ }
110
+
111
+ const array = this.array;
112
+
113
+ array[startIndex++] = x2;
114
+ array[startIndex++] = y2;
115
+ array[startIndex++] = -n1;
116
+ array[startIndex++] = -n2;
117
+ array[startIndex++] = radius;
118
+ array[startIndex++] = floatColor(color);
119
+ array[startIndex++] = ["both", options.extremity].includes(
120
+ data.arrow ?? "",
121
+ )
122
+ ? data.opacity ?? 1
123
+ : 0;
124
+ array[startIndex++] = edgeIndex;
125
+ }
126
+
127
+ setUniforms(
128
+ params: RenderParams,
129
+ { gl, uniformLocations }: ProgramInfo,
130
+ ): void {
131
+ const {
132
+ u_matrix,
133
+ u_sizeRatio,
134
+ u_correctionRatio,
135
+ u_minEdgeThickness,
136
+ u_lengthToThicknessRatio,
137
+ u_widenessToThicknessRatio,
138
+ } = uniformLocations;
139
+
140
+ gl.uniformMatrix3fv(u_matrix, false, params.matrix);
141
+ gl.uniform1f(u_sizeRatio, params.sizeRatio);
142
+ gl.uniform1f(u_correctionRatio, params.correctionRatio);
143
+ gl.uniform1f(u_minEdgeThickness, params.minEdgeThickness);
144
+ gl.uniform1f(u_lengthToThicknessRatio, 2.5);
145
+ gl.uniform1f(u_widenessToThicknessRatio, 2);
146
+ }
147
+ };
148
+ }
@@ -0,0 +1,75 @@
1
+ /* istanbul ignore file */
2
+
3
+ // language=GLSL
4
+ const SHADER_SOURCE = /*glsl*/ `
5
+ attribute vec2 a_position;
6
+ attribute vec2 a_normal;
7
+ attribute float a_radius;
8
+ attribute vec3 a_barycentric;
9
+ attribute float a_opacity;
10
+
11
+ #ifdef PICKING_MODE
12
+ attribute vec4 a_id;
13
+ #else
14
+ attribute vec4 a_color;
15
+ #endif
16
+
17
+ uniform mat3 u_matrix;
18
+ uniform float u_sizeRatio;
19
+ uniform float u_correctionRatio;
20
+ uniform float u_minEdgeThickness;
21
+ uniform float u_lengthToThicknessRatio;
22
+ uniform float u_widenessToThicknessRatio;
23
+
24
+ varying vec4 v_color;
25
+ varying float v_opacity;
26
+
27
+ const float bias = 255.0 / 254.0;
28
+
29
+ void main() {
30
+ float minThickness = u_minEdgeThickness;
31
+
32
+ float normalLength = length(a_normal);
33
+ vec2 unitNormal = a_normal / normalLength;
34
+
35
+ // These first computations are taken from edge.vert.glsl and
36
+ // edge.clamped.vert.glsl. Please read it to get better comments on what's
37
+ // happening:
38
+ float pixelsThickness = max(normalLength / u_sizeRatio, minThickness);
39
+ float webGLThickness = pixelsThickness * u_correctionRatio;
40
+ float webGLNodeRadius = a_radius * 2.0 * u_correctionRatio / u_sizeRatio;
41
+ float webGLArrowHeadLength = webGLThickness * u_lengthToThicknessRatio * 2.0;
42
+ float webGLArrowHeadThickness = webGLThickness * u_widenessToThicknessRatio;
43
+
44
+ float da = a_barycentric.x;
45
+ float db = a_barycentric.y;
46
+ float dc = a_barycentric.z;
47
+
48
+ vec2 delta = vec2(
49
+ da * (webGLNodeRadius * unitNormal.y)
50
+ + db * ((webGLNodeRadius + webGLArrowHeadLength) * unitNormal.y + webGLArrowHeadThickness * unitNormal.x)
51
+ + dc * ((webGLNodeRadius + webGLArrowHeadLength) * unitNormal.y - webGLArrowHeadThickness * unitNormal.x),
52
+
53
+ da * (-webGLNodeRadius * unitNormal.x)
54
+ + db * (-(webGLNodeRadius + webGLArrowHeadLength) * unitNormal.x + webGLArrowHeadThickness * unitNormal.y)
55
+ + dc * (-(webGLNodeRadius + webGLArrowHeadLength) * unitNormal.x - webGLArrowHeadThickness * unitNormal.y)
56
+ );
57
+
58
+ vec2 position = (u_matrix * vec3(a_position + delta, 1)).xy;
59
+
60
+ gl_Position = vec4(position, 0, 1);
61
+
62
+ #ifdef PICKING_MODE
63
+ // For picking mode, we use the ID as the color:
64
+ v_color = a_id;
65
+ #else
66
+ // For normal mode, we use the color:
67
+ v_color = a_color;
68
+ v_opacity = a_opacity;
69
+ #endif
70
+
71
+ v_color.a *= bias;
72
+ }
73
+ `;
74
+
75
+ export default SHADER_SOURCE;