@cosmos.gl/graph 2.4.0 → 2.6.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 (49) hide show
  1. package/.github/SECURITY.md +7 -1
  2. package/dist/config.d.ts +73 -1
  3. package/dist/index.d.ts +34 -6
  4. package/dist/index.js +4087 -3837
  5. package/dist/index.js.map +1 -1
  6. package/dist/index.min.js +124 -44
  7. package/dist/index.min.js.map +1 -1
  8. package/dist/modules/GraphData/index.d.ts +1 -0
  9. package/dist/modules/Lines/index.d.ts +8 -0
  10. package/dist/modules/Points/index.d.ts +3 -0
  11. package/dist/modules/Store/index.d.ts +14 -2
  12. package/dist/modules/core-module.d.ts +1 -0
  13. package/dist/stories/beginners/link-hovering/data-generator.d.ts +19 -0
  14. package/dist/stories/beginners/link-hovering/index.d.ts +5 -0
  15. package/dist/stories/beginners/pinned-points/data-gen.d.ts +5 -0
  16. package/dist/stories/beginners/pinned-points/index.d.ts +5 -0
  17. package/dist/stories/beginners.stories.d.ts +2 -0
  18. package/dist/variables.d.ts +5 -2
  19. package/package.json +1 -1
  20. package/src/config.ts +95 -3
  21. package/src/index.ts +179 -32
  22. package/src/modules/GraphData/index.ts +2 -1
  23. package/src/modules/Lines/draw-curve-line.frag +12 -1
  24. package/src/modules/Lines/draw-curve-line.vert +29 -2
  25. package/src/modules/Lines/hovered-line-index.frag +27 -0
  26. package/src/modules/Lines/hovered-line-index.vert +8 -0
  27. package/src/modules/Lines/index.ts +112 -2
  28. package/src/modules/Points/index.ts +34 -0
  29. package/src/modules/Points/update-position.frag +12 -0
  30. package/src/modules/Store/index.ts +33 -2
  31. package/src/modules/core-module.ts +1 -0
  32. package/src/stories/1. welcome.mdx +11 -4
  33. package/src/stories/2. configuration.mdx +13 -3
  34. package/src/stories/3. api-reference.mdx +13 -4
  35. package/src/stories/beginners/basic-set-up/index.ts +21 -11
  36. package/src/stories/beginners/link-hovering/data-generator.ts +198 -0
  37. package/src/stories/beginners/link-hovering/index.ts +61 -0
  38. package/src/stories/beginners/link-hovering/style.css +73 -0
  39. package/src/stories/beginners/pinned-points/data-gen.ts +153 -0
  40. package/src/stories/beginners/pinned-points/index.ts +61 -0
  41. package/src/stories/beginners/quick-start.ts +3 -2
  42. package/src/stories/beginners/remove-points/config.ts +1 -1
  43. package/src/stories/beginners/remove-points/index.ts +28 -30
  44. package/src/stories/beginners.stories.ts +31 -0
  45. package/src/stories/clusters/polygon-selection/index.ts +2 -4
  46. package/src/stories/create-cosmos.ts +1 -1
  47. package/src/stories/geospatial/moscow-metro-stations/index.ts +1 -1
  48. package/src/stories/shapes/image-example/index.ts +7 -8
  49. package/src/variables.ts +5 -2
@@ -2,21 +2,44 @@ import regl from 'regl'
2
2
  import { CoreModule } from '@/graph/modules/core-module'
3
3
  import drawLineFrag from '@/graph/modules/Lines/draw-curve-line.frag'
4
4
  import drawLineVert from '@/graph/modules/Lines/draw-curve-line.vert'
5
+ import hoveredLineIndexFrag from '@/graph/modules/Lines/hovered-line-index.frag'
6
+ import hoveredLineIndexVert from '@/graph/modules/Lines/hovered-line-index.vert'
5
7
  import { defaultConfigValues } from '@/graph/variables'
6
8
  import { getCurveLineGeometry } from '@/graph/modules/Lines/geometry'
7
9
 
