@neo4j-nvl/base 1.1.0 → 1.2.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.
Files changed (43) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/dist/base.mjs +1 -1
  3. package/dist/types/index.d.ts +20 -1
  4. package/dist/types/layouts/d3forcelayout/__mocks__/d3ForceLayout.d.ts +10 -0
  5. package/dist/types/layouts/d3forcelayout/d3ForceLayout.d.ts +20 -20
  6. package/dist/types/layouts/d3forcelayout/d3ForceLayout.test.d.ts +1 -0
  7. package/dist/types/layouts/d3forcelayout/types.d.ts +5 -6
  8. package/dist/types/layouts/forcedirectedlayout/physlayout/PhysLayout.d.ts +0 -1
  9. package/dist/types/layouts/forcedirectedlayout/physlayout/shaders/multilevel-fragment.d.ts +1 -1
  10. package/dist/types/layouts/forcedirectedlayout/physlayout/shaders/multilevel-repulsive-fragment.d.ts +1 -1
  11. package/dist/types/layouts/forcedirectedlayout/physlayout/solarmerger/SolarMerger.bench.d.ts +1 -0
  12. package/dist/types/layouts/gridLayout/GridLayout.d.ts +25 -9
  13. package/dist/types/modules/NvlController.d.ts +17 -3
  14. package/dist/types/modules/NvlController.test.d.ts +1 -0
  15. package/dist/types/modules/state/types.d.ts +2 -6
  16. package/dist/types/renderers/domrenderer/BaseRenderer.d.ts +1 -1
  17. package/dist/types/renderers/domrenderer/BaseRenderer.test.d.ts +1 -0
  18. package/dist/types/renderers/domrenderer/canvasrenderer/CanvasRenderer.d.ts +2 -36
  19. package/dist/types/renderers/domrenderer/canvasrenderer/arrowDrawing.d.ts +168 -0
  20. package/dist/types/renderers/domrenderer/canvasrenderer/arrowDrawing.test.d.ts +1 -0
  21. package/dist/types/renderers/domrenderer/canvasrenderer/nodeDrawing.d.ts +109 -0
  22. package/dist/types/renderers/domrenderer/canvasrenderer/nodeDrawing.test.d.ts +1 -0
  23. package/dist/types/renderers/domrenderer/shared/ImageCache.d.ts +3 -2
  24. package/dist/types/renderers/domrenderer/shared/arrows/ArrowBundle.d.ts +18 -2
  25. package/dist/types/renderers/domrenderer/shared/arrows/ArrowBundler.d.ts +10 -0
  26. package/dist/types/renderers/domrenderer/shared/nodes/nodes.d.ts +53 -1
  27. package/dist/types/renderers/domrenderer/shared/util.d.ts +6 -1
  28. package/dist/types/renderers/domrenderer/shared/wordwrap.d.ts +12 -1
  29. package/dist/types/renderers/domrenderer/svgrenderer/SvgRenderer.d.ts +1 -3
  30. package/dist/types/renderers/domrenderer/svgrenderer/arrowDrawing.d.ts +59 -0
  31. package/dist/types/renderers/domrenderer/svgrenderer/arrowDrawing.test.d.ts +1 -0
  32. package/dist/types/renderers/domrenderer/svgrenderer/nodeDrawing.d.ts +16 -0
  33. package/dist/types/renderers/domrenderer/svgrenderer/nodeDrawing.test.d.ts +1 -0
  34. package/dist/types/renderers/domrenderer/svgrenderer/svgUtils.d.ts +33 -141
  35. package/dist/types/renderers/domrenderer/svgrenderer/svgUtils.test.d.ts +1 -0
  36. package/dist/types/utils/constants.d.ts +3 -2
  37. package/dist/types/utils/geometry.d.ts +4 -0
  38. package/dist/types/utils/segmentAnalytics.d.ts +2 -2
  39. package/package.json +6 -5
  40. package/dist/types/layouts/forcedirectedlayout/physlayout/shaders/multilevel-fragment-verlet.d.ts +0 -2
  41. package/dist/types/layouts/forcedirectedlayout/physlayout/shaders/multilevel-repulsive-fragment-verlet.d.ts +0 -2
  42. package/dist/types/renderers/domrenderer/canvasrenderer/canvasUtils.d.ts +0 -56
  43. package/dist/types/renderers/domrenderer/shared/nodes/nodeUtils.d.ts +0 -29
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@neo4j-nvl/base",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "license": "SEE LICENSE IN 'LICENSE.txt'",
5
5
  "homepage": "https://neo4j.com/docs/nvl/current/",
6
6
  "description": "Base library for the Neo4j Visualization Library",
