@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.
- package/index.ts +1 -0
- package/package.json +26 -9
- package/public/bundle.js +205 -0
- package/public/bundle.js.LICENSE.txt +88 -0
- package/public/package.json +29 -0
- package/scripts/build/index.js +20 -0
- package/src/__tests__/GraphView.test.tsx +25 -0
- package/src/components/CircleLayout/CircleLayout.tsx +76 -0
- package/src/components/CircleLayout/__tests__/CircleLayout.test.tsx +194 -0
- package/src/components/GotoButton/GotoButton.tsx +23 -0
- package/src/components/GotoButton/__tests__/GotoButton.test.tsx +33 -0
- package/src/components/GotoButton/styles.ts +15 -0
- package/src/components/GraphArea/GraphArea.tsx +113 -0
- package/src/components/GraphArea/__tests__/GraphArea.test.tsx +202 -0
- package/src/components/GraphArea/styles.ts +30 -0
- package/src/components/GraphLayoutSelector/GraphLayoutSelector.tsx +43 -0
- package/src/components/GraphLayoutSelector/__tests__/GraphLayoutSelector.spec.tsx +44 -0
- package/src/components/GraphLayoutSelector/styles.ts +15 -0
- package/src/components/GraphPerspectiveView/GraphPerspectiveView.tsx +58 -0
- package/src/components/GraphPerspectiveView/__tests__/GraphPerspectiveView.test.tsx +115 -0
- package/src/components/GraphPerspectiveView/__tests__/useGraphLoader.test.tsx +1519 -0
- package/src/components/GraphPerspectiveView/__tests__/useRelationshipTable.test.tsx +1003 -0
- package/src/components/GraphPerspectiveView/__tests__/useSelectedEntity.test.tsx +373 -0
- package/src/components/GraphPerspectiveView/styles.ts +34 -0
- package/src/components/GraphRightSidePanel/GraphRightSidePanel.tsx +27 -0
- package/src/components/GraphRightSidePanel/__tests__/GraphRightSidePanel.test.tsx +18 -0
- package/src/components/GraphRightSidePanel/icons/relationship-icon.svg +3 -0
- package/src/components/GraphRightSidePanel/styles.ts +8 -0
- package/src/components/GraphTypeSelector/GraphTypeSelector.tsx +56 -0
- package/src/components/GraphTypeSelector/__tests__/GraphTypeSelector.test.tsx +109 -0
- package/src/components/GraphTypeSelector/styles.ts +17 -0
- package/src/components/HierarchyLayout/HierarchyLayout.ts +102 -0
- package/src/components/HierarchyLayout/__tests__/HierarchyLayout.spec.tsx +241 -0
- package/src/components/HierarchyLayout/__tests__/buildHierarchy.spec.ts +130 -0
- package/src/components/HierarchyLayout/__tests__/calculations.spec.ts +230 -0
- package/src/components/HierarchyLayout/buildHierarchy.ts +109 -0
- package/src/components/HierarchyLayout/calculations.ts +86 -0
- package/src/components/RightPanelEntityDetails/RightPanelEntityDetails.tsx +33 -0
- package/src/components/RightPanelEntityDetails/__tests__/RightPanelEntityDetails.test.tsx +39 -0
- package/src/components/RightPanelEntityDetails/styles.ts +12 -0
- package/src/components/RightPanelProfileBand/RightPanelProfileBand.tsx +33 -0
- package/src/components/RightPanelProfileBand/__tests__/RightPanelProfileBand.test.tsx +67 -0
- package/src/components/RightPanelProfileBand/styles.ts +8 -0
- package/src/components/RightPanelRelationship/RightPanelRelationship.tsx +25 -0
- package/src/components/RightPanelRelationship/__tests__/RightPanelRelationship.test.tsx +18 -0
- package/src/components/RightPanelRelationship/components/CollapsibleTable/CollapsibleTable.tsx +100 -0
- package/src/components/RightPanelRelationship/components/CollapsibleTable/TableHead.tsx +38 -0
- package/src/components/RightPanelRelationship/components/CollapsibleTable/__tests__/CollapsibleTable.test.tsx +169 -0
- package/src/components/RightPanelRelationship/components/CollapsibleTable/__tests__/TableHead.test.tsx +107 -0
- package/src/components/RightPanelRelationship/components/CollapsibleTable/styles.ts +38 -0
- package/src/components/RightPanelRelationship/components/CollapsibleTable/types.ts +20 -0
- package/src/components/RightPanelRelationship/components/DeleteRelationDialog/DeleteRelationDialog.tsx +34 -0
- package/src/components/RightPanelRelationship/components/DeleteRelationDialog/__tests__/DeleteRelationDialog.test.tsx +46 -0
- package/src/components/RightPanelRelationship/components/GraphAddRelationDialog/GraphAddRelationButton.tsx +43 -0
- package/src/components/RightPanelRelationship/components/GraphAddRelationDialog/GraphAddRelationDialog.tsx +121 -0
- package/src/components/RightPanelRelationship/components/GraphAddRelationDialog/__tests__/GraphAddRelationButton.test.tsx +80 -0
- package/src/components/RightPanelRelationship/components/GraphAddRelationDialog/__tests__/GraphAddRelationDialog.test.tsx +262 -0
- package/src/components/RightPanelRelationship/components/GraphAddRelationDialog/__tests__/mockdata.ts +75 -0
- package/src/components/RightPanelRelationship/components/GraphAddRelationDialog/styles.ts +25 -0
- package/src/components/RightPanelRelationship/components/GraphAddRelationDialog/useCreatableInOutRelationTypes.ts +13 -0
- package/src/components/RightPanelRelationship/components/RelationshipTable/RelationshipTable.tsx +126 -0
- package/src/components/RightPanelRelationship/components/RelationshipTable/__tests__/RelationshipTable.test.tsx +176 -0
- package/src/components/RightPanelRelationship/components/RelationshipTable/cell-renderers/ControlsCellRenderer.tsx +59 -0
- package/src/components/RightPanelRelationship/components/RelationshipTable/cell-renderers/DefaultCellRenderer.tsx +29 -0
- package/src/components/RightPanelRelationship/components/RelationshipTable/cell-renderers/ExpandedRowRenderer.tsx +94 -0
- package/src/components/RightPanelRelationship/components/RelationshipTable/cell-renderers/HeadCellRenderer.tsx +34 -0
- package/src/components/RightPanelRelationship/components/RelationshipTable/cell-renderers/ProfileCellRenderer.tsx +41 -0
- package/src/components/RightPanelRelationship/components/RelationshipTable/cell-renderers/__tests__/ControlsCellRenderer.test.tsx +80 -0
- package/src/components/RightPanelRelationship/components/RelationshipTable/cell-renderers/__tests__/DefaultCellRenderer.test.tsx +47 -0
- package/src/components/RightPanelRelationship/components/RelationshipTable/cell-renderers/__tests__/ExpandedRowRenderer.test.tsx +166 -0
- package/src/components/RightPanelRelationship/components/RelationshipTable/cell-renderers/__tests__/HeadCellRenderer.test.tsx +23 -0
- package/src/components/RightPanelRelationship/components/RelationshipTable/cell-renderers/__tests__/ProfileCellRenderer.test.tsx +47 -0
- package/src/components/RightPanelRelationship/components/RelationshipTable/cell-renderers/components/DeleteRelationButton.tsx +32 -0
- package/src/components/RightPanelRelationship/components/RelationshipTable/cell-renderers/components/__tests__/DeleteRelationButton.test.tsx +28 -0
- package/src/components/RightPanelRelationship/components/RelationshipTable/cell-renderers/styles.ts +113 -0
- package/src/components/RightPanelRelationship/components/RelationshipTable/styles.ts +36 -0
- package/src/components/RightPanelRelationship/components/RelationshipsFilters/RelationshipsFilters.tsx +41 -0
- package/src/components/RightPanelRelationship/components/RelationshipsFilters/RelationshipsFiltersDialog/RelationshipsFiltersDialog.tsx +91 -0
- package/src/components/RightPanelRelationship/components/RelationshipsFilters/RelationshipsFiltersDialog/__tests__/RelationshipsFilterDialog.test.tsx +192 -0
- package/src/components/RightPanelRelationship/components/RelationshipsFilters/RelationshipsFiltersDialog/styles.ts +34 -0
- package/src/components/RightPanelRelationship/components/RelationshipsFilters/RelationshipsSearchTextField/RelationshipsSearchTextField.tsx +31 -0
- package/src/components/RightPanelRelationship/components/RelationshipsFilters/RelationshipsSearchTextField/__tests__/RelationshipsSearchTextField.test.tsx +43 -0
- package/src/components/RightPanelRelationship/components/RelationshipsFilters/RelationshipsSearchTextField/styles.ts +17 -0
- package/src/components/RightPanelRelationship/components/RelationshipsFilters/__tests__/RelationshipsFilters.test.tsx +76 -0
- package/src/components/RightPanelRelationship/components/RelationshipsFilters/styles.ts +19 -0
- package/src/components/RightPanelRelationship/styles.ts +20 -0
- package/src/components/SigmaCustomRenderers/SigmaCustomRenderersContainer.tsx +16 -0
- package/src/components/SigmaGraphContainer/SigmaGraphContainer.tsx +55 -0
- package/src/components/SigmaGraphContainer/__tests__/SigmaGraphContainer.test.tsx +25 -0
- package/src/components/SigmaGraphResizer/SigmaGraphResizer.tsx +13 -0
- package/src/components/SigmaGraphResizer/__tests__/SigmaGraphResizer.test.tsx +28 -0
- package/src/components/TreeLayout/TreeLayout.tsx +33 -0
- package/src/components/TreeLayout/__tests__/TreeLayout.test.tsx +42 -0
- package/src/components/TreeLayout/styles.ts +10 -0
- package/src/components/ZoomSlider/ZoomSlider.tsx +90 -0
- package/src/components/ZoomSlider/__tests__/ZoomSlider.test.tsx +84 -0
- package/src/components/ZoomSlider/styles.ts +57 -0
- package/src/constants/index.ts +1 -0
- package/src/contexts/GraphStateContext.tsx +19 -0
- package/src/contexts/SigmaCustomRenderersContext.ts +20 -0
- package/src/helpers/relationsHelpers.ts +9 -0
- package/src/hooks/__tests__/useGraphLayout.test.tsx +825 -0
- package/src/hooks/__tests__/useGraphLayoutSelector.test.tsx +19 -0
- package/src/hooks/__tests__/useSelfRelationLoopsRenderer.test.ts +198 -0
- package/src/hooks/__tests__/useSigmaCustomRenderers.test.ts +273 -0
- package/src/hooks/__tests__/useTooltipRenderer.test.ts +289 -0
- package/src/hooks/useGraphLayout.ts +308 -0
- package/src/hooks/useGraphLayoutSelector.ts +19 -0
- package/src/hooks/useGraphLoader.ts +279 -0
- package/src/hooks/useGraphRightSidePanelElements.tsx +36 -0
- package/src/hooks/useGraphState.ts +40 -0
- package/src/hooks/useGraphType.ts +32 -0
- package/src/hooks/useRelationshipTable.ts +212 -0
- package/src/hooks/useRelationshipTableFilters.ts +43 -0
- package/src/hooks/useSelectedEntity.ts +89 -0
- package/src/hooks/useSelfRelationLoopsRenderer.ts +52 -0
- package/src/hooks/useSigmaCustomRenderers.ts +112 -0
- package/src/hooks/useTooltipRenderer.ts +80 -0
- package/src/index.tsx +37 -0
- package/src/rendering/canvas/__tests__/hover.spec.ts +31 -0
- package/src/rendering/canvas/__tests__/label.spec.ts +64 -0
- package/src/rendering/canvas/__tests__/nodeBackground.spec.ts +99 -0
- package/src/rendering/canvas/__tests__/selfRelationLoop.spec.ts +88 -0
- package/src/rendering/canvas/__tests__/tooltip.spec.ts +33 -0
- package/src/rendering/canvas/hover.ts +13 -0
- package/src/rendering/canvas/label.ts +33 -0
- package/src/rendering/canvas/nodeBackground.ts +61 -0
- package/src/rendering/canvas/selfRelationLoop.ts +108 -0
- package/src/rendering/canvas/tooltip.ts +38 -0
- package/src/rendering/icons/collapseIcon.inline.svg.ts +6 -0
- package/src/rendering/icons/expandIcon.inline.svg.ts +5 -0
- package/src/rendering/icons/no_photo.inline.svg.ts +13 -0
- package/src/rendering/webgl/edge.arrowHead.ts +87 -0
- package/src/rendering/webgl/edge.clamped.ts +246 -0
- package/src/rendering/webgl/edge.reversedArrowHead.ts +14 -0
- package/src/rendering/webgl/helpers/__tests__/imageHelper.spec.ts +36 -0
- package/src/rendering/webgl/helpers/imageHelper.ts +13 -0
- package/src/rendering/webgl/image.ts +115 -0
- package/src/rendering/webgl/node.border.ts +78 -0
- package/src/rendering/webgl/node.buttons.ts +241 -0
- package/src/rendering/webgl/node.image.ts +169 -0
- package/src/rendering/webgl/shaders/edge.clamped.vert.glsl.ts +55 -0
- package/src/rendering/webgl/shaders/node.border.frag.glsl.ts +30 -0
- package/src/rendering/webgl/shaders/node.border.vert.glsl.ts +37 -0
- package/src/rendering/webgl/shaders/node.buttons.frag.glsl.ts +32 -0
- package/src/rendering/webgl/shaders/node.buttons.vert.glsl.ts +49 -0
- package/src/rendering/webgl/shaders/node.image.frag.glsl.ts +46 -0
- package/src/rendering/webgl/shaders/node.image.vert.glsl.ts +42 -0
- package/src/types/graphDataTypes.ts +143 -0
- package/src/types/sigmaCustomRenderersTypes.ts +13 -0
- package/src/utils/__tests__/graph.spec.ts +152 -0
- package/src/utils/__tests__/graphLayout.spec.ts +125 -0
- package/src/utils/__tests__/hopsData.spec.ts +456 -0
- package/src/utils/__tests__/processResponceToGraph.spec.ts +165 -0
- package/src/utils/graph.ts +83 -0
- package/src/utils/graphLayout.ts +70 -0
- package/src/utils/hopsData.ts +198 -0
- package/src/utils/processResponseToGraph.ts +32 -0
- package/tsconfig.json +4 -0
- package/webpack.config.js +10 -0
- package/bundle.js +0 -2
- package/bundle.js.LICENSE.txt +0 -54
- /package/{5271a9e7b6651c852e93.png → public/5271a9e7b6651c852e93.png} +0 -0
- /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
|
+
}`;
|