@reltio/graph 1.4.1585 → 1.4.1586-mui5

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 (164) hide show
  1. package/index.ts +1 -0
  2. package/package.json +26 -9
  3. package/public/bundle.js +205 -0
  4. package/public/bundle.js.LICENSE.txt +88 -0
  5. package/public/package.json +29 -0
  6. package/scripts/build/index.js +20 -0
  7. package/src/__tests__/GraphView.test.tsx +25 -0
  8. package/src/components/CircleLayout/CircleLayout.tsx +76 -0
  9. package/src/components/CircleLayout/__tests__/CircleLayout.test.tsx +194 -0
  10. package/src/components/GotoButton/GotoButton.tsx +23 -0
  11. package/src/components/GotoButton/__tests__/GotoButton.test.tsx +33 -0
  12. package/src/components/GotoButton/styles.ts +15 -0
  13. package/src/components/GraphArea/GraphArea.tsx +113 -0
  14. package/src/components/GraphArea/__tests__/GraphArea.test.tsx +202 -0
  15. package/src/components/GraphArea/styles.ts +30 -0
  16. package/src/components/GraphLayoutSelector/GraphLayoutSelector.tsx +43 -0
  17. package/src/components/GraphLayoutSelector/__tests__/GraphLayoutSelector.spec.tsx +44 -0
  18. package/src/components/GraphLayoutSelector/styles.ts +15 -0
  19. package/src/components/GraphPerspectiveView/GraphPerspectiveView.tsx +58 -0
  20. package/src/components/GraphPerspectiveView/__tests__/GraphPerspectiveView.test.tsx +115 -0
  21. package/src/components/GraphPerspectiveView/__tests__/useGraphLoader.test.tsx +1519 -0
  22. package/src/components/GraphPerspectiveView/__tests__/useRelationshipTable.test.tsx +1003 -0
  23. package/src/components/GraphPerspectiveView/__tests__/useSelectedEntity.test.tsx +373 -0
  24. package/src/components/GraphPerspectiveView/styles.ts +34 -0
  25. package/src/components/GraphRightSidePanel/GraphRightSidePanel.tsx +27 -0
  26. package/src/components/GraphRightSidePanel/__tests__/GraphRightSidePanel.test.tsx +18 -0
  27. package/src/components/GraphRightSidePanel/icons/relationship-icon.svg +3 -0
  28. package/src/components/GraphRightSidePanel/styles.ts +8 -0
  29. package/src/components/GraphTypeSelector/GraphTypeSelector.tsx +56 -0
  30. package/src/components/GraphTypeSelector/__tests__/GraphTypeSelector.test.tsx +109 -0
  31. package/src/components/GraphTypeSelector/styles.ts +17 -0
  32. package/src/components/HierarchyLayout/HierarchyLayout.ts +102 -0
  33. package/src/components/HierarchyLayout/__tests__/HierarchyLayout.spec.tsx +241 -0
  34. package/src/components/HierarchyLayout/__tests__/buildHierarchy.spec.ts +130 -0
  35. package/src/components/HierarchyLayout/__tests__/calculations.spec.ts +230 -0
  36. package/src/components/HierarchyLayout/buildHierarchy.ts +109 -0
  37. package/src/components/HierarchyLayout/calculations.ts +86 -0
  38. package/src/components/RightPanelEntityDetails/RightPanelEntityDetails.tsx +33 -0
  39. package/src/components/RightPanelEntityDetails/__tests__/RightPanelEntityDetails.test.tsx +39 -0
  40. package/src/components/RightPanelEntityDetails/styles.ts +12 -0
  41. package/src/components/RightPanelProfileBand/RightPanelProfileBand.tsx +33 -0
  42. package/src/components/RightPanelProfileBand/__tests__/RightPanelProfileBand.test.tsx +67 -0
  43. package/src/components/RightPanelProfileBand/styles.ts +8 -0
  44. package/src/components/RightPanelRelationship/RightPanelRelationship.tsx +25 -0
  45. package/src/components/RightPanelRelationship/__tests__/RightPanelRelationship.test.tsx +18 -0
  46. package/src/components/RightPanelRelationship/components/CollapsibleTable/CollapsibleTable.tsx +100 -0
  47. package/src/components/RightPanelRelationship/components/CollapsibleTable/TableHead.tsx +38 -0
  48. package/src/components/RightPanelRelationship/components/CollapsibleTable/__tests__/CollapsibleTable.test.tsx +169 -0
  49. package/src/components/RightPanelRelationship/components/CollapsibleTable/__tests__/TableHead.test.tsx +107 -0
  50. package/src/components/RightPanelRelationship/components/CollapsibleTable/styles.ts +38 -0
  51. package/src/components/RightPanelRelationship/components/CollapsibleTable/types.ts +20 -0
  52. package/src/components/RightPanelRelationship/components/DeleteRelationDialog/DeleteRelationDialog.tsx +34 -0
  53. package/src/components/RightPanelRelationship/components/DeleteRelationDialog/__tests__/DeleteRelationDialog.test.tsx +46 -0
  54. package/src/components/RightPanelRelationship/components/GraphAddRelationDialog/GraphAddRelationButton.tsx +43 -0
  55. package/src/components/RightPanelRelationship/components/GraphAddRelationDialog/GraphAddRelationDialog.tsx +121 -0
  56. package/src/components/RightPanelRelationship/components/GraphAddRelationDialog/__tests__/GraphAddRelationButton.test.tsx +80 -0
  57. package/src/components/RightPanelRelationship/components/GraphAddRelationDialog/__tests__/GraphAddRelationDialog.test.tsx +262 -0
  58. package/src/components/RightPanelRelationship/components/GraphAddRelationDialog/__tests__/mockdata.ts +75 -0
  59. package/src/components/RightPanelRelationship/components/GraphAddRelationDialog/styles.ts +25 -0
  60. package/src/components/RightPanelRelationship/components/GraphAddRelationDialog/useCreatableInOutRelationTypes.ts +13 -0
  61. package/src/components/RightPanelRelationship/components/RelationshipTable/RelationshipTable.tsx +126 -0
  62. package/src/components/RightPanelRelationship/components/RelationshipTable/__tests__/RelationshipTable.test.tsx +176 -0
  63. package/src/components/RightPanelRelationship/components/RelationshipTable/cell-renderers/ControlsCellRenderer.tsx +59 -0
  64. package/src/components/RightPanelRelationship/components/RelationshipTable/cell-renderers/DefaultCellRenderer.tsx +29 -0
  65. package/src/components/RightPanelRelationship/components/RelationshipTable/cell-renderers/ExpandedRowRenderer.tsx +94 -0
  66. package/src/components/RightPanelRelationship/components/RelationshipTable/cell-renderers/HeadCellRenderer.tsx +34 -0
  67. package/src/components/RightPanelRelationship/components/RelationshipTable/cell-renderers/ProfileCellRenderer.tsx +41 -0
  68. package/src/components/RightPanelRelationship/components/RelationshipTable/cell-renderers/__tests__/ControlsCellRenderer.test.tsx +80 -0
  69. package/src/components/RightPanelRelationship/components/RelationshipTable/cell-renderers/__tests__/DefaultCellRenderer.test.tsx +47 -0
  70. package/src/components/RightPanelRelationship/components/RelationshipTable/cell-renderers/__tests__/ExpandedRowRenderer.test.tsx +166 -0
  71. package/src/components/RightPanelRelationship/components/RelationshipTable/cell-renderers/__tests__/HeadCellRenderer.test.tsx +23 -0
  72. package/src/components/RightPanelRelationship/components/RelationshipTable/cell-renderers/__tests__/ProfileCellRenderer.test.tsx +47 -0
  73. package/src/components/RightPanelRelationship/components/RelationshipTable/cell-renderers/components/DeleteRelationButton.tsx +32 -0
  74. package/src/components/RightPanelRelationship/components/RelationshipTable/cell-renderers/components/__tests__/DeleteRelationButton.test.tsx +28 -0
  75. package/src/components/RightPanelRelationship/components/RelationshipTable/cell-renderers/styles.ts +113 -0
  76. package/src/components/RightPanelRelationship/components/RelationshipTable/styles.ts +36 -0
  77. package/src/components/RightPanelRelationship/components/RelationshipsFilters/RelationshipsFilters.tsx +41 -0
  78. package/src/components/RightPanelRelationship/components/RelationshipsFilters/RelationshipsFiltersDialog/RelationshipsFiltersDialog.tsx +91 -0
  79. package/src/components/RightPanelRelationship/components/RelationshipsFilters/RelationshipsFiltersDialog/__tests__/RelationshipsFilterDialog.test.tsx +192 -0
  80. package/src/components/RightPanelRelationship/components/RelationshipsFilters/RelationshipsFiltersDialog/styles.ts +34 -0
  81. package/src/components/RightPanelRelationship/components/RelationshipsFilters/RelationshipsSearchTextField/RelationshipsSearchTextField.tsx +31 -0
  82. package/src/components/RightPanelRelationship/components/RelationshipsFilters/RelationshipsSearchTextField/__tests__/RelationshipsSearchTextField.test.tsx +43 -0
  83. package/src/components/RightPanelRelationship/components/RelationshipsFilters/RelationshipsSearchTextField/styles.ts +17 -0
  84. package/src/components/RightPanelRelationship/components/RelationshipsFilters/__tests__/RelationshipsFilters.test.tsx +76 -0
  85. package/src/components/RightPanelRelationship/components/RelationshipsFilters/styles.ts +19 -0
  86. package/src/components/RightPanelRelationship/styles.ts +20 -0
  87. package/src/components/SigmaCustomRenderers/SigmaCustomRenderersContainer.tsx +16 -0
  88. package/src/components/SigmaGraphContainer/SigmaGraphContainer.tsx +55 -0
  89. package/src/components/SigmaGraphContainer/__tests__/SigmaGraphContainer.test.tsx +25 -0
  90. package/src/components/SigmaGraphResizer/SigmaGraphResizer.tsx +13 -0
  91. package/src/components/SigmaGraphResizer/__tests__/SigmaGraphResizer.test.tsx +28 -0
  92. package/src/components/TreeLayout/TreeLayout.tsx +33 -0
  93. package/src/components/TreeLayout/__tests__/TreeLayout.test.tsx +42 -0
  94. package/src/components/TreeLayout/styles.ts +10 -0
  95. package/src/components/ZoomSlider/ZoomSlider.tsx +90 -0
  96. package/src/components/ZoomSlider/__tests__/ZoomSlider.test.tsx +84 -0
  97. package/src/components/ZoomSlider/styles.ts +57 -0
  98. package/src/constants/index.ts +1 -0
  99. package/src/contexts/GraphStateContext.tsx +19 -0
  100. package/src/contexts/SigmaCustomRenderersContext.ts +20 -0
  101. package/src/helpers/relationsHelpers.ts +9 -0
  102. package/src/hooks/__tests__/useGraphLayout.test.tsx +825 -0
  103. package/src/hooks/__tests__/useGraphLayoutSelector.test.tsx +19 -0
  104. package/src/hooks/__tests__/useSelfRelationLoopsRenderer.test.ts +198 -0
  105. package/src/hooks/__tests__/useSigmaCustomRenderers.test.ts +273 -0
  106. package/src/hooks/__tests__/useTooltipRenderer.test.ts +289 -0
  107. package/src/hooks/useGraphLayout.ts +308 -0
  108. package/src/hooks/useGraphLayoutSelector.ts +19 -0
  109. package/src/hooks/useGraphLoader.ts +279 -0
  110. package/src/hooks/useGraphRightSidePanelElements.tsx +36 -0
  111. package/src/hooks/useGraphState.ts +40 -0
  112. package/src/hooks/useGraphType.ts +32 -0
  113. package/src/hooks/useRelationshipTable.ts +212 -0
  114. package/src/hooks/useRelationshipTableFilters.ts +43 -0
  115. package/src/hooks/useSelectedEntity.ts +89 -0
  116. package/src/hooks/useSelfRelationLoopsRenderer.ts +52 -0
  117. package/src/hooks/useSigmaCustomRenderers.ts +112 -0
  118. package/src/hooks/useTooltipRenderer.ts +80 -0
  119. package/src/index.tsx +37 -0
  120. package/src/rendering/canvas/__tests__/hover.spec.ts +31 -0
  121. package/src/rendering/canvas/__tests__/label.spec.ts +64 -0
  122. package/src/rendering/canvas/__tests__/nodeBackground.spec.ts +99 -0
  123. package/src/rendering/canvas/__tests__/selfRelationLoop.spec.ts +88 -0
  124. package/src/rendering/canvas/__tests__/tooltip.spec.ts +33 -0
  125. package/src/rendering/canvas/hover.ts +13 -0
  126. package/src/rendering/canvas/label.ts +33 -0
  127. package/src/rendering/canvas/nodeBackground.ts +61 -0
  128. package/src/rendering/canvas/selfRelationLoop.ts +108 -0
  129. package/src/rendering/canvas/tooltip.ts +38 -0
  130. package/src/rendering/icons/collapseIcon.inline.svg.ts +6 -0
  131. package/src/rendering/icons/expandIcon.inline.svg.ts +5 -0
  132. package/src/rendering/icons/no_photo.inline.svg.ts +13 -0
  133. package/src/rendering/webgl/edge.arrowHead.ts +87 -0
  134. package/src/rendering/webgl/edge.clamped.ts +246 -0
  135. package/src/rendering/webgl/edge.reversedArrowHead.ts +14 -0
  136. package/src/rendering/webgl/helpers/__tests__/imageHelper.spec.ts +36 -0
  137. package/src/rendering/webgl/helpers/imageHelper.ts +13 -0
  138. package/src/rendering/webgl/image.ts +115 -0
  139. package/src/rendering/webgl/node.border.ts +78 -0
  140. package/src/rendering/webgl/node.buttons.ts +241 -0
  141. package/src/rendering/webgl/node.image.ts +169 -0
  142. package/src/rendering/webgl/shaders/edge.clamped.vert.glsl.ts +55 -0
  143. package/src/rendering/webgl/shaders/node.border.frag.glsl.ts +30 -0
  144. package/src/rendering/webgl/shaders/node.border.vert.glsl.ts +37 -0
  145. package/src/rendering/webgl/shaders/node.buttons.frag.glsl.ts +32 -0
  146. package/src/rendering/webgl/shaders/node.buttons.vert.glsl.ts +49 -0
  147. package/src/rendering/webgl/shaders/node.image.frag.glsl.ts +46 -0
  148. package/src/rendering/webgl/shaders/node.image.vert.glsl.ts +42 -0
  149. package/src/types/graphDataTypes.ts +143 -0
  150. package/src/types/sigmaCustomRenderersTypes.ts +13 -0
  151. package/src/utils/__tests__/graph.spec.ts +152 -0
  152. package/src/utils/__tests__/graphLayout.spec.ts +125 -0
  153. package/src/utils/__tests__/hopsData.spec.ts +456 -0
  154. package/src/utils/__tests__/processResponceToGraph.spec.ts +165 -0
  155. package/src/utils/graph.ts +83 -0
  156. package/src/utils/graphLayout.ts +70 -0
  157. package/src/utils/hopsData.ts +198 -0
  158. package/src/utils/processResponseToGraph.ts +32 -0
  159. package/tsconfig.json +4 -0
  160. package/webpack.config.js +10 -0
  161. package/bundle.js +0 -2
  162. package/bundle.js.LICENSE.txt +0 -54
  163. /package/{5271a9e7b6651c852e93.png → public/5271a9e7b6651c852e93.png} +0 -0
  164. /package/{main.css → public/main.css} +0 -0