@@ -23,25 +23,26 @@
23
23
  "build:dev": "yarn global:tsc && webpack --mode development",
24
24
  "watch": "concurrently 'tsc -w' 'webpack -w --mode development' -k -n 'tsc,webpack' -c 'cyan,magenta'",
25
25
  "test": "yarn global:jest",
26
+ "test:perf": "yarn global:jest --testPathPattern='.bench.' --testPathIgnorePatterns=",
26
27
  "eslint": "yarn global:eslint ./src/",
27
28
  "coverage": "yarn test --coverage --silent",
28
29
  "prepack": "cp ../../LICENSE.txt ./ && cp ../../CHANGELOG.md ./",
29
30
  "postpack": "rm LICENSE.txt && rm CHANGELOG.md"
30
31
  },
31
32
  "dependencies": {
32
- "@neo4j-nvl/layout-workers": "1.1.0",
33
+ "@neo4j-nvl/layout-workers": "1.2.0",
33
34
  "@segment/analytics-next": "1.81.1",
34
35
  "color-string": "1.9.1",
35
36
  "d3-force": "3.0.0",
36
37
  "gl-matrix": "3.4.4",
37
38
  "glsl-inject-defines": "1.0.3",
38
- "lodash": "4.17.23",
39
+ "lodash": "4.18.1",
39
40
  "loglevel": "1.9.2",
40
41
  "mobx": "3.6.2",
41
42
  "node-pid-controller": "1.0.1",
42
43
  "resizelistener": "1.1.0",
43
44
  "tinycolor2": "1.6.0",
44
- "uuid": "8.3.2"
45
+ "uuid": "14.0.0"
45
46
  },
46
47
  "devDependencies": {
47
48
  "@babel/core": "7.28.5",
@@ -53,7 +54,7 @@
53
54
  "babel-loader": "8.4.1",
54
55
  "copy-webpack-plugin": "11.0.0",
55
56
  "neo4j-driver": "5.28.2",
56
- "webpack": "5.103.0",
57
+ "webpack": "5.104.1",
57
58
  "webpack-cli": "5.1.4"
58
59
  },