8
10
  export class Lines extends CoreModule {
11
+ public linkIndexFbo: regl.Framebuffer2D | undefined
12
+ public hoveredLineIndexFbo: regl.Framebuffer2D | undefined
9
13
  private drawCurveCommand: regl.DrawCommand | undefined
14
+ private hoveredLineIndexCommand: regl.DrawCommand | undefined
10
15
  private pointsBuffer: regl.Buffer | undefined
11
16
  private colorBuffer: regl.Buffer | undefined
12
17
  private widthBuffer: regl.Buffer | undefined
13
18
  private arrowBuffer: regl.Buffer | undefined
14
19
  private curveLineGeometry: number[][] | undefined
15
20
  private curveLineBuffer: regl.Buffer | undefined
21
+ private linkIndexBuffer: regl.Buffer | undefined
22
+ private quadBuffer: regl.Buffer | undefined
16
23
 
17
24
  public initPrograms (): void {
18
25
  const { reglInstance, config, store } = this
19
26
 
27
+ this.updateLinkIndexFbo()
28
+
29
+ // Initialize the hovered line index FBO
30
+ if (!this.hoveredLineIndexFbo) {
31
+ this.hoveredLineIndexFbo = reglInstance.framebuffer({
32
+ color: reglInstance.texture({
33
+ width: 1,
34
+ height: 1,
35
+ format: 'rgba',
36
+ type: 'float',
37
+ }),
38
+ depth: false,
39
+ stencil: false,
40
+ })
41
+ }
42
+
20
43
  if (!this.drawCurveCommand) {
21
44
  this.drawCurveCommand = reglInstance({
22
45
  vert: drawLineVert,
@@ -57,6 +80,12 @@ export class Lines extends CoreModule {
57
80
  offset: Float32Array.BYTES_PER_ELEMENT * 0,
58
81
  stride: Float32Array.BYTES_PER_ELEMENT * 1,
59
82
  },
83
+ linkIndices: {
84
+ buffer: () => this.linkIndexBuffer,
85
+ divisor: 1,
86
+ offset: Float32Array.BYTES_PER_ELEMENT * 0,
87
+ stride: Float32Array.BYTES_PER_ELEMENT * 1,
88
+ },
60
89
  },
61
90
  uniforms: {
62
91
  positionsTexture: () => this.points?.currentPositionFbo,
@@ -64,7 +93,7 @@ export class Lines extends CoreModule {
64
93
  transformationMatrix: () => store.transform,
65
94
  pointsTextureSize: () => store.pointsTextureSize,
66
95
  widthScale: () => config.linkWidthScale,
67
- arrowSizeScale: () => config.linkArrowsSizeScale,
96
+ linkArrowsSizeScale: () => config.linkArrowsSizeScale,
68
97
  spaceSize: () => store.adjustedSpaceSize,
69
98
  screenSize: () => store.screenSize,
70
99
  linkVisibilityDistanceRange: () => config.linkVisibilityDistanceRange,
@@ -76,11 +105,24 @@ export class Lines extends CoreModule {
76
105
  curvedWeight: () => config.curvedLinkWeight,
77
106
  curvedLinkControlPointDistance: () => config.curvedLinkControlPointDistance,
78
107
  curvedLinkSegments: () => config.curvedLinks ? config.curvedLinkSegments ?? defaultConfigValues.curvedLinkSegments : 1,
108
+ hoveredLinkIndex: () => store.hoveredLinkIndex ?? -1,
109
+ hoveredLinkColor: () => store.hoveredLinkColor,
110
+ hoveredLinkWidthIncrease: () => config.hoveredLinkWidthIncrease,
111
+ renderMode: reglInstance.prop<{ renderMode: number }, 'renderMode'>('renderMode'),
79
112
  },
80
113
  cull: {
81
114
  enable: true,
82
115
  face: 'back',
83
116
  },
117
+ /**
118
+ * Blending behavior for link index rendering (renderMode: 1.0 - hover detection):
119
+ *
120
+ * When rendering link indices to the framebuffer, we use full opacity (1.0).
121
+ * This means:
122
+ * - The source color completely overwrites the destination
123
+ * - No blending occurs - it's like drawing with a permanent marker
124
+ * - This preserves the exact index values we need for picking/selection
125
+ */
84
126
  blend: {
85
127
  enable: true,
86
128
  func: {
@@ -98,11 +140,37 @@ export class Lines extends CoreModule {
98
140
  enable: false,
99
141
  mask: false,
100
142
  },
143
+ framebuffer: reglInstance.prop<{ framebuffer: regl.Framebuffer2D }, 'framebuffer'>('framebuffer'),
101
144
  count: () => this.curveLineGeometry?.length ?? 0,
102
145
  instances: () => this.data.linksNumber ?? 0,
103
146
  primitive: 'triangle strip',
104
147
  })
105
148
  }
149
+
150
+ if (!this.hoveredLineIndexCommand) {
151
+ this.hoveredLineIndexCommand = reglInstance({
152
+ vert: hoveredLineIndexVert,
153
+ frag: hoveredLineIndexFrag,
154
+ attributes: {
155
+ position: {
156
+ buffer: () => this.quadBuffer,
157
+ },
158
+ },
159
+ uniforms: {
160
+ linkIndexTexture: () => this.linkIndexFbo,
161
+ mousePosition: () => store.screenMousePosition,
162
+ screenSize: () => store.screenSize,
163
+ },
164
+ framebuffer: this.hoveredLineIndexFbo,
165
+ count: 4,
166
+ primitive: 'triangle strip',
167
+ })
168
+ }
169
+
170
+ // Initialize quad buffer for full-screen rendering
171
+ if (!this.quadBuffer) {
172
+ this.quadBuffer = reglInstance.buffer([-1, -1, 1, -1, -1, 1, 1, 1])
173
+ }
106
174
  }
107
175
 
108
176
  public draw (): void {
@@ -111,7 +179,28 @@ export class Lines extends CoreModule {
111
179
  if (!this.widthBuffer) this.updateWidth()
112
180
  if (!this.arrowBuffer) this.updateArrow()
113
181
  if (!this.curveLineGeometry) this.updateCurveLineGeometry()
114
- this.drawCurveCommand?.()
182
+
183
+ // Render normal links (renderMode: 0.0 = normal rendering)
184
+ this.drawCurveCommand?.({ framebuffer: null, renderMode: 0.0 })
185
+ }
186
+
187
+ public updateLinkIndexFbo (): void {
188
+ const { reglInstance, store } = this
189
+
190
+ // Only create and update the link index FBO if link hovering is enabled
191
+ if (!this.store.isLinkHoveringEnabled) return
192
+
193
+ if (!this.linkIndexFbo) this.linkIndexFbo = reglInstance.framebuffer()
194
+ this.linkIndexFbo({
195
+ color: reglInstance.texture({
196
+ width: store.screenSize[0],
197
+ height: store.screenSize[1],
198
+ format: 'rgba',
199
+ type: 'float',
200
+ }),
201
+ depth: false,
202
+ stencil: false,
203
+ })
115
204
  }
116
205
 
117
206
  public updatePointsBuffer (): void {
@@ -134,6 +223,13 @@ export class Lines extends CoreModule {
134
223
 
135
224
  if (!this.pointsBuffer) this.pointsBuffer = reglInstance.buffer(0)
136
225
  this.pointsBuffer(instancePoints)
226
+
227
+ const linkIndices = new Float32Array(data.linksNumber)
228
+ for (let i = 0; i < data.linksNumber; i++) {
229
+ linkIndices[i] = i
230
+ }
231
+ if (!this.linkIndexBuffer) this.linkIndexBuffer = reglInstance.buffer(0)
232
+ this.linkIndexBuffer(linkIndices)
137
233
  }
138
234
 
139
235
  public updateColor (): void {
@@ -160,4 +256,18 @@ export class Lines extends CoreModule {
160
256
  if (!this.curveLineBuffer) this.curveLineBuffer = reglInstance.buffer(0)
161
257
  this.curveLineBuffer(this.curveLineGeometry)
162
258
  }
259
+
260
+ public findHoveredLine (): void {
261
+ if (!this.data.linksNumber || !this.store.isLinkHoveringEnabled) return
262
+ if (!this.linkIndexFbo) this.updateLinkIndexFbo()
263
+ this.reglInstance.clear({
264
+ framebuffer: this.linkIndexFbo as regl.Framebuffer2D,
265
+ color: [0, 0, 0, 0],
266
+ })
267
+ // Render to index buffer for picking/hover detection (renderMode: 1.0 = index rendering)
268
+ this.drawCurveCommand?.({ framebuffer: this.linkIndexFbo, renderMode: 1.0 })
269
+
270
+ // Execute the command to read the link index at mouse position
271
+ this.hoveredLineIndexCommand?.()
272
+ }
163
273
  }
@@ -61,6 +61,8 @@ export class Points extends CoreModule {
61
61
  private trackedIndices: number[] | undefined
62
62
  private selectedTexture: regl.Texture2D | undefined
63
63
  private greyoutStatusTexture: regl.Texture2D | undefined
64
+ private pinnedStatusTexture: regl.Texture2D | undefined
65
+ private pinnedStatusFbo: regl.Framebuffer2D | undefined
64
66
  private sizeTexture: regl.Texture2D | undefined
65
67
  private trackedIndicesTexture: regl.Texture2D | undefined
66
68
  private polygonPathTexture: regl.Texture2D | undefined
@@ -172,6 +174,7 @@ export class Points extends CoreModule {
172
174
  this.sampledPointIndices(createIndexesForBuffer(store.pointsTextureSize))
173
175
 
174
176
  this.updateGreyoutStatus()
177
+ this.updatePinnedStatus()
175
178
  this.updateSampledPointsGrid()
176
179
 
177
180
  this.trackPointsByIndices()
@@ -193,6 +196,7 @@ export class Points extends CoreModule {
193
196
  velocity: () => this.velocityFbo,
194
197
  friction: () => config.simulationFriction,
195
198
  spaceSize: () => store.adjustedSpaceSize,
199
+ pinnedStatusTexture: () => this.pinnedStatusFbo,
196
200
  },
197
201
  })
198
202
  }
@@ -520,6 +524,36 @@ export class Points extends CoreModule {
520
524
  })
521
525
  }
522
526
 
527
+ public updatePinnedStatus (): void {
528
+ const { reglInstance, store: { pointsTextureSize }, data } = this
529
+ if (!pointsTextureSize) return
530
+
531
+ // Pinned status: 0 - not pinned, 1 - pinned
532
+ const initialState = new Float32Array(pointsTextureSize * pointsTextureSize * 4).fill(0)
533
+
534
+ if (data.inputPinnedPoints && data.pointsNumber !== undefined) {
535
+ for (const pinnedIndex of data.inputPinnedPoints) {
536
+ if (pinnedIndex >= 0 && pinnedIndex < data.pointsNumber) {
537
+ initialState[pinnedIndex * 4] = 1
538
+ }
539
+ }
540
+ }
541
+
542
+ if (!this.pinnedStatusTexture) this.pinnedStatusTexture = reglInstance.texture()
543
+ this.pinnedStatusTexture({
544
+ data: initialState,
545
+ width: pointsTextureSize,
546
+ height: pointsTextureSize,
547
+ type: 'float',
548
+ })
549
+ if (!this.pinnedStatusFbo) this.pinnedStatusFbo = reglInstance.framebuffer()
550
+ this.pinnedStatusFbo({
551
+ color: this.pinnedStatusTexture,
552
+ depth: false,
553
+ stencil: false,
554
+ })
555
+ }
556
+
523
557
  public updateSize (): void {
524
558
  const { reglInstance, store: { pointsTextureSize }, data } = this
525
559
  if (!pointsTextureSize || data.pointsNumber === undefined || data.pointSizes === undefined) return
@@ -4,6 +4,7 @@ precision highp float;
4
4
 
5
5
  uniform sampler2D positionsTexture;
6
6
  uniform sampler2D velocity;
7
+ uniform sampler2D pinnedStatusTexture;
7
8
  uniform float friction;
8
9
  uniform float spaceSize;
9
10
 
@@ -13,6 +14,17 @@ void main() {
13
14
  vec4 pointPosition = texture2D(positionsTexture, textureCoords);
14
15
  vec4 pointVelocity = texture2D(velocity, textureCoords);
15
16
 
17
+ // Check if point is pinned
18
+ // pinnedStatusTexture has the same size and layout as positionsTexture
19
+ // Each pixel corresponds to a point: red channel > 0.5 means the point is pinned
20
+ vec4 pinnedStatus = texture2D(pinnedStatusTexture, textureCoords);
21
+
22
+ // If pinned, don't update position
23
+ if (pinnedStatus.r > 0.5) {
24
+ gl_FragColor = pointPosition;
25
+ return;
26
+ }
27
+
16
28
  // Friction
17
29
  pointVelocity.rg *= friction;
18
30
 
@@ -3,10 +3,18 @@ import { mat3 } from 'gl-matrix'
3
3
  import { Random } from 'random'
4
4
  import { getRgbaColor, rgbToBrightness } from '@/graph/helper'
5
5
  import { hoveredPointRingOpacity, focusedPointRingOpacity, defaultConfigValues } from '@/graph/variables'
6
+ import type { GraphConfigInterface } from '@/graph/config'
6
7
 
7
8
  export const ALPHA_MIN = 0.001
8
9
  export const MAX_POINT_SIZE = 64
9
10
 
11
+ /**
12
+ * Maximum number of executions to delay before performing hover detection.
13
+ * This threshold prevents excessive hover detection calls for performance optimization.
14
+ * The `findHoveredItem` method will skip actual detection until this count is reached.
15
+ */
16
+ export const MAX_HOVER_DETECTION_DELAY = 4
17
+
10
18
  export type Hovered = { index: number; position: [ number, number ] }
11
19
  type Focused = { index: number }
12
20
 
@@ -26,6 +34,7 @@ export class Store {
26
34
  public hoveredPoint: Hovered | undefined = undefined
27
35
  public focusedPoint: Focused | undefined = undefined
28
36
  public draggingPointIndex: number | undefined = undefined
37
+ public hoveredLinkIndex: number | undefined = undefined
29
38
  public adjustedSpaceSize = defaultConfigValues.spaceSize
30
39
  public isSpaceKeyPressed = false
31
40
  public div: HTMLDivElement | undefined
@@ -33,10 +42,13 @@ export class Store {
33
42
 
34
43
  public hoveredPointRingColor = [1, 1, 1, hoveredPointRingOpacity]
35
44
  public focusedPointRingColor = [1, 1, 1, focusedPointRingOpacity]
45
+ public hoveredLinkColor = [-1, -1, -1, -1]
36
46
  // -1 means that the color is not set
37
47
  public greyoutPointColor = [-1, -1, -1, -1]
38
48
  // If backgroundColor is dark, isDarkenGreyout is true
39
49
  public isDarkenGreyout = false
50
+ // Whether link hovering is enabled based on configured event handlers
51
+ public isLinkHoveringEnabled = false
40
52
  private alphaTarget = 0
41
53
  private scalePointX = scaleLinear()
42
54
  private scalePointY = scaleLinear()
@@ -102,14 +114,14 @@ export class Store {
102
114
  return this.scalePointY(y)
103
115
  }
104
116
 
105
- public setHoveredPointRingColor (color: string): void {
117
+ public setHoveredPointRingColor (color: string | [number, number, number, number]): void {
106
118
  const convertedRgba = getRgbaColor(color)
107
119
  this.hoveredPointRingColor[0] = convertedRgba[0]
108
120
  this.hoveredPointRingColor[1] = convertedRgba[1]
109
121
  this.hoveredPointRingColor[2] = convertedRgba[2]
110
122
  }
111
123
 
112
- public setFocusedPointRingColor (color: string): void {
124
+ public setFocusedPointRingColor (color: string | [number, number, number, number]): void {
113
125
  const convertedRgba = getRgbaColor(color)
114
126
  this.focusedPointRingColor[0] = convertedRgba[0]
115
127
  this.focusedPointRingColor[1] = convertedRgba[1]
@@ -128,6 +140,25 @@ export class Store {
128
140
  this.greyoutPointColor[3] = convertedRgba[3]
129
141
  }
130
142
 
143
+ public updateLinkHoveringEnabled (config: Pick<GraphConfigInterface, 'onLinkClick' | 'onLinkMouseOver' | 'onLinkMouseOut'>): void {
144
+ this.isLinkHoveringEnabled = !!(config.onLinkClick || config.onLinkMouseOver || config.onLinkMouseOut)
145
+ if (!this.isLinkHoveringEnabled) {
146
+ this.hoveredLinkIndex = undefined
147
+ }
148
+ }
149
+
150
+ public setHoveredLinkColor (color?: string | [number, number, number, number]): void {
151
+ if (color === undefined) {
152
+ this.hoveredLinkColor = [-1, -1, -1, -1]
153
+ return
154
+ }
155
+ const convertedRgba = getRgbaColor(color)
156
+ this.hoveredLinkColor[0] = convertedRgba[0]
157
+ this.hoveredLinkColor[1] = convertedRgba[1]
158
+ this.hoveredLinkColor[2] = convertedRgba[2]
159
+ this.hoveredLinkColor[3] = convertedRgba[3]
160
+ }
161
+
131
162
  public setFocusedPoint (index?: number): void {
132
163
  if (index !== undefined) {
133
164
  this.focusedPoint = { index }
@@ -10,6 +10,7 @@ export class CoreModule {
10
10
  public readonly store: Store
11
11
  public readonly data: GraphData
12
12
  public readonly points: Points | undefined
13
+ public _debugRandomNumber = Math.floor(Math.random() * 1000)
13
14
 
14
15
  public constructor (
15
16
  reglInstance: regl.Regl,
@@ -2,13 +2,19 @@ import { Meta } from "@storybook/blocks";
2
2
 
3
3
  <Meta title="Welcome to cosmos.gl" />
4
4
 
5
- <p style={{ fontSize: '2rem', lineHeight: '1.25em' }}>Welcome to cosmos.gl — a high-performance WebGL library for visualizing network graphs and machine learning embeddings.</p>
5
+ <div style={{ fontSize: '1.0rem', float: 'right' }}>
6
+ <a href="https://github.com/cosmosgl/graph" target="_blank" rel="noopener noreferrer" style={{ display: 'inline-flex', alignItems: 'center', gap: '0.5rem', color: '#fff' }}>
7
+ <svg height="30" viewBox="0 0 16 16" width="30" aria-hidden="true">
8
+ <path fill="currentColor" d="M8 0c4.42 0 8 3.58 8 8a8.013 8.013 0 0 1-5.45 7.59c-.4.08-.55-.17-.55-.38 0-.27.01-1.13.01-2.2 0-.75-.25-1.23-.54-1.48 1.78-.2 3.65-.88 3.65-3.95 0-.88-.31-1.59-.82-2.15.08-.2.36-1.02-.08-2.12 0 0-.67-.22-2.2.82-.64-.18-1.32-.27-2-.27-.68 0-1.36.09-2 .27-1.53-1.03-2.2-.82-2.2-.82-.44 1.1-.16 1.92-.08 2.12-.51.56-.82 1.28-.82 2.15 0 3.06 1.86 3.75 3.64 3.95-.23.2-.44.55-.51 1.07-.46.21-1.61.55-2.33-.66-.15-.24-.6-.83-1.23-.82-.67.01-.27.38.01.53.34.19.73.9.82 1.13.16.45.68 1.31 2.69.94 0 .67.01 1.3.01 1.49 0 .21-.15.45-.55.38A7.995 7.995 0 0 1 0 8c0-4.42 3.58-8 8-8Z"></path>
9
+ </svg>
10
+ </a>
11
+ </div>
12
+
13
+ <p style={{ fontSize: '1.75rem', lineHeight: '1.25em', marginTop: 0 }}>Welcome to <b>cosmos.gl</b> – a high-performance WebGL library for visualizing network graphs and machine learning embeddings.</p>
6
14
 
7
15
  <video style={{ width: '100%' }} src="https://user-images.githubusercontent.com/755708/173392407-9b05cbb6-d39e-4c2c-ab41-50900cfda823.mp4" loop autoPlay muted playsInline>
8
16
  </video>
9
17
 
10
- <p style={{ fontSize: '1.0rem' }}>Here you can find documentaion and examples of how to use cosmos.gl</p>
11
-
12
18
  ---
13
19
 
14
20
  ### Quick Start
@@ -35,7 +41,8 @@ const config = {
35
41
  fitViewPadding: 0.3, // centers the graph width padding of ~30% of screen
36
42
  rescalePositions: true, // rescale positions
37
43
  enableDrag: true, // enable dragging points
38
- onClick: pointIndex => { console.log('Clicked point index: ', pointIndex) },
44
+ onPointClick: pointIndex => { console.log('Clicked point index: ', pointIndex) },
45
+ onBackgroundClick: () => { console.log('Clicked background') },
39
46
  /* ... */
40
47
  }
41
48
 
@@ -9,13 +9,15 @@ import { Meta } from "@storybook/blocks";
9
9
  | enableSimulation | If set to `false`, the simulation will not run. This property will be applied only on component initialization and it can't be changed using the `setConfig` method | `true` |
10
10
  | backgroundColor | Canvas background color | `#222222` |
11
11
  | spaceSize | Simulation space size (max 8192) | `8192` |
12
- | pointColor | The default color to use for points when no point colors are provided, or if the color value in the array is `undefined` or `null`. This can be either a hex color string (e.g., '#b3b3b3') or an array of RGBA values in the format `[red, green, blue, alpha]` where each value is a number between 0 and 255 | `#b3b3b3` |
12
+ | pointDefaultColor | The default color to use for points when no point colors are provided, or if the color value in the array is `undefined` or `null`. This can be either a hex color string (e.g., '#b3b3b3') or an array of RGBA values in the format `[red, green, blue, alpha]` where each value is a number between 0 and 255 | `#b3b3b3` |
13
+ | pointColor | **[DEPRECATED]** Use `pointDefaultColor` instead. The default color to use for points when no point colors are provided... | `#b3b3b3` |
13
14
  | pointGreyoutOpacity | Greyed out point opacity value when the selection is active | `undefined` |
14
- | pointGreyoutColor | Greyed out point color value when the selection is active | `undefined` |
15
+ | pointGreyoutColor | The color to use for points when they are greyed out (when selection is active). This can be either a hex color string (e.g., '#b3b3b3') or an array of RGBA values in the format `[red, green, blue, alpha]` where each value is a number between 0 and 255. If not provided, the color will be the same as the point's original color, but darkened or lightened depending on the background color. If `pointGreyoutOpacity` is also defined, it will override the alpha/opacity component of this color. | `undefined` |
15
16
  | pointSize | The default size value to use for points when no point sizes are provided or if the size value in the array is `undefined` or `null` | `4` |
16
17
  | pointOpacity | Universal opacity value applied to all points. This value multiplies with individual point alpha values (if set via setPointColors). Useful for dynamically controlling opacity of all points without updating individual RGBA arrays. | `1.0` |
17
18
  | pointSizeScale | Scale factor for the point size | `1` |
18
19
  | hoveredPointCursor | Cursor style to use when hovering over a point | `auto` |
20
+ | hoveredLinkCursor | Cursor style to use when hovering over a link | `auto` |
19
21
  | renderHoveredPointRing | Turns ring rendering around a point on hover on / off | `false` |
20
22
  | hoveredPointRingColor | Hovered point ring color hex value or an array of RGBA values | `white` |
21
23
  | focusedPointRingColor | Focused point ring color hex value or an array of RGBA values | `white` |
@@ -26,6 +28,8 @@ import { Meta } from "@storybook/blocks";
26
28
  | linkGreyoutOpacity | Greyed out link opacity value when the selection is active | `0.1` |
27
29
  | linkWidth | The default width value to use for links when no link widths are provided or if the width value in the array is `undefined` or `null` | `1` |
28
30
  | linkWidthScale | Scale factor for the link width | `1` |
31
+ | hoveredLinkColor | The color to use for links when they are hovered. This can be either a hex color string (e.g., '#ff3333') or an array of RGBA values in the format `[red, green, blue, alpha]` where each value is a number between 0 and 255 | `undefined` |
32
+ | hoveredLinkWidthIncrease | Number of pixels to add to the link width when hovered | `5` |
29
33
  | scaleLinksOnZoom | Increase/decrease link width when zooming | `false` |
30
34
  | curvedLinks | If set to true, links are rendered as curved lines. Otherwise as straight lines | `false` |
31
35
  | curvedLinkSegments | Number of segments in a curved line | `19` |
@@ -86,11 +90,17 @@ cosmos.gl layout algorithm was inspired by the [d3-force](https://github.com/d3/
86
90
  | onSimulationTick | Called on every simulation tick, with the current alpha value and hover information |
87
91
  | onSimulationEnd | Called when simulation stops |
88
92
  | onSimulationPause | Called when simulation pauses |
89
- | onSimulationRestart | Called when simulation restarts |
93
+ | onSimulationUnpause | Called when simulation unpauses |
94
+ | onSimulationRestart | **[DEPRECATED]** Called when simulation restarts. Use `onSimulationUnpause` instead |
90
95
  | onClick | Called on canvas click with point index and position |
96
+ | onPointClick | Called when a point is clicked |
97
+ | onLinkClick | Called when a link is clicked |
98
+ | onBackgroundClick | Called when the background (empty space) is clicked |
91
99
  | onMouseMove | Called on mouse movement with hover info |
92
100
  | onPointMouseOver | Called when pointer enters a point |
93
101
  | onPointMouseOut | Called when pointer leaves a point |
102
+ | onLinkMouseOver | Called when pointer enters a link |
103
+ | onLinkMouseOut | Called when pointer leaves a link |
94
104
  | onZoomStart | Called when zoom/pan starts |
95
105
  | onZoom | Called during zoom/pan |
96
106
  | onZoomEnd | Called when zoom/pan ends |
@@ -8,11 +8,14 @@ This method sets the [cosmos.gl configuration](../?path=/docs/configuration--doc
8
8
 
9
9
  * **`config`** (Object): The configuration object adhering to cosmos.gl configuration properties.
10
10
 
11
- ### <a name="set_point_positions" href="#set_point_positions">#</a> graph.<b>setPointPositions</b>(<i>pointPositions</i>)
11
+ ### <a name="set_point_positions" href="#set_point_positions">#</a> graph.<b>setPointPositions</b>(<i>pointPositions</i>, [<i>dontRescale</i>])
12
12
 
13
13
  This method sets the positions of points in a cosmos.gl graph using the provided coordinates array.
14
14
 
15
15
  * **`pointPositions`** (Float32Array): A Float32Array representing the x and y coordinates of points in the format `[x1, y1, x2, y2, ..., xN, yN]`. Each pair represents the coordinates of a single point.
16
+ * **`dontRescale`** (Boolean, optional): For this call only, controls whether to rescale the points.
17
+ - `true`: Don't rescale the points.
18
+ - `false` or `undefined` (default): Use the behavior defined by `config.rescalePositions`.
16
19
 
17
20
  **Example:**
18
21
  ```javascript
@@ -246,7 +249,7 @@ graph.render();
246
249
 
247
250
  In this example, the `linkArrows` array contains three boolean values. The first value `true` sets an arrow on the first link, the second value `false` leaves the second link without an arrow, and the third value `true` sets an arrow on the third link.
248
251
 
249
- ### <a name="set_link_strengths" href="#set_link_strengths">#</a> graph.<b>setLinkStrength</b>(<i>linkStrength</i>)
252
+ ### <a name="set_link_strength" href="#set_link_strength">#</a> graph.<b>setLinkStrength</b>(<i>linkStrength</i>)
250
253
 
251
254
  This method sets the strength of the graph links.
252
255
 
@@ -298,7 +301,7 @@ This method sets the force strength coefficients for clustering points in the gr
298
301
 
299
302
  The `render` method renders the graph and, optionally, controls the initial energy of the simulation.
300
303
 
301
- * **`runSimulation`** (number, optional): The higher the value, the more initial energy the simulation will get. Zero value stops the simulation.
304
+ * **`simulationAlpha`** (number, optional): The higher the value, the more initial energy the simulation will get. Zero value stops the simulation.
302
305
 
303
306
  ### <a name="zoom_to_point_by_index" href="#zoom_to_point_by_index">#</a> graph.<b>zoomToPointByIndex</b>(<i>index</i>, [<i>duration</i>], [<i>scale</i>], [<i>canZoomOut</i>])
304
307
 
@@ -508,7 +511,13 @@ Starts the simulation with an optional <i>alpha</i> parameter, which controls th
508
511
 
509
512
  Pauses the current simulation in the graph.
510
513
 
511
- ### <a name="restart" href="#restart">#</a> graph.<b>restart</b>()
514
+ ### <a name="unpause" href="#unpause">#</a> graph.<b>unpause</b>()
515
+
516
+ Unpauses (resumes) the current simulation in the graph.
517
+
518
+ ### <a name="restart" href="#restart">#</a> graph.<b>restart</b>() <b style={{ color: 'orange' }}>[DEPRECATED]</b>
519
+
520
+ **⚠️ Deprecated:** Use `unpause()` instead. This method will be removed in a future version.
512
521
 
513
522
  Restarts the current simulation in the graph.
514
523
 
@@ -23,7 +23,7 @@ export const basicSetUp = (): { graph: Graph; div: HTMLDivElement} => {
23
23
  spaceSize: 4096,
24
24
  backgroundColor: '#2d313a',
25
25
  pointSize: 4,
26
- pointColor: '#4B5BBF',
26
+ pointDefaultColor: '#4B5BBF',
27
27
  linkWidth: 0.6,
28
28
  scalePointsOnZoom: true,
29
29
  linkColor: '#5F74C2',
@@ -38,15 +38,15 @@ export const basicSetUp = (): { graph: Graph; div: HTMLDivElement} => {
38
38
  simulationRepulsion: 0.2,
39
39
  simulationGravity: 0.1,
40
40
  simulationDecay: 100000,
41
- onClick: (index: number | undefined): void => {
42
- if (index !== undefined) {
43
- graph.selectPointByIndex(index)
44
- graph.zoomToPointByIndex(index)
45
- } else {
46
- graph.unselectPoints()
47
- }
41
+ onPointClick: (index: number): void => {
42
+ graph.selectPointByIndex(index)
43
+ graph.zoomToPointByIndex(index)
48
44
  console.log('Clicked point index: ', index)
49
45
  },
46
+ onBackgroundClick: (): void => {
47
+ graph.unselectPoints()
48
+ console.log('Clicked background')
49
+ },
50
50
  attribution: 'visualized with <a href="https://cosmograph.app/" style="color: var(--cosmosgl-attribution-color);" target="_blank">Cosmograph</a>',
51
51
  })
52
52
 
@@ -71,18 +71,28 @@ export const basicSetUp = (): { graph: Graph; div: HTMLDivElement} => {
71
71
  graph.pause()
72
72
  }
73
73
 
74
- function start (): void {
74
+ function unpause (): void {
75
75
  isPaused = false
76
76
  pauseButton.textContent = 'Pause'
77
- graph.start()
77
+ // if the graph is at 100% progress, start the graph
78
+ if (graph.progress === 1) {
79
+ graph.start()
80
+ } else {
81
+ graph.unpause()
82
+ }
78
83
  }
79
84
 
80
85
  function togglePause (): void {
81
- if (isPaused) start()
86
+ if (isPaused) unpause()
82
87
  else pause()
83
88
  }
84
89
 
85
90
  pauseButton.addEventListener('click', togglePause)
91
+ graph.setConfig({
92
+ onSimulationEnd: (): void => {
93
+ pause()
94
+ },
95
+ })
86
96
 
87
97
  // Zoom and Select
88
98
  function getRandomPointIndex (): number {