@neo4j-nvl/base 1.0.0 → 1.1.0
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/CHANGELOG.md +25 -0
- package/dist/base.mjs +1 -1
- package/dist/types/index.d.ts +25 -11
- package/dist/types/layouts/circularLayout/CircularLayout.d.ts +18 -0
- package/dist/types/layouts/forcedirectedlayout/ForceCytoLayout.d.ts +1 -1
- package/dist/types/layouts/forcedirectedlayout/physlayout/PhysLayout.d.ts +8 -3
- package/dist/types/layouts/forcedirectedlayout/physlayout/shaders/multilevel-fragment-verlet.d.ts +1 -1
- package/dist/types/layouts/forcedirectedlayout/physlayout/solarmerger/SolarMerger.d.ts +17 -39
- package/dist/types/layouts/forcedirectedlayout/physlayout/solarmerger/types.d.ts +49 -0
- package/dist/types/modules/NvlController.d.ts +6 -2
- package/dist/types/modules/state/types.d.ts +30 -9
- package/dist/types/modules/state/utils.d.ts +2 -2
- package/dist/types/renderers/domrenderer/BaseRenderer.d.ts +75 -0
- package/dist/types/renderers/domrenderer/canvasrenderer/CanvasRenderer.d.ts +120 -0
- package/dist/types/renderers/{canvasrenderer/util.d.ts → domrenderer/canvasrenderer/canvasUtils.d.ts} +2 -14
- package/dist/types/renderers/domrenderer/shared/ImageCache.d.ts +16 -0
- package/dist/types/renderers/{canvasrenderer → domrenderer/shared}/arrows/ArrowBundle.d.ts +2 -2
- package/dist/types/renderers/{canvasrenderer → domrenderer/shared}/arrows/ArrowBundler.d.ts +1 -1
- package/dist/types/renderers/domrenderer/shared/arrows/arrows.d.ts +175 -0
- package/dist/types/renderers/domrenderer/shared/nodes/nodeUtils.d.ts +29 -0
- package/dist/types/renderers/domrenderer/shared/nodes/nodes.d.ts +58 -0
- package/dist/types/renderers/{canvasrenderer → domrenderer/shared}/types.d.ts +2 -2
- package/dist/types/renderers/domrenderer/shared/util.d.ts +11 -0
- package/dist/types/renderers/{canvasrenderer → domrenderer/shared}/vectorUtils.d.ts +1 -1
- package/dist/types/renderers/{canvasrenderer → domrenderer/shared}/wordwrap.d.ts +10 -0
- package/dist/types/renderers/domrenderer/shared/wordwrap.test.d.ts +1 -0
- package/dist/types/renderers/domrenderer/svgrenderer/SvgRenderer.d.ts +22 -0
- package/dist/types/renderers/domrenderer/svgrenderer/SvgRenderer.test.d.ts +1 -0
- package/dist/types/renderers/domrenderer/svgrenderer/svgUtils.d.ts +175 -0
- package/dist/types/renderers/webglrenderer/Renderer.d.ts +5 -1
- package/dist/types/renderers/webglrenderer/Renderer.test.d.ts +1 -0
- package/dist/types/types/graph-element.d.ts +1 -1
- package/dist/types/utils/canvasManagement.d.ts +16 -1
- package/dist/types/utils/circularUtils.d.ts +3 -0
- package/dist/types/utils/circularUtils.test.d.ts +1 -0
- package/dist/types/utils/constants.d.ts +4 -1
- package/dist/types/utils/geometry.d.ts +2 -1
- package/dist/types/utils/graphObjectUtils.d.ts +2 -2
- package/dist/types/utils/jsDriverResultTransformer.d.ts +1 -1
- package/package.json +23 -23
- package/dist/types/modules/performance.d.ts +0 -93
- package/dist/types/renderers/canvasrenderer/CanvasRenderer.d.ts +0 -93
- package/dist/types/renderers/canvasrenderer/ImageCache.d.ts +0 -11
- package/dist/types/renderers/canvasrenderer/arrows/arrows.d.ts +0 -55
- package/dist/types/renderers/canvasrenderer/nodes/nodes.d.ts +0 -59
- /package/dist/types/{renderers/canvasrenderer/Animation.test.d.ts → layouts/d3forcelayout/circularLayout.test.d.ts} +0 -0
- /package/dist/types/renderers/{canvasrenderer → domrenderer/canvasrenderer}/Animation.d.ts +0 -0
- /package/dist/types/renderers/{canvasrenderer/CanvasRenderer.test.d.ts → domrenderer/canvasrenderer/Animation.test.d.ts} +0 -0
- /package/dist/types/renderers/{canvasrenderer → domrenderer/canvasrenderer}/AnimationHandler.d.ts +0 -0
- /package/dist/types/renderers/{canvasrenderer/ImageCache.test.d.ts → domrenderer/canvasrenderer/CanvasRenderer.test.d.ts} +0 -0
- /package/dist/types/renderers/{canvasrenderer/arrows/ArrowBundle.test.d.ts → domrenderer/shared/ImageCache.test.d.ts} +0 -0
- /package/dist/types/renderers/{canvasrenderer/arrows/ArrowBundler.test.d.ts → domrenderer/shared/arrows/ArrowBundle.test.d.ts} +0 -0
- /package/dist/types/renderers/{canvasrenderer/arrows/arrows.test.d.ts → domrenderer/shared/arrows/ArrowBundler.test.d.ts} +0 -0
- /package/dist/types/renderers/{canvasrenderer/nodes/nodes.test.d.ts → domrenderer/shared/arrows/arrows.test.d.ts} +0 -0
- /package/dist/types/renderers/{canvasrenderer → domrenderer/shared}/arrows/constants.d.ts +0 -0
- /package/dist/types/renderers/{canvasrenderer/util.test.d.ts → domrenderer/shared/nodes/nodes.test.d.ts} +0 -0
- /package/dist/types/renderers/{canvasrenderer/wordwrap.test.d.ts → domrenderer/shared/util.test.d.ts} +0 -0
package/dist/types/index.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { ExternalCallbacks } from './modules/ExternalCallbackHandler';
|
|
2
|
-
import type { ForceDirectedOptions, HierarchicalOptions, Layout, LayoutOptions, NvlOptions, NvlState,
|
|
3
|
-
import { CanvasRendererType, ForceDirectedLayoutType, FreeLayoutType, GridLayoutType, HierarchicalLayoutType, WebGLRendererType, d3ForceLayoutType } from './modules/state/types';
|
|
4
|
-
import
|
|
5
|
-
import {
|
|
2
|
+
import type { CircularOptions, ForceDirectedOptions, HierarchicalOptions, Renderer as InternalRenderer, Layout, LayoutOptions, NvlOptions, NvlState, ZoomOptions } from './modules/state/types';
|
|
3
|
+
import { CanvasRendererType, CircularLayoutType, ForceDirectedLayoutType, FreeLayoutType, GridLayoutType, HierarchicalLayoutType, SvgRendererType, WebGLRendererType, d3ForceLayoutType } from './modules/state/types';
|
|
4
|
+
import { drawCircleBand } from './renderers/domrenderer/canvasrenderer/canvasUtils';
|
|
5
|
+
import type { StyledCaption } from './renderers/domrenderer/shared/types';
|
|
6
6
|
import type { Node, PartialNode, PartialRelationship, Relationship } from './types/graph-element';
|
|
7
7
|
import { CompatibilityError } from './utils/errors';
|
|
8
8
|
import type { Point } from './utils/geometry';
|
|
@@ -38,11 +38,6 @@ interface NvlMouseEvent extends MouseEvent {
|
|
|
38
38
|
*/
|
|
39
39
|
declare class NVL {
|
|
40
40
|
#private;
|
|
41
|
-
/**
|
|
42
|
-
* @internal
|
|
43
|
-
* @hidden
|
|
44
|
-
*/
|
|
45
|
-
readonly performance: any;
|
|
46
41
|
/**
|
|
47
42
|
* Creates a new NVL instance.
|
|
48
43
|
* @param frame - The DOM element to display the graph in.
|
|
@@ -274,6 +269,17 @@ declare class NVL {
|
|
|
274
269
|
filename?: string;
|
|
275
270
|
backgroundColor?: string;
|
|
276
271
|
}): void;
|
|
272
|
+
/**
|
|
273
|
+
* Saves the entire graph visualization as an SVG file to the client.
|
|
274
|
+
* @param options - Options for the SVG export
|
|
275
|
+
* @param options.filename - The filename of the SVG file.
|
|
276
|
+
* @param options.backgroundColor - The background color of the SVG file.
|
|
277
|
+
* @experimental
|
|
278
|
+
*/
|
|
279
|
+
saveToSvg(options?: {
|
|
280
|
+
filename?: string;
|
|
281
|
+
backgroundColor?: string;
|
|
282
|
+
}): void;
|
|
277
283
|
/**
|
|
278
284
|
* Returns the current view of the graph visualization canvas as a data URL.
|
|
279
285
|
* @param options - The options for the image.
|
|
@@ -295,6 +301,10 @@ declare class NVL {
|
|
|
295
301
|
filename?: string;
|
|
296
302
|
backgroundColor?: string;
|
|
297
303
|
}): void;
|
|
304
|
+
getZoomLimits(): {
|
|
305
|
+
minZoom: number;
|
|
306
|
+
maxZoom: number;
|
|
307
|
+
};
|
|
298
308
|
/**
|
|
299
309
|
* Sets the zoom of the viewport to a specific value.
|
|
300
310
|
* @param zoomValue - The desired zoom level.
|
|
@@ -381,6 +391,10 @@ declare class NVL {
|
|
|
381
391
|
declare const colorMapperFunctions: {
|
|
382
392
|
textColorForBackground: (color: string) => string;
|
|
383
393
|
};
|
|
394
|
+
/**
|
|
395
|
+
* The different types of renderers available
|
|
396
|
+
*/
|
|
397
|
+
type Renderer = Exclude<InternalRenderer, typeof SvgRendererType>;
|
|
384
398
|
export default NVL;
|
|
385
|
-
export type { NvlOptions, Renderer, Node, Relationship, PartialNode, PartialRelationship, Layout, LayoutOptions, ForceDirectedOptions, HierarchicalOptions, ExternalCallbacks, HitTargets, HitTargetNode, HitTargetRelationship, Point, NvlMouseEvent, ZoomOptions, StyledCaption, WebGLRendererType, CanvasRendererType };
|
|
386
|
-
export { NVL, colorMapperFunctions, CompatibilityError, ForceDirectedLayoutType, HierarchicalLayoutType, GridLayoutType, FreeLayoutType, d3ForceLayoutType, drawCircleBand, nvlResultTransformer, getZoomTargetForNodePositions };
|
|
399
|
+
export type { NvlOptions, Renderer, Node, Relationship, PartialNode, PartialRelationship, Layout, LayoutOptions, ForceDirectedOptions, HierarchicalOptions, CircularOptions, ExternalCallbacks, HitTargets, HitTargetNode, HitTargetRelationship, Point, NvlMouseEvent, ZoomOptions, StyledCaption, WebGLRendererType, CanvasRendererType };
|
|
400
|
+
export { NVL, colorMapperFunctions, CompatibilityError, ForceDirectedLayoutType, HierarchicalLayoutType, GridLayoutType, FreeLayoutType, d3ForceLayoutType, CircularLayoutType, drawCircleBand, nvlResultTransformer, getZoomTargetForNodePositions };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { CircularOptions, LayoutOptions, NvlState } from '../../modules/state/types';
|
|
2
|
+
import AnimatedLayout from '../animatedlayout/AnimatedLayout';
|
|
3
|
+
type CircularLayoutConfig = {
|
|
4
|
+
state: NvlState;
|
|
5
|
+
} & CircularOptions;
|
|
6
|
+
export declare class CircularLayout extends AnimatedLayout {
|
|
7
|
+
private stateDisposers;
|
|
8
|
+
private sortFunction;
|
|
9
|
+
constructor(config: CircularLayoutConfig);
|
|
10
|
+
setOptions(options?: LayoutOptions): void;
|
|
11
|
+
update(refreshPositions?: boolean): void;
|
|
12
|
+
getShouldUpdate(): boolean;
|
|
13
|
+
getComputing(): boolean;
|
|
14
|
+
private layout;
|
|
15
|
+
terminateUpdate(): void;
|
|
16
|
+
destroy(): void;
|
|
17
|
+
}
|
|
18
|
+
export {};
|
|
@@ -16,7 +16,7 @@ export declare class ForceCytoLayout {
|
|
|
16
16
|
getShouldUpdate(): boolean;
|
|
17
17
|
getComputing(): boolean;
|
|
18
18
|
updateNodes(positionList: any): void;
|
|
19
|
-
getNodePositions(data: any): import("
|
|
19
|
+
getNodePositions(data: any): import("../..").Node[];
|
|
20
20
|
terminateUpdate(): void;
|
|
21
21
|
destroy(): void;
|
|
22
22
|
}
|
|
@@ -52,9 +52,14 @@ export declare class PhysLayout {
|
|
|
52
52
|
private pinTexture;
|
|
53
53
|
private addedNodes;
|
|
54
54
|
private updateTexture;
|
|
55
|
+
private vaoExt;
|
|
56
|
+
private physVao;
|
|
57
|
+
private physSmallVao;
|
|
58
|
+
private updateVao;
|
|
59
|
+
private workaroundVao;
|
|
55
60
|
enableVerlet: boolean;
|
|
56
61
|
constructor(config: ForceDirectedOptions & {
|
|
57
|
-
webGLContext:
|
|
62
|
+
webGLContext: WebGLRenderingContext;
|
|
58
63
|
state: NvlState;
|
|
59
64
|
});
|
|
60
65
|
/**
|
|
@@ -71,7 +76,7 @@ export declare class PhysLayout {
|
|
|
71
76
|
setData(data: {
|
|
72
77
|
nodes: Node[];
|
|
73
78
|
rels: Relationship[];
|
|
74
|
-
}):
|
|
79
|
+
}): import("./solarmerger/types").CoarsenedGraph;
|
|
75
80
|
/**
|
|
76
81
|
* Updates the node's positions for the next step in the physics layout iterations if the layout needs to update
|
|
77
82
|
* @param refreshPositions whether the entire layout should be reheated
|
|
@@ -130,7 +135,7 @@ export declare class PhysLayout {
|
|
|
130
135
|
}, relationshipChanges: {
|
|
131
136
|
adds: Record<string, Relationship>;
|
|
132
137
|
removes: Record<string, Relationship>;
|
|
133
|
-
}):
|
|
138
|
+
}): import("./solarmerger/types").CoarsenedGraph;
|
|
134
139
|
/**
|
|
135
140
|
* Destroys the class and all buffers and textures.
|
|
136
141
|
*/
|
package/dist/types/layouts/forcedirectedlayout/physlayout/shaders/multilevel-fragment-verlet.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
declare const _default: "precision mediump float;\n\nuniform sampler2D u_physData;\nuniform sampler2D u_connections;\nuniform sampler2D u_connectionOffsets;\nuniform sampler2D u_pinnedNodes;\nuniform sampler2D u_sizeTexture;\nuniform float u_baseLength;\nuniform float u_curIteration;\nuniform float u_iterationMultiplier;\nuniform vec2 u_gravityCenter;\nuniform float u_numNodes;\nuniform float u_gravity;\n\nuniform sampler2D u_clusterData;\nuniform sampler2D u_prevForce;\nuniform float u_collisionMultiplier;\n\n\nfloat DAMP = 0.6;\nfloat COOL = 0.99998;\nfloat TEMP = max(0.02, pow(COOL, u_curIteration));\nfloat TIMESTEP = 1.0 / 30.0;\nfloat VELOCITYDECAY = 0.6;\nfloat accLimitLow = 500000.0;\nfloat accLimitHigh = 750000.0;\nfloat accLimitPosHigh = 10000000.0;\n\nconst float denseNodeThreshold = 1000.0;\nconst float MIN_DISTANCE = 0.00000001;\nconst float MAX_DISTANCE = 1000000000.0;\nconst float MAX_ACCELERATION = 50000.0;\n\nvec4 getTextureData(sampler2D texture, float index, float base) {\n float x = mod(index, base);\n float y = (index - x) / base;\n return texture2D(texture, vec2(x + 0.5, y + 0.5) / base);\n}\n\nbool isNan(float val) {\n return (val < 0.0 || 0.0 < val || val == 0.0) ? false : true;\n}\n\nconst float BIG_NUMBER = 999999999999999999.0;\nbool isInf(float val) {\n return val > BIG_NUMBER || val < -BIG_NUMBER;\n}\n\nvec2 getDelta(vec2 v1, vec2 v2) {\n vec2 delta = v1 - v2;\n float dist = length(delta);\n if (dist < MIN_DISTANCE || isNan(dist)) {\n return vec2(MIN_DISTANCE, MIN_DISTANCE);\n }\n if (dist > MAX_DISTANCE) {\n vec2 normDelta = delta / dist;\n return normDelta * MAX_DISTANCE;\n }\n return delta;\n}\n\nvec4 getOtherNodePosition(float i) {\n return getTextureData(u_physData, i, 256.0);\n}\n\nfloat getCombinedNodeSize(float i, float nodeSize) {\n float otherNodeSize = getTextureData(u_sizeTexture, i, 256.0).a;\n return nodeSize + otherNodeSize;\n}\n\nvec2 getSpringForce(float curConnection, float numConnections, float springFScale, vec4 myPosition, float i) {\n float curSpring = getTextureData(u_connections, curConnection + i, 4096.0).a;\n\n vec4 otherPosition = getTextureData(u_physData, curSpring, 256.0);\n float otherDataPosition = getTextureData(u_connectionOffsets, curSpring, 256.0).a;\n float avgDegree;\n#if INTEL_WORKAROUND\n avgDegree = max(numConnections, 4.0);\n#else\n float otherNumConnections = getTextureData(u_connections, otherDataPosition, 4096.0).a;\n avgDegree = max((otherNumConnections + numConnections * 3.0) / 4.0, 4.0);\n#endif\n\n vec2 delta = getDelta(myPosition.xy, otherPosition.xy);\n float dist = length(delta);\n\n float F = (dist * dist * springFScale) / (u_baseLength * avgDegree);\n if (u_collisionMultiplier > 0.0) {\n F *= u_collisionMultiplier;\n }\n return (-delta / dist) * F;\n}\n\nvec2 getCollisionForce(float combinedNodeSize, float dist, float fScale, vec2 delta) {\n float collisionForce = (combinedNodeSize - dist) / (dist);\n if (u_collisionMultiplier > 0.0) {\n collisionForce *= u_collisionMultiplier;\n }\n return (delta * collisionForce * fScale * combinedNodeSize) / (combinedNodeSize + 1.0);\n}\n\nvec2 getRepulsionForce(float dist, float fScale, vec2 delta) {\n float F = (u_baseLength * u_baseLength * fScale) / (dist);\n return (delta / dist) * F * 0.05;\n}\n\nvoid main(void) {\n float textureSide = 256.0; //#TEXTURE_SIDE#;\n float index = (gl_FragCoord.x - 0.5) + (gl_FragCoord.y - 0.5) * textureSide;\n\n if (index >= u_numNodes) {\n discard;\n }\n\n vec4 clusterData = getTextureData(u_clusterData, index, 256.0);\n\n float clusterIndex = clusterData.x;\n float clusterStartIndex = clusterData.y;\n float clusterSize = clusterData.z;\n float clusterWeight = clusterData.w;\n\n vec4 myPosition = getTextureData(u_physData, index, 256.0);\n vec4 previousForce = getTextureData(u_prevForce, clusterIndex, 256.0);\n\n vec2 acceleration = previousForce.xy;\n\n float isPinned = getTextureData(u_pinnedNodes, index, 256.0).a;\n float nodeSize = getTextureData(u_sizeTexture, index, 256.0).a;\n\n if (isPinned > 0.5) {\n gl_FragColor = vec4(myPosition.xy, 0.0, 0.0);\n return;\n }\n\n float curConnection = getTextureData(u_connectionOffsets, index, 256.0).a;\n float numConnections = getTextureData(u_connections, curConnection, 4096.0).a;\n\n float fScale = 1.0 + sqrt(u_iterationMultiplier);\n float springFScale = fScale;\n\n if (numConnections > denseNodeThreshold) {\n springFScale = sqrt(fScale);\n }\n\n float numOfRels = 0.0;\n\n // Springs\n for (float i = 1.0; i <= 256.0 * 256.0; i++) {\n if (numOfRels >= numConnections) {\n break;\n }\n acceleration += getSpringForce(curConnection, numConnections, springFScale, myPosition, i);\n numOfRels += 1.0;\n }\n\n // Repulsion && collision detection\n if (u_collisionMultiplier > 0.0) {\n float number_of_collisions = 0.0;\n for (float i = 0.0; i < 256.0 * 256.0; i++) {\n if (i >= u_numNodes) {\n break;\n }\n\n if (i == index) {\n continue;\n }\n\n vec4 otherPosition = getOtherNodePosition(i);\n vec2 delta = getDelta(myPosition.xy, otherPosition.xy);\n float dist = length(delta);\n float combinedNodeSize = getCombinedNodeSize(i, nodeSize) * 2.0;\n\n if (dist < combinedNodeSize && number_of_collisions < 40.0) {\n number_of_collisions++;\n acceleration += getCollisionForce(combinedNodeSize, dist, fScale, delta);\n }\n\n if (i >= clusterStartIndex && i < clusterStartIndex + clusterSize) {\n acceleration += getRepulsionForce(dist, fScale, delta);\n }\n }\n } else {\n for (float i = 0.0; i < 256.0 * 256.0; i++) {\n if (i >= clusterStartIndex + clusterSize || i >= u_numNodes) {\n break;\n }\n\n if (i < clusterStartIndex || i == index) {\n continue;\n }\n\n vec4 otherPosition = getOtherNodePosition(i);\n vec2 delta = getDelta(myPosition.xy, otherPosition.xy);\n float dist = length(delta);\n float combinedNodeSize = getCombinedNodeSize(i, nodeSize);\n\n if (dist < combinedNodeSize) {\n acceleration += getCollisionForce(combinedNodeSize, dist, fScale, delta);\n }\n\n acceleration += getRepulsionForce(dist, fScale, delta);\n }\n }\n\n // Gravity\n vec2 delta = getDelta(u_gravityCenter, myPosition.xy);\n float dist = length(delta);\n\n vec2 grav = (delta / dist) * u_gravity * fScale
|
|
1
|
+
declare const _default: "precision mediump float;\n\nuniform sampler2D u_physData;\nuniform sampler2D u_connections;\nuniform sampler2D u_connectionOffsets;\nuniform sampler2D u_pinnedNodes;\nuniform sampler2D u_sizeTexture;\nuniform float u_baseLength;\nuniform float u_curIteration;\nuniform float u_iterationMultiplier;\nuniform vec2 u_gravityCenter;\nuniform float u_numNodes;\nuniform float u_gravity;\n\nuniform sampler2D u_clusterData;\nuniform sampler2D u_prevForce;\nuniform float u_collisionMultiplier;\n\n\nfloat DAMP = 0.6;\nfloat COOL = 0.99998;\nfloat TEMP = max(0.02, pow(COOL, u_curIteration));\nfloat TIMESTEP = 1.0 / 30.0;\nfloat VELOCITYDECAY = 0.6;\nfloat accLimitLow = 500000.0;\nfloat accLimitHigh = 750000.0;\nfloat accLimitPosHigh = 10000000.0;\n\nconst float denseNodeThreshold = 1000.0;\nconst float MIN_DISTANCE = 0.00000001;\nconst float MAX_DISTANCE = 1000000000.0;\nconst float MAX_ACCELERATION = 50000.0;\n\nvec4 getTextureData(sampler2D texture, float index, float base) {\n float x = mod(index, base);\n float y = (index - x) / base;\n return texture2D(texture, vec2(x + 0.5, y + 0.5) / base);\n}\n\nbool isNan(float val) {\n return (val < 0.0 || 0.0 < val || val == 0.0) ? false : true;\n}\n\nconst float BIG_NUMBER = 999999999999999999.0;\nbool isInf(float val) {\n return val > BIG_NUMBER || val < -BIG_NUMBER;\n}\n\nvec2 getDelta(vec2 v1, vec2 v2) {\n vec2 delta = v1 - v2;\n float dist = length(delta);\n if (dist < MIN_DISTANCE || isNan(dist)) {\n return vec2(MIN_DISTANCE, MIN_DISTANCE);\n }\n if (dist > MAX_DISTANCE) {\n vec2 normDelta = delta / dist;\n return normDelta * MAX_DISTANCE;\n }\n return delta;\n}\n\nvec4 getOtherNodePosition(float i) {\n return getTextureData(u_physData, i, 256.0);\n}\n\nfloat getCombinedNodeSize(float i, float nodeSize) {\n float otherNodeSize = getTextureData(u_sizeTexture, i, 256.0).a;\n return nodeSize + otherNodeSize;\n}\n\nvec2 getSpringForce(float curConnection, float numConnections, float springFScale, vec4 myPosition, float i) {\n float curSpring = getTextureData(u_connections, curConnection + i, 4096.0).a;\n\n vec4 otherPosition = getTextureData(u_physData, curSpring, 256.0);\n float otherDataPosition = getTextureData(u_connectionOffsets, curSpring, 256.0).a;\n float avgDegree;\n#if INTEL_WORKAROUND\n avgDegree = max(numConnections, 4.0);\n#else\n float otherNumConnections = getTextureData(u_connections, otherDataPosition, 4096.0).a;\n avgDegree = max((otherNumConnections + numConnections * 3.0) / 4.0, 4.0);\n#endif\n\n vec2 delta = getDelta(myPosition.xy, otherPosition.xy);\n float dist = length(delta);\n\n float F = (dist * dist * springFScale) / (u_baseLength * avgDegree);\n if (u_collisionMultiplier > 0.0) {\n F *= u_collisionMultiplier;\n }\n return (-delta / dist) * F;\n}\n\nvec2 getCollisionForce(float combinedNodeSize, float dist, float fScale, vec2 delta) {\n float collisionForce = (combinedNodeSize - dist) / (dist);\n if (u_collisionMultiplier > 0.0) {\n collisionForce *= u_collisionMultiplier;\n }\n return (delta * collisionForce * fScale * combinedNodeSize) / (combinedNodeSize + 1.0);\n}\n\nvec2 getRepulsionForce(float dist, float fScale, vec2 delta) {\n float F = (u_baseLength * u_baseLength * fScale) / (dist);\n return (delta / dist) * F * 0.05;\n}\n\nvoid main(void) {\n float textureSide = 256.0; //#TEXTURE_SIDE#;\n float index = (gl_FragCoord.x - 0.5) + (gl_FragCoord.y - 0.5) * textureSide;\n\n if (index >= u_numNodes) {\n discard;\n }\n\n vec4 clusterData = getTextureData(u_clusterData, index, 256.0);\n\n float clusterIndex = clusterData.x;\n float clusterStartIndex = clusterData.y;\n float clusterSize = clusterData.z;\n float clusterWeight = clusterData.w;\n\n vec4 myPosition = getTextureData(u_physData, index, 256.0);\n vec4 previousForce = getTextureData(u_prevForce, clusterIndex, 256.0);\n\n vec2 acceleration = previousForce.xy;\n\n float isPinned = getTextureData(u_pinnedNodes, index, 256.0).a;\n float nodeSize = getTextureData(u_sizeTexture, index, 256.0).a;\n\n if (isPinned > 0.5) {\n gl_FragColor = vec4(myPosition.xy, 0.0, 0.0);\n return;\n }\n\n float curConnection = getTextureData(u_connectionOffsets, index, 256.0).a;\n float numConnections = getTextureData(u_connections, curConnection, 4096.0).a;\n\n float fScale = 1.0 + sqrt(u_iterationMultiplier);\n float springFScale = fScale;\n\n if (numConnections > denseNodeThreshold) {\n springFScale = sqrt(fScale);\n }\n\n float numOfRels = 0.0;\n\n // Springs\n for (float i = 1.0; i <= 256.0 * 256.0; i++) {\n if (numOfRels >= numConnections) {\n break;\n }\n acceleration += getSpringForce(curConnection, numConnections, springFScale, myPosition, i);\n numOfRels += 1.0;\n }\n\n // Repulsion && collision detection\n if (u_collisionMultiplier > 0.0) {\n float number_of_collisions = 0.0;\n for (float i = 0.0; i < 256.0 * 256.0; i++) {\n if (i >= u_numNodes) {\n break;\n }\n\n if (i == index) {\n continue;\n }\n\n vec4 otherPosition = getOtherNodePosition(i);\n vec2 delta = getDelta(myPosition.xy, otherPosition.xy);\n float dist = length(delta);\n float combinedNodeSize = getCombinedNodeSize(i, nodeSize) * 2.0;\n\n if (dist < combinedNodeSize && number_of_collisions < 40.0) {\n number_of_collisions++;\n acceleration += getCollisionForce(combinedNodeSize, dist, fScale, delta);\n }\n\n if (i >= clusterStartIndex && i < clusterStartIndex + clusterSize) {\n acceleration += getRepulsionForce(dist, fScale, delta);\n }\n }\n } else {\n for (float i = 0.0; i < 256.0 * 256.0; i++) {\n if (i >= clusterStartIndex + clusterSize || i >= u_numNodes) {\n break;\n }\n\n if (i < clusterStartIndex || i == index) {\n continue;\n }\n\n vec4 otherPosition = getOtherNodePosition(i);\n vec2 delta = getDelta(myPosition.xy, otherPosition.xy);\n float dist = length(delta);\n float combinedNodeSize = getCombinedNodeSize(i, nodeSize);\n\n if (dist < combinedNodeSize) {\n acceleration += getCollisionForce(combinedNodeSize, dist, fScale, delta);\n }\n\n acceleration += getRepulsionForce(dist, fScale, delta);\n }\n }\n\n // Gravity\n vec2 delta = getDelta(u_gravityCenter, myPosition.xy);\n float dist = length(delta);\n\n vec2 grav = (delta / dist) * u_gravity * fScale * (dist / 1000.0);\n acceleration += grav;\n\n float accMagnitude = length(acceleration);\n acceleration *= min(MAX_ACCELERATION, accMagnitude) / accMagnitude;\n\n float iterationFrictionThreshold = 1000.0;\n\n if (u_curIteration > iterationFrictionThreshold) {\n float friction = 1.0 + pow((u_curIteration - iterationFrictionThreshold), 2.0) / 100.0;\n acceleration *= 1.0 / friction;\n }\n\n if (u_curIteration == 0.0) {\n gl_FragColor = vec4(myPosition.xy, myPosition.zw);\n } else {\n vec2 prevVelocity = myPosition.zw;\n vec2 currentPos = myPosition.xy;\n vec2 prevPos = currentPos - prevVelocity;\n\n vec2 newPos = currentPos + TEMP * ( DAMP * (prevVelocity) + acceleration * TIMESTEP * TIMESTEP);\n vec2 newVelocity = newPos - currentPos;\n gl_FragColor = vec4(newPos, newVelocity);\n }\n}";
|
|
2
2
|
export default _default;
|
|
@@ -1,43 +1,21 @@
|
|
|
1
|
+
import type { Node, Relationship } from '../../../../types/graph-element';
|
|
2
|
+
import type { CoarsenedGraph, SolarRelationship } from './types';
|
|
1
3
|
export default class SolarMerger {
|
|
2
|
-
constructor(graph: any, nodeIdToIndex: any);
|
|
3
4
|
graph: {
|
|
4
|
-
nodes:
|
|
5
|
-
relationships:
|
|
6
|
-
idToRel:
|
|
7
|
-
};
|
|
8
|
-
subGraphs: any[];
|
|
9
|
-
sunMap: {};
|
|
10
|
-
constructGraphObjects(graph: any, nodeIdToIndex: any): {
|
|
11
|
-
nodes: any[];
|
|
12
|
-
relationships: any[];
|
|
13
|
-
idToRel: {};
|
|
14
|
-
};
|
|
15
|
-
relIdMap: any[];
|
|
16
|
-
coarsenTo(targetSize: any): {
|
|
17
|
-
nodes: any[];
|
|
18
|
-
relationships: any[];
|
|
19
|
-
idToRel: {};
|
|
20
|
-
};
|
|
21
|
-
nodeSortMap: {};
|
|
22
|
-
coarsenBy(levelToCoarsenBy: any): {
|
|
23
|
-
nodes: any[];
|
|
24
|
-
relationships: any[];
|
|
25
|
-
idToRel: {};
|
|
26
|
-
};
|
|
27
|
-
coarsen({ nodes, relationships }: {
|
|
28
|
-
nodes: any;
|
|
29
|
-
relationships: any;
|
|
30
|
-
}, firstIteration: any): {
|
|
31
|
-
output: {
|
|
32
|
-
nodes: {
|
|
33
|
-
id: any;
|
|
34
|
-
}[];
|
|
35
|
-
relationships: any[];
|
|
36
|
-
};
|
|
37
|
-
sortedInput: {
|
|
38
|
-
nodes: any[];
|
|
39
|
-
relationships: any[];
|
|
40
|
-
};
|
|
41
|
-
nodeSortMap: {};
|
|
5
|
+
nodes: Node[];
|
|
6
|
+
relationships: number[][];
|
|
7
|
+
idToRel: Record<string, SolarRelationship>;
|
|
42
8
|
};
|
|
9
|
+
subGraphs: CoarsenedGraph[];
|
|
10
|
+
sunMap: Record<string, string>;
|
|
11
|
+
relIdMap: string[][];
|
|
12
|
+
nodeSortMap?: Record<number, number>;
|
|
13
|
+
constructor(inputGraph: {
|
|
14
|
+
nodes: Node[];
|
|
15
|
+
rels: Relationship[];
|
|
16
|
+
}, nodeIdToIndex: Record<string, number>);
|
|
17
|
+
private constructGraphObjects;
|
|
18
|
+
coarsenTo(targetSize: number): CoarsenedGraph;
|
|
19
|
+
coarsenBy(levelToCoarsenBy: number): CoarsenedGraph;
|
|
20
|
+
private coarsen;
|
|
43
21
|
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { Node } from '../../../../types/graph-element';
|
|
2
|
+
export interface SolarNode extends Omit<Node, 'id' | 'size'> {
|
|
3
|
+
id: number;
|
|
4
|
+
weight?: number;
|
|
5
|
+
finestIndex?: number;
|
|
6
|
+
originalId: string;
|
|
7
|
+
position?: {
|
|
8
|
+
x: number;
|
|
9
|
+
y: number;
|
|
10
|
+
};
|
|
11
|
+
placement?: {
|
|
12
|
+
x: number;
|
|
13
|
+
y: number;
|
|
14
|
+
};
|
|
15
|
+
size?: number | (() => number);
|
|
16
|
+
}
|
|
17
|
+
export interface SolarRelationship {
|
|
18
|
+
id: string;
|
|
19
|
+
from: string;
|
|
20
|
+
to: string;
|
|
21
|
+
}
|
|
22
|
+
export interface CoarsenedGraph {
|
|
23
|
+
nodes: SolarNode[];
|
|
24
|
+
relationships: number[][];
|
|
25
|
+
idToRel: Record<string, SolarRelationship>;
|
|
26
|
+
}
|
|
27
|
+
export interface Sun extends SolarNode {
|
|
28
|
+
planets: Planet[];
|
|
29
|
+
size: () => number;
|
|
30
|
+
children: () => Planet[];
|
|
31
|
+
previousIndex: number;
|
|
32
|
+
}
|
|
33
|
+
export interface Planet extends SolarNode {
|
|
34
|
+
parent: Sun;
|
|
35
|
+
sunId: number;
|
|
36
|
+
moons: Moon[];
|
|
37
|
+
size: () => number;
|
|
38
|
+
children: () => Moon[];
|
|
39
|
+
}
|
|
40
|
+
export interface Moon extends SolarNode {
|
|
41
|
+
parent: Planet;
|
|
42
|
+
sunId: number;
|
|
43
|
+
size: () => number;
|
|
44
|
+
}
|
|
45
|
+
export type Celestial = Sun | Planet | Moon;
|
|
46
|
+
export declare const isSolarNode: (node: SolarNode | Node) => node is SolarNode;
|
|
47
|
+
export declare const isSun: (node: SolarNode | Celestial) => node is Sun;
|
|
48
|
+
export declare const isPlanet: (node: SolarNode | Celestial) => node is Planet;
|
|
49
|
+
export declare const isMoon: (node: SolarNode | Celestial) => node is Moon;
|
|
@@ -27,12 +27,15 @@ export default class NvlController {
|
|
|
27
27
|
private readonly gridLayout;
|
|
28
28
|
private readonly freeLayout;
|
|
29
29
|
private readonly d3ForceLayout;
|
|
30
|
+
private readonly circularLayout;
|
|
30
31
|
private readonly forceLayout;
|
|
31
32
|
private readonly canvasRenderer;
|
|
33
|
+
private readonly svgRenderer;
|
|
32
34
|
private readonly glCanvas;
|
|
33
35
|
private canvasRect;
|
|
34
36
|
private readonly glMinimapCanvas;
|
|
35
37
|
private readonly c2dCanvas;
|
|
38
|
+
private readonly svg;
|
|
36
39
|
private isInRenderSwitchAnimation;
|
|
37
40
|
private justSwitchedRenderer;
|
|
38
41
|
private justSwitchedLayout;
|
|
@@ -104,8 +107,8 @@ export default class NvlController {
|
|
|
104
107
|
isDestroyed(): boolean;
|
|
105
108
|
destroy(): void;
|
|
106
109
|
callIfRegistered(...args: any[]): void;
|
|
107
|
-
getCanvasRelsAt(point: Point): import("
|
|
108
|
-
getCanvasNodesAt(point: Point, hitNodeMarginWidth?: number): import("
|
|
110
|
+
getCanvasRelsAt(point: Point): import("..").HitTargetRelationship[];
|
|
111
|
+
getCanvasNodesAt(point: Point, hitNodeMarginWidth?: number): import("..").HitTargetNode[];
|
|
109
112
|
private getLayout;
|
|
110
113
|
setLayout(layoutType: Layout): void;
|
|
111
114
|
setLayoutOptions(options: LayoutOptions): void;
|
|
@@ -113,6 +116,7 @@ export default class NvlController {
|
|
|
113
116
|
private initiateFileDownload;
|
|
114
117
|
private updateLayoutAndPositions;
|
|
115
118
|
saveToFile(options: SaveToFileOptions): void;
|
|
119
|
+
saveToSvg(options?: SaveToFileOptions): Promise<void>;
|
|
116
120
|
getImageDataURL(options: SaveToFileOptions): string;
|
|
117
121
|
private prepareLargeFileForDownload;
|
|
118
122
|
private createCanvasAndRenderImage;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { LogLevelDesc } from 'loglevel';
|
|
2
|
-
import type { WaypointPath } from '../../renderers/
|
|
2
|
+
import type { WaypointPath } from '../../renderers/domrenderer/shared/types';
|
|
3
|
+
import type { Node } from '../../types/graph-element';
|
|
3
4
|
import type { ExternalCallbacks } from '../ExternalCallbackHandler';
|
|
4
5
|
import type { NodeDataSet, RelationshipDataSet } from '../dataset';
|
|
5
6
|
type RingStyle = {
|
|
@@ -67,6 +68,15 @@ export interface HierarchicalOptions {
|
|
|
67
68
|
packing?: 'bin' | 'stack';
|
|
68
69
|
}
|
|
69
70
|
export declare const isHierarchicalLayoutOptions: (options: LayoutOptions) => options is HierarchicalOptions;
|
|
71
|
+
/**
|
|
72
|
+
* The options for the circular layout.
|
|
73
|
+
*/
|
|
74
|
+
export interface CircularOptions {
|
|
75
|
+
/**
|
|
76
|
+
* Function which should return the sorted nodes.
|
|
77
|
+
*/
|
|
78
|
+
sortFunction?: (nodes: Node[]) => Node[];
|
|
79
|
+
}
|
|
70
80
|
/**
|
|
71
81
|
* NVL's main force directed layout.
|
|
72
82
|
*/
|
|
@@ -87,6 +97,11 @@ export declare const FreeLayoutType = "free";
|
|
|
87
97
|
* The commonly used d3-force layout.
|
|
88
98
|
*/
|
|
89
99
|
export declare const d3ForceLayoutType = "d3Force";
|
|
100
|
+
/**
|
|
101
|
+
* A basic circular layout.
|
|
102
|
+
* @experimental
|
|
103
|
+
*/
|
|
104
|
+
export declare const CircularLayoutType = "circular";
|
|
90
105
|
/**
|
|
91
106
|
* A WebGL renderer that uses the GPU for rendering.
|
|
92
107
|
*
|
|
@@ -103,18 +118,26 @@ export declare const WebGLRendererType = "webgl";
|
|
|
103
118
|
* but supports captions and arrowheads.
|
|
104
119
|
*/
|
|
105
120
|
export declare const CanvasRendererType = "canvas";
|
|
121
|
+
/**
|
|
122
|
+
* A renderer using SVG.
|
|
123
|
+
*
|
|
124
|
+
* @experimental
|
|
125
|
+
* @remarks
|
|
126
|
+
* This renderer is experimental.
|
|
127
|
+
*/
|
|
128
|
+
export declare const SvgRendererType = "svg";
|
|
106
129
|
/**
|
|
107
130
|
* The different types of layouts available
|
|
108
131
|
*/
|
|
109
|
-
export type Layout = typeof ForceDirectedLayoutType | typeof HierarchicalLayoutType | typeof GridLayoutType | typeof FreeLayoutType | typeof d3ForceLayoutType;
|
|
132
|
+
export type Layout = typeof ForceDirectedLayoutType | typeof HierarchicalLayoutType | typeof GridLayoutType | typeof FreeLayoutType | typeof d3ForceLayoutType | typeof CircularLayoutType;
|
|
110
133
|
/**
|
|
111
134
|
* The options for the layout.
|
|
112
135
|
*/
|
|
113
|
-
export type LayoutOptions = ForceDirectedOptions | HierarchicalOptions;
|
|
136
|
+
export type LayoutOptions = ForceDirectedOptions | HierarchicalOptions | CircularOptions;
|
|
114
137
|
/**
|
|
115
138
|
* The different types of renderers available
|
|
116
139
|
*/
|
|
117
|
-
export type Renderer = typeof WebGLRendererType | typeof CanvasRendererType;
|
|
140
|
+
export type Renderer = typeof WebGLRendererType | typeof CanvasRendererType | typeof SvgRendererType;
|
|
118
141
|
/** Configurations for a NVL instance */
|
|
119
142
|
export interface NvlOptions {
|
|
120
143
|
/**
|
|
@@ -149,7 +172,7 @@ export interface NvlOptions {
|
|
|
149
172
|
* @remarks When using a React ref, make sure the attached element is rendered before the NVL instance is created.
|
|
150
173
|
* Otherwise, the minimap will not be displayed.
|
|
151
174
|
*/
|
|
152
|
-
minimapContainer?: HTMLElement;
|
|
175
|
+
minimapContainer?: HTMLElement | null;
|
|
153
176
|
/** Configuration for the current layout */
|
|
154
177
|
layoutOptions?: LayoutOptions;
|
|
155
178
|
/** X-coordinate for panning of the current viewport */
|
|
@@ -160,10 +183,9 @@ export interface NvlOptions {
|
|
|
160
183
|
initialZoom?: number;
|
|
161
184
|
/**
|
|
162
185
|
* What renderer to use
|
|
163
|
-
*
|
|
164
|
-
* @defaultValue 'webgl'
|
|
186
|
+
* @defaultValue 'canvas'
|
|
165
187
|
* WebGL renderer uses GPU and has better performance.
|
|
166
|
-
* Captions and arrowheads are only displayed when using the canvas renderer.
|
|
188
|
+
* Captions and arrowheads are only displayed when using the canvas or svg renderer.
|
|
167
189
|
*/
|
|
168
190
|
renderer?: Renderer;
|
|
169
191
|
/**
|
|
@@ -258,7 +280,6 @@ export interface NvlState {
|
|
|
258
280
|
fitNodeIds: string[];
|
|
259
281
|
resetZoom: boolean;
|
|
260
282
|
forceWebGL: boolean;
|
|
261
|
-
webGLVisible: boolean;
|
|
262
283
|
renderer: Renderer;
|
|
263
284
|
disableWebGL: boolean;
|
|
264
285
|
disableWebWorkers: boolean;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { StyledCaption } from '../../renderers/
|
|
1
|
+
import type { StyledCaption } from '../../renderers/domrenderer/shared/types';
|
|
2
2
|
import type { Node, Relationship } from '../../types/graph-element';
|
|
3
3
|
import type { NvlOptions } from './types';
|
|
4
4
|
/**
|
|
@@ -6,7 +6,7 @@ import type { NvlOptions } from './types';
|
|
|
6
6
|
* If both caption and captions are provided, captions takes precedence.
|
|
7
7
|
*/
|
|
8
8
|
export declare const processCaptions: (item: Partial<Node | Relationship>) => StyledCaption[];
|
|
9
|
-
export declare const processColorStyles: (styling: NvlOptions[
|
|
9
|
+
export declare const processColorStyles: (styling: NvlOptions["styling"]) => {
|
|
10
10
|
nodeBorderStyles: {
|
|
11
11
|
default: {
|
|
12
12
|
rings?: {
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import type { Channel, DataSet } from '../../modules/dataset';
|
|
2
|
+
import type { NvlState } from '../../modules/state/types';
|
|
3
|
+
import type { Node } from '../../types/graph-element';
|
|
4
|
+
import ImageCache from './shared/ImageCache';
|
|
5
|
+
import ArrowBundler from './shared/arrows/ArrowBundler';
|
|
6
|
+
import type { RelationshipToRender } from './shared/types';
|
|
7
|
+
export type RendererOptions = {
|
|
8
|
+
relationshipThreshold?: number;
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* Base class for renderers (Canvas and SVG) that provides common functionality
|
|
12
|
+
*/
|
|
13
|
+
export default abstract class BaseRenderer {
|
|
14
|
+
arrowBundler: ArrowBundler;
|
|
15
|
+
protected state: NvlState;
|
|
16
|
+
protected relationshipThreshold: number;
|
|
17
|
+
protected stateDisposers: NvlState['reaction'][];
|
|
18
|
+
protected needsRun: boolean;
|
|
19
|
+
protected imageCache: ImageCache;
|
|
20
|
+
protected nodeVersion: number;
|
|
21
|
+
protected relVersion: number;
|
|
22
|
+
protected waypointVersion: number;
|
|
23
|
+
protected channelId: string;
|
|
24
|
+
protected activeNodes: Set<string>;
|
|
25
|
+
constructor(state: NvlState, channelId: string, options?: RendererOptions);
|
|
26
|
+
/**
|
|
27
|
+
* Gets relationships to render, sorted by their rendering order
|
|
28
|
+
* @param showCaptions - Whether to show relationship captions
|
|
29
|
+
* @param zoom - Current zoom level (optional, used for threshold checking)
|
|
30
|
+
* @param clientWidth - Width of the rendering area
|
|
31
|
+
* @param clientHeight - Height of the rendering area
|
|
32
|
+
* @returns Array of relationships to render, sorted (disabled, normal, selected)
|
|
33
|
+
*/
|
|
34
|
+
protected getRelationshipsToRender(showCaptions: boolean, zoom?: number, clientWidth?: number, clientHeight?: number): RelationshipToRender[];
|
|
35
|
+
/**
|
|
36
|
+
* Gets nodes to render, sorted by their rendering order
|
|
37
|
+
* @param positionArray - Array of nodes with positions
|
|
38
|
+
* @param clientWidth - Width of the rendering area
|
|
39
|
+
* @param clientHeight - Height of the rendering area
|
|
40
|
+
* @returns Array of nodes to render, sorted (disabled, normal, selected)
|
|
41
|
+
*/
|
|
42
|
+
protected getNodesToRender(positionArray: Node[], clientWidth?: number, clientHeight?: number): Node[];
|
|
43
|
+
/**
|
|
44
|
+
* Processes updates in nodes and relationships.
|
|
45
|
+
*/
|
|
46
|
+
processUpdates(): void;
|
|
47
|
+
/**
|
|
48
|
+
* Processes node channel updates to track activated nodes.
|
|
49
|
+
* Adds or removes node IDs from the activeNodes set based on their activated state.
|
|
50
|
+
* @param channel - The node channel with adds, removes, and updates
|
|
51
|
+
* @param fullData - The full node dataset
|
|
52
|
+
*/
|
|
53
|
+
protected processNodeChannelUpdates(channel: Channel<Node>, fullData: DataSet<Node>): void;
|
|
54
|
+
/**
|
|
55
|
+
* Checks if a bounding box is off screen
|
|
56
|
+
* @param boundingBox - The bounding box to check
|
|
57
|
+
* @param clientWidth - Width of the rendering area
|
|
58
|
+
* @param clientHeight - Height of the rendering area
|
|
59
|
+
* @returns Whether the bounding box is off screen
|
|
60
|
+
*/
|
|
61
|
+
protected isBoundingBoxOffScreen(boundingBox: DOMRect, clientWidth: number, clientHeight: number): boolean;
|
|
62
|
+
/**
|
|
63
|
+
* Checks if the renderer needs to run.
|
|
64
|
+
* @returns Whether the renderer needs to run.
|
|
65
|
+
*/
|
|
66
|
+
needsToRun(): boolean;
|
|
67
|
+
/**
|
|
68
|
+
* Returns a promise that resolves when all images in the cache have finished loading.
|
|
69
|
+
*/
|
|
70
|
+
waitForImages(): Promise<void>;
|
|
71
|
+
/**
|
|
72
|
+
* Cleans up the renderer by disposing state reactions and removing channels.
|
|
73
|
+
*/
|
|
74
|
+
destroy(): void;
|
|
75
|
+
}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import type { NvlState } from '../../../modules/state/types';
|
|
2
|
+
import type { Node } from '../../../types/graph-element';
|
|
3
|
+
import type { Point } from '../../../utils/geometry';
|
|
4
|
+
import type { HitTargetNode, HitTargetRelationship } from '../../../utils/hittest';
|
|
5
|
+
import BaseRenderer, { RendererOptions } from '../BaseRenderer';
|
|
6
|
+
export default class CanvasRenderer extends BaseRenderer {
|
|
7
|
+
private canvas;
|
|
8
|
+
private context;
|
|
9
|
+
private animationHandler;
|
|
10
|
+
private ellipsisWidth;
|
|
11
|
+
private disableArrowShadow;
|
|
12
|
+
/**
|
|
13
|
+
* Creates a new CanvasRenderer.
|
|
14
|
+
* @param canvas {HTMLCanvasElement} - The canvas to render on.
|
|
15
|
+
* @param context {CanvasRenderingContext2D} - The canvas context.
|
|
16
|
+
* @param state {NvlState} - The state.
|
|
17
|
+
* @param options {RendererOptions} - The visualization options.
|
|
18
|
+
*/
|
|
19
|
+
constructor(canvas: HTMLCanvasElement, context: CanvasRenderingContext2D | null, state: NvlState, options?: RendererOptions);
|
|
20
|
+
/**
|
|
21
|
+
* Checks if the renderer needs to run.
|
|
22
|
+
* @returns Whether the renderer needs to run.
|
|
23
|
+
*/
|
|
24
|
+
needsToRun(): boolean;
|
|
25
|
+
/**
|
|
26
|
+
* Override processUpdates to add Canvas-specific shadow handling
|
|
27
|
+
*/
|
|
28
|
+
processUpdates(): void;
|
|
29
|
+
/**
|
|
30
|
+
* Draws a single node on the canvas with all its visual elements (circle, icons, captions, etc.)
|
|
31
|
+
* @param ctx - The canvas rendering context
|
|
32
|
+
* @param node - The node to draw
|
|
33
|
+
* @param imageCache - The image cache for icons
|
|
34
|
+
* @param animationHandler - The animation handler for transitions
|
|
35
|
+
* @param nodeBorderStyles - The border styles for nodes
|
|
36
|
+
* @param disabledItemStyles - The styles for disabled items
|
|
37
|
+
* @param defaultNodeColor - The default node color
|
|
38
|
+
* @param ellipsisWidth - The width of the ellipsis character
|
|
39
|
+
* @param zoomLevel - The current zoom level
|
|
40
|
+
*/
|
|
41
|
+
private drawNode;
|
|
42
|
+
/**
|
|
43
|
+
* Helper method to enable shadow on canvas context
|
|
44
|
+
*/
|
|
45
|
+
private enableShadow;
|
|
46
|
+
/**
|
|
47
|
+
* Helper method to disable shadow on canvas context
|
|
48
|
+
*/
|
|
49
|
+
private disableShadow;
|
|
50
|
+
/**
|
|
51
|
+
* Draws line segments on canvas (straight or curved)
|
|
52
|
+
*/
|
|
53
|
+
private drawSegments;
|
|
54
|
+
/**
|
|
55
|
+
* Draws a self-referencing loop on canvas
|
|
56
|
+
*/
|
|
57
|
+
private drawLoop;
|
|
58
|
+
/**
|
|
59
|
+
* Draws a label for a relationship
|
|
60
|
+
*/
|
|
61
|
+
private drawLabel;
|
|
62
|
+
/**
|
|
63
|
+
* Renders a waypoint arrow (relationship between two different nodes)
|
|
64
|
+
*/
|
|
65
|
+
private renderWaypointArrow;
|
|
66
|
+
/**
|
|
67
|
+
* Renders a self-referencing arrow (relationship from node to itself)
|
|
68
|
+
*/
|
|
69
|
+
private renderSelfArrow;
|
|
70
|
+
/**
|
|
71
|
+
* Main arrow rendering method that delegates to waypoint or self-arrow rendering
|
|
72
|
+
*/
|
|
73
|
+
private renderArrow;
|
|
74
|
+
/**
|
|
75
|
+
* Draws the nodes and relationships to their positions on the canvas.
|
|
76
|
+
* @param positionArray {Node[]} - The array of nodes to draw
|
|
77
|
+
* @param options {any} - The options for the render
|
|
78
|
+
*/
|
|
79
|
+
render(positionArray: Node[], options?: {
|
|
80
|
+
canvas?: HTMLCanvasElement;
|
|
81
|
+
context?: CanvasRenderingContext2D;
|
|
82
|
+
backgroundColor?: string;
|
|
83
|
+
ignoreAnimations?: boolean;
|
|
84
|
+
showCaptions?: boolean;
|
|
85
|
+
}): void;
|
|
86
|
+
private renderNodes;
|
|
87
|
+
private renderRelationships;
|
|
88
|
+
/**
|
|
89
|
+
* Returns the nodes at the pointer position
|
|
90
|
+
* @param pointer - The position of the pointer.
|
|
91
|
+
* @returns The nodes at the pointer position.
|
|
92
|
+
* @todo Sort nodes by distance descending
|
|
93
|
+
*/
|
|
94
|
+
getNodesAt(pointer: Point, hitNodeMarginWidth?: number): HitTargetNode[];
|
|
95
|
+
/**
|
|
96
|
+
* Returns the relationships at the pointer position
|
|
97
|
+
* @param pointer - The position of the pointer.
|
|
98
|
+
* @returns The relationships at the pointer position.
|
|
99
|
+
* @todo: sort relationships by distance descending
|
|
100
|
+
*/
|
|
101
|
+
getRelsAt(pointer: Point): HitTargetRelationship[];
|
|
102
|
+
/**
|
|
103
|
+
* Returns an array of styles for the rings of a node.
|
|
104
|
+
* It takes the node as an argument, and an optional array of size animations.
|
|
105
|
+
* If the node is selected, it returns the selectedStyle.rings array.
|
|
106
|
+
* If the node is not selected, it returns an array containing only one object with
|
|
107
|
+
* a width of 0 and an empty color.
|
|
108
|
+
* @param node - The node to get the ring styles for.
|
|
109
|
+
* @param animationHandler - The animation handler.
|
|
110
|
+
* @param nodeBorderStyles - The node border styles.
|
|
111
|
+
* @returns An array of ring styles.
|
|
112
|
+
*/
|
|
113
|
+
private getRingStyles;
|
|
114
|
+
/**
|
|
115
|
+
* Handles zoom and pan on the canvas.
|
|
116
|
+
* @param context {CanvasRenderingContext2D} - The canvas context
|
|
117
|
+
* @param canvas {HTMLCanvasElement} - The canvas
|
|
118
|
+
*/
|
|
119
|
+
private zoomAndPan;
|
|
120
|
+
}
|
|
@@ -1,11 +1,5 @@
|
|
|
1
|
-
import type { Point } from '
|
|
2
|
-
import type { TextSegment } from '
|
|
3
|
-
export declare const fontThresholds: [number, number][];
|
|
4
|
-
/**
|
|
5
|
-
* This function takes color in hex format or rgb() or rgba() format and overrides the opacity. Returns rgba() string.
|
|
6
|
-
* @param color - * @param opacity - * @returns rgba() string with the given opacity.
|
|
7
|
-
*/
|
|
8
|
-
export declare const overrideOpacity: (color: string, opacity: number) => string;
|
|
1
|
+
import type { Point } from '../../../utils/geometry';
|
|
2
|
+
import type { TextSegment } from '../shared/types';
|
|
9
3
|
/**
|
|
10
4
|
* The parameters for drawing an arrowhead.
|
|
11
5
|
*/
|
|
@@ -40,7 +34,6 @@ export declare const drawCircleBand: (ctx: CanvasRenderingContext2D, x: number,
|
|
|
40
34
|
width: number;
|
|
41
35
|
color: string;
|
|
42
36
|
}[]) => void;
|
|
43
|
-
export declare const drawCircle: (ctx: CanvasRenderingContext2D, x: number, y: number, r: number) => void;
|
|
44
37
|
/**
|
|
45
38
|
* Fill a circle band with a gradient from a certain color to transparent
|
|
46
39
|
* @param ctx - The canvas context.
|
|
@@ -56,11 +49,6 @@ export declare const drawGradientCircleBand: (ctx: CanvasRenderingContext2D, x:
|
|
|
56
49
|
* Draw a circle shape with a solid color
|
|
57
50
|
*/
|
|
58
51
|
export declare const drawSolidCircle: (ctx: CanvasRenderingContext2D, x: number, y: number, color: string, size: number) => void;
|
|
59
|
-
export declare function getIndividualInfoLevels(r: number, zoomLevel: number): {
|
|
60
|
-
nodeInfoLevel: number;
|
|
61
|
-
fontInfoLevel: number;
|
|
62
|
-
iconInfoLevel: number;
|
|
63
|
-
};
|
|
64
52
|
/**
|
|
65
53
|
* Prints the caption for a node
|
|
66
54
|
*/
|