59
60
  "peerDependencies": {
@@ -1,2 +0,0 @@
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
- export default _default;
@@ -1,2 +0,0 @@
1
- declare const _default: "precision mediump float;\nuniform sampler2D u_physData;\nuniform sampler2D u_clusterData;\nuniform sampler2D u_finestIndexes;\nuniform sampler2D u_prevForce;\n\nuniform float u_baseLength;\nuniform float u_numNodes;\nuniform float u_iterationMultiplier;\nuniform float u_isTopLevel;\n\nfloat PI = 3.1415926535897932384626433832795;\nfloat TIMESTEP = 1.0 / 30.0;\nfloat VELOCITYDECAY = 1.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\nfloat getSquaredLogClusterWeight(float value) {\n return pow(log(value), 2.0);\n}\n\nvoid main(void) {\n float index = (gl_FragCoord.x - 0.5) + (gl_FragCoord.y - 0.5) * 256.0;\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 clusterArea = pow(clusterSize + u_baseLength * 2.0, 2.0);\n\n float finestIndex = getTextureData(u_finestIndexes, index, 256.0).a;\n vec4 myPosition = getTextureData(u_physData, finestIndex, 256.0);\n vec4 previousForce = getTextureData(u_prevForce, clusterIndex, 256.0);\n float fScale = 1.0 + sqrt(u_iterationMultiplier);\n\n vec2 acceleration = previousForce.xy;\n\n // Repulsion & Collision Detection\n for (float i = 0.0; i < 256.0 * 256.0; i++) {\n if (i >= clusterStartIndex + clusterSize || i >= u_numNodes) {\n break;\n }\n if (i < clusterStartIndex || i == index) {\n continue;\n }\n\n vec4 otherClusterData = getTextureData(u_clusterData, i, 256.0);\n float otherClusterWeight = getSquaredLogClusterWeight(otherClusterData.w);\n\n float otherFinestIndex = getTextureData(u_finestIndexes, i, 256.0).a;\n vec4 otherPosition = getTextureData(u_physData, otherFinestIndex, 256.0);\n\n vec2 delta = myPosition.xy - otherPosition.xy;\n float dist = max(length(delta), 0.0000001);\n float maxDist = 25.0;\n float repulsionForceScale = 0.1;\n\n float F = (clusterArea * fScale) / (dist * dist);\n\n if (u_isTopLevel == 1.0) {\n repulsionForceScale = 0.2;\n }\n\n acceleration += ((delta / sqrt(dist)) * F) * repulsionForceScale * otherClusterWeight;\n\n if (dist < maxDist) {\n float collide = (maxDist - dist) / (dist * dist);\n acceleration += delta * collide * fScale * maxDist / (maxDist + 1.0);\n }\n }\n\n gl_FragColor = vec4(acceleration, vec2(finestIndex, 0));\n}";
2
- export default _default;
@@ -1,56 +0,0 @@
1
- import type { Point } from '../../../utils/geometry';
2
- import type { TextSegment } from '../shared/types';
3
- /**
4
- * The parameters for drawing an arrowhead.
5
- */
6
- type ArrowHeadParameters = {
7
- headPosition: Point;
8
- headAngle: number;
9
- headHeight: number;
10
- headChinHeight: number;
11
- headWidth: number;
12
- };
13
- /**
14
- * Creates an arrowhead shape using a polygon.
15
- * @param ctx - The canvas context to draw on.
16
- * @param headLineWidth - The width of the arrowhead's outline.
17
- * @param color - The color of the arrowhead.
18
- * @param arrowHeadParameters - The parameters for the arrowhead.
19
- * @param fill - Whether or not to fill the triangle.
20
- * @param stroke - Whether or not to stroke the triangle.
21
- */
22
- export declare const drawArrowHead: (ctx: CanvasRenderingContext2D, headLineWidth: number, color: string, arrowHeadParameters: ArrowHeadParameters, fill?: boolean, stroke?: boolean) => void;
23
- /**
24
- * Draws borders around a node with a given array of border styles
25
- * @param ctx - The canvas context.
26
- * @param x - The x coordinate of the node.
27
- * @param y - The y coordinate of the node.
28
- * @param innerRadius - The inner radius of the node without any border.
29
- * @param borderStyles - An array of border styles.
30
- * @internal
31
- * @hidden
32
- */
33
- export declare const drawCircleBand: (ctx: CanvasRenderingContext2D, x: number, y: number, innerRadius: number, borderStyles: {
34
- width: number;
35
- color: string;
36
- }[]) => void;
37
- /**
38
- * Fill a circle band with a gradient from a certain color to transparent
39
- * @param ctx - The canvas context.
40
- * @param x - The x coordinate of the node.
41
- * @param y - The y coordinate of the node.
42
- * @param color - The color of the gradient.
43
- * @param radius - The inner radius of the node without any border.
44
- * @param blur - The blur radius of the gradient.
45
- * @param maxOpacity - The maximum opacity of the gradient.
46
- */
47
- export declare const drawGradientCircleBand: (ctx: CanvasRenderingContext2D, x: number, y: number, color: string, radius: number, blur: number, maxOpacity?: number) => void;
48
- /**
49
- * Draw a circle shape with a solid color
50
- */
51
- export declare const drawSolidCircle: (ctx: CanvasRenderingContext2D, x: number, y: number, color: string, size: number) => void;
52
- /**
53
- * Prints the caption for a node
54
- */
55
- export declare const drawNodeCaption: (ctx: CanvasRenderingContext2D, lines: TextSegment[], stylesPerChar: string[][], initialYPos: number, fontSize: number, fontFace: string, lineDistance: number, x: number, y: number, ellipsisWidth: number) => void;
56
- export {};
@@ -1,29 +0,0 @@
1
- import type { Node } from '../../../../types/graph-element';
2
- import type { TextSegment } from '../types';
3
- /**
4
- * Returns the caption font size that should be used
5
- * for the given info level and node diameter.
6
- * @param infoLevel {number} - The info level.
7
- * @param nodeRadius {number} - The radius of the node.
8
- * @param captionSize {number} - The size of the caption.
9
- * @returns {number} - The font size.
10
- */
11
- export declare const infoLevelToFontSize: (infoLevel: number, nodeRadius?: number, captionSize?: number, hasIcon?: boolean) => number;
12
- /**
13
- * Prepares node caption data for rendering (works for both Canvas and SVG)
14
- * @param node - The node to prepare caption data for
15
- * @param zoomLevel - Current zoom level
16
- * @param ctx - Canvas context for text measurement (optional for SVG, will create one if not provided)
17
- * @returns Caption rendering data including lines, styles, positioning, and font info
18
- */
19
- export declare function prepareNodeCaptionData(node: Node, zoomLevel: number, ctx?: CanvasRenderingContext2D): {
20
- lines: TextSegment[];
21
- stylesPerChar: string[][];
22
- fullCaption: string;
23
- fontSize: number;
24
- fontFace: string;
25
- fontColor: string;
26
- yPos: number;
27
- maxNoLines: number;
28
- hasContent: boolean;
29
- };