@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.
- package/.github/SECURITY.md +7 -1
- package/dist/config.d.ts +73 -1
- package/dist/index.d.ts +34 -6
- package/dist/index.js +4087 -3837
- package/dist/index.js.map +1 -1
- package/dist/index.min.js +124 -44
- package/dist/index.min.js.map +1 -1
- package/dist/modules/GraphData/index.d.ts +1 -0
- package/dist/modules/Lines/index.d.ts +8 -0
- package/dist/modules/Points/index.d.ts +3 -0
- package/dist/modules/Store/index.d.ts +14 -2
- package/dist/modules/core-module.d.ts +1 -0
- package/dist/stories/beginners/link-hovering/data-generator.d.ts +19 -0
- package/dist/stories/beginners/link-hovering/index.d.ts +5 -0
- package/dist/stories/beginners/pinned-points/data-gen.d.ts +5 -0
- package/dist/stories/beginners/pinned-points/index.d.ts +5 -0
- package/dist/stories/beginners.stories.d.ts +2 -0
- package/dist/variables.d.ts +5 -2
- package/package.json +1 -1
- package/src/config.ts +95 -3
- package/src/index.ts +179 -32
- package/src/modules/GraphData/index.ts +2 -1
- package/src/modules/Lines/draw-curve-line.frag +12 -1
- package/src/modules/Lines/draw-curve-line.vert +29 -2
- package/src/modules/Lines/hovered-line-index.frag +27 -0
- package/src/modules/Lines/hovered-line-index.vert +8 -0
- package/src/modules/Lines/index.ts +112 -2
- package/src/modules/Points/index.ts +34 -0
- package/src/modules/Points/update-position.frag +12 -0
- package/src/modules/Store/index.ts +33 -2
- package/src/modules/core-module.ts +1 -0
- package/src/stories/1. welcome.mdx +11 -4
- package/src/stories/2. configuration.mdx +13 -3
- package/src/stories/3. api-reference.mdx +13 -4
- package/src/stories/beginners/basic-set-up/index.ts +21 -11
- package/src/stories/beginners/link-hovering/data-generator.ts +198 -0
- package/src/stories/beginners/link-hovering/index.ts +61 -0
- package/src/stories/beginners/link-hovering/style.css +73 -0
- package/src/stories/beginners/pinned-points/data-gen.ts +153 -0
- package/src/stories/beginners/pinned-points/index.ts +61 -0
- package/src/stories/beginners/quick-start.ts +3 -2
- package/src/stories/beginners/remove-points/config.ts +1 -1
- package/src/stories/beginners/remove-points/index.ts +28 -30
- package/src/stories/beginners.stories.ts +31 -0
- package/src/stories/clusters/polygon-selection/index.ts +2 -4
- package/src/stories/create-cosmos.ts +1 -1
- package/src/stories/geospatial/moscow-metro-stations/index.ts +1 -1
- package/src/stories/shapes/image-example/index.ts +7 -8
- 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
|
-
|
|
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
|
-
|
|
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 }
|
|
@@ -2,13 +2,19 @@ import { Meta } from "@storybook/blocks";
|
|
|
2
2
|
|
|
3
3
|
<Meta title="Welcome to cosmos.gl" />
|
|
4
4
|
|
|
5
|
-
<
|
|
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
|
-
|
|
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
|
-
|
|
|
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 |
|
|
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
|
-
|
|
|
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="
|
|
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
|
-
* **`
|
|
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="
|
|
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
|
-
|
|
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
|
-
|
|
42
|
-
|
|
43
|
-
|
|
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
|
|
74
|
+
function unpause (): void {
|
|
75
75
|
isPaused = false
|
|
76
76
|
pauseButton.textContent = 'Pause'
|
|
77
|
-
graph
|
|
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)
|
|
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 {
|