@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,30 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* This file copies sigma/examples/custom-rendering/programs/node.border.frag.glsl, but with a some
|
|
3
|
+
* difference: white color was changed to transparent and used border radius from v_borderRadius variable
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export const fragmentShaderSource = `
|
|
7
|
+
precision mediump float;
|
|
8
|
+
|
|
9
|
+
varying vec4 v_color; // base color of node
|
|
10
|
+
varying float v_border;
|
|
11
|
+
varying float v_borderRadius; // inner border radius
|
|
12
|
+
|
|
13
|
+
const vec4 transparent = vec4(0.0, 0.0, 0.0, 0.0); // transparent color
|
|
14
|
+
const float radius = 0.5;
|
|
15
|
+
|
|
16
|
+
void main(void) {
|
|
17
|
+
float distToCenter = length(gl_PointCoord - vec2(0.5, 0.5)); // distance from current point to center of node
|
|
18
|
+
|
|
19
|
+
if (distToCenter < v_borderRadius - v_border) // distance to inner border radius
|
|
20
|
+
gl_FragColor = transparent;
|
|
21
|
+
else if (distToCenter < v_borderRadius)
|
|
22
|
+
gl_FragColor = mix(v_color, transparent, (v_borderRadius - distToCenter) / v_border);
|
|
23
|
+
else if (distToCenter < radius - v_border) // distance to outer border radius
|
|
24
|
+
gl_FragColor = v_color;
|
|
25
|
+
else if (distToCenter < radius)
|
|
26
|
+
gl_FragColor = mix(transparent, v_color, (radius - distToCenter) / v_border);
|
|
27
|
+
else // points outside the button
|
|
28
|
+
gl_FragColor = transparent;
|
|
29
|
+
}
|
|
30
|
+
`;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* This file copies sigma/examples/custom-rendering/programs/node.border.vert.glsl, but with a some
|
|
3
|
+
* difference: added calculation of v_borderRadius using a_borderSize variable
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export const vertexShaderSource = `
|
|
7
|
+
attribute vec2 a_position;
|
|
8
|
+
attribute float a_size;
|
|
9
|
+
attribute vec4 a_color;
|
|
10
|
+
attribute float a_borderSize;
|
|
11
|
+
|
|
12
|
+
uniform float u_ratio;
|
|
13
|
+
uniform float u_scale;
|
|
14
|
+
uniform mat3 u_matrix;
|
|
15
|
+
|
|
16
|
+
varying vec4 v_color;
|
|
17
|
+
varying float v_border;
|
|
18
|
+
varying float v_borderRadius;
|
|
19
|
+
|
|
20
|
+
const float bias = 255.0 / 254.0;
|
|
21
|
+
const float radius = 0.5;
|
|
22
|
+
|
|
23
|
+
void main() {
|
|
24
|
+
gl_Position = vec4((u_matrix * vec3(a_position, 1)).xy, 0, 1);
|
|
25
|
+
|
|
26
|
+
// Multiply the point size twice:
|
|
27
|
+
// - x SCALING_RATIO to correct the canvas scaling
|
|
28
|
+
// - x 2 to correct the formulae
|
|
29
|
+
gl_PointSize = a_size * u_ratio * u_scale * 2.0;
|
|
30
|
+
|
|
31
|
+
v_border = (1.0 / u_ratio) * (0.5 / a_size);
|
|
32
|
+
v_borderRadius = radius - (radius * a_borderSize / a_size); // border radius in node's size (full size is 1)
|
|
33
|
+
|
|
34
|
+
// Extract the color:
|
|
35
|
+
v_color = a_color;
|
|
36
|
+
v_color.a *= bias;
|
|
37
|
+
}`;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export const fragmentShaderSource = `
|
|
2
|
+
precision mediump float;
|
|
3
|
+
|
|
4
|
+
varying float v_border;
|
|
5
|
+
varying vec4 v_texture;
|
|
6
|
+
|
|
7
|
+
uniform sampler2D u_atlas;
|
|
8
|
+
|
|
9
|
+
const vec4 transparent = vec4(0.0, 0.0, 0.0, 0.0);
|
|
10
|
+
const vec4 black = vec4(0.0, 0.0, 0.0, 1.0);
|
|
11
|
+
const float bias = 255.0 / 254.0;
|
|
12
|
+
const float radius = 0.5;
|
|
13
|
+
|
|
14
|
+
void main(void) {
|
|
15
|
+
vec4 color;
|
|
16
|
+
float distToCenter = length(gl_PointCoord - vec2(0.5, 0.5));
|
|
17
|
+
|
|
18
|
+
// set texel as color of point
|
|
19
|
+
if (v_texture.w > 0.0) {
|
|
20
|
+
vec4 texel = texture2D(u_atlas, v_texture.xy + gl_PointCoord * v_texture.zw, -1.0);
|
|
21
|
+
color = vec4(mix(black, texel, texel.a).rgb, max(texel.a, bias));
|
|
22
|
+
} else {
|
|
23
|
+
color = black;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (distToCenter < radius - v_border) // points inside button
|
|
27
|
+
gl_FragColor = color;
|
|
28
|
+
else if (distToCenter < radius) // border of button
|
|
29
|
+
gl_FragColor = mix(transparent, color, (0.5 - distToCenter) / v_border);
|
|
30
|
+
else // points outside button
|
|
31
|
+
gl_FragColor = transparent;
|
|
32
|
+
}`;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
export const vertexShaderSource = `
|
|
2
|
+
attribute vec2 a_position;
|
|
3
|
+
attribute float a_size;
|
|
4
|
+
attribute vec4 a_color;
|
|
5
|
+
attribute float a_buttonSize;
|
|
6
|
+
attribute vec2 a_normals;
|
|
7
|
+
attribute vec4 a_texture;
|
|
8
|
+
|
|
9
|
+
uniform float u_ratio;
|
|
10
|
+
uniform float u_scale;
|
|
11
|
+
uniform mat3 u_matrix;
|
|
12
|
+
uniform float u_sqrtZoomRatio;
|
|
13
|
+
uniform float u_correctionRatio;
|
|
14
|
+
|
|
15
|
+
varying float v_border;
|
|
16
|
+
varying vec4 v_texture;
|
|
17
|
+
varying vec4 v_color;
|
|
18
|
+
|
|
19
|
+
const float bias = 255.0 / 254.0;
|
|
20
|
+
|
|
21
|
+
void main() {
|
|
22
|
+
float normalLength = length(a_normals);
|
|
23
|
+
vec2 unitNormal = (a_normals) / normalLength;
|
|
24
|
+
|
|
25
|
+
float pixelsThickness = max(normalLength, 1.0 * u_sqrtZoomRatio);
|
|
26
|
+
float webGLThickness = pixelsThickness * u_correctionRatio;
|
|
27
|
+
float adaptedWebGLThickness = webGLThickness * u_sqrtZoomRatio;
|
|
28
|
+
|
|
29
|
+
// Move the point
|
|
30
|
+
float adaptedWebGLNodeRadius = a_size * 2.0 * u_correctionRatio * u_sqrtZoomRatio;
|
|
31
|
+
vec2 compensationVector = vec2(-unitNormal.y, unitNormal.x) * (adaptedWebGLNodeRadius);
|
|
32
|
+
|
|
33
|
+
// Set position
|
|
34
|
+
gl_Position = vec4((u_matrix * vec3(a_position + compensationVector, 1)).xy, 0, 1);
|
|
35
|
+
|
|
36
|
+
// Multiply the point size twice:
|
|
37
|
+
// - x SCALING_RATIO to correct the canvas scaling
|
|
38
|
+
// - x 2 to correct the formulae
|
|
39
|
+
gl_PointSize = a_buttonSize * u_ratio * u_scale * 2.0;
|
|
40
|
+
|
|
41
|
+
v_border = (1.0 / u_ratio) * (0.5 / a_size);
|
|
42
|
+
|
|
43
|
+
// Extract the color:
|
|
44
|
+
v_color = a_color;
|
|
45
|
+
v_color.a *= bias;
|
|
46
|
+
|
|
47
|
+
// Pass the texture coordinates:
|
|
48
|
+
v_texture = a_texture;
|
|
49
|
+
}`;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
export const fragmentShaderSource = `
|
|
2
|
+
precision mediump float;
|
|
3
|
+
|
|
4
|
+
varying float v_border;
|
|
5
|
+
varying float v_inactive;
|
|
6
|
+
varying vec4 v_color;
|
|
7
|
+
varying vec4 v_texture;
|
|
8
|
+
|
|
9
|
+
uniform sampler2D u_atlas;
|
|
10
|
+
|
|
11
|
+
const vec4 transparent = vec4(0.0, 0.0, 0.0, 0.0);
|
|
12
|
+
const float radius = 0.5;
|
|
13
|
+
|
|
14
|
+
// convert color to gray
|
|
15
|
+
vec4 toGrayscale(in vec4 color)
|
|
16
|
+
{
|
|
17
|
+
float average = (color.r + color.g + color.b) / 3.0;
|
|
18
|
+
return vec4(average, average, average, 1.0);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
void main(void) {
|
|
22
|
+
vec4 color;
|
|
23
|
+
|
|
24
|
+
// set texel as color of point
|
|
25
|
+
if (v_texture.w > 0.0) {
|
|
26
|
+
vec4 texel = texture2D(u_atlas, v_texture.xy + gl_PointCoord * v_texture.zw, -1.0);
|
|
27
|
+
color = vec4(mix(v_color, texel, texel.a).rgb, max(texel.a, v_color.a));
|
|
28
|
+
} else {
|
|
29
|
+
color = v_color;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// convert color to gray
|
|
33
|
+
if (v_inactive > 0.0) {
|
|
34
|
+
color = toGrayscale(color);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// distance from point to center of node
|
|
38
|
+
float dist = length(gl_PointCoord - vec2(0.5, 0.5));
|
|
39
|
+
|
|
40
|
+
if (dist < radius - v_border) // points inside node
|
|
41
|
+
gl_FragColor = color;
|
|
42
|
+
else if (dist < radius) // border of node
|
|
43
|
+
gl_FragColor = mix(transparent, color, (radius - dist) / v_border);
|
|
44
|
+
else // points outside node
|
|
45
|
+
gl_FragColor = transparent;
|
|
46
|
+
}`;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* This file copies sigma/examples/custom-rendering/programs/node.image.vert.glsl, but with a some
|
|
3
|
+
* difference: white color was changed to transparent and used border radius from v_borderRadius variable
|
|
4
|
+
*/
|
|
5
|
+
export const vertexShaderSource = `
|
|
6
|
+
attribute vec2 a_position;
|
|
7
|
+
attribute float a_size;
|
|
8
|
+
attribute vec4 a_color;
|
|
9
|
+
attribute vec4 a_texture;
|
|
10
|
+
attribute float a_inactive;
|
|
11
|
+
|
|
12
|
+
uniform float u_ratio;
|
|
13
|
+
uniform float u_scale;
|
|
14
|
+
uniform mat3 u_matrix;
|
|
15
|
+
|
|
16
|
+
varying float v_border;
|
|
17
|
+
varying float v_inactive;
|
|
18
|
+
varying vec4 v_color;
|
|
19
|
+
varying vec4 v_texture;
|
|
20
|
+
|
|
21
|
+
const float bias = 255.0 / 254.0;
|
|
22
|
+
|
|
23
|
+
void main() {
|
|
24
|
+
gl_Position = vec4((u_matrix * vec3(a_position, 1)).xy, 0, 1);
|
|
25
|
+
|
|
26
|
+
// Multiply the point size twice:
|
|
27
|
+
// - x SCALING_RATIO to correct the canvas scaling
|
|
28
|
+
// - x 2 to correct the formulae
|
|
29
|
+
gl_PointSize = a_size * u_ratio * u_scale * 2.0;
|
|
30
|
+
|
|
31
|
+
v_border = (1.0 / u_ratio) * (0.5 / a_size);
|
|
32
|
+
|
|
33
|
+
// Extract the color:
|
|
34
|
+
v_color = a_color;
|
|
35
|
+
v_color.a *= bias;
|
|
36
|
+
|
|
37
|
+
// Pass the texture coordinates:
|
|
38
|
+
v_texture = a_texture;
|
|
39
|
+
|
|
40
|
+
// Pass inactive property
|
|
41
|
+
v_inactive = a_inactive;
|
|
42
|
+
}`;
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import Graph from 'graphology';
|
|
2
|
+
import {NodeDisplayData, EdgeDisplayData} from 'sigma/types';
|
|
3
|
+
import {
|
|
4
|
+
Entity,
|
|
5
|
+
HopsResponse,
|
|
6
|
+
HopEntity,
|
|
7
|
+
HopRelation,
|
|
8
|
+
TRelationType,
|
|
9
|
+
TEntityType,
|
|
10
|
+
Relation,
|
|
11
|
+
RecordAttributesType,
|
|
12
|
+
RelationTypeDirection,
|
|
13
|
+
GraphLayout
|
|
14
|
+
} from '@reltio/mdm-sdk';
|
|
15
|
+
|
|
16
|
+
export type AddRelation = {
|
|
17
|
+
startEntityUri: string;
|
|
18
|
+
endEntityUri: string;
|
|
19
|
+
relationType: string;
|
|
20
|
+
attributes?: RecordAttributesType;
|
|
21
|
+
startDate?: number;
|
|
22
|
+
endDate?: number;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export type Filters = {entityTypesUris: string[]; relationTypesUris: string[]};
|
|
26
|
+
|
|
27
|
+
export type GraphState = {
|
|
28
|
+
graphLoading: boolean;
|
|
29
|
+
data: HopsResponse;
|
|
30
|
+
graphologyGraph: Graph;
|
|
31
|
+
selectedEntityLoading: boolean;
|
|
32
|
+
selectedEntity: Entity;
|
|
33
|
+
onDeleteRelation?: (uri: string) => void;
|
|
34
|
+
onEntitySelect: (uri: string) => void;
|
|
35
|
+
onCollapseEntity: (uri: string, path: GraphPathType) => void;
|
|
36
|
+
onExpandEntity: (uri: string) => void;
|
|
37
|
+
graphTypeUri?: string;
|
|
38
|
+
setGraphTypeUri?: (graphType: string) => void;
|
|
39
|
+
relationshipTable: RelationshipTableState;
|
|
40
|
+
onAddRelation?: (params: AddRelation) => Promise<void>;
|
|
41
|
+
layout: GraphLayout;
|
|
42
|
+
setLayout: (layout: GraphLayout) => void;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export type RelationshipTableState = {
|
|
46
|
+
rowsData?: RelationshipRow[];
|
|
47
|
+
onSort?: (sorting: {field: string; order: string}) => void;
|
|
48
|
+
sorting?: {
|
|
49
|
+
field: string;
|
|
50
|
+
order: string;
|
|
51
|
+
};
|
|
52
|
+
editingRelations?: Array<{initialRelation: Relation; relation: Relation}>;
|
|
53
|
+
onStartRelationEditing?: (uri: string) => void;
|
|
54
|
+
onCancelRelationEditing?: (uri: string) => void;
|
|
55
|
+
onUpdateEditingRelation?: (relation: Relation) => void;
|
|
56
|
+
onSaveEditingRelation?: (oldRelation: Relation, newRelation: Relation) => void;
|
|
57
|
+
total?: number;
|
|
58
|
+
page?: number;
|
|
59
|
+
rowsPerPage?: number;
|
|
60
|
+
onPageChange?: (page: number) => void;
|
|
61
|
+
onRowsPerPageChange?: (page: number) => void;
|
|
62
|
+
searchText?: string;
|
|
63
|
+
onChangeSearchText?: (value: string) => void;
|
|
64
|
+
filters?: Filters;
|
|
65
|
+
onFilter?: (filters: Filters) => void;
|
|
66
|
+
relationTypesOptions?: TRelationType[];
|
|
67
|
+
entityTypesOptions?: TEntityType[];
|
|
68
|
+
loading?: boolean;
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
export type Edge = {
|
|
72
|
+
from: string;
|
|
73
|
+
to: string;
|
|
74
|
+
key: string;
|
|
75
|
+
relationTypeUri: string;
|
|
76
|
+
direction: RelationTypeDirection;
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
export type Node = {
|
|
80
|
+
id: string;
|
|
81
|
+
name: string;
|
|
82
|
+
entityTypeUri: string;
|
|
83
|
+
traversedRelationsCount: number;
|
|
84
|
+
untraversedRelationsCount: number;
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
export type GraphologyGraphData = {
|
|
88
|
+
nodes: Node[];
|
|
89
|
+
edges: Edge[];
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
export type EdgeAttributes = EdgeDisplayData & {
|
|
93
|
+
loop: boolean;
|
|
94
|
+
relationTypeUri?: string;
|
|
95
|
+
direction?: RelationTypeDirection;
|
|
96
|
+
hidden?: boolean;
|
|
97
|
+
arrowSizeRatio?: number;
|
|
98
|
+
hovered?: boolean;
|
|
99
|
+
relationLabel?: string;
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
export type NodeAttributes = NodeDisplayData & {
|
|
103
|
+
buttonSize: number;
|
|
104
|
+
buttonOffset: [number, number];
|
|
105
|
+
image: string;
|
|
106
|
+
entityTypeUri: string;
|
|
107
|
+
traversedRelationsCount?: number;
|
|
108
|
+
untraversedRelationsCount?: number;
|
|
109
|
+
inPath?: boolean;
|
|
110
|
+
inactive?: boolean;
|
|
111
|
+
showExpand?: boolean;
|
|
112
|
+
showCollapse?: boolean;
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
export type NodesHierarchy = Array<string[]>;
|
|
116
|
+
|
|
117
|
+
export type GraphPathType = {
|
|
118
|
+
edges?: string[];
|
|
119
|
+
nodes?: string[];
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
export type RelationshipRow = {
|
|
123
|
+
entity: HopEntity;
|
|
124
|
+
relation: HopRelation;
|
|
125
|
+
entityLabel: string;
|
|
126
|
+
entityTypeLabel: string;
|
|
127
|
+
relationTypeLabel: string;
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
export interface GraphologyLayout<T> {
|
|
131
|
+
(graph: Graph, options: T): {[node: string]: {[dimension: string]: number}};
|
|
132
|
+
assign?(graph: Graph, options: T): void;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
interface GraphologyWorkerLayout {
|
|
136
|
+
stop: () => void;
|
|
137
|
+
start: () => void;
|
|
138
|
+
kill: () => void;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
export interface GraphologyWorkerLayoutConstructor<T> {
|
|
142
|
+
new (graph: Graph, settings: T): GraphologyWorkerLayout;
|
|
143
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
type Renderer = {
|
|
2
|
+
renderer: (context: CanvasRenderingContext2D) => void;
|
|
3
|
+
insertBefore: string;
|
|
4
|
+
};
|
|
5
|
+
|
|
6
|
+
export type Renderers = Record<string, Renderer>;
|
|
7
|
+
|
|
8
|
+
export type Canvas = {
|
|
9
|
+
canvasElement: HTMLCanvasElement;
|
|
10
|
+
context: CanvasRenderingContext2D;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export type Canvases = Record<string, Canvas>;
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import {MultiGraph} from 'graphology';
|
|
2
|
+
import {HopsResponse} from '@reltio/mdm-sdk';
|
|
3
|
+
import {fillGraphWithHopsResponse, getIsolatedNodes} from '../graph';
|
|
4
|
+
|
|
5
|
+
describe('Graph utils', () => {
|
|
6
|
+
describe('getIsolatedNodes behavior', () => {
|
|
7
|
+
/**
|
|
8
|
+
* 'e1' ---- 'e3
|
|
9
|
+
* |
|
|
10
|
+
* 'e2' ---- 'e6'
|
|
11
|
+
* |
|
|
12
|
+
* 'e4' ---- 'e5' --- 'e7'
|
|
13
|
+
*/
|
|
14
|
+
const data: HopsResponse = {
|
|
15
|
+
entities: [
|
|
16
|
+
{uri: 'e1', type: ''},
|
|
17
|
+
{uri: 'e2', type: ''},
|
|
18
|
+
{uri: 'e3', type: ''},
|
|
19
|
+
{uri: 'e4', type: ''},
|
|
20
|
+
{uri: 'e5', type: ''},
|
|
21
|
+
{uri: 'e6', type: ''},
|
|
22
|
+
{uri: 'e7', type: ''}
|
|
23
|
+
],
|
|
24
|
+
relations: [
|
|
25
|
+
{
|
|
26
|
+
uri: 'r1',
|
|
27
|
+
type: '',
|
|
28
|
+
startObject: {
|
|
29
|
+
objectURI: 'e1'
|
|
30
|
+
},
|
|
31
|
+
endObject: {
|
|
32
|
+
objectURI: 'e2'
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
uri: 'r2',
|
|
37
|
+
type: '',
|
|
38
|
+
startObject: {
|
|
39
|
+
objectURI: 'e1'
|
|
40
|
+
},
|
|
41
|
+
endObject: {
|
|
42
|
+
objectURI: 'e3'
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
uri: 'r3',
|
|
47
|
+
type: '',
|
|
48
|
+
startObject: {
|
|
49
|
+
objectURI: 'e2'
|
|
50
|
+
},
|
|
51
|
+
endObject: {
|
|
52
|
+
objectURI: 'e4'
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
uri: 'r4',
|
|
57
|
+
type: '',
|
|
58
|
+
startObject: {
|
|
59
|
+
objectURI: 'e2'
|
|
60
|
+
},
|
|
61
|
+
endObject: {
|
|
62
|
+
objectURI: 'e6'
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
uri: 'r5',
|
|
67
|
+
type: '',
|
|
68
|
+
startObject: {
|
|
69
|
+
objectURI: 'e4'
|
|
70
|
+
},
|
|
71
|
+
endObject: {
|
|
72
|
+
objectURI: 'e5'
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
uri: 'r6',
|
|
77
|
+
type: '',
|
|
78
|
+
startObject: {
|
|
79
|
+
objectURI: 'e5'
|
|
80
|
+
},
|
|
81
|
+
endObject: {
|
|
82
|
+
objectURI: 'e7'
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
]
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
it('should return isolated nodes', () => {
|
|
89
|
+
const entityUri = 'e1';
|
|
90
|
+
const mainNode = 'e2';
|
|
91
|
+
|
|
92
|
+
const graph = new MultiGraph();
|
|
93
|
+
fillGraphWithHopsResponse(graph, data);
|
|
94
|
+
|
|
95
|
+
expect(getIsolatedNodes(entityUri, mainNode, ['e4', 'e6'], graph)).toEqual(['e4', 'e5', 'e6', 'e7']);
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it('should not remove node if it has path to entityUri', () => {
|
|
99
|
+
const hopsData = {
|
|
100
|
+
entities: [...data.entities],
|
|
101
|
+
relations: [
|
|
102
|
+
...data.relations,
|
|
103
|
+
{
|
|
104
|
+
uri: 'r7',
|
|
105
|
+
type: '',
|
|
106
|
+
startObject: {
|
|
107
|
+
objectURI: 'e5'
|
|
108
|
+
},
|
|
109
|
+
endObject: {
|
|
110
|
+
objectURI: 'e3'
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
]
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
const graph = new MultiGraph();
|
|
117
|
+
fillGraphWithHopsResponse(graph, hopsData);
|
|
118
|
+
|
|
119
|
+
const entityUri = 'e1';
|
|
120
|
+
const mainNode = 'e2';
|
|
121
|
+
|
|
122
|
+
expect(getIsolatedNodes(entityUri, mainNode, ['e4', 'e6'], graph)).toEqual(['e4', 'e6']);
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
it('should remove node from directed graph', () => {
|
|
126
|
+
const hopsData = {
|
|
127
|
+
entities: [...data.entities],
|
|
128
|
+
relations: [
|
|
129
|
+
...data.relations,
|
|
130
|
+
{
|
|
131
|
+
uri: 'r7',
|
|
132
|
+
type: '',
|
|
133
|
+
startObject: {
|
|
134
|
+
objectURI: 'e5'
|
|
135
|
+
},
|
|
136
|
+
endObject: {
|
|
137
|
+
objectURI: 'e4'
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
]
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
const graph = new MultiGraph();
|
|
144
|
+
fillGraphWithHopsResponse(graph, hopsData);
|
|
145
|
+
|
|
146
|
+
const entityUri = 'e1';
|
|
147
|
+
const mainNode = 'e2';
|
|
148
|
+
|
|
149
|
+
expect(getIsolatedNodes(entityUri, mainNode, ['e4', 'e6'], graph)).toEqual(['e4', 'e5', 'e6', 'e7']);
|
|
150
|
+
});
|
|
151
|
+
});
|
|
152
|
+
});
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import {HopsResponse, RelationTypeDirection} from '@reltio/mdm-sdk';
|
|
2
|
+
import {MultiGraph} from 'graphology';
|
|
3
|
+
import {fillGraphWithHopsResponse} from '../graph';
|
|
4
|
+
import {mouseIsOnNode, directionTypeToEdgeType, edgePathFromNodePath, getMousePos} from '../graphLayout';
|
|
5
|
+
|
|
6
|
+
describe('Graph Layout utils', () => {
|
|
7
|
+
describe('mouseIsOnNode behaviour', () => {
|
|
8
|
+
it('should work correctly if cursor over node', () => {
|
|
9
|
+
expect(mouseIsOnNode(100, 100, 100, 100, 50)).toBe(true);
|
|
10
|
+
expect(mouseIsOnNode(130, 100, 100, 100, 50)).toBe(true);
|
|
11
|
+
expect(mouseIsOnNode(80, 100, 100, 100, 50)).toBe(true);
|
|
12
|
+
expect(mouseIsOnNode(70, 70, 100, 100, 50)).toBe(true);
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it('should work correctly if cursor does not over node', () => {
|
|
16
|
+
expect(mouseIsOnNode(160, 100, 100, 100, 50)).toBe(false);
|
|
17
|
+
expect(mouseIsOnNode(100, 160, 100, 100, 50)).toBe(false);
|
|
18
|
+
expect(mouseIsOnNode(40, 100, 100, 100, 50)).toBe(false);
|
|
19
|
+
expect(mouseIsOnNode(100, 40, 100, 100, 50)).toBe(false);
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
describe('directionTypeToEdgeType behaviour', () => {
|
|
24
|
+
it('should format direction type to edge type correctly', () => {
|
|
25
|
+
expect(directionTypeToEdgeType(RelationTypeDirection.bidirectional)).toBe('doubleArrow');
|
|
26
|
+
expect(directionTypeToEdgeType(RelationTypeDirection.directed)).toBe('arrow');
|
|
27
|
+
expect(directionTypeToEdgeType(RelationTypeDirection.undirected)).toBe('line');
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it('should return line edge type by default for unknown direction type', () => {
|
|
31
|
+
expect(directionTypeToEdgeType('unknownDirectionType' as any)).toBe('line');
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
describe('edgePathFromNodePath behaviour', () => {
|
|
36
|
+
it('should return correct edge path from node path', () => {
|
|
37
|
+
const data: HopsResponse = {
|
|
38
|
+
entities: [
|
|
39
|
+
{
|
|
40
|
+
uri: 'entities/mnGjvTt',
|
|
41
|
+
type: 'configuration/entityTypes/HCP',
|
|
42
|
+
label: 'new23цц new1m123 - kkk',
|
|
43
|
+
secondaryLabel: ', kkk',
|
|
44
|
+
untraversedRelations: 94,
|
|
45
|
+
traversedRelations: 22
|
|
46
|
+
},
|
|
47
|
+
|
|
48
|
+
{
|
|
49
|
+
label: 'MK HCP17991 MyTest1 - Name - QitLNIUQIIvHTTv Rolojfeg',
|
|
50
|
+
secondaryLabel: 'QitLNIUQIIvHTTv Rolojfeg CO, Name',
|
|
51
|
+
traversedRelations: 27,
|
|
52
|
+
type: 'configuration/entityTypes/HCP',
|
|
53
|
+
untraversedRelations: 0,
|
|
54
|
+
uri: 'entities/tw5GACk'
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
label: 'Copy of MK HCP17991 - New Name Created Entity7',
|
|
58
|
+
secondaryLabel: ', New Name Created Entity7',
|
|
59
|
+
traversedRelations: 2,
|
|
60
|
+
type: 'configuration/entityTypes/HCP',
|
|
61
|
+
untraversedRelations: 4,
|
|
62
|
+
uri: 'entities/1oUp8K0G'
|
|
63
|
+
}
|
|
64
|
+
],
|
|
65
|
+
relations: [
|
|
66
|
+
{
|
|
67
|
+
uri: 'relations/1GJ69oZR',
|
|
68
|
+
type: 'configuration/relationTypes/Family',
|
|
69
|
+
startObject: {
|
|
70
|
+
objectURI: 'entities/tw5GACk',
|
|
71
|
+
directionalLabel: 'Family'
|
|
72
|
+
},
|
|
73
|
+
endObject: {
|
|
74
|
+
objectURI: 'entities/mnGjvTt',
|
|
75
|
+
directionalLabel: 'Family'
|
|
76
|
+
},
|
|
77
|
+
direction: RelationTypeDirection.bidirectional
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
direction: RelationTypeDirection.directed,
|
|
81
|
+
endObject: {
|
|
82
|
+
directionalLabel: '',
|
|
83
|
+
objectURI: 'entities/1oUp8K0G'
|
|
84
|
+
},
|
|
85
|
+
startObject: {
|
|
86
|
+
directionalLabel: '',
|
|
87
|
+
objectURI: 'entities/mnGjvTt'
|
|
88
|
+
},
|
|
89
|
+
type: 'configuration/relationTypes/HCPtoHCP',
|
|
90
|
+
uri: 'relations/1DKed0bI'
|
|
91
|
+
}
|
|
92
|
+
]
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
const graph = new MultiGraph();
|
|
96
|
+
fillGraphWithHopsResponse(graph, data);
|
|
97
|
+
const nodes = ['entities/tw5GACk', 'entities/mnGjvTt', 'entities/1oUp8K0G'];
|
|
98
|
+
const isDirected = false;
|
|
99
|
+
expect(edgePathFromNodePath(graph, nodes, isDirected)).toEqual([
|
|
100
|
+
'relations/1GJ69oZR',
|
|
101
|
+
'relations/1DKed0bI'
|
|
102
|
+
]);
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
describe('getMousePos behaviour', () => {
|
|
107
|
+
it('should return real mouse position correctly', () => {
|
|
108
|
+
const canvas = {
|
|
109
|
+
getBoundingClientRect: () => ({
|
|
110
|
+
left: 64,
|
|
111
|
+
right: 888,
|
|
112
|
+
top: 148,
|
|
113
|
+
bottom: 1000
|
|
114
|
+
}),
|
|
115
|
+
width: 772,
|
|
116
|
+
height: 798
|
|
117
|
+
} as HTMLCanvasElement;
|
|
118
|
+
const mouseEvent = {
|
|
119
|
+
clientX: 864,
|
|
120
|
+
clientY: 547
|
|
121
|
+
} as MouseEvent;
|
|
122
|
+
expect(getMousePos(canvas, mouseEvent)).toEqual({x: 749.5145631067961, y: 373.7112676056338});
|
|
123
|
+
});
|
|
124
|
+
});
|
|
125
|
+
});
|