@@ -0,0 +1,13 @@
1
+ import {Coordinates, Dimensions} from 'sigma/types';
2
+
3
+ type ImageLoading = {status: 'loading'};
4
+ type ImageError = {status: 'error'};
5
+ type ImagePending = {status: 'pending'; image: HTMLImageElement};
6
+ type ImageReady = {status: 'ready'} & Coordinates & Dimensions;
7
+ export type ImageType = ImageLoading | ImageError | ImagePending | ImageReady;
8
+
9
+ export const clearCrossOriginForCORSIfNotSameOrigin = (img: HTMLImageElement, url: string): void => {
10
+ if (new URL(url, window.location.href).origin !== window.location.origin) {
11
+ img.crossOrigin = '';
12
+ }
13
+ };
@@ -0,0 +1,115 @@
1
+ import {clearCrossOriginForCORSIfNotSameOrigin, ImageType} from './helpers/imageHelper';
2
+
3
+ /*
4
+ * ImageLoader is a part of sigma/rendering/webgl/programs/node.image
5
+ * It loads images in one texture, which used for all nodes.
6
+ */
7
+
8
+ const MAX_TEXTURE_SIZE = 128;
9
+
10
+ export class ImageLoader {
11
+ rebindTextureFns: (() => void)[] = [];
12
+ images: Record<string, ImageType> = {};
13
+ textureImage: ImageData;
14
+ hasReceivedImages = false;
15
+ pendingImagesFrameID: number | undefined = undefined;
16
+ constructor() {}
17
+
18
+ /**
19
+ * Helper to load an image:
20
+ */
21
+ loadImage = (id: string, imageSource: string): void => {
22
+ if (this.images[id]) return;
23
+
24
+ const image = new Image();
25
+ image.addEventListener('load', () => {
26
+ this.images[id] = {
27
+ status: 'pending',
28
+ image
29
+ };
30
+
31
+ if (typeof this.pendingImagesFrameID !== 'number') {
32
+ this.pendingImagesFrameID = requestAnimationFrame(() => this.finalizePendingImages());
33
+ }
34
+ });
35
+ image.addEventListener('error', () => {
36
+ this.images[id] = {status: 'error'};
37
+ });
38
+ this.images[id] = {status: 'loading'};
39
+
40
+ // Load image:
41
+ clearCrossOriginForCORSIfNotSameOrigin(image, imageSource);
42
+ // add ?not-from-cache parameter for loading image not from cache
43
+ // because cached image does not contain cors headers
44
+ // https://www.hacksoft.io/blog/handle-images-cors-error-in-chrome
45
+ image.src = imageSource.startsWith('data:image') ? imageSource : imageSource + '?not-from-cache';
46
+ };
47
+
48
+ /**
49
+ * Helper that takes all pending images and adds them into the texture:
50
+ */
51
+ finalizePendingImages = (): void => {
52
+ this.pendingImagesFrameID = undefined;
53
+
54
+ const pendingImages: {image: HTMLImageElement; id: string; size: number}[] = [];
55
+
56
+ // List all pending images:
57
+ for (const id in this.images) {
58
+ const state = this.images[id];
59
+ if (state.status === 'pending') {
60
+ pendingImages.push({
61
+ id,
62
+ image: state.image,
63
+ size: Math.min(state.image.width, state.image.height) || 1
64
+ });
65
+ }
66
+ }
67
+
68
+ // Add images to texture:
69
+ const canvas = document.createElement('canvas');
70
+ const ctx = canvas.getContext('2d') as CanvasRenderingContext2D;
71
+
72
+ canvas.width = pendingImages.reduce(
73
+ (iter, {size}) => iter + size,
74
+ this.hasReceivedImages ? this.textureImage.width : 0
75
+ );
76
+ canvas.height = Math.max(
77
+ this.hasReceivedImages ? this.textureImage.height : 0,
78
+ ...pendingImages.map(({size}) => size)
79
+ );
80
+
81
+ let xOffset = 0;
82
+ if (this.hasReceivedImages) {
83
+ ctx.putImageData(this.textureImage, 0, 0);
84
+ xOffset = this.textureImage.width;
85
+ }
86
+ pendingImages.forEach(({id, image, size}) => {
87
+ const imageSizeInTexture = Math.min(MAX_TEXTURE_SIZE, size);
88
+
89
+ // Crop image, to only keep the biggest square, centered:
90
+ let dx = 0,
91
+ dy = 0;
92
+ if ((image.width || 0) > (image.height || 0)) {
93
+ dx = (image.width - image.height) / 2;
94
+ } else {
95
+ dy = (image.height - image.width) / 2;
96
+ }
97
+ ctx.drawImage(image, dx, dy, size, size, xOffset, 0, imageSizeInTexture, imageSizeInTexture);
98
+
99
+ // Update image state:
100
+ this.images[id] = {
101
+ status: 'ready',
102
+ x: xOffset,
103
+ y: 0,
104
+ width: imageSizeInTexture,
105
+ height: imageSizeInTexture
106
+ };
107
+
108
+ xOffset += imageSizeInTexture;
109
+ });
110
+
111
+ this.textureImage = ctx.getImageData(0, 0, canvas.width, canvas.height);
112
+ this.hasReceivedImages = true;
113
+ this.rebindTextureFns.forEach((fn) => fn());
114
+ };
115
+ }
@@ -0,0 +1,78 @@
1
+ /*
2
+ * This class copies sigma/examples/custom-rendering/programs/node.border, but with a some
3
+ * difference: The fragment shader ("./node.border.frag.glsl") draws a transparent
4
+ * disc with a colored border. Size of border depends on inPath and highlighted props
5
+ */
6
+
7
+ import {floatColor} from 'sigma/utils';
8
+ import {AbstractNodeProgram} from 'sigma/rendering/webgl/programs/common/node';
9
+ import {RenderParams} from 'sigma/rendering/webgl/programs/common/program';
10
+
11
+ import {vertexShaderSource} from './shaders/node.border.vert.glsl';
12
+ import {fragmentShaderSource} from './shaders/node.border.frag.glsl';
13
+ import {NodeAttributes} from '../../types/graphDataTypes';
14
+
15
+ const POINTS = 1; // number of vertices for a node
16
+ const ATTRIBUTES = 5; // number of attributes for one vertex
17
+
18
+ export default class NodeProgramBorder extends AbstractNodeProgram {
19
+ borderSize: GLint; // GL variable for border size
20
+ constructor(gl: WebGLRenderingContext) {
21
+ super(gl, vertexShaderSource, fragmentShaderSource, POINTS, ATTRIBUTES);
22
+
23
+ // Attribute Location
24
+ this.borderSize = gl.getAttribLocation(this.program, 'a_borderSize');
25
+
26
+ this.bind();
27
+ }
28
+
29
+ bind(): void {
30
+ super.bind();
31
+
32
+ const gl = this.gl;
33
+
34
+ gl.enableVertexAttribArray(this.borderSize);
35
+ gl.vertexAttribPointer(
36
+ this.borderSize,
37
+ 1,
38
+ gl.FLOAT,
39
+ false,
40
+ this.attributes * Float32Array.BYTES_PER_ELEMENT,
41
+ 16
42
+ );
43
+ }
44
+
45
+ process(data: NodeAttributes, hidden: boolean, offset: number): void {
46
+ const array = this.array;
47
+ let i = offset * POINTS * ATTRIBUTES;
48
+
49
+ if (hidden || !data.inPath) {
50
+ // draw border only for nodes with inPath or not hidden
51
+ array[i++] = 0;
52
+ array[i++] = 0;
53
+ array[i++] = 0;
54
+ array[i++] = 0;
55
+ array[i++] = 0;
56
+ return;
57
+ }
58
+
59
+ array[i++] = data.x; // position of center
60
+ array[i++] = data.y;
61
+ array[i++] = data.size; // size
62
+ array[i++] = floatColor(data.color); // color
63
+ array[i] = data.highlighted ? 4 : 2; // size of border in pixels
64
+ }
65
+
66
+ render(params: RenderParams): void {
67
+ const gl = this.gl;
68
+
69
+ const program = this.program;
70
+ gl.useProgram(program);
71
+
72
+ gl.uniform1f(this.ratioLocation, 1 / Math.sqrt(params.ratio));
73
+ gl.uniform1f(this.scaleLocation, params.scalingRatio);
74
+ gl.uniformMatrix3fv(this.matrixLocation, false, params.matrix);
75
+
76
+ gl.drawArrays(gl.POINTS, 0, this.array.length / ATTRIBUTES);
77
+ }
78
+ }
@@ -0,0 +1,241 @@
1
+ import {vertexShaderSource} from './shaders/node.buttons.vert.glsl';
2
+ import {fragmentShaderSource} from './shaders/node.buttons.frag.glsl';
3
+
4
+ import Sigma from 'sigma/sigma';
5
+ import {AbstractNodeProgram} from 'sigma/rendering/webgl/programs/common/node';
6
+ import {RenderParams} from 'sigma/rendering/webgl/programs/common/program';
7
+ import {floatColor} from 'sigma/utils';
8
+ import {svg2Url} from '@reltio/mdm-sdk';
9
+ import {EXPAND_ICON} from '../icons/expandIcon.inline.svg';
10
+ import {COLLAPSE_ICON} from '../icons/collapseIcon.inline.svg';
11
+ import {ImageLoader} from './image';
12
+ import {NodeAttributes} from '../../types/graphDataTypes';
13
+
14
+ const POINTS = 2; // number of button for 1 node
15
+ const ATTRIBUTES = 11; // number of attributes for one button
16
+
17
+ // images for buttons
18
+ const defaultImages = [
19
+ {id: 'expandIcon', path: svg2Url(EXPAND_ICON)},
20
+ {id: 'collapseIcon', path: svg2Url(COLLAPSE_ICON)}
21
+ ];
22
+
23
+ export default class NodeButtonsProgram extends AbstractNodeProgram {
24
+ imageLoader: ImageLoader;
25
+ texture: WebGLTexture;
26
+ textureLocation: GLint;
27
+ buttonSize: GLint; // buttons size
28
+ normals: GLint; // normals to calculate positions of buttons
29
+ correctionRatioLocation: WebGLUniformLocation;
30
+ sqrtZoomRatioLocation: WebGLUniformLocation;
31
+ atlasLocation: WebGLUniformLocation;
32
+ latestRenderParams?: RenderParams;
33
+
34
+ constructor(gl: WebGLRenderingContext, renderer: Sigma) {
35
+ super(gl, vertexShaderSource, fragmentShaderSource, POINTS, ATTRIBUTES);
36
+
37
+ this.imageLoader = new ImageLoader();
38
+
39
+ this.imageLoader.rebindTextureFns.push(() => {
40
+ if (this && this.rebindTexture) this.rebindTexture();
41
+ if (renderer && renderer.refresh) renderer.refresh();
42
+ });
43
+
44
+ this.imageLoader.textureImage = new ImageData(1, 1);
45
+
46
+ // Attribute Location
47
+ this.textureLocation = gl.getAttribLocation(this.program, 'a_texture');
48
+ this.buttonSize = gl.getAttribLocation(this.program, 'a_buttonSize');
49
+ this.normals = gl.getAttribLocation(this.program, 'a_normals');
50
+
51
+ // Uniform Location
52
+ const correctionRatioLocation = gl.getUniformLocation(this.program, 'u_correctionRatio');
53
+ if (correctionRatioLocation === null)
54
+ throw new Error('NodeButtonsProgram: error while getting correctionRatioLocation');
55
+ this.correctionRatioLocation = correctionRatioLocation;
56
+
57
+ const sqrtZoomRatioLocation = gl.getUniformLocation(this.program, 'u_sqrtZoomRatio');
58
+ if (sqrtZoomRatioLocation === null)
59
+ throw new Error('NodeButtonsProgram: error while getting sqrtZoomRatioLocation');
60
+ this.sqrtZoomRatioLocation = sqrtZoomRatioLocation;
61
+
62
+ const atlasLocation = gl.getUniformLocation(this.program, 'u_atlas');
63
+ if (atlasLocation === null) throw new Error('NodeButtonsProgram: error while getting atlasLocation');
64
+ this.atlasLocation = atlasLocation;
65
+
66
+ // Initialize WebGL texture:
67
+ this.texture = gl.createTexture() as WebGLTexture;
68
+ gl.bindTexture(gl.TEXTURE_2D, this.texture);
69
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array([0, 0, 0, 0]));
70
+
71
+ defaultImages.map((image) => this.imageLoader.loadImage(image.id, image.path));
72
+
73
+ this.bind();
74
+ }
75
+
76
+ bind(): void {
77
+ super.bind();
78
+
79
+ const gl = this.gl;
80
+
81
+ gl.enableVertexAttribArray(this.buttonSize);
82
+ gl.enableVertexAttribArray(this.normals);
83
+ gl.enableVertexAttribArray(this.textureLocation);
84
+
85
+ gl.vertexAttribPointer(
86
+ this.buttonSize,
87
+ 1,
88
+ gl.FLOAT,
89
+ false,
90
+ this.attributes * Float32Array.BYTES_PER_ELEMENT,
91
+ 16
92
+ );
93
+ gl.vertexAttribPointer(this.normals, 2, gl.FLOAT, false, this.attributes * Float32Array.BYTES_PER_ELEMENT, 20);
94
+ gl.vertexAttribPointer(
95
+ this.textureLocation,
96
+ 4,
97
+ gl.FLOAT,
98
+ false,
99
+ this.attributes * Float32Array.BYTES_PER_ELEMENT,
100
+ 28
101
+ );
102
+ }
103
+
104
+ process(data: NodeAttributes, hidden: boolean, offset: number): void {
105
+ const array = this.array;
106
+ let i = offset * POINTS * ATTRIBUTES;
107
+ const hideButtons = hidden || (data.inactive && !data.highlighted);
108
+
109
+ // Computing normals
110
+ const [dx, dy] = data.buttonOffset || [0, 0];
111
+
112
+ let len = dx * dx + dy * dy,
113
+ n1 = 0,
114
+ n2 = 0;
115
+
116
+ if (len) {
117
+ len = 1 / Math.sqrt(len);
118
+
119
+ n1 = dy * len;
120
+ n2 = dx * len;
121
+ }
122
+
123
+ // Expand button
124
+
125
+ if (hideButtons || !data.showExpand) {
126
+ array[i++] = 0;
127
+ array[i++] = 0;
128
+ array[i++] = 0;
129
+ array[i++] = 0;
130
+ array[i++] = 0;
131
+ array[i++] = 0;
132
+ array[i++] = 0;
133
+ // Texture:
134
+ array[i++] = 0;
135
+ array[i++] = 0;
136
+ array[i++] = 0;
137
+ array[i++] = 0;
138
+ } else {
139
+ const expandImageState = this.imageLoader.images['expandIcon'];
140
+
141
+ array[i++] = data.x; // position of center
142
+ array[i++] = data.y;
143
+ array[i++] = data.size; // size
144
+ array[i++] = floatColor(data.color); // color
145
+ array[i++] = data.buttonSize || 0; // button radius
146
+ array[i++] = n1; // normals
147
+ array[i++] = -n2;
148
+
149
+ // Reference texture:
150
+ if (expandImageState && expandImageState.status === 'ready') {
151
+ const {width, height} = this.imageLoader.textureImage;
152
+ array[i++] = expandImageState.x / width;
153
+ array[i++] = expandImageState.y / height;
154
+ array[i++] = expandImageState.width / width;
155
+ array[i++] = expandImageState.height / height;
156
+ } else {
157
+ array[i++] = 0;
158
+ array[i++] = 0;
159
+ array[i++] = 0;
160
+ array[i++] = 0;
161
+ }
162
+ }
163
+
164
+ // Collapse button
165
+
166
+ // don't show button
167
+ if (hideButtons || !data.showCollapse) {
168
+ array[i++] = 0;
169
+ array[i++] = 0;
170
+ array[i++] = 0;
171
+ array[i++] = 0;
172
+ array[i++] = 0;
173
+ array[i++] = 0;
174
+ array[i++] = 0;
175
+ // Texture:
176
+ array[i++] = 0;
177
+ array[i++] = 0;
178
+ array[i++] = 0;
179
+ array[i++] = 0;
180
+ } else {
181
+ const collapseImageState = this.imageLoader.images['collapseIcon'];
182
+
183
+ array[i++] = data.x; // position of center
184
+ array[i++] = data.y;
185
+ array[i++] = data.size; // size
186
+ array[i++] = floatColor(data.color); // color
187
+ array[i++] = data.buttonSize || 0; // button radius
188
+ array[i++] = -n1; // normals
189
+ array[i++] = -n2;
190
+
191
+ // Reference texture:
192
+ if (collapseImageState && collapseImageState.status === 'ready') {
193
+ const {width, height} = this.imageLoader.textureImage;
194
+ array[i++] = collapseImageState.x / width;
195
+ array[i++] = collapseImageState.y / height;
196
+ array[i++] = collapseImageState.width / width;
197
+ array[i++] = collapseImageState.height / height;
198
+ } else {
199
+ array[i++] = 0;
200
+ array[i++] = 0;
201
+ array[i++] = 0;
202
+ array[i++] = 0;
203
+ }
204
+ }
205
+ }
206
+
207
+ render(params: RenderParams): void {
208
+ if (this.hasNothingToRender()) return;
209
+
210
+ this.latestRenderParams = params;
211
+
212
+ const gl = this.gl;
213
+
214
+ const program = this.program;
215
+ gl.useProgram(program);
216
+
217
+ gl.uniform1f(this.ratioLocation, 1 / Math.sqrt(params.ratio));
218
+ gl.uniform1f(this.scaleLocation, params.scalingRatio);
219
+ gl.uniformMatrix3fv(this.matrixLocation, false, params.matrix);
220
+ gl.uniform1f(this.sqrtZoomRatioLocation, Math.sqrt(params.ratio));
221
+ gl.uniform1f(this.correctionRatioLocation, params.correctionRatio);
222
+ gl.uniform1i(this.atlasLocation, 1);
223
+
224
+ gl.drawArrays(gl.POINTS, 0, this.array.length / ATTRIBUTES);
225
+ }
226
+
227
+ rebindTexture() {
228
+ const gl = this.gl;
229
+
230
+ gl.activeTexture(gl.TEXTURE1);
231
+ gl.bindTexture(gl.TEXTURE_2D, this.texture);
232
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, this.imageLoader.textureImage);
233
+ gl.generateMipmap(gl.TEXTURE_2D);
234
+
235
+ if (this.latestRenderParams) {
236
+ this.bind();
237
+ this.bufferData();
238
+ this.render(this.latestRenderParams);
239
+ }
240
+ }
241
+ }
@@ -0,0 +1,169 @@
1
+ /*
2
+ * This class copies sigma/rendering/webgl/programs/node.image, but with a some
3
+ * difference: it can change color of picture for inactive state
4
+ * Program rendering nodes using GL_POINTS, but that draws an image on top of
5
+ * the classic colored disc.
6
+ */
7
+ import {vertexShaderSource} from './shaders/node.image.vert.glsl';
8
+ import {fragmentShaderSource} from './shaders/node.image.frag.glsl';
9
+
10
+ import {AbstractNodeProgram} from 'sigma/rendering/webgl/programs/common/node';
11
+ import {RenderParams} from 'sigma/rendering/webgl/programs/common/program';
12
+ import Sigma from 'sigma/sigma';
13
+ import {floatColor} from 'sigma/utils';
14
+ import {svg2Url} from '@reltio/mdm-sdk';
15
+ import {DEFAULT_PROFILE_IMAGE} from '../icons/no_photo.inline.svg';
16
+ import {ImageLoader} from './image';
17
+ import {NodeAttributes} from '../../types/graphDataTypes';
18
+
19
+ const POINTS = 1;
20
+ const ATTRIBUTES = 9;
21
+
22
+ const defaultImage = {id: 'defaultImage', path: svg2Url(DEFAULT_PROFILE_IMAGE)};
23
+
24
+ /*
25
+ * To share the texture between the program instances of the graph and the
26
+ * hovered nodes (to prevent some flickering, mostly), this program must be
27
+ * "built" for each sigma instance:
28
+ */
29
+ export default class NodeImageProgram extends AbstractNodeProgram {
30
+ imageLoader: ImageLoader;
31
+ texture: WebGLTexture;
32
+ textureLocation: GLint;
33
+ atlasLocation: WebGLUniformLocation;
34
+ latestRenderParams?: RenderParams;
35
+ inactive: GLint;
36
+
37
+ constructor(gl: WebGLRenderingContext, renderer: Sigma) {
38
+ super(gl, vertexShaderSource, fragmentShaderSource, POINTS, ATTRIBUTES);
39
+
40
+ this.imageLoader = new ImageLoader();
41
+
42
+ this.imageLoader.rebindTextureFns.push(() => {
43
+ if (this && this.rebindTexture) this.rebindTexture();
44
+ if (renderer && renderer.refresh) renderer.refresh();
45
+ });
46
+
47
+ this.imageLoader.textureImage = new ImageData(1, 1);
48
+
49
+ // Attribute Location
50
+ this.textureLocation = gl.getAttribLocation(this.program, 'a_texture');
51
+ this.inactive = gl.getAttribLocation(this.program, 'a_inactive');
52
+
53
+ // Uniform Location
54
+ const atlasLocation = gl.getUniformLocation(this.program, 'u_atlas');
55
+ if (atlasLocation === null) throw new Error('NodeProgramImage: error while getting atlasLocation');
56
+ this.atlasLocation = atlasLocation;
57
+
58
+ // Initialize WebGL texture:
59
+ this.texture = gl.createTexture() as WebGLTexture;
60
+ gl.bindTexture(gl.TEXTURE_2D, this.texture);
61
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array([0, 0, 0, 0]));
62
+
63
+ this.imageLoader.loadImage(defaultImage.id, defaultImage.path);
64
+
65
+ this.bind();
66
+ }
67
+
68
+ bind(): void {
69
+ super.bind();
70
+
71
+ const gl = this.gl;
72
+
73
+ gl.enableVertexAttribArray(this.textureLocation);
74
+ gl.enableVertexAttribArray(this.inactive);
75
+
76
+ gl.vertexAttribPointer(this.inactive, 1, gl.FLOAT, false, this.attributes * Float32Array.BYTES_PER_ELEMENT, 16);
77
+
78
+ gl.vertexAttribPointer(
79
+ this.textureLocation,
80
+ 4,
81
+ gl.FLOAT,
82
+ false,
83
+ this.attributes * Float32Array.BYTES_PER_ELEMENT,
84
+ 20
85
+ );
86
+ }
87
+
88
+ process(data: NodeAttributes, hidden: boolean, offset: number): void {
89
+ const array = this.array;
90
+ let i = offset * POINTS * ATTRIBUTES;
91
+
92
+ const imageSource = data.image;
93
+ let imageState = imageSource && this.imageLoader.images[imageSource];
94
+ if (typeof imageSource === 'string' && !imageState) {
95
+ this.imageLoader.loadImage(imageSource, imageSource);
96
+ }
97
+
98
+ if (hidden) {
99
+ array[i++] = 0;
100
+ array[i++] = 0;
101
+ array[i++] = 0;
102
+ array[i++] = 0;
103
+ array[i++] = 0;
104
+ // Texture:
105
+ array[i++] = 0;
106
+ array[i++] = 0;
107
+ array[i++] = 0;
108
+ array[i++] = 0;
109
+ return;
110
+ }
111
+
112
+ array[i++] = data.x; // position of center
113
+ array[i++] = data.y;
114
+ array[i++] = data.size; // size
115
+ array[i++] = floatColor(data.color); // color
116
+ array[i++] = data.inactive ? 1 : 0; // inactive property
117
+
118
+ // Reference texture:
119
+ if (!imageState || imageState.status !== 'ready') {
120
+ imageState = this.imageLoader.images[defaultImage.id];
121
+ }
122
+
123
+ if (imageState && imageState.status === 'ready') {
124
+ const {width, height} = this.imageLoader.textureImage;
125
+ array[i++] = imageState.x / width;
126
+ array[i++] = imageState.y / height;
127
+ array[i++] = imageState.width / width;
128
+ array[i++] = imageState.height / height;
129
+ } else {
130
+ array[i++] = 0;
131
+ array[i++] = 0;
132
+ array[i++] = 0;
133
+ array[i++] = 0;
134
+ }
135
+ }
136
+
137
+ render(params: RenderParams): void {
138
+ if (this.hasNothingToRender()) return;
139
+
140
+ this.latestRenderParams = params;
141
+
142
+ const gl = this.gl;
143
+
144
+ const program = this.program;
145
+ gl.useProgram(program);
146
+
147
+ gl.uniform1f(this.ratioLocation, 1 / Math.sqrt(params.ratio));
148
+ gl.uniform1f(this.scaleLocation, params.scalingRatio);
149
+ gl.uniformMatrix3fv(this.matrixLocation, false, params.matrix);
150
+ gl.uniform1i(this.atlasLocation, 0);
151
+
152
+ gl.drawArrays(gl.POINTS, 0, this.array.length / ATTRIBUTES);
153
+ }
154
+
155
+ rebindTexture() {
156
+ const gl = this.gl;
157
+
158
+ gl.activeTexture(gl.TEXTURE0);
159
+ gl.bindTexture(gl.TEXTURE_2D, this.texture);
160
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, this.imageLoader.textureImage);
161
+ gl.generateMipmap(gl.TEXTURE_2D);
162
+
163
+ if (this.latestRenderParams) {
164
+ this.bind();
165
+ this.bufferData();
166
+ this.render(this.latestRenderParams);
167
+ }
168
+ }
169
+ }
@@ -0,0 +1,55 @@
1
+ /*
2
+ * This file copies sigma/src/rendering/webgl/shaders/edge.clamped.vert.glsl, but with a some
3
+ * difference: added calculation of arrowSizeCoefficient using a_arrowSizeRatio attribute
4
+ */
5
+
6
+ export const vertexShaderSource = `
7
+ attribute vec4 a_color;
8
+ attribute vec2 a_normal;
9
+ attribute vec2 a_position;
10
+ attribute float a_radius;
11
+ attribute float a_arrowSizeRatio;
12
+
13
+ uniform mat3 u_matrix;
14
+ uniform float u_sqrtZoomRatio;
15
+ uniform float u_correctionRatio;
16
+
17
+ varying vec4 v_color;
18
+ varying vec2 v_normal;
19
+ varying float v_thickness;
20
+
21
+ const float minThickness = 1.7;
22
+ const float bias = 255.0 / 254.0;
23
+ const float arrowHeadLengthThicknessRatio = 2.5;
24
+
25
+ void main() {
26
+ float normalLength = length(a_normal);
27
+ vec2 unitNormal = a_normal / normalLength;
28
+
29
+ // These first computations are taken from edge.vert.glsl. Please read it to
30
+ // get better comments on what's happening:
31
+ float pixelsThickness = max(normalLength, minThickness * u_sqrtZoomRatio);
32
+ float webGLThickness = pixelsThickness * u_correctionRatio;
33
+ float adaptedWebGLThickness = webGLThickness * u_sqrtZoomRatio;
34
+
35
+ // our change - apply a_arrowSizeRatio depending on current zoom and minThickness
36
+ float arrowSizeCoefficient = min(a_arrowSizeRatio, a_arrowSizeRatio / (u_sqrtZoomRatio * minThickness));
37
+
38
+ // Here, we move the point to leave space for the arrow head:
39
+ float direction = sign(a_radius);
40
+ float adaptedWebGLNodeRadius = direction * a_radius * 2.0 * u_correctionRatio * u_sqrtZoomRatio;
41
+
42
+ float adaptedWebGLArrowHeadLength = adaptedWebGLThickness * 2.0 * arrowHeadLengthThicknessRatio * arrowSizeCoefficient;
43
+
44
+
45
+ vec2 compensationVector = vec2(-direction * unitNormal.y, direction * unitNormal.x) * (adaptedWebGLNodeRadius + adaptedWebGLArrowHeadLength);
46
+
47
+ // Here is the proper position of the vertex
48
+ gl_Position = vec4((u_matrix * vec3(a_position + unitNormal * adaptedWebGLThickness + compensationVector, 1)).xy, 0, 1);
49
+
50
+ v_thickness = webGLThickness / u_sqrtZoomRatio;
51
+
52
+ v_normal = unitNormal;
53
+ v_color = a_color;
54
+ v_color.a *= bias;
55
+ }